home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume15 / olvwm-3.0 / part06 < prev    next >
Internet Message Format  |  1992-02-03  |  57KB

  1. Path: uunet!sun-barr!ames!pasteur!nntp
  2. From: scott.oaks@East.Sun.COM (Scott Oaks)
  3. Newsgroups: comp.sources.x
  4. Subject: v15i152: OpenLook Virtual Window Mgr (3.0), Part06/21
  5. Message-ID: <1992Feb4.135555.7121@pasteur.Berkeley.EDU>
  6. Date: 4 Feb 92 13:55:55 GMT
  7. References: <csx-15i147-olvwm-3.0@uunet.UU.NET>
  8. Sender: dcmartin@msi.com (David C. Martin - Moderator)
  9. Organization: University of California, at Berkeley
  10. Lines: 2006
  11. Approved: dcmartin@msi.com
  12. Nntp-Posting-Host: postgres.berkeley.edu
  13.  
  14. Submitted-by: scott.oaks@East.Sun.COM (Scott Oaks)
  15. Posting-number: Volume 15, Issue 152
  16. Archive-name: olvwm-3.0/part06
  17.  
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  22. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  23. # If this archive is complete, you will see the following message at the end:
  24. #        "End of archive 6 (of 21)."
  25. # Contents:  defaults.h evbind.c winpane.c
  26. # Wrapped by dcmartin@fascet on Tue Jan 14 05:54:43 1992
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'defaults.h' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'defaults.h'\"
  30. else
  31. echo shar: Extracting \"'defaults.h'\" \(771 characters\)
  32. sed "s/^X//" >'defaults.h' <<'END_OF_FILE'
  33. X/*
  34. X *      (c) Copyright 1990 Sun Microsystems, Inc. Sun design patents
  35. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  36. X *      file for terms of the license.
  37. X */
  38. X
  39. X#ident    "@(#)defaults.h    1.1 olvwm version 1/3/92"
  40. X
  41. X/*
  42. X * Based on
  43. X#ident    "@(#)defaults.h    26.7    91/09/14 SMI"
  44. X *
  45. X */
  46. X
  47. X/* 
  48. X *    default constants 
  49. X */
  50. X#define DEFWORKSPACECOLOR        "#40a0c0"
  51. X#define DEFWINDOWCOLOR        "#cccccc"
  52. X#define DEFFOREGROUNDCOLOR        "#000000"
  53. X#define DEFBACKGROUNDCOLOR        "#ffffff"
  54. X#define DEFBORDERCOLOR        "#000000"
  55. X
  56. X#define DEFVIRTUALFORECOLOR    "#cccccc"
  57. X#define DEFVIRTUALBACKCOLOR    "#40a0c0"
  58. X#define DEFVIRTUALFONTCOLOR    "#ffffff"
  59. X#define DEFVIRTUALGRIDCOLOR    "#ffffff"
  60. X#define DEFVIRTUALPIXMAPCOLOR    "#000000"
  61. X
  62. X#define DEFAULTFONT        "9x15"
  63. X
  64. Xvoid    SetAllDBValues();
  65. END_OF_FILE
  66. if test 771 -ne `wc -c <'defaults.h'`; then
  67.     echo shar: \"'defaults.h'\" unpacked with wrong size!
  68. fi
  69. # end of 'defaults.h'
  70. fi
  71. if test -f 'evbind.c' -a "${1}" != "-c" ; then 
  72.   echo shar: Will not clobber existing file \"'evbind.c'\"
  73. else
  74. echo shar: Extracting \"'evbind.c'\" \(38223 characters\)
  75. sed "s/^X//" >'evbind.c' <<'END_OF_FILE'
  76. X/*
  77. X *      (c) Copyright 1991 Sun Microsystems, Inc. Sun design patents
  78. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  79. X *      file for terms of the license.
  80. X */
  81. X
  82. X#ident    "@(#)evbind.c    1.1 olvwm version 1/3/92"
  83. X
  84. X/*
  85. X * Based on
  86. X#ident    "@(#)evbind.c    1.21    91/09/14 SMI"
  87. X *
  88. X */
  89. X
  90. X#include <errno.h>
  91. X#include <stdio.h>
  92. X#include <string.h>
  93. X#include <sys/types.h>
  94. X#include <sys/time.h>
  95. X
  96. X#include <X11/Xlib.h>
  97. X#include <X11/Xutil.h>
  98. X#include <X11/keysym.h>
  99. X
  100. X#include "i18n.h"
  101. X#include "ollocale.h"
  102. X#include "olwm.h"
  103. X#include "win.h"
  104. X#include "globals.h"
  105. X#include "events.h"
  106. X#include "list.h"
  107. X#include "mem.h"
  108. X#include "kbdfuncs.h"
  109. X#include "resources.h"
  110. X
  111. X
  112. X/* ===== externs ========================================================== */
  113. X
  114. Xextern List *ScreenInfoList;
  115. X
  116. X/* ===== private data ===================================================== */
  117. X
  118. Xstatic XrmQuark kbdCmdInstanceQ;
  119. Xstatic XrmQuark kbdCmdClassQ;
  120. Xstatic XrmQuark modInstanceQ;
  121. Xstatic XrmQuark modClassQ;
  122. X
  123. X/* ===== Modifier Binding ================================================= */
  124. X
  125. X
  126. Xunsigned int ModMaskMap[MOD_MASK_COUNT];
  127. X
  128. Xtypedef struct {
  129. X    char *rsrc_name;
  130. X    char *dflt_binding;
  131. X    int mapindex;
  132. X} ModDescriptor;
  133. X
  134. XModDescriptor ModDescriptorTable[] = {
  135. X
  136. X     /*        rsrc_name        default            mapindex */
  137. X    {        "Constrain",    "Control",        MOD_CONSTRAIN    },
  138. X    {        "WMGrab",        "Alt",            MOD_WMGRAB        },
  139. X    {        "Reduce",        "Meta",            MOD_REDUCE        },
  140. X    {        "Invert",        "Shift",        MOD_INVERT        },
  141. X    {        "SetDefault",    "Control",        MOD_SETDEFAULT    },
  142. X    {        "Ignore", "Lock,Num_Lock,mod5,Mode_switch", MOD_IGNORE    }
  143. X
  144. X};
  145. X#define NMODBINDINGS (sizeof(ModDescriptorTable)/sizeof(ModDescriptor))
  146. X
  147. X
  148. X/*
  149. X * establishModBindings
  150. X *
  151. X * Read through the modifier descriptor table and fill in the modifier mask 
  152. X * map with modifier masks found in the server's modifier mask map.
  153. X */
  154. Xstatic void
  155. XestablishModBindings(dpy, newDB)
  156. X    Display *dpy;
  157. X    XrmDatabase newDB;
  158. X{
  159. X    XrmQuark classlist[4], instlist[4];
  160. X    char *s;
  161. X    XrmRepresentation rep;
  162. X    XrmValue value;
  163. X    ModDescriptor *d;
  164. X    unsigned int polyStringToModifier();
  165. X    static XrmBinding bindings[] =
  166. X    { XrmBindTightly, XrmBindTightly, XrmBindTightly };
  167. X
  168. X    classlist[0] = OpenWinQ;
  169. X    classlist[1] = modClassQ;
  170. X    classlist[3] = NULLQUARK;
  171. X
  172. X    instlist[0] = TopInstanceQ;
  173. X    instlist[1] = modInstanceQ;
  174. X    instlist[3] = NULLQUARK;
  175. X
  176. X    for (d = ModDescriptorTable; d < ModDescriptorTable + NMODBINDINGS; ++d) {
  177. X
  178. X    classlist[2] = instlist[2] = XrmStringToQuark(d->rsrc_name);
  179. X
  180. X    if (XrmQGetResource(newDB, instlist, classlist, &rep, &value))
  181. X        s = (char *) value.addr;
  182. X    else {
  183. X        /*
  184. X         * Use olwm binding -- see resources.c
  185. X         */
  186. X        classlist[0] = OlwmQ;
  187. X        if (XrmQGetResource(newDB, instlist, classlist, &rep, &value))
  188. X        s = (char *) value.addr;
  189. X        else s = d->dflt_binding;
  190. X            classlist[0] = OpenWinQ;
  191. X    }
  192. X
  193. X    ModMaskMap[d->mapindex] = polyStringToModifier(dpy, s);
  194. X    }
  195. X}
  196. X
  197. X
  198. X/* ===== Mouse Binding ==================================================== */
  199. X
  200. X
  201. X/*
  202. X * Table of mouse bindings.
  203. X *
  204. X * REMIND
  205. X * 
  206. X * At a future time, this table will be changeable via resources.  For now,
  207. X * it's specified as a compile-time constant.
  208. X */
  209. X
  210. Xtypedef struct {
  211. X    int state;
  212. X    int button;
  213. X    SemanticAction action;
  214. X} MouseBinding;
  215. X
  216. XMouseBinding MouseBindingTable[] = {
  217. X  /*  state,        button,     action         */
  218. X    { 0,        Button1, ACTION_SELECT },
  219. X    { 0,        Button2, ACTION_ADJUST },
  220. X    { 0,        Button3, ACTION_MENU   },
  221. X    { ButtonToMask(1),    Button2, ACTION_MENU },
  222. X    { ButtonToMask(2),    Button1, ACTION_MENU },
  223. X    { ShiftMask,    Button1, ACTION_ADJUST },
  224. X    { ControlMask,    Button3, ACTION_MENU }, 
  225. X    { ControlMask|ButtonToMask(1),    Button2, ACTION_MENU },
  226. X    { ControlMask|ButtonToMask(2),    Button1, ACTION_MENU },
  227. X};
  228. X#define NMOUSEBINDINGS (sizeof(MouseBindingTable)/sizeof(MouseBinding))
  229. X
  230. X
  231. X/*
  232. X * searchMouseBindings
  233. X * 
  234. X * Search the mouse binding table and return information about what was found.
  235. X * Return values of MATCH_NONE, MATCH_INCOMPLETE, and MATCH_AMBIG mean that no
  236. X * action is available for the given event.  MATCH_PREFIX and MATCH_EXACT
  237. X * indicate that an action is available; this action is returned in the area
  238. X * pointed to by the action parameter.
  239. X */
  240. Xstatic MouseMatchState
  241. XsearchMouseBindings(pe, action)
  242. X    XButtonEvent *pe;
  243. X    SemanticAction *action;
  244. X{
  245. X    int i;
  246. X    int nexact = 0;    /* number of exact matches */
  247. X    int nprefix = 0;    /* number of prefix matches */
  248. X    int lastexact = 0;    /* index of last exact match */
  249. X    unsigned int modmask = (pe->state | ButtonToMask(pe->button));
  250. X
  251. X    for (i=0; i<NMOUSEBINDINGS; ++i) {
  252. X    if (pe->state == MouseBindingTable[i].state &&
  253. X      pe->button == MouseBindingTable[i].button) {
  254. X        lastexact = i;
  255. X        ++nexact;
  256. X    } else if (modmask == MouseBindingTable[i].state) {
  257. X        ++nprefix;
  258. X    }
  259. X    }
  260. X
  261. X    if (nexact == 0 && nprefix == 0)
  262. X    return MATCH_NONE;
  263. X    if (nexact == 0 && nprefix > 0)
  264. X    return MATCH_INCOMPLETE;
  265. X    if (nexact > 1)
  266. X    return MATCH_AMBIG;
  267. X
  268. X    /* at this point, we know there is exactly one exact match */
  269. X    *action = MouseBindingTable[lastexact].action;
  270. X    if (nprefix == 0)
  271. X    return MATCH_EXACT;
  272. X    else
  273. X    return MATCH_PREFIX;
  274. X}
  275. X
  276. X
  277. X/*
  278. X * checkChording
  279. X *
  280. X * Scan the input queue for button events that will disambiguate a single
  281. X * action from a chorded action.  If there aren't any events in the queue,
  282. X * wait for them until a certain timeout period has elapsed.  Return value
  283. X * indicates whether a ButtonPress was seen further ahead in the event stream,
  284. X * which indicates that this event is part of a chorded sequence.  The timeout 
  285. X * parameter is updated with the amount of time remaining.
  286. X */
  287. Xstatic Bool
  288. XcheckChording(dpy, timeout, pr)
  289. X    Display *dpy;
  290. X    struct timeval timeout;
  291. X    XButtonEvent *pr;
  292. X{
  293. X    XEvent e;
  294. X    int n;
  295. X    
  296. X    while (1) {
  297. X    /*
  298. X     * Check for data on the connection.  Scan it for disambiguating 
  299. X     * events.  Note that MotionNotify events within the move threshold 
  300. X     * are discarded.
  301. X     */
  302. X    n = XEventsQueued(dpy, QueuedAfterReading);
  303. X    if (n > 0 && XCheckMaskEvent(dpy,
  304. X    ButtonPressMask|ButtonReleaseMask|ButtonMotionMask, &e)) {
  305. X        switch (e.type) {
  306. X        case ButtonPress:
  307. X        XPutBackEvent(dpy, &e);
  308. X        return True;
  309. X        case ButtonRelease:
  310. X        XPutBackEvent(dpy, &e);
  311. X        return False;
  312. X        case MotionNotify:
  313. X        if (ABS(pr->x_root - e.xmotion.x_root) > GRV.MoveThreshold ||
  314. X            ABS(pr->y_root - e.xmotion.y_root) > GRV.MoveThreshold) {
  315. X            XPutBackEvent(dpy, &e);
  316. X            return False;
  317. X        }
  318. X        break;
  319. X        }
  320. X    }
  321. X
  322. X    if (!AwaitEvents(dpy, &timeout))
  323. X        return False;
  324. X    }
  325. X}
  326. X
  327. X
  328. X/*
  329. X * ResolveMouseBinding
  330. X *
  331. X * Given a mouse button press event, determines whether this event completes
  332. X * an event sequence that binds to an action.  If the button press is a prefix
  333. X * of a chording sequence, and this press falls within the chording time of
  334. X * the initial button press, checkChording is called to disambiguate the event
  335. X * stream.  Returns a proper action if the action is complete, otherwise
  336. X * returns ACTION_NONE.  All callers should ensure that no action is taken
  337. X * when this routine returns ACTION_NONE.
  338. X */
  339. XSemanticAction
  340. XResolveMouseBinding(dpy, pevent, ignoremask)
  341. X    Display *dpy;
  342. X    XEvent *pevent;
  343. X    unsigned long ignoremask;
  344. X{
  345. X    MouseMatchState m;
  346. X    struct timeval timeout;
  347. X    SemanticAction a;
  348. X    static Time firstpresstime;
  349. X    XEvent e;
  350. X
  351. X    /* copy *pevent to e, masking off ignored bits from the state */
  352. X    e = *pevent;
  353. X    e.xbutton.state &= ~(ignoremask |
  354. X             ModMaskMap[MOD_IGNORE] |
  355. X             ModMaskMap[MOD_WMGRAB]);
  356. X
  357. X    /* Chording is in msec.  Convert to sec/usec for timeval. */
  358. X    timeout.tv_usec = GRV.MouseChordTimeout * 1000;
  359. X    if (timeout.tv_usec >= 1000000) {
  360. X    timeout.tv_sec = timeout.tv_usec / 1000000;
  361. X    timeout.tv_usec %= 1000000;
  362. X    } else {
  363. X    timeout.tv_sec = 0;
  364. X    }
  365. X
  366. X    if (FirstButtonDown(&e)) {
  367. X    firstpresstime = e.xbutton.time;
  368. X    } else {
  369. X    if (e.xbutton.time - firstpresstime > GRV.MouseChordTimeout)
  370. X        return ACTION_NONE;
  371. X    }
  372. X
  373. X    m = searchMouseBindings(&e, &a);
  374. X    if ((m == MATCH_PREFIX && !checkChording(dpy, timeout, &e))
  375. X    || m == MATCH_EXACT) {
  376. X    return a;
  377. X    } else {
  378. X    return ACTION_NONE;
  379. X    }
  380. X}
  381. X
  382. X
  383. X/* ===== Keyboard Binding ================================================= */
  384. X
  385. X/*
  386. X * Table of default keyboard descriptors.  This table contains information 
  387. X * necessary to initialize keyboard bindings and customize them based on 
  388. X * resources.
  389. X */
  390. X
  391. X#define NULLFUNC ((void (*)())0)
  392. X
  393. Xextern void HandleHelpKey();
  394. X
  395. Xstatic void keySuspend();
  396. Xstatic void keyResume();
  397. Xstatic void keyQuoteNext();
  398. X
  399. Xstatic unsigned long mouselessMaskTable[] = { KD_SUNVIEW, KD_BASIC, KD_FULL };
  400. X
  401. XKeyDescriptor KeyDescriptorTable[] = {
  402. X
  403. X/*
  404. X    rsrc_name            dflt_binding        function
  405. X    action                flags
  406. X */
  407. X
  408. X{
  409. X    "Stop",                "L1,Escape",        NULLFUNC,
  410. X    ACTION_STOP,            KD_ALWAYS
  411. X}, {
  412. X    "DefaultAction",    "Return,Return+Meta,KP_Enter",    NULLFUNC,
  413. X    ACTION_EXEC_DEFAULT,        KD_ALWAYS
  414. X}, {
  415. X    "Select",            "space",            NULLFUNC,
  416. X    ACTION_SELECT,            KD_ALWAYS
  417. X}, {
  418. X    "Adjust",            "Insert+Alt",        NULLFUNC,
  419. X    ACTION_ADJUST,            KD_ALWAYS
  420. X}, {
  421. X    "Menu",                "space+Alt",        NULLFUNC,
  422. X    ACTION_MENU,            KD_ALWAYS
  423. X}, {
  424. X    "InputFocusHelp",        "question,question+Ctrl",    NULLFUNC,
  425. X    ACTION_FOCUS_HELP,        KD_ALWAYS
  426. X}, {
  427. X    "Up",                "Up",            NULLFUNC,
  428. X    ACTION_UP,            KD_ALWAYS,
  429. X}, {
  430. X    "Down",                "Down",            NULLFUNC,
  431. X    ACTION_DOWN,            KD_ALWAYS,
  432. X}, {
  433. X    "Left",                "Left",            NULLFUNC,
  434. X    ACTION_LEFT,            KD_ALWAYS
  435. X}, {
  436. X    "Right",            "Right",            NULLFUNC,
  437. X    ACTION_RIGHT,            KD_ALWAYS
  438. X}, {
  439. X    "JumpUp",            "Up+Ctrl",            NULLFUNC,
  440. X    ACTION_JUMP_UP,            KD_ALWAYS
  441. X}, {
  442. X    "JumpDown",            "Down+Ctrl",        NULLFUNC,
  443. X    ACTION_JUMP_DOWN,        KD_ALWAYS
  444. X}, {
  445. X    "JumpLeft",            "Left+Ctrl",        NULLFUNC,
  446. X    ACTION_JUMP_LEFT,        KD_ALWAYS
  447. X}, {
  448. X    "JumpRight",            "Right+Ctrl",        NULLFUNC,
  449. X    ACTION_JUMP_RIGHT,        KD_ALWAYS
  450. X}, {
  451. X    "RowStart",            "Home,R7",            NULLFUNC,
  452. X    ACTION_ROW_START,        KD_ALWAYS
  453. X}, {
  454. X    "RowEnd",            "End,R13",            NULLFUNC,
  455. X    ACTION_ROW_END,            KD_ALWAYS
  456. X}, {
  457. X    "DataStart",            "Home+Ctrl",        NULLFUNC,
  458. X    ACTION_DATA_START,        KD_ALWAYS
  459. X}, {
  460. X    "DataEnd",            "End+Ctrl",            NULLFUNC,
  461. X    ACTION_DATA_END,        KD_ALWAYS
  462. X}, {
  463. X    "FirstControl",            "bracketleft+Ctrl",        NULLFUNC,
  464. X    ACTION_FIRST_CONTROL,        KD_ALWAYS
  465. X}, {
  466. X    "LastControl",            "bracketright+Ctrl",    NULLFUNC,
  467. X    ACTION_LAST_CONTROL,        KD_ALWAYS
  468. X}, {
  469. X    "NextElement",            "Tab,Tab+Ctrl",        NULLFUNC,
  470. X    ACTION_NEXT_ELEMENT,        KD_ALWAYS
  471. X}, {
  472. X    "PreviousElement",        "Tab+Shift,Tab+Shift+Ctrl",    NULLFUNC,
  473. X    ACTION_PREVIOUS_ELEMENT,    KD_ALWAYS
  474. X}, {
  475. X    "Open",                "L7+Alt",            NULLFUNC,
  476. X    ACTION_OPEN,            KD_ALWAYS
  477. X}, {
  478. X    "Help",                "Help",            HandleHelpKey,
  479. X    ACTION_HELP,            KD_BASIC_FULL
  480. X}, {
  481. X    "LockColormap",            "L2+Ctrl",            KeyLockColormap,
  482. X    ACTION_NONE,            KD_BASIC_FULL
  483. X}, {
  484. X    "UnlockColormap",        "L4+Ctrl",            KeyUnlockColormap,
  485. X    ACTION_NONE,            KD_BASIC_FULL
  486. X}, {
  487. X    "Front",            "L5+Alt",            KeyFrontFocus,
  488. X    ACTION_FRONT,            KD_BASIC_FULL
  489. X}, {
  490. X    "FocusToPointer",        "j+Shift+Alt",        KeyFocusToPointer,
  491. X    ACTION_NONE,            KD_FULL
  492. X}, {
  493. X    "NextApp",            "n+Alt",            KeyNextApp,
  494. X    ACTION_NONE,            KD_FULL
  495. X}, {
  496. X    "PreviousApp",            "N+Alt",            KeyPrevApp,
  497. X    ACTION_NONE,            KD_FULL
  498. X}, {
  499. X    "ToggleInput",            "t+Alt",            KeyToggleInput,
  500. X    ACTION_NONE,            KD_FULL
  501. X}, {
  502. X    "NextWindow",            "w+Alt",            KeyNextWindow,
  503. X    ACTION_NONE,            KD_FULL
  504. X}, {
  505. X    "PreviousWindow",        "W+Alt",            KeyPrevWindow,
  506. X    ACTION_NONE,            KD_FULL
  507. X}, {
  508. X    "TogglePin",            "Insert+Meta",        KeyTogglePin,
  509. X    ACTION_TOGGLE_PIN,        KD_FULL
  510. X}, {
  511. X    "SuspendMouseless",        "z+Alt",            keySuspend,
  512. X    ACTION_NONE,            KD_BASIC_FULL
  513. X}, {
  514. X    "ResumeMouseless",        "Z+Alt",            keyResume,
  515. X    ACTION_NONE,            KD_IMMUNE | KD_BASIC_FULL
  516. X}, {
  517. X    "QuoteNextKey",            "q+Alt",            keyQuoteNext,
  518. X    ACTION_NONE,            KD_BASIC_FULL
  519. X}, {
  520. X    "Refresh",            "F8+Alt",            KeyRefresh,
  521. X    ACTION_NONE,            KD_FULL
  522. X}, {
  523. X    "Back",                "F5+Alt",            KeyBackFocus,
  524. X    ACTION_NONE,            KD_FULL
  525. X}, {
  526. X    "OpenClose",            "F2+Alt",            KeyOpenCloseFocus,
  527. X    ACTION_NONE,            KD_FULL
  528. X}, {
  529. X    "FullRestore",            "F3+Alt",            KeyFullRestore,
  530. X    ACTION_NONE,            KD_FULL
  531. X}, {
  532. X    "Quit",                "F9+Alt",            KeyQuit,
  533. X    ACTION_NONE,            KD_FULL
  534. X}, {
  535. X    "Owner",            "F10+Alt",            KeyOwner,
  536. X    ACTION_NONE,            KD_FULL
  537. X}, {
  538. X    "WorkspaceMenu",        "M+Alt",            KeyWorkspaceMenu,
  539. X    ACTION_NONE,            KD_FULL
  540. X}, {
  541. X    "WindowMenu",            "m+Alt",            KeyWindowMenu,
  542. X    ACTION_NONE,            KD_FULL
  543. X}, {
  544. X    "Move",                "F6+Alt",            KeyMove,
  545. X    ACTION_NONE,            KD_FULL
  546. X}, {
  547. X    "Resize",            "F7+Alt",            KeyResize,
  548. X    ACTION_NONE,            KD_FULL
  549. X}, {
  550. X    "Properties",            "F4+Alt",            KeyProperties,
  551. X    ACTION_NONE,            KD_FULL
  552. X}, {
  553. X    "OpenClosePointer",        "L7",          KeyOpenClosePointer,
  554. X    ACTION_NONE,            KD_ALWAYS
  555. X}, {
  556. X    "RaiseLower",            "L5",         KeyRaiseLowerPointer,
  557. X    ACTION_NONE,            KD_ALWAYS
  558. X},
  559. X
  560. X/*
  561. X * Keymappings for the virtual desktop.  The keypad keys are mapped
  562. X * in a clockwise fashion around the arrow keys.  These keys with a meta
  563. X * modifier are grabbed and are always active, otherwise they fall through
  564. X * to the no focus window which moves the vdm
  565. X *
  566. X * We don't have a nofocus action for R7 and R13 since they already have
  567. X * an action above
  568. X */
  569. X   {    "VirtualUp",            "Up+Meta",        KeyMoveVDM,
  570. X    ACTION_UP,            KD_ALWAYS                },
  571. X   {    "HalfUp",            "Up+Shift",        NULLFUNC,
  572. X    ACTION_HALF_UP,                KD_ALWAYS                },
  573. X   {    "VirtualHalfUp",        "Up+Shift+Meta",    KeyMoveVDM,
  574. X    ACTION_HALF_UP,            KD_ALWAYS                },
  575. X   {    "VirtualJumpUp",        "Up+Ctrl+Meta",    KeyMoveVDM,
  576. X    ACTION_JUMP_UP,            KD_ALWAYS                },
  577. X
  578. X   {    "VirtualDown",            "Down+Meta",    KeyMoveVDM,
  579. X    ACTION_DOWN,            KD_ALWAYS                },
  580. X   {    "HalfDown",            "Down+Shift",    NULLFUNC,
  581. X    ACTION_HALF_DOWN,            KD_ALWAYS                },
  582. X   {    "VirtualHalfDown",        "Down+Shift+Meta",    KeyMoveVDM,
  583. X    ACTION_HALF_DOWN,        KD_ALWAYS                },
  584. X   {    "VirtualJumpDown",        "Down+Ctrl+Meta",    KeyMoveVDM,
  585. X    ACTION_JUMP_DOWN,        KD_ALWAYS                },
  586. X
  587. X   {    "VirtualLeft",            "Left+Meta",    KeyMoveVDM,
  588. X    ACTION_LEFT,            KD_ALWAYS                },
  589. X   {    "HalfLeft",            "Left+Shift",    NULLFUNC,
  590. X    ACTION_HALF_LEFT,        KD_ALWAYS                },
  591. X   {    "VirtualHalfLeft",        "Left+Shift+Meta",    KeyMoveVDM,
  592. X    ACTION_HALF_LEFT,        KD_ALWAYS                },
  593. X   {    "VirtualJumpLeft",        "Left+Ctrl+Meta",    KeyMoveVDM,
  594. X    ACTION_JUMP_LEFT,        KD_ALWAYS                },
  595. X
  596. X   {    "VirtualRight",            "Right+Meta",    KeyMoveVDM,
  597. X    ACTION_RIGHT,            KD_ALWAYS                },
  598. X   {    "HalfRight",            "Right+Shift",    NULLFUNC,
  599. X    ACTION_HALF_RIGHT,        KD_ALWAYS                },
  600. X   {    "VirtualHalfRight",        "Right+Shift+Meta",    KeyMoveVDM,
  601. X    ACTION_HALF_RIGHT,        KD_ALWAYS                },
  602. X   {    "VirtualJumpRight",        "Right+Ctrl+Meta",    KeyMoveVDM,
  603. X    ACTION_JUMP_RIGHT,        KD_ALWAYS                },
  604. X
  605. X   {    "VirtualUpLeft",        "R7+Meta",        KeyMoveVDM,
  606. X    ACTION_UPLEFT,            KD_ALWAYS                },
  607. X   {    "JumpUpLeft",            "R7+Ctrl",        NULLFUNC,
  608. X    ACTION_JUMP_UPLEFT,        KD_ALWAYS                },
  609. X   {    "VirtualJumpUpLeft",        "R7+Ctrl+Meta",    KeyMoveVDM,
  610. X    ACTION_JUMP_UPLEFT,        KD_ALWAYS                },
  611. X   {    "HalfUpLeft",            "R7+Shift",        NULLFUNC,
  612. X    ACTION_HALF_UPLEFT,        KD_ALWAYS                },
  613. X   {    "VirtualHalfUpLeft",        "R7+Shift+Meta",    KeyMoveVDM,
  614. X    ACTION_HALF_UPLEFT,        KD_ALWAYS                },
  615. X
  616. X   {    "VirtualUpRight",        "R9+Meta",        KeyMoveVDM,
  617. X    ACTION_UPRIGHT,            KD_ALWAYS                },
  618. X   {    "UpRight",            "R9",        NULLFUNC,
  619. X    ACTION_UPRIGHT,            KD_ALWAYS                },
  620. X   {    "JumpUpRight",            "R9+Ctrl",        NULLFUNC,
  621. X    ACTION_JUMP_UPRIGHT,        KD_ALWAYS                },
  622. X   {    "VirtualJumpUpRight",        "R9+Ctrl+Meta",    KeyMoveVDM,
  623. X    ACTION_JUMP_UPRIGHT,        KD_ALWAYS                },
  624. X   {    "HalfUpRight",            "R9+Shift",        NULLFUNC,
  625. X    ACTION_HALF_UPRIGHT,        KD_ALWAYS                },
  626. X   {    "VirtualHalfUpRight",        "R9+Shift+Meta",    KeyMoveVDM,
  627. X    ACTION_HALF_UPRIGHT,        KD_ALWAYS                },
  628. X
  629. X   {    "VirtualDownLeft",        "R13+Meta",        KeyMoveVDM,
  630. X    ACTION_DOWNLEFT,        KD_ALWAYS                },
  631. X   {    "JumpDownLeft",            "R13+Ctrl",        NULLFUNC,
  632. X    ACTION_JUMP_DOWNLEFT,        KD_ALWAYS                },
  633. X   {    "VirtualJumpDownLeft",        "R13+Ctrl+Meta",    KeyMoveVDM,
  634. X    ACTION_JUMP_DOWNLEFT,        KD_ALWAYS                },
  635. X   {    "HalfDownLeft",            "R13+Shift",    NULLFUNC,
  636. X    ACTION_HALF_DOWNLEFT,        KD_ALWAYS                },
  637. X   {    "VirtualHalfDownLeft",        "R13+Shift+Meta",    KeyMoveVDM,
  638. X    ACTION_HALF_DOWNLEFT,        KD_ALWAYS                },
  639. X
  640. X   {    "VirtualDownRight",        "R15+Meta",        KeyMoveVDM,
  641. X    ACTION_DOWNRIGHT,        KD_ALWAYS                },
  642. X   {    "DownRight",            "R15",        NULLFUNC,
  643. X    ACTION_DOWNRIGHT,        KD_ALWAYS                },
  644. X   {    "JumpDownRight",        "R15+Ctrl",        NULLFUNC,
  645. X    ACTION_JUMP_DOWNRIGHT,        KD_ALWAYS                },
  646. X   {    "VirtualJumpDownRight",        "R15+Ctrl+Meta",    KeyMoveVDM,
  647. X    ACTION_JUMP_DOWNRIGHT,        KD_ALWAYS                },
  648. X   {    "HalfDownRight",        "R15+Shift",    NULLFUNC,
  649. X    ACTION_HALF_DOWNRIGHT,        KD_ALWAYS                },
  650. X   {    "VirtualHalfDownRight",        "R15+Shift+Meta",    KeyMoveVDM,
  651. X    ACTION_HALF_DOWNRIGHT,        KD_ALWAYS                },
  652. X
  653. X   {    "VirtualHome",                "R11+Meta",        KeyMoveVDM,
  654. X    ACTION_HOME,                KD_ALWAYS                },
  655. X   {    "GoHome",            "R11",        NULLFUNC,
  656. X    ACTION_HOME,            KD_ALWAYS                },
  657. X
  658. X   {    "VirtualScreen1",        "F1+Meta",        KeyMoveVDM,
  659. X    ACTION_GOTO_1,            KD_ALWAYS                },
  660. X   {    "Screen1",                "F1",        NULLFUNC,
  661. X    ACTION_GOTO_1,            KD_ALWAYS                },
  662. X   {    "VirtualScreen2",        "F2+Meta",        KeyMoveVDM,
  663. X    ACTION_GOTO_2,            KD_ALWAYS                },
  664. X   {    "Screen2",                "F2",        NULLFUNC,
  665. X    ACTION_GOTO_2,            KD_ALWAYS                },
  666. X   {    "VirtualScreen3",        "F3+Meta",        KeyMoveVDM,
  667. X    ACTION_GOTO_3,            KD_ALWAYS                },
  668. X   {    "Screen3",                "F3",        NULLFUNC,
  669. X    ACTION_GOTO_3,            KD_ALWAYS                },
  670. X   {    "VirtualScreen4",        "F4+Meta",        KeyMoveVDM,
  671. X    ACTION_GOTO_4,            KD_ALWAYS                },
  672. X   {    "Screen4",                "F4",        NULLFUNC,
  673. X    ACTION_GOTO_4,            KD_ALWAYS                },
  674. X   {    "VirtualScreen5",        "F5+Meta",        KeyMoveVDM,
  675. X    ACTION_GOTO_5,            KD_ALWAYS                },
  676. X   {    "Screen5",                "F5",        NULLFUNC,
  677. X    ACTION_GOTO_5,            KD_ALWAYS                },
  678. X   {    "VirtualScreen6",        "F6+Meta",        KeyMoveVDM,
  679. X    ACTION_GOTO_6,            KD_ALWAYS                },
  680. X   {    "Screen6",                "F6",        NULLFUNC,
  681. X    ACTION_GOTO_6,            KD_ALWAYS                },
  682. X   {    "VirtualScreen7",        "F7+Meta",        KeyMoveVDM,
  683. X    ACTION_GOTO_7,            KD_ALWAYS                },
  684. X   {    "Screen7",                "F7",        NULLFUNC,
  685. X    ACTION_GOTO_7,            KD_ALWAYS                },
  686. X   {    "VirtualScreen8",        "F8+Meta",        KeyMoveVDM,
  687. X    ACTION_GOTO_8,            KD_ALWAYS                },
  688. X   {    "Screen8",                "F8",        NULLFUNC,
  689. X    ACTION_GOTO_8,            KD_ALWAYS                },
  690. X   {    "VirtualScreen9",        "F9+Meta",        KeyMoveVDM,
  691. X    ACTION_GOTO_9,            KD_ALWAYS                },
  692. X   {    "Screen9",                "F9",        NULLFUNC,
  693. X    ACTION_GOTO_9,            KD_ALWAYS                },
  694. X   {    "VirtualScreen10",        "F10+Meta",        KeyMoveVDM,
  695. X    ACTION_GOTO_10,            KD_ALWAYS                },
  696. X   {    "Screen10",                "F10",        NULLFUNC,
  697. X    ACTION_GOTO_10,            KD_ALWAYS                },
  698. X};
  699. X
  700. X#define NUMKEYDESCRIPTORS (sizeof(KeyDescriptorTable)/sizeof(KeyDescriptor))
  701. X
  702. X
  703. Xtypedef struct {
  704. X    unsigned int modstate;
  705. X    KeyCode keycode;
  706. X    KeyDescriptor *desc;
  707. X} KeyBinding;
  708. X
  709. X
  710. Xtypedef struct {
  711. X    KeySym sym;
  712. X    unsigned int mod;
  713. X} modsym;
  714. X
  715. X
  716. X#define KEYBINDING_TABLE_SIZE 60
  717. X#define KEYBINDING_TABLE_INCR 20
  718. X
  719. Xstatic KeyBinding *KeyBindingTable = NULL;
  720. Xstatic KeyBinding *activeKey = NULL;
  721. Xstatic int bindingTableCount = 0;
  722. Xstatic int bindingTableSize = 0;
  723. Xstatic Bool suspended = False;
  724. Xstatic Bool quotenext = False;
  725. X
  726. X
  727. X/*
  728. X * Suspension and resumption of Mouseless functions.
  729. X */
  730. Xstatic void
  731. XkeySuspend(dpy, ke)
  732. X    Display *dpy;
  733. X    XKeyEvent *ke;
  734. X{
  735. X    if (ke->type != KeyPress)
  736. X    return;
  737. X    suspended = True;
  738. X}
  739. X
  740. X
  741. Xstatic void
  742. XkeyResume(dpy, ke)
  743. X    Display *dpy;
  744. X    XKeyEvent *ke;
  745. X{
  746. X    if (ke->type != KeyPress)
  747. X    return;
  748. X    suspended = False;
  749. X}
  750. X
  751. X
  752. XBool
  753. XIsMouselessSuspended()
  754. X{
  755. X    return suspended;
  756. X}
  757. X
  758. Xstatic void
  759. XkeyQuoteNext(dpy, ke)
  760. X    Display *dpy;
  761. X    XKeyEvent *ke;
  762. X{
  763. X    /*
  764. X     * Turn on quotenext on the release.  If we set it on the press,
  765. X     * the subsequent release would turn it off!
  766. X     */
  767. X    if (ke->type != KeyRelease)
  768. X    return;
  769. X    quotenext = True;
  770. X}
  771. X
  772. X
  773. X/*
  774. X * Add a binding to the key binding table.
  775. X */
  776. Xvoid
  777. XAddKeyBinding(kc, mod, desc)
  778. X    KeyCode kc;
  779. X    unsigned int mod;
  780. X    KeyDescriptor *desc;
  781. X{
  782. X    KeyBinding *b;
  783. X
  784. X    if (bindingTableCount == bindingTableSize) {
  785. X    bindingTableSize += KEYBINDING_TABLE_INCR;
  786. X    KeyBindingTable = MemRealloc(KeyBindingTable,
  787. X                     bindingTableSize*sizeof(KeyBinding));
  788. X    }
  789. X
  790. X    b = &KeyBindingTable[bindingTableCount];
  791. X    b->keycode = kc;
  792. X    b->modstate = mod;
  793. X    b->desc = desc;
  794. X    ++bindingTableCount;
  795. X}
  796. X
  797. X
  798. X/*
  799. X * Keysym aliasing.  Provides aliases for modifier keysyms.  Allows an alias 
  800. X * to represent a mask or to be a synonym for up to two keysyms.  The keysyms 
  801. X * are only looked at if the mask value is zero.
  802. X */
  803. X
  804. Xtypedef struct {
  805. X    char *alias;
  806. X    unsigned int mask;
  807. X    KeySym sym1, sym2;
  808. X} KeysymAlias;
  809. X
  810. Xstatic KeysymAlias KeysymAliasTable[] = {
  811. X   /* alias        mask        sym1        sym2 */
  812. X    { "Any",        AnyModifier,    0,            0 },
  813. X    { "Shift",        ShiftMask,        0,            0 },
  814. X    { "Lock",        LockMask,        0,            0 },
  815. X    { "Control",    ControlMask,    0,            0 },
  816. X    { "Ctrl",        ControlMask,    0,            0 },
  817. X    { "Ctl",        ControlMask,    0,            0 },
  818. X    { "Meta",        0,            XK_Meta_L,        XK_Meta_R },
  819. X    { "Alt",        0,            XK_Alt_L,        XK_Alt_R },
  820. X    { "Super",        0,            XK_Super_L,        XK_Super_R },
  821. X    { "Hyper",        0,            XK_Hyper_L,        XK_Hyper_R }
  822. X};
  823. X#define NUMALIASES (sizeof(KeysymAliasTable)/sizeof(KeysymAlias))
  824. X
  825. X
  826. X/*
  827. X * Takes a word and presumes that it names a keysym.  Looks up this keysym in
  828. X * the modifier mapping table and returns the corresponding modifier mask.  If
  829. X * the string doesn't name a valid keysym, returns 0.  If the keysym is not a
  830. X * modifier, returns 0.  If the word is "Any", returns AnyModifier.  Several
  831. X * aliases are supported for well-known modifiers, e.g. "Meta" for "Meta_L" or
  832. X * "Meta_R".  REMIND: If a keysym is on several keys, and only some of the
  833. X * keys are modifiers, this function may fail to find the modifier mask.
  834. X */
  835. Xunsigned int
  836. XstringToModifier(dpy, word)
  837. X    Display *dpy;
  838. X    char *word;
  839. X{
  840. X    KeySym ks;
  841. X    KeyCode kc;
  842. X    KeysymAlias *ksa;
  843. X    int modnum;
  844. X
  845. X    ks = XStringToKeysym(word);
  846. X
  847. X    if (ks != NoSymbol) {
  848. X    kc = XKeysymToKeycode(dpy, ks);
  849. X
  850. X    if (kc == 0)
  851. X        return 0;
  852. X    else
  853. X        return FindModifierMask(kc);
  854. X    }
  855. X
  856. X    /*
  857. X     * It's not a valid keysym name, so try a bunch of aliases.  First,
  858. X     * Allow "mod1" ... "mod5" as synonyms for Mod1Mask ... Mod5Mask.
  859. X     */
  860. X
  861. X    if (1 == sscanf(word, "mod%d", &modnum) &&
  862. X    modnum >= 1 && modnum <= 5)
  863. X    {
  864. X    return (1 << (Mod1MapIndex + modnum - 1));
  865. X    }
  866. X
  867. X    /* look through the alias table for masks or keysyms */
  868. X
  869. X    kc = 0;
  870. X    for (ksa = KeysymAliasTable; ksa < KeysymAliasTable + NUMALIASES;
  871. X     ++ksa)
  872. X    {
  873. X    if (0 == strcmp(word, ksa->alias)) {
  874. X        if (ksa->mask != 0)
  875. X        return ksa->mask;
  876. X
  877. X        kc = XKeysymToKeycode(dpy, ksa->sym1);
  878. X
  879. X        if (kc == 0)
  880. X        kc = XKeysymToKeycode(dpy, ksa->sym2);
  881. X
  882. X        if (kc == 0)
  883. X        return 0;
  884. X        else
  885. X        return FindModifierMask(kc);
  886. X    }
  887. X    }
  888. X
  889. X    return 0;
  890. X}
  891. X
  892. X
  893. X/*
  894. X * Parses a comma-separated string into words, gets the modifier mask for 
  895. X * each, ORs them together and returns the result.
  896. X */
  897. Xunsigned int
  898. XpolyStringToModifier(dpy, str)
  899. X    Display *dpy;
  900. X    char *str;
  901. X{
  902. X    char buf[200];
  903. X    unsigned int result = 0;
  904. X    char *word;
  905. X
  906. X    /* make a copy first, because strtok riddles the string with nulls. */
  907. X    strcpy(buf, str);
  908. X    word = strtok(buf, ",");
  909. X    while (word != NULL) {
  910. X    result |= stringToModifier(dpy, word);
  911. X    word = strtok(NULL, ",");
  912. X    }
  913. X    return result;
  914. X}
  915. X
  916. X
  917. X#define MAX_MAPPINGS 6
  918. X
  919. X/*
  920. X * Parses a key specification of the form
  921. X *        keymod[,keymod[,...]]
  922. X * where keymod is
  923. X *        keysym[+modifier[+...]]
  924. X */
  925. Xstatic int
  926. XparseKeySpec(dpy, specifier, syms)
  927. X    char *specifier;
  928. X    modsym *syms;
  929. X{
  930. X    char spec[200];
  931. X    char *mapping[MAX_MAPPINGS];
  932. X    char *keysym_string, *mod_string;
  933. X    KeySym keysym;
  934. X    int k;
  935. X    int modmask, newmod;
  936. X    int nbound = 0;
  937. X    char buffer[200];
  938. X
  939. X    /* make a copy first, because strtok riddles the string with nulls. */
  940. X    strcpy(spec, specifier);
  941. X
  942. X    /* break apart comma-separated mappings */
  943. X    mapping[0] = strtok(spec, ",");
  944. X    for (k = 1; k < MAX_MAPPINGS; ++k) {
  945. X    mapping[k] = strtok(NULL, ",");
  946. X    if (mapping[k] == NULL)
  947. X        break;
  948. X    }
  949. X
  950. X    /* for each mapping, break into keysym and modifier components */
  951. X    for (k = 0; k < MAX_MAPPINGS && mapping[k]; ++k) {
  952. X    keysym_string = strtok(mapping[k], "+");
  953. X    if (!keysym_string) {
  954. X        (void) sprintf(buffer, gettext("bad key mapping `%s'\n"),
  955. X              mapping[k]);
  956. X        ErrorWarning(buffer);
  957. X        continue;
  958. X    }
  959. X    keysym = XStringToKeysym(keysym_string);
  960. X    if (keysym == NoSymbol) {
  961. X        (void) sprintf(buffer, gettext("can't find keysym for `%s'\n"),
  962. X               keysym_string);
  963. X        ErrorWarning(buffer);
  964. X        continue;
  965. X    }
  966. X
  967. X    /*
  968. X     * If the keysym is upper case alphabetic, add a shift mask.  If it's 
  969. X     * lower case, convert it to upper case.
  970. X     */
  971. X    modmask = 0;
  972. X    if (XK_A <= keysym && keysym <= XK_Z)
  973. X        modmask = ShiftMask;
  974. X    if (XK_a <= keysym && keysym <= XK_z)
  975. X        keysym -= (XK_a - XK_A);
  976. X
  977. X    while (1) {
  978. X        mod_string = strtok(NULL, "+");
  979. X        if (!mod_string)
  980. X        break;
  981. X        newmod = stringToModifier(dpy, mod_string);
  982. X        if (newmod == 0) {
  983. X        /*
  984. X         * We couldn't find a modifier; ignore this binding.  We can't 
  985. X         * use continue, because we want to continue an outer loop.
  986. X         */
  987. X        goto nobinding;
  988. X        }
  989. X        modmask |= newmod;
  990. X    }
  991. X    syms[nbound].sym = keysym;
  992. X    syms[nbound].mod = modmask;
  993. X    ++nbound;
  994. X    nobinding: ;
  995. X    }  /* for each mapping */
  996. X    return nbound;
  997. X}
  998. X
  999. X
  1000. X/*
  1001. X * Run through the table of key descriptors and establish key bindings for
  1002. X * each descriptor.  First, the resource database is probed for a customized
  1003. X * key binding specification.  If one isn't found, the default key binding
  1004. X * specification is used.  Then, this specification is parsed into an array of
  1005. X * keysym/modifier pairs.  For each pair, the keyboard mapping table is
  1006. X * searched for the keysym and an entry is made into the binding table for
  1007. X * each instance of the keysym in the mapping table.  Thus, if a keysym
  1008. X * appears on more than one keystation, a key binding entry is created for
  1009. X * each.
  1010. X *
  1011. X * If a resource is found, it is always used.  If no resource is found, the
  1012. X * default specification is used only if the current mouseless setting has
  1013. X * this binding enabled.  So, setting mouseless to Basic or SunView will 
  1014. X * disable most key bindings.  However, if you add a specific resource, it 
  1015. X * will always be honored.
  1016. X */
  1017. Xstatic void
  1018. XestablishKeyBindings(dpy)
  1019. X    Display *dpy;
  1020. X{
  1021. X    KeyDescriptor *d;
  1022. X    KeyBinding *kb;
  1023. X    modsym syms[MAX_MAPPINGS];
  1024. X    int nsyms;
  1025. X    int i, j;
  1026. X    int keytblsize = (MaxKeyCode-MinKeyCode+1) * KeySymsPerKeyCode;
  1027. X    XrmQuark classlist[4], namelist[4];
  1028. X    XrmQuark rep;
  1029. X    XrmValue value;
  1030. X    char *keyspec;
  1031. X    unsigned long mask;
  1032. X
  1033. X    classlist[1] = kbdCmdClassQ;
  1034. X    classlist[3] = NULLQUARK;
  1035. X
  1036. X    namelist[0] = TopInstanceQ;
  1037. X    namelist[1] = kbdCmdInstanceQ;
  1038. X    namelist[3] = NULLQUARK;
  1039. X
  1040. X    mask = mouselessMaskTable[GRV.Mouseless];
  1041. X
  1042. X    for (d=KeyDescriptorTable; d < KeyDescriptorTable+NUMKEYDESCRIPTORS;
  1043. X        ++d) {
  1044. X    classlist[0] = OpenWinQ;
  1045. X    classlist[2] = namelist[2] = XrmStringToQuark(d->rsrc_name);
  1046. X    if (XrmQGetResource(OlwmDB, namelist, classlist, &rep, &value)) {
  1047. X        keyspec = (char *) value.addr;
  1048. X    } else {
  1049. X        /*
  1050. X         * Use olwm binding; see resources.c
  1051. X         */
  1052. X        classlist[0] = OlwmQ;
  1053. X        if (XrmQGetResource(OlwmDB, namelist, classlist, &rep, &value))
  1054. X        keyspec = (char *) value.addr;
  1055. X        else if (mask & d->flags)
  1056. X        keyspec = d->dflt_binding;
  1057. X        else
  1058. X        continue;
  1059. X    }
  1060. X    nsyms = parseKeySpec(dpy, keyspec, syms);
  1061. X    for (i=0; i<nsyms; ++i) {
  1062. X        for (j=0; j<keytblsize; ++j) {
  1063. X        if (KbdMap[j] == syms[i].sym) {
  1064. X            AddKeyBinding(j/KeySymsPerKeyCode+MinKeyCode, syms[i].mod, d);
  1065. X            j += KeySymsPerKeyCode - (j % KeySymsPerKeyCode) - 1;
  1066. X        }
  1067. X        }
  1068. X    }
  1069. X    }
  1070. X}
  1071. X    
  1072. X
  1073. X/*
  1074. X * Issue or release passive grabs for the necessary keys on this particular
  1075. X * root window.  Run through the binding table and un/grab the key-modifier
  1076. X * combination itself, and also combined with the Lock and NumLock (if any)
  1077. X * modifier.  There thus may be up to four actual grabs per key binding.
  1078. X */
  1079. Xstatic void
  1080. XgrabRootKeys(dpy, root, grab)
  1081. X    Display *dpy;
  1082. X    Window root;
  1083. X    Bool grab;        /* True = grab, False = release */
  1084. X{
  1085. X    KeyBinding *k;
  1086. X    unsigned int NumLockMask =
  1087. X    FindModifierMask(XKeysymToKeycode(dpy, XK_Num_Lock));
  1088. X    for (k=KeyBindingTable; k < KeyBindingTable+bindingTableCount; ++k) {
  1089. X    if (k->desc->function != NULLFUNC) {
  1090. X        if (grab) {
  1091. X        XGrabKey(dpy, k->keycode, k->modstate,
  1092. X             root, False, GrabModeAsync, GrabModeSync);
  1093. X        XGrabKey(dpy, k->keycode, k->modstate | LockMask,
  1094. X             root, False, GrabModeAsync, GrabModeSync);
  1095. X        } else {
  1096. X        XUngrabKey(dpy, k->keycode, k->modstate, root);
  1097. X        XUngrabKey(dpy, k->keycode, k->modstate|LockMask, root);
  1098. X        }
  1099. X        if (NumLockMask != 0) {
  1100. X        if (grab) {
  1101. X            XGrabKey(dpy, k->keycode, k->modstate | NumLockMask,
  1102. X                 root, False, GrabModeAsync, GrabModeSync);
  1103. X            XGrabKey(dpy, k->keycode,
  1104. X                 k->modstate | NumLockMask | LockMask,
  1105. X                 root, False, GrabModeAsync, GrabModeSync);
  1106. X        } else {
  1107. X            XUngrabKey(dpy, k->keycode, k->modstate | NumLockMask,
  1108. X                   root);
  1109. X            XUngrabKey(dpy, k->keycode,
  1110. X                   k->modstate | NumLockMask | LockMask, root);
  1111. X        }
  1112. X        }
  1113. X    }
  1114. X    }
  1115. X}
  1116. X
  1117. X
  1118. X/*
  1119. X * Issue or release passive button grabs on this root window.  Like
  1120. X * grabRootKeys, has to deal with Lock and NumLock by issuing up to four
  1121. X * separate grabs.  Note: these are synchronous grabs.  This relies on the
  1122. X * root event handler to issue an AllowEvents or GrabPointer request.
  1123. X */
  1124. Xstatic void
  1125. XgrabRootButtons(dpy, root, grab)
  1126. X    Display *dpy;
  1127. X    Window root;
  1128. X    Bool grab;        /* True = grab, False = release */
  1129. X{
  1130. X    unsigned int NumLockMask =
  1131. X    FindModifierMask(XKeysymToKeycode(dpy, XK_Num_Lock));
  1132. X    unsigned int eventmask =
  1133. X    ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
  1134. X
  1135. X    if (ModMaskMap[MOD_WMGRAB] != 0) {
  1136. X    if (grab) {
  1137. X        XGrabButton(dpy, AnyButton,
  1138. X            ModMaskMap[MOD_WMGRAB],
  1139. X            root, False, eventmask,
  1140. X            GrabModeSync, GrabModeSync, None, None);
  1141. X        XGrabButton(dpy, AnyButton,
  1142. X            ModMaskMap[MOD_WMGRAB] | LockMask,
  1143. X            root, False, eventmask,
  1144. X            GrabModeSync, GrabModeSync, None, None);
  1145. X    } else {
  1146. X        XUngrabButton(dpy, AnyButton,
  1147. X              ModMaskMap[MOD_WMGRAB],
  1148. X              root);
  1149. X        XUngrabButton(dpy, AnyButton,
  1150. X              ModMaskMap[MOD_WMGRAB] | LockMask,
  1151. X              root);
  1152. X    }
  1153. X
  1154. X    if (NumLockMask != 0) {
  1155. X        if (grab) {
  1156. X        XGrabButton(dpy, AnyButton,
  1157. X                ModMaskMap[MOD_WMGRAB] | NumLockMask,
  1158. X                root, False, eventmask,
  1159. X                GrabModeSync, GrabModeSync, None, None);
  1160. X        XGrabButton(dpy, AnyButton,
  1161. X                ModMaskMap[MOD_WMGRAB] | LockMask | NumLockMask,
  1162. X                root, False, eventmask,
  1163. X                GrabModeSync, GrabModeSync, None, None);
  1164. X        } else {
  1165. X        XUngrabButton(dpy, AnyButton,
  1166. X                  ModMaskMap[MOD_WMGRAB] | NumLockMask,
  1167. X                  root);
  1168. X        XUngrabButton(dpy, AnyButton,
  1169. X                  ModMaskMap[MOD_WMGRAB] | LockMask | NumLockMask,
  1170. X                  root);
  1171. X        }
  1172. X    }
  1173. X    }
  1174. X}
  1175. X
  1176. X
  1177. X/* ===== public functions ================================================= */
  1178. X
  1179. X
  1180. X/*
  1181. X * Given a keyboard event, looks it up in the keyboard binding table.  If a 
  1182. X * binding is found, returns the semantic action associated with that key.  If 
  1183. X * no binding is found, returns ACTION_NONE.
  1184. X */
  1185. X
  1186. XSemanticAction
  1187. XFindKeyboardAction(dpy, event)
  1188. X    Display *dpy;
  1189. X    XEvent *event;
  1190. X{
  1191. X    KeyBinding *k;
  1192. X    SemanticAction a = ACTION_NONE;
  1193. X    unsigned long ignore = ModMaskMap[MOD_IGNORE] | AnyButtonMask;
  1194. X
  1195. X    for (k=KeyBindingTable; k < KeyBindingTable+bindingTableCount; ++k) {
  1196. X    if (k->keycode == event->xkey.keycode
  1197. X        && k->modstate == (event->xkey.state & ~ignore)) {
  1198. X        a = k->desc->action;
  1199. X        break;
  1200. X    }
  1201. X    }
  1202. X    return a;
  1203. X}
  1204. X
  1205. X/*
  1206. X * Keyboard actions added by olvwmrc are at the end of the list, but they
  1207. X * should take precedence over previous ones.  So this function does a
  1208. X * similar search as above but starts at the end.
  1209. X */
  1210. XSemanticAction
  1211. XFindNewKeyboardAction(dpy, event)
  1212. X    Display *dpy;
  1213. X    XEvent *event;
  1214. X{
  1215. X    KeyBinding *k;
  1216. X    SemanticAction a = ACTION_NONE;
  1217. X    unsigned long ignore = ModMaskMap[MOD_IGNORE] | AnyButtonMask;
  1218. X
  1219. X    for (k=KeyBindingTable+bindingTableCount-1; k >= KeyBindingTable; --k) {
  1220. X    if (k->keycode == event->xkey.keycode
  1221. X        && k->modstate == (event->xkey.state & ~ignore)) {
  1222. X        a = k->desc->action;
  1223. X        break;
  1224. X    }
  1225. X    }
  1226. X    return a;
  1227. X}
  1228. X
  1229. X
  1230. X/*
  1231. X * Given a keyboard event, looks it up in the keyboard binding table.
  1232. X * If a binding is found, executes the function bound to that key.  Returns 
  1233. X * True if a function was found and called, otherwise False.
  1234. X */
  1235. XBool
  1236. XExecuteKeyboardFunction(dpy, event)
  1237. X    Display *dpy;
  1238. X    XEvent *event;
  1239. X{
  1240. X    KeyBinding *k;
  1241. X    void (*f)() = NULLFUNC;
  1242. X    unsigned long ignore = ModMaskMap[MOD_IGNORE] | AnyButtonMask;
  1243. X
  1244. X    for (k=KeyBindingTable; k < KeyBindingTable+bindingTableCount; ++k) {
  1245. X    if (k->keycode == event->xkey.keycode
  1246. X        && k->modstate == (event->xkey.state & ~ignore)
  1247. X        && k->desc->function != NULLFUNC) {
  1248. X        f = k->desc->function;
  1249. X        break;
  1250. X    }
  1251. X    }
  1252. X
  1253. X    /* If the user pressed the STOP key, clear active key. */
  1254. X
  1255. X    if (f == NULLFUNC) {
  1256. X    if (FindKeyboardAction(dpy, event) == ACTION_STOP)
  1257. X        activeKey = NULL;
  1258. X    XAllowEvents(dpy, AsyncKeyboard, event->xkey.time);
  1259. X    return False;
  1260. X    }
  1261. X
  1262. X    /* invariant: k points to a valid key binding */
  1263. X
  1264. X#ifdef notdef
  1265. X    /*
  1266. X     * On the first keypress, stash the active key binding; ignore subsequent
  1267. X     * keypresses.  Ignore all key releases except the one corresponding to
  1268. X     * the active binding.
  1269. X     */
  1270. X    if (event->type == KeyPress) {
  1271. X    if (activeKey == NULL)
  1272. X        activeKey = k;
  1273. X    else
  1274. X        return False;
  1275. X    } else {                /* KeyRelease */
  1276. X    if (k == activeKey)
  1277. X        activeKey = NULL;
  1278. X    else
  1279. X        return False;        /* ignore it */
  1280. X    }
  1281. X#endif
  1282. X
  1283. X    if (suspended && !(k->desc->flags & KD_IMMUNE)) {
  1284. X    XAllowEvents(dpy, ReplayKeyboard, event->xkey.time);
  1285. X    return True;
  1286. X    }
  1287. X
  1288. X    if (quotenext) {
  1289. X    XAllowEvents(dpy, ReplayKeyboard, event->xkey.time);
  1290. X    quotenext = False;
  1291. X    return True;
  1292. X    }
  1293. X
  1294. X    if (event->type == KeyPress)
  1295. X    XAllowEvents(dpy, AsyncKeyboard, event->xkey.time);
  1296. X
  1297. X    (*f)(dpy, event);
  1298. X    return True;
  1299. X}
  1300. X
  1301. X
  1302. X/* ===== Initialization =================================================== */
  1303. X
  1304. X/*
  1305. X * Deal with key grabs on all root windows.  If grab = True, grab the keys; if 
  1306. X * grab = False, release the keys.  Note: the screens and the keyboard binding 
  1307. X * information must be initialized prior to calling this function.
  1308. X */
  1309. Xvoid
  1310. XGrabKeys(dpy, grab)
  1311. X    Display *dpy;
  1312. X    Bool grab;
  1313. X{
  1314. X    List *l = ScreenInfoList;
  1315. X    ScreenInfo *scr;
  1316. X    for (scr = ListEnum(&l); scr != NULL; scr = ListEnum(&l))
  1317. X    grabRootKeys(dpy, scr->rootid, grab);
  1318. X}
  1319. X
  1320. X
  1321. X/*
  1322. X * Remove all key grabs, zero out the binding table, and rebuild it from the 
  1323. X * resource database.  Then, re-establish key grabs.
  1324. X */
  1325. Xvoid
  1326. XRefreshKeyGrabs(dpy)
  1327. X    Display *dpy;
  1328. X{
  1329. X    GrabKeys(dpy, False);
  1330. X    bindingTableCount = 0;
  1331. X    establishKeyBindings(dpy);
  1332. X    ReInitOlvwmRC(dpy);
  1333. X    GrabKeys(dpy, True);
  1334. X}
  1335. X
  1336. X
  1337. X/*
  1338. X * Deal with button grabs on all root windows.  If grab = True, grab the 
  1339. X * buttons; if grab = False, release them.
  1340. X */
  1341. Xvoid
  1342. XGrabButtons(dpy, grab)
  1343. X    Display *dpy;
  1344. X    Bool grab;
  1345. X{
  1346. X    List *l = ScreenInfoList;
  1347. X    ScreenInfo *scr;
  1348. X
  1349. X    for (scr = ListEnum(&l); scr != NULL; scr = ListEnum(&l))
  1350. X    grabRootButtons(dpy, scr->rootid, grab);
  1351. X}
  1352. X
  1353. X
  1354. X/*
  1355. X * Remove all button grabs, regenerate the modifier mask table, and
  1356. X * re-establish the button grabs.
  1357. X */
  1358. Xvoid
  1359. XRefreshButtonGrabs(dpy)
  1360. X    Display *dpy;
  1361. X{
  1362. X    GrabButtons(dpy, False);
  1363. X    establishModBindings(dpy, OlwmDB);
  1364. X    GrabButtons(dpy, True);
  1365. X}
  1366. X
  1367. X
  1368. X/*
  1369. X * Update all bindings from a new resource database.  Called whenever the 
  1370. X * resource database changes.  
  1371. X */
  1372. Xvoid
  1373. XUpdateBindings(dpy, newDB)
  1374. X    Display *dpy;
  1375. X    XrmDatabase    newDB;
  1376. X{
  1377. X    KeyDescriptor *d;
  1378. X    XrmQuark classlist[4], instlist[4];
  1379. X    XrmQuark rep;
  1380. X    XrmValue newvalue, oldvalue;
  1381. X    Bool regrab = False;
  1382. X    static XrmBinding bindings[] =
  1383. X    { XrmBindTightly, XrmBindTightly, XrmBindTightly };
  1384. X
  1385. X    GrabButtons(dpy, False);
  1386. X    establishModBindings(dpy, newDB);
  1387. X    GrabButtons(dpy, True);
  1388. X
  1389. X    /* run through the KeyDescriptorTable and probe resources */
  1390. X
  1391. X    classlist[0] = OpenWinQ;
  1392. X    classlist[1] = kbdCmdClassQ;
  1393. X    classlist[3] = NULLQUARK;
  1394. X
  1395. X    instlist[0] = TopInstanceQ;
  1396. X    instlist[1] = kbdCmdInstanceQ;
  1397. X    instlist[3] = NULLQUARK;
  1398. X
  1399. X    for (d=KeyDescriptorTable; d < KeyDescriptorTable+NUMKEYDESCRIPTORS;
  1400. X        ++d) {
  1401. X
  1402. X    classlist[2] = instlist[2] = XrmStringToQuark(d->rsrc_name);
  1403. X
  1404. X    if (XrmQGetResource(newDB, instlist, classlist, &rep, &newvalue)) {
  1405. X        if (XrmQGetResource(OlwmDB, instlist, classlist, &rep, &oldvalue) &&
  1406. X            0 == strcmp((char *) newvalue.addr, (char *) oldvalue.addr))
  1407. X        {
  1408. X            /* old and new values the same; ignore */
  1409. X            continue;
  1410. X        }
  1411. X
  1412. X        regrab = True;
  1413. X        XrmQPutStringResource(&OlwmDB, bindings, instlist,
  1414. X                  (char *) newvalue.addr);
  1415. X    }
  1416. X    else {
  1417. X        /*
  1418. X         * Use olwm binding; see resources.c
  1419. X         */
  1420. X        classlist[0] = OlwmQ;
  1421. X        if (XrmQGetResource(newDB, instlist, classlist, &rep, &newvalue)) {
  1422. X            if (XrmQGetResource(OlwmDB, instlist, classlist,
  1423. X                    &rep, &oldvalue) &&
  1424. X                0 == strcmp((char *) newvalue.addr, (char *) oldvalue.addr))
  1425. X                {
  1426. X                    /* old and new values the same; ignore */
  1427. X                classlist[0] = OpenWinQ;
  1428. X                    continue;
  1429. X                }
  1430. X
  1431. X            regrab = True;
  1432. X            XrmQPutStringResource(&OlwmDB, bindings, instlist,
  1433. X                      (char *) newvalue.addr);
  1434. X        classlist[0] = OpenWinQ;
  1435. X        }
  1436. X    }
  1437. X    }
  1438. X
  1439. X    if (regrab)
  1440. X    RefreshKeyGrabs(dpy);
  1441. X}
  1442. X
  1443. X
  1444. X/*
  1445. X * Initialize the event handling system, but don't do any key grabbing.  This 
  1446. X * function is called exactly *once* at startup.
  1447. X */
  1448. Xvoid
  1449. XInitBindings(dpy)
  1450. X    Display *dpy;
  1451. X{
  1452. X    kbdCmdInstanceQ = XrmStringToQuark("keyboardCommand");
  1453. X    kbdCmdClassQ    = XrmStringToQuark("KeyboardCommand");
  1454. X
  1455. X    modInstanceQ    = XrmStringToQuark("modifier");
  1456. X    modClassQ        = XrmStringToQuark("Modifier");
  1457. X
  1458. X    KeyBindingTable = MemCalloc(KEYBINDING_TABLE_SIZE,sizeof(KeyBinding));
  1459. X    bindingTableSize = KEYBINDING_TABLE_SIZE;
  1460. X    establishKeyBindings(dpy);
  1461. X    establishModBindings(dpy, OlwmDB);
  1462. X}
  1463. END_OF_FILE
  1464. if test 38223 -ne `wc -c <'evbind.c'`; then
  1465.     echo shar: \"'evbind.c'\" unpacked with wrong size!
  1466. fi
  1467. # end of 'evbind.c'
  1468. fi
  1469. if test -f 'winpane.c' -a "${1}" != "-c" ; then 
  1470.   echo shar: Will not clobber existing file \"'winpane.c'\"
  1471. else
  1472. echo shar: Extracting \"'winpane.c'\" \(12706 characters\)
  1473. sed "s/^X//" >'winpane.c' <<'END_OF_FILE'
  1474. X/*
  1475. X *      (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents
  1476. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  1477. X *      file for terms of the license.
  1478. X */
  1479. X
  1480. X#ident    "@(#)winpane.c    1.1 olvwm version 1/3/92"
  1481. X
  1482. X/*
  1483. X * Based on
  1484. X#ident    "@(#)winpane.c    26.14    91/09/14 SMI"
  1485. X *
  1486. X */
  1487. X
  1488. X#include <errno.h>
  1489. X#include <stdio.h>
  1490. X#include <X11/Xos.h>
  1491. X#include <X11/Xlib.h>
  1492. X#include <X11/Xutil.h>
  1493. X#include <X11/Xatom.h>
  1494. X#include <olgx/olgx.h>
  1495. X
  1496. X#include "i18n.h"
  1497. X#include "ollocale.h"
  1498. X#include "mem.h"
  1499. X#include "olwm.h"
  1500. X#include "win.h"
  1501. X#include "globals.h"
  1502. X
  1503. X/***************************************************************************
  1504. X* global data
  1505. X***************************************************************************/
  1506. X
  1507. Xextern Atom AtomChangeState;
  1508. Xextern Atom AtomColorMapWindows;
  1509. Xextern Atom AtomOlwmTimestamp;
  1510. Xextern Window NoFocusWin;
  1511. Xextern void ColormapChange();
  1512. X
  1513. X/***************************************************************************
  1514. X* private data
  1515. X***************************************************************************/
  1516. X
  1517. X/* border width for reparented windows */
  1518. X#define NORMAL_BORDERWIDTH      0
  1519. X
  1520. Xstatic ClassPane classPane;
  1521. X
  1522. X/***************************************************************************
  1523. X* private functions
  1524. X***************************************************************************/
  1525. X
  1526. X/* 
  1527. X * eventEnterLeaveNotify - The pointer has entered or left the window
  1528. X */
  1529. Xstatic int
  1530. XeventEnterLeaveNotify(dpy, event, winInfo)
  1531. XDisplay    *dpy;
  1532. XXEvent    *event;
  1533. XWinPane    *winInfo;
  1534. X{
  1535. X    if (event->xany.type == EnterNotify)
  1536. X        ColorWindowCrossing(dpy, event, winInfo);
  1537. X}
  1538. X
  1539. X/* 
  1540. X * eventColormapNotify
  1541. X *
  1542. X * Handle changes to this window's colormap attribute.
  1543. X */
  1544. Xstatic int
  1545. XeventColormapNotify(dpy, event, winInfo)
  1546. X    Display    *dpy;
  1547. X    XEvent    *event;
  1548. X    WinPane    *winInfo;
  1549. X{
  1550. X    ColormapChange(dpy, event, (WinGeneric *)winInfo);
  1551. X}
  1552. X
  1553. X/* 
  1554. X * eventUnmapNotify - the client is transitioning to withrdrawn
  1555. X */
  1556. Xstatic int
  1557. XeventUnmapNotify(dpy, event, winInfo)
  1558. XDisplay    *dpy;
  1559. XXEvent    *event;
  1560. XWinPane    *winInfo;
  1561. X{
  1562. X        if (winInfo->pcore.pendingUnmaps > 0)
  1563. X        {
  1564. X            --winInfo->pcore.pendingUnmaps;
  1565. X        }
  1566. X    else
  1567. X    {
  1568. X            /* Mark current state */
  1569. X        StateWithdrawn(winInfo->core.client);
  1570. X    }
  1571. X}
  1572. X
  1573. X
  1574. X/* 
  1575. X * eventDestroyNotify - the pane window has disappeared
  1576. X *    This function can get called either during new state processing,
  1577. X *    or while app is iconic
  1578. X */
  1579. Xstatic int
  1580. XeventDestroyNotify(dpy, event, winInfo)
  1581. XDisplay    *dpy;
  1582. XXEvent    *event;
  1583. XWinPane    *winInfo;
  1584. X{
  1585. X    StateWithdrawn(winInfo->core.client);
  1586. X}
  1587. X
  1588. X
  1589. X/* 
  1590. X * eventPropertyNotify - handle client messages, in particular iconic requests
  1591. X */
  1592. Xstatic int
  1593. XeventPropertyNotify(dpy, event, winInfo)
  1594. XDisplay    *dpy;
  1595. XXEvent    *event;
  1596. XWinPane    *winInfo;
  1597. X{
  1598. X    ClientDistributeProperty(winInfo->core.client,event);
  1599. X}
  1600. X
  1601. X/* 
  1602. X * eventClientMessage - handle client messages, in particular iconic requests
  1603. X */
  1604. Xstatic int
  1605. XeventClientMessage(dpy, event, winInfo)
  1606. XDisplay    *dpy;
  1607. XXEvent    *event;
  1608. XWinPane    *winInfo;
  1609. X{
  1610. X    Client        *cli = winInfo->core.client;
  1611. X
  1612. X        if (event->xclient.message_type == AtomChangeState)
  1613. X        {
  1614. X                if (event->xclient.data.l[0] == IconicState)
  1615. X                        StateNormIcon(cli);
  1616. X        }
  1617. X}
  1618. X
  1619. X
  1620. X/*
  1621. X * eventExtension - handle extension events
  1622. X */
  1623. Xstatic int
  1624. XeventExtension(dpy, event, winInfo)
  1625. X    Display    *dpy;
  1626. X    XEvent    *event;
  1627. X    WinPane    *winInfo;
  1628. X{
  1629. X#ifdef SHAPE
  1630. X    XShapeEvent *se;
  1631. X    Client *cli;
  1632. X
  1633. X    if (event->xany.type == ShapeEventBase) {
  1634. X    /* it's a ShapeNotify event */
  1635. X    se = (XShapeEvent *) event;
  1636. X    if (se->kind != ShapeBounding)
  1637. X        return;
  1638. X    cli = winInfo->core.client;
  1639. X    
  1640. X    FrameUpdateShape(cli, cli->framewin);
  1641. X    }
  1642. X#endif /* SHAPE */
  1643. X}
  1644. X
  1645. X
  1646. X/*
  1647. X * drawPane -- draw the pane window
  1648. X */
  1649. X/*ARGSUSED*/    /* dpy arg will be used when multiple Displays supported */
  1650. Xstatic int
  1651. XdrawPane(dpy, winInfo)
  1652. XDisplay    *dpy;
  1653. XWinGeneric *winInfo;
  1654. X{
  1655. X}
  1656. X
  1657. X
  1658. X/*
  1659. X * focusPane -- handle focus change
  1660. X */
  1661. Xstatic int
  1662. XfocusPane(dpy, winInfo, focus)
  1663. XDisplay    *dpy;
  1664. XWinGeneric *winInfo;
  1665. XBool focus;
  1666. X{
  1667. X}
  1668. X
  1669. X/*
  1670. X * DestroyPane -- destroy the pane window resources and free any allocated
  1671. X *    data.
  1672. X */
  1673. Xstatic int
  1674. XdestroyPane(dpy, winInfo)
  1675. XDisplay    *dpy;
  1676. XWinGeneric *winInfo;
  1677. X{
  1678. X    /* free our data and throw away window */
  1679. X    WIUninstallInfo(winInfo->core.self);
  1680. X    MemFree(winInfo);
  1681. X}
  1682. X
  1683. X/*
  1684. X * setconfigPane -- change configuration of pane window
  1685. X */
  1686. X/*ARGSUSED*/    /* dpy arg will be used when multiple Displays supported */
  1687. Xstatic int
  1688. XsetconfigPane(dpy, winInfo)
  1689. XDisplay    *dpy;
  1690. XWinPane *winInfo;
  1691. X{
  1692. X    XConfigureEvent ce;
  1693. X    XWindowChanges xwc;
  1694. X
  1695. X    if (winInfo->core.dirtyconfig)
  1696. X    {
  1697. X        xwc.x = winInfo->core.x;
  1698. X        xwc.y = winInfo->core.y;
  1699. X        xwc.width = winInfo->core.width;
  1700. X        xwc.height = winInfo->core.height;
  1701. X        ConfigureWindow(dpy, winInfo,
  1702. X            winInfo->core.dirtyconfig, &xwc);
  1703. X        winInfo->core.dirtyconfig &= ~(CWX|CWY|CWWidth|CWHeight);
  1704. X    }
  1705. X
  1706. X    /* send synthetic configure notify in root coordinates */
  1707. X    ce.type = ConfigureNotify;
  1708. X    ce.serial = 0L;
  1709. X    ce.event = winInfo->core.self;
  1710. X    ce.window = winInfo->core.self;
  1711. X    WinRootPos(winInfo,&ce.x,&ce.y);
  1712. X    ce.x -= winInfo->pcore.oldBorderWidth;
  1713. X    ce.y -= winInfo->pcore.oldBorderWidth;
  1714. X    ce.width = winInfo->core.width;
  1715. X    ce.height = winInfo->core.height;
  1716. X    ce.border_width = winInfo->pcore.oldBorderWidth;
  1717. X    ce.above = None;
  1718. X    ce.override_redirect = False;
  1719. X
  1720. X    XSendEvent(dpy, winInfo->core.self, False, 
  1721. X            StructureNotifyMask, (XEvent *)&ce);
  1722. X}
  1723. X
  1724. X
  1725. X/* 
  1726. X * newconfigPane - compute a new configuration given an event
  1727. X * Note:  this function must *always* be called with a configure request
  1728. X * event.
  1729. X */
  1730. Xstatic int
  1731. XnewconfigPane(win, pxcre)
  1732. XWinPane *win;
  1733. XXConfigureRequestEvent *pxcre;
  1734. X{
  1735. X    int oldWidth, oldHeight;
  1736. X    Client *cli = win->core.client;
  1737. X    int oldX, oldY;
  1738. X    WinPaneFrame *winFrame = cli->framewin;
  1739. X    void FrameMoveRelative();
  1740. X    int dwidth, dheight;
  1741. X
  1742. X    if (pxcre == NULL)
  1743. X    return win->core.dirtyconfig;
  1744. X
  1745. X    WinRootPos(win, &oldX, &oldY);
  1746. X    oldWidth = win->core.width;
  1747. X    oldHeight = win->core.height;
  1748. X
  1749. X    if ((pxcre->value_mask & CWHeight) && (pxcre->height != oldHeight))
  1750. X    {
  1751. X    win->core.height = pxcre->height;
  1752. X    win->core.dirtyconfig |= CWHeight;
  1753. X    }
  1754. X
  1755. X    if ((pxcre->value_mask & CWWidth) && (pxcre->width != oldWidth))
  1756. X    {
  1757. X    win->core.width = pxcre->width;
  1758. X    win->core.dirtyconfig |= CWWidth;
  1759. X    }
  1760. X
  1761. X    if (pxcre->value_mask & CWBorderWidth)
  1762. X    {
  1763. X    win->pcore.oldBorderWidth = pxcre->border_width;
  1764. X    }
  1765. X
  1766. X    if (pxcre->value_mask & (CWX | CWY)) 
  1767. X    {
  1768. X    FrameSetPosAbsolute(winFrame,
  1769. X                (pxcre->value_mask & CWX)?(pxcre->x):oldX,
  1770. X                (pxcre->value_mask & CWY)?(pxcre->y):oldY);
  1771. X    }
  1772. X    else 
  1773. X    {
  1774. X    dwidth = oldWidth - win->core.width;
  1775. X    dheight = oldHeight - win->core.height;
  1776. X    if ((dwidth != 0) || (dheight!=0))
  1777. X    {
  1778. X        switch (cli->normHints->win_gravity)
  1779. X        {
  1780. X        case NorthWestGravity:
  1781. X            break;
  1782. X        case NorthGravity:
  1783. X            FrameMoveRelative(winFrame,dwidth/2,0);
  1784. X            break;
  1785. X        case NorthEastGravity:
  1786. X            FrameMoveRelative(winFrame,dwidth,0);
  1787. X            break;
  1788. X        case WestGravity:
  1789. X            FrameMoveRelative(winFrame,0,dheight/2);
  1790. X            break;
  1791. X        case CenterGravity:
  1792. X            FrameMoveRelative(winFrame,dwidth/2,dheight/2);
  1793. X            break;
  1794. X        case EastGravity:
  1795. X            FrameMoveRelative(winFrame,dwidth,dheight/2);
  1796. X            break;
  1797. X        case SouthWestGravity:
  1798. X            FrameMoveRelative(winFrame,0,dheight);
  1799. X            break;
  1800. X        case SouthGravity:
  1801. X            FrameMoveRelative(winFrame,dwidth/2,dheight);
  1802. X            break;
  1803. X        case SouthEastGravity:
  1804. X            FrameMoveRelative(winFrame,dwidth,dheight);
  1805. X            break;
  1806. X        }
  1807. X    }
  1808. X    }
  1809. X
  1810. X
  1811. X    if (pxcre->value_mask & (CWStackMode | CWSibling))
  1812. X    {
  1813. X    GFrameSetStack(winFrame, pxcre->value_mask, pxcre->detail, pxcre->above);
  1814. X    }
  1815. X
  1816. X    return win->core.dirtyconfig;
  1817. X}
  1818. X
  1819. X/* 
  1820. X * newposPane - move to a given position (relative to parent)
  1821. X */
  1822. Xstatic int
  1823. XnewposPane(win,x,y)
  1824. XWinPane *win;
  1825. Xint x, y;
  1826. X{
  1827. X    if (win->core.x != x)
  1828. X    {
  1829. X        win->core.x = x;
  1830. X        win->core.dirtyconfig |= CWX;
  1831. X    }
  1832. X
  1833. X    if (win->core.y != y)
  1834. X    {
  1835. X        win->core.y = y;
  1836. X        win->core.dirtyconfig |= CWY;
  1837. X    }
  1838. X
  1839. X    return win->core.dirtyconfig;
  1840. X}
  1841. X
  1842. X/* 
  1843. X * setsizePane - set the pane to a particular size, and initiate a reconfigure
  1844. X */
  1845. Xstatic int
  1846. XsetsizePane(win,w,h)
  1847. XWinPane *win;
  1848. Xint w, h;
  1849. X{
  1850. X    if (win->core.width != w)
  1851. X    {
  1852. X        win->core.width = w;
  1853. X        win->core.dirtyconfig |= CWWidth;
  1854. X    }
  1855. X
  1856. X    if (win->core.height != h)
  1857. X    {
  1858. X        win->core.height = h;
  1859. X        win->core.dirtyconfig |= CWHeight;
  1860. X    }
  1861. X}
  1862. X
  1863. X/***************************************************************************
  1864. X* global functions
  1865. X***************************************************************************/
  1866. X
  1867. X/*
  1868. X * MakePane  -- create the pane window. Return a WinGeneric structure.
  1869. X */
  1870. XWinPane *
  1871. XMakePane(cli,par,win,paneattrs)
  1872. XClient *cli;
  1873. XWinGeneric *par;
  1874. XWindow win;
  1875. XXWindowAttributes *paneattrs;
  1876. X{
  1877. X    WinPane *w;
  1878. X    XSetWindowAttributes attributes;
  1879. X    long mask;
  1880. X    WinColormap *colorwin;
  1881. X
  1882. X    /* this window may already be mentioned as a colourmap window.
  1883. X     * grab its colourmap window structure, and unhook it from the
  1884. X     * event dispatching table so we can register a new structure
  1885. X     * for the window.  We will call another function at the end
  1886. X     * of pane processing to re-establish the relation between this
  1887. X     * window and other structures in the system.
  1888. X     */
  1889. X    colorwin = ColormapUnhook(win);
  1890. X
  1891. X    /* create the associated structure */
  1892. X    w = MemNew(WinPane);
  1893. X    w->core.self = win;
  1894. X    w->class = &classPane;
  1895. X    w->core.kind = WIN_PANE;
  1896. X    WinAddChild(par,w);
  1897. X    w->core.children = NULL;
  1898. X    w->core.client = cli;
  1899. X    w->core.x = 0;         /* gets fixed up later */
  1900. X    w->core.y = 0;        /* gets fixed up later */
  1901. X    w->core.width = paneattrs->width;
  1902. X    w->core.height = paneattrs->height;
  1903. X    w->core.colormap = paneattrs->colormap;
  1904. X    w->core.dirtyconfig = CWX|CWY|CWWidth|CWHeight;
  1905. X    w->core.exposures = NULL;
  1906. X    w->pcore.oldBorderWidth = paneattrs->border_width;
  1907. X    w->pcore.oldSaveUnder = paneattrs->save_under;
  1908. X    w->core.helpstring = (char *)NULL;    /* no help */
  1909. X
  1910. X    cli->framewin->fcore.panewin = (WinGenericPane *)w;
  1911. X
  1912. X    /* register the window */
  1913. X    WIInstallInfo(w);
  1914. X
  1915. X    /* Put the window in the save set so it doesn't go away */
  1916. X    XChangeSaveSet(cli->dpy,win,SetModeInsert);
  1917. X
  1918. X        /*
  1919. X         * Since the pane is reparented, save-unders are not useful.
  1920. X         * In the code above the save-under attribute is propogated to
  1921. X         * the frame, so it is safe to remove it here.  But don't do this for 
  1922. X     * InputOnly windows.
  1923. X         */
  1924. X    if (paneattrs->class == InputOutput) {
  1925. X        attributes.save_under = False;
  1926. X        XChangeWindowAttributes(cli->dpy, win,
  1927. X                    (unsigned long) CWSaveUnder, &attributes);
  1928. X
  1929. X        /*
  1930. X         * Change the border width if necessary.  The border width of 
  1931. X         * InputOnly windows is zero by definition.
  1932. X         */
  1933. X        if (paneattrs->border_width != NORMAL_BORDERWIDTH)
  1934. X        XSetWindowBorderWidth(cli->dpy, win, NORMAL_BORDERWIDTH);
  1935. X    }
  1936. X
  1937. X        /*
  1938. X     * Focus Lenience.  Be lenient about enforcing the requirement that
  1939. X     * clients set the input hint in WM_HINTS before they can get keyboard
  1940. X     * input.  If this flag is set, and if the focus mode is NoInput, then
  1941. X     * force the mode to be passive.  This way, if a client either fails
  1942. X     * to set the WM_HINTS.input field, or fails to write WM_HINTS at all,
  1943. X     * it can still get keyboard input.
  1944. X     * 
  1945. X     * REMIND This kind of flag should be implemented on a
  1946. X     * client-by-client basis, not on a global basis.
  1947. X         */
  1948. X        if (GRV.FocusLenience && cli->focusMode == NoInput ) {
  1949. X            cli->focusMode = Passive;
  1950. X        }
  1951. X
  1952. X        /* Reparent the pane */
  1953. X        XReparentWindow(cli->dpy, win, par->core.self,
  1954. X        w->core.x, w->core.y);
  1955. X
  1956. X    /* we may have saved colourmap manipulation information at 
  1957. X     * the beginning.  Re-establish the connection between this window
  1958. X     * and other structures based on the old structure.
  1959. X     */
  1960. X    ColormapTransmogrify(colorwin, w);
  1961. X
  1962. X    return w;
  1963. X}
  1964. X
  1965. X/*
  1966. X * PaneInit -- initialise the Pane class function vector
  1967. X */
  1968. Xvoid
  1969. XPaneInit(dpy)
  1970. XDisplay *dpy;
  1971. X{
  1972. X    classPane.core.kind = WIN_PANE;
  1973. X    classPane.core.xevents[EnterNotify] = eventEnterLeaveNotify;
  1974. X    classPane.core.xevents[LeaveNotify] = eventEnterLeaveNotify;
  1975. X    classPane.core.xevents[ColormapNotify] = eventColormapNotify;
  1976. X    classPane.core.xevents[UnmapNotify] = eventUnmapNotify;
  1977. X    classPane.core.xevents[DestroyNotify] = eventDestroyNotify;
  1978. X    classPane.core.xevents[PropertyNotify] = eventPropertyNotify;
  1979. X    classPane.core.xevents[ClientMessage] = eventClientMessage;
  1980. X    classPane.core.extEventHdlr = eventExtension;
  1981. X    classPane.core.focusfunc = focusPane;
  1982. X    classPane.core.drawfunc = NULL;
  1983. X    classPane.core.destroyfunc = destroyPane;
  1984. X    classPane.core.selectfunc = NULL;
  1985. X    classPane.core.newconfigfunc = newconfigPane;
  1986. X    classPane.core.newposfunc = newposPane;
  1987. X    classPane.core.setconfigfunc = setconfigPane;
  1988. X    classPane.core.createcallback = NULL;
  1989. X    classPane.core.heightfunc = NULL;
  1990. X    classPane.core.widthfunc = NULL;
  1991. X    classPane.pcore.setsizefunc = setsizePane;
  1992. X}
  1993. END_OF_FILE
  1994. if test 12706 -ne `wc -c <'winpane.c'`; then
  1995.     echo shar: \"'winpane.c'\" unpacked with wrong size!
  1996. fi
  1997. # end of 'winpane.c'
  1998. fi
  1999. echo shar: End of archive 6 \(of 21\).
  2000. cp /dev/null ark6isdone
  2001. MISSING=""
  2002. 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
  2003.     if test ! -f ark${I}isdone ; then
  2004.     MISSING="${MISSING} ${I}"
  2005.     fi
  2006. done
  2007. if test "${MISSING}" = "" ; then
  2008.     echo You have unpacked all 21 archives.
  2009.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2010. else
  2011.     echo You still need to unpack the following archives:
  2012.     echo "        " ${MISSING}
  2013. fi
  2014. ##  End of shell archive.
  2015. exit 0
  2016. --
  2017. Molecular Simulations, Inc.             mail: dcmartin@postgres.berkeley.edu
  2018. 796 N. Pastoria Avenue                  uucp: uwvax!ucbvax!dcmartin
  2019. Sunnyvale, California 94086             at&t: 408/522-9236
  2020.