toml@marvin.Solbourne.COM (Tom LaStrange) (08/30/90)
Submitted-by: toml@marvin.Solbourne.COM (Tom LaStrange) Posting-number: Volume 9, Issue 10 Archive-name: tvtwm/part09 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting test in a file # 3. Execute the file with /bin/sh (not csh) to create the files: # #events.c # # Created by toml () on Wed Aug 29 08:43:43 MDT 1990 # if test -f 'events.c' then echo shar: will not over-write existing file "events.c" else echo extracting "events.c" sed 's/^X//' >events.c <<'SHAR_EOF' X/*****************************************************************************/ X/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ X/** Salt Lake City, Utah **/ X/** Portions Copyright 1989 by the Massachusetts Institute of Technology **/ X/** Cambridge, Massachusetts **/ X/** **/ X/** All Rights Reserved **/ X/** **/ X/** Permission to use, copy, modify, and distribute this software and **/ X/** its documentation for any purpose and without fee is hereby **/ X/** granted, provided that the above copyright notice appear in all **/ X/** copies and that both that copyright notice and this permis- **/ X/** sion notice appear in supporting documentation, and that the **/ X/** names of Evans & Sutherland and M.I.T. not be used in advertising **/ X/** in publicity pertaining to distribution of the software without **/ X/** specific, written prior permission. **/ X/** **/ X/** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/ X/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ X/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/ X/** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ X/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ X/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ X/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ X/** OR PERFORMANCE OF THIS SOFTWARE. **/ X/*****************************************************************************/ X X X/*********************************************************************** X * X * $XConsortium: events.c,v 1.148 90/03/22 18:52:48 jim Exp $ X * X * twm event handling X * X * 17-Nov-87 Thomas E. LaStrange File created X * X ***********************************************************************/ X X#if !defined(lint) && !defined(SABER) Xstatic char RCSinfo[]= X"$XConsortium: events.c,v 1.148 90/03/22 18:52:48 jim Exp $"; X#endif X X#include <stdio.h> X#include "twm.h" X#include <X11/Xatom.h> X#include "add_window.h" X#include "menus.h" X#include "events.h" X#include "resize.h" X#include "parse.h" X#include "gram.h" X#include "util.h" X#include "screen.h" X#include "iconmgr.h" X#include "version.h" X#include "vdt.h" X Xextern int iconifybox_width, iconifybox_height; Xextern unsigned int mods_used; X X#define MAX_X_EVENT 256 Xevent_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */ Xchar *Action; Xint Context = C_NO_CONTEXT; /* current button press context */ XTwmWindow *ButtonWindow; /* button press window structure */ XXEvent ButtonEvent; /* button press event */ XXEvent Event; /* the current event */ XTwmWindow *Tmp_win; /* the current twm window */ X XWindow DragWindow; /* variables used in moving windows */ XWindow DragVirtual; /* variables used in moving windows */ Xint origDragX; Xint origDragY; Xint DragX; Xint DragY; Xint DragWidth; Xint DragHeight; Xint CurrentDragX; Xint CurrentDragY; X Xint FromVirtualDesktop = False; X Xstatic int enter_flag; Xstatic int ColortableThrashing; Xstatic TwmWindow *enter_win, *raise_win; X XScreenInfo *FindScreenInfo(); Xint ButtonPressed = -1; Xint Cancel = FALSE; X Xvoid HandleCreateNotify(); Xvoid HandleReparentNotify(); X X#ifdef SHAPE Xvoid HandleShapeNotify (); Xextern int ShapeEventBase, ShapeErrorBase; X#endif X Xvoid AutoRaiseWindow (tmp) X TwmWindow *tmp; X{ X RaiseFrame(tmp); X XSync (dpy, 0); X enter_win = NULL; X enter_flag = TRUE; X raise_win = tmp; X} X Xvoid SetRaiseWindow (tmp) X TwmWindow *tmp; X{ X enter_flag = TRUE; X enter_win = NULL; X raise_win = tmp; X XSync (dpy, 0); X} X X X/*********************************************************************** X * X * Procedure: X * InitEvents - initialize the event jump table X * X *********************************************************************** X */ X Xvoid XInitEvents() X{ X int i; X X X ResizeWindow = NULL; X DragWindow = NULL; X enter_flag = FALSE; X enter_win = raise_win = NULL; X X for (i = 0; i < MAX_X_EVENT; i++) X EventHandler[i] = HandleUnknown; X X EventHandler[Expose] = HandleExpose; X EventHandler[CreateNotify] = HandleCreateNotify; X EventHandler[ReparentNotify] = HandleReparentNotify; X EventHandler[DestroyNotify] = HandleDestroyNotify; X EventHandler[MapRequest] = HandleMapRequest; X EventHandler[MapNotify] = HandleMapNotify; X EventHandler[UnmapNotify] = HandleUnmapNotify; X EventHandler[MotionNotify] = HandleMotionNotify; X EventHandler[ButtonRelease] = HandleButtonRelease; X EventHandler[ButtonPress] = HandleButtonPress; X EventHandler[EnterNotify] = HandleEnterNotify; X EventHandler[LeaveNotify] = HandleLeaveNotify; X EventHandler[ConfigureRequest] = HandleConfigureRequest; X EventHandler[ClientMessage] = HandleClientMessage; X EventHandler[PropertyNotify] = HandlePropertyNotify; X EventHandler[KeyPress] = HandleKeyPress; X EventHandler[ColormapNotify] = HandleColormapNotify; X EventHandler[VisibilityNotify] = HandleVisibilityNotify; X#ifdef SHAPE X if (HasShape) X EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify; X#endif X} X X XTime lastTimestamp = CurrentTime; /* until Xlib does this for us */ X XBool StashEventTime (ev) X register XEvent *ev; X{ X switch (ev->type) { X case KeyPress: X case KeyRelease: X lastTimestamp = ev->xkey.time; X return True; X case ButtonPress: X case ButtonRelease: X lastTimestamp = ev->xbutton.time; X return True; X case MotionNotify: X lastTimestamp = ev->xmotion.time; X return True; X case EnterNotify: X case LeaveNotify: X lastTimestamp = ev->xcrossing.time; X return True; X case PropertyNotify: X lastTimestamp = ev->xproperty.time; X return True; X case SelectionClear: X lastTimestamp = ev->xselectionclear.time; X return True; X case SelectionRequest: X lastTimestamp = ev->xselectionrequest.time; X return True; X case SelectionNotify: X lastTimestamp = ev->xselection.time; X return True; X } X return False; X} X X X/* X * WindowOfEvent - return the window about which this event is concerned; this X * window may not be the same as XEvent.xany.window (the first window listed X * in the structure). X */ XWindow WindowOfEvent (e) X XEvent *e; X{ X /* X * Each window subfield is marked with whether or not it is the same as X * XEvent.xany.window or is different (which is the case for some of the X * notify events). X */ X switch (e->type) { X case KeyPress: X case KeyRelease: return e->xkey.window; /* same */ X case ButtonPress: X case ButtonRelease: return e->xbutton.window; /* same */ X case MotionNotify: return e->xmotion.window; /* same */ X case EnterNotify: X case LeaveNotify: return e->xcrossing.window; /* same */ X case FocusIn: X case FocusOut: return e->xfocus.window; /* same */ X case KeymapNotify: return e->xkeymap.window; /* same */ X case Expose: return e->xexpose.window; /* same */ X case GraphicsExpose: return e->xgraphicsexpose.drawable; /* same */ X case NoExpose: return e->xnoexpose.drawable; /* same */ X case VisibilityNotify: return e->xvisibility.window; /* same */ X case CreateNotify: return e->xcreatewindow.window; /* DIFF */ X case DestroyNotify: return e->xdestroywindow.window; /* DIFF */ X case UnmapNotify: return e->xunmap.window; /* DIFF */ X case MapNotify: return e->xmap.window; /* DIFF */ X case MapRequest: return e->xmaprequest.window; /* DIFF */ X case ReparentNotify: return e->xreparent.window; /* DIFF */ X case ConfigureNotify: return e->xconfigure.window; /* DIFF */ X case ConfigureRequest: return e->xconfigurerequest.window; /* DIFF */ X case GravityNotify: return e->xgravity.window; /* DIFF */ X case ResizeRequest: return e->xresizerequest.window; /* same */ X case CirculateNotify: return e->xcirculate.window; /* DIFF */ X case CirculateRequest: return e->xcirculaterequest.window; /* DIFF */ X case PropertyNotify: return e->xproperty.window; /* same */ X case SelectionClear: return e->xselectionclear.window; /* same */ X case SelectionRequest: return e->xselectionrequest.requestor; /* DIFF */ X case SelectionNotify: return e->xselection.requestor; /* same */ X case ColormapNotify: return e->xcolormap.window; /* same */ X case ClientMessage: return e->xclient.window; /* same */ X case MappingNotify: return None; X } X return None; X} X X/*********************************************************************** X * X * Procedure: X * DispatchEvent - handle a single X event stored in global var Event X * X *********************************************************************** X */ XBool DispatchEvent () X{ X Window w = Event.xany.window; X StashEventTime (&Event); X X if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT) X Tmp_win = NULL; X X if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) { X Scr = FindScreenInfo (WindowOfEvent (&Event)); X } X X if (!Scr) return False; X X if (Event.type >= 0 && Event.type < MAX_X_EVENT) { X (*EventHandler[Event.type])(); X } X X return True; X} X X X/*********************************************************************** X * X * Procedure: X * HandleEvents - handle X events X * X *********************************************************************** X */ X Xvoid XHandleEvents() X{ X while (TRUE) X { X if (ResizeWindow && !XPending(dpy) ) X { X Event.xany.window = ResizeWindow; X XQueryPointer( dpy, Event.xany.window, X &(Event.xmotion.root), &JunkChild, X &(Event.xmotion.x_root), &(Event.xmotion.y_root), X &(Event.xmotion.x), &(Event.xmotion.y), X &JunkMask); X XFindContext(dpy, Event.xany.window, ScreenContext, (caddr_t *)&Scr); X X (*EventHandler[MotionNotify])(); X } X else X { X if (enter_flag && !QLength(dpy)) { X if (enter_win && enter_win != raise_win) { X AutoRaiseWindow (enter_win); /* sets enter_flag T */ X } else { X enter_flag = FALSE; X } X } X if (ColortableThrashing && !QLength(dpy) && Scr) { X InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); X } X WindowMoved = FALSE; X XNextEvent(dpy, &Event); X (void) DispatchEvent (); X } X } X} X X X/*********************************************************************** X * X * Procedure: X * HandleColormapNotify - colormap notify event handler X * X * This procedure handles both a client changing its own colormap, and X * a client explicitly installing its colormap itself (only the window X * manager should do that, so we must set it correctly). X * X *********************************************************************** X */ X Xvoid XHandleColormapNotify() X{ X XColormapEvent *cevent = (XColormapEvent *) &Event; X ColormapWindow *cwin, **cwins; X TwmColormap *cmap; X int i, j, n, number_cwins; X extern TwmColormap *CreateTwmColormap(); X X if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT) X return; X cmap = cwin->colormap; X X if (cevent->new) X { X if (XFindContext(dpy, cevent->colormap, ColormapContext, X (caddr_t *)&cwin->colormap) == XCNOENT) X cwin->colormap = CreateTwmColormap(cevent->colormap); X else X cwin->colormap->refcnt++; X X cmap->refcnt--; X X if (cevent->state == ColormapUninstalled) X cmap->state &= ~CM_INSTALLED; X else X cmap->state |= CM_INSTALLED; X X if (cmap->state & CM_INSTALLABLE) X InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); X X if (cmap->refcnt == 0) X { X XDeleteContext(dpy, cmap->c, ColormapContext); X free((char *) cmap); X } X X return; X } X X if (cevent->state == ColormapUninstalled && X (cmap->state & CM_INSTALLABLE)) X { X if (!(cmap->state & CM_INSTALLED)) X return; X cmap->state &= ~CM_INSTALLED; X X if (!ColortableThrashing) X { X ColortableThrashing = TRUE; X XSync(dpy, 0); X } X X if (cevent->serial >= Scr->cmapInfo.first_req) X { X number_cwins = Scr->cmapInfo.cmaps->number_cwins; X X /* X * Find out which colortables collided. X */ X X cwins = Scr->cmapInfo.cmaps->cwins; X for (i = j = -1, n = 0; X (i == -1 || j == -1) && n < number_cwins; X n++) X { X if (i == -1 && cwins[n] == cwin) X { X i = n; X continue; X } X X if (j == -1 && X cwins[n]->colormap->install_req == cevent->serial) X { X j = n; X continue; /* for symetry and later added code */ X } X } X X /* need if test in case client was fooling arround w/ X * XInstallColormap() or XUninstallColormap() X */ X if (i != -1 && j != -1) X { X /* lower diagonal index calculation */ X if (i > j) X n = i*(i-1)/2 + j; X else X n = j*(j-1)/2 + i; X Scr->cmapInfo.cmaps->scoreboard[n] = 1; X } else { X InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL); X } X } X } X X else if (cevent->state == ColormapUninstalled) X cmap->state &= ~CM_INSTALLED; X X else if (cevent->state == ColormapInstalled) X cmap->state |= CM_INSTALLED; X} X X/*********************************************************************** X * X * Procedure: X * HandleVisibilityNotify - visibility notify event handler X * X * This routine keeps track of visibility events so that colormap X * installation can keep the maximum number of useful colormaps X * installed at one time. X * X *********************************************************************** X */ X Xvoid XHandleVisibilityNotify() X{ X XVisibilityEvent *vevent = (XVisibilityEvent *) &Event; X ColormapWindow *cwin; X TwmColormap *cmap; X X if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT) X return; X X /* X * when Saber complains about retreiving an <int> from an <unsigned int> X * just type "touch vevent->state" and "cont" X */ X cmap = cwin->colormap; X if ((cmap->state & CM_INSTALLABLE) && X vevent->state != cwin->visibility && X (vevent->state == VisibilityFullyObscured || X cwin->visibility == VisibilityFullyObscured) && X cmap->w == cwin->w) { X cwin->visibility = vevent->state; X InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL); X } else X cwin->visibility = vevent->state; X} X X/*********************************************************************** X * X * Procedure: X * HandleKeyPress - key press event handler X * X *********************************************************************** X */ X Xvoid XHandleKeyPress() X{ X FuncKey *key; X int len; X unsigned int modifier; X X if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow); X Context = C_NO_CONTEXT; X X if (Event.xany.window == Scr->Root) X Context = C_ROOT; X if (Tmp_win) X { X if (Event.xany.window == Tmp_win->title_w) X Context = C_TITLE; X if (Event.xany.window == Tmp_win->w || X Event.xany.window == Tmp_win->virtualWindow) X Context = C_WINDOW; X if (Event.xany.window == Tmp_win->icon_w || X Event.xany.window == Tmp_win->virtualIcon) X Context = C_ICON; X if (Event.xany.window == Tmp_win->frame) X Context = C_FRAME; X if (Tmp_win->list && Event.xany.window == Tmp_win->list->w) X Context = C_ICONMGR; X if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon) X Context = C_ICONMGR; X } X X modifier = (Event.xkey.state & mods_used); X for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next) X { X if (key->keycode == Event.xkey.keycode && X key->mods == modifier && X (key->cont == Context || key->cont == C_NAME)) X { X /* weed out the functions that don't make sense to execute X * from a key press X */ X if (key->func == F_MOVE || key->func == F_RESIZE) X return; X X if (key->cont != C_NAME) X { X ExecuteFunction(key->func, key->action, Event.xany.window, X Tmp_win, &Event, Context, FALSE); X XUngrabPointer(dpy, CurrentTime); X return; X } X else X { X int matched = FALSE; X len = strlen(key->win_name); X X /* try and match the name first */ X for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL; X Tmp_win = Tmp_win->next) X { X if (!strncmp(key->win_name, Tmp_win->name, len)) X { X matched = TRUE; X ExecuteFunction(key->func, key->action, Tmp_win->frame, X Tmp_win, &Event, C_FRAME, FALSE); X XUngrabPointer(dpy, CurrentTime); X } X } X X /* now try the res_name */ X if (!matched) X for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL; X Tmp_win = Tmp_win->next) X { X if (!strncmp(key->win_name, Tmp_win->class.res_name, len)) X { X matched = TRUE; X ExecuteFunction(key->func, key->action, Tmp_win->frame, X Tmp_win, &Event, C_FRAME, FALSE); X XUngrabPointer(dpy, CurrentTime); X } X } X X /* now try the res_class */ X if (!matched) X for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL; X Tmp_win = Tmp_win->next) X { X if (!strncmp(key->win_name, Tmp_win->class.res_class, len)) X { X matched = TRUE; X ExecuteFunction(key->func, key->action, Tmp_win->frame, X Tmp_win, &Event, C_FRAME, FALSE); X XUngrabPointer(dpy, CurrentTime); X } X } X if (matched) X return; X } X } X } X X /* if we get here, no function key was bound to the key. Send it X * to the client if it was in a window we know about. X */ X if (Tmp_win) X { X if (Event.xany.window == Tmp_win->icon_w || X Event.xany.window == Tmp_win->virtualWindow || X Event.xany.window == Tmp_win->virtualIcon || X Event.xany.window == Tmp_win->frame || X Event.xany.window == Tmp_win->title_w || X (Tmp_win->list && (Event.xany.window == Tmp_win->list->w))) X { X Event.xkey.window = Tmp_win->w; X XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event); X } X } X X} X Xstatic void free_window_names (tmp, nukefull, nukename, nukeicon) X TwmWindow *tmp; X Bool nukefull, nukename, nukeicon; X{ X/* X * XXX - are we sure that nobody ever sets these to another constant (check X * twm windows)? X */ X if (tmp->name == tmp->full_name) nukefull = False; X if (tmp->icon_name == tmp->name) nukename = False; X X#define isokay(v) ((v) && (v) != NoName) X if (nukefull && isokay(tmp->full_name)) XFree (tmp->full_name); X if (nukename && isokay(tmp->name)) XFree (tmp->name); X if (nukeicon && isokay(tmp->icon_name)) XFree (tmp->icon_name); X#undef isokay X return; X} X Xvoid free_cwins (tmp) X TwmWindow *tmp; X{ X int i; X TwmColormap *cmap; X X if (tmp->cmaps.number_cwins) { X for (i = 0; i < tmp->cmaps.number_cwins; i++) { X if (--tmp->cmaps.cwins[i]->refcnt == 0) { X cmap = tmp->cmaps.cwins[i]->colormap; X if (--cmap->refcnt == 0) { X XDeleteContext(dpy, cmap->c, ColormapContext); X free((char *) cmap); X } X XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext); X free((char *) tmp->cmaps.cwins[i]); X } X } X free((char *) tmp->cmaps.cwins); X if (tmp->cmaps.number_cwins > 1) { X free(tmp->cmaps.scoreboard); X tmp->cmaps.scoreboard = NULL; X } X tmp->cmaps.number_cwins = 0; X } X} X X/*********************************************************************** X * X * Procedure: X * HandlePropertyNotify - property notify event handler X * X *********************************************************************** X */ X Xvoid XHandlePropertyNotify() X{ X char *prop = NULL; X Atom actual = None; X int actual_format; X unsigned long nitems, bytesafter; X unsigned long valuemask; /* mask for create windows */ X XSetWindowAttributes attributes; /* attributes for create windows */ X Pixmap pm; X long supplied; X X /* watch for standard colormap changes */ X if (Event.xproperty.window == Scr->Root) { X XStandardColormap *maps = NULL; X int nmaps; X X switch (Event.xproperty.state) { X case PropertyNewValue: X if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, X Event.xproperty.atom)) { X /* if got one, then replace any existing entry */ X InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True); X } X return; X X case PropertyDelete: X RemoveRGBColormap (Event.xproperty.atom); X return; X } X } X X if (!Tmp_win) return; /* unknown window */ X X#define MAX_NAME_LEN 200L /* truncate to this many */ X#define MAX_ICON_NAME_LEN 200L /* ditto */ X X switch (Event.xproperty.atom) { X case XA_WM_NAME: X if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L, X MAX_NAME_LEN, False, XA_STRING, &actual, X &actual_format, &nitems, &bytesafter, X (unsigned char **) &prop) != Success || X actual == None) X return; X if (!prop) prop = NoName; X free_window_names (Tmp_win, True, True, False); X X Tmp_win->full_name = prop; X Tmp_win->name = prop; X X Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font, X Tmp_win->name, X strlen (Tmp_win->name)); X X SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y, X Tmp_win->frame_width, Tmp_win->frame_height, -1); X X if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True); X X /* X * if the icon name is NoName, set the name of the icon to be X * the same as the window X */ X if (Tmp_win->icon_name == NoName) { X Tmp_win->icon_name = Tmp_win->name; X RedoIconName(); X } X break; X X case XA_WM_ICON_NAME: X if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0, X MAX_ICON_NAME_LEN, False, XA_STRING, &actual, X &actual_format, &nitems, &bytesafter, X (unsigned char **) &prop) != Success || X actual == None) X return; X if (!prop) prop = NoName; X free_window_names (Tmp_win, False, False, True); X Tmp_win->icon_name = prop; X X RedoIconName(); X break; X X case XA_WM_HINTS: X if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints); X Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window); X X if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint)) X Tmp_win->group = Tmp_win->wmhints->window_group; X X if (!Tmp_win->forced && Tmp_win->wmhints && X Tmp_win->wmhints->flags & IconWindowHint) { X if (Tmp_win->icon_w) { X int icon_x, icon_y; X X /* X * There's already an icon window. X * Try to find out where it is; if we succeed, move the new X * window to where the old one is. X */ X if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x, X &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) { X /* X * Move the new icon window to where the old one was. X */ X XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x, X icon_y); X } X X /* X * If the window is iconic, map the new icon window. X */ X if (Tmp_win->icon) X XMapWindow(dpy, Tmp_win->wmhints->icon_window); X X /* X * Now, if the old window isn't ours, unmap it, otherwise X * just get rid of it completely. X */ X if (Tmp_win->icon_not_ours) X XUnmapWindow(dpy, Tmp_win->icon_w); X else X XDestroyWindow(dpy, Tmp_win->icon_w); X X /* X * The new icon window isn't our window, so note that fact X * so that we don't treat it as ours. X */ X Tmp_win->icon_not_ours = TRUE; X X /* X * Now make the new window the icon window for this window, X * and set it up to work as such (select for key presses X * and button presses/releases, set up the contexts for it, X * and define the cursor for it). X */ X Tmp_win->icon_w = Tmp_win->wmhints->icon_window; X XSelectInput (dpy, Tmp_win->icon_w, X KeyPressMask | ButtonPressMask | ButtonReleaseMask); X XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win); X XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr); X XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor); X if (Tmp_win->virtualIcon) { X XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x, X &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth); X ResizeVirtual(Tmp_win->virtualIcon, JunkWidth, JunkHeight); X } X } X } X X if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints && X (Tmp_win->wmhints->flags & IconPixmapHint)) { X if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot, X &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width, X (unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) { X return; X } X X pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width, X Tmp_win->icon_height, Scr->d_depth); X X FB(Tmp_win->iconc.fore, Tmp_win->iconc.back); X XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, X Scr->NormalGC, X 0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 ); X X valuemask = CWBackPixmap; X attributes.background_pixmap = pm; X X if (Tmp_win->icon_bm_w) X XDestroyWindow(dpy, Tmp_win->icon_bm_w); X X Tmp_win->icon_bm_w = X XCreateWindow (dpy, Tmp_win->icon_w, 0, 0, X (unsigned int) Tmp_win->icon_width, X (unsigned int) Tmp_win->icon_height, X (unsigned int) 0, Scr->d_depth, X (unsigned int) CopyFromParent, Scr->d_visual, X valuemask, &attributes); X X XFreePixmap (dpy, pm); X RedoIconName(); X } X break; X X case XA_WM_NORMAL_HINTS: X if (XGetWMNormalHints (dpy, Tmp_win->w, &Tmp_win->hints, &supplied) && X !(supplied & PWinGravity)) X SimulateWinGravity (Tmp_win); X break; X X default: X if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) { X FetchWmColormapWindows (Tmp_win); /* frees old data */ X break; X } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) { X FetchWmProtocols (Tmp_win); X break; X } X break; X } X} X X/*********************************************************************** X * X * Procedure: X * RedoIconName - procedure to re-position the icon window and name X * X *********************************************************************** X */ X XRedoIconName() X{ X int x, y; X X if (Tmp_win->list) X { X /* let the expose event cause the repaint */ X XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True); X X if (Scr->SortIconMgr) X SortIconManager(Tmp_win->list->iconmgr); X } X X if (Tmp_win->icon_w == NULL) X return; X X if (Tmp_win->icon_not_ours) X return; X X Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font, X Tmp_win->icon_name, strlen(Tmp_win->icon_name)); X X Tmp_win->icon_w_width += 6; X if (Tmp_win->icon_w_width < Tmp_win->icon_width) X { X Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2; X Tmp_win->icon_x += 3; X Tmp_win->icon_w_width = Tmp_win->icon_width; X } X else X { X Tmp_win->icon_x = 3; X } X X if (Tmp_win->icon_w_width == Tmp_win->icon_width) X x = 0; X else X x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2; X X y = 0; X X Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4; X Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height; X X XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width, X Tmp_win->icon_w_height); X ResizeVirtual(Tmp_win->virtualIcon, Tmp_win->icon_w_width, Tmp_win->icon_w_height); X if (Tmp_win->icon_bm_w) X { X XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y); X XMapWindow(dpy, Tmp_win->icon_bm_w); X } X if (Tmp_win->icon) X { X XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True); X } X} X X/*********************************************************************** X * X * Procedure: X * HandleClientMessage - client message event handler X * X *********************************************************************** X */ X Xvoid XHandleClientMessage() X{ X if (Event.xclient.message_type == _XA_WM_CHANGE_STATE) X { X if (Tmp_win != NULL) X { X if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon) X { X XEvent button; X X XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild, X &(button.xmotion.x_root), X &(button.xmotion.y_root), X &JunkX, &JunkY, &JunkMask); X X ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window, X Tmp_win, &button, FRAME, FALSE); X XUngrabPointer(dpy, CurrentTime); X } X } X } X} X X X/*********************************************************************** X * X * Procedure: X * HandleExpose - expose event handler X * X *********************************************************************** X */ X Xvoid XHandleExpose() X{ X MenuRoot *tmp; X static void flush_expose(); X X if (Event.xany.window == Scr->Panner) X { X HandlePannerExpose(&Event); X return; X } X X if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0) X { X PaintMenu(tmp, &Event); X return; X } X X if (Event.xexpose.count != 0) X return; X X if (Event.xany.window == Scr->InfoWindow && InfoLines) X { X int i; X int height; X X FBF(Scr->DefaultC.fore, Scr->DefaultC.back, X Scr->DefaultFont.font->fid); X X height = Scr->DefaultFont.height+2; X for (i = 0; i < InfoLines; i++) X { X XDrawString(dpy, Scr->InfoWindow, Scr->NormalGC, X 5, (i*height) + Scr->DefaultFont.y, Info[i], strlen(Info[i])); X } X flush_expose (Event.xany.window); X } X else if (Tmp_win != NULL) X { X if (Event.xany.window == Tmp_win->title_w) X { X FBF(Tmp_win->title.fore, Tmp_win->title.back, X Scr->TitleBarFont.font->fid); X X XDrawString (dpy, Tmp_win->title_w, Scr->NormalGC, X Scr->TBInfo.titlex, Scr->TitleBarFont.y, X Tmp_win->name, strlen(Tmp_win->name)); X flush_expose (Event.xany.window); X } X else if (Event.xany.window == Tmp_win->icon_w) X { X FBF(Tmp_win->iconc.fore, Tmp_win->iconc.back, X Scr->IconFont.font->fid); X X XDrawString (dpy, Tmp_win->icon_w, X Scr->NormalGC, X Tmp_win->icon_x, Tmp_win->icon_y, X Tmp_win->icon_name, strlen(Tmp_win->icon_name)); X flush_expose (Event.xany.window); X return; X } else if (Tmp_win->titlebuttons) { X int i; X Window w = Event.xany.window; X register TBWindow *tbw; X int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; X X for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) { X if (w == tbw->window) { X register TitleButton *tb = tbw->info; X X FB(Tmp_win->title.fore, Tmp_win->title.back); X XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC, X tb->srcx, tb->srcy, tb->width, tb->height, X tb->dstx, tb->dsty, 1); X flush_expose (w); X return; X } X } X } X if (Tmp_win->list) { X if (Event.xany.window == Tmp_win->list->w) X { X FBF(Tmp_win->list->fore, Tmp_win->list->back, X Scr->IconManagerFont.font->fid); X XDrawString (dpy, Event.xany.window, Scr->NormalGC, X iconmgr_textx, Scr->IconManagerFont.y+4, X Tmp_win->icon_name, strlen(Tmp_win->icon_name)); X DrawIconManagerBorder(Tmp_win->list); X flush_expose (Event.xany.window); X return; X } X if (Event.xany.window == Tmp_win->list->icon) X { X FB(Tmp_win->list->fore, Tmp_win->list->back); X XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon, X Scr->NormalGC, X 0,0, iconifybox_width, iconifybox_height, 0, 0, 1); X flush_expose (Event.xany.window); X return; X } X } X } X} X Xstatic void remove_window_from_ring (tmp) X TwmWindow *tmp; X{ X TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next; X X if (enter_win == tmp) { X enter_flag = FALSE; X enter_win = NULL; X } X if (raise_win == Tmp_win) raise_win = NULL; X X /* X * 1. Unlink window X * 2. If window was only thing in ring, null out ring X * 3. If window was ring leader, set to next (or null) X */ X if (prev) prev->ring.next = next; X if (next) next->ring.prev = prev; X if (Scr->Ring == tmp) X Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL); X X if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring; X} X X/*********************************************************************** X * X * Procedure: X * HandleDestroyNotify - DestroyNotify event handler X * X *********************************************************************** X */ X Xvoid XHandleDestroyNotify() X{ X int i; X X /* X * Warning, this is also called by HandleUnmapNotify; if it ever needs to X * look at the event, HandleUnmapNotify will have to mash the UnmapNotify X * into a DestroyNotify. X */ X X if (Tmp_win == NULL) X return; X X if (Tmp_win == Scr->Focus) X { X FocusOnRoot(); X } X XDeleteContext(dpy, Tmp_win->w, TwmContext); X XDeleteContext(dpy, Tmp_win->w, ScreenContext); X XDeleteContext(dpy, Tmp_win->frame, TwmContext); X XDeleteContext(dpy, Tmp_win->frame, ScreenContext); X if (Tmp_win->icon_w) X { X XDeleteContext(dpy, Tmp_win->icon_w, TwmContext); X XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext); X } X if (Tmp_win->title_height) X { X int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; X XDeleteContext(dpy, Tmp_win->title_w, TwmContext); X XDeleteContext(dpy, Tmp_win->title_w, ScreenContext); X if (Tmp_win->hilite_w) X { X XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext); X XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext); X } X if (Tmp_win->titlebuttons) { X for (i = 0; i < nb; i++) { X XDeleteContext (dpy, Tmp_win->titlebuttons[i].window, X TwmContext); X XDeleteContext (dpy, Tmp_win->titlebuttons[i].window, X ScreenContext); X } X } X } X X if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps) X InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot); X X if (Tmp_win->virtualWindow) X { X XDeleteContext(dpy, Tmp_win->virtualWindow, TwmContext); X XDeleteContext(dpy, Tmp_win->virtualWindow, VirtualContext); X XDeleteContext(dpy, Tmp_win->virtualWindow, ScreenContext); X XDestroyWindow(dpy, Tmp_win->virtualWindow); X } X if (Tmp_win->virtualIcon) X { X XDeleteContext(dpy, Tmp_win->virtualIcon, TwmContext); X XDeleteContext(dpy, Tmp_win->virtualIcon, VirtualContext); X XDeleteContext(dpy, Tmp_win->virtualIcon, ScreenContext); X XDestroyWindow(dpy, Tmp_win->virtualIcon); X } X /* X * TwmWindows contain the following pointers X * X * 1. full_name X * 2. name X * 3. icon_name X * 4. wmhints X * 5. class.res_name X * 6. class.res_class X * 7. list X * 8. iconmgrp X * 9. cwins X * 10. titlebuttons X * 11. window ring X */ X if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray); X X XDestroyWindow(dpy, Tmp_win->frame); X if (Tmp_win->icon_w) { X XDestroyWindow(dpy, Tmp_win->icon_w); X IconDown (Tmp_win); X } X RemoveIconManager(Tmp_win); /* 7 */ X Tmp_win->prev->next = Tmp_win->next; X if (Tmp_win->next != NULL) X Tmp_win->next->prev = Tmp_win->prev; X if (Tmp_win->auto_raise) Scr->NumAutoRaises--; X X free_window_names (Tmp_win, True, True, True); /* 1, 2, 3 */ X if (Tmp_win->wmhints) /* 4 */ X XFree ((char *)Tmp_win->wmhints); X if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName) /* 5 */ X XFree ((char *)Tmp_win->class.res_name); X if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */ X XFree ((char *)Tmp_win->class.res_class); X free_cwins (Tmp_win); /* 9 */ X if (Tmp_win->titlebuttons) /* 10 */ X free ((char *) Tmp_win->titlebuttons); X remove_window_from_ring (Tmp_win); /* 11 */ X X free((char *)Tmp_win); X} X Xvoid XHandleCreateNotify() X{ X#ifdef DEBUG_EVENTS X fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window); X fflush(stderr); X XBell(dpy, 0); X XSync(dpy, 0); X#endif X X /* OI clients will actually create windows on the virtual desktop window, X * we need to save these just in case we get killed without being able X * to clean things up X */ X if (Event.xcreatewindow.parent == Scr->VirtualDesktop) X XAddToSaveSet(dpy, Event.xcreatewindow.window); X X} X Xvoid XHandleReparentNotify() X{ X /* OI clients will actually create windows on the virtual desktop window, X * we need to save these just in case we get killed without being able X * to clean things up X */ X if (Event.xreparent.event == Scr->VirtualDesktop) { X if (Event.xreparent.parent == Scr->VirtualDesktop) X XAddToSaveSet(dpy, Event.xreparent.window); X else X XRemoveFromSaveSet(dpy, Event.xreparent.window); X } X} X X X/*********************************************************************** X * X * Procedure: X * HandleMapRequest - MapRequest event handler X * X *********************************************************************** X */ X Xvoid XHandleMapRequest() X{ X int stat; X int zoom_save; X Window parent; X X parent = Event.xmaprequest.parent; X Event.xany.window = Event.xmaprequest.window; X stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win); X if (stat == XCNOENT) X Tmp_win = NULL; X X /* If the window has never been mapped before ... */ X if (Tmp_win == NULL) X { X /* Add decorations. */ X if (parent == Scr->VirtualDesktop) X FromVirtualDesktop == True; X Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL); X FromVirtualDesktop == False; X if (Tmp_win == NULL) X return; X } X else X { X /* X * If the window has been unmapped by the client, it won't be listed X * in the icon manager. Add it again, if requested. X */ X if (Tmp_win->list == NULL) X (void) AddIconManager (Tmp_win); X } X X /* If it's not merely iconified, and we have hints, use them. */ X if ((! Tmp_win->icon) && X Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint)) X { X int state; X Window icon; X X /* use WM_STATE if enabled */ X if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) && X (state == NormalState || state == IconicState))) X state = Tmp_win->wmhints->initial_state; X X switch (state) X { X case DontCareState: X case NormalState: X case ZoomState: X case InactiveState: X MapFrame(Tmp_win); X SetMapStateProp(Tmp_win, NormalState); X SetRaiseWindow (Tmp_win); X break; X X case IconicState: X zoom_save = Scr->DoZoom; X Scr->DoZoom = FALSE; X Iconify(Tmp_win, 0, 0); X Scr->DoZoom = zoom_save; X break; X } X } X /* If no hints, or currently an icon, just "deiconify" */ X else X { X DeIconify(Tmp_win); X SetRaiseWindow (Tmp_win); X } X} X Xvoid SimulateMapRequest (w) X Window w; X{ X Event.xmaprequest.window = w; X HandleMapRequest (); X} X X X/*********************************************************************** X * X * Procedure: X * HandleMapNotify - MapNotify event handler X * X *********************************************************************** X */ X Xvoid XHandleMapNotify() X{ X if (Tmp_win == NULL) X return; X X /* X * Need to do the grab to avoid race condition of having server send X * MapNotify to client before the frame gets mapped; this is bad because X * the client would think that the window has a chance of being viewable X * when it really isn't. X */ X XGrabServer (dpy); X if (Tmp_win->icon_w) X UnmapIcon(Tmp_win); X if (Tmp_win->title_w) X XMapSubwindows(dpy, Tmp_win->title_w); X XMapSubwindows(dpy, Tmp_win->frame); X if (Scr->Focus != Tmp_win && Tmp_win->hilite_w) X XUnmapWindow(dpy, Tmp_win->hilite_w); X X MapFrame(Tmp_win); X XUngrabServer (dpy); X XFlush (dpy); X Tmp_win->mapped = TRUE; X Tmp_win->icon = FALSE; X Tmp_win->icon_on = FALSE; X} X X X X/*********************************************************************** X * X * Procedure: X * HandleUnmapNotify - UnmapNotify event handler X * X *********************************************************************** X */ X Xvoid XHandleUnmapNotify() X{ X int dstx, dsty; X Window dumwin; X X /* X * The July 27, 1988 ICCCM spec states that a client wishing to switch X * to WithdrawnState should send a synthetic UnmapNotify with the X * event field set to (pseudo-)root, in case the window is already X * unmapped (which is the case for twm for IconicState). Unfortunately, X * we looked for the TwmContext using that field, so try the window X * field also. X */ X if (Tmp_win == NULL) X { X Event.xany.window = Event.xunmap.window; X if (XFindContext(dpy, Event.xany.window, X TwmContext, (caddr_t *)&Tmp_win) == XCNOENT) X Tmp_win = NULL; X } X X if (Tmp_win == NULL || Event.xunmap.window == Tmp_win->frame || X Event.xunmap.window == Tmp_win->icon_w || X (!Tmp_win->mapped && !Tmp_win->icon)) X return; X X /* X * The program may have unmapped the client window, from either X * NormalState or IconicState. Handle the transition to WithdrawnState. X * X * We need to reparent the window back to the root (so that twm exiting X * won't cause it to get mapped) and then throw away all state (pretend X * that we've received a DestroyNotify). X */ X X XGrabServer (dpy); X if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root, X 0, 0, &dstx, &dsty, &dumwin)) { X SetMapStateProp (Tmp_win, WithdrawnState); X XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root, X dstx, dsty); X RestoreWithdrawnLocation (Tmp_win); X XRemoveFromSaveSet (dpy, Event.xunmap.window); X HandleDestroyNotify (); /* do not need to mash event before */ X } /* else window no longer exists and we'll get a destroy notify */ X XUngrabServer (dpy); X XFlush (dpy); X} X X/*********************************************************************** X * X * Procedure: X * HandleMotionNotify - MotionNotify event handler X * X *********************************************************************** X */ X Xvoid XHandleMotionNotify() X{ X if (Event.xany.window == Scr->Panner) X { X HandlePannerMotionNotify(&Event); X return; X } X if (ResizeWindow != NULL) X { X XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win); X DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win); X } X} X X/*********************************************************************** X * X * Procedure: X * HandleButtonRelease - ButtonRelease event handler X * X *********************************************************************** X */ X Xvoid XHandleButtonRelease() X{ X int xl, xr, yt, yb, w, h; X unsigned mask; X X if (Event.xany.window == Scr->Panner) X { X HandlePannerButtonRelease(&Event); X return; X } X if (DragWindow != None) X { X MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); X X XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win); X if (DragWindow == Tmp_win->frame) X { X xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw; X yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw; X w = DragWidth + 2 * Tmp_win->frame_bw; X h = DragHeight + 2 * Tmp_win->frame_bw; X } X else X { X xl = Event.xbutton.x_root - DragX - BW; X yt = Event.xbutton.y_root - DragY - BW; X w = DragWidth + 2 * BW; X h = DragHeight + 2 * BW; X } X X if (ConstMove) X { X if (ConstMoveDir == MOVE_HORIZ) X yt = ConstMoveY; X X if (ConstMoveDir == MOVE_VERT) X xl = ConstMoveX; X X if (ConstMoveDir == MOVE_NONE) X { X yt = ConstMoveY; X xl = ConstMoveX; X } X } X X if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) X { X xr = xl + w; X yb = yt + h; X X if (xl < 0) X xl = 0; X if (xr > Scr->MyDisplayWidth) X xl = Scr->MyDisplayWidth - w; X X if (yt < 0) X yt = 0; X if (yb > Scr->MyDisplayHeight) X yt = Scr->MyDisplayHeight - h; X } X X CurrentDragX = xl; X CurrentDragY = yt; X if (DragWindow == Tmp_win->frame) X SetupWindow (Tmp_win, xl, yt, X Tmp_win->frame_width, Tmp_win->frame_height, -1); X else { X XMoveWindow (dpy, DragWindow, xl, yt); X if (DragVirtual) X XMoveWindow(dpy, DragVirtual, xl/Scr->PannerScale, yt/Scr->PannerScale); X } X X if (!Scr->NoRaiseMove/* && !Scr->OpaqueMove*/) { /* opaque already did */ X XRaiseWindow(dpy, DragWindow); X if (DragVirtual) X XRaiseWindow(dpy, DragVirtual); X } X X if (!Scr->OpaqueMove) X UninstallRootColormap(); X else X XSync(dpy, 0); X X if (Scr->NumAutoRaises) { X enter_flag = TRUE; X enter_win = NULL; X raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove) X ? Tmp_win : NULL); X } X X DragWindow = NULL; X DragVirtual = NULL; X ConstMove = FALSE; X } X X if (ResizeWindow != NULL) X { X EndResize(); X } X X if (ActiveMenu != NULL && RootFunction == NULL) X { X if (ActiveItem != NULL) X { X Action = ActiveItem->action; X if (ActiveItem->func == F_MOVE || X ActiveItem->func == F_FORCEMOVE) X ButtonPressed = -1; X ExecuteFunction(ActiveItem->func, ActiveItem->action, X ButtonWindow ? ButtonWindow->frame : NULL, X ButtonWindow, &ButtonEvent, Context, TRUE); X Context = C_NO_CONTEXT; X ButtonWindow = NULL; X X /* if we are not executing a defered command, then take down the X * menu X */ X if (RootFunction == NULL) X { X PopDownMenu(); X } X } X else X PopDownMenu(); X } X X mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask); X switch (Event.xbutton.button) X { X case Button1: mask &= ~Button1Mask; break; X case Button2: mask &= ~Button2Mask; break; X case Button3: mask &= ~Button3Mask; break; X case Button4: mask &= ~Button4Mask; break; X case Button5: mask &= ~Button5Mask; break; X } X X if (RootFunction != NULL || X ResizeWindow != None || X DragWindow != None) X ButtonPressed = -1; X X if (RootFunction == NULL && X (Event.xbutton.state & mask) == 0 && X DragWindow == None && X ResizeWindow == None) X { X XUngrabPointer(dpy, CurrentTime); X XUngrabServer(dpy); X XFlush(dpy); X EventHandler[EnterNotify] = HandleEnterNotify; X EventHandler[LeaveNotify] = HandleLeaveNotify; X ButtonPressed = -1; X if (DownIconManager) X { X DownIconManager->down = FALSE; X if (Scr->Highlight) DrawIconManagerBorder(DownIconManager); X DownIconManager = NULL; X } X Cancel = FALSE; X } X} X X Xstatic do_menu (menu, w) X MenuRoot *menu; /* menu to pop up */ X Window w; /* invoking window or None */ X{ X int x = Event.xbutton.x_root; X int y = Event.xbutton.y_root; X Bool center; X X if (!Scr->NoGrabServer) X XGrabServer(dpy); X if (w) { X int h = Scr->TBInfo.width - Scr->TBInfo.border; X Window child; X X (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child); X center = False; X } else { X center = True; X } X if (PopUpMenu (menu, x, y, center)) { X UpdateMenu(); X } else { X XBell (dpy, 0); X } X} X X X/*********************************************************************** X * X * Procedure: X * HandleButtonPress - ButtonPress event handler X * X *********************************************************************** X */ Xvoid XHandleButtonPress() X{ X unsigned int modifier; X Cursor cur; X X /* pop down the menu, if any */ X if (ActiveMenu != NULL) X PopDownMenu(); X X if (InfoLines) { X XUnmapWindow(dpy, Scr->InfoWindow); X InfoLines = 0; X } X XSync(dpy, 0); /* XXX - remove? */ X X if (Event.xany.window == Scr->Panner) X { X HandlePannerButtonPress(&Event); X return; X } X X if (XFindContext (dpy, Event.xany.window, VirtualContext, (caddr_t *) &Tmp_win) != XCNOENT) X { X HandlePannerMove(&Event, Tmp_win); X return; X } X if (ButtonPressed != -1) X { X /* we got another butt press in addition to one still held X * down, we need to cancel the operation we were doing X */ X Cancel = TRUE; X CurrentDragX = origDragX; X CurrentDragY = origDragY; X if (Scr->OpaqueMove && DragWindow != None) { X XMoveWindow (dpy, DragWindow, origDragX, origDragY); X } else { X MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); X } X XUnmapWindow(dpy, Scr->SizeWindow); X if (!Scr->OpaqueMove) X UninstallRootColormap(); X ResizeWindow = None; X DragWindow = None; X cur = LeftButt; X if (Event.xbutton.button == Button2) X cur = MiddleButt; X else if (Event.xbutton.button >= Button3) X cur = RightButt; X X XGrabPointer(dpy, Scr->Root, True, X ButtonReleaseMask | ButtonPressMask, X GrabModeAsync, GrabModeAsync, X Scr->Root, cur, CurrentTime); X X return; X } X else X ButtonPressed = Event.xbutton.button; X X if (ResizeWindow != None || X DragWindow != None || X ActiveMenu != NULL) X return; X X /* check the title bar buttons */ X if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons) X { X register int i; X register TBWindow *tbw; X int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; X X for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) { X if (Event.xany.window == tbw->window) { X if (tbw->info->func == F_MENU) { X ButtonEvent = Event; X ButtonWindow = Tmp_win; X do_menu (tbw->info->menuroot, tbw->window); X } else { X ExecuteFunction (tbw->info->func, tbw->info->action, X Event.xany.window, Tmp_win, &Event, X C_TITLE, FALSE); X } X return; X } X } X } X X Context = C_NO_CONTEXT; X X if (Event.xany.window == Scr->Root) X Context = C_ROOT; X if (Tmp_win) X { X if (Tmp_win->list && RootFunction != NULL && X (Event.xany.window == Tmp_win->list->w || X Event.xany.window == Tmp_win->list->icon)) X { X Tmp_win = Tmp_win->list->iconmgr->twm_win; X XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w, X Event.xbutton.x, Event.xbutton.y, X &JunkX, &JunkY, &JunkChild); X X Event.xbutton.x = JunkX; X Event.xbutton.y = JunkY - Tmp_win->title_height; X Event.xany.window = Tmp_win->w; X Context = C_WINDOW; X } X else if (Event.xany.window == Tmp_win->title_w) X { X Context = C_TITLE; X } X else if (Event.xany.window == Tmp_win->w) X Context = C_WINDOW; X else if (Event.xany.window == Tmp_win->icon_w) X { X Context = C_ICON; X } X else if (Event.xany.window == Tmp_win->frame) X Context = C_FRAME; X else if (Tmp_win->list && X (Event.xany.window == Tmp_win->list->w || X Event.xany.window == Tmp_win->list->icon)) X { X Tmp_win->list->down = TRUE; X if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list); X DownIconManager = Tmp_win->list; X Context = C_ICONMGR; X } X } X X /* this section of code checks to see if we were in the middle of X * a command executed from a menu X */ X if (RootFunction != NULL) X { X if (Event.xany.window == Scr->Root) X { X Window child, last_child, found_child; X /* if the window was the Root, we don't know for sure it X * it was the root. We must check to see if it happened to be X * inside of a client that was getting button press events. X */ X X Tmp_win = NULL; X child = Scr->Root; X do { X last_child = child; X XTranslateCoordinates(dpy, Scr->Root, last_child, X Event.xbutton.x, Event.xbutton.y, X &JunkX, &JunkY, &child); X if (child) X if (XFindContext(dpy, child, TwmContext, (caddr_t *)&Tmp_win) != XCNOENT) X found_child = child; X } while (child != None); X X if (!Tmp_win) X { X RootFunction = NULL; X XBell(dpy, 0); X return; X } X X /* if the window was one of the small virtual windows, the user X * probably meant to move the panner X */ X if (found_child == Tmp_win->virtualWindow || X found_child == Tmp_win->virtualIcon) X { X XFindContext(dpy, Scr->Panner, TwmContext, (caddr_t *)&Tmp_win); X } X X Event.xany.window = Tmp_win->w; X XTranslateCoordinates(dpy, Scr->Root, Event.xany.window, X Event.xbutton.x, X Event.xbutton.y, X &JunkX, &JunkY, &JunkChild); X X Event.xbutton.x = JunkX; X Event.xbutton.y = JunkY; X Context = C_WINDOW; X } X X ExecuteFunction(RootFunction, Action, Event.xany.window, X Tmp_win, &Event, Context, FALSE); X X RootFunction = NULL; X return; X } X X ButtonEvent = Event; X ButtonWindow = Tmp_win; X X /* if we get to here, we have to execute a function or pop up a X * menu X */ X modifier = (Event.xbutton.state & mods_used); X X if (Context == C_NO_CONTEXT) X return; X X RootFunction = NULL; X if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU) X { X do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu, X (Window) None); X } X else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != NULL) X { X Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ? X Scr->Mouse[Event.xbutton.button][Context][modifier].item->action : NULL; X ExecuteFunction(Scr->Mouse[Event.xbutton.button][Context][modifier].func, X Action, Event.xany.window, Tmp_win, &Event, Context, FALSE); X } X else if (Scr->DefaultFunction.func != NULL) X { X if (Scr->DefaultFunction.func == F_MENU) X { X do_menu (Scr->DefaultFunction.menu, (Window) None); X } X else X { X Action = Scr->DefaultFunction.item ? X Scr->DefaultFunction.item->action : NULL; X ExecuteFunction(Scr->DefaultFunction.func, Action, X Event.xany.window, Tmp_win, &Event, Context, FALSE); X } X } X} X X X/*********************************************************************** X * X * Procedure: X * HENQueueScanner - EnterNotify event q scanner X * X * Looks at the queued events and determines if any matching X * LeaveNotify events or EnterEvents deriving from the X * termination of a grab are behind this event to allow X * skipping of unnecessary processing. X * X *********************************************************************** X */ X Xtypedef struct HENScanArgs { X Window w; /* Window we are currently entering */ X Bool leaves; /* Any LeaveNotifies found for this window */ X Bool inferior; /* Was NotifyInferior the mode for LeaveNotify */ X Bool enters; /* Any EnterNotify events with NotifyUngrab */ X} HENScanArgs; X X/* ARGSUSED*/ Xstatic Bool XHENQueueScanner(dpy, ev, args) X Display *dpy; X XEvent *ev; X char *args; X{ X if (ev->type == LeaveNotify) { X if (ev->xcrossing.window == ((HENScanArgs *) args)->w && X ev->xcrossing.mode == NotifyNormal) { X ((HENScanArgs *) args)->leaves = True; X /* X * Only the last event found matters for the Inferior field. X */ X ((HENScanArgs *) args)->inferior = X (ev->xcrossing.detail == NotifyInferior); X } X } else if (ev->type == EnterNotify) { X if (ev->xcrossing.mode == NotifyUngrab) X ((HENScanArgs *) args)->enters = True; X } X X return (False); X} X X/*********************************************************************** X * X * Procedure: X * HandleEnterNotify - EnterNotify event handler X * X *********************************************************************** X */ X Xvoid XHandleEnterNotify() X{ X MenuRoot *mr; X XEnterWindowEvent *ewp = &Event.xcrossing; X HENScanArgs scanArgs; X XEvent dummy; X X /* X * if we aren't in the middle of menu processing X */ X if (!ActiveMenu) { X /* X * We're not interested in pseudo Enter/Leave events generated X * from grab initiations. X */ X if (ewp->mode == NotifyGrab) X return; X X /* X * Scan for Leave and Enter Notify events to see if we can avoid some X * unnecessary processing. X */ X scanArgs.w = ewp->window; X scanArgs.leaves = scanArgs.enters = False; X (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs); X X /* X * if entering root window, restore twm default colormap so that X * titlebars are legible X */ X if (ewp->window == Scr->Root) { X if (!scanArgs.leaves && !scanArgs.enters) X InstallWindowColormaps(EnterNotify, &Scr->TwmRoot); X return; X } X X /* X * if we have an event for a specific one of our windows X */ X if (Tmp_win) { X /* X * If currently in PointerRoot mode (indicated by FocusRoot), then X * focus on this window X */ X if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) { X if (Tmp_win->list) ActiveIconManager(Tmp_win->list); X if (Tmp_win->mapped) { X /* X * unhighlight old focus window X */ X if (Scr->Focus && X Scr->Focus != Tmp_win && Tmp_win->hilite_w) X XUnmapWindow(dpy, Scr->Focus->hilite_w); X X /* X * If entering the frame or the icon manager, then do X * "window activation things": X * X * 1. turn on highlight window (if any) X * 2. install frame colormap X * 3. set frame and highlight window (if any) border X * 4. focus on client window to forward typing X * 5. send WM_TAKE_FOCUS if requested X */ X if (ewp->window == Tmp_win->frame || X (Tmp_win->list && ewp->window == Tmp_win->list->w)) { X if (Tmp_win->hilite_w) /* 1 */ X XMapWindow (dpy, Tmp_win->hilite_w); X if (!scanArgs.leaves && !scanArgs.enters) X InstallWindowColormaps (EnterNotify, /* 2 */ X &Scr->TwmRoot); X SetBorder (Tmp_win, True); /* 3 */ X if (Tmp_win->title_w && Scr->TitleFocus) /* 4 */ X SetFocus (Tmp_win); X if (Tmp_win->protocols & DoesWmTakeFocus) /* 5 */ X SendTakeFocusMessage (Tmp_win, ewp->time); X Scr->Focus = Tmp_win; X } else if (ewp->window == Tmp_win->w) { X /* X * If we are entering the application window, install X * its colormap(s). X */ X if (!scanArgs.leaves || scanArgs.inferior) X InstallWindowColormaps(EnterNotify, Tmp_win); X } X } /* end if Tmp_win->mapped */ X } /* end if FocusRoot */ X /* X * If this window is to be autoraised, mark it so X */ X if (Tmp_win->auto_raise) { X enter_win = Tmp_win; X if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win); X } else if (enter_flag && raise_win == Tmp_win) X enter_win = Tmp_win; X /* X * set ring leader X */ X if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win)) X Scr->RingLeader = Tmp_win; X XSync (dpy, 0); X return; X } /* end if Tmp_win */ X } /* end if !ActiveMenu */ X X /* X * Find the menu that we are dealing with now; punt if unknown X */ X if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return; X X mr->entered = TRUE; X if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == NULL) { X if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow); X XUnmapWindow (dpy, ActiveMenu->w); X ActiveMenu->mapped = UNMAPPED; X UninstallRootColormap (); X if (ActiveItem) ActiveItem->state = 0; X ActiveItem = NULL; X ActiveMenu = mr; X MenuDepth--; X } X return; X} X X X/*********************************************************************** X * X * Procedure: X * HLNQueueScanner - LeaveNotify event q scanner X * X * Looks at the queued events and determines if any X * EnterNotify events are behind this event to allow X * skipping of unnecessary processing. X * X *********************************************************************** X */ X Xtypedef struct HLNScanArgs { X Window w; /* The window getting the LeaveNotify */ X Bool enters; /* Any EnterNotify event at all */ X Bool matches; /* Any matching EnterNotify events */ X} HLNScanArgs; X X/* ARGSUSED*/ Xstatic Bool XHLNQueueScanner(dpy, ev, args) X Display *dpy; X XEvent *ev; X char *args; X{ X if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) { X ((HLNScanArgs *) args)->enters = True; X if (ev->xcrossing.window == ((HLNScanArgs *) args)->w) X ((HLNScanArgs *) args)->matches = True; X } X X return (False); X} X X/*********************************************************************** X * X * Procedure: X * HandleLeaveNotify - LeaveNotify event handler X * X *********************************************************************** X */ X Xvoid XHandleLeaveNotify() X{ X HLNScanArgs scanArgs; X XEvent dummy; X X if (Tmp_win != NULL) X { X Bool inicon; X X /* X * We're not interested in pseudo Enter/Leave events generated X * from grab initiations and terminations. X */ X if (Event.xcrossing.mode != NotifyNormal) X return; X X inicon = (Tmp_win->list && X Tmp_win->list->w == Event.xcrossing.window); X X if (Scr->RingLeader && Scr->RingLeader == Tmp_win && X (Event.xcrossing.detail != NotifyInferior && X Event.xcrossing.window != Tmp_win->w)) { X if (!inicon) { X if (Tmp_win->mapped) { X Tmp_win->ring.cursor_valid = False; X } else { X Tmp_win->ring.cursor_valid = True; X Tmp_win->ring.curs_x = (Event.xcrossing.x_root - X Tmp_win->frame_x); X Tmp_win->ring.curs_y = (Event.xcrossing.y_root - X Tmp_win->frame_y); X } X } X Scr->RingLeader = (TwmWindow *) NULL; X } X if (Scr->FocusRoot) { X X if (Event.xcrossing.detail != NotifyInferior) { X X /* X * Scan for EnterNotify events to see if we can avoid some X * unnecessary processing. X */ X scanArgs.w = Event.xcrossing.window; X scanArgs.enters = scanArgs.matches = False; X (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner, X (char *) &scanArgs); X X if ((Event.xcrossing.window == Tmp_win->frame && X !scanArgs.matches) || inicon) { X if (Tmp_win->list) NotActiveIconManager(Tmp_win->list); X if (Tmp_win->hilite_w) X XUnmapWindow (dpy, Tmp_win->hilite_w); X SetBorder (Tmp_win, False); X if (Scr->TitleFocus || X Tmp_win->protocols & DoesWmTakeFocus) X SetFocus ((TwmWindow *) NULL); X Scr->Focus = NULL; X } else if (Event.xcrossing.window == Tmp_win->w && X !scanArgs.enters) { X InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot); X } X } X } X XSync (dpy, 0); X return; X } X} X X X/*********************************************************************** X * X * Procedure: X * HandleConfigureRequest - ConfigureRequest event handler X * X *********************************************************************** X */ X Xvoid XHandleConfigureRequest() X{ X XWindowChanges xwc; X unsigned long xwcm; X int x, y, width, height, bw; X int gravx, gravy; X XConfigureRequestEvent *cre = &Event.xconfigurerequest; X X#ifdef DEBUG_EVENTS X fprintf(stderr, "ConfigureRequest\n"); X if (cre->value_mask & CWX) X fprintf(stderr, " x = %d\n", cre->x); X if (cre->value_mask & CWY) X fprintf(stderr, " y = %d\n", cre->y); X if (cre->value_mask & CWWidth) X fprintf(stderr, " width = %d\n", cre->width); X if (cre->value_mask & CWHeight) X fprintf(stderr, " height = %d\n", cre->height); X if (cre->value_mask & CWSibling) X fprintf(stderr, " above = 0x%x\n", cre->above); X if (cre->value_mask & CWStackMode) X fprintf(stderr, " stack = %d\n", cre->detail); X#endif X X /* X * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will X * be wrong X */ X Event.xany.window = cre->window; /* mash parent field */ X if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) == X XCNOENT) X Tmp_win = NULL; X X X /* X * According to the July 27, 1988 ICCCM draft, we should ignore size and X * position fields in the WM_NORMAL_HINTS property when we map a window. X * Instead, we'll read the current geometry. Therefore, we should respond X * to configuration requests for windows which have never been mapped. X */ X if (!Tmp_win) { X xwcm = cre->value_mask & X (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); X xwc.x = cre->x; X xwc.y = cre->y; X xwc.width = cre->width; X xwc.height = cre->height; X xwc.border_width = cre->border_width; X XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc); X return; X } X X if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) { X TwmWindow *otherwin; X X xwc.sibling = (((cre->value_mask & CWSibling) && X (XFindContext (dpy, cre->above, TwmContext, X (caddr_t *) &otherwin) == XCSUCCESS)) X ? otherwin->frame : cre->above); X xwc.stack_mode = cre->detail; X XConfigureWindow (dpy, Tmp_win->frame, X cre->value_mask & (CWSibling | CWStackMode), &xwc); X } X X X /* Don't modify frame_XXX fields before calling SetupWindow! */ X x = Tmp_win->frame_x; X y = Tmp_win->frame_y; X width = Tmp_win->frame_width; X height = Tmp_win->frame_height; X bw = Tmp_win->frame_bw; X X /* X * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the X * configure request are for the upper-left outer corner of the window. X * This means that we need to adjust for the additional title height as X * well as for any border width changes that we decide to allow. The X * current window gravity is to be used in computing the adjustments, just X * as when initially locating the window. Note that if we do decide to X * allow border width changes, we will need to send the synthetic X * ConfigureNotify event. X */ X GetGravityOffsets (Tmp_win, &gravx, &gravy); X X if (cre->value_mask & CWBorderWidth) { X int bwdelta = cre->border_width - Tmp_win->old_bw; /* posit growth */ X if (bwdelta && Scr->ClientBorderWidth) { /* if change allowed */ X x += gravx * bwdelta; /* change default values only */ X y += gravy * bwdelta; /* ditto */ X bw = cre->border_width; X if (Tmp_win->title_height) height += bwdelta; X x += (gravx < 0) ? bwdelta : -bwdelta; X y += (gravy < 0) ? bwdelta : -bwdelta; X } X Tmp_win->old_bw = cre->border_width; /* for restoring */ X } X X if (cre->value_mask & CWX) { /* override even if border change */ X x = cre->x - bw; X } X if (cre->value_mask & CWY) { X y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw; X } X X if (cre->value_mask & CWWidth) { X width = cre->width; X } X if (cre->value_mask & CWHeight) { X height = cre->height + Scr->TitleHeight + bw; X } X X if (width != Tmp_win->frame_width || height != Tmp_win->frame_height) X Tmp_win->zoomed = ZOOM_NONE; X X /* X * SetupWindow (x,y) are the location of the upper-left outer corner and X * are passed directly to XMoveResizeWindow (frame). The (width,height) X * are the inner size of the frame. The inner width is the same as the X * requested client window width; the inner height is the same as the X * requested client window height plus any title bar slop. X */ X SetupWindow (Tmp_win, x, y, width, height, bw); X} X X#ifdef SHAPE X/*********************************************************************** X * X * Procedure: X * HandleShapeNotify - shape notification event handler X * X *********************************************************************** X */ Xvoid XHandleShapeNotify () X{ X XShapeEvent *sev = (XShapeEvent *) &Event; X X if (Tmp_win == NULL) X return; X if (sev->kind != ShapeBounding) X return; X Tmp_win->wShaped = sev->shaped; X SetFrameShape (Tmp_win); X} X#endif X X/*********************************************************************** X * X * Procedure: X * HandleUnknown - unknown event handler X * X *********************************************************************** X */ X Xvoid XHandleUnknown() X{ X#ifdef DEBUG_EVENTS X fprintf(stderr, "type = %d\n", Event.type); X#endif X} X X/*********************************************************************** X * X * Procedure: X * Transient - checks to see if the window is a transient X * X * Returned Value: X * TRUE - window is a transient X * FALSE - window is not a transient X * X * Inputs: X * w - the window to check X * X *********************************************************************** X */ X Xint XTransient(w) X Window w; X{ X Window propw; X X return (XGetTransientForHint(dpy, w, &propw)); X} X X/*********************************************************************** X * X * Procedure: X * FindScreenInfo - get ScreenInfo struct associated with a given window X * X * Returned Value: X * ScreenInfo struct X * X * Inputs: X * w - the window X * X *********************************************************************** X */ X XScreenInfo * XFindScreenInfo(w) X Window w; X{ X XWindowAttributes attr; X int scrnum; X X attr.screen = NULL; X if (XGetWindowAttributes(dpy, w, &attr)) { X for (scrnum = 0; scrnum < NumScreens; scrnum++) { X if (ScreenList[scrnum] != NULL && X (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) == X attr.screen)) X return ScreenList[scrnum]; X } X } X X return NULL; X} X X Xstatic void flush_expose (w) X Window w; X{ X XEvent dummy; X X while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ; X} X X X/*********************************************************************** X * X * Procedure: X * InstallWindowColormaps - install the colormaps for one twm window X * X * Inputs: X * type - type of event that caused the installation X * tmp - for a subset of event types, the address of the X * window structure, whose colormaps are to be installed. X * X *********************************************************************** X */ X XInstallWindowColormaps (type, tmp) X int type; X TwmWindow *tmp; X{ X int i, j, n, number_cwins, state; X ColormapWindow **cwins, *cwin, **maxcwin = NULL; X TwmColormap *cmap; X char *row, *scoreboard; X X switch (type) { X case EnterNotify: X case LeaveNotify: X case DestroyNotify: X default: X /* Save the colormap to be loaded for when force loading of X * root colormap(s) ends. X */ X Scr->cmapInfo.pushed_window = tmp; X /* Don't load any new colormap if root colormap(s) has been X * force loaded. X */ X if (Scr->cmapInfo.root_pushes) X return; X /* Don't reload the currend window colormap list. X */ X if (Scr->cmapInfo.cmaps == &tmp->cmaps) X return; X if (Scr->cmapInfo.cmaps) X for (i = Scr->cmapInfo.cmaps->number_cwins, X cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++) X (*cwins)->colormap->state &= ~CM_INSTALLABLE; X Scr->cmapInfo.cmaps = &tmp->cmaps; X break; X X case PropertyNotify: X case VisibilityNotify: X case ColormapNotify: X break; X } X X number_cwins = Scr->cmapInfo.cmaps->number_cwins; X cwins = Scr->cmapInfo.cmaps->cwins; X scoreboard = Scr->cmapInfo.cmaps->scoreboard; X X ColortableThrashing = FALSE; /* in case installation aborted */ X X state = CM_INSTALLED; X X for (i = n = 0; i < number_cwins; i++) { X cwin = cwins[i]; X cmap = cwin->colormap; X cmap->state |= CM_INSTALLABLE; X cmap->state &= ~CM_INSTALL; X cmap->w = cwin->w; X if (cwin->visibility != VisibilityFullyObscured && X n < Scr->cmapInfo.maxCmaps) { X row = scoreboard + (i*(i-1)/2); X for (j = 0; j < i; j++) X if (row[j] && (cwins[j]->colormap->state & CM_INSTALL)) X break; X if (j != i) X continue; X n++; X maxcwin = &cwins[i]; X state &= (cmap->state & CM_INSTALLED); X cmap->state |= CM_INSTALL; X } X } X X Scr->cmapInfo.first_req = NextRequest(dpy); X X for ( ; n > 0; maxcwin--) { X cmap = (*maxcwin)->colormap; X if (cmap->state & CM_INSTALL) { X cmap->state &= ~CM_INSTALL; X if (!(state & CM_INSTALLED)) { X cmap->install_req = NextRequest(dpy); X XInstallColormap(dpy, cmap->c); X } X cmap->state |= CM_INSTALLED; X n--; X } X } X} X X/*********************************************************************** X * X * Procedures: X * <Uni/I>nstallRootColormap - Force (un)loads root colormap(s) X * X * These matching routines provide a mechanism to insure that X * the root colormap(s) is installed during operations like X * rubber banding or menu display that require colors from X * that colormap. Calls may be nested arbitrarily deeply, X * as long as there is one UninstallRootColormap call per X * InstallRootColormap call. X * X * The final UninstallRootColormap will cause the colormap list X * which would otherwise have be loaded to be loaded, unless X * Enter or Leave Notify events are queued, indicating some X * other colormap list would potentially be loaded anyway. X *********************************************************************** X */ X XInstallRootColormap() X{ X TwmWindow *tmp; X if (Scr->cmapInfo.root_pushes == 0) { X /* X * The saving and restoring of cmapInfo.pushed_window here X * is a slimy way to remember the actual pushed list and X * not that of the root window. X */ X tmp = Scr->cmapInfo.pushed_window; X InstallWindowColormaps(0, &Scr->TwmRoot); X Scr->cmapInfo.pushed_window = tmp; X } X Scr->cmapInfo.root_pushes++; X} X X X/* ARGSUSED*/ Xstatic Bool XUninstallRootColormapQScanner(dpy, ev, args) X Display *dpy; X XEvent *ev; X char *args; X{ X if (!*args) X if (ev->type == EnterNotify) { X if (ev->xcrossing.mode != NotifyGrab) X *args = 1; X } else if (ev->type == LeaveNotify) { X if (ev->xcrossing.mode == NotifyNormal) X *args = 1; X } X X return (False); X} X XUninstallRootColormap() X{ X char args; X XEvent dummy; X X if (Scr->cmapInfo.root_pushes) X Scr->cmapInfo.root_pushes--; X X if (!Scr->cmapInfo.root_pushes) { X /* X * If we have subsequent Enter or Leave Notify events, X * we can skip the reload of pushed colormaps. X */ X XSync (dpy, 0); X args = 0; X (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args); X X if (!args) X InstallWindowColormaps(0, Scr->cmapInfo.pushed_window); X } X} X X X#ifdef TRACE Xdumpevent (e) X XEvent *e; X{ X char *name = NULL; X X switch (e->type) { X case KeyPress: name = "KeyPress"; break; X case KeyRelease: name = "KeyRelease"; break; X case ButtonPress: name = "ButtonPress"; break; X case ButtonRelease: name = "ButtonRelease"; break; X case MotionNotify: name = "MotionNotify"; break; X case EnterNotify: name = "EnterNotify"; break; X case LeaveNotify: name = "LeaveNotify"; break; X case FocusIn: name = "FocusIn"; break; X case FocusOut: name = "FocusOut"; break; X case KeymapNotify: name = "KeymapNotify"; break; X case Expose: name = "Expose"; break; X case GraphicsExpose: name = "GraphicsExpose"; break; X case NoExpose: name = "NoExpose"; break; X case VisibilityNotify: name = "VisibilityNotify"; break; X case CreateNotify: name = "CreateNotify"; break; X case DestroyNotify: name = "DestroyNotify"; break; X case UnmapNotify: name = "UnmapNotify"; break; X case MapNotify: name = "MapNotify"; break; X case MapRequest: name = "MapRequest"; break; X case ReparentNotify: name = "ReparentNotify"; break; X case ConfigureNotify: name = "ConfigureNotify"; break; X case ConfigureRequest: name = "ConfigureRequest"; break; X case GravityNotify: name = "GravityNotify"; break; X case ResizeRequest: name = "ResizeRequest"; break; X case CirculateNotify: name = "CirculateNotify"; break; X case CirculateRequest: name = "CirculateRequest"; break; X case PropertyNotify: name = "PropertyNotify"; break; X case SelectionClear: name = "SelectionClear"; break; X case SelectionRequest: name = "SelectionRequest"; break; X case SelectionNotify: name = "SelectionNotify"; break; X case ColormapNotify: name = "ColormapNotify"; break; X case ClientMessage: name = "ClientMessage"; break; X case MappingNotify: name = "MappingNotify"; break; X } X X if (name) { X printf ("event: %s, %d remaining\n", name, QLength(dpy)); X } else { X printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy)); X } X} X#endif /* TRACE */ X SHAR_EOF if test 73881 -ne "`wc -c < events.c`" then echo shar: error transmitting "events.c" '(should have been 73881 characters)' fi fi # end of shell archive exit 0 dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.