home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
x
/
volume15
/
olvwm-3.0
/
part06
< prev
next >
Wrap
Internet Message Format
|
1992-02-03
|
57KB
Path: uunet!sun-barr!ames!pasteur!nntp
From: scott.oaks@East.Sun.COM (Scott Oaks)
Newsgroups: comp.sources.x
Subject: v15i152: OpenLook Virtual Window Mgr (3.0), Part06/21
Message-ID: <1992Feb4.135555.7121@pasteur.Berkeley.EDU>
Date: 4 Feb 92 13:55:55 GMT
References: <csx-15i147-olvwm-3.0@uunet.UU.NET>
Sender: dcmartin@msi.com (David C. Martin - Moderator)
Organization: University of California, at Berkeley
Lines: 2006
Approved: dcmartin@msi.com
Nntp-Posting-Host: postgres.berkeley.edu
Submitted-by: scott.oaks@East.Sun.COM (Scott Oaks)
Posting-number: Volume 15, Issue 152
Archive-name: olvwm-3.0/part06
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 6 (of 21)."
# Contents: defaults.h evbind.c winpane.c
# Wrapped by dcmartin@fascet on Tue Jan 14 05:54:43 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'defaults.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'defaults.h'\"
else
echo shar: Extracting \"'defaults.h'\" \(771 characters\)
sed "s/^X//" >'defaults.h' <<'END_OF_FILE'
X/*
X * (c) Copyright 1990 Sun Microsystems, Inc. Sun design patents
X * pending in the U.S. and foreign countries. See LEGAL_NOTICE
X * file for terms of the license.
X */
X
X#ident "@(#)defaults.h 1.1 olvwm version 1/3/92"
X
X/*
X * Based on
X#ident "@(#)defaults.h 26.7 91/09/14 SMI"
X *
X */
X
X/*
X * default constants
X */
X#define DEFWORKSPACECOLOR "#40a0c0"
X#define DEFWINDOWCOLOR "#cccccc"
X#define DEFFOREGROUNDCOLOR "#000000"
X#define DEFBACKGROUNDCOLOR "#ffffff"
X#define DEFBORDERCOLOR "#000000"
X
X#define DEFVIRTUALFORECOLOR "#cccccc"
X#define DEFVIRTUALBACKCOLOR "#40a0c0"
X#define DEFVIRTUALFONTCOLOR "#ffffff"
X#define DEFVIRTUALGRIDCOLOR "#ffffff"
X#define DEFVIRTUALPIXMAPCOLOR "#000000"
X
X#define DEFAULTFONT "9x15"
X
Xvoid SetAllDBValues();
END_OF_FILE
if test 771 -ne `wc -c <'defaults.h'`; then
echo shar: \"'defaults.h'\" unpacked with wrong size!
fi
# end of 'defaults.h'
fi
if test -f 'evbind.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'evbind.c'\"
else
echo shar: Extracting \"'evbind.c'\" \(38223 characters\)
sed "s/^X//" >'evbind.c' <<'END_OF_FILE'
X/*
X * (c) Copyright 1991 Sun Microsystems, Inc. Sun design patents
X * pending in the U.S. and foreign countries. See LEGAL_NOTICE
X * file for terms of the license.
X */
X
X#ident "@(#)evbind.c 1.1 olvwm version 1/3/92"
X
X/*
X * Based on
X#ident "@(#)evbind.c 1.21 91/09/14 SMI"
X *
X */
X
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X#include <sys/types.h>
X#include <sys/time.h>
X
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/keysym.h>
X
X#include "i18n.h"
X#include "ollocale.h"
X#include "olwm.h"
X#include "win.h"
X#include "globals.h"
X#include "events.h"
X#include "list.h"
X#include "mem.h"
X#include "kbdfuncs.h"
X#include "resources.h"
X
X
X/* ===== externs ========================================================== */
X
Xextern List *ScreenInfoList;
X
X/* ===== private data ===================================================== */
X
Xstatic XrmQuark kbdCmdInstanceQ;
Xstatic XrmQuark kbdCmdClassQ;
Xstatic XrmQuark modInstanceQ;
Xstatic XrmQuark modClassQ;
X
X/* ===== Modifier Binding ================================================= */
X
X
Xunsigned int ModMaskMap[MOD_MASK_COUNT];
X
Xtypedef struct {
X char *rsrc_name;
X char *dflt_binding;
X int mapindex;
X} ModDescriptor;
X
XModDescriptor ModDescriptorTable[] = {
X
X /* rsrc_name default mapindex */
X { "Constrain", "Control", MOD_CONSTRAIN },
X { "WMGrab", "Alt", MOD_WMGRAB },
X { "Reduce", "Meta", MOD_REDUCE },
X { "Invert", "Shift", MOD_INVERT },
X { "SetDefault", "Control", MOD_SETDEFAULT },
X { "Ignore", "Lock,Num_Lock,mod5,Mode_switch", MOD_IGNORE }
X
X};
X#define NMODBINDINGS (sizeof(ModDescriptorTable)/sizeof(ModDescriptor))
X
X
X/*
X * establishModBindings
X *
X * Read through the modifier descriptor table and fill in the modifier mask
X * map with modifier masks found in the server's modifier mask map.
X */
Xstatic void
XestablishModBindings(dpy, newDB)
X Display *dpy;
X XrmDatabase newDB;
X{
X XrmQuark classlist[4], instlist[4];
X char *s;
X XrmRepresentation rep;
X XrmValue value;
X ModDescriptor *d;
X unsigned int polyStringToModifier();
X static XrmBinding bindings[] =
X { XrmBindTightly, XrmBindTightly, XrmBindTightly };
X
X classlist[0] = OpenWinQ;
X classlist[1] = modClassQ;
X classlist[3] = NULLQUARK;
X
X instlist[0] = TopInstanceQ;
X instlist[1] = modInstanceQ;
X instlist[3] = NULLQUARK;
X
X for (d = ModDescriptorTable; d < ModDescriptorTable + NMODBINDINGS; ++d) {
X
X classlist[2] = instlist[2] = XrmStringToQuark(d->rsrc_name);
X
X if (XrmQGetResource(newDB, instlist, classlist, &rep, &value))
X s = (char *) value.addr;
X else {
X /*
X * Use olwm binding -- see resources.c
X */
X classlist[0] = OlwmQ;
X if (XrmQGetResource(newDB, instlist, classlist, &rep, &value))
X s = (char *) value.addr;
X else s = d->dflt_binding;
X classlist[0] = OpenWinQ;
X }
X
X ModMaskMap[d->mapindex] = polyStringToModifier(dpy, s);
X }
X}
X
X
X/* ===== Mouse Binding ==================================================== */
X
X
X/*
X * Table of mouse bindings.
X *
X * REMIND
X *
X * At a future time, this table will be changeable via resources. For now,
X * it's specified as a compile-time constant.
X */
X
Xtypedef struct {
X int state;
X int button;
X SemanticAction action;
X} MouseBinding;
X
XMouseBinding MouseBindingTable[] = {
X /* state, button, action */
X { 0, Button1, ACTION_SELECT },
X { 0, Button2, ACTION_ADJUST },
X { 0, Button3, ACTION_MENU },
X { ButtonToMask(1), Button2, ACTION_MENU },
X { ButtonToMask(2), Button1, ACTION_MENU },
X { ShiftMask, Button1, ACTION_ADJUST },
X { ControlMask, Button3, ACTION_MENU },
X { ControlMask|ButtonToMask(1), Button2, ACTION_MENU },
X { ControlMask|ButtonToMask(2), Button1, ACTION_MENU },
X};
X#define NMOUSEBINDINGS (sizeof(MouseBindingTable)/sizeof(MouseBinding))
X
X
X/*
X * searchMouseBindings
X *
X * Search the mouse binding table and return information about what was found.
X * Return values of MATCH_NONE, MATCH_INCOMPLETE, and MATCH_AMBIG mean that no
X * action is available for the given event. MATCH_PREFIX and MATCH_EXACT
X * indicate that an action is available; this action is returned in the area
X * pointed to by the action parameter.
X */
Xstatic MouseMatchState
XsearchMouseBindings(pe, action)
X XButtonEvent *pe;
X SemanticAction *action;
X{
X int i;
X int nexact = 0; /* number of exact matches */
X int nprefix = 0; /* number of prefix matches */
X int lastexact = 0; /* index of last exact match */
X unsigned int modmask = (pe->state | ButtonToMask(pe->button));
X
X for (i=0; i<NMOUSEBINDINGS; ++i) {
X if (pe->state == MouseBindingTable[i].state &&
X pe->button == MouseBindingTable[i].button) {
X lastexact = i;
X ++nexact;
X } else if (modmask == MouseBindingTable[i].state) {
X ++nprefix;
X }
X }
X
X if (nexact == 0 && nprefix == 0)
X return MATCH_NONE;
X if (nexact == 0 && nprefix > 0)
X return MATCH_INCOMPLETE;
X if (nexact > 1)
X return MATCH_AMBIG;
X
X /* at this point, we know there is exactly one exact match */
X *action = MouseBindingTable[lastexact].action;
X if (nprefix == 0)
X return MATCH_EXACT;
X else
X return MATCH_PREFIX;
X}
X
X
X/*
X * checkChording
X *
X * Scan the input queue for button events that will disambiguate a single
X * action from a chorded action. If there aren't any events in the queue,
X * wait for them until a certain timeout period has elapsed. Return value
X * indicates whether a ButtonPress was seen further ahead in the event stream,
X * which indicates that this event is part of a chorded sequence. The timeout
X * parameter is updated with the amount of time remaining.
X */
Xstatic Bool
XcheckChording(dpy, timeout, pr)
X Display *dpy;
X struct timeval timeout;
X XButtonEvent *pr;
X{
X XEvent e;
X int n;
X
X while (1) {
X /*
X * Check for data on the connection. Scan it for disambiguating
X * events. Note that MotionNotify events within the move threshold
X * are discarded.
X */
X n = XEventsQueued(dpy, QueuedAfterReading);
X if (n > 0 && XCheckMaskEvent(dpy,
X ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, &e)) {
X switch (e.type) {
X case ButtonPress:
X XPutBackEvent(dpy, &e);
X return True;
X case ButtonRelease:
X XPutBackEvent(dpy, &e);
X return False;
X case MotionNotify:
X if (ABS(pr->x_root - e.xmotion.x_root) > GRV.MoveThreshold ||
X ABS(pr->y_root - e.xmotion.y_root) > GRV.MoveThreshold) {
X XPutBackEvent(dpy, &e);
X return False;
X }
X break;
X }
X }
X
X if (!AwaitEvents(dpy, &timeout))
X return False;
X }
X}
X
X
X/*
X * ResolveMouseBinding
X *
X * Given a mouse button press event, determines whether this event completes
X * an event sequence that binds to an action. If the button press is a prefix
X * of a chording sequence, and this press falls within the chording time of
X * the initial button press, checkChording is called to disambiguate the event
X * stream. Returns a proper action if the action is complete, otherwise
X * returns ACTION_NONE. All callers should ensure that no action is taken
X * when this routine returns ACTION_NONE.
X */
XSemanticAction
XResolveMouseBinding(dpy, pevent, ignoremask)
X Display *dpy;
X XEvent *pevent;
X unsigned long ignoremask;
X{
X MouseMatchState m;
X struct timeval timeout;
X SemanticAction a;
X static Time firstpresstime;
X XEvent e;
X
X /* copy *pevent to e, masking off ignored bits from the state */
X e = *pevent;
X e.xbutton.state &= ~(ignoremask |
X ModMaskMap[MOD_IGNORE] |
X ModMaskMap[MOD_WMGRAB]);
X
X /* Chording is in msec. Convert to sec/usec for timeval. */
X timeout.tv_usec = GRV.MouseChordTimeout * 1000;
X if (timeout.tv_usec >= 1000000) {
X timeout.tv_sec = timeout.tv_usec / 1000000;
X timeout.tv_usec %= 1000000;
X } else {
X timeout.tv_sec = 0;
X }
X
X if (FirstButtonDown(&e)) {
X firstpresstime = e.xbutton.time;
X } else {
X if (e.xbutton.time - firstpresstime > GRV.MouseChordTimeout)
X return ACTION_NONE;
X }
X
X m = searchMouseBindings(&e, &a);
X if ((m == MATCH_PREFIX && !checkChording(dpy, timeout, &e))
X || m == MATCH_EXACT) {
X return a;
X } else {
X return ACTION_NONE;
X }
X}
X
X
X/* ===== Keyboard Binding ================================================= */
X
X/*
X * Table of default keyboard descriptors. This table contains information
X * necessary to initialize keyboard bindings and customize them based on
X * resources.
X */
X
X#define NULLFUNC ((void (*)())0)
X
Xextern void HandleHelpKey();
X
Xstatic void keySuspend();
Xstatic void keyResume();
Xstatic void keyQuoteNext();
X
Xstatic unsigned long mouselessMaskTable[] = { KD_SUNVIEW, KD_BASIC, KD_FULL };
X
XKeyDescriptor KeyDescriptorTable[] = {
X
X/*
X rsrc_name dflt_binding function
X action flags
X */
X
X{
X "Stop", "L1,Escape", NULLFUNC,
X ACTION_STOP, KD_ALWAYS
X}, {
X "DefaultAction", "Return,Return+Meta,KP_Enter", NULLFUNC,
X ACTION_EXEC_DEFAULT, KD_ALWAYS
X}, {
X "Select", "space", NULLFUNC,
X ACTION_SELECT, KD_ALWAYS
X}, {
X "Adjust", "Insert+Alt", NULLFUNC,
X ACTION_ADJUST, KD_ALWAYS
X}, {
X "Menu", "space+Alt", NULLFUNC,
X ACTION_MENU, KD_ALWAYS
X}, {
X "InputFocusHelp", "question,question+Ctrl", NULLFUNC,
X ACTION_FOCUS_HELP, KD_ALWAYS
X}, {
X "Up", "Up", NULLFUNC,
X ACTION_UP, KD_ALWAYS,
X}, {
X "Down", "Down", NULLFUNC,
X ACTION_DOWN, KD_ALWAYS,
X}, {
X "Left", "Left", NULLFUNC,
X ACTION_LEFT, KD_ALWAYS
X}, {
X "Right", "Right", NULLFUNC,
X ACTION_RIGHT, KD_ALWAYS
X}, {
X "JumpUp", "Up+Ctrl", NULLFUNC,
X ACTION_JUMP_UP, KD_ALWAYS
X}, {
X "JumpDown", "Down+Ctrl", NULLFUNC,
X ACTION_JUMP_DOWN, KD_ALWAYS
X}, {
X "JumpLeft", "Left+Ctrl", NULLFUNC,
X ACTION_JUMP_LEFT, KD_ALWAYS
X}, {
X "JumpRight", "Right+Ctrl", NULLFUNC,
X ACTION_JUMP_RIGHT, KD_ALWAYS
X}, {
X "RowStart", "Home,R7", NULLFUNC,
X ACTION_ROW_START, KD_ALWAYS
X}, {
X "RowEnd", "End,R13", NULLFUNC,
X ACTION_ROW_END, KD_ALWAYS
X}, {
X "DataStart", "Home+Ctrl", NULLFUNC,
X ACTION_DATA_START, KD_ALWAYS
X}, {
X "DataEnd", "End+Ctrl", NULLFUNC,
X ACTION_DATA_END, KD_ALWAYS
X}, {
X "FirstControl", "bracketleft+Ctrl", NULLFUNC,
X ACTION_FIRST_CONTROL, KD_ALWAYS
X}, {
X "LastControl", "bracketright+Ctrl", NULLFUNC,
X ACTION_LAST_CONTROL, KD_ALWAYS
X}, {
X "NextElement", "Tab,Tab+Ctrl", NULLFUNC,
X ACTION_NEXT_ELEMENT, KD_ALWAYS
X}, {
X "PreviousElement", "Tab+Shift,Tab+Shift+Ctrl", NULLFUNC,
X ACTION_PREVIOUS_ELEMENT, KD_ALWAYS
X}, {
X "Open", "L7+Alt", NULLFUNC,
X ACTION_OPEN, KD_ALWAYS
X}, {
X "Help", "Help", HandleHelpKey,
X ACTION_HELP, KD_BASIC_FULL
X}, {
X "LockColormap", "L2+Ctrl", KeyLockColormap,
X ACTION_NONE, KD_BASIC_FULL
X}, {
X "UnlockColormap", "L4+Ctrl", KeyUnlockColormap,
X ACTION_NONE, KD_BASIC_FULL
X}, {
X "Front", "L5+Alt", KeyFrontFocus,
X ACTION_FRONT, KD_BASIC_FULL
X}, {
X "FocusToPointer", "j+Shift+Alt", KeyFocusToPointer,
X ACTION_NONE, KD_FULL
X}, {
X "NextApp", "n+Alt", KeyNextApp,
X ACTION_NONE, KD_FULL
X}, {
X "PreviousApp", "N+Alt", KeyPrevApp,
X ACTION_NONE, KD_FULL
X}, {
X "ToggleInput", "t+Alt", KeyToggleInput,
X ACTION_NONE, KD_FULL
X}, {
X "NextWindow", "w+Alt", KeyNextWindow,
X ACTION_NONE, KD_FULL
X}, {
X "PreviousWindow", "W+Alt", KeyPrevWindow,
X ACTION_NONE, KD_FULL
X}, {
X "TogglePin", "Insert+Meta", KeyTogglePin,
X ACTION_TOGGLE_PIN, KD_FULL
X}, {
X "SuspendMouseless", "z+Alt", keySuspend,
X ACTION_NONE, KD_BASIC_FULL
X}, {
X "ResumeMouseless", "Z+Alt", keyResume,
X ACTION_NONE, KD_IMMUNE | KD_BASIC_FULL
X}, {
X "QuoteNextKey", "q+Alt", keyQuoteNext,
X ACTION_NONE, KD_BASIC_FULL
X}, {
X "Refresh", "F8+Alt", KeyRefresh,
X ACTION_NONE, KD_FULL
X}, {
X "Back", "F5+Alt", KeyBackFocus,
X ACTION_NONE, KD_FULL
X}, {
X "OpenClose", "F2+Alt", KeyOpenCloseFocus,
X ACTION_NONE, KD_FULL
X}, {
X "FullRestore", "F3+Alt", KeyFullRestore,
X ACTION_NONE, KD_FULL
X}, {
X "Quit", "F9+Alt", KeyQuit,
X ACTION_NONE, KD_FULL
X}, {
X "Owner", "F10+Alt", KeyOwner,
X ACTION_NONE, KD_FULL
X}, {
X "WorkspaceMenu", "M+Alt", KeyWorkspaceMenu,
X ACTION_NONE, KD_FULL
X}, {
X "WindowMenu", "m+Alt", KeyWindowMenu,
X ACTION_NONE, KD_FULL
X}, {
X "Move", "F6+Alt", KeyMove,
X ACTION_NONE, KD_FULL
X}, {
X "Resize", "F7+Alt", KeyResize,
X ACTION_NONE, KD_FULL
X}, {
X "Properties", "F4+Alt", KeyProperties,
X ACTION_NONE, KD_FULL
X}, {
X "OpenClosePointer", "L7", KeyOpenClosePointer,
X ACTION_NONE, KD_ALWAYS
X}, {
X "RaiseLower", "L5", KeyRaiseLowerPointer,
X ACTION_NONE, KD_ALWAYS
X},
X
X/*
X * Keymappings for the virtual desktop. The keypad keys are mapped
X * in a clockwise fashion around the arrow keys. These keys with a meta
X * modifier are grabbed and are always active, otherwise they fall through
X * to the no focus window which moves the vdm
X *
X * We don't have a nofocus action for R7 and R13 since they already have
X * an action above
X */
X { "VirtualUp", "Up+Meta", KeyMoveVDM,
X ACTION_UP, KD_ALWAYS },
X { "HalfUp", "Up+Shift", NULLFUNC,
X ACTION_HALF_UP, KD_ALWAYS },
X { "VirtualHalfUp", "Up+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_UP, KD_ALWAYS },
X { "VirtualJumpUp", "Up+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_UP, KD_ALWAYS },
X
X { "VirtualDown", "Down+Meta", KeyMoveVDM,
X ACTION_DOWN, KD_ALWAYS },
X { "HalfDown", "Down+Shift", NULLFUNC,
X ACTION_HALF_DOWN, KD_ALWAYS },
X { "VirtualHalfDown", "Down+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_DOWN, KD_ALWAYS },
X { "VirtualJumpDown", "Down+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_DOWN, KD_ALWAYS },
X
X { "VirtualLeft", "Left+Meta", KeyMoveVDM,
X ACTION_LEFT, KD_ALWAYS },
X { "HalfLeft", "Left+Shift", NULLFUNC,
X ACTION_HALF_LEFT, KD_ALWAYS },
X { "VirtualHalfLeft", "Left+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_LEFT, KD_ALWAYS },
X { "VirtualJumpLeft", "Left+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_LEFT, KD_ALWAYS },
X
X { "VirtualRight", "Right+Meta", KeyMoveVDM,
X ACTION_RIGHT, KD_ALWAYS },
X { "HalfRight", "Right+Shift", NULLFUNC,
X ACTION_HALF_RIGHT, KD_ALWAYS },
X { "VirtualHalfRight", "Right+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_RIGHT, KD_ALWAYS },
X { "VirtualJumpRight", "Right+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_RIGHT, KD_ALWAYS },
X
X { "VirtualUpLeft", "R7+Meta", KeyMoveVDM,
X ACTION_UPLEFT, KD_ALWAYS },
X { "JumpUpLeft", "R7+Ctrl", NULLFUNC,
X ACTION_JUMP_UPLEFT, KD_ALWAYS },
X { "VirtualJumpUpLeft", "R7+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_UPLEFT, KD_ALWAYS },
X { "HalfUpLeft", "R7+Shift", NULLFUNC,
X ACTION_HALF_UPLEFT, KD_ALWAYS },
X { "VirtualHalfUpLeft", "R7+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_UPLEFT, KD_ALWAYS },
X
X { "VirtualUpRight", "R9+Meta", KeyMoveVDM,
X ACTION_UPRIGHT, KD_ALWAYS },
X { "UpRight", "R9", NULLFUNC,
X ACTION_UPRIGHT, KD_ALWAYS },
X { "JumpUpRight", "R9+Ctrl", NULLFUNC,
X ACTION_JUMP_UPRIGHT, KD_ALWAYS },
X { "VirtualJumpUpRight", "R9+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_UPRIGHT, KD_ALWAYS },
X { "HalfUpRight", "R9+Shift", NULLFUNC,
X ACTION_HALF_UPRIGHT, KD_ALWAYS },
X { "VirtualHalfUpRight", "R9+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_UPRIGHT, KD_ALWAYS },
X
X { "VirtualDownLeft", "R13+Meta", KeyMoveVDM,
X ACTION_DOWNLEFT, KD_ALWAYS },
X { "JumpDownLeft", "R13+Ctrl", NULLFUNC,
X ACTION_JUMP_DOWNLEFT, KD_ALWAYS },
X { "VirtualJumpDownLeft", "R13+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_DOWNLEFT, KD_ALWAYS },
X { "HalfDownLeft", "R13+Shift", NULLFUNC,
X ACTION_HALF_DOWNLEFT, KD_ALWAYS },
X { "VirtualHalfDownLeft", "R13+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_DOWNLEFT, KD_ALWAYS },
X
X { "VirtualDownRight", "R15+Meta", KeyMoveVDM,
X ACTION_DOWNRIGHT, KD_ALWAYS },
X { "DownRight", "R15", NULLFUNC,
X ACTION_DOWNRIGHT, KD_ALWAYS },
X { "JumpDownRight", "R15+Ctrl", NULLFUNC,
X ACTION_JUMP_DOWNRIGHT, KD_ALWAYS },
X { "VirtualJumpDownRight", "R15+Ctrl+Meta", KeyMoveVDM,
X ACTION_JUMP_DOWNRIGHT, KD_ALWAYS },
X { "HalfDownRight", "R15+Shift", NULLFUNC,
X ACTION_HALF_DOWNRIGHT, KD_ALWAYS },
X { "VirtualHalfDownRight", "R15+Shift+Meta", KeyMoveVDM,
X ACTION_HALF_DOWNRIGHT, KD_ALWAYS },
X
X { "VirtualHome", "R11+Meta", KeyMoveVDM,
X ACTION_HOME, KD_ALWAYS },
X { "GoHome", "R11", NULLFUNC,
X ACTION_HOME, KD_ALWAYS },
X
X { "VirtualScreen1", "F1+Meta", KeyMoveVDM,
X ACTION_GOTO_1, KD_ALWAYS },
X { "Screen1", "F1", NULLFUNC,
X ACTION_GOTO_1, KD_ALWAYS },
X { "VirtualScreen2", "F2+Meta", KeyMoveVDM,
X ACTION_GOTO_2, KD_ALWAYS },
X { "Screen2", "F2", NULLFUNC,
X ACTION_GOTO_2, KD_ALWAYS },
X { "VirtualScreen3", "F3+Meta", KeyMoveVDM,
X ACTION_GOTO_3, KD_ALWAYS },
X { "Screen3", "F3", NULLFUNC,
X ACTION_GOTO_3, KD_ALWAYS },
X { "VirtualScreen4", "F4+Meta", KeyMoveVDM,
X ACTION_GOTO_4, KD_ALWAYS },
X { "Screen4", "F4", NULLFUNC,
X ACTION_GOTO_4, KD_ALWAYS },
X { "VirtualScreen5", "F5+Meta", KeyMoveVDM,
X ACTION_GOTO_5, KD_ALWAYS },
X { "Screen5", "F5", NULLFUNC,
X ACTION_GOTO_5, KD_ALWAYS },
X { "VirtualScreen6", "F6+Meta", KeyMoveVDM,
X ACTION_GOTO_6, KD_ALWAYS },
X { "Screen6", "F6", NULLFUNC,
X ACTION_GOTO_6, KD_ALWAYS },
X { "VirtualScreen7", "F7+Meta", KeyMoveVDM,
X ACTION_GOTO_7, KD_ALWAYS },
X { "Screen7", "F7", NULLFUNC,
X ACTION_GOTO_7, KD_ALWAYS },
X { "VirtualScreen8", "F8+Meta", KeyMoveVDM,
X ACTION_GOTO_8, KD_ALWAYS },
X { "Screen8", "F8", NULLFUNC,
X ACTION_GOTO_8, KD_ALWAYS },
X { "VirtualScreen9", "F9+Meta", KeyMoveVDM,
X ACTION_GOTO_9, KD_ALWAYS },
X { "Screen9", "F9", NULLFUNC,
X ACTION_GOTO_9, KD_ALWAYS },
X { "VirtualScreen10", "F10+Meta", KeyMoveVDM,
X ACTION_GOTO_10, KD_ALWAYS },
X { "Screen10", "F10", NULLFUNC,
X ACTION_GOTO_10, KD_ALWAYS },
X};
X
X#define NUMKEYDESCRIPTORS (sizeof(KeyDescriptorTable)/sizeof(KeyDescriptor))
X
X
Xtypedef struct {
X unsigned int modstate;
X KeyCode keycode;
X KeyDescriptor *desc;
X} KeyBinding;
X
X
Xtypedef struct {
X KeySym sym;
X unsigned int mod;
X} modsym;
X
X
X#define KEYBINDING_TABLE_SIZE 60
X#define KEYBINDING_TABLE_INCR 20
X
Xstatic KeyBinding *KeyBindingTable = NULL;
Xstatic KeyBinding *activeKey = NULL;
Xstatic int bindingTableCount = 0;
Xstatic int bindingTableSize = 0;
Xstatic Bool suspended = False;
Xstatic Bool quotenext = False;
X
X
X/*
X * Suspension and resumption of Mouseless functions.
X */
Xstatic void
XkeySuspend(dpy, ke)
X Display *dpy;
X XKeyEvent *ke;
X{
X if (ke->type != KeyPress)
X return;
X suspended = True;
X}
X
X
Xstatic void
XkeyResume(dpy, ke)
X Display *dpy;
X XKeyEvent *ke;
X{
X if (ke->type != KeyPress)
X return;
X suspended = False;
X}
X
X
XBool
XIsMouselessSuspended()
X{
X return suspended;
X}
X
Xstatic void
XkeyQuoteNext(dpy, ke)
X Display *dpy;
X XKeyEvent *ke;
X{
X /*
X * Turn on quotenext on the release. If we set it on the press,
X * the subsequent release would turn it off!
X */
X if (ke->type != KeyRelease)
X return;
X quotenext = True;
X}
X
X
X/*
X * Add a binding to the key binding table.
X */
Xvoid
XAddKeyBinding(kc, mod, desc)
X KeyCode kc;
X unsigned int mod;
X KeyDescriptor *desc;
X{
X KeyBinding *b;
X
X if (bindingTableCount == bindingTableSize) {
X bindingTableSize += KEYBINDING_TABLE_INCR;
X KeyBindingTable = MemRealloc(KeyBindingTable,
X bindingTableSize*sizeof(KeyBinding));
X }
X
X b = &KeyBindingTable[bindingTableCount];
X b->keycode = kc;
X b->modstate = mod;
X b->desc = desc;
X ++bindingTableCount;
X}
X
X
X/*
X * Keysym aliasing. Provides aliases for modifier keysyms. Allows an alias
X * to represent a mask or to be a synonym for up to two keysyms. The keysyms
X * are only looked at if the mask value is zero.
X */
X
Xtypedef struct {
X char *alias;
X unsigned int mask;
X KeySym sym1, sym2;
X} KeysymAlias;
X
Xstatic KeysymAlias KeysymAliasTable[] = {
X /* alias mask sym1 sym2 */
X { "Any", AnyModifier, 0, 0 },
X { "Shift", ShiftMask, 0, 0 },
X { "Lock", LockMask, 0, 0 },
X { "Control", ControlMask, 0, 0 },
X { "Ctrl", ControlMask, 0, 0 },
X { "Ctl", ControlMask, 0, 0 },
X { "Meta", 0, XK_Meta_L, XK_Meta_R },
X { "Alt", 0, XK_Alt_L, XK_Alt_R },
X { "Super", 0, XK_Super_L, XK_Super_R },
X { "Hyper", 0, XK_Hyper_L, XK_Hyper_R }
X};
X#define NUMALIASES (sizeof(KeysymAliasTable)/sizeof(KeysymAlias))
X
X
X/*
X * Takes a word and presumes that it names a keysym. Looks up this keysym in
X * the modifier mapping table and returns the corresponding modifier mask. If
X * the string doesn't name a valid keysym, returns 0. If the keysym is not a
X * modifier, returns 0. If the word is "Any", returns AnyModifier. Several
X * aliases are supported for well-known modifiers, e.g. "Meta" for "Meta_L" or
X * "Meta_R". REMIND: If a keysym is on several keys, and only some of the
X * keys are modifiers, this function may fail to find the modifier mask.
X */
Xunsigned int
XstringToModifier(dpy, word)
X Display *dpy;
X char *word;
X{
X KeySym ks;
X KeyCode kc;
X KeysymAlias *ksa;
X int modnum;
X
X ks = XStringToKeysym(word);
X
X if (ks != NoSymbol) {
X kc = XKeysymToKeycode(dpy, ks);
X
X if (kc == 0)
X return 0;
X else
X return FindModifierMask(kc);
X }
X
X /*
X * It's not a valid keysym name, so try a bunch of aliases. First,
X * Allow "mod1" ... "mod5" as synonyms for Mod1Mask ... Mod5Mask.
X */
X
X if (1 == sscanf(word, "mod%d", &modnum) &&
X modnum >= 1 && modnum <= 5)
X {
X return (1 << (Mod1MapIndex + modnum - 1));
X }
X
X /* look through the alias table for masks or keysyms */
X
X kc = 0;
X for (ksa = KeysymAliasTable; ksa < KeysymAliasTable + NUMALIASES;
X ++ksa)
X {
X if (0 == strcmp(word, ksa->alias)) {
X if (ksa->mask != 0)
X return ksa->mask;
X
X kc = XKeysymToKeycode(dpy, ksa->sym1);
X
X if (kc == 0)
X kc = XKeysymToKeycode(dpy, ksa->sym2);
X
X if (kc == 0)
X return 0;
X else
X return FindModifierMask(kc);
X }
X }
X
X return 0;
X}
X
X
X/*
X * Parses a comma-separated string into words, gets the modifier mask for
X * each, ORs them together and returns the result.
X */
Xunsigned int
XpolyStringToModifier(dpy, str)
X Display *dpy;
X char *str;
X{
X char buf[200];
X unsigned int result = 0;
X char *word;
X
X /* make a copy first, because strtok riddles the string with nulls. */
X strcpy(buf, str);
X word = strtok(buf, ",");
X while (word != NULL) {
X result |= stringToModifier(dpy, word);
X word = strtok(NULL, ",");
X }
X return result;
X}
X
X
X#define MAX_MAPPINGS 6
X
X/*
X * Parses a key specification of the form
X * keymod[,keymod[,...]]
X * where keymod is
X * keysym[+modifier[+...]]
X */
Xstatic int
XparseKeySpec(dpy, specifier, syms)
X char *specifier;
X modsym *syms;
X{
X char spec[200];
X char *mapping[MAX_MAPPINGS];
X char *keysym_string, *mod_string;
X KeySym keysym;
X int k;
X int modmask, newmod;
X int nbound = 0;
X char buffer[200];
X
X /* make a copy first, because strtok riddles the string with nulls. */
X strcpy(spec, specifier);
X
X /* break apart comma-separated mappings */
X mapping[0] = strtok(spec, ",");
X for (k = 1; k < MAX_MAPPINGS; ++k) {
X mapping[k] = strtok(NULL, ",");
X if (mapping[k] == NULL)
X break;
X }
X
X /* for each mapping, break into keysym and modifier components */
X for (k = 0; k < MAX_MAPPINGS && mapping[k]; ++k) {
X keysym_string = strtok(mapping[k], "+");
X if (!keysym_string) {
X (void) sprintf(buffer, gettext("bad key mapping `%s'\n"),
X mapping[k]);
X ErrorWarning(buffer);
X continue;
X }
X keysym = XStringToKeysym(keysym_string);
X if (keysym == NoSymbol) {
X (void) sprintf(buffer, gettext("can't find keysym for `%s'\n"),
X keysym_string);
X ErrorWarning(buffer);
X continue;
X }
X
X /*
X * If the keysym is upper case alphabetic, add a shift mask. If it's
X * lower case, convert it to upper case.
X */
X modmask = 0;
X if (XK_A <= keysym && keysym <= XK_Z)
X modmask = ShiftMask;
X if (XK_a <= keysym && keysym <= XK_z)
X keysym -= (XK_a - XK_A);
X
X while (1) {
X mod_string = strtok(NULL, "+");
X if (!mod_string)
X break;
X newmod = stringToModifier(dpy, mod_string);
X if (newmod == 0) {
X /*
X * We couldn't find a modifier; ignore this binding. We can't
X * use continue, because we want to continue an outer loop.
X */
X goto nobinding;
X }
X modmask |= newmod;
X }
X syms[nbound].sym = keysym;
X syms[nbound].mod = modmask;
X ++nbound;
X nobinding: ;
X } /* for each mapping */
X return nbound;
X}
X
X
X/*
X * Run through the table of key descriptors and establish key bindings for
X * each descriptor. First, the resource database is probed for a customized
X * key binding specification. If one isn't found, the default key binding
X * specification is used. Then, this specification is parsed into an array of
X * keysym/modifier pairs. For each pair, the keyboard mapping table is
X * searched for the keysym and an entry is made into the binding table for
X * each instance of the keysym in the mapping table. Thus, if a keysym
X * appears on more than one keystation, a key binding entry is created for
X * each.
X *
X * If a resource is found, it is always used. If no resource is found, the
X * default specification is used only if the current mouseless setting has
X * this binding enabled. So, setting mouseless to Basic or SunView will
X * disable most key bindings. However, if you add a specific resource, it
X * will always be honored.
X */
Xstatic void
XestablishKeyBindings(dpy)
X Display *dpy;
X{
X KeyDescriptor *d;
X KeyBinding *kb;
X modsym syms[MAX_MAPPINGS];
X int nsyms;
X int i, j;
X int keytblsize = (MaxKeyCode-MinKeyCode+1) * KeySymsPerKeyCode;
X XrmQuark classlist[4], namelist[4];
X XrmQuark rep;
X XrmValue value;
X char *keyspec;
X unsigned long mask;
X
X classlist[1] = kbdCmdClassQ;
X classlist[3] = NULLQUARK;
X
X namelist[0] = TopInstanceQ;
X namelist[1] = kbdCmdInstanceQ;
X namelist[3] = NULLQUARK;
X
X mask = mouselessMaskTable[GRV.Mouseless];
X
X for (d=KeyDescriptorTable; d < KeyDescriptorTable+NUMKEYDESCRIPTORS;
X ++d) {
X classlist[0] = OpenWinQ;
X classlist[2] = namelist[2] = XrmStringToQuark(d->rsrc_name);
X if (XrmQGetResource(OlwmDB, namelist, classlist, &rep, &value)) {
X keyspec = (char *) value.addr;
X } else {
X /*
X * Use olwm binding; see resources.c
X */
X classlist[0] = OlwmQ;
X if (XrmQGetResource(OlwmDB, namelist, classlist, &rep, &value))
X keyspec = (char *) value.addr;
X else if (mask & d->flags)
X keyspec = d->dflt_binding;
X else
X continue;
X }
X nsyms = parseKeySpec(dpy, keyspec, syms);
X for (i=0; i<nsyms; ++i) {
X for (j=0; j<keytblsize; ++j) {
X if (KbdMap[j] == syms[i].sym) {
X AddKeyBinding(j/KeySymsPerKeyCode+MinKeyCode, syms[i].mod, d);
X j += KeySymsPerKeyCode - (j % KeySymsPerKeyCode) - 1;
X }
X }
X }
X }
X}
X
X
X/*
X * Issue or release passive grabs for the necessary keys on this particular
X * root window. Run through the binding table and un/grab the key-modifier
X * combination itself, and also combined with the Lock and NumLock (if any)
X * modifier. There thus may be up to four actual grabs per key binding.
X */
Xstatic void
XgrabRootKeys(dpy, root, grab)
X Display *dpy;
X Window root;
X Bool grab; /* True = grab, False = release */
X{
X KeyBinding *k;
X unsigned int NumLockMask =
X FindModifierMask(XKeysymToKeycode(dpy, XK_Num_Lock));
X for (k=KeyBindingTable; k < KeyBindingTable+bindingTableCount; ++k) {
X if (k->desc->function != NULLFUNC) {
X if (grab) {
X XGrabKey(dpy, k->keycode, k->modstate,
X root, False, GrabModeAsync, GrabModeSync);
X XGrabKey(dpy, k->keycode, k->modstate | LockMask,
X root, False, GrabModeAsync, GrabModeSync);
X } else {
X XUngrabKey(dpy, k->keycode, k->modstate, root);
X XUngrabKey(dpy, k->keycode, k->modstate|LockMask, root);
X }
X if (NumLockMask != 0) {
X if (grab) {
X XGrabKey(dpy, k->keycode, k->modstate | NumLockMask,
X root, False, GrabModeAsync, GrabModeSync);
X XGrabKey(dpy, k->keycode,
X k->modstate | NumLockMask | LockMask,
X root, False, GrabModeAsync, GrabModeSync);
X } else {
X XUngrabKey(dpy, k->keycode, k->modstate | NumLockMask,
X root);
X XUngrabKey(dpy, k->keycode,
X k->modstate | NumLockMask | LockMask, root);
X }
X }
X }
X }
X}
X
X
X/*
X * Issue or release passive button grabs on this root window. Like
X * grabRootKeys, has to deal with Lock and NumLock by issuing up to four
X * separate grabs. Note: these are synchronous grabs. This relies on the
X * root event handler to issue an AllowEvents or GrabPointer request.
X */
Xstatic void
XgrabRootButtons(dpy, root, grab)
X Display *dpy;
X Window root;
X Bool grab; /* True = grab, False = release */
X{
X unsigned int NumLockMask =
X FindModifierMask(XKeysymToKeycode(dpy, XK_Num_Lock));
X unsigned int eventmask =
X ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
X
X if (ModMaskMap[MOD_WMGRAB] != 0) {
X if (grab) {
X XGrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB],
X root, False, eventmask,
X GrabModeSync, GrabModeSync, None, None);
X XGrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB] | LockMask,
X root, False, eventmask,
X GrabModeSync, GrabModeSync, None, None);
X } else {
X XUngrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB],
X root);
X XUngrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB] | LockMask,
X root);
X }
X
X if (NumLockMask != 0) {
X if (grab) {
X XGrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB] | NumLockMask,
X root, False, eventmask,
X GrabModeSync, GrabModeSync, None, None);
X XGrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB] | LockMask | NumLockMask,
X root, False, eventmask,
X GrabModeSync, GrabModeSync, None, None);
X } else {
X XUngrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB] | NumLockMask,
X root);
X XUngrabButton(dpy, AnyButton,
X ModMaskMap[MOD_WMGRAB] | LockMask | NumLockMask,
X root);
X }
X }
X }
X}
X
X
X/* ===== public functions ================================================= */
X
X
X/*
X * Given a keyboard event, looks it up in the keyboard binding table. If a
X * binding is found, returns the semantic action associated with that key. If
X * no binding is found, returns ACTION_NONE.
X */
X
XSemanticAction
XFindKeyboardAction(dpy, event)
X Display *dpy;
X XEvent *event;
X{
X KeyBinding *k;
X SemanticAction a = ACTION_NONE;
X unsigned long ignore = ModMaskMap[MOD_IGNORE] | AnyButtonMask;
X
X for (k=KeyBindingTable; k < KeyBindingTable+bindingTableCount; ++k) {
X if (k->keycode == event->xkey.keycode
X && k->modstate == (event->xkey.state & ~ignore)) {
X a = k->desc->action;
X break;
X }
X }
X return a;
X}
X
X/*
X * Keyboard actions added by olvwmrc are at the end of the list, but they
X * should take precedence over previous ones. So this function does a
X * similar search as above but starts at the end.
X */
XSemanticAction
XFindNewKeyboardAction(dpy, event)
X Display *dpy;
X XEvent *event;
X{
X KeyBinding *k;
X SemanticAction a = ACTION_NONE;
X unsigned long ignore = ModMaskMap[MOD_IGNORE] | AnyButtonMask;
X
X for (k=KeyBindingTable+bindingTableCount-1; k >= KeyBindingTable; --k) {
X if (k->keycode == event->xkey.keycode
X && k->modstate == (event->xkey.state & ~ignore)) {
X a = k->desc->action;
X break;
X }
X }
X return a;
X}
X
X
X/*
X * Given a keyboard event, looks it up in the keyboard binding table.
X * If a binding is found, executes the function bound to that key. Returns
X * True if a function was found and called, otherwise False.
X */
XBool
XExecuteKeyboardFunction(dpy, event)
X Display *dpy;
X XEvent *event;
X{
X KeyBinding *k;
X void (*f)() = NULLFUNC;
X unsigned long ignore = ModMaskMap[MOD_IGNORE] | AnyButtonMask;
X
X for (k=KeyBindingTable; k < KeyBindingTable+bindingTableCount; ++k) {
X if (k->keycode == event->xkey.keycode
X && k->modstate == (event->xkey.state & ~ignore)
X && k->desc->function != NULLFUNC) {
X f = k->desc->function;
X break;
X }
X }
X
X /* If the user pressed the STOP key, clear active key. */
X
X if (f == NULLFUNC) {
X if (FindKeyboardAction(dpy, event) == ACTION_STOP)
X activeKey = NULL;
X XAllowEvents(dpy, AsyncKeyboard, event->xkey.time);
X return False;
X }
X
X /* invariant: k points to a valid key binding */
X
X#ifdef notdef
X /*
X * On the first keypress, stash the active key binding; ignore subsequent
X * keypresses. Ignore all key releases except the one corresponding to
X * the active binding.
X */
X if (event->type == KeyPress) {
X if (activeKey == NULL)
X activeKey = k;
X else
X return False;
X } else { /* KeyRelease */
X if (k == activeKey)
X activeKey = NULL;
X else
X return False; /* ignore it */
X }
X#endif
X
X if (suspended && !(k->desc->flags & KD_IMMUNE)) {
X XAllowEvents(dpy, ReplayKeyboard, event->xkey.time);
X return True;
X }
X
X if (quotenext) {
X XAllowEvents(dpy, ReplayKeyboard, event->xkey.time);
X quotenext = False;
X return True;
X }
X
X if (event->type == KeyPress)
X XAllowEvents(dpy, AsyncKeyboard, event->xkey.time);
X
X (*f)(dpy, event);
X return True;
X}
X
X
X/* ===== Initialization =================================================== */
X
X/*
X * Deal with key grabs on all root windows. If grab = True, grab the keys; if
X * grab = False, release the keys. Note: the screens and the keyboard binding
X * information must be initialized prior to calling this function.
X */
Xvoid
XGrabKeys(dpy, grab)
X Display *dpy;
X Bool grab;
X{
X List *l = ScreenInfoList;
X ScreenInfo *scr;
X for (scr = ListEnum(&l); scr != NULL; scr = ListEnum(&l))
X grabRootKeys(dpy, scr->rootid, grab);
X}
X
X
X/*
X * Remove all key grabs, zero out the binding table, and rebuild it from the
X * resource database. Then, re-establish key grabs.
X */
Xvoid
XRefreshKeyGrabs(dpy)
X Display *dpy;
X{
X GrabKeys(dpy, False);
X bindingTableCount = 0;
X establishKeyBindings(dpy);
X ReInitOlvwmRC(dpy);
X GrabKeys(dpy, True);
X}
X
X
X/*
X * Deal with button grabs on all root windows. If grab = True, grab the
X * buttons; if grab = False, release them.
X */
Xvoid
XGrabButtons(dpy, grab)
X Display *dpy;
X Bool grab;
X{
X List *l = ScreenInfoList;
X ScreenInfo *scr;
X
X for (scr = ListEnum(&l); scr != NULL; scr = ListEnum(&l))
X grabRootButtons(dpy, scr->rootid, grab);
X}
X
X
X/*
X * Remove all button grabs, regenerate the modifier mask table, and
X * re-establish the button grabs.
X */
Xvoid
XRefreshButtonGrabs(dpy)
X Display *dpy;
X{
X GrabButtons(dpy, False);
X establishModBindings(dpy, OlwmDB);
X GrabButtons(dpy, True);
X}
X
X
X/*
X * Update all bindings from a new resource database. Called whenever the
X * resource database changes.
X */
Xvoid
XUpdateBindings(dpy, newDB)
X Display *dpy;
X XrmDatabase newDB;
X{
X KeyDescriptor *d;
X XrmQuark classlist[4], instlist[4];
X XrmQuark rep;
X XrmValue newvalue, oldvalue;
X Bool regrab = False;
X static XrmBinding bindings[] =
X { XrmBindTightly, XrmBindTightly, XrmBindTightly };
X
X GrabButtons(dpy, False);
X establishModBindings(dpy, newDB);
X GrabButtons(dpy, True);
X
X /* run through the KeyDescriptorTable and probe resources */
X
X classlist[0] = OpenWinQ;
X classlist[1] = kbdCmdClassQ;
X classlist[3] = NULLQUARK;
X
X instlist[0] = TopInstanceQ;
X instlist[1] = kbdCmdInstanceQ;
X instlist[3] = NULLQUARK;
X
X for (d=KeyDescriptorTable; d < KeyDescriptorTable+NUMKEYDESCRIPTORS;
X ++d) {
X
X classlist[2] = instlist[2] = XrmStringToQuark(d->rsrc_name);
X
X if (XrmQGetResource(newDB, instlist, classlist, &rep, &newvalue)) {
X if (XrmQGetResource(OlwmDB, instlist, classlist, &rep, &oldvalue) &&
X 0 == strcmp((char *) newvalue.addr, (char *) oldvalue.addr))
X {
X /* old and new values the same; ignore */
X continue;
X }
X
X regrab = True;
X XrmQPutStringResource(&OlwmDB, bindings, instlist,
X (char *) newvalue.addr);
X }
X else {
X /*
X * Use olwm binding; see resources.c
X */
X classlist[0] = OlwmQ;
X if (XrmQGetResource(newDB, instlist, classlist, &rep, &newvalue)) {
X if (XrmQGetResource(OlwmDB, instlist, classlist,
X &rep, &oldvalue) &&
X 0 == strcmp((char *) newvalue.addr, (char *) oldvalue.addr))
X {
X /* old and new values the same; ignore */
X classlist[0] = OpenWinQ;
X continue;
X }
X
X regrab = True;
X XrmQPutStringResource(&OlwmDB, bindings, instlist,
X (char *) newvalue.addr);
X classlist[0] = OpenWinQ;
X }
X }
X }
X
X if (regrab)
X RefreshKeyGrabs(dpy);
X}
X
X
X/*
X * Initialize the event handling system, but don't do any key grabbing. This
X * function is called exactly *once* at startup.
X */
Xvoid
XInitBindings(dpy)
X Display *dpy;
X{
X kbdCmdInstanceQ = XrmStringToQuark("keyboardCommand");
X kbdCmdClassQ = XrmStringToQuark("KeyboardCommand");
X
X modInstanceQ = XrmStringToQuark("modifier");
X modClassQ = XrmStringToQuark("Modifier");
X
X KeyBindingTable = MemCalloc(KEYBINDING_TABLE_SIZE,sizeof(KeyBinding));
X bindingTableSize = KEYBINDING_TABLE_SIZE;
X establishKeyBindings(dpy);
X establishModBindings(dpy, OlwmDB);
X}
END_OF_FILE
if test 38223 -ne `wc -c <'evbind.c'`; then
echo shar: \"'evbind.c'\" unpacked with wrong size!
fi
# end of 'evbind.c'
fi
if test -f 'winpane.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'winpane.c'\"
else
echo shar: Extracting \"'winpane.c'\" \(12706 characters\)
sed "s/^X//" >'winpane.c' <<'END_OF_FILE'
X/*
X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents
X * pending in the U.S. and foreign countries. See LEGAL_NOTICE
X * file for terms of the license.
X */
X
X#ident "@(#)winpane.c 1.1 olvwm version 1/3/92"
X
X/*
X * Based on
X#ident "@(#)winpane.c 26.14 91/09/14 SMI"
X *
X */
X
X#include <errno.h>
X#include <stdio.h>
X#include <X11/Xos.h>
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/Xatom.h>
X#include <olgx/olgx.h>
X
X#include "i18n.h"
X#include "ollocale.h"
X#include "mem.h"
X#include "olwm.h"
X#include "win.h"
X#include "globals.h"
X
X/***************************************************************************
X* global data
X***************************************************************************/
X
Xextern Atom AtomChangeState;
Xextern Atom AtomColorMapWindows;
Xextern Atom AtomOlwmTimestamp;
Xextern Window NoFocusWin;
Xextern void ColormapChange();
X
X/***************************************************************************
X* private data
X***************************************************************************/
X
X/* border width for reparented windows */
X#define NORMAL_BORDERWIDTH 0
X
Xstatic ClassPane classPane;
X
X/***************************************************************************
X* private functions
X***************************************************************************/
X
X/*
X * eventEnterLeaveNotify - The pointer has entered or left the window
X */
Xstatic int
XeventEnterLeaveNotify(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPane *winInfo;
X{
X if (event->xany.type == EnterNotify)
X ColorWindowCrossing(dpy, event, winInfo);
X}
X
X/*
X * eventColormapNotify
X *
X * Handle changes to this window's colormap attribute.
X */
Xstatic int
XeventColormapNotify(dpy, event, winInfo)
X Display *dpy;
X XEvent *event;
X WinPane *winInfo;
X{
X ColormapChange(dpy, event, (WinGeneric *)winInfo);
X}
X
X/*
X * eventUnmapNotify - the client is transitioning to withrdrawn
X */
Xstatic int
XeventUnmapNotify(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPane *winInfo;
X{
X if (winInfo->pcore.pendingUnmaps > 0)
X {
X --winInfo->pcore.pendingUnmaps;
X }
X else
X {
X /* Mark current state */
X StateWithdrawn(winInfo->core.client);
X }
X}
X
X
X/*
X * eventDestroyNotify - the pane window has disappeared
X * This function can get called either during new state processing,
X * or while app is iconic
X */
Xstatic int
XeventDestroyNotify(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPane *winInfo;
X{
X StateWithdrawn(winInfo->core.client);
X}
X
X
X/*
X * eventPropertyNotify - handle client messages, in particular iconic requests
X */
Xstatic int
XeventPropertyNotify(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPane *winInfo;
X{
X ClientDistributeProperty(winInfo->core.client,event);
X}
X
X/*
X * eventClientMessage - handle client messages, in particular iconic requests
X */
Xstatic int
XeventClientMessage(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPane *winInfo;
X{
X Client *cli = winInfo->core.client;
X
X if (event->xclient.message_type == AtomChangeState)
X {
X if (event->xclient.data.l[0] == IconicState)
X StateNormIcon(cli);
X }
X}
X
X
X/*
X * eventExtension - handle extension events
X */
Xstatic int
XeventExtension(dpy, event, winInfo)
X Display *dpy;
X XEvent *event;
X WinPane *winInfo;
X{
X#ifdef SHAPE
X XShapeEvent *se;
X Client *cli;
X
X if (event->xany.type == ShapeEventBase) {
X /* it's a ShapeNotify event */
X se = (XShapeEvent *) event;
X if (se->kind != ShapeBounding)
X return;
X cli = winInfo->core.client;
X
X FrameUpdateShape(cli, cli->framewin);
X }
X#endif /* SHAPE */
X}
X
X
X/*
X * drawPane -- draw the pane window
X */
X/*ARGSUSED*/ /* dpy arg will be used when multiple Displays supported */
Xstatic int
XdrawPane(dpy, winInfo)
XDisplay *dpy;
XWinGeneric *winInfo;
X{
X}
X
X
X/*
X * focusPane -- handle focus change
X */
Xstatic int
XfocusPane(dpy, winInfo, focus)
XDisplay *dpy;
XWinGeneric *winInfo;
XBool focus;
X{
X}
X
X/*
X * DestroyPane -- destroy the pane window resources and free any allocated
X * data.
X */
Xstatic int
XdestroyPane(dpy, winInfo)
XDisplay *dpy;
XWinGeneric *winInfo;
X{
X /* free our data and throw away window */
X WIUninstallInfo(winInfo->core.self);
X MemFree(winInfo);
X}
X
X/*
X * setconfigPane -- change configuration of pane window
X */
X/*ARGSUSED*/ /* dpy arg will be used when multiple Displays supported */
Xstatic int
XsetconfigPane(dpy, winInfo)
XDisplay *dpy;
XWinPane *winInfo;
X{
X XConfigureEvent ce;
X XWindowChanges xwc;
X
X if (winInfo->core.dirtyconfig)
X {
X xwc.x = winInfo->core.x;
X xwc.y = winInfo->core.y;
X xwc.width = winInfo->core.width;
X xwc.height = winInfo->core.height;
X ConfigureWindow(dpy, winInfo,
X winInfo->core.dirtyconfig, &xwc);
X winInfo->core.dirtyconfig &= ~(CWX|CWY|CWWidth|CWHeight);
X }
X
X /* send synthetic configure notify in root coordinates */
X ce.type = ConfigureNotify;
X ce.serial = 0L;
X ce.event = winInfo->core.self;
X ce.window = winInfo->core.self;
X WinRootPos(winInfo,&ce.x,&ce.y);
X ce.x -= winInfo->pcore.oldBorderWidth;
X ce.y -= winInfo->pcore.oldBorderWidth;
X ce.width = winInfo->core.width;
X ce.height = winInfo->core.height;
X ce.border_width = winInfo->pcore.oldBorderWidth;
X ce.above = None;
X ce.override_redirect = False;
X
X XSendEvent(dpy, winInfo->core.self, False,
X StructureNotifyMask, (XEvent *)&ce);
X}
X
X
X/*
X * newconfigPane - compute a new configuration given an event
X * Note: this function must *always* be called with a configure request
X * event.
X */
Xstatic int
XnewconfigPane(win, pxcre)
XWinPane *win;
XXConfigureRequestEvent *pxcre;
X{
X int oldWidth, oldHeight;
X Client *cli = win->core.client;
X int oldX, oldY;
X WinPaneFrame *winFrame = cli->framewin;
X void FrameMoveRelative();
X int dwidth, dheight;
X
X if (pxcre == NULL)
X return win->core.dirtyconfig;
X
X WinRootPos(win, &oldX, &oldY);
X oldWidth = win->core.width;
X oldHeight = win->core.height;
X
X if ((pxcre->value_mask & CWHeight) && (pxcre->height != oldHeight))
X {
X win->core.height = pxcre->height;
X win->core.dirtyconfig |= CWHeight;
X }
X
X if ((pxcre->value_mask & CWWidth) && (pxcre->width != oldWidth))
X {
X win->core.width = pxcre->width;
X win->core.dirtyconfig |= CWWidth;
X }
X
X if (pxcre->value_mask & CWBorderWidth)
X {
X win->pcore.oldBorderWidth = pxcre->border_width;
X }
X
X if (pxcre->value_mask & (CWX | CWY))
X {
X FrameSetPosAbsolute(winFrame,
X (pxcre->value_mask & CWX)?(pxcre->x):oldX,
X (pxcre->value_mask & CWY)?(pxcre->y):oldY);
X }
X else
X {
X dwidth = oldWidth - win->core.width;
X dheight = oldHeight - win->core.height;
X if ((dwidth != 0) || (dheight!=0))
X {
X switch (cli->normHints->win_gravity)
X {
X case NorthWestGravity:
X break;
X case NorthGravity:
X FrameMoveRelative(winFrame,dwidth/2,0);
X break;
X case NorthEastGravity:
X FrameMoveRelative(winFrame,dwidth,0);
X break;
X case WestGravity:
X FrameMoveRelative(winFrame,0,dheight/2);
X break;
X case CenterGravity:
X FrameMoveRelative(winFrame,dwidth/2,dheight/2);
X break;
X case EastGravity:
X FrameMoveRelative(winFrame,dwidth,dheight/2);
X break;
X case SouthWestGravity:
X FrameMoveRelative(winFrame,0,dheight);
X break;
X case SouthGravity:
X FrameMoveRelative(winFrame,dwidth/2,dheight);
X break;
X case SouthEastGravity:
X FrameMoveRelative(winFrame,dwidth,dheight);
X break;
X }
X }
X }
X
X
X if (pxcre->value_mask & (CWStackMode | CWSibling))
X {
X GFrameSetStack(winFrame, pxcre->value_mask, pxcre->detail, pxcre->above);
X }
X
X return win->core.dirtyconfig;
X}
X
X/*
X * newposPane - move to a given position (relative to parent)
X */
Xstatic int
XnewposPane(win,x,y)
XWinPane *win;
Xint x, y;
X{
X if (win->core.x != x)
X {
X win->core.x = x;
X win->core.dirtyconfig |= CWX;
X }
X
X if (win->core.y != y)
X {
X win->core.y = y;
X win->core.dirtyconfig |= CWY;
X }
X
X return win->core.dirtyconfig;
X}
X
X/*
X * setsizePane - set the pane to a particular size, and initiate a reconfigure
X */
Xstatic int
XsetsizePane(win,w,h)
XWinPane *win;
Xint w, h;
X{
X if (win->core.width != w)
X {
X win->core.width = w;
X win->core.dirtyconfig |= CWWidth;
X }
X
X if (win->core.height != h)
X {
X win->core.height = h;
X win->core.dirtyconfig |= CWHeight;
X }
X}
X
X/***************************************************************************
X* global functions
X***************************************************************************/
X
X/*
X * MakePane -- create the pane window. Return a WinGeneric structure.
X */
XWinPane *
XMakePane(cli,par,win,paneattrs)
XClient *cli;
XWinGeneric *par;
XWindow win;
XXWindowAttributes *paneattrs;
X{
X WinPane *w;
X XSetWindowAttributes attributes;
X long mask;
X WinColormap *colorwin;
X
X /* this window may already be mentioned as a colourmap window.
X * grab its colourmap window structure, and unhook it from the
X * event dispatching table so we can register a new structure
X * for the window. We will call another function at the end
X * of pane processing to re-establish the relation between this
X * window and other structures in the system.
X */
X colorwin = ColormapUnhook(win);
X
X /* create the associated structure */
X w = MemNew(WinPane);
X w->core.self = win;
X w->class = &classPane;
X w->core.kind = WIN_PANE;
X WinAddChild(par,w);
X w->core.children = NULL;
X w->core.client = cli;
X w->core.x = 0; /* gets fixed up later */
X w->core.y = 0; /* gets fixed up later */
X w->core.width = paneattrs->width;
X w->core.height = paneattrs->height;
X w->core.colormap = paneattrs->colormap;
X w->core.dirtyconfig = CWX|CWY|CWWidth|CWHeight;
X w->core.exposures = NULL;
X w->pcore.oldBorderWidth = paneattrs->border_width;
X w->pcore.oldSaveUnder = paneattrs->save_under;
X w->core.helpstring = (char *)NULL; /* no help */
X
X cli->framewin->fcore.panewin = (WinGenericPane *)w;
X
X /* register the window */
X WIInstallInfo(w);
X
X /* Put the window in the save set so it doesn't go away */
X XChangeSaveSet(cli->dpy,win,SetModeInsert);
X
X /*
X * Since the pane is reparented, save-unders are not useful.
X * In the code above the save-under attribute is propogated to
X * the frame, so it is safe to remove it here. But don't do this for
X * InputOnly windows.
X */
X if (paneattrs->class == InputOutput) {
X attributes.save_under = False;
X XChangeWindowAttributes(cli->dpy, win,
X (unsigned long) CWSaveUnder, &attributes);
X
X /*
X * Change the border width if necessary. The border width of
X * InputOnly windows is zero by definition.
X */
X if (paneattrs->border_width != NORMAL_BORDERWIDTH)
X XSetWindowBorderWidth(cli->dpy, win, NORMAL_BORDERWIDTH);
X }
X
X /*
X * Focus Lenience. Be lenient about enforcing the requirement that
X * clients set the input hint in WM_HINTS before they can get keyboard
X * input. If this flag is set, and if the focus mode is NoInput, then
X * force the mode to be passive. This way, if a client either fails
X * to set the WM_HINTS.input field, or fails to write WM_HINTS at all,
X * it can still get keyboard input.
X *
X * REMIND This kind of flag should be implemented on a
X * client-by-client basis, not on a global basis.
X */
X if (GRV.FocusLenience && cli->focusMode == NoInput ) {
X cli->focusMode = Passive;
X }
X
X /* Reparent the pane */
X XReparentWindow(cli->dpy, win, par->core.self,
X w->core.x, w->core.y);
X
X /* we may have saved colourmap manipulation information at
X * the beginning. Re-establish the connection between this window
X * and other structures based on the old structure.
X */
X ColormapTransmogrify(colorwin, w);
X
X return w;
X}
X
X/*
X * PaneInit -- initialise the Pane class function vector
X */
Xvoid
XPaneInit(dpy)
XDisplay *dpy;
X{
X classPane.core.kind = WIN_PANE;
X classPane.core.xevents[EnterNotify] = eventEnterLeaveNotify;
X classPane.core.xevents[LeaveNotify] = eventEnterLeaveNotify;
X classPane.core.xevents[ColormapNotify] = eventColormapNotify;
X classPane.core.xevents[UnmapNotify] = eventUnmapNotify;
X classPane.core.xevents[DestroyNotify] = eventDestroyNotify;
X classPane.core.xevents[PropertyNotify] = eventPropertyNotify;
X classPane.core.xevents[ClientMessage] = eventClientMessage;
X classPane.core.extEventHdlr = eventExtension;
X classPane.core.focusfunc = focusPane;
X classPane.core.drawfunc = NULL;
X classPane.core.destroyfunc = destroyPane;
X classPane.core.selectfunc = NULL;
X classPane.core.newconfigfunc = newconfigPane;
X classPane.core.newposfunc = newposPane;
X classPane.core.setconfigfunc = setconfigPane;
X classPane.core.createcallback = NULL;
X classPane.core.heightfunc = NULL;
X classPane.core.widthfunc = NULL;
X classPane.pcore.setsizefunc = setsizePane;
X}
END_OF_FILE
if test 12706 -ne `wc -c <'winpane.c'`; then
echo shar: \"'winpane.c'\" unpacked with wrong size!
fi
# end of 'winpane.c'
fi
echo shar: End of archive 6 \(of 21\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 21 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Molecular Simulations, Inc. mail: dcmartin@postgres.berkeley.edu
796 N. Pastoria Avenue uucp: uwvax!ucbvax!dcmartin
Sunnyvale, California 94086 at&t: 408/522-9236