home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / x / volume15 / olvwm-3.0 / part07 < prev    next >
Text File  |  1992-02-03  |  57KB  |  2,179 lines

  1. Newsgroups: comp.sources.x
  2. Path: uunet!elroy.jpl.nasa.gov!ames!pasteur!nntp
  3. From: scott.oaks@East.Sun.COM (Scott Oaks)
  4. Subject: v15i153: OpenLook Virtual Window Mgr (3.0), Part07/21
  5. Message-ID: <1992Feb4.135625.7258@pasteur.Berkeley.EDU>
  6. Sender: dcmartin@msi.com (David C. Martin - Moderator)
  7. Nntp-Posting-Host: postgres.berkeley.edu
  8. Organization: University of California, at Berkeley
  9. References: <csx-15i147-olvwm-3.0@uunet.UU.NET>
  10. Date: Tue, 4 Feb 1992 13:56:25 GMT
  11. Approved: dcmartin@msi.com
  12.  
  13. Submitted-by: scott.oaks@East.Sun.COM (Scott Oaks)
  14. Posting-number: Volume 15, Issue 153
  15. Archive-name: olvwm-3.0/part07
  16.  
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  21. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  22. # If this archive is complete, you will see the following message at the end:
  23. #        "End of archive 7 (of 21)."
  24. # Contents:  client.c events.h winpush.c
  25. # Wrapped by dcmartin@fascet on Tue Jan 14 05:54:43 1992
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'client.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'client.c'\"
  29. else
  30. echo shar: Extracting \"'client.c'\" \(37162 characters\)
  31. sed "s/^X//" >'client.c' <<'END_OF_FILE'
  32. X/* 
  33. X *      (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents
  34. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  35. X *      file for terms of the license.
  36. X */
  37. X
  38. X/* client.c - functions relating to clients as a whole 
  39. X */
  40. X
  41. X#ident    "@(#)client.c    1.1 olvwm version 1/3/92"
  42. X
  43. X/*
  44. X * Based on
  45. X#ident    "@(#)client.c    26.42    91/09/14 SMI"
  46. X *
  47. X */
  48. X
  49. X#include <errno.h>
  50. X#include <stdio.h>
  51. X#include <X11/Xos.h>
  52. X#include <X11/Xlib.h>
  53. X#include <X11/Xutil.h>
  54. X#include <X11/Xatom.h>
  55. X#include <X11/keysym.h>
  56. X#include <olgx/olgx.h>
  57. X
  58. X#include "i18n.h"
  59. X#include "ollocale.h"
  60. X#include "events.h"
  61. X#include "mem.h"
  62. X#include "olwm.h"
  63. X#include "win.h"
  64. X#include "group.h"
  65. X#include "globals.h"
  66. X#include "virtual.h"
  67. X
  68. X/***************************************************************************
  69. X* global data
  70. X***************************************************************************/
  71. X
  72. X/*
  73. X * List of currently active clients.  All frames and icons and the no-focus 
  74. X * window are reachable by traversing this list.
  75. X */
  76. XList *ActiveClientList;
  77. X
  78. X/*
  79. X * Pointer to the "current" client.  This is usually the client whose window
  80. X * has the input focus, but not always.  The exceptions include icons and
  81. X * pinned menus, where the icon or menu window may be the "current" client but
  82. X * where the focus really is with the no-focus window.
  83. X */
  84. X
  85. XClient *CurrentClient = NULL;
  86. X
  87. X/*
  88. X * DoingWindowState indicates whether olwm is doing window state.
  89. X * This is set in InitClientState() and used in MakeRoot().
  90. X */
  91. XBool    DoingWindowState = False;
  92. X
  93. Xextern Atom AtomColorMapWindows;
  94. Xextern Atom AtomDecorDel;
  95. Xextern Atom AtomDecorAdd;
  96. Xextern Atom AtomDeleteWindow;
  97. Xextern Atom AtomProtocols;
  98. Xextern Atom AtomLeftFooter;
  99. Xextern Atom AtomRightFooter;
  100. Xextern Atom AtomShowProperties;
  101. Xextern Atom AtomTakeFocus;
  102. Xextern Atom AtomWindowBusy;
  103. Xextern Atom AtomWinAttr;
  104. Xextern Atom AtomWMState;
  105. Xextern Atom AtomWMName;
  106. Xextern Atom AtomWMIconName;
  107. Xextern Atom AtomWMHints;
  108. Xextern Atom AtomWMNormalHints;
  109. Xextern Atom AtomSunLedMap;
  110. Xextern Atom AtomSunWindowState;
  111. Xextern Atom AtomSunDragDropInterest;
  112. X
  113. Xextern void RecursiveRefresh();
  114. Xextern void PushPinChangeState();
  115. Xextern void FrameUpdateHeader();
  116. Xextern void FrameUpdateFooter();
  117. Xextern void IconUpdateName();
  118. Xextern void ColorUpdateColorMapWindows();
  119. Xextern void StateUpdateWinAttr();
  120. Xextern void StateUpdateDecorAdd();
  121. Xextern void StateUpdateDecorDel();
  122. Xextern void StateUpdateWMNormalHints();
  123. Xextern void StateUpdateWMHints();
  124. Xextern void StateUpdateWMProtocols();
  125. X
  126. X/***************************************************************************
  127. X* private data
  128. X***************************************************************************/
  129. X
  130. Xtypedef struct _ledstate {
  131. X    int    led;
  132. X    int    led_mode;
  133. X} LedState;
  134. X
  135. Xstatic    LedState    composeLedState;
  136. X
  137. Xstatic    Client        *lastCurrentClient = NULL;
  138. X
  139. X#define    LED_MAP_LENGTH        (33L)
  140. X
  141. X/***************************************************************************
  142. X* private functions
  143. X***************************************************************************/
  144. X
  145. Xstatic void clientSetBusy();
  146. X
  147. X/*
  148. X * setComposeLed - sets the compose led to the new mode iff different than
  149. X *           the current mode.
  150. X */
  151. Xstatic void
  152. XsetComposeLed(dpy,mode)
  153. X    Display        *dpy;
  154. X    int        mode;
  155. X{
  156. X    XKeyboardControl    kbdValue;
  157. X
  158. X    if (mode == composeLedState.led_mode)
  159. X        return;
  160. X
  161. X    composeLedState.led_mode = mode;
  162. X    kbdValue.led = composeLedState.led;
  163. X    kbdValue.led_mode = composeLedState.led_mode;
  164. X
  165. X    XChangeKeyboardControl(dpy,KBLed|KBLedMode,&kbdValue);
  166. X}
  167. X
  168. X/***************************************************************************
  169. X* global functions
  170. X***************************************************************************/
  171. X
  172. X/*
  173. X * InitClientState - init kbd led state for client use
  174. X */
  175. XInitClientState(dpy)
  176. XDisplay    *dpy;
  177. X{
  178. X    int    *ledMap;
  179. X    int    i,numLeds,led;
  180. X    unsigned int nitems,nremain;
  181. X    XKeyboardControl  kbdvalue;
  182. X
  183. X    DoingWindowState = False;
  184. X
  185. X    /* 
  186. X     * Get the _SUN_LED_MAP property from the default root window
  187. X     */
  188. X    ledMap = GetWindowProperty(dpy,DefaultRootWindow(dpy),AtomSunLedMap,
  189. X            0L,LED_MAP_LENGTH,XA_INTEGER,32,&nitems,&nremain);
  190. X
  191. X    if (ledMap == NULL || nitems != LED_MAP_LENGTH || nremain != 0) {
  192. X        return;
  193. X    }
  194. X    numLeds = ledMap[0];    /* first entry is the number of leds */
  195. X
  196. X    /*
  197. X     * Find out which led number is marked Compose
  198. X     */
  199. X    for (i = 1; i <= numLeds; i++) {
  200. X        if (ledMap[i] == XK_Multi_key) {
  201. X            composeLedState.led = i;
  202. X            composeLedState.led_mode = -1; /* for first time */
  203. X            DoingWindowState = True;
  204. X        }
  205. X    }
  206. X
  207. X    /* 
  208. X     * Turn off the compose led 
  209. X     */
  210. X    if (DoingWindowState)
  211. X        setComposeLed(dpy,LedModeOff);
  212. X
  213. X    XFree((char *)ledMap);
  214. X}
  215. X
  216. X/*
  217. X * ClientDefaultWindowState - applies the default window state
  218. X */
  219. XClientDefaultWindowState(dpy)
  220. X    Display    *dpy;
  221. X{
  222. X    setComposeLed(dpy,LedModeOff);
  223. X}
  224. X
  225. X/*
  226. X * ClientSetWindowState - applies the client's window state
  227. X */
  228. XClientSetWindowState(cli)
  229. X    Client    *cli;
  230. X{
  231. X    if (!DoingWindowState)
  232. X        return;
  233. X
  234. X    /*
  235. X      * If the client has specified the window state then interpret it.
  236. X      */
  237. X    if (cli->windowState) {
  238. X        if (cli->windowState->flags & WSSemanticState) {
  239. X            if (cli->windowState->state & WSSemanticCompose)
  240. X                setComposeLed(cli->dpy,LedModeOn);
  241. X            else
  242. X                setComposeLed(cli->dpy,LedModeOff);
  243. X        }
  244. X    /*
  245. X     * Else just apply the default state
  246. X     */
  247. X    } else {
  248. X        ClientDefaultWindowState(cli->dpy);
  249. X    }
  250. X}
  251. X
  252. X/*
  253. X * ClientGetWindowState - gets the _SUN_WINDOW_STATE property and if the
  254. X *              client has the focus then apply that new state.
  255. X */
  256. XClientGetWindowState(cli)
  257. X    Client    *cli;
  258. X{
  259. X    Window        pane;
  260. X    OLWindowState    winState;
  261. X
  262. X    if (!DoingWindowState)
  263. X        return;
  264. X
  265. X    if (cli->framewin == NULL)
  266. X        return;
  267. X
  268. X    pane = PANEWINOFCLIENT(cli);
  269. X
  270. X    if (!PropGetOLWindowState(cli->dpy,pane,&winState))
  271. X        return;
  272. X
  273. X    if (cli->windowState == NULL)
  274. X        cli->windowState = MemNew(OLWindowState);
  275. X
  276. X    *cli->windowState = winState;
  277. X
  278. X    if (cli->isFocus)
  279. X        ClientSetWindowState(cli);
  280. X}
  281. X
  282. X/*
  283. X * ClientUpdateWindowState - handle PropertyNotify on _SUN_WINDOW_STATE
  284. X */
  285. Xvoid
  286. XClientUpdateWindowState(cli,event)
  287. X    Client        *cli;
  288. X    XPropertyEvent    *event;
  289. X{
  290. X    if (!DoingWindowState)
  291. X        return;
  292. X
  293. X    if (event->state == PropertyNewValue) {
  294. X        ClientGetWindowState(cli);
  295. X    } else {
  296. X        if (cli->windowState)
  297. X            MemFree((char *)cli->windowState);
  298. X        cli->windowState = (OLWindowState *)NULL;
  299. X        ClientDefaultWindowState(cli->dpy);
  300. X    }
  301. X}
  302. X
  303. X/* ClientSendProtocol - send a protocol message to a client
  304. X */
  305. Xvoid *
  306. XClientSendProtocol(cli,proto,evtime)
  307. XClient *cli;
  308. XAtom proto;
  309. XTime evtime;
  310. X{
  311. X    XEvent          clientEvent;
  312. X
  313. X    clientEvent.xclient.type = ClientMessage;
  314. X    clientEvent.xclient.message_type = AtomProtocols;
  315. X    clientEvent.xclient.format = 32;
  316. X    clientEvent.xclient.display = cli->dpy;
  317. X    clientEvent.xclient.window = ClientPane(cli);
  318. X    clientEvent.xclient.data.l[0] = proto;
  319. X    clientEvent.xclient.data.l[1] = evtime;
  320. X
  321. X    XSendEvent(cli->dpy, clientEvent.xclient.window, False,
  322. X        NoEventMask, &clientEvent);
  323. X    return NULL;
  324. X}
  325. X
  326. X/* ClientShowProps - send a ClientMessage of type WM_SHOW_PROPERTIES
  327. X */
  328. Xvoid
  329. XClientShowProps(cli)
  330. XClient *cli;
  331. X{
  332. X    XEvent clientEvent;
  333. X    
  334. X    clientEvent.xclient.type = ClientMessage;
  335. X    clientEvent.xclient.message_type = AtomShowProperties;
  336. X    clientEvent.xclient.format = 32;
  337. X    clientEvent.xclient.display = cli->dpy;
  338. X    clientEvent.xclient.window = PANEWINOFCLIENT(cli);
  339. X
  340. X    XSendEvent(cli->dpy, clientEvent.xclient.window, False,
  341. X        NoEventMask, &clientEvent);
  342. X}
  343. X
  344. X/* ClientKill - a client must be killed.  If it can handle the DELETE_WINDOW
  345. X *    protocol, use it; otherwise, if we are forcing the client to go
  346. X *    away, kill it.
  347. X */
  348. Xvoid *
  349. XClientKill(cli,pforce)
  350. XClient *cli;
  351. XBool pforce;
  352. X{
  353. X    if (cli->framewin == NULL)
  354. X        return NULL;
  355. X
  356. X    if (cli->protocols & DELETE_WINDOW) {
  357. X        ClientSendProtocol(cli,AtomDeleteWindow,LastEventTime);
  358. X    } else {
  359. X        if (pforce && ! cli->flags & CLOlwmOwned)
  360. X            XKillClient(cli->dpy,ClientPane(cli));
  361. X        else
  362. X            if (GRV.Beep == BeepAlways)
  363. X                XBell(cli->dpy, 100);
  364. X    }
  365. X    return NULL;    
  366. X}
  367. X
  368. X/* ClientShutdown - a client must be shut down.  Force the client
  369. X * the go away without any further user interaction.
  370. X */
  371. Xvoid *
  372. XClientShutdown(cli,junk)
  373. XClient    *cli;
  374. Xvoid    *junk;
  375. X{
  376. X    /* Only kill non-olwm owned clients */
  377. X    if (! cli->flags & CLOlwmOwned)
  378. X        XKillClient(cli->dpy,ClientPane(cli));
  379. X    return NULL;
  380. X}
  381. X
  382. X
  383. X/* UnparentClient - while exiting OLWM: unmap all icons that are on the
  384. X * screen.  Reparent all windows back to the root, suitably offset
  385. X * according to their window-gravities.  Also remap all non-withdrawn
  386. X * windows, and remove all Withdrawn windows from the save-set (so
  387. X * they don't get remapped.  REMIND: We have to do this because
  388. X * Withdrawn windows are still left reparented inside the frame; this
  389. X * shouldn't be the case.
  390. X */
  391. X/*ARGSUSED*/
  392. Xvoid *
  393. XUnparentClient(cli,junk)
  394. XClient *cli;
  395. Xvoid *junk;
  396. X{
  397. X    WinPaneFrame *frameInfo;
  398. X    WinPane *paneInfo;
  399. X    Window pane;
  400. X
  401. X    /* if no framewin then it's probably a root window */
  402. X    if (cli->framewin == NULL)
  403. X        return NULL;
  404. X
  405. X    if (cli->wmState == IconicState)
  406. X    {
  407. X        IconHide(cli, cli->iconwin);
  408. X    }
  409. X
  410. X    frameInfo = cli->framewin;
  411. X    paneInfo = (WinPane*)(frameInfo->fcore.panewin);
  412. X    pane = paneInfo->core.self;
  413. X    FrameUnparentPane(cli, frameInfo, paneInfo);
  414. X
  415. X    if (cli->wmState == DontCareState) 
  416. X    { 
  417. X        if (!(cli->flags & CLOlwmOwned))
  418. X            XChangeSaveSet(cli->dpy, pane, SetModeDelete);
  419. X    } 
  420. X    else 
  421. X    {
  422. X        XMapWindow(cli->dpy,pane);
  423. X    }
  424. X
  425. X    return NULL;
  426. X}
  427. X
  428. X/*
  429. X * addClient -- add this client structure to the list of active clients
  430. X */
  431. Xstatic void
  432. XaddClient(cli)
  433. XClient *cli;
  434. X{
  435. X    List *l = ActiveClientList;
  436. X    Client *tc;
  437. X
  438. X        /* First look to see if window is already listed.  */
  439. X        for(tc = ListEnum(&l); tc != NULL; tc = ListEnum(&l))
  440. X        {
  441. X                if (tc == cli)
  442. X                        return;
  443. X        }
  444. X
  445. X        /* Wasn't present, add to list. */
  446. X    ActiveClientList = ListCons(cli, ActiveClientList);
  447. X}
  448. X
  449. X/*
  450. X * removeClient -- remove this client structure from the list of active
  451. X *      clients.
  452. X */
  453. Xstatic void
  454. XremoveClient(cli)
  455. XClient *cli;
  456. X{
  457. X    List **l;
  458. X
  459. X    for (l = &ActiveClientList ; *l != NULL; l = &((*l)->next))
  460. X    {
  461. X        if ((*l)->value == cli)
  462. X        {
  463. X            ListDestroyCell(l);
  464. X            return;
  465. X        }
  466. X    }
  467. X}
  468. X
  469. X/* 
  470. X * DestroyClient -- destroy all resources associated with this client, and 
  471. X * remove external references to this client.  If this is the current client, 
  472. X * and we are in click-to-type, set the focus to the topmost client *after* 
  473. X * having destroyed this client.
  474. X */
  475. Xvoid 
  476. XDestroyClient(cli)
  477. XClient *cli;
  478. X{
  479. X    Bool        setfocus = False;
  480. X    Display        *dpy = cli->dpy;
  481. X    ScreenInfo  *scrInfo = cli->scrInfo;
  482. X    List        *l;
  483. X    Client        *tcli;
  484. X
  485. X    UnTrackSubwindows(cli, True);
  486. X    if (IsSelected(cli))
  487. X        RemoveSelection(cli);
  488. X
  489. X    if (cli == CurrentClient) {
  490. X        ClientSetCurrent(NoFocusWinInfo->core.client);
  491. X        /* purge the old client from lastCurrentClient */
  492. X        /* REMIND need a better interface */
  493. X        lastCurrentClient = NULL;
  494. X
  495. X        setfocus = !GRV.FocusFollowsMouse;
  496. X    }
  497. X    
  498. X    removeClient(cli);
  499. X
  500. X    /*
  501. X     * Run through the remaining clients and remove any references to this 
  502. X     * client from their warp-back records.
  503. X     */
  504. X    l = ActiveClientList;
  505. X    while (tcli = ListEnum(&l)) {
  506. X        if (tcli->framewin != NULL &&
  507. X        tcli->warpInfo.warpBackClient == cli)
  508. X        {
  509. X        tcli->framewin->pointerIsWarped = False;
  510. X        }
  511. X    }
  512. X
  513. X    /* destroy the window resources associated with the client */
  514. X    WinCallDestroy(cli);
  515. X
  516. X    GroupRemove(cli->groupid, cli);
  517. X
  518. X    /* free up the client structure resources */
  519. X    if (cli->wmDecors)
  520. X        MemFree(cli->wmDecors);
  521. X    if (cli->normHints)
  522. X        MemFree(cli->normHints);
  523. X    if (cli->wmHints)
  524. X        MemFree(cli->wmHints);
  525. X    if (cli->wmInstance)
  526. X        MemFree(cli->wmInstance);
  527. X    if (cli->wmClass)
  528. X        MemFree(cli->wmClass);
  529. X    if (cli->windowState)
  530. X        MemFree(cli->windowState);
  531. X
  532. X    /* REMIND  what's to be done with followers here? */
  533. X
  534. X#ifdef DEBUG
  535. X    memset(cli, 0, sizeof(Client));
  536. X#endif /* DEBUG */
  537. X
  538. X    MemFree(cli);
  539. X
  540. X    if (setfocus)
  541. X        ClientFocusTopmost(dpy, scrInfo, CurrentTime);
  542. X}
  543. X
  544. X/*
  545. X * ClientConfigure - a configure request event has been received on the
  546. X * pane.  Configure the windows accordingly.
  547. X */
  548. Xvoid
  549. XClientConfigure(cli,win,pxcre)
  550. XClient *cli;
  551. XWinGeneric *win;
  552. XXConfigureRequestEvent *pxcre;
  553. X{
  554. X        XWindowChanges          winChange;
  555. X
  556. X    if ((cli == NULL) || (win == NULL))
  557. X    {
  558. X                /* We don't know about this window, or it's withdrawn
  559. X                 * convert the request into an XConfigureWindow
  560. X                 * call. We do not look at the hints to see if
  561. X                 * the resize is in the proper increments, but since
  562. X                 * the app is asking for the reconfigure this seems
  563. X                 * right.
  564. X                 */
  565. X                winChange.x = pxcre->x;
  566. X                winChange.y = pxcre->y;
  567. X                winChange.width = pxcre->width;
  568. X                winChange.height = pxcre->height;
  569. X                winChange.border_width = pxcre->border_width;
  570. X                winChange.stack_mode = pxcre->detail;
  571. X                winChange.sibling = pxcre->above;
  572. X
  573. X                XConfigureWindow(pxcre->display,
  574. X                         pxcre->window,
  575. X                         /* lint will warn: this is a long, not int */
  576. X                         (int) pxcre->value_mask,
  577. X                         &winChange );
  578. X    }
  579. X    else /* cli->wmState == NormalState or IconicState */
  580. X    {
  581. X        WinCallConfig(cli->dpy,win,pxcre);
  582. X    }
  583. X}
  584. X
  585. X/*
  586. X * ClientSetWMState     -- set the contents of the WM_STATE property,
  587. X *                         given the information in the WinInfo struct.
  588. X */
  589. Xvoid
  590. XClientSetWMState( cli )
  591. X    Client *cli;
  592. X{
  593. X    WinIconFrame *iconWinInfo = cli->iconwin;
  594. X    Window     pane = PANEWINOFCLIENT(cli);
  595. X    Window    icon;
  596. X
  597. X    if (cli->framewin->core.self ==
  598. X        cli->scrInfo->vdm->client->framewin->core.self)
  599. X        return;
  600. X    if (iconWinInfo) {
  601. X            if ( iconWinInfo->fcore.panewin )
  602. X                icon = iconWinInfo->fcore.panewin->core.self;
  603. X            else
  604. X                    icon = iconWinInfo->core.self;
  605. X        } else {
  606. X            icon = None;
  607. X        }
  608. X
  609. X    PropSetWMState(cli->dpy,pane,cli->wmState,icon);
  610. X}
  611. X
  612. X
  613. X/* ===== Drag-and-Drop Interest Property ================================== */
  614. X
  615. X
  616. X#define DRAGDROP_VERSION    0
  617. X#define INTEREST_RECT        0
  618. X#define INTEREST_WINDOW        1
  619. X#define SITE_DEFAULT        (1<<2)
  620. X#define SITE_FORWARD        (1<<3)
  621. X
  622. X/*
  623. X * Get the next word from the `data' array, indexed by `cur'.  If this causes 
  624. X * us to go beyond `nitems', return silently.
  625. X */
  626. X#define NEXTWORD(dest) do {                        \
  627. X        if (++cur >= nitems) {                    \
  628. X        XFree((char *)data);                    \
  629. X        return;                            \
  630. X        }                                \
  631. X        (dest) = data[cur];                        \
  632. X    } while (0)
  633. X
  634. X#define INCR(by) do {                            \
  635. X        cur += (by);                        \
  636. X        if (cur >= nitems)                        \
  637. X        return;                            \
  638. X    } while (0)
  639. X
  640. X
  641. Xstatic struct {
  642. X    unsigned long
  643. X    version,
  644. X    nsites,
  645. X    wid,
  646. X    sid,
  647. X    flags,
  648. X    areatype,
  649. X    nelts,
  650. X    rx, ry, rw, rh;
  651. X} forwardingInterest = {
  652. X    0,            /* version */
  653. X    1,            /* nsites */
  654. X    0,            /* window id -- to be filled in */
  655. X    0,            /* site id -- to be filled in */
  656. X    0,            /* flags -- to be filled in */
  657. X    INTEREST_RECT,    /* areatype */
  658. X    1,            /* number of rects */
  659. X    0, 0, 0, 0        /* rectangle -- to be filled in */
  660. X};
  661. X#define FI_LENGTH \
  662. X    (sizeof(forwardingInterest)/sizeof(unsigned long))
  663. X
  664. X
  665. X/*
  666. X * ClientProcessDragDropInterest - read the clients drag'n'drop interest
  667. X * property, and put an interest containing the default site onto the frame
  668. X * window and the icon window.  If we encounter an error reading the property,
  669. X * do nothing and return silently.
  670. X */
  671. Xvoid
  672. XClientProcessDragDropInterest(cli, state)
  673. X    Client *cli;
  674. X    int state;        /* PropertyNewValue or PropertyDelete */
  675. X{
  676. X    unsigned long *data;
  677. X    int nitems, remain, nsites, i, areatype, nelts;
  678. X    int cur = 0;
  679. X    Window wid;
  680. X    unsigned long sid, flags;
  681. X
  682. X    if (state == PropertyDelete) {
  683. X    DeleteProperty(cli->dpy, cli->framewin,
  684. X        AtomSunDragDropInterest);
  685. X    if (cli->iconwin != NULL)
  686. X        DeleteProperty(cli->dpy, cli->iconwin,
  687. X        AtomSunDragDropInterest);
  688. X    return;
  689. X    }
  690. X
  691. X    data = GetWindowProperty(cli->dpy, PANEWINOFCLIENT(cli),
  692. X    AtomSunDragDropInterest, 0L, 1000000L, AtomSunDragDropInterest,
  693. X    32, &nitems, &remain);
  694. X
  695. X    if (data == NULL)
  696. X    return;
  697. X
  698. X    if (data[cur] != DRAGDROP_VERSION) {
  699. X    XFree((char *)data);
  700. X    return;
  701. X    }
  702. X
  703. X    NEXTWORD(nsites);
  704. X    for (i=0; i<nsites; ++i) {
  705. X    NEXTWORD(wid);
  706. X    NEXTWORD(sid);
  707. X    NEXTWORD(flags);
  708. X    NEXTWORD(areatype);
  709. X    switch (areatype) {
  710. X    case INTEREST_RECT:
  711. X        NEXTWORD(nelts);
  712. X        INCR(4*nelts);
  713. X        break;
  714. X    case INTEREST_WINDOW:
  715. X        NEXTWORD(nelts);
  716. X        INCR(nelts);
  717. X        break;
  718. X    default:
  719. X        /* unknown area type; just return */
  720. X        XFree((char *)data);
  721. X        return;
  722. X    }
  723. X    if (flags & SITE_DEFAULT) {
  724. X        forwardingInterest.wid = wid;
  725. X        forwardingInterest.sid = sid;
  726. X        forwardingInterest.flags = flags & ~SITE_DEFAULT;
  727. X        forwardingInterest.flags |= SITE_FORWARD;
  728. X
  729. X        /* write the property on the frame */
  730. X
  731. X        forwardingInterest.rx = 0;
  732. X        forwardingInterest.ry = 0;
  733. X        forwardingInterest.rw = cli->framewin->core.width;
  734. X        forwardingInterest.rh = cli->framewin->core.height;
  735. X        ChangeProperty(cli->dpy, cli->framewin,
  736. X        AtomSunDragDropInterest, AtomSunDragDropInterest,
  737. X        32, PropModeReplace,
  738. X        (unsigned char *) &forwardingInterest, FI_LENGTH);
  739. X
  740. X        /* write the property on the icon */
  741. X        if (cli->iconwin != NULL) {
  742. X        forwardingInterest.rx = 0;
  743. X        forwardingInterest.ry = 0;
  744. X        forwardingInterest.rw = cli->iconwin->core.width;
  745. X        forwardingInterest.rh = cli->iconwin->core.height;
  746. X        ChangeProperty(cli->dpy, cli->iconwin,
  747. X            AtomSunDragDropInterest, AtomSunDragDropInterest,
  748. X            32, PropModeReplace,
  749. X            (unsigned char *) &forwardingInterest, FI_LENGTH);
  750. X        }
  751. X        break;
  752. X    }
  753. X    }
  754. X    XFree((char *)data);
  755. X}
  756. X
  757. X/*
  758. X * ClientUpdateDragDropInterest - handle PropertyNotify on DragDropInterest
  759. X */
  760. Xvoid
  761. XClientUpdateDragDropInterest(cli,event)
  762. X    Client        *cli;
  763. X    XPropertyEvent    *event;
  764. X{
  765. X    ClientProcessDragDropInterest(cli,event->state);
  766. X}
  767. X
  768. X
  769. X/* ClientCreate -- allocate and initialise a client structure 
  770. X */
  771. XClient *
  772. XClientCreate(dpy,screen)
  773. X    Display *dpy;
  774. X    int     screen;
  775. X{
  776. X    Client *cli = MemNew(Client);
  777. X
  778. X    cli->wmState = DontCareState;
  779. X    cli->dpy = dpy;
  780. X    cli->screen = screen;
  781. X    cli->scrInfo = GetScrInfoOfScreen(screen);
  782. X    /* all other fields set to zero by allocation function */
  783. X    addClient(cli);
  784. X    return cli;
  785. X}
  786. X
  787. X/* ClientPane - return the pane window of a client
  788. X */
  789. XWindow
  790. XClientPane(cli)
  791. XClient *cli;
  792. X{
  793. X    WinPaneFrame *wf;
  794. X    WinPane *wp;
  795. X
  796. X    if ((wf = cli->framewin) == NULL)
  797. X        return NULL;
  798. X    if ((wp = (WinPane *)(wf->fcore.panewin)) == NULL)
  799. X        return NULL;
  800. X    return wp->core.self;
  801. X}
  802. X
  803. X
  804. X/*
  805. X * ClientOpenCloseToggle
  806. X *    Perform the appropriate open/close action.
  807. X */
  808. Xvoid
  809. XClientOpenCloseToggle(cli)
  810. XClient    *cli;
  811. X{
  812. X    /*
  813. X     * If we are a pop-up (have a pushpin) or are transient,
  814. X     * then dismiss.
  815. X     */
  816. X    if ((cli->wmDecors->flags & WMDecorationPushPin)
  817. X        || cli->transientFor != 0) {
  818. X        ClientKill(cli,False);
  819. X
  820. X    /* else switch the state from/to normal/iconic */
  821. X    } else {
  822. X        switch (cli->wmState) {
  823. X        case NormalState:
  824. X            StateNormIcon(cli);
  825. X            break;
  826. X        case IconicState:
  827. X            StateIconNorm(cli);
  828. X            break;
  829. X        default:
  830. X            break;
  831. X        }
  832. X    }
  833. X}
  834. X
  835. X/*
  836. X * ClientStickUnstickToggle
  837. X *    Perform the appropriate Stick/Unstick action.
  838. X */
  839. Xvoid
  840. XClientStickUnstickToggle(cli)
  841. XClient    *cli;
  842. X{
  843. X    MakeSticky(cli, !cli->sticky);
  844. X    if (cli->groupmask == GROUP_LEADER)
  845. X    GroupApply(cli->groupid, MakeSticky, cli->sticky, GROUP_DEPENDENT);
  846. X}
  847. X
  848. X/*
  849. X * ClientFullRestoreSizeToggle
  850. X *    Call both frame and icon full/restore toggle functions.
  851. X */
  852. Xvoid
  853. XClientFullRestoreSizeToggle(cli)
  854. XClient    *cli;
  855. X{
  856. X    if (cli->wmDecors->flags & WMDecorationResizeable) {
  857. X        (WinFunc(cli->framewin,fcore.fullrestoreToggle))(cli);
  858. X        (WinFunc(cli->iconwin,fcore.fullrestoreToggle))(cli);
  859. X    }
  860. X}
  861. X
  862. X/*
  863. X * ClientMove
  864. X *    Moves the client to a new x,y position.
  865. X */
  866. Xvoid
  867. XClientMove(cli,trigger)
  868. X        Client     *cli;
  869. X    XEvent    *trigger;
  870. X{
  871. X    UserMoveWindows(cli, trigger);
  872. X}
  873. X
  874. X/*
  875. X * ClientResize
  876. X *    Resizes the client to a new w,h size.
  877. X */
  878. Xvoid
  879. XClientResize(cli,trigger,which,callback,cbarg)
  880. X        Client     *cli;
  881. X    XEvent    *trigger;
  882. X    WhichResize which;
  883. X    void    (*callback)();
  884. X    void    *cbarg;
  885. X{
  886. X    if (cli->wmDecors->flags & WMDecorationResizeable)
  887. X        UserResizeWin(cli, trigger, which, callback, cbarg);
  888. X}
  889. X
  890. X
  891. X/*
  892. X * ClientRaiseTransients
  893. X *
  894. X * Raise any transient windows associated with this client.  Return the 
  895. X * client for the bottommost transient window.  This is useful so that the 
  896. X * parent window can be restacked just below the bottommost transient.  If 
  897. X * there are no transient windows, returns NULL.
  898. X *
  899. X * REMIND raises all transient windows in the order they are encountered in 
  900. X * the active client list, and returns the first one found.  Ideally, this 
  901. X * should preserve the stacking order of the transients.
  902. X */
  903. XClient *
  904. XClientRaiseTransients(cli)
  905. X    Client *cli;
  906. X{
  907. X    List *l = ActiveClientList;
  908. X    Client *tc;
  909. X    Client *first = NULL;
  910. X
  911. X    if (!GRV.KeepTransientsAbove)
  912. X    return NULL;
  913. X
  914. X    while (tc = ListEnum(&l)) {
  915. X    if (tc->transientFor == PANEWINOFCLIENT(cli)) {
  916. X        RaiseWindow(tc->framewin);
  917. X        if (first == NULL)
  918. X        first = tc;
  919. X    }
  920. X    }
  921. X    return first;
  922. X}
  923. X
  924. X
  925. X/*
  926. X * ClientLowerTransients
  927. X *
  928. X * Restack any transient windows associated with this client to be just above 
  929. X * this client's frame.
  930. X *
  931. X * REMIND this lowers all transient windows in the order they are encountered 
  932. X * in the active client list.  Ideally, this should preserve the stacking 
  933. X * order of the transients.
  934. X */
  935. Xvoid
  936. XClientLowerTransients(cli)
  937. X    Client *cli;
  938. X{
  939. X    List *l = ActiveClientList;
  940. X    Client *tc;
  941. X    XWindowChanges xwc;
  942. X
  943. X    if (!GRV.KeepTransientsAbove)
  944. X    return;
  945. X
  946. X    xwc.stack_mode = Above;
  947. X    xwc.sibling = cli->framewin->core.self;
  948. X    while (tc = ListEnum(&l)) {
  949. X    if (tc->transientFor == PANEWINOFCLIENT(cli)) {
  950. X        ConfigureWindow(tc->dpy, tc->framewin,
  951. X                 CWSibling | CWStackMode, &xwc);
  952. X    }
  953. X    }
  954. X}
  955. X
  956. X
  957. X/*
  958. X * ClientFront
  959. X * 
  960. X * Moves the appropriate client window to the front of the window hierarchy.
  961. X * If this window has any transient windows, move them in front first.
  962. X */
  963. Xvoid
  964. XClientFront(cli)
  965. XClient    *cli;
  966. X{
  967. X    Client *firsttransient;
  968. X    XWindowChanges xwc;
  969. X
  970. X    switch (cli->wmState) {
  971. X    case NormalState:
  972. X        firsttransient = ClientRaiseTransients(cli);
  973. X        if (firsttransient != NULL) {
  974. X            xwc.sibling = firsttransient->framewin->core.self;
  975. X            xwc.stack_mode = Below;
  976. X            ConfigureWindow(cli->dpy, cli->framewin,
  977. X                     CWSibling | CWStackMode, &xwc);
  978. X        } else {
  979. X            RaiseWindow(cli->framewin);
  980. X        }
  981. X        break;
  982. X    case IconicState:
  983. X        RaiseWindow(cli->iconwin);
  984. X        break;
  985. X    default:
  986. X        break;
  987. X    }
  988. X}
  989. X
  990. X
  991. X/*
  992. X * ClientBack
  993. X * 
  994. X * Moves the appropriate client window to the back of the window hierarchy.
  995. X * If this is a transient window, move its parent window to the back first, 
  996. X * and then move this window just in front of it.
  997. X *
  998. X * REMIND this isn't optimal behavior for transient windows, but it does 
  999. X * ensure that transient windows always remain in front of their parents.
  1000. X */
  1001. Xvoid
  1002. XClientBack(cli)
  1003. XClient    *cli;
  1004. X{
  1005. X    WinGeneric *owner;
  1006. X    Window ownerwin;
  1007. X    XWindowChanges xwc;
  1008. X
  1009. X    switch (cli->wmState) {
  1010. X    case NormalState:
  1011. X        if (cli->transientFor != 0 && GRV.KeepTransientsAbove) {
  1012. X            owner = WIGetInfo(cli->transientFor);
  1013. X            if (owner == NULL ||
  1014. X                owner->core.kind != WIN_PANE) {
  1015. X            LowerWindow(cli->framewin);
  1016. X            } else {
  1017. X            ownerwin = owner->core.client->framewin->core.self;
  1018. X            LowerWindow(owner->core.client->framewin);
  1019. X            xwc.sibling = ownerwin;
  1020. X            xwc.stack_mode = Above;
  1021. X            ConfigureWindow(cli->dpy, cli->framewin,
  1022. X                     CWSibling | CWStackMode, &xwc);
  1023. X            }
  1024. X        } else {
  1025. X            LowerWindow(cli->framewin);
  1026. X        }
  1027. X        break;
  1028. X    case IconicState:
  1029. X        LowerWindow(cli->iconwin);
  1030. X        break;
  1031. X    default:
  1032. X        break;
  1033. X    }
  1034. X}
  1035. X
  1036. X
  1037. X/*
  1038. X * ClientToggleStacking
  1039. X *
  1040. X * Moves the appropriate client window to the front of the window hierarchy if 
  1041. X * it is obscured, otherwise move it to the back of the hierarchy if it 
  1042. X * obscures any other window.  REMIND: doesn't deal with transient windows at 
  1043. X * all.
  1044. X */
  1045. Xvoid
  1046. XClientToggleStacking(cli)
  1047. XClient    *cli;
  1048. X{
  1049. X    XWindowChanges xwc;
  1050. X    WinGeneric *win;
  1051. X
  1052. X    switch (cli->wmState) {
  1053. X    case NormalState:
  1054. X        win = (WinGeneric *) cli->framewin;
  1055. X        break;
  1056. X    case IconicState:
  1057. X        win = (WinGeneric *) cli->iconwin;
  1058. X        break;
  1059. X    }
  1060. X
  1061. X    xwc.stack_mode = Opposite;
  1062. X    ConfigureWindow(cli->dpy, win, CWStackMode, &xwc);
  1063. X}
  1064. X
  1065. X
  1066. X/*
  1067. X * ClientRefresh
  1068. X *      Refresh the window.  We do this by creating a window on top
  1069. X *     of the window to refresh and then immediately destroy it.
  1070. X *    Refresh either icon or frame windows.
  1071. X */
  1072. Xvoid
  1073. XClientRefresh(cli)
  1074. XClient *cli;
  1075. X{
  1076. X    Window     w,cliwin;
  1077. X    int    cliwidth,cliheight;
  1078. X    XSetWindowAttributes xswa;
  1079. X
  1080. X    /*     Chose which window to refresh */
  1081. X    switch (cli->wmState) {
  1082. X    case NormalState:
  1083. X        cliwin = cli->framewin->core.self;
  1084. X        cliwidth = cli->framewin->core.width;
  1085. X        cliheight = cli->framewin->core.height;
  1086. X        break;
  1087. X    case IconicState:
  1088. X        cliwin = cli->iconwin->core.self;
  1089. X        cliwidth = cli->iconwin->core.width;
  1090. X        cliheight = cli->iconwin->core.height;
  1091. X        break;
  1092. X    default:
  1093. X        return;
  1094. X        /*NOTREACHED*/
  1095. X        break;
  1096. X    }
  1097. X
  1098. X    /*    if we should refresh all windows */
  1099. X        if (GRV.RefreshRecursively) {
  1100. X        RecursiveRefresh(cli->dpy,cliwin);
  1101. X
  1102. X    /*     or just the top/main window */
  1103. X        } else {
  1104. X        w = XCreateWindow(cli->dpy,
  1105. X            cliwin, 0, 0, cliwidth, cliheight, 0,
  1106. X                CopyFromParent, InputOutput, CopyFromParent,
  1107. X                0, &xswa);
  1108. X        XMapRaised(cli->dpy,w);
  1109. X        XDestroyWindow(cli->dpy,w);
  1110. X    }
  1111. X}
  1112. X
  1113. X/*
  1114. X * ClientFlashOwner
  1115. X *    Find group leader frame, bring it to the top and then
  1116. X *    flash its title bar.
  1117. X * 
  1118. X *    REMIND:  make sure transient windows get treated properly
  1119. X *         before or after (which? not sure) the leader is raised.
  1120. X */
  1121. Xvoid
  1122. XClientFlashOwner(cli)
  1123. XClient    *cli;
  1124. X{
  1125. X    Client  *cliLead = GroupLeader(cli->groupid);
  1126. X    if (cliLead && cliLead->framewin) {
  1127. X        RaiseWindow(cliLead->framewin);
  1128. X        WinCallDraw((WinGeneric *)cliLead->framewin);
  1129. X        FrameFlashTitleBar(cliLead->framewin);
  1130. X    }
  1131. X}
  1132. X
  1133. X/*
  1134. X * Toggle the pushpin of this client's window.  Returns False if this client's 
  1135. X * window has no pin, otherwise, returns True.
  1136. X */
  1137. XBool
  1138. XClientTogglePin(cli)
  1139. X    Client *cli;
  1140. X{
  1141. X    WinPushPin *pin;
  1142. X
  1143. X    if (cli->framewin == NULL || !ClientIsPinnable(cli))
  1144. X    return False;
  1145. X
  1146. X    pin = (WinPushPin *)cli->framewin->winDeco;
  1147. X    PushPinTogglePinState(cli->dpy,pin,True);
  1148. X    return True;
  1149. X}
  1150. X
  1151. X
  1152. X/* ClientInBox -- given a bounding box, apply a function to all clients
  1153. X *      which fall inside the rectangle
  1154. X */
  1155. Xvoid *
  1156. XClientInBox(cli, close)
  1157. XClient *cli;
  1158. XClientInBoxClosure *close;
  1159. X{
  1160. X    int x, y, w, h;
  1161. X
  1162. X    if (cli->screen != close->screen)
  1163. X        return NULL;
  1164. X
  1165. X    if (cli->framewin == NULL)
  1166. X        return NULL;
  1167. X
  1168. X    if (cli->wmState == IconicState)
  1169. X    {
  1170. X        x = cli->iconwin->core.x;
  1171. X        y = cli->iconwin->core.y;
  1172. X        w = cli->iconwin->core.width;
  1173. X        h = cli->iconwin->core.height;
  1174. X    }
  1175. X    else
  1176. X    {
  1177. X        x = cli->framewin->core.x;
  1178. X        y = cli->framewin->core.y;
  1179. X        w = cli->framewin->core.width;
  1180. X        h = cli->framewin->core.height;
  1181. X    }
  1182. X
  1183. X    if ((x >= close->bx) &&
  1184. X        (y >= close->by) &&
  1185. X        ((x + w) <= (close->bx + close->bw)) &&
  1186. X        ((y + h) <= (close->by + close->bh)))
  1187. X        (close->func)(cli, close->timestamp);
  1188. X
  1189. X    return NULL;
  1190. X}
  1191. X
  1192. X/*
  1193. X * ClientSetBusy -- the busy state has (possibly) been changed for a client.
  1194. X *    if the client is going from normal to busy:
  1195. X *          mark the client as busy
  1196. X *          put up a busy window
  1197. X *      if the client is going from busy to normal:
  1198. X *          mark the client as unbusy
  1199. X *          take down a busy window (if it exists)
  1200. X */
  1201. Xvoid
  1202. XClientUpdateBusy(cli,event)
  1203. X    Client         *cli;
  1204. X    XPropertyEvent    *event;
  1205. X{
  1206. X        int *newBusyPtr;
  1207. X    int newBusy;
  1208. X        unsigned long nItems, remain;
  1209. X
  1210. X    if (event->state == PropertyNewValue) {
  1211. X        newBusyPtr = GetWindowProperty(cli->dpy, PANEWINOFCLIENT(cli),
  1212. X        AtomWindowBusy, 0L, LONG_LENGTH(*newBusyPtr), 
  1213. X        XA_INTEGER, 32, &nItems, &remain);
  1214. X
  1215. X        if (newBusyPtr == NULL) {
  1216. X        /* property not found or has the wrong type */
  1217. X        newBusy = 0;
  1218. X        } else {
  1219. X        if (nItems != LONG_LENGTH(newBusy) || remain != 0) {
  1220. X            /* got a property, but it is invalid */
  1221. X            newBusy = 0;
  1222. X        } else {
  1223. X            /* valid property */
  1224. X            newBusy = *newBusyPtr;
  1225. X        }
  1226. X        XFree((char *)newBusyPtr);
  1227. X        }
  1228. X    } else {
  1229. X        /* property was deleted */
  1230. X        newBusy = 0;
  1231. X    }
  1232. X
  1233. X    /* 
  1234. X     * Losing busy
  1235. X     */
  1236. X        if (cli->isBusy && (newBusy == 0)) {
  1237. X            cli->isBusy = False;
  1238. X        if (cli->isFocus)
  1239. X        ClientSetFocus(cli,True,event->time);
  1240. X        FrameSetBusy(cli->framewin, False);
  1241. X        }
  1242. X    /*
  1243. X     * Else Gaining busy
  1244. X     */
  1245. X        else if (!cli->isBusy && (newBusy == 1)) {
  1246. X            cli->isBusy = True;
  1247. X        FrameSetBusy(cli->framewin, True);
  1248. X        if (cli->isFocus)
  1249. X                ClientSetFocus(cli,True,event->time);
  1250. X        }
  1251. X}
  1252. X
  1253. X
  1254. X/*
  1255. X *    REMIND    this function should be removed when menu/menuinfos
  1256. X *    are reorged.
  1257. X */
  1258. Xvoid
  1259. XDestroyPinnedMenuClients()
  1260. X{
  1261. X    List    *l = ActiveClientList;
  1262. X    Client    *cli;
  1263. X
  1264. X
  1265. X    for (cli = ListEnum(&l); cli != NULL; cli = ListEnum(&l)) {
  1266. X        if (cli->framewin && cli->framewin->fcore.panewin &&
  1267. X            cli->framewin->fcore.panewin->core.kind == WIN_PINMENU) {
  1268. X#ifdef DEBUG
  1269. X            printf("DestroyPinnedMenuClients: destroyed %x\n",cli);
  1270. X#endif
  1271. X            DestroyClient(cli);
  1272. X        }
  1273. X    }
  1274. X}
  1275. X
  1276. X
  1277. X/* ===== focus stuff ====================================================== */
  1278. X
  1279. X
  1280. X/*
  1281. X * Focus Change Inhibition.
  1282. X *
  1283. X * If focus changing is inhibited, information about focus changing is stored
  1284. X * in the FocusInhibitRecord instead of being used to set the focus.  If
  1285. X * several focus changes occur while focus changing is inhibited, only
  1286. X * information for the latest change is stored.  When focus changing becomes
  1287. X * uninhibited, the information is used to set the focus for real.  This 
  1288. X * prevents unnecessary focus changing.  REMIND: focus inhibition doesn't 
  1289. X * occur when the focus is set to the NoFocus window.  This isn't too bad, as 
  1290. X * no highlighting occurs when this happens.
  1291. X */
  1292. X
  1293. Xstatic struct FocusInhibitRecord {
  1294. X    Bool inhibited;
  1295. X    Client *cli;
  1296. X    Bool sendTF;
  1297. X    Time evtime;
  1298. X} fir;
  1299. X
  1300. X
  1301. X/*
  1302. X * ClientInhibitFocus -- inhibit or uninhibit focus changing.
  1303. X */
  1304. Xvoid
  1305. XClientInhibitFocus(inhibit)
  1306. X    Bool inhibit;
  1307. X{
  1308. X    if (inhibit) {
  1309. X    fir.inhibited = True;
  1310. X    fir.cli = NULL;
  1311. X    } else {
  1312. X    fir.inhibited = False;
  1313. X    if (fir.cli != NULL)
  1314. X        ClientSetFocus(fir.cli, fir.sendTF, fir.evtime);
  1315. X    fir.cli = NULL;
  1316. X    }
  1317. X}
  1318. X
  1319. X
  1320. X/*
  1321. X * ClientSetFocus -- possibly set the focus to this client.  If focus changing
  1322. X * is inhibited, store information in the inhibit record.  Otherwise, set the
  1323. X * focus normally.  If the client is GloballyActive, we only send TakeFocus
  1324. X * messages if sendTF is true.  If the client has a different focus mode
  1325. X * sendTF is ignored.  If the client is a NoInput client, set the focus to the
  1326. X * frame itself.  REMIND: this works, if a little bizarre.  The frame doesn't
  1327. X * select for keystrokes, so they fall to the root.  The root event handler
  1328. X * ends up beeping, which is OK.
  1329. X */
  1330. Xvoid
  1331. XClientSetFocus(cli,sendTF,evtime)
  1332. XClient *cli;
  1333. XBool sendTF;
  1334. XTime evtime;
  1335. X{
  1336. X    if (fir.inhibited) {
  1337. X        fir.cli = cli;
  1338. X        fir.sendTF = sendTF;
  1339. X        fir.evtime = evtime;
  1340. X        return;
  1341. X    }
  1342. X
  1343. X    if (cli->wmState == IconicState) {
  1344. X        if (cli->iconwin != NULL)
  1345. X        XSetInputFocus(cli->dpy, cli->iconwin->core.self,
  1346. X                   RevertToParent, evtime);
  1347. X    } else {
  1348. X        switch (cli->focusMode)
  1349. X        {
  1350. X        case NoInput:
  1351. X        XSetInputFocus(cli->dpy, cli->framewin->core.self,
  1352. X                   RevertToParent, evtime);
  1353. X            break;
  1354. X
  1355. X        case Passive:
  1356. X        case LocallyActive:
  1357. X            XSetInputFocus(cli->dpy, PANEWINOFCLIENT(cli),
  1358. X            RevertToParent, evtime);
  1359. X            break;
  1360. X
  1361. X        case GloballyActive:
  1362. X            if (sendTF)
  1363. X            {
  1364. X            ClientSendProtocol(cli, AtomTakeFocus, evtime);
  1365. X            }
  1366. X            break;
  1367. X        }
  1368. X    }
  1369. X}
  1370. X
  1371. X
  1372. X/*
  1373. X * Current Client.
  1374. X *
  1375. X * The current client is used by the mouseless functions.  These functions
  1376. X * maintain the current and previously-current client.  If cli is already the
  1377. X * current client, don't do anything.  This is necessary because this may be
  1378. X * called when a client is activated explicitly (from ClientActivate) or
  1379. X * implicitly (when a globally active client takes the focus).  Therefore, if
  1380. X * ClientActivate activates a globally active client, this function will be
  1381. X * called twice.
  1382. X * 
  1383. X * Eventually, this may change to be a "ring-buffer" history of clients.
  1384. X *
  1385. X * REMIND: the notion of the current client may be a vestige from the time
  1386. X * when some objects (like icons and pinned menus) didn't take the focus.
  1387. X * Activating one of these items would set the focus to the NoFocus window,
  1388. X * but set the current client to that particular client.  Thus, having the
  1389. X * focus was not the same as being the current client.  This distinction may
  1390. X * no longer be true, in which case it is sufficient to keep track of the
  1391. X * client that has the focus, without the separate notion of a current client.
  1392. X * One possible problem may occur with buggy Globally Active clients that
  1393. X * don't take the focus when requested.  If we rely on the focus to keep track
  1394. X * of the current client, we may get "stuck" if the next client fails to take
  1395. X * the focus when requested.
  1396. X */
  1397. Xvoid
  1398. XClientSetCurrent(cli)
  1399. X    Client *cli;
  1400. X{
  1401. X    if (cli != CurrentClient) {
  1402. X    lastCurrentClient = CurrentClient;
  1403. X    CurrentClient = cli;
  1404. X    }
  1405. X}
  1406. X
  1407. X
  1408. XClient *
  1409. XClientGetLastCurrent()
  1410. X{
  1411. X    return lastCurrentClient;
  1412. X}
  1413. X
  1414. X
  1415. X/*
  1416. X * Client Activation.
  1417. X * 
  1418. X * Activate the named client.  The difference between this and ClientSetFocus
  1419. X * is that this function selects and raises the client's window in addition to
  1420. X * setting the focus.  Further, this function works on iconic clients as well
  1421. X * as open ones.  This function sets the current client explicitly.  We would
  1422. X * rely on the resulting focus change to set the current client, except that
  1423. X * a globally active client may decline the focus when it is asked to take it.
  1424. X *
  1425. X * REMIND this shouldn't have to deal with selections at all.  However, 
  1426. X * icons and headerless windows currently have no way to indicate that they 
  1427. X * have the focus.  Therefore, select them.
  1428. X */
  1429. Xvoid
  1430. XClientActivate(dpy, cli, time)
  1431. X    Display *dpy;
  1432. X    Client *cli;
  1433. X    Time time;
  1434. X{
  1435. X    /*
  1436. X     * If the current client is selected, assume it was selected because it 
  1437. X     * was made the active client, and deselect it.  (See REMIND above.)
  1438. X     */
  1439. X    if (CurrentClient != NULL && CurrentClient->isSelected)
  1440. X    ClearSelections(dpy);
  1441. X
  1442. X    /*
  1443. X     * If we are being asked to activate a NULL client, or a client without a 
  1444. X     * frame (i.e. a root client), activate the NoFocus client.
  1445. X     */
  1446. X    if (cli == NULL) {
  1447. X    NoFocusTakeFocus(dpy, time, NULL);
  1448. X    } else if (cli->framewin == NULL) {
  1449. X    NoFocusTakeFocus(dpy, time, cli->scrInfo);
  1450. X    } else {
  1451. X    ClientSetFocus(cli, True, time);
  1452. X
  1453. X    /*
  1454. X     * If the client is iconic or has no header, select it to show that it 
  1455. X     * is the active client.  (See REMIND above.)
  1456. X     */
  1457. X    if (cli->wmState == IconicState ||
  1458. X        !(cli->wmDecors->flags & WMDecorationHeader)) {
  1459. X        ClearSelections(dpy);
  1460. X        AddSelection(cli, time);
  1461. X    }
  1462. X
  1463. X    if (GRV.RaiseOnActivate)
  1464. X        ClientFront(cli);
  1465. X
  1466. X    ClientSetCurrent(cli);
  1467. X    }
  1468. X}
  1469. X
  1470. X
  1471. X/*
  1472. X * Set the focus to the topmost window on the given screen.
  1473. X */
  1474. Xvoid
  1475. XClientFocusTopmost(dpy, scrinfo, time)
  1476. X    Display *dpy;
  1477. X    ScreenInfo *scrinfo;
  1478. X    Time time;
  1479. X{
  1480. X    Window wjunk;
  1481. X    Window *children;
  1482. X    unsigned int nchildren;
  1483. X    int i;
  1484. X    Client *topframeclient = NULL;
  1485. X    Client *topiconclient = NULL;
  1486. X    WinGeneric *win;
  1487. X
  1488. X    if (0 == XQueryTree(dpy, scrinfo->rootid, &wjunk, &wjunk,
  1489. X            &children, &nchildren))
  1490. X    {
  1491. X    return;
  1492. X    }
  1493. X
  1494. X    /*
  1495. X     * QueryTree returns children on bottom-to-top order, so search backward, 
  1496. X     * looking for the topmost frame and icon.
  1497. X     */
  1498. X    for (i = nchildren-1; i >= 0; --i) {
  1499. X    win = WIGetInfo(children[i]);
  1500. X    if (win != NULL) {
  1501. X        if (win->core.kind == WIN_FRAME &&
  1502. X        win->core.client->wmState == NormalState &&
  1503. X        topframeclient == NULL)
  1504. X        {
  1505. X        topframeclient = win->core.client;
  1506. X        }
  1507. X
  1508. X        if (win->core.kind == WIN_ICON &&
  1509. X        win->core.client->wmState == IconicState &&
  1510. X        topiconclient == NULL)
  1511. X        {
  1512. X        topiconclient = win->core.client;
  1513. X        }
  1514. X
  1515. X        if (topframeclient != NULL && topiconclient != NULL)
  1516. X        break;
  1517. X    }
  1518. X    }
  1519. X
  1520. X    if (topframeclient != NULL)
  1521. X    ClientSetFocus(topframeclient, True, time);
  1522. X    else if (topiconclient != NULL)
  1523. X    ClientSetFocus(topiconclient, True, time);
  1524. X    else
  1525. X    NoFocusTakeFocus(dpy, time, scrinfo);
  1526. X
  1527. X    XFree((char *) children);
  1528. X}
  1529. X
  1530. X/* ===== Client Property Changes ================================== */
  1531. X
  1532. Xtypedef struct {
  1533. X    Atom    *propAtom;
  1534. X    void    (*updateFunc)();
  1535. X} ClientPropUpdate; 
  1536. X
  1537. Xstatic ClientPropUpdate propUpdateTable[] =  {
  1538. X    &AtomWMName,            FrameUpdateHeader,
  1539. X    &AtomLeftFooter,        FrameUpdateFooter,
  1540. X    &AtomRightFooter,        FrameUpdateFooter,
  1541. X    &AtomWMIconName,        IconUpdateName,
  1542. X    &AtomColorMapWindows,        ColorUpdateColorMapWindows,
  1543. X    &AtomProtocols,            StateUpdateWMProtocols,
  1544. X    &AtomWMNormalHints,        StateUpdateWMNormalHints,
  1545. X    &AtomWMHints,            StateUpdateWMHints,
  1546. X    &AtomWindowBusy,        ClientUpdateBusy,
  1547. X    &AtomSunWindowState,        ClientUpdateWindowState,
  1548. X    &AtomSunDragDropInterest,    ClientUpdateDragDropInterest,
  1549. X    &AtomWinAttr,            StateUpdateWinAttr,
  1550. X    &AtomDecorAdd,            StateUpdateDecorAdd,
  1551. X    &AtomDecorDel,            StateUpdateDecorDel,
  1552. X};
  1553. X#define NPROPUPDATETABLE (sizeof(propUpdateTable)/sizeof(ClientPropUpdate))
  1554. X
  1555. X/* ClientDistributeProperty -- a property of the client has changed.
  1556. X *    Forward the change notification to the appropriate handler.
  1557. X */
  1558. Xvoid
  1559. XClientDistributeProperty(cli, event)
  1560. X    Client        *cli;
  1561. X    XPropertyEvent    *event;
  1562. X{
  1563. X    int        i;
  1564. X
  1565. X    for (i=0; i<NPROPUPDATETABLE; i++) {
  1566. X        if (event->atom == *propUpdateTable[i].propAtom) {
  1567. X            (propUpdateTable[i].updateFunc)(cli,event);
  1568. X            break;
  1569. X        }
  1570. X    }
  1571. X}
  1572. END_OF_FILE
  1573. if test 37162 -ne `wc -c <'client.c'`; then
  1574.     echo shar: \"'client.c'\" unpacked with wrong size!
  1575. fi
  1576. # end of 'client.c'
  1577. fi
  1578. if test -f 'events.h' -a "${1}" != "-c" ; then 
  1579.   echo shar: Will not clobber existing file \"'events.h'\"
  1580. else
  1581. echo shar: Extracting \"'events.h'\" \(3632 characters\)
  1582. sed "s/^X//" >'events.h' <<'END_OF_FILE'
  1583. X/*
  1584. X *      (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents
  1585. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  1586. X *      file for terms of the license.
  1587. X */
  1588. X
  1589. X#ifndef _OLWM_EVENT_H
  1590. X#define _OLWM_EVENT_H
  1591. X
  1592. X#ident  "@(#)events.h    1.1 olvwm version 1/3/92"
  1593. X
  1594. X/*
  1595. X * Based on
  1596. X#ident    "@(#)events.h    26.11    91/09/14 SMI"
  1597. X *
  1598. X */
  1599. X
  1600. X/* global functions */
  1601. Xextern void EventLoop();
  1602. Xextern int PropagateEventToParent();
  1603. Xextern void PropagatePressEventToChild();
  1604. Xextern Time LastEventTime;
  1605. Xextern Bool AwaitEvents();
  1606. Xextern void GrabKeys();
  1607. Xextern void RefreshKeyGrabs();
  1608. Xextern void GrabButtons();
  1609. Xextern void RefreshButtonGrabs();
  1610. Xextern void UpdateBindings();
  1611. Xextern void InitEvents();
  1612. Xextern void InitBindings();
  1613. X
  1614. X/* interposition */
  1615. Xextern void InstallInterposer();
  1616. Xextern void UninstallInterposer();
  1617. X
  1618. Xenum {
  1619. X    DISPOSE_DISPATCH,
  1620. X    DISPOSE_USED,
  1621. X    DISPOSE_DEFER,
  1622. X};
  1623. X
  1624. X/* keyboard mapping */
  1625. Xextern KeySym *KbdMap;
  1626. Xextern int MinKeyCode;
  1627. Xextern int MaxKeyCode;
  1628. Xextern int KeySymsPerKeyCode;
  1629. X
  1630. X/* modifiers and modifier masks */
  1631. X
  1632. Xenum {
  1633. X    MOD_CONSTRAIN,
  1634. X    MOD_WMGRAB,
  1635. X    MOD_REDUCE,
  1636. X    MOD_INVERT,
  1637. X    MOD_SETDEFAULT,
  1638. X    MOD_IGNORE,
  1639. X    MOD_MASK_COUNT        /* must be last */
  1640. X};
  1641. X
  1642. Xextern unsigned int ModMaskMap[MOD_MASK_COUNT];
  1643. Xextern unsigned int FindModifierMask();
  1644. X
  1645. X/* mouse binding match states */
  1646. Xtypedef enum {
  1647. X    MATCH_NONE,        /* no binding matches at all */
  1648. X    MATCH_INCOMPLETE,    /* partial match */
  1649. X    MATCH_AMBIG,    /* more than one exact match */
  1650. X    MATCH_PREFIX,    /* exact match, but also a prefix for another */
  1651. X    MATCH_EXACT,    /* exact match, not a prefix */
  1652. X} MouseMatchState;
  1653. X
  1654. X/* semantic actions */
  1655. Xtypedef enum {
  1656. X    ACTION_NONE,
  1657. X    ACTION_SELECT,
  1658. X    ACTION_ADJUST,
  1659. X    ACTION_MENU,
  1660. X    ACTION_HELP,
  1661. X    ACTION_STOP,
  1662. X    ACTION_PROPS,
  1663. X    ACTION_FRONT,
  1664. X    ACTION_OPEN,
  1665. X    ACTION_EXEC_DEFAULT,
  1666. X    ACTION_FOCUS_HELP,
  1667. X    ACTION_SET_DEFAULT,
  1668. X    ACTION_UP,
  1669. X    ACTION_DOWN,
  1670. X    ACTION_LEFT,
  1671. X    ACTION_RIGHT,
  1672. X    ACTION_JUMP_UP,
  1673. X    ACTION_JUMP_DOWN,
  1674. X    ACTION_JUMP_LEFT,
  1675. X    ACTION_JUMP_RIGHT,
  1676. X    ACTION_ROW_START,
  1677. X    ACTION_ROW_END,
  1678. X    ACTION_DATA_START,
  1679. X    ACTION_DATA_END,
  1680. X    ACTION_FIRST_CONTROL,
  1681. X    ACTION_LAST_CONTROL,
  1682. X    ACTION_TOGGLE_PIN,
  1683. X    ACTION_CANCEL,        /* REMIND does this differ from STOP? */
  1684. X    ACTION_NEXT_ELEMENT,
  1685. X    ACTION_PREVIOUS_ELEMENT,
  1686. X    ACTION_UPLEFT,
  1687. X    ACTION_UPRIGHT,
  1688. X    ACTION_DOWNLEFT,
  1689. X    ACTION_DOWNRIGHT,
  1690. X    ACTION_HOME,
  1691. X    ACTION_JUMP_UPLEFT,
  1692. X    ACTION_JUMP_UPRIGHT,
  1693. X    ACTION_JUMP_DOWNLEFT,
  1694. X    ACTION_JUMP_DOWNRIGHT,
  1695. X    ACTION_HALF_UP,
  1696. X    ACTION_HALF_DOWN,
  1697. X    ACTION_HALF_LEFT,
  1698. X    ACTION_HALF_RIGHT,
  1699. X    ACTION_HALF_UPLEFT,
  1700. X    ACTION_HALF_UPRIGHT,
  1701. X    ACTION_HALF_DOWNLEFT,
  1702. X    ACTION_HALF_DOWNRIGHT,
  1703. X    ACTION_GOTO_1,
  1704. X    ACTION_GOTO_2,
  1705. X    ACTION_GOTO_3,
  1706. X    ACTION_GOTO_4,
  1707. X    ACTION_GOTO_5,
  1708. X    ACTION_GOTO_6,
  1709. X    ACTION_GOTO_7,
  1710. X    ACTION_GOTO_8,
  1711. X    ACTION_GOTO_9,
  1712. X    ACTION_GOTO_10,
  1713. X    ACTION_VIRTUAL
  1714. X} SemanticAction;
  1715. X
  1716. X/* convert a button number to a button mask */
  1717. X#define ButtonToMask(b) (1<<(b+7))
  1718. X
  1719. X#define AnyButtonMask \
  1720. X    (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
  1721. X
  1722. X/* given a ButtonRelease event, determines whether all buttons are now up. */
  1723. X#define AllButtonsUp(e) \
  1724. X  (!((e)->xbutton.state & ~ButtonToMask((e)->xbutton.button) & AnyButtonMask))
  1725. X
  1726. X/* given a ButtonPress event, determine whether it's the first button down. */
  1727. X#define FirstButtonDown(e) \
  1728. X  (((e)->xbutton.state & AnyButtonMask) == 0)
  1729. X
  1730. X/* timeouts */
  1731. Xtypedef void (*TimeoutFunc)();
  1732. Xextern void TimeoutRequest();    /* int time, TimeoutFunc f, void *closure */
  1733. Xextern void TimeoutCancel();    /* no params */
  1734. X
  1735. X#endif /* _OLWM_EVENT_H */
  1736. END_OF_FILE
  1737. if test 3632 -ne `wc -c <'events.h'`; then
  1738.     echo shar: \"'events.h'\" unpacked with wrong size!
  1739. fi
  1740. # end of 'events.h'
  1741. fi
  1742. if test -f 'winpush.c' -a "${1}" != "-c" ; then 
  1743.   echo shar: Will not clobber existing file \"'winpush.c'\"
  1744. else
  1745. echo shar: Extracting \"'winpush.c'\" \(10989 characters\)
  1746. sed "s/^X//" >'winpush.c' <<'END_OF_FILE'
  1747. X/*
  1748. X *      (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents
  1749. X *      pending in the U.S. and foreign countries. See LEGAL_NOTICE
  1750. X *      file for terms of the license.
  1751. X */
  1752. X
  1753. X#ident    "@(#)winpush.c    1.1 olvwm version 1/3/92"
  1754. X
  1755. X/*
  1756. X * Based on
  1757. X#ident    "@(#)winpush.c    26.19    91/09/14 SMI"
  1758. X *
  1759. X */
  1760. X
  1761. X#include <errno.h>
  1762. X#include <stdio.h>
  1763. X#include <X11/Xos.h>
  1764. X#include <X11/Xlib.h>
  1765. X#include <X11/Xutil.h>
  1766. X#include <X11/Xatom.h>
  1767. X#include <olgx/olgx.h>
  1768. X
  1769. X#include "i18n.h"
  1770. X#include "ollocale.h"
  1771. X#include "mem.h"
  1772. X#include "olwm.h"
  1773. X#include "win.h"
  1774. X#include "globals.h"
  1775. X
  1776. X/***************************************************************************
  1777. X* global data
  1778. X***************************************************************************/
  1779. X
  1780. Xextern Atom AtomDeleteWindow;
  1781. Xextern Atom AtomPushpinState;
  1782. Xextern void FrameAllowEvents();
  1783. X
  1784. X/***************************************************************************
  1785. X* private data
  1786. X***************************************************************************/
  1787. X
  1788. Xstatic ClassPushPin classPushPin;
  1789. Xstatic Bool     pushpinStateAfterPress;  /* State of the pushpin
  1790. X                      * after the user pressed
  1791. X                         * the mouse button. */
  1792. Xstatic SemanticAction currentAction = ACTION_NONE;
  1793. Xvoid PushPinChangePinState();
  1794. X
  1795. X/***************************************************************************
  1796. X* private functions
  1797. X***************************************************************************/
  1798. X
  1799. X/* locallyChangePushPinState -- temporarily change the pushpin state,
  1800. X *     while tracking a button press over the pin.  The permanent change
  1801. X *    will be made later.
  1802. X */
  1803. Xstatic void
  1804. XlocallyChangePushPinState(dpy,winInfo,newState)
  1805. XDisplay *dpy;
  1806. XWinPushPin *winInfo;
  1807. XBool newState;
  1808. X{
  1809. X        if (winInfo->pushpinin != newState)
  1810. X        {
  1811. X                winInfo->pushpinin = newState;
  1812. X                (WinFunc(winInfo,core.drawfunc))(dpy, winInfo);
  1813. X        }
  1814. X}
  1815. X
  1816. X
  1817. X/* 
  1818. X * eventButtonPress - handle button press events on the pushpin window 
  1819. X */
  1820. Xstatic int
  1821. XeventButtonPress(dpy, event, winInfo)
  1822. XDisplay    *dpy;
  1823. XXEvent    *event;
  1824. XWinPushPin    *winInfo;
  1825. X{
  1826. X    SemanticAction a = ResolveMouseBinding(dpy, event, 0L);
  1827. X    FrameAllowEvents(winInfo->core.client, event->xbutton.time);
  1828. X    switch (a) {
  1829. X    case ACTION_SELECT:
  1830. X    case ACTION_ADJUST:
  1831. X            locallyChangePushPinState(dpy, winInfo, !(winInfo->pushpinin));
  1832. X            pushpinStateAfterPress = winInfo->pushpinin;
  1833. X        currentAction = a;
  1834. X        break;
  1835. X    }
  1836. X}
  1837. X
  1838. X/* 
  1839. X * eventButtonRelease - handle button release events on the pushpin window 
  1840. X */
  1841. Xstatic int
  1842. XeventButtonRelease(dpy, event, winInfo)
  1843. XDisplay    *dpy;
  1844. XXEvent    *event;
  1845. XWinPushPin    *winInfo;
  1846. X{
  1847. X    FrameAllowEvents(winInfo->core.client, event->xbutton.time);
  1848. X    if (!AllButtonsUp(event))
  1849. X        return;
  1850. X
  1851. X    /*
  1852. X     * If pushpinStateAfterPress equals the current pin state, we know 
  1853. X     * that the user really wants to change the pin state.  If they are 
  1854. X     * not equal, the user has released the button outside the pin, so 
  1855. X     * there should be no change of state.
  1856. X     */
  1857. X    if (pushpinStateAfterPress == winInfo->pushpinin) {
  1858. X        PushPinChangePinState(dpy, winInfo,
  1859. X                   currentAction == ACTION_SELECT);
  1860. X    }
  1861. X    currentAction = ACTION_NONE;
  1862. X}
  1863. X
  1864. X/* 
  1865. X * eventMotionNotify - handle pointer moves
  1866. X */
  1867. Xstatic int
  1868. XeventMotionNotify(dpy, event, winInfo)
  1869. XDisplay    *dpy;
  1870. XXEvent    *event;
  1871. XWinPushPin    *winInfo;
  1872. X{
  1873. X    Bool     fInWindow;
  1874. X    Graphics_info    *gisNormal = WinGI(winInfo,NORMAL_GINFO);
  1875. X
  1876. X    if (!event->xmotion.same_screen)
  1877. X        return;
  1878. X    if (currentAction != ACTION_SELECT && currentAction != ACTION_ADJUST)
  1879. X        return;
  1880. X
  1881. X        /* When the user moves the cursor off the pushpin
  1882. X         * while s/he has the button down we should pull
  1883. X         * the button out.  If the user moves back onto the
  1884. X         * pushpin put the pin back in.  So,
  1885. X         *
  1886. X         * if (cursor is off the pushpin) and (pin is in)
  1887. X         *                  OR
  1888. X         *    (cursor is on the pushpin) and (pin is out)
  1889. X         * then
  1890. X         *      change the state of the pushpin.
  1891. X         */
  1892. X        fInWindow = !((event->xmotion.x < 0) ||
  1893. X             (event->xmotion.y < 0) ||
  1894. X             (event->xmotion.x >= PushPinOut_Width(gisNormal)) ||
  1895. X             (event->xmotion.y >= PushPinOut_Height(gisNormal)));
  1896. X        locallyChangePushPinState(dpy, winInfo,
  1897. X                fInWindow?pushpinStateAfterPress:!pushpinStateAfterPress);
  1898. X}
  1899. X
  1900. X
  1901. X/*
  1902. X * drawPushPin -- draw the pushpin window
  1903. X */
  1904. X/*ARGSUSED*/
  1905. Xstatic int
  1906. XdrawPushPin(dpy, winInfo)
  1907. XDisplay    *dpy;
  1908. XWinPushPin *winInfo;
  1909. X{
  1910. X    Client *cli = winInfo->core.client;
  1911. X    Graphics_info *gis;
  1912. X    int focusLines = (GRV.FocusFollowsMouse ? 1 : 0) ^
  1913. X             (GRV.InvertFocusHighlighting ? 1 : 0);
  1914. X
  1915. X    if (cli->isFocus)
  1916. X        gis = WinGI(winInfo, INPUTFOCUS_GINFO);
  1917. X    else gis = WinGI(winInfo,NORMAL_GINFO);
  1918. X        /* If the titlebar is in reverse video we need to
  1919. X         * draw the pushpin in reverse video also.
  1920. X         */
  1921. X    if (Win3D(winInfo)) {
  1922. X        /*
  1923. X         * REMIND
  1924. X         * We need to erase the background here to BG2.  We can't use
  1925. X         * OLGX_ERASE because olgx erases only in BG1.  So, we draw an 
  1926. X         * filled, invoked box that is just larger than the pin 
  1927. X         * window, so that the border doesn't show.
  1928. X         */
  1929. X        
  1930. X        olgx_draw_box(gis, winInfo->core.self, -1, -1,
  1931. X                  winInfo->core.width+2,
  1932. X                  winInfo->core.height+2,
  1933. X                              ((cli->isFocus) && !focusLines) ?
  1934. X                      OLGX_INVOKED : OLGX_NORMAL, 
  1935. X                  True);
  1936. X        } else {
  1937. X        GC gc;
  1938. X
  1939. X        if (cli->isFocus && !focusLines) {
  1940. X            gc = WinGC(winInfo, FOREGROUND_GC);
  1941. X            gis = WinGI(winInfo, REVPIN_GINFO);
  1942. X        } else {
  1943. X            gc = WinGC(winInfo, WINDOW_GC);
  1944. X        }
  1945. X        XFillRectangle(dpy, winInfo->core.self, gc, 0, 0,
  1946. X            winInfo->core.width, winInfo->core.height);
  1947. X        }
  1948. X    if (winInfo->core.client->isBusy)
  1949. X    {
  1950. X        XFillRectangle(dpy, winInfo->core.self, WinGC(winInfo,BUSY_GC),
  1951. X        0, 0, winInfo->core.width, winInfo->core.height);
  1952. X    }
  1953. X    olgx_draw_pushpin(gis, winInfo->core.self, 0, 0,
  1954. X                    ((winInfo->pushpinin) ? OLGX_PUSHPIN_IN : OLGX_PUSHPIN_OUT));
  1955. X}
  1956. X
  1957. X
  1958. X/*
  1959. X * DestroyPushPin -- destroy the pushpin window resources and free any allocated
  1960. X *    data.
  1961. X */
  1962. Xstatic int
  1963. XdestroyPushPin(dpy, winInfo)
  1964. XDisplay    *dpy;
  1965. XWinPushPin *winInfo;
  1966. X{
  1967. X    /* free our data and throw away window */
  1968. X    DestroyWindow(winInfo);
  1969. X    MemFree(winInfo);
  1970. X}
  1971. X
  1972. X/* 
  1973. X * focusselectPushPin - the focus or selection state has changed
  1974. X */
  1975. Xstatic int
  1976. XfocusselectPushPin(dpy, winInfo, selected)
  1977. XDisplay *dpy;
  1978. XWinPushPin *winInfo;
  1979. XBool selected;
  1980. X{
  1981. X        (WinFunc(winInfo,core.drawfunc))(dpy, winInfo);
  1982. X}
  1983. X
  1984. X/*
  1985. X * heightfuncPushPin - recomputes the correct height of the window
  1986. X */
  1987. Xstatic int 
  1988. XheightfuncPushPin(win, pxcre)
  1989. XWinPushPin *win;
  1990. XXConfigureRequestEvent *pxcre;
  1991. X{
  1992. X    return PushPinOut_Width(WinGI(win,NORMAL_GINFO));
  1993. X}
  1994. X
  1995. X/*
  1996. X * widthfuncPushPin - recomputes the correct width of the window
  1997. X */
  1998. Xstatic int 
  1999. XwidthfuncPushPin(win, pxcre)
  2000. XWinPushPin *win;
  2001. XXConfigureRequestEvent *pxcre;
  2002. X{
  2003. X    return PushPinOut_Height(WinGI(win,NORMAL_GINFO));
  2004. X}
  2005. X
  2006. X/***************************************************************************
  2007. X* global functions
  2008. X***************************************************************************/
  2009. X
  2010. X/*
  2011. X * MakePushPin  -- create the pushpin window. Return a WinGeneric structure.
  2012. X */
  2013. XWinPushPin *
  2014. XMakePushPin(dpy, par, pane, x, y)
  2015. XDisplay    *dpy;
  2016. XWinGeneric *par;
  2017. XWindow pane;
  2018. Xint x,y;
  2019. X{
  2020. X    WinPushPin *w;
  2021. X    Window win;
  2022. X        unsigned long valuemask;
  2023. X        XSetWindowAttributes attributes;
  2024. X    Graphics_info    *gisNormal = WinGI(par,NORMAL_GINFO);
  2025. X
  2026. X        attributes.event_mask = ButtonMotionMask | ButtonReleaseMask | 
  2027. X        ButtonPressMask | ExposureMask;
  2028. X        attributes.win_gravity = NorthWestGravity;
  2029. X        valuemask = CWEventMask | CWWinGravity;
  2030. X
  2031. X        win = XCreateWindow(dpy, par->core.self,
  2032. X                        x, y,
  2033. X            PushPinOut_Width(gisNormal),
  2034. X            PushPinOut_Height(gisNormal),
  2035. X                        0,
  2036. X                        CopyFromParent,
  2037. X                        CopyFromParent,
  2038. X                        CopyFromParent,
  2039. X                        valuemask,
  2040. X                        &attributes);
  2041. X
  2042. X    /* create the associated structure */
  2043. X    w = MemNew(WinPushPin);
  2044. X    w->core.self = win;
  2045. X    w->class = &classPushPin;
  2046. X    w->core.kind = WIN_PUSHPIN;
  2047. X    WinAddChild(par,w);
  2048. X    w->core.children = NULL;
  2049. X    w->core.client = par->core.client;
  2050. X    w->core.x = x;    
  2051. X    w->core.y = y;
  2052. X    w->core.width = PushPinOut_Width(gisNormal);
  2053. X    w->core.height = PushPinOut_Height(gisNormal);
  2054. X    w->core.dirtyconfig = CWX | CWY | CWWidth | CWHeight;
  2055. X    w->core.exposures = NULL;
  2056. X    w->core.helpstring = "olwm:PushPin";
  2057. X
  2058. X        /* Determine initial state of push pin. */
  2059. X        w->pushpinin =  
  2060. X        (par->core.client->wmDecors->pushpin_initial_state == PIN_IN);
  2061. X
  2062. X        /* Register the push-pin state. */
  2063. X        XChangeProperty(dpy, pane,
  2064. X                        AtomPushpinState,
  2065. X                        XA_INTEGER, 32,
  2066. X                        PropModeReplace,
  2067. X                        (unsigned char *)&(w->pushpinin), 1);
  2068. X
  2069. X    /* register the window */
  2070. X    WIInstallInfo(w);
  2071. X
  2072. X        MapRaised(w);
  2073. X
  2074. X    return w;
  2075. X}
  2076. X
  2077. Xvoid
  2078. XPushPinInit(dpy)
  2079. XDisplay *dpy;
  2080. X{
  2081. X    classPushPin.core.kind = WIN_PUSHPIN;
  2082. X    classPushPin.core.xevents[Expose] = WinEventExpose;
  2083. X    classPushPin.core.xevents[ButtonPress] = eventButtonPress;
  2084. X    classPushPin.core.xevents[ButtonRelease] = eventButtonRelease;
  2085. X    classPushPin.core.xevents[MotionNotify] = eventMotionNotify;
  2086. X    classPushPin.core.focusfunc = focusselectPushPin;
  2087. X    classPushPin.core.drawfunc = drawPushPin;
  2088. X    classPushPin.core.destroyfunc = destroyPushPin;
  2089. X    classPushPin.core.selectfunc = focusselectPushPin;
  2090. X    classPushPin.core.newconfigfunc = WinNewConfigFunc;
  2091. X    classPushPin.core.newposfunc = WinNewPosFunc;
  2092. X    classPushPin.core.setconfigfunc = WinSetConfigFunc;
  2093. X    classPushPin.core.createcallback = NULL;
  2094. X    classPushPin.core.heightfunc = heightfuncPushPin;
  2095. X    classPushPin.core.widthfunc = widthfuncPushPin;
  2096. X}
  2097. X
  2098. X
  2099. X/*
  2100. X * Permanently change the push pin state.
  2101. X */
  2102. Xvoid
  2103. XPushPinChangePinState(dpy, winInfo, sendDelete)
  2104. X    Display *dpy;
  2105. X    WinPushPin *winInfo;
  2106. X    Bool sendDelete;
  2107. X{
  2108. X    Client        *cli = winInfo->core.client;
  2109. X
  2110. X        (WinFunc(winInfo,core.drawfunc))(dpy, winInfo);
  2111. X
  2112. X        /* Tell the client that the state of its push-pin has changed. */
  2113. X        XChangeProperty(dpy, PANEWINOFCLIENT(cli),
  2114. X                        AtomPushpinState,
  2115. X                        XA_INTEGER, 32,
  2116. X                        PropModeReplace,
  2117. X                        (unsigned char *)&(winInfo->pushpinin), 1);
  2118. X
  2119. X        if (!winInfo->pushpinin && sendDelete)
  2120. X        ClientKill(winInfo->core.client,False);
  2121. X}  
  2122. X
  2123. X/*
  2124. X * Sets the pin state to a new state (if different that current state)
  2125. X */
  2126. Xvoid
  2127. XPushPinSetPinState(dpy,winInfo,newState,sendDelete)
  2128. X    Display        *dpy;
  2129. X    WinPushPin    *winInfo;
  2130. X    int        newState;
  2131. X    Bool        sendDelete;
  2132. X{
  2133. X    if (newState == winInfo->pushpinin)
  2134. X        return;
  2135. X
  2136. X    winInfo->pushpinin = newState;
  2137. X    PushPinChangePinState(dpy,winInfo,sendDelete);
  2138. X}
  2139. X
  2140. X/*
  2141. X * Toggles the pin state
  2142. X */
  2143. Xvoid
  2144. XPushPinTogglePinState(dpy,winInfo,sendDelete)
  2145. X    Display        *dpy;
  2146. X    WinPushPin    *winInfo;
  2147. X    Bool        sendDelete;
  2148. X{
  2149. X    winInfo->pushpinin = !winInfo->pushpinin;
  2150. X    PushPinChangePinState(dpy,winInfo,sendDelete);
  2151. X}
  2152. END_OF_FILE
  2153. if test 10989 -ne `wc -c <'winpush.c'`; then
  2154.     echo shar: \"'winpush.c'\" unpacked with wrong size!
  2155. fi
  2156. # end of 'winpush.c'
  2157. fi
  2158. echo shar: End of archive 7 \(of 21\).
  2159. cp /dev/null ark7isdone
  2160. MISSING=""
  2161. 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
  2162.     if test ! -f ark${I}isdone ; then
  2163.     MISSING="${MISSING} ${I}"
  2164.     fi
  2165. done
  2166. if test "${MISSING}" = "" ; then
  2167.     echo You have unpacked all 21 archives.
  2168.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2169. else
  2170.     echo You still need to unpack the following archives:
  2171.     echo "        " ${MISSING}
  2172. fi
  2173. ##  End of shell archive.
  2174. exit 0
  2175. --
  2176. Molecular Simulations, Inc.             mail: dcmartin@postgres.berkeley.edu
  2177. 796 N. Pastoria Avenue                  uucp: uwvax!ucbvax!dcmartin
  2178. Sunnyvale, California 94086             at&t: 408/522-9236
  2179.