home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
x
/
volume15
/
olvwm-3.0
/
part07
< prev
next >
Wrap
Text File
|
1992-02-03
|
57KB
|
2,179 lines
Newsgroups: comp.sources.x
Path: uunet!elroy.jpl.nasa.gov!ames!pasteur!nntp
From: scott.oaks@East.Sun.COM (Scott Oaks)
Subject: v15i153: OpenLook Virtual Window Mgr (3.0), Part07/21
Message-ID: <1992Feb4.135625.7258@pasteur.Berkeley.EDU>
Sender: dcmartin@msi.com (David C. Martin - Moderator)
Nntp-Posting-Host: postgres.berkeley.edu
Organization: University of California, at Berkeley
References: <csx-15i147-olvwm-3.0@uunet.UU.NET>
Date: Tue, 4 Feb 1992 13:56:25 GMT
Approved: dcmartin@msi.com
Submitted-by: scott.oaks@East.Sun.COM (Scott Oaks)
Posting-number: Volume 15, Issue 153
Archive-name: olvwm-3.0/part07
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 7 (of 21)."
# Contents: client.c events.h winpush.c
# Wrapped by dcmartin@fascet on Tue Jan 14 05:54:43 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'client.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'client.c'\"
else
echo shar: Extracting \"'client.c'\" \(37162 characters\)
sed "s/^X//" >'client.c' <<'END_OF_FILE'
X/*
X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents
X * pending in the U.S. and foreign countries. See LEGAL_NOTICE
X * file for terms of the license.
X */
X
X/* client.c - functions relating to clients as a whole
X */
X
X#ident "@(#)client.c 1.1 olvwm version 1/3/92"
X
X/*
X * Based on
X#ident "@(#)client.c 26.42 91/09/14 SMI"
X *
X */
X
X#include <errno.h>
X#include <stdio.h>
X#include <X11/Xos.h>
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/Xatom.h>
X#include <X11/keysym.h>
X#include <olgx/olgx.h>
X
X#include "i18n.h"
X#include "ollocale.h"
X#include "events.h"
X#include "mem.h"
X#include "olwm.h"
X#include "win.h"
X#include "group.h"
X#include "globals.h"
X#include "virtual.h"
X
X/***************************************************************************
X* global data
X***************************************************************************/
X
X/*
X * List of currently active clients. All frames and icons and the no-focus
X * window are reachable by traversing this list.
X */
XList *ActiveClientList;
X
X/*
X * Pointer to the "current" client. This is usually the client whose window
X * has the input focus, but not always. The exceptions include icons and
X * pinned menus, where the icon or menu window may be the "current" client but
X * where the focus really is with the no-focus window.
X */
X
XClient *CurrentClient = NULL;
X
X/*
X * DoingWindowState indicates whether olwm is doing window state.
X * This is set in InitClientState() and used in MakeRoot().
X */
XBool DoingWindowState = False;
X
Xextern Atom AtomColorMapWindows;
Xextern Atom AtomDecorDel;
Xextern Atom AtomDecorAdd;
Xextern Atom AtomDeleteWindow;
Xextern Atom AtomProtocols;
Xextern Atom AtomLeftFooter;
Xextern Atom AtomRightFooter;
Xextern Atom AtomShowProperties;
Xextern Atom AtomTakeFocus;
Xextern Atom AtomWindowBusy;
Xextern Atom AtomWinAttr;
Xextern Atom AtomWMState;
Xextern Atom AtomWMName;
Xextern Atom AtomWMIconName;
Xextern Atom AtomWMHints;
Xextern Atom AtomWMNormalHints;
Xextern Atom AtomSunLedMap;
Xextern Atom AtomSunWindowState;
Xextern Atom AtomSunDragDropInterest;
X
Xextern void RecursiveRefresh();
Xextern void PushPinChangeState();
Xextern void FrameUpdateHeader();
Xextern void FrameUpdateFooter();
Xextern void IconUpdateName();
Xextern void ColorUpdateColorMapWindows();
Xextern void StateUpdateWinAttr();
Xextern void StateUpdateDecorAdd();
Xextern void StateUpdateDecorDel();
Xextern void StateUpdateWMNormalHints();
Xextern void StateUpdateWMHints();
Xextern void StateUpdateWMProtocols();
X
X/***************************************************************************
X* private data
X***************************************************************************/
X
Xtypedef struct _ledstate {
X int led;
X int led_mode;
X} LedState;
X
Xstatic LedState composeLedState;
X
Xstatic Client *lastCurrentClient = NULL;
X
X#define LED_MAP_LENGTH (33L)
X
X/***************************************************************************
X* private functions
X***************************************************************************/
X
Xstatic void clientSetBusy();
X
X/*
X * setComposeLed - sets the compose led to the new mode iff different than
X * the current mode.
X */
Xstatic void
XsetComposeLed(dpy,mode)
X Display *dpy;
X int mode;
X{
X XKeyboardControl kbdValue;
X
X if (mode == composeLedState.led_mode)
X return;
X
X composeLedState.led_mode = mode;
X kbdValue.led = composeLedState.led;
X kbdValue.led_mode = composeLedState.led_mode;
X
X XChangeKeyboardControl(dpy,KBLed|KBLedMode,&kbdValue);
X}
X
X/***************************************************************************
X* global functions
X***************************************************************************/
X
X/*
X * InitClientState - init kbd led state for client use
X */
XInitClientState(dpy)
XDisplay *dpy;
X{
X int *ledMap;
X int i,numLeds,led;
X unsigned int nitems,nremain;
X XKeyboardControl kbdvalue;
X
X DoingWindowState = False;
X
X /*
X * Get the _SUN_LED_MAP property from the default root window
X */
X ledMap = GetWindowProperty(dpy,DefaultRootWindow(dpy),AtomSunLedMap,
X 0L,LED_MAP_LENGTH,XA_INTEGER,32,&nitems,&nremain);
X
X if (ledMap == NULL || nitems != LED_MAP_LENGTH || nremain != 0) {
X return;
X }
X numLeds = ledMap[0]; /* first entry is the number of leds */
X
X /*
X * Find out which led number is marked Compose
X */
X for (i = 1; i <= numLeds; i++) {
X if (ledMap[i] == XK_Multi_key) {
X composeLedState.led = i;
X composeLedState.led_mode = -1; /* for first time */
X DoingWindowState = True;
X }
X }
X
X /*
X * Turn off the compose led
X */
X if (DoingWindowState)
X setComposeLed(dpy,LedModeOff);
X
X XFree((char *)ledMap);
X}
X
X/*
X * ClientDefaultWindowState - applies the default window state
X */
XClientDefaultWindowState(dpy)
X Display *dpy;
X{
X setComposeLed(dpy,LedModeOff);
X}
X
X/*
X * ClientSetWindowState - applies the client's window state
X */
XClientSetWindowState(cli)
X Client *cli;
X{
X if (!DoingWindowState)
X return;
X
X /*
X * If the client has specified the window state then interpret it.
X */
X if (cli->windowState) {
X if (cli->windowState->flags & WSSemanticState) {
X if (cli->windowState->state & WSSemanticCompose)
X setComposeLed(cli->dpy,LedModeOn);
X else
X setComposeLed(cli->dpy,LedModeOff);
X }
X /*
X * Else just apply the default state
X */
X } else {
X ClientDefaultWindowState(cli->dpy);
X }
X}
X
X/*
X * ClientGetWindowState - gets the _SUN_WINDOW_STATE property and if the
X * client has the focus then apply that new state.
X */
XClientGetWindowState(cli)
X Client *cli;
X{
X Window pane;
X OLWindowState winState;
X
X if (!DoingWindowState)
X return;
X
X if (cli->framewin == NULL)
X return;
X
X pane = PANEWINOFCLIENT(cli);
X
X if (!PropGetOLWindowState(cli->dpy,pane,&winState))
X return;
X
X if (cli->windowState == NULL)
X cli->windowState = MemNew(OLWindowState);
X
X *cli->windowState = winState;
X
X if (cli->isFocus)
X ClientSetWindowState(cli);
X}
X
X/*
X * ClientUpdateWindowState - handle PropertyNotify on _SUN_WINDOW_STATE
X */
Xvoid
XClientUpdateWindowState(cli,event)
X Client *cli;
X XPropertyEvent *event;
X{
X if (!DoingWindowState)
X return;
X
X if (event->state == PropertyNewValue) {
X ClientGetWindowState(cli);
X } else {
X if (cli->windowState)
X MemFree((char *)cli->windowState);
X cli->windowState = (OLWindowState *)NULL;
X ClientDefaultWindowState(cli->dpy);
X }
X}
X
X/* ClientSendProtocol - send a protocol message to a client
X */
Xvoid *
XClientSendProtocol(cli,proto,evtime)
XClient *cli;
XAtom proto;
XTime evtime;
X{
X XEvent clientEvent;
X
X clientEvent.xclient.type = ClientMessage;
X clientEvent.xclient.message_type = AtomProtocols;
X clientEvent.xclient.format = 32;
X clientEvent.xclient.display = cli->dpy;
X clientEvent.xclient.window = ClientPane(cli);
X clientEvent.xclient.data.l[0] = proto;
X clientEvent.xclient.data.l[1] = evtime;
X
X XSendEvent(cli->dpy, clientEvent.xclient.window, False,
X NoEventMask, &clientEvent);
X return NULL;
X}
X
X/* ClientShowProps - send a ClientMessage of type WM_SHOW_PROPERTIES
X */
Xvoid
XClientShowProps(cli)
XClient *cli;
X{
X XEvent clientEvent;
X
X clientEvent.xclient.type = ClientMessage;
X clientEvent.xclient.message_type = AtomShowProperties;
X clientEvent.xclient.format = 32;
X clientEvent.xclient.display = cli->dpy;
X clientEvent.xclient.window = PANEWINOFCLIENT(cli);
X
X XSendEvent(cli->dpy, clientEvent.xclient.window, False,
X NoEventMask, &clientEvent);
X}
X
X/* ClientKill - a client must be killed. If it can handle the DELETE_WINDOW
X * protocol, use it; otherwise, if we are forcing the client to go
X * away, kill it.
X */
Xvoid *
XClientKill(cli,pforce)
XClient *cli;
XBool pforce;
X{
X if (cli->framewin == NULL)
X return NULL;
X
X if (cli->protocols & DELETE_WINDOW) {
X ClientSendProtocol(cli,AtomDeleteWindow,LastEventTime);
X } else {
X if (pforce && ! cli->flags & CLOlwmOwned)
X XKillClient(cli->dpy,ClientPane(cli));
X else
X if (GRV.Beep == BeepAlways)
X XBell(cli->dpy, 100);
X }
X return NULL;
X}
X
X/* ClientShutdown - a client must be shut down. Force the client
X * the go away without any further user interaction.
X */
Xvoid *
XClientShutdown(cli,junk)
XClient *cli;
Xvoid *junk;
X{
X /* Only kill non-olwm owned clients */
X if (! cli->flags & CLOlwmOwned)
X XKillClient(cli->dpy,ClientPane(cli));
X return NULL;
X}
X
X
X/* UnparentClient - while exiting OLWM: unmap all icons that are on the
X * screen. Reparent all windows back to the root, suitably offset
X * according to their window-gravities. Also remap all non-withdrawn
X * windows, and remove all Withdrawn windows from the save-set (so
X * they don't get remapped. REMIND: We have to do this because
X * Withdrawn windows are still left reparented inside the frame; this
X * shouldn't be the case.
X */
X/*ARGSUSED*/
Xvoid *
XUnparentClient(cli,junk)
XClient *cli;
Xvoid *junk;
X{
X WinPaneFrame *frameInfo;
X WinPane *paneInfo;
X Window pane;
X
X /* if no framewin then it's probably a root window */
X if (cli->framewin == NULL)
X return NULL;
X
X if (cli->wmState == IconicState)
X {
X IconHide(cli, cli->iconwin);
X }
X
X frameInfo = cli->framewin;
X paneInfo = (WinPane*)(frameInfo->fcore.panewin);
X pane = paneInfo->core.self;
X FrameUnparentPane(cli, frameInfo, paneInfo);
X
X if (cli->wmState == DontCareState)
X {
X if (!(cli->flags & CLOlwmOwned))
X XChangeSaveSet(cli->dpy, pane, SetModeDelete);
X }
X else
X {
X XMapWindow(cli->dpy,pane);
X }
X
X return NULL;
X}
X
X/*
X * addClient -- add this client structure to the list of active clients
X */
Xstatic void
XaddClient(cli)
XClient *cli;
X{
X List *l = ActiveClientList;
X Client *tc;
X
X /* First look to see if window is already listed. */
X for(tc = ListEnum(&l); tc != NULL; tc = ListEnum(&l))
X {
X if (tc == cli)
X return;
X }
X
X /* Wasn't present, add to list. */
X ActiveClientList = ListCons(cli, ActiveClientList);
X}
X
X/*
X * removeClient -- remove this client structure from the list of active
X * clients.
X */
Xstatic void
XremoveClient(cli)
XClient *cli;
X{
X List **l;
X
X for (l = &ActiveClientList ; *l != NULL; l = &((*l)->next))
X {
X if ((*l)->value == cli)
X {
X ListDestroyCell(l);
X return;
X }
X }
X}
X
X/*
X * DestroyClient -- destroy all resources associated with this client, and
X * remove external references to this client. If this is the current client,
X * and we are in click-to-type, set the focus to the topmost client *after*
X * having destroyed this client.
X */
Xvoid
XDestroyClient(cli)
XClient *cli;
X{
X Bool setfocus = False;
X Display *dpy = cli->dpy;
X ScreenInfo *scrInfo = cli->scrInfo;
X List *l;
X Client *tcli;
X
X UnTrackSubwindows(cli, True);
X if (IsSelected(cli))
X RemoveSelection(cli);
X
X if (cli == CurrentClient) {
X ClientSetCurrent(NoFocusWinInfo->core.client);
X /* purge the old client from lastCurrentClient */
X /* REMIND need a better interface */
X lastCurrentClient = NULL;
X
X setfocus = !GRV.FocusFollowsMouse;
X }
X
X removeClient(cli);
X
X /*
X * Run through the remaining clients and remove any references to this
X * client from their warp-back records.
X */
X l = ActiveClientList;
X while (tcli = ListEnum(&l)) {
X if (tcli->framewin != NULL &&
X tcli->warpInfo.warpBackClient == cli)
X {
X tcli->framewin->pointerIsWarped = False;
X }
X }
X
X /* destroy the window resources associated with the client */
X WinCallDestroy(cli);
X
X GroupRemove(cli->groupid, cli);
X
X /* free up the client structure resources */
X if (cli->wmDecors)
X MemFree(cli->wmDecors);
X if (cli->normHints)
X MemFree(cli->normHints);
X if (cli->wmHints)
X MemFree(cli->wmHints);
X if (cli->wmInstance)
X MemFree(cli->wmInstance);
X if (cli->wmClass)
X MemFree(cli->wmClass);
X if (cli->windowState)
X MemFree(cli->windowState);
X
X /* REMIND what's to be done with followers here? */
X
X#ifdef DEBUG
X memset(cli, 0, sizeof(Client));
X#endif /* DEBUG */
X
X MemFree(cli);
X
X if (setfocus)
X ClientFocusTopmost(dpy, scrInfo, CurrentTime);
X}
X
X/*
X * ClientConfigure - a configure request event has been received on the
X * pane. Configure the windows accordingly.
X */
Xvoid
XClientConfigure(cli,win,pxcre)
XClient *cli;
XWinGeneric *win;
XXConfigureRequestEvent *pxcre;
X{
X XWindowChanges winChange;
X
X if ((cli == NULL) || (win == NULL))
X {
X /* We don't know about this window, or it's withdrawn
X * convert the request into an XConfigureWindow
X * call. We do not look at the hints to see if
X * the resize is in the proper increments, but since
X * the app is asking for the reconfigure this seems
X * right.
X */
X winChange.x = pxcre->x;
X winChange.y = pxcre->y;
X winChange.width = pxcre->width;
X winChange.height = pxcre->height;
X winChange.border_width = pxcre->border_width;
X winChange.stack_mode = pxcre->detail;
X winChange.sibling = pxcre->above;
X
X XConfigureWindow(pxcre->display,
X pxcre->window,
X /* lint will warn: this is a long, not int */
X (int) pxcre->value_mask,
X &winChange );
X }
X else /* cli->wmState == NormalState or IconicState */
X {
X WinCallConfig(cli->dpy,win,pxcre);
X }
X}
X
X/*
X * ClientSetWMState -- set the contents of the WM_STATE property,
X * given the information in the WinInfo struct.
X */
Xvoid
XClientSetWMState( cli )
X Client *cli;
X{
X WinIconFrame *iconWinInfo = cli->iconwin;
X Window pane = PANEWINOFCLIENT(cli);
X Window icon;
X
X if (cli->framewin->core.self ==
X cli->scrInfo->vdm->client->framewin->core.self)
X return;
X if (iconWinInfo) {
X if ( iconWinInfo->fcore.panewin )
X icon = iconWinInfo->fcore.panewin->core.self;
X else
X icon = iconWinInfo->core.self;
X } else {
X icon = None;
X }
X
X PropSetWMState(cli->dpy,pane,cli->wmState,icon);
X}
X
X
X/* ===== Drag-and-Drop Interest Property ================================== */
X
X
X#define DRAGDROP_VERSION 0
X#define INTEREST_RECT 0
X#define INTEREST_WINDOW 1
X#define SITE_DEFAULT (1<<2)
X#define SITE_FORWARD (1<<3)
X
X/*
X * Get the next word from the `data' array, indexed by `cur'. If this causes
X * us to go beyond `nitems', return silently.
X */
X#define NEXTWORD(dest) do { \
X if (++cur >= nitems) { \
X XFree((char *)data); \
X return; \
X } \
X (dest) = data[cur]; \
X } while (0)
X
X#define INCR(by) do { \
X cur += (by); \
X if (cur >= nitems) \
X return; \
X } while (0)
X
X
Xstatic struct {
X unsigned long
X version,
X nsites,
X wid,
X sid,
X flags,
X areatype,
X nelts,
X rx, ry, rw, rh;
X} forwardingInterest = {
X 0, /* version */
X 1, /* nsites */
X 0, /* window id -- to be filled in */
X 0, /* site id -- to be filled in */
X 0, /* flags -- to be filled in */
X INTEREST_RECT, /* areatype */
X 1, /* number of rects */
X 0, 0, 0, 0 /* rectangle -- to be filled in */
X};
X#define FI_LENGTH \
X (sizeof(forwardingInterest)/sizeof(unsigned long))
X
X
X/*
X * ClientProcessDragDropInterest - read the clients drag'n'drop interest
X * property, and put an interest containing the default site onto the frame
X * window and the icon window. If we encounter an error reading the property,
X * do nothing and return silently.
X */
Xvoid
XClientProcessDragDropInterest(cli, state)
X Client *cli;
X int state; /* PropertyNewValue or PropertyDelete */
X{
X unsigned long *data;
X int nitems, remain, nsites, i, areatype, nelts;
X int cur = 0;
X Window wid;
X unsigned long sid, flags;
X
X if (state == PropertyDelete) {
X DeleteProperty(cli->dpy, cli->framewin,
X AtomSunDragDropInterest);
X if (cli->iconwin != NULL)
X DeleteProperty(cli->dpy, cli->iconwin,
X AtomSunDragDropInterest);
X return;
X }
X
X data = GetWindowProperty(cli->dpy, PANEWINOFCLIENT(cli),
X AtomSunDragDropInterest, 0L, 1000000L, AtomSunDragDropInterest,
X 32, &nitems, &remain);
X
X if (data == NULL)
X return;
X
X if (data[cur] != DRAGDROP_VERSION) {
X XFree((char *)data);
X return;
X }
X
X NEXTWORD(nsites);
X for (i=0; i<nsites; ++i) {
X NEXTWORD(wid);
X NEXTWORD(sid);
X NEXTWORD(flags);
X NEXTWORD(areatype);
X switch (areatype) {
X case INTEREST_RECT:
X NEXTWORD(nelts);
X INCR(4*nelts);
X break;
X case INTEREST_WINDOW:
X NEXTWORD(nelts);
X INCR(nelts);
X break;
X default:
X /* unknown area type; just return */
X XFree((char *)data);
X return;
X }
X if (flags & SITE_DEFAULT) {
X forwardingInterest.wid = wid;
X forwardingInterest.sid = sid;
X forwardingInterest.flags = flags & ~SITE_DEFAULT;
X forwardingInterest.flags |= SITE_FORWARD;
X
X /* write the property on the frame */
X
X forwardingInterest.rx = 0;
X forwardingInterest.ry = 0;
X forwardingInterest.rw = cli->framewin->core.width;
X forwardingInterest.rh = cli->framewin->core.height;
X ChangeProperty(cli->dpy, cli->framewin,
X AtomSunDragDropInterest, AtomSunDragDropInterest,
X 32, PropModeReplace,
X (unsigned char *) &forwardingInterest, FI_LENGTH);
X
X /* write the property on the icon */
X if (cli->iconwin != NULL) {
X forwardingInterest.rx = 0;
X forwardingInterest.ry = 0;
X forwardingInterest.rw = cli->iconwin->core.width;
X forwardingInterest.rh = cli->iconwin->core.height;
X ChangeProperty(cli->dpy, cli->iconwin,
X AtomSunDragDropInterest, AtomSunDragDropInterest,
X 32, PropModeReplace,
X (unsigned char *) &forwardingInterest, FI_LENGTH);
X }
X break;
X }
X }
X XFree((char *)data);
X}
X
X/*
X * ClientUpdateDragDropInterest - handle PropertyNotify on DragDropInterest
X */
Xvoid
XClientUpdateDragDropInterest(cli,event)
X Client *cli;
X XPropertyEvent *event;
X{
X ClientProcessDragDropInterest(cli,event->state);
X}
X
X
X/* ClientCreate -- allocate and initialise a client structure
X */
XClient *
XClientCreate(dpy,screen)
X Display *dpy;
X int screen;
X{
X Client *cli = MemNew(Client);
X
X cli->wmState = DontCareState;
X cli->dpy = dpy;
X cli->screen = screen;
X cli->scrInfo = GetScrInfoOfScreen(screen);
X /* all other fields set to zero by allocation function */
X addClient(cli);
X return cli;
X}
X
X/* ClientPane - return the pane window of a client
X */
XWindow
XClientPane(cli)
XClient *cli;
X{
X WinPaneFrame *wf;
X WinPane *wp;
X
X if ((wf = cli->framewin) == NULL)
X return NULL;
X if ((wp = (WinPane *)(wf->fcore.panewin)) == NULL)
X return NULL;
X return wp->core.self;
X}
X
X
X/*
X * ClientOpenCloseToggle
X * Perform the appropriate open/close action.
X */
Xvoid
XClientOpenCloseToggle(cli)
XClient *cli;
X{
X /*
X * If we are a pop-up (have a pushpin) or are transient,
X * then dismiss.
X */
X if ((cli->wmDecors->flags & WMDecorationPushPin)
X || cli->transientFor != 0) {
X ClientKill(cli,False);
X
X /* else switch the state from/to normal/iconic */
X } else {
X switch (cli->wmState) {
X case NormalState:
X StateNormIcon(cli);
X break;
X case IconicState:
X StateIconNorm(cli);
X break;
X default:
X break;
X }
X }
X}
X
X/*
X * ClientStickUnstickToggle
X * Perform the appropriate Stick/Unstick action.
X */
Xvoid
XClientStickUnstickToggle(cli)
XClient *cli;
X{
X MakeSticky(cli, !cli->sticky);
X if (cli->groupmask == GROUP_LEADER)
X GroupApply(cli->groupid, MakeSticky, cli->sticky, GROUP_DEPENDENT);
X}
X
X/*
X * ClientFullRestoreSizeToggle
X * Call both frame and icon full/restore toggle functions.
X */
Xvoid
XClientFullRestoreSizeToggle(cli)
XClient *cli;
X{
X if (cli->wmDecors->flags & WMDecorationResizeable) {
X (WinFunc(cli->framewin,fcore.fullrestoreToggle))(cli);
X (WinFunc(cli->iconwin,fcore.fullrestoreToggle))(cli);
X }
X}
X
X/*
X * ClientMove
X * Moves the client to a new x,y position.
X */
Xvoid
XClientMove(cli,trigger)
X Client *cli;
X XEvent *trigger;
X{
X UserMoveWindows(cli, trigger);
X}
X
X/*
X * ClientResize
X * Resizes the client to a new w,h size.
X */
Xvoid
XClientResize(cli,trigger,which,callback,cbarg)
X Client *cli;
X XEvent *trigger;
X WhichResize which;
X void (*callback)();
X void *cbarg;
X{
X if (cli->wmDecors->flags & WMDecorationResizeable)
X UserResizeWin(cli, trigger, which, callback, cbarg);
X}
X
X
X/*
X * ClientRaiseTransients
X *
X * Raise any transient windows associated with this client. Return the
X * client for the bottommost transient window. This is useful so that the
X * parent window can be restacked just below the bottommost transient. If
X * there are no transient windows, returns NULL.
X *
X * REMIND raises all transient windows in the order they are encountered in
X * the active client list, and returns the first one found. Ideally, this
X * should preserve the stacking order of the transients.
X */
XClient *
XClientRaiseTransients(cli)
X Client *cli;
X{
X List *l = ActiveClientList;
X Client *tc;
X Client *first = NULL;
X
X if (!GRV.KeepTransientsAbove)
X return NULL;
X
X while (tc = ListEnum(&l)) {
X if (tc->transientFor == PANEWINOFCLIENT(cli)) {
X RaiseWindow(tc->framewin);
X if (first == NULL)
X first = tc;
X }
X }
X return first;
X}
X
X
X/*
X * ClientLowerTransients
X *
X * Restack any transient windows associated with this client to be just above
X * this client's frame.
X *
X * REMIND this lowers all transient windows in the order they are encountered
X * in the active client list. Ideally, this should preserve the stacking
X * order of the transients.
X */
Xvoid
XClientLowerTransients(cli)
X Client *cli;
X{
X List *l = ActiveClientList;
X Client *tc;
X XWindowChanges xwc;
X
X if (!GRV.KeepTransientsAbove)
X return;
X
X xwc.stack_mode = Above;
X xwc.sibling = cli->framewin->core.self;
X while (tc = ListEnum(&l)) {
X if (tc->transientFor == PANEWINOFCLIENT(cli)) {
X ConfigureWindow(tc->dpy, tc->framewin,
X CWSibling | CWStackMode, &xwc);
X }
X }
X}
X
X
X/*
X * ClientFront
X *
X * Moves the appropriate client window to the front of the window hierarchy.
X * If this window has any transient windows, move them in front first.
X */
Xvoid
XClientFront(cli)
XClient *cli;
X{
X Client *firsttransient;
X XWindowChanges xwc;
X
X switch (cli->wmState) {
X case NormalState:
X firsttransient = ClientRaiseTransients(cli);
X if (firsttransient != NULL) {
X xwc.sibling = firsttransient->framewin->core.self;
X xwc.stack_mode = Below;
X ConfigureWindow(cli->dpy, cli->framewin,
X CWSibling | CWStackMode, &xwc);
X } else {
X RaiseWindow(cli->framewin);
X }
X break;
X case IconicState:
X RaiseWindow(cli->iconwin);
X break;
X default:
X break;
X }
X}
X
X
X/*
X * ClientBack
X *
X * Moves the appropriate client window to the back of the window hierarchy.
X * If this is a transient window, move its parent window to the back first,
X * and then move this window just in front of it.
X *
X * REMIND this isn't optimal behavior for transient windows, but it does
X * ensure that transient windows always remain in front of their parents.
X */
Xvoid
XClientBack(cli)
XClient *cli;
X{
X WinGeneric *owner;
X Window ownerwin;
X XWindowChanges xwc;
X
X switch (cli->wmState) {
X case NormalState:
X if (cli->transientFor != 0 && GRV.KeepTransientsAbove) {
X owner = WIGetInfo(cli->transientFor);
X if (owner == NULL ||
X owner->core.kind != WIN_PANE) {
X LowerWindow(cli->framewin);
X } else {
X ownerwin = owner->core.client->framewin->core.self;
X LowerWindow(owner->core.client->framewin);
X xwc.sibling = ownerwin;
X xwc.stack_mode = Above;
X ConfigureWindow(cli->dpy, cli->framewin,
X CWSibling | CWStackMode, &xwc);
X }
X } else {
X LowerWindow(cli->framewin);
X }
X break;
X case IconicState:
X LowerWindow(cli->iconwin);
X break;
X default:
X break;
X }
X}
X
X
X/*
X * ClientToggleStacking
X *
X * Moves the appropriate client window to the front of the window hierarchy if
X * it is obscured, otherwise move it to the back of the hierarchy if it
X * obscures any other window. REMIND: doesn't deal with transient windows at
X * all.
X */
Xvoid
XClientToggleStacking(cli)
XClient *cli;
X{
X XWindowChanges xwc;
X WinGeneric *win;
X
X switch (cli->wmState) {
X case NormalState:
X win = (WinGeneric *) cli->framewin;
X break;
X case IconicState:
X win = (WinGeneric *) cli->iconwin;
X break;
X }
X
X xwc.stack_mode = Opposite;
X ConfigureWindow(cli->dpy, win, CWStackMode, &xwc);
X}
X
X
X/*
X * ClientRefresh
X * Refresh the window. We do this by creating a window on top
X * of the window to refresh and then immediately destroy it.
X * Refresh either icon or frame windows.
X */
Xvoid
XClientRefresh(cli)
XClient *cli;
X{
X Window w,cliwin;
X int cliwidth,cliheight;
X XSetWindowAttributes xswa;
X
X /* Chose which window to refresh */
X switch (cli->wmState) {
X case NormalState:
X cliwin = cli->framewin->core.self;
X cliwidth = cli->framewin->core.width;
X cliheight = cli->framewin->core.height;
X break;
X case IconicState:
X cliwin = cli->iconwin->core.self;
X cliwidth = cli->iconwin->core.width;
X cliheight = cli->iconwin->core.height;
X break;
X default:
X return;
X /*NOTREACHED*/
X break;
X }
X
X /* if we should refresh all windows */
X if (GRV.RefreshRecursively) {
X RecursiveRefresh(cli->dpy,cliwin);
X
X /* or just the top/main window */
X } else {
X w = XCreateWindow(cli->dpy,
X cliwin, 0, 0, cliwidth, cliheight, 0,
X CopyFromParent, InputOutput, CopyFromParent,
X 0, &xswa);
X XMapRaised(cli->dpy,w);
X XDestroyWindow(cli->dpy,w);
X }
X}
X
X/*
X * ClientFlashOwner
X * Find group leader frame, bring it to the top and then
X * flash its title bar.
X *
X * REMIND: make sure transient windows get treated properly
X * before or after (which? not sure) the leader is raised.
X */
Xvoid
XClientFlashOwner(cli)
XClient *cli;
X{
X Client *cliLead = GroupLeader(cli->groupid);
X if (cliLead && cliLead->framewin) {
X RaiseWindow(cliLead->framewin);
X WinCallDraw((WinGeneric *)cliLead->framewin);
X FrameFlashTitleBar(cliLead->framewin);
X }
X}
X
X/*
X * Toggle the pushpin of this client's window. Returns False if this client's
X * window has no pin, otherwise, returns True.
X */
XBool
XClientTogglePin(cli)
X Client *cli;
X{
X WinPushPin *pin;
X
X if (cli->framewin == NULL || !ClientIsPinnable(cli))
X return False;
X
X pin = (WinPushPin *)cli->framewin->winDeco;
X PushPinTogglePinState(cli->dpy,pin,True);
X return True;
X}
X
X
X/* ClientInBox -- given a bounding box, apply a function to all clients
X * which fall inside the rectangle
X */
Xvoid *
XClientInBox(cli, close)
XClient *cli;
XClientInBoxClosure *close;
X{
X int x, y, w, h;
X
X if (cli->screen != close->screen)
X return NULL;
X
X if (cli->framewin == NULL)
X return NULL;
X
X if (cli->wmState == IconicState)
X {
X x = cli->iconwin->core.x;
X y = cli->iconwin->core.y;
X w = cli->iconwin->core.width;
X h = cli->iconwin->core.height;
X }
X else
X {
X x = cli->framewin->core.x;
X y = cli->framewin->core.y;
X w = cli->framewin->core.width;
X h = cli->framewin->core.height;
X }
X
X if ((x >= close->bx) &&
X (y >= close->by) &&
X ((x + w) <= (close->bx + close->bw)) &&
X ((y + h) <= (close->by + close->bh)))
X (close->func)(cli, close->timestamp);
X
X return NULL;
X}
X
X/*
X * ClientSetBusy -- the busy state has (possibly) been changed for a client.
X * if the client is going from normal to busy:
X * mark the client as busy
X * put up a busy window
X * if the client is going from busy to normal:
X * mark the client as unbusy
X * take down a busy window (if it exists)
X */
Xvoid
XClientUpdateBusy(cli,event)
X Client *cli;
X XPropertyEvent *event;
X{
X int *newBusyPtr;
X int newBusy;
X unsigned long nItems, remain;
X
X if (event->state == PropertyNewValue) {
X newBusyPtr = GetWindowProperty(cli->dpy, PANEWINOFCLIENT(cli),
X AtomWindowBusy, 0L, LONG_LENGTH(*newBusyPtr),
X XA_INTEGER, 32, &nItems, &remain);
X
X if (newBusyPtr == NULL) {
X /* property not found or has the wrong type */
X newBusy = 0;
X } else {
X if (nItems != LONG_LENGTH(newBusy) || remain != 0) {
X /* got a property, but it is invalid */
X newBusy = 0;
X } else {
X /* valid property */
X newBusy = *newBusyPtr;
X }
X XFree((char *)newBusyPtr);
X }
X } else {
X /* property was deleted */
X newBusy = 0;
X }
X
X /*
X * Losing busy
X */
X if (cli->isBusy && (newBusy == 0)) {
X cli->isBusy = False;
X if (cli->isFocus)
X ClientSetFocus(cli,True,event->time);
X FrameSetBusy(cli->framewin, False);
X }
X /*
X * Else Gaining busy
X */
X else if (!cli->isBusy && (newBusy == 1)) {
X cli->isBusy = True;
X FrameSetBusy(cli->framewin, True);
X if (cli->isFocus)
X ClientSetFocus(cli,True,event->time);
X }
X}
X
X
X/*
X * REMIND this function should be removed when menu/menuinfos
X * are reorged.
X */
Xvoid
XDestroyPinnedMenuClients()
X{
X List *l = ActiveClientList;
X Client *cli;
X
X
X for (cli = ListEnum(&l); cli != NULL; cli = ListEnum(&l)) {
X if (cli->framewin && cli->framewin->fcore.panewin &&
X cli->framewin->fcore.panewin->core.kind == WIN_PINMENU) {
X#ifdef DEBUG
X printf("DestroyPinnedMenuClients: destroyed %x\n",cli);
X#endif
X DestroyClient(cli);
X }
X }
X}
X
X
X/* ===== focus stuff ====================================================== */
X
X
X/*
X * Focus Change Inhibition.
X *
X * If focus changing is inhibited, information about focus changing is stored
X * in the FocusInhibitRecord instead of being used to set the focus. If
X * several focus changes occur while focus changing is inhibited, only
X * information for the latest change is stored. When focus changing becomes
X * uninhibited, the information is used to set the focus for real. This
X * prevents unnecessary focus changing. REMIND: focus inhibition doesn't
X * occur when the focus is set to the NoFocus window. This isn't too bad, as
X * no highlighting occurs when this happens.
X */
X
Xstatic struct FocusInhibitRecord {
X Bool inhibited;
X Client *cli;
X Bool sendTF;
X Time evtime;
X} fir;
X
X
X/*
X * ClientInhibitFocus -- inhibit or uninhibit focus changing.
X */
Xvoid
XClientInhibitFocus(inhibit)
X Bool inhibit;
X{
X if (inhibit) {
X fir.inhibited = True;
X fir.cli = NULL;
X } else {
X fir.inhibited = False;
X if (fir.cli != NULL)
X ClientSetFocus(fir.cli, fir.sendTF, fir.evtime);
X fir.cli = NULL;
X }
X}
X
X
X/*
X * ClientSetFocus -- possibly set the focus to this client. If focus changing
X * is inhibited, store information in the inhibit record. Otherwise, set the
X * focus normally. If the client is GloballyActive, we only send TakeFocus
X * messages if sendTF is true. If the client has a different focus mode
X * sendTF is ignored. If the client is a NoInput client, set the focus to the
X * frame itself. REMIND: this works, if a little bizarre. The frame doesn't
X * select for keystrokes, so they fall to the root. The root event handler
X * ends up beeping, which is OK.
X */
Xvoid
XClientSetFocus(cli,sendTF,evtime)
XClient *cli;
XBool sendTF;
XTime evtime;
X{
X if (fir.inhibited) {
X fir.cli = cli;
X fir.sendTF = sendTF;
X fir.evtime = evtime;
X return;
X }
X
X if (cli->wmState == IconicState) {
X if (cli->iconwin != NULL)
X XSetInputFocus(cli->dpy, cli->iconwin->core.self,
X RevertToParent, evtime);
X } else {
X switch (cli->focusMode)
X {
X case NoInput:
X XSetInputFocus(cli->dpy, cli->framewin->core.self,
X RevertToParent, evtime);
X break;
X
X case Passive:
X case LocallyActive:
X XSetInputFocus(cli->dpy, PANEWINOFCLIENT(cli),
X RevertToParent, evtime);
X break;
X
X case GloballyActive:
X if (sendTF)
X {
X ClientSendProtocol(cli, AtomTakeFocus, evtime);
X }
X break;
X }
X }
X}
X
X
X/*
X * Current Client.
X *
X * The current client is used by the mouseless functions. These functions
X * maintain the current and previously-current client. If cli is already the
X * current client, don't do anything. This is necessary because this may be
X * called when a client is activated explicitly (from ClientActivate) or
X * implicitly (when a globally active client takes the focus). Therefore, if
X * ClientActivate activates a globally active client, this function will be
X * called twice.
X *
X * Eventually, this may change to be a "ring-buffer" history of clients.
X *
X * REMIND: the notion of the current client may be a vestige from the time
X * when some objects (like icons and pinned menus) didn't take the focus.
X * Activating one of these items would set the focus to the NoFocus window,
X * but set the current client to that particular client. Thus, having the
X * focus was not the same as being the current client. This distinction may
X * no longer be true, in which case it is sufficient to keep track of the
X * client that has the focus, without the separate notion of a current client.
X * One possible problem may occur with buggy Globally Active clients that
X * don't take the focus when requested. If we rely on the focus to keep track
X * of the current client, we may get "stuck" if the next client fails to take
X * the focus when requested.
X */
Xvoid
XClientSetCurrent(cli)
X Client *cli;
X{
X if (cli != CurrentClient) {
X lastCurrentClient = CurrentClient;
X CurrentClient = cli;
X }
X}
X
X
XClient *
XClientGetLastCurrent()
X{
X return lastCurrentClient;
X}
X
X
X/*
X * Client Activation.
X *
X * Activate the named client. The difference between this and ClientSetFocus
X * is that this function selects and raises the client's window in addition to
X * setting the focus. Further, this function works on iconic clients as well
X * as open ones. This function sets the current client explicitly. We would
X * rely on the resulting focus change to set the current client, except that
X * a globally active client may decline the focus when it is asked to take it.
X *
X * REMIND this shouldn't have to deal with selections at all. However,
X * icons and headerless windows currently have no way to indicate that they
X * have the focus. Therefore, select them.
X */
Xvoid
XClientActivate(dpy, cli, time)
X Display *dpy;
X Client *cli;
X Time time;
X{
X /*
X * If the current client is selected, assume it was selected because it
X * was made the active client, and deselect it. (See REMIND above.)
X */
X if (CurrentClient != NULL && CurrentClient->isSelected)
X ClearSelections(dpy);
X
X /*
X * If we are being asked to activate a NULL client, or a client without a
X * frame (i.e. a root client), activate the NoFocus client.
X */
X if (cli == NULL) {
X NoFocusTakeFocus(dpy, time, NULL);
X } else if (cli->framewin == NULL) {
X NoFocusTakeFocus(dpy, time, cli->scrInfo);
X } else {
X ClientSetFocus(cli, True, time);
X
X /*
X * If the client is iconic or has no header, select it to show that it
X * is the active client. (See REMIND above.)
X */
X if (cli->wmState == IconicState ||
X !(cli->wmDecors->flags & WMDecorationHeader)) {
X ClearSelections(dpy);
X AddSelection(cli, time);
X }
X
X if (GRV.RaiseOnActivate)
X ClientFront(cli);
X
X ClientSetCurrent(cli);
X }
X}
X
X
X/*
X * Set the focus to the topmost window on the given screen.
X */
Xvoid
XClientFocusTopmost(dpy, scrinfo, time)
X Display *dpy;
X ScreenInfo *scrinfo;
X Time time;
X{
X Window wjunk;
X Window *children;
X unsigned int nchildren;
X int i;
X Client *topframeclient = NULL;
X Client *topiconclient = NULL;
X WinGeneric *win;
X
X if (0 == XQueryTree(dpy, scrinfo->rootid, &wjunk, &wjunk,
X &children, &nchildren))
X {
X return;
X }
X
X /*
X * QueryTree returns children on bottom-to-top order, so search backward,
X * looking for the topmost frame and icon.
X */
X for (i = nchildren-1; i >= 0; --i) {
X win = WIGetInfo(children[i]);
X if (win != NULL) {
X if (win->core.kind == WIN_FRAME &&
X win->core.client->wmState == NormalState &&
X topframeclient == NULL)
X {
X topframeclient = win->core.client;
X }
X
X if (win->core.kind == WIN_ICON &&
X win->core.client->wmState == IconicState &&
X topiconclient == NULL)
X {
X topiconclient = win->core.client;
X }
X
X if (topframeclient != NULL && topiconclient != NULL)
X break;
X }
X }
X
X if (topframeclient != NULL)
X ClientSetFocus(topframeclient, True, time);
X else if (topiconclient != NULL)
X ClientSetFocus(topiconclient, True, time);
X else
X NoFocusTakeFocus(dpy, time, scrinfo);
X
X XFree((char *) children);
X}
X
X/* ===== Client Property Changes ================================== */
X
Xtypedef struct {
X Atom *propAtom;
X void (*updateFunc)();
X} ClientPropUpdate;
X
Xstatic ClientPropUpdate propUpdateTable[] = {
X &AtomWMName, FrameUpdateHeader,
X &AtomLeftFooter, FrameUpdateFooter,
X &AtomRightFooter, FrameUpdateFooter,
X &AtomWMIconName, IconUpdateName,
X &AtomColorMapWindows, ColorUpdateColorMapWindows,
X &AtomProtocols, StateUpdateWMProtocols,
X &AtomWMNormalHints, StateUpdateWMNormalHints,
X &AtomWMHints, StateUpdateWMHints,
X &AtomWindowBusy, ClientUpdateBusy,
X &AtomSunWindowState, ClientUpdateWindowState,
X &AtomSunDragDropInterest, ClientUpdateDragDropInterest,
X &AtomWinAttr, StateUpdateWinAttr,
X &AtomDecorAdd, StateUpdateDecorAdd,
X &AtomDecorDel, StateUpdateDecorDel,
X};
X#define NPROPUPDATETABLE (sizeof(propUpdateTable)/sizeof(ClientPropUpdate))
X
X/* ClientDistributeProperty -- a property of the client has changed.
X * Forward the change notification to the appropriate handler.
X */
Xvoid
XClientDistributeProperty(cli, event)
X Client *cli;
X XPropertyEvent *event;
X{
X int i;
X
X for (i=0; i<NPROPUPDATETABLE; i++) {
X if (event->atom == *propUpdateTable[i].propAtom) {
X (propUpdateTable[i].updateFunc)(cli,event);
X break;
X }
X }
X}
END_OF_FILE
if test 37162 -ne `wc -c <'client.c'`; then
echo shar: \"'client.c'\" unpacked with wrong size!
fi
# end of 'client.c'
fi
if test -f 'events.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'events.h'\"
else
echo shar: Extracting \"'events.h'\" \(3632 characters\)
sed "s/^X//" >'events.h' <<'END_OF_FILE'
X/*
X * (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents
X * pending in the U.S. and foreign countries. See LEGAL_NOTICE
X * file for terms of the license.
X */
X
X#ifndef _OLWM_EVENT_H
X#define _OLWM_EVENT_H
X
X#ident "@(#)events.h 1.1 olvwm version 1/3/92"
X
X/*
X * Based on
X#ident "@(#)events.h 26.11 91/09/14 SMI"
X *
X */
X
X/* global functions */
Xextern void EventLoop();
Xextern int PropagateEventToParent();
Xextern void PropagatePressEventToChild();
Xextern Time LastEventTime;
Xextern Bool AwaitEvents();
Xextern void GrabKeys();
Xextern void RefreshKeyGrabs();
Xextern void GrabButtons();
Xextern void RefreshButtonGrabs();
Xextern void UpdateBindings();
Xextern void InitEvents();
Xextern void InitBindings();
X
X/* interposition */
Xextern void InstallInterposer();
Xextern void UninstallInterposer();
X
Xenum {
X DISPOSE_DISPATCH,
X DISPOSE_USED,
X DISPOSE_DEFER,
X};
X
X/* keyboard mapping */
Xextern KeySym *KbdMap;
Xextern int MinKeyCode;
Xextern int MaxKeyCode;
Xextern int KeySymsPerKeyCode;
X
X/* modifiers and modifier masks */
X
Xenum {
X MOD_CONSTRAIN,
X MOD_WMGRAB,
X MOD_REDUCE,
X MOD_INVERT,
X MOD_SETDEFAULT,
X MOD_IGNORE,
X MOD_MASK_COUNT /* must be last */
X};
X
Xextern unsigned int ModMaskMap[MOD_MASK_COUNT];
Xextern unsigned int FindModifierMask();
X
X/* mouse binding match states */
Xtypedef enum {
X MATCH_NONE, /* no binding matches at all */
X MATCH_INCOMPLETE, /* partial match */
X MATCH_AMBIG, /* more than one exact match */
X MATCH_PREFIX, /* exact match, but also a prefix for another */
X MATCH_EXACT, /* exact match, not a prefix */
X} MouseMatchState;
X
X/* semantic actions */
Xtypedef enum {
X ACTION_NONE,
X ACTION_SELECT,
X ACTION_ADJUST,
X ACTION_MENU,
X ACTION_HELP,
X ACTION_STOP,
X ACTION_PROPS,
X ACTION_FRONT,
X ACTION_OPEN,
X ACTION_EXEC_DEFAULT,
X ACTION_FOCUS_HELP,
X ACTION_SET_DEFAULT,
X ACTION_UP,
X ACTION_DOWN,
X ACTION_LEFT,
X ACTION_RIGHT,
X ACTION_JUMP_UP,
X ACTION_JUMP_DOWN,
X ACTION_JUMP_LEFT,
X ACTION_JUMP_RIGHT,
X ACTION_ROW_START,
X ACTION_ROW_END,
X ACTION_DATA_START,
X ACTION_DATA_END,
X ACTION_FIRST_CONTROL,
X ACTION_LAST_CONTROL,
X ACTION_TOGGLE_PIN,
X ACTION_CANCEL, /* REMIND does this differ from STOP? */
X ACTION_NEXT_ELEMENT,
X ACTION_PREVIOUS_ELEMENT,
X ACTION_UPLEFT,
X ACTION_UPRIGHT,
X ACTION_DOWNLEFT,
X ACTION_DOWNRIGHT,
X ACTION_HOME,
X ACTION_JUMP_UPLEFT,
X ACTION_JUMP_UPRIGHT,
X ACTION_JUMP_DOWNLEFT,
X ACTION_JUMP_DOWNRIGHT,
X ACTION_HALF_UP,
X ACTION_HALF_DOWN,
X ACTION_HALF_LEFT,
X ACTION_HALF_RIGHT,
X ACTION_HALF_UPLEFT,
X ACTION_HALF_UPRIGHT,
X ACTION_HALF_DOWNLEFT,
X ACTION_HALF_DOWNRIGHT,
X ACTION_GOTO_1,
X ACTION_GOTO_2,
X ACTION_GOTO_3,
X ACTION_GOTO_4,
X ACTION_GOTO_5,
X ACTION_GOTO_6,
X ACTION_GOTO_7,
X ACTION_GOTO_8,
X ACTION_GOTO_9,
X ACTION_GOTO_10,
X ACTION_VIRTUAL
X} SemanticAction;
X
X/* convert a button number to a button mask */
X#define ButtonToMask(b) (1<<(b+7))
X
X#define AnyButtonMask \
X (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
X
X/* given a ButtonRelease event, determines whether all buttons are now up. */
X#define AllButtonsUp(e) \
X (!((e)->xbutton.state & ~ButtonToMask((e)->xbutton.button) & AnyButtonMask))
X
X/* given a ButtonPress event, determine whether it's the first button down. */
X#define FirstButtonDown(e) \
X (((e)->xbutton.state & AnyButtonMask) == 0)
X
X/* timeouts */
Xtypedef void (*TimeoutFunc)();
Xextern void TimeoutRequest(); /* int time, TimeoutFunc f, void *closure */
Xextern void TimeoutCancel(); /* no params */
X
X#endif /* _OLWM_EVENT_H */
END_OF_FILE
if test 3632 -ne `wc -c <'events.h'`; then
echo shar: \"'events.h'\" unpacked with wrong size!
fi
# end of 'events.h'
fi
if test -f 'winpush.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'winpush.c'\"
else
echo shar: Extracting \"'winpush.c'\" \(10989 characters\)
sed "s/^X//" >'winpush.c' <<'END_OF_FILE'
X/*
X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents
X * pending in the U.S. and foreign countries. See LEGAL_NOTICE
X * file for terms of the license.
X */
X
X#ident "@(#)winpush.c 1.1 olvwm version 1/3/92"
X
X/*
X * Based on
X#ident "@(#)winpush.c 26.19 91/09/14 SMI"
X *
X */
X
X#include <errno.h>
X#include <stdio.h>
X#include <X11/Xos.h>
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include <X11/Xatom.h>
X#include <olgx/olgx.h>
X
X#include "i18n.h"
X#include "ollocale.h"
X#include "mem.h"
X#include "olwm.h"
X#include "win.h"
X#include "globals.h"
X
X/***************************************************************************
X* global data
X***************************************************************************/
X
Xextern Atom AtomDeleteWindow;
Xextern Atom AtomPushpinState;
Xextern void FrameAllowEvents();
X
X/***************************************************************************
X* private data
X***************************************************************************/
X
Xstatic ClassPushPin classPushPin;
Xstatic Bool pushpinStateAfterPress; /* State of the pushpin
X * after the user pressed
X * the mouse button. */
Xstatic SemanticAction currentAction = ACTION_NONE;
Xvoid PushPinChangePinState();
X
X/***************************************************************************
X* private functions
X***************************************************************************/
X
X/* locallyChangePushPinState -- temporarily change the pushpin state,
X * while tracking a button press over the pin. The permanent change
X * will be made later.
X */
Xstatic void
XlocallyChangePushPinState(dpy,winInfo,newState)
XDisplay *dpy;
XWinPushPin *winInfo;
XBool newState;
X{
X if (winInfo->pushpinin != newState)
X {
X winInfo->pushpinin = newState;
X (WinFunc(winInfo,core.drawfunc))(dpy, winInfo);
X }
X}
X
X
X/*
X * eventButtonPress - handle button press events on the pushpin window
X */
Xstatic int
XeventButtonPress(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPushPin *winInfo;
X{
X SemanticAction a = ResolveMouseBinding(dpy, event, 0L);
X FrameAllowEvents(winInfo->core.client, event->xbutton.time);
X switch (a) {
X case ACTION_SELECT:
X case ACTION_ADJUST:
X locallyChangePushPinState(dpy, winInfo, !(winInfo->pushpinin));
X pushpinStateAfterPress = winInfo->pushpinin;
X currentAction = a;
X break;
X }
X}
X
X/*
X * eventButtonRelease - handle button release events on the pushpin window
X */
Xstatic int
XeventButtonRelease(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPushPin *winInfo;
X{
X FrameAllowEvents(winInfo->core.client, event->xbutton.time);
X if (!AllButtonsUp(event))
X return;
X
X /*
X * If pushpinStateAfterPress equals the current pin state, we know
X * that the user really wants to change the pin state. If they are
X * not equal, the user has released the button outside the pin, so
X * there should be no change of state.
X */
X if (pushpinStateAfterPress == winInfo->pushpinin) {
X PushPinChangePinState(dpy, winInfo,
X currentAction == ACTION_SELECT);
X }
X currentAction = ACTION_NONE;
X}
X
X/*
X * eventMotionNotify - handle pointer moves
X */
Xstatic int
XeventMotionNotify(dpy, event, winInfo)
XDisplay *dpy;
XXEvent *event;
XWinPushPin *winInfo;
X{
X Bool fInWindow;
X Graphics_info *gisNormal = WinGI(winInfo,NORMAL_GINFO);
X
X if (!event->xmotion.same_screen)
X return;
X if (currentAction != ACTION_SELECT && currentAction != ACTION_ADJUST)
X return;
X
X /* When the user moves the cursor off the pushpin
X * while s/he has the button down we should pull
X * the button out. If the user moves back onto the
X * pushpin put the pin back in. So,
X *
X * if (cursor is off the pushpin) and (pin is in)
X * OR
X * (cursor is on the pushpin) and (pin is out)
X * then
X * change the state of the pushpin.
X */
X fInWindow = !((event->xmotion.x < 0) ||
X (event->xmotion.y < 0) ||
X (event->xmotion.x >= PushPinOut_Width(gisNormal)) ||
X (event->xmotion.y >= PushPinOut_Height(gisNormal)));
X locallyChangePushPinState(dpy, winInfo,
X fInWindow?pushpinStateAfterPress:!pushpinStateAfterPress);
X}
X
X
X/*
X * drawPushPin -- draw the pushpin window
X */
X/*ARGSUSED*/
Xstatic int
XdrawPushPin(dpy, winInfo)
XDisplay *dpy;
XWinPushPin *winInfo;
X{
X Client *cli = winInfo->core.client;
X Graphics_info *gis;
X int focusLines = (GRV.FocusFollowsMouse ? 1 : 0) ^
X (GRV.InvertFocusHighlighting ? 1 : 0);
X
X if (cli->isFocus)
X gis = WinGI(winInfo, INPUTFOCUS_GINFO);
X else gis = WinGI(winInfo,NORMAL_GINFO);
X /* If the titlebar is in reverse video we need to
X * draw the pushpin in reverse video also.
X */
X if (Win3D(winInfo)) {
X /*
X * REMIND
X * We need to erase the background here to BG2. We can't use
X * OLGX_ERASE because olgx erases only in BG1. So, we draw an
X * filled, invoked box that is just larger than the pin
X * window, so that the border doesn't show.
X */
X
X olgx_draw_box(gis, winInfo->core.self, -1, -1,
X winInfo->core.width+2,
X winInfo->core.height+2,
X ((cli->isFocus) && !focusLines) ?
X OLGX_INVOKED : OLGX_NORMAL,
X True);
X } else {
X GC gc;
X
X if (cli->isFocus && !focusLines) {
X gc = WinGC(winInfo, FOREGROUND_GC);
X gis = WinGI(winInfo, REVPIN_GINFO);
X } else {
X gc = WinGC(winInfo, WINDOW_GC);
X }
X XFillRectangle(dpy, winInfo->core.self, gc, 0, 0,
X winInfo->core.width, winInfo->core.height);
X }
X if (winInfo->core.client->isBusy)
X {
X XFillRectangle(dpy, winInfo->core.self, WinGC(winInfo,BUSY_GC),
X 0, 0, winInfo->core.width, winInfo->core.height);
X }
X olgx_draw_pushpin(gis, winInfo->core.self, 0, 0,
X ((winInfo->pushpinin) ? OLGX_PUSHPIN_IN : OLGX_PUSHPIN_OUT));
X}
X
X
X/*
X * DestroyPushPin -- destroy the pushpin window resources and free any allocated
X * data.
X */
Xstatic int
XdestroyPushPin(dpy, winInfo)
XDisplay *dpy;
XWinPushPin *winInfo;
X{
X /* free our data and throw away window */
X DestroyWindow(winInfo);
X MemFree(winInfo);
X}
X
X/*
X * focusselectPushPin - the focus or selection state has changed
X */
Xstatic int
XfocusselectPushPin(dpy, winInfo, selected)
XDisplay *dpy;
XWinPushPin *winInfo;
XBool selected;
X{
X (WinFunc(winInfo,core.drawfunc))(dpy, winInfo);
X}
X
X/*
X * heightfuncPushPin - recomputes the correct height of the window
X */
Xstatic int
XheightfuncPushPin(win, pxcre)
XWinPushPin *win;
XXConfigureRequestEvent *pxcre;
X{
X return PushPinOut_Width(WinGI(win,NORMAL_GINFO));
X}
X
X/*
X * widthfuncPushPin - recomputes the correct width of the window
X */
Xstatic int
XwidthfuncPushPin(win, pxcre)
XWinPushPin *win;
XXConfigureRequestEvent *pxcre;
X{
X return PushPinOut_Height(WinGI(win,NORMAL_GINFO));
X}
X
X/***************************************************************************
X* global functions
X***************************************************************************/
X
X/*
X * MakePushPin -- create the pushpin window. Return a WinGeneric structure.
X */
XWinPushPin *
XMakePushPin(dpy, par, pane, x, y)
XDisplay *dpy;
XWinGeneric *par;
XWindow pane;
Xint x,y;
X{
X WinPushPin *w;
X Window win;
X unsigned long valuemask;
X XSetWindowAttributes attributes;
X Graphics_info *gisNormal = WinGI(par,NORMAL_GINFO);
X
X attributes.event_mask = ButtonMotionMask | ButtonReleaseMask |
X ButtonPressMask | ExposureMask;
X attributes.win_gravity = NorthWestGravity;
X valuemask = CWEventMask | CWWinGravity;
X
X win = XCreateWindow(dpy, par->core.self,
X x, y,
X PushPinOut_Width(gisNormal),
X PushPinOut_Height(gisNormal),
X 0,
X CopyFromParent,
X CopyFromParent,
X CopyFromParent,
X valuemask,
X &attributes);
X
X /* create the associated structure */
X w = MemNew(WinPushPin);
X w->core.self = win;
X w->class = &classPushPin;
X w->core.kind = WIN_PUSHPIN;
X WinAddChild(par,w);
X w->core.children = NULL;
X w->core.client = par->core.client;
X w->core.x = x;
X w->core.y = y;
X w->core.width = PushPinOut_Width(gisNormal);
X w->core.height = PushPinOut_Height(gisNormal);
X w->core.dirtyconfig = CWX | CWY | CWWidth | CWHeight;
X w->core.exposures = NULL;
X w->core.helpstring = "olwm:PushPin";
X
X /* Determine initial state of push pin. */
X w->pushpinin =
X (par->core.client->wmDecors->pushpin_initial_state == PIN_IN);
X
X /* Register the push-pin state. */
X XChangeProperty(dpy, pane,
X AtomPushpinState,
X XA_INTEGER, 32,
X PropModeReplace,
X (unsigned char *)&(w->pushpinin), 1);
X
X /* register the window */
X WIInstallInfo(w);
X
X MapRaised(w);
X
X return w;
X}
X
Xvoid
XPushPinInit(dpy)
XDisplay *dpy;
X{
X classPushPin.core.kind = WIN_PUSHPIN;
X classPushPin.core.xevents[Expose] = WinEventExpose;
X classPushPin.core.xevents[ButtonPress] = eventButtonPress;
X classPushPin.core.xevents[ButtonRelease] = eventButtonRelease;
X classPushPin.core.xevents[MotionNotify] = eventMotionNotify;
X classPushPin.core.focusfunc = focusselectPushPin;
X classPushPin.core.drawfunc = drawPushPin;
X classPushPin.core.destroyfunc = destroyPushPin;
X classPushPin.core.selectfunc = focusselectPushPin;
X classPushPin.core.newconfigfunc = WinNewConfigFunc;
X classPushPin.core.newposfunc = WinNewPosFunc;
X classPushPin.core.setconfigfunc = WinSetConfigFunc;
X classPushPin.core.createcallback = NULL;
X classPushPin.core.heightfunc = heightfuncPushPin;
X classPushPin.core.widthfunc = widthfuncPushPin;
X}
X
X
X/*
X * Permanently change the push pin state.
X */
Xvoid
XPushPinChangePinState(dpy, winInfo, sendDelete)
X Display *dpy;
X WinPushPin *winInfo;
X Bool sendDelete;
X{
X Client *cli = winInfo->core.client;
X
X (WinFunc(winInfo,core.drawfunc))(dpy, winInfo);
X
X /* Tell the client that the state of its push-pin has changed. */
X XChangeProperty(dpy, PANEWINOFCLIENT(cli),
X AtomPushpinState,
X XA_INTEGER, 32,
X PropModeReplace,
X (unsigned char *)&(winInfo->pushpinin), 1);
X
X if (!winInfo->pushpinin && sendDelete)
X ClientKill(winInfo->core.client,False);
X}
X
X/*
X * Sets the pin state to a new state (if different that current state)
X */
Xvoid
XPushPinSetPinState(dpy,winInfo,newState,sendDelete)
X Display *dpy;
X WinPushPin *winInfo;
X int newState;
X Bool sendDelete;
X{
X if (newState == winInfo->pushpinin)
X return;
X
X winInfo->pushpinin = newState;
X PushPinChangePinState(dpy,winInfo,sendDelete);
X}
X
X/*
X * Toggles the pin state
X */
Xvoid
XPushPinTogglePinState(dpy,winInfo,sendDelete)
X Display *dpy;
X WinPushPin *winInfo;
X Bool sendDelete;
X{
X winInfo->pushpinin = !winInfo->pushpinin;
X PushPinChangePinState(dpy,winInfo,sendDelete);
X}
END_OF_FILE
if test 10989 -ne `wc -c <'winpush.c'`; then
echo shar: \"'winpush.c'\" unpacked with wrong size!
fi
# end of 'winpush.c'
fi
echo shar: End of archive 7 \(of 21\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 21 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Molecular Simulations, Inc. mail: dcmartin@postgres.berkeley.edu
796 N. Pastoria Avenue uucp: uwvax!ucbvax!dcmartin
Sunnyvale, California 94086 at&t: 408/522-9236