/*****************************************************************************/ /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ /** Salt Lake City, Utah **/ /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/ /** Cambridge, Massachusetts **/ /** **/ /** All Rights Reserved **/ /** **/ /** Permission to use, copy, modify, and distribute this software and **/ /** its documentation for any purpose and without fee is hereby **/ /** granted, provided that the above copyright notice appear in all **/ /** copies and that both that copyright notice and this permis- **/ /** sion notice appear in supporting documentation, and that the **/ /** names of Evans & Sutherland and M.I.T. not be used in advertising **/ /** in publicity pertaining to distribution of the software without **/ /** specific, written prior permission. **/ /** **/ /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/ /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/ /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ /** OR PERFORMANCE OF THIS SOFTWARE. **/ /*****************************************************************************/ /* * [ ctwm ] * * Copyright 1992 Claude Lecommandeur. * * Permission to use, copy, modify and distribute this software [ctwm] and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting documen- * tation, and that the name of Claude Lecommandeur not be used in adverti- * sing or publicity pertaining to distribution of the software without * specific, written prior permission. Claude Lecommandeur make no represen- * tations about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. * * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ] */ /*********************************************************************** * * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $ * * twm event handling * * 17-Nov-87 Thomas E. LaStrange File created * * Do the necessary modification to be integrated in ctwm. * Can no longer be used for the standard twm. * * 22-April-92 Claude Lecommandeur. * * ***********************************************************************/ #include #include #ifndef VMS #include #endif #if defined(AIXV3) || defined(_SYSTYPE_SVR4) || defined(ibm) || defined __QNX__ #include #endif #include #include "twm.h" #ifdef VMS #include #else #include #endif #include "add_window.h" #include "clicktofocus.h" #include "menus.h" #include "events.h" #include "resize.h" #include "parse.h" #include "util.h" #include "screen.h" #include "icons.h" #include "iconmgr.h" #include "version.h" #ifdef VMS #include #include #include #define USE_SIGNALS #else #define MAX(x,y) ((x)>(y)?(x):(y)) #define MIN(x,y) ((x)<(y)?(x):(y)) #endif #define ABS(x) ((x)<0?-(x):(x)) extern int iconifybox_width, iconifybox_height; extern unsigned int mods_used; extern int menuFromFrameOrWindowOrTitlebar; extern char *CurrentSelectedWorkspace; extern int RaiseDelay; #ifdef USE_SIGNALS extern Bool AnimationPending; #else /* USE_SIGNALS */ extern struct timeval AnimateTimeout; #endif /* USE_SIGNALS */ extern int AnimationSpeed; extern Bool AnimationActive; extern Bool MaybeAnimate; extern int AlternateKeymap; extern Bool AlternateContext; static void CtwmNextEvent (Display *display, XEvent *event); static void RedoIcon(void); static void do_key_menu (MenuRoot *menu, /* menu to pop up */ Window w); /* invoking window or None */ void RedoIconName(void); extern void twmrc_error_prefix(void); #ifdef SOUNDS extern void play_sound(int snd); #endif FILE *tracefile = NULL; #define MAX_X_EVENT 256 event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */ char *Action; int Context = C_NO_CONTEXT; /* current button press context */ TwmWindow *ButtonWindow; /* button press window structure */ XEvent ButtonEvent; /* button press event */ XEvent Event; /* the current event */ TwmWindow *Tmp_win; /* the current twm window */ extern Window captiveroot; Window DragWindow; /* variables used in moving windows */ int origDragX; int origDragY; int DragX; int DragY; unsigned int DragWidth; unsigned int DragHeight; unsigned int DragBW; int CurrentDragX; int CurrentDragY; /* Vars to tell if the resize has moved. */ extern int ResizeOrigX; extern int ResizeOrigY; static int enter_flag; static int leave_flag; static int ColortableThrashing; static TwmWindow *enter_win, *raise_win, *leave_win, *lower_win; int ButtonPressed = -1; int Cancel = FALSE; void HandleCreateNotify(void); void HandleShapeNotify (void); void HandleFocusChange (void); extern int ShapeEventBase, ShapeErrorBase; extern Window lowerontop; #ifdef GNOME # include "gnomewindefs.h" extern Atom _XA_WIN_WORKSPACE; extern Atom _XA_WIN_STATE; #endif /* GNOME */ extern Atom _XA_WM_OCCUPATION; extern Atom _XA_WM_CURRENTWORKSPACE; int GnomeProxyButtonPress = -1; /*#define TRACE_FOCUS*/ /*#define TRACE*/ static void dumpevent (XEvent *e); #if defined(__hpux) && !defined(_XPG4_EXTENDED) # define FDSET int* #else # define FDSET fd_set* #endif static unsigned int set_mask_ignore (unsigned int modifier) { int i; unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (Scr->IgnoreLockModifier) modifier &= ~LockMask; for (i = 0 ; i < 8 ; i++) { if (Scr->IgnoreModifier & ModifierMask [i]) modifier &= ~ModifierMask [i]; } return modifier; } void AutoRaiseWindow (TwmWindow *tmp) { RaiseWindow (tmp); if (ActiveMenu && ActiveMenu->w) XRaiseWindow (dpy, ActiveMenu->w); XSync (dpy, 0); enter_win = NULL; enter_flag = TRUE; raise_win = tmp; WMapRaise (tmp); } void SetRaiseWindow (TwmWindow *tmp) { enter_flag = TRUE; enter_win = NULL; raise_win = tmp; leave_win = NULL; leave_flag = FALSE; lower_win = NULL; XSync (dpy, 0); } void AutoLowerWindow (TwmWindow *tmp) { LowerWindow (tmp); if (ActiveMenu && ActiveMenu->w) XRaiseWindow (dpy, ActiveMenu->w); XSync (dpy, 0); enter_win = NULL; enter_flag = FALSE; raise_win = NULL; leave_win = NULL; leave_flag = TRUE; lower_win = tmp; WMapLower (tmp); } /*********************************************************************** * * Procedure: * InitEvents - initialize the event jump table * *********************************************************************** */ void InitEvents(void) { int i; ResizeWindow = (Window) 0; DragWindow = (Window) 0; enter_flag = FALSE; enter_win = raise_win = NULL; leave_flag = FALSE; leave_win = lower_win = NULL; for (i = 0; i < MAX_X_EVENT; i++) EventHandler[i] = HandleUnknown; EventHandler[Expose] = HandleExpose; EventHandler[CreateNotify] = HandleCreateNotify; EventHandler[DestroyNotify] = HandleDestroyNotify; EventHandler[MapRequest] = HandleMapRequest; EventHandler[MapNotify] = HandleMapNotify; EventHandler[UnmapNotify] = HandleUnmapNotify; EventHandler[MotionNotify] = HandleMotionNotify; EventHandler[ButtonRelease] = HandleButtonRelease; EventHandler[ButtonPress] = HandleButtonPress; EventHandler[EnterNotify] = HandleEnterNotify; EventHandler[LeaveNotify] = HandleLeaveNotify; EventHandler[ConfigureRequest] = HandleConfigureRequest; EventHandler[ClientMessage] = HandleClientMessage; EventHandler[PropertyNotify] = HandlePropertyNotify; EventHandler[KeyPress] = HandleKeyPress; EventHandler[KeyRelease] = HandleKeyRelease; EventHandler[ColormapNotify] = HandleColormapNotify; EventHandler[VisibilityNotify] = HandleVisibilityNotify; EventHandler[FocusIn] = HandleFocusChange; EventHandler[FocusOut] = HandleFocusChange; if (HasShape) EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify; } Time lastTimestamp = CurrentTime; /* until Xlib does this for us */ Bool StashEventTime (register XEvent *ev) { switch (ev->type) { case KeyPress: case KeyRelease: lastTimestamp = ev->xkey.time; return True; case ButtonPress: case ButtonRelease: lastTimestamp = ev->xbutton.time; return True; case MotionNotify: lastTimestamp = ev->xmotion.time; return True; case EnterNotify: case LeaveNotify: lastTimestamp = ev->xcrossing.time; return True; case PropertyNotify: lastTimestamp = ev->xproperty.time; return True; case SelectionClear: lastTimestamp = ev->xselectionclear.time; return True; case SelectionRequest: lastTimestamp = ev->xselectionrequest.time; return True; case SelectionNotify: lastTimestamp = ev->xselection.time; return True; } return False; } /* * WindowOfEvent - return the window about which this event is concerned; this * window may not be the same as XEvent.xany.window (the first window listed * in the structure). */ Window WindowOfEvent (XEvent *e) { /* * Each window subfield is marked with whether or not it is the same as * XEvent.xany.window or is different (which is the case for some of the * notify events). */ switch (e->type) { case KeyPress: case KeyRelease: return e->xkey.window; /* same */ case ButtonPress: case ButtonRelease: return e->xbutton.window; /* same */ case MotionNotify: return e->xmotion.window; /* same */ case EnterNotify: case LeaveNotify: return e->xcrossing.window; /* same */ case FocusIn: case FocusOut: return e->xfocus.window; /* same */ case KeymapNotify: return e->xkeymap.window; /* same */ case Expose: return e->xexpose.window; /* same */ case GraphicsExpose: return e->xgraphicsexpose.drawable; /* same */ case NoExpose: return e->xnoexpose.drawable; /* same */ case VisibilityNotify: return e->xvisibility.window; /* same */ case CreateNotify: return e->xcreatewindow.window; /* DIFF */ case DestroyNotify: return e->xdestroywindow.window; /* DIFF */ case UnmapNotify: return e->xunmap.window; /* DIFF */ case MapNotify: return e->xmap.window; /* DIFF */ case MapRequest: return e->xmaprequest.window; /* DIFF */ case ReparentNotify: return e->xreparent.window; /* DIFF */ case ConfigureNotify: return e->xconfigure.window; /* DIFF */ case ConfigureRequest: return e->xconfigurerequest.window; /* DIFF */ case GravityNotify: return e->xgravity.window; /* DIFF */ case ResizeRequest: return e->xresizerequest.window; /* same */ case CirculateNotify: return e->xcirculate.window; /* DIFF */ case CirculateRequest: return e->xcirculaterequest.window; /* DIFF */ case PropertyNotify: return e->xproperty.window; /* same */ case SelectionClear: return e->xselectionclear.window; /* same */ case SelectionRequest: return e->xselectionrequest.requestor; /* DIFF */ case SelectionNotify: return e->xselection.requestor; /* same */ case ColormapNotify: return e->xcolormap.window; /* same */ case ClientMessage: return e->xclient.window; /* same */ case MappingNotify: return None; } return None; } void FixRootEvent (XEvent *e) { if (Scr->Root == Scr->RealRoot) return; switch (e->type) { case KeyPress: case KeyRelease: e->xkey.x_root -= Scr->rootx; e->xkey.y_root -= Scr->rooty; e->xkey.root = Scr->Root; break; case ButtonPress: case ButtonRelease: e->xbutton.x_root -= Scr->rootx; e->xbutton.y_root -= Scr->rooty; e->xbutton.root = Scr->Root; break; case MotionNotify: e->xmotion.x_root -= Scr->rootx; e->xmotion.y_root -= Scr->rooty; e->xmotion.root = Scr->Root; break; case EnterNotify: case LeaveNotify: e->xcrossing.x_root -= Scr->rootx; e->xcrossing.y_root -= Scr->rooty; e->xcrossing.root = Scr->Root; break; default: break; } } /* Move this next to GetTwmWindow()? */ static ScreenInfo *GetTwmScreen(XEvent *event) { ScreenInfo *scr; if (XFindContext(dpy, event->xany.window, ScreenContext, (XPointer *)&scr) == XCNOENT) { scr = FindScreenInfo(WindowOfEvent(event)); } return scr; } /*********************************************************************** * * Procedure: * DispatchEvent2 - * handle a single X event stored in global var Event * this routine for is for a call during an f.move * *********************************************************************** */ Bool DispatchEvent2 (void) { Window w = Event.xany.window; ScreenInfo *lastScr = Scr; /* XXX_MIKE - assume Scr OK on entry... */ StashEventTime (&Event); Tmp_win = GetTwmWindow(w); Scr = GetTwmScreen(&Event); dumpevent(&Event); if (!Scr) { Scr = lastScr; /* XXX_MIKE - try not to leave Scr NULL */ return False; } FixRootEvent (&Event); #ifdef SOUNDS play_sound(Event.type); #endif if (menuFromFrameOrWindowOrTitlebar) { if (Event.type == Expose) HandleExpose(); } else { if (Event.type>= 0 && Event.type < MAX_X_EVENT) (*EventHandler[Event.type])(); } return True; } /*********************************************************************** * * Procedure: * DispatchEvent - handle a single X event stored in global var Event * *********************************************************************** */ Bool DispatchEvent (void) { Window w = Event.xany.window; ScreenInfo *lastScr = Scr; /* XXX_MIKE - assume Scr OK on entry... */ StashEventTime (&Event); Tmp_win = GetTwmWindow(w); Scr = GetTwmScreen(&Event); dumpevent(&Event); if (!Scr) { Scr = lastScr; /* XXX_MIKE - try not to leave Scr NULL */ return False; } if (captive) { if ((Event.type == ConfigureNotify) && (Event.xconfigure.window == Scr->CaptiveRoot)) { ConfigureRootWindow (&Event); return (False); } } FixRootEvent (&Event); if (Event.type>= 0 && Event.type < MAX_X_EVENT) { #ifdef SOUNDS play_sound(Event.type); #endif (*EventHandler[Event.type])(); } return True; } /*********************************************************************** * * Procedure: * HandleEvents - handle X events * *********************************************************************** */ void HandleEvents(void) { while (TRUE) { if (enter_flag && !QLength(dpy)) { if (enter_win && enter_win != raise_win) { AutoRaiseWindow (enter_win); /* sets enter_flag T */ } else { enter_flag = FALSE; } } if ( leave_flag && !QLength(dpy) ) { if (leave_win && leave_win != lower_win) { AutoLowerWindow (leave_win); /* sets leave_flag T */ } else { leave_flag = FALSE; } } if (ColortableThrashing && !QLength(dpy) && Scr) { InstallColormaps(ColormapNotify, NULL); } WindowMoved = FALSE; CtwmNextEvent (dpy, &Event); if (Event.type < 0 || Event.type >= MAX_X_EVENT) XtDispatchEvent (&Event); else (void) DispatchEvent (); } } #define nextEvent(event) XtAppNextEvent(appContext, event); #ifdef VMS extern unsigned long timefe; #endif static void CtwmNextEvent (Display *display, XEvent *event) { int animate = (AnimationActive && MaybeAnimate); #ifdef VMS if (QLength (display) != 0) { nextEvent (event); return; } if (animate && AnimationPending) Animate (); while (1) { sys$waitfr(timefe); sys$clref(timefe); if (animate && AnimationPending) Animate (); if (QLength (display) != 0) { nextEvent (event); return; } } #else /* VMS */ int found; fd_set mask; int fd; struct timeval timeout, *tout = NULL; if (RestartFlag) DoRestart(CurrentTime); if (XEventsQueued (display, QueuedAfterFlush) != 0) { nextEvent (event); return; } fd = ConnectionNumber (display); #ifdef USE_SIGNALS if (animate && AnimationPending) Animate (); while (1) { FD_ZERO (&mask); FD_SET (fd, &mask); found = select (fd + 1, (FDSET)&mask, (FDSET) 0, (FDSET) 0, 0); if (RestartFlag) DoRestart(CurrentTime); if (found < 0) { if (errno == EINTR) { if (animate) Animate (); } else perror ("select"); continue; } if (FD_ISSET (fd, &mask)) { nextEvent (event); return; } } #else /* USE_SIGNALS */ if (animate) TryToAnimate (); if (RestartFlag) DoRestart(CurrentTime); if (! MaybeAnimate) { nextEvent (event); return; } if (animate) tout = (AnimationSpeed > 0) ? &timeout : NULL; while (1) { FD_ZERO (&mask); FD_SET (fd, &mask); if (animate) { timeout = AnimateTimeout; } found = select (fd + 1, (FDSET)&mask, (FDSET) 0, (FDSET) 0, tout); if (RestartFlag) DoRestart(CurrentTime); if (found < 0) { if (errno != EINTR) perror ("select"); continue; } if (FD_ISSET (fd, &mask)) { nextEvent (event); return; } if (found == 0) { if (animate) TryToAnimate (); if (RestartFlag) DoRestart(CurrentTime); if (! MaybeAnimate) { nextEvent (event); return; } continue; } } #endif /* USE_SIGNALS */ #endif /* VMS */ } /*********************************************************************** * * Procedure: * HandleColormapNotify - colormap notify event handler * * This procedure handles both a client changing its own colormap, and * a client explicitly installing its colormap itself (only the window * manager should do that, so we must set it correctly). * *********************************************************************** */ void HandleColormapNotify(void) { XColormapEvent *cevent = (XColormapEvent *) &Event; ColormapWindow *cwin, **cwins; TwmColormap *cmap; int lost, won, n, number_cwins; /* if (! Tmp_win) return; */ if (XFindContext(dpy, cevent->window, ColormapContext, (XPointer *)&cwin) == XCNOENT) return; cmap = cwin->colormap; if (cevent->new) { if (XFindContext(dpy, cevent->colormap, ColormapContext, (XPointer *)&cwin->colormap) == XCNOENT) cwin->colormap = CreateTwmColormap(cevent->colormap); else cwin->colormap->refcnt++; cmap->refcnt--; if (cevent->state == ColormapUninstalled) cmap->state &= ~CM_INSTALLED; else cmap->state |= CM_INSTALLED; if (cmap->state & CM_INSTALLABLE) { InstallColormaps(ColormapNotify, NULL); } if (cmap->refcnt == 0) { XDeleteContext(dpy, cmap->c, ColormapContext); free((char *) cmap); } return; } if (cevent->state == ColormapUninstalled && (cmap->state & CM_INSTALLABLE)) { if (!(cmap->state & CM_INSTALLED)) return; cmap->state &= ~CM_INSTALLED; if (!ColortableThrashing) { ColortableThrashing = TRUE; XSync(dpy, 0); } if (cevent->serial >= Scr->cmapInfo.first_req) { number_cwins = Scr->cmapInfo.cmaps->number_cwins; /* * Find out which colortables collided. */ cwins = Scr->cmapInfo.cmaps->cwins; for (lost = won = -1, n = 0; (lost == -1 || won == -1) && n < number_cwins; n++) { if (lost == -1 && cwins[n] == cwin) { lost = n; /* This is the window which lost its colormap */ continue; } if (won == -1 && cwins[n]->colormap->install_req == cevent->serial) { won = n; /* This is the window whose colormap caused */ continue; /* the de-install of the previous colormap */ } } /* ** Cases are: ** Both the request and the window were found: ** One of the installs made honoring the WM_COLORMAP ** property caused another of the colormaps to be ** de-installed, just mark the scoreboard. ** ** Only the request was found: ** One of the installs made honoring the WM_COLORMAP ** property caused a window not in the WM_COLORMAP ** list to lose its map. This happens when the map ** it is losing is one which is trying to be installed, ** but is getting getting de-installed by another map ** in this case, we'll get a scoreable event later, ** this one is meaningless. ** ** Neither the request nor the window was found: ** Somebody called installcolormap, but it doesn't ** affect the WM_COLORMAP windows. This case will ** probably never occur. ** ** Only the window was found: ** One of the WM_COLORMAP windows lost its colormap ** but it wasn't one of the requests known. This is ** probably because someone did an "InstallColormap". ** The colormap policy is "enforced" by re-installing ** the colormaps which are believed to be correct. */ if (won != -1) { if (lost != -1) { /* lower diagonal index calculation */ if (lost > won) n = lost*(lost-1)/2 + won; else n = won*(won-1)/2 + lost; Scr->cmapInfo.cmaps->scoreboard[n] = 1; } else { /* ** One of the cwin installs caused one of the cwin ** colormaps to be de-installed, so I'm sure to get an ** UninstallNotify for the cwin I know about later. ** I haven't got it yet, or the test of CM_INSTALLED ** above would have failed. Turning the CM_INSTALLED ** bit back on makes sure we get back here to score ** the collision. */ cmap->state |= CM_INSTALLED; } } else if (lost != -1) { InstallColormaps(ColormapNotify, NULL); } else { ColortableThrashing = FALSE; /* Gross Hack for HP WABI. CL. */ } } } else if (cevent->state == ColormapUninstalled) cmap->state &= ~CM_INSTALLED; else if (cevent->state == ColormapInstalled) cmap->state |= CM_INSTALLED; } /* * LastFocusEvent -- skip over focus in/out events for this * window. */ static XEvent *LastFocusEvent(Window w, XEvent *first) { static XEvent current; XEvent *last, new; new= *first; last=NULL; do { if ( (new.type == FocusIn || new.type == FocusOut) && new.xfocus.mode == NotifyNormal && (new.xfocus.detail == NotifyNonlinear || new.xfocus.detail == NotifyPointer || new.xfocus.detail == NotifyAncestor || (new.xfocus.detail == NotifyNonlinearVirtual) )) { current=new; last= ¤t; #ifdef TRACE_FOCUS printf("! %s 0x%x mode=%d, detail=%d\n", new.xfocus.type == FocusIn?"in":"out", Tmp_win,new.xfocus.mode, new.xfocus.detail); #endif } else { #ifdef TRACE_FOCUS printf("~ %s 0x%x mode=%d, detail=%d\n", new.xfocus.type == FocusIn?"in":"out", Tmp_win,new.xfocus.mode, new.xfocus.detail); #endif } } while (XCheckWindowEvent(dpy, w, FocusChangeMask, &new)); return last; } /* * HandleFocusIn -- deal with the focus moving under us. */ void HandleFocusIn(XFocusInEvent *event) { #ifdef TRACE_FOCUS printf("HandleFocusIn : +0x%x (0x%x, 0x%x), mode=%d, detail=%d\n", Tmp_win, Tmp_win->w, event->window, event->mode, event->detail); #endif if (Tmp_win->iconmgr) return; if (Tmp_win->wmhints && ! Tmp_win->wmhints->input) return; if (Scr->Focus == Tmp_win) return; if (Tmp_win->AutoSqueeze && Tmp_win->squeezed) AutoSqueeze (Tmp_win); SetFocusVisualAttributes (Tmp_win, True); Scr->Focus = Tmp_win; } void HandleFocusOut(XFocusOutEvent *event) { #ifdef TRACE_FOCUS printf("HandleFocusOut : -0x%x (0x%x, 0x%x), mode=%d, detail=%d\n", Tmp_win, Tmp_win->w, event->window, event->mode, event->detail); #endif if (Tmp_win->iconmgr) return; if (Scr->Focus != Tmp_win) return; if (Scr->SloppyFocus) return; if (Tmp_win->AutoSqueeze && !Tmp_win->squeezed) AutoSqueeze (Tmp_win); SetFocusVisualAttributes (Tmp_win, False); Scr->Focus= NULL; } void HandleFocusChange(void) { XEvent *event; if (Tmp_win) { event = LastFocusEvent(Event.xany.window,&Event); if ( event != NULL) { if (event->type == FocusIn) HandleFocusIn(&event->xfocus); else HandleFocusOut(&event->xfocus); } } } void SynthesiseFocusOut(Window w) { XEvent event; #ifdef TRACE_FOCUS printf ("Synthesizing FocusOut on %x\n", w); #endif event.type=FocusOut; event.xfocus.window=w; event.xfocus.mode=NotifyNormal; event.xfocus.detail=NotifyPointer; XPutBackEvent(dpy, &event); } void SynthesiseFocusIn(Window w) { XEvent event; #ifdef TRACE_FOCUS printf ("Synthesizing FocusIn on %x\n", w); #endif event.type=FocusIn; event.xfocus.window=w; event.xfocus.mode=NotifyNormal; event.xfocus.detail=NotifyPointer; XPutBackEvent(dpy, &event); } /*********************************************************************** * * Procedure: * HandleVisibilityNotify - visibility notify event handler * * This routine keeps track of visibility events so that colormap * installation can keep the maximum number of useful colormaps * installed at one time. * *********************************************************************** */ void HandleVisibilityNotify(void) { XVisibilityEvent *vevent = (XVisibilityEvent *) &Event; ColormapWindow *cwin; TwmColormap *cmap; if (XFindContext(dpy, vevent->window, ColormapContext, (XPointer *)&cwin) == XCNOENT) return; /* * when Saber complains about retreiving an from an * just type "touch vevent->state" and "cont" */ cmap = cwin->colormap; if ((cmap->state & CM_INSTALLABLE) && vevent->state != cwin->visibility && (vevent->state == VisibilityFullyObscured || cwin->visibility == VisibilityFullyObscured) && cmap->w == cwin->w) { cwin->visibility = vevent->state; InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL); } else cwin->visibility = vevent->state; } /*********************************************************************** * * Procedure: * HandleKeyRelease - key release event handler * *********************************************************************** */ void HandleKeyRelease(void) { if (Tmp_win == Scr->currentvs->wsw->twm_win) WMgrHandleKeyReleaseEvent (Scr->currentvs, &Event); } /*********************************************************************** * * Procedure: * HandleKeyPress - key press event handler * *********************************************************************** */ void HandleKeyPress(void) { FuncKey *key; int len; unsigned int modifier; Window w; if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow); if (ActiveMenu != NULL) { MenuItem *item; int offset; char *keynam; KeySym keysym; int xx, yy, wx, wy; Window junkW; item = (MenuItem*) 0; keysym = XLookupKeysym ((XKeyEvent*) &Event, 0); if (! keysym) return; keynam = XKeysymToString (keysym); if (! keynam) return; if (!strcmp (keynam, "Down") || !strcmp (keynam, "space")) { xx = Event.xkey.x; yy = Event.xkey.y + Scr->EntryHeight; XTranslateCoordinates (dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW); if ((wy < 0) || (wy > ActiveMenu->height)) yy -= (wy - (Scr->EntryHeight / 2) - 2); if ((wx < 0) || (wx > ActiveMenu->width)) xx -= (wx - (ActiveMenu->width / 2)); XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y, ActiveMenu->width, ActiveMenu->height, xx, yy); return; } else if (!strcmp (keynam, "Up")) { xx = Event.xkey.x; yy = Event.xkey.y - Scr->EntryHeight; XTranslateCoordinates (dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW); if ((wy < 0) || (wy > ActiveMenu->height)) yy -= (wy - ActiveMenu->height + (Scr->EntryHeight / 2) + 2); if ((wx < 0) || (wx > ActiveMenu->width)) xx -= (wx - (ActiveMenu->width / 2)); XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y, ActiveMenu->width, ActiveMenu->height, xx, yy); return; } else if (!strcmp (keynam, "Right") || !strcmp (keynam, "Return")) { item = ActiveItem; } else if (!strcmp (keynam, "Left") || !strcmp(keynam, "Escape")) { MenuRoot *menu; if (ActiveMenu->pinned) return; if (!ActiveMenu->prev || MenuDepth == 1) { PopDownMenu (); XUngrabPointer (dpy, CurrentTime); return; } xx = Event.xkey.x; yy = Event.xkey.y; menu = ActiveMenu->prev; XTranslateCoordinates (dpy, Scr->Root, menu->w, xx, yy, &wx, &wy, &junkW); xx -= (wx - (menu->width / 2)); if (menu->lastactive) yy -= (wy - menu->lastactive->item_num * Scr->EntryHeight - (Scr->EntryHeight / 2) - 2); else yy -= (wy - (Scr->EntryHeight / 2) - 2); XUnmapWindow (dpy, ActiveMenu->w); if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow); XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y, menu->width, menu->height, xx, yy); return; } else if (strlen (keynam) == 1) { MenuItem *startitem; xx = Event.xkey.x; yy = Event.xkey.y; startitem = ActiveItem ? ActiveItem : ActiveMenu->first; item = startitem->next; if (item == (MenuItem*) 0) item = ActiveMenu->first; modifier = (Event.xkey.state & mods_used); modifier = set_mask_ignore (modifier); while (item != startitem) { Boolean matched = False; offset = 0; switch (item->item [0]) { case '^' : if ((modifier & ControlMask) && (keynam [0] == Tolower (item->item [1]))) matched = True; break; case '~' : if ((modifier & Mod1Mask) && (keynam [0] == Tolower (item->item [1]))) matched = True; break; case ' ' : offset = 1; /*FALLTHROUGH*/ default : if (((Scr->IgnoreCaseInMenuSelection) && (keynam [0] == Tolower (item->item [offset]))) || ((modifier & ShiftMask) && Isupper (item->item [offset]) && (keynam [0] == Tolower (item->item [offset]))) || (!(modifier & ShiftMask) && Islower (item->item [offset]) && (keynam [0] == item->item [offset]))) matched = True; break; } if (matched) break; item = item->next; if (item == (MenuItem*) 0) item = ActiveMenu->first; } if (item == startitem) return; wx = ActiveMenu->width / 2; wy = (item->item_num * Scr->EntryHeight) + (Scr->EntryHeight / 2) + 2; XTranslateCoordinates (dpy, ActiveMenu->w, Scr->Root, wx, wy, &xx, &yy, &junkW); XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y, ActiveMenu->width, ActiveMenu->height, xx, yy); return; } else return; if (item) { switch (item->func) { case 0 : case F_TITLE : break; case F_MENU : if (!strcmp (keynam, "Return")) { if (ActiveMenu == Scr->Workspaces) { PopDownMenu(); XUngrabPointer (dpy, CurrentTime); GotoWorkSpaceByName (Scr->currentvs, item->action + 8); } else { ExecuteFunction (item->func, item->action, ButtonWindow ? ButtonWindow->frame : None, ButtonWindow, &Event, Context, FALSE); PopDownMenu(); } return; } xx = Event.xkey.x; yy = Event.xkey.y; XTranslateCoordinates (dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW); if (ActiveItem) { ActiveItem->state = 0; PaintEntry (ActiveMenu, ActiveItem, False); ActiveItem = NULL; } xx -= (wx - ActiveMenu->width); yy -= (wy - item->item_num * Scr->EntryHeight - (Scr->EntryHeight / 2) - 2); Event.xkey.x_root = xx; Event.xkey.y_root = yy; XWarpPointer (dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y, ActiveMenu->width, ActiveMenu->height, xx, yy); if (ActiveMenu == Scr->Workspaces) CurrentSelectedWorkspace = item->item; do_key_menu (item->sub, None); CurrentSelectedWorkspace = NULL; break; default : if (item->func != F_PIN) PopDownMenu(); ExecuteFunction (item->func, item->action, ButtonWindow ? ButtonWindow->frame : None, ButtonWindow, &Event, Context, FALSE); } } else { PopDownMenu(); XUngrabPointer (dpy, CurrentTime); } return; } Context = C_NO_CONTEXT; if (Event.xany.window == Scr->Root) { if (AlternateContext) { XUngrabPointer (dpy, CurrentTime); XUngrabKeyboard (dpy, CurrentTime); AlternateContext = False; Context = C_ALTERNATE; } else if (AlternateKeymap && Event.xkey.subwindow) { w = Event.xkey.subwindow; Tmp_win = GetTwmWindow(w); if (Tmp_win) Event.xany.window = Tmp_win->w; } else Context = C_ROOT; } if (Tmp_win) { if (Event.xany.window == Tmp_win->title_w) Context = C_TITLE; if (Event.xany.window == Tmp_win->w) Context = C_WINDOW; if (Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w)) Context = C_ICON; if (Event.xany.window == Tmp_win->frame) Context = C_FRAME; if (Tmp_win->iconmanagerlist) { if (Event.xany.window == Tmp_win->iconmanagerlist->w || Event.xany.window == Tmp_win->iconmanagerlist->icon) Context = C_ICONMGR; } if (Tmp_win->wspmgr) Context = C_WORKSPACE; } modifier = (Event.xkey.state | AlternateKeymap) & mods_used; modifier = set_mask_ignore (modifier); if (AlternateKeymap) { XUngrabPointer (dpy, CurrentTime); XUngrabKeyboard (dpy, CurrentTime); AlternateKeymap = 0; } for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next) { if (key->keycode == Event.xkey.keycode && key->mods == modifier && (key->cont == Context || key->cont == C_NAME)) { /* weed out the functions that don't make sense to execute * from a key press * TODO: add keyboard moving/resizing of windows. */ if (key->func == F_MOVE || key->func == F_RESIZE) return; if (key->cont != C_NAME) { if (key->func == F_MENU) { ButtonEvent = Event; ButtonWindow = Tmp_win; do_key_menu (key->menu, (Window) None); } else { ExecuteFunction(key->func, key->action, Event.xany.window, Tmp_win, &Event, Context, FALSE); if (!AlternateKeymap && !AlternateContext) XUngrabPointer(dpy, CurrentTime); } return; } else { int matched = FALSE; len = strlen(key->win_name); /* try and match the name first */ for (Tmp_win = Scr->FirstWindow; Tmp_win != NULL; Tmp_win = Tmp_win->next) { if (!strncmp(key->win_name, Tmp_win->name, len)) { matched = TRUE; ExecuteFunction(key->func, key->action, Tmp_win->frame, Tmp_win, &Event, C_FRAME, FALSE); if (!AlternateKeymap && !AlternateContext) XUngrabPointer(dpy, CurrentTime); } } /* now try the res_name */ if (!matched) for (Tmp_win = Scr->FirstWindow; Tmp_win != NULL; Tmp_win = Tmp_win->next) { if (!strncmp(key->win_name, Tmp_win->class.res_name, len)) { matched = TRUE; ExecuteFunction(key->func, key->action, Tmp_win->frame, Tmp_win, &Event, C_FRAME, FALSE); if (!AlternateKeymap && !AlternateContext) XUngrabPointer(dpy, CurrentTime); } } /* now try the res_class */ if (!matched) for (Tmp_win = Scr->FirstWindow; Tmp_win != NULL; Tmp_win = Tmp_win->next) { if (!strncmp(key->win_name, Tmp_win->class.res_class, len)) { matched = TRUE; ExecuteFunction(key->func, key->action, Tmp_win->frame, Tmp_win, &Event, C_FRAME, FALSE); if (!AlternateKeymap && !AlternateContext) XUngrabPointer(dpy, CurrentTime); } } if (matched) return; } } } /* if we get here, no function key was bound to the key. Send it * to the client if it was in a window we know about. */ if (Tmp_win) { /* if (Tmp_win == Scr->currentvs->wsw->twm_win) */ if (Tmp_win->wspmgr) { WMgrHandleKeyPressEvent (Scr->currentvs, &Event); return; } if (Tmp_win->icon && ((Event.xany.window == Tmp_win->icon->w) || (Event.xany.window == Tmp_win->frame) || (Event.xany.window == Tmp_win->title_w) || (Tmp_win->iconmanagerlist && (Event.xany.window == Tmp_win->iconmanagerlist->w)))) { Event.xkey.window = Tmp_win->w; XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event); } } } static void free_window_names (TwmWindow *tmp, Bool nukefull, Bool nukename, Bool nukeicon) { /* * XXX - are we sure that nobody ever sets these to another constant (check * twm windows)? */ if ((tmp->name == tmp->full_name) && (tmp->name == tmp->icon_name)) { if (nukefull && nukename && nukeicon) FreeWMPropertyString(tmp->name); } else if (tmp->name == tmp->full_name) { if (nukename && nukefull) FreeWMPropertyString(tmp->name); if (nukeicon) FreeWMPropertyString(tmp->icon_name); } else if (tmp->name == tmp->icon_name) { if (nukename && nukeicon) FreeWMPropertyString(tmp->name); if (nukefull) FreeWMPropertyString(tmp->full_name); } else if (tmp->icon_name == tmp->full_name) { if (nukeicon && nukefull) FreeWMPropertyString(tmp->icon_name); if (nukename) FreeWMPropertyString(tmp->name); } else { if (nukefull) FreeWMPropertyString(tmp->full_name); if (nukename) FreeWMPropertyString(tmp->name); if (nukeicon) FreeWMPropertyString(tmp->icon_name); } return; } void free_cwins (TwmWindow *tmp) { int i; TwmColormap *cmap; if (tmp->cmaps.number_cwins) { for (i = 0; i < tmp->cmaps.number_cwins; i++) { if (--tmp->cmaps.cwins[i]->refcnt == 0) { cmap = tmp->cmaps.cwins[i]->colormap; if (--cmap->refcnt == 0) { XDeleteContext(dpy, cmap->c, ColormapContext); free((char *) cmap); } XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext); free((char *) tmp->cmaps.cwins[i]); } } free((char *) tmp->cmaps.cwins); if (tmp->cmaps.number_cwins > 1) { free(tmp->cmaps.scoreboard); tmp->cmaps.scoreboard = NULL; } tmp->cmaps.number_cwins = 0; } } /*********************************************************************** * * Procedure: * HandlePropertyNotify - property notify event handler * *********************************************************************** */ void HandlePropertyNotify(void) { unsigned char *prop = NULL; Atom actual = None; int actual_format; unsigned long nitems, bytesafter; unsigned long valuemask; /* mask for create windows */ XSetWindowAttributes attributes; /* attributes for create windows */ Pixmap pm; int icon_change; XRectangle inc_rect; XRectangle logical_rect; unsigned char *gwkspc; /* watch for standard colormap changes */ if (Event.xproperty.window == Scr->Root) { XStandardColormap *maps = NULL; int nmaps; if (Event.xproperty.atom == _XA_WM_CURRENTWORKSPACE) { switch (Event.xproperty.state) { case PropertyNewValue: if (XGetWindowProperty (dpy, Scr->Root, _XA_WM_CURRENTWORKSPACE, 0L, 200L, False, XA_STRING, &actual, &actual_format, &nitems, &bytesafter, &prop) == Success) { if (nitems == 0) return; GotoWorkSpaceByName (Scr->vScreenList, (char*)prop); XFree ((char*) prop); } return; default: return; } } switch (Event.xproperty.state) { case PropertyNewValue: if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, Event.xproperty.atom)) { /* if got one, then replace any existing entry */ InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True); } return; case PropertyDelete: RemoveRGBColormap (Event.xproperty.atom); return; } } if (!Tmp_win) return; /* unknown window */ #define MAX_NAME_LEN 200L /* truncate to this many */ #define MAX_ICON_NAME_LEN 200L /* ditto */ switch (Event.xproperty.atom) { case XA_WM_NAME: prop = GetWMPropertyString(Tmp_win->w, XA_WM_NAME); if (prop == NULL) return; #ifdef CLAUDE if (strstr (prop, " - Mozilla")) { char *moz = strstr (prop, " - Mozilla"); *moz = '\0'; } #endif free_window_names (Tmp_win, True, True, False); Tmp_win->full_name = (char*) prop; Tmp_win->name = (char*) prop; Tmp_win->nameChanged = 1; XmbTextExtents(Scr->TitleBarFont.font_set, Tmp_win->name, strlen (Tmp_win->name), &inc_rect, &logical_rect); Tmp_win->name_width = logical_rect.width; SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y, Tmp_win->frame_width, Tmp_win->frame_height, -1); if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True); if (Scr->AutoOccupy) WmgrRedoOccupation (Tmp_win); /* Experimental, not yet working. { ColorPair cp; int f, b; f = GetColorFromList (Scr->TitleForegroundL, Tmp_win->full_name, &Tmp_win->class, &cp.fore); b = GetColorFromList (Scr->TitleBackgroundL, Tmp_win->full_name, &Tmp_win->class, &cp.back); if (f || b) { if (Scr->use3Dtitles && !Scr->BeNiceToColormap) GetShadeColors (&cp); Tmp_win->title = cp; } f = GetColorFromList (Scr->BorderColorL, Tmp_win->full_name, &Tmp_win->class, &cp.fore); b = GetColorFromList (Scr->BorderColorL, Tmp_win->full_name, &Tmp_win->class, &cp.back); if (f || b) { if (Scr->use3Dborders && !Scr->BeNiceToColormap) GetShadeColors (&cp); Tmp_win->borderC = cp; } f = GetColorFromList (Scr->BorderTileForegroundL, Tmp_win->full_name, &Tmp_win->class, &cp.fore); b = GetColorFromList (Scr->BorderTileBackgroundL, Tmp_win->full_name, &Tmp_win->class, &cp.back); if (f || b) { if (Scr->use3Dborders && !Scr->BeNiceToColormap) GetShadeColors (&cp); Tmp_win->border_tile = cp; } } */ /* * if the icon name is NoName, set the name of the icon to be * the same as the window */ if (Tmp_win->icon_name == NoName) { Tmp_win->icon_name = Tmp_win->name; RedoIcon(); } break; case XA_WM_ICON_NAME: prop = GetWMPropertyString(Tmp_win->w, XA_WM_ICON_NAME); if (prop == NULL) return; #ifdef CLAUDE if (strstr (prop, " - Mozilla")) { char *moz = strstr (prop, " - Mozilla"); *moz = '\0'; } #endif icon_change = strcmp (Tmp_win->icon_name, (char*) prop); free_window_names (Tmp_win, False, False, True); Tmp_win->icon_name = (char*) prop; if (icon_change) { RedoIcon(); } break; case XA_WM_HINTS: if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints); Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window); if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint)) { Tmp_win->group = Tmp_win->wmhints->window_group; if (Tmp_win->group && !GetTwmWindow(Tmp_win->group)) Tmp_win->group = 0; /* see comment in AddWindow() */ } if (!Tmp_win->forced && Tmp_win->wmhints && Tmp_win->wmhints->flags & IconWindowHint) { if (Tmp_win->icon && Tmp_win->icon->w) { int icon_x, icon_y; /* * There's already an icon window. * Try to find out where it is; if we succeed, move the new * window to where the old one is. */ if (XGetGeometry (dpy, Tmp_win->icon->w, &JunkRoot, &icon_x, &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) { /* * Move the new icon window to where the old one was. */ XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x, icon_y); } /* * If the window is iconic, map the new icon window. */ if (Tmp_win->isicon) XMapWindow(dpy, Tmp_win->wmhints->icon_window); /* * Now, if the old window isn't ours, unmap it, otherwise * just get rid of it completely. */ if (Tmp_win->icon_not_ours) { if (Tmp_win->icon->w != Tmp_win->wmhints->icon_window) XUnmapWindow(dpy, Tmp_win->icon->w); } else XDestroyWindow(dpy, Tmp_win->icon->w); /* * The new icon window isn't our window, so note that fact * so that we don't treat it as ours. */ Tmp_win->icon_not_ours = TRUE; /* * Now make the new window the icon window for this window, * and set it up to work as such (select for key presses * and button presses/releases, set up the contexts for it, * and define the cursor for it). */ Tmp_win->icon->w = Tmp_win->wmhints->icon_window; XSelectInput (dpy, Tmp_win->icon->w, KeyPressMask | ButtonPressMask | ButtonReleaseMask); XSaveContext(dpy, Tmp_win->icon->w, TwmContext, (XPointer)Tmp_win); XSaveContext(dpy, Tmp_win->icon->w, ScreenContext, (XPointer)Scr); XDefineCursor(dpy, Tmp_win->icon->w, Scr->IconCursor); } } if (Tmp_win->icon && Tmp_win->icon->w && !Tmp_win->forced && Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconPixmapHint)) { int x; if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot, &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon->width, (unsigned int *)&Tmp_win->icon->height, &JunkBW, &JunkDepth)) { return; } pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon->width, Tmp_win->icon->height, Scr->d_depth); FB(Tmp_win->icon->iconc.fore, Tmp_win->icon->iconc.back); if (JunkDepth == Scr->d_depth) XCopyArea (dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC, 0,0, Tmp_win->icon->width, Tmp_win->icon->height, 0, 0); else XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC, 0,0, Tmp_win->icon->width, Tmp_win->icon->height, 0, 0, 1 ); if (Tmp_win->icon->image) { if (Tmp_win->icon->image->pixmap) XFreePixmap (dpy, Tmp_win->icon->image->pixmap); Tmp_win->icon->image->pixmap = pm; Tmp_win->icon->image->width = Tmp_win->icon->width; Tmp_win->icon->image->height = Tmp_win->icon->height; Tmp_win->icon->image->mask = None; Tmp_win->icon->image->next = None; } valuemask = CWBackPixmap; attributes.background_pixmap = pm; if (Tmp_win->icon->bm_w) XDestroyWindow(dpy, Tmp_win->icon->bm_w); x = GetIconOffset (Tmp_win->icon); Tmp_win->icon->bm_w = XCreateWindow (dpy, Tmp_win->icon->w, x, 0, (unsigned int) Tmp_win->icon->width, (unsigned int) Tmp_win->icon->height, (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); if (! (Tmp_win->wmhints->flags & IconMaskHint)) { XRectangle rect; rect.x = x; rect.y = 0; rect.width = Tmp_win->icon->width; rect.height = Tmp_win->icon->height; XShapeCombineRectangles (dpy, Tmp_win->icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeUnion, 0); } XMapSubwindows (dpy, Tmp_win->icon->w); RedoIconName(); } if (Tmp_win->icon && Tmp_win->icon->w && !Tmp_win->forced && Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconMaskHint)) { int x; Pixmap mask; GC gc; if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_mask, &JunkRoot, &JunkX, &JunkY, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) { return; } if (JunkDepth != 1) return; mask = XCreatePixmap (dpy, Scr->Root, JunkWidth, JunkHeight, 1); if (!mask) return; gc = XCreateGC (dpy, mask, 0, NULL); if (!gc) return; XCopyArea (dpy, Tmp_win->wmhints->icon_mask, mask, gc, 0, 0, JunkWidth, JunkHeight, 0, 0); XFreeGC (dpy, gc); x = GetIconOffset (Tmp_win->icon); XShapeCombineMask (dpy, Tmp_win->icon->bm_w, ShapeBounding, 0, 0, mask, ShapeSet); XShapeCombineMask (dpy, Tmp_win->icon->w, ShapeBounding, x, 0, mask, ShapeSet); if (Tmp_win->icon->image) { if (Tmp_win->icon->image->mask) XFreePixmap (dpy, Tmp_win->icon->image->mask); Tmp_win->icon->image->mask = mask; RedoIconName (); } } break; case XA_WM_NORMAL_HINTS: { GetWindowSizeHints (Tmp_win); break; } default: if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) { FetchWmColormapWindows (Tmp_win); /* frees old data */ break; } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) { FetchWmProtocols (Tmp_win); break; } else if (Event.xproperty.atom == _XA_WM_OCCUPATION) { if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L, MAX_NAME_LEN, False, XA_STRING, &actual, &actual_format, &nitems, &bytesafter, &prop) != Success || actual == None) return; ChangeOccupation (Tmp_win, GetMaskFromProperty (prop, nitems)); XFree ((char *)prop); } #ifdef GNOME else if (Event.xproperty.atom == _XA_WIN_WORKSPACE){ if(XGetWindowProperty(dpy, Tmp_win->w, Event.xproperty.atom, 0L, 32, False, XA_CARDINAL, &actual, &actual_format, &nitems, &bytesafter, &gwkspc) != Success || actual == None) return; ChangeOccupation (Tmp_win, 1 << (int)(*gwkspc)); XFree ((char *)gwkspc); } #endif /* GNOME */ break; } } static void RedoIcon(void) { Icon *icon; char *pattern; if (Tmp_win->icon_not_ours) { RedoIconName (); return; } icon = (Icon*) 0; if ((pattern = LookPatternInNameList (Scr->IconNames, Tmp_win->icon_name))) { icon = (Icon*) LookInNameList (Tmp_win->iconslist, pattern); } else if ((pattern = LookPatternInNameList (Scr->IconNames, Tmp_win->full_name))) { icon = (Icon*) LookInNameList (Tmp_win->iconslist, pattern); } else if ((pattern = LookPatternInList (Scr->IconNames, Tmp_win->full_name, &Tmp_win->class))) { icon = (Icon*) LookInNameList (Tmp_win->iconslist, pattern); } if (pattern == NULL) { RedoIconName (); return; } if (icon != NULL) { if (Tmp_win->icon == icon) { RedoIconName (); return; } if (Tmp_win->icon_on && visible (Tmp_win)) { IconDown (Tmp_win); if (Tmp_win->icon && Tmp_win->icon->w) XUnmapWindow (dpy, Tmp_win->icon->w); Tmp_win->icon = icon; IconUp (Tmp_win); XMapRaised (dpy, Tmp_win->icon->w); } else { Tmp_win->icon = icon; } RedoIconName (); } else { if (Tmp_win->icon_on && visible (Tmp_win)) { IconDown (Tmp_win); if (Tmp_win->icon && Tmp_win->icon->w) XUnmapWindow (dpy, Tmp_win->icon->w); CreateIconWindow (Tmp_win, -100, -100); XMapRaised (dpy, Tmp_win->icon->w); } else { Tmp_win->icon = (Icon*) 0; WMapUpdateIconName (Tmp_win); } RedoIconName (); } } /*********************************************************************** * * Procedure: * RedoIconName - procedure to re-position the icon window and name * *********************************************************************** */ void RedoIconName(void) { int x; XRectangle ink_rect; XRectangle logical_rect; if (Scr->NoIconTitlebar || LookInNameList (Scr->NoIconTitle, Tmp_win->icon_name) || LookInList (Scr->NoIconTitle, Tmp_win->full_name, &Tmp_win->class)) goto wmapupd; if (Tmp_win->iconmanagerlist) { /* let the expose event cause the repaint */ XClearArea(dpy, Tmp_win->iconmanagerlist->w, 0,0,0,0, True); if (Scr->SortIconMgr) SortIconManager(Tmp_win->iconmanagerlist->iconmgr); } if (!Tmp_win->icon || !Tmp_win->icon->w) goto wmapupd; if (Tmp_win->icon_not_ours) goto wmapupd; XmbTextExtents(Scr->IconFont.font_set, Tmp_win->icon_name, strlen(Tmp_win->icon_name), &ink_rect, &logical_rect); Tmp_win->icon->w_width = logical_rect.width; Tmp_win->icon->w_width += 2 * Scr->IconManagerShadowDepth + 6; if (Tmp_win->icon->w_width > Scr->MaxIconTitleWidth) Tmp_win->icon->w_width = Scr->MaxIconTitleWidth; if (Tmp_win->icon->w_width < Tmp_win->icon->width) { Tmp_win->icon->x = (Tmp_win->icon->width - Tmp_win->icon->w_width)/2; Tmp_win->icon->x += Scr->IconManagerShadowDepth + 3; Tmp_win->icon->w_width = Tmp_win->icon->width; } else { Tmp_win->icon->x = Scr->IconManagerShadowDepth + 3; } x = GetIconOffset (Tmp_win->icon); Tmp_win->icon->y = Tmp_win->icon->height + Scr->IconFont.height + Scr->IconManagerShadowDepth; Tmp_win->icon->w_height = Tmp_win->icon->height + Scr->IconFont.height + 2 * Scr->IconManagerShadowDepth + 6; XResizeWindow(dpy, Tmp_win->icon->w, Tmp_win->icon->w_width, Tmp_win->icon->w_height); if (Tmp_win->icon->bm_w) { XRectangle rect; XMoveWindow(dpy, Tmp_win->icon->bm_w, x, 0); XMapWindow(dpy, Tmp_win->icon->bm_w); if (Tmp_win->icon->image && Tmp_win->icon->image->mask) { XShapeCombineMask(dpy, Tmp_win->icon->bm_w, ShapeBounding, 0, 0, Tmp_win->icon->image->mask, ShapeSet); XShapeCombineMask(dpy, Tmp_win->icon->w, ShapeBounding, x, 0, Tmp_win->icon->image->mask, ShapeSet); } else if (Tmp_win->icon->has_title) { rect.x = x; rect.y = 0; rect.width = Tmp_win->icon->width; rect.height = Tmp_win->icon->height; XShapeCombineRectangles (dpy, Tmp_win->icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 0); } if (Tmp_win->icon->has_title) { if (Scr->ShrinkIconTitles && Tmp_win->icon->title_shrunk) { rect.x = x; rect.y = Tmp_win->icon->height; rect.width = Tmp_win->icon->width; rect.height = Tmp_win->icon->w_height - Tmp_win->icon->height; } else { rect.x = 0; rect.y = Tmp_win->icon->height; rect.width = Tmp_win->icon->w_width; rect.height = Tmp_win->icon->w_height - Tmp_win->icon->height; } XShapeCombineRectangles (dpy, Tmp_win->icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeUnion, 0); } } if (Scr->ShrinkIconTitles && Tmp_win->icon->title_shrunk && Tmp_win->icon_on && (visible (Tmp_win))) { IconDown (Tmp_win); IconUp (Tmp_win); } if (Tmp_win->isicon) { XClearArea(dpy, Tmp_win->icon->w, 0, 0, 0, 0, True); } wmapupd: WMapUpdateIconName (Tmp_win); } /*********************************************************************** * * Procedure: * HandleClientMessage - client message event handler * *********************************************************************** */ void HandleClientMessage(void) { TwmWindow *twm_win; int i; if (Event.xclient.message_type == _XA_WM_CHANGE_STATE) { if (Tmp_win != NULL) { if (Event.xclient.data.l[0] == IconicState && !Tmp_win->isicon) { XEvent button; XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &(button.xmotion.x_root), &(button.xmotion.y_root), &JunkX, &JunkY, &JunkMask); ExecuteFunction (F_ICONIFY, NULLSTR, Event.xany.window, Tmp_win, &button, FRAME, FALSE); XUngrabPointer (dpy, CurrentTime); } } return; } #ifdef GNOME /* 6/19/1999 nhd for GNOME compliance */ if (Event.xclient.message_type == _XA_WIN_WORKSPACE) { /* XXXXX supposedly works with a single screen, but is less certain with multiple screens */ GotoWorkSpaceByNumber (Scr->currentvs, Event.xclient.data.l[0]); return; } if (Event.xclient.message_type == _XA_WIN_STATE) { unsigned long new_stuff = (unsigned long) Event.xclient.data.l [1]; unsigned long old_stuff = (unsigned long) Event.xclient.data.l [0]; Window tmp_win = Event.xclient.window; for (twm_win = Scr->FirstWindow; twm_win != NULL; twm_win = twm_win->next) if (twm_win->w == tmp_win) break; if (twm_win == NULL) return; for (i = 1; i < (1 << 10); i <<= 1){ switch (old_stuff & i) { case WIN_STATE_STICKY: /* sticky */ if (new_stuff & i) OccupyAll (twm_win); else ChangeOccupation (twm_win, (1<<(Scr->currentvs->wsw->currentwspc->number))); break; case WIN_STATE_MINIMIZED: /* minimized - reserved */ break; case WIN_STATE_MAXIMIZED_VERT: /* window in maximized V state */ break; case WIN_STATE_MAXIMIZED_HORIZ: /* maximized horizontally */ break; case WIN_STATE_HIDDEN: /* hidden - what does this mean?? */ break; case WIN_STATE_SHADED: /* shaded (squeezed) */ Squeeze (twm_win); break; case WIN_STATE_HID_WORKSPACE: /* not on this workspace */ break; case WIN_STATE_HID_TRANSIENT: /* owner of transient hidden ? */ break; case WIN_STATE_FIXED_POSITION: /* position fixed, don't move */ break; case WIN_STATE_ARRANGE_IGNORE: /* ignore when auto-arranging */ break; } } } #endif /* GNOME */ } /*********************************************************************** * * Procedure: * HandleExpose - expose event handler * *********************************************************************** */ static void flush_expose(Window w); void HandleExpose(void) { MenuRoot *tmp; virtualScreen *vs; if (XFindContext(dpy, Event.xany.window, MenuContext, (XPointer *)&tmp) == 0) { PaintMenu(tmp, &Event); return; } if (Event.xexpose.count != 0) return; if (Event.xany.window == Scr->InfoWindow && InfoLines) { int i; int height; Draw3DBorder (Scr->InfoWindow, 0, 0, InfoWidth, InfoHeight, 2, Scr->DefaultC, off, True, False); FB(Scr->DefaultC.fore, Scr->DefaultC.back); height = Scr->DefaultFont.height+2; for (i = 0; i < InfoLines; i++) { XmbDrawString(dpy, Scr->InfoWindow, Scr->DefaultFont.font_set, Scr->NormalGC, 5, (i*height) + Scr->DefaultFont.y + 5, Info[i], strlen(Info[i])); } flush_expose (Event.xany.window); } else if (Tmp_win != NULL) { if (Scr->use3Dborders && (Event.xany.window == Tmp_win->frame)) { PaintBorders (Tmp_win, ((Tmp_win == Scr->Focus) ? True : False)); flush_expose (Event.xany.window); return; } else if (Event.xany.window == Tmp_win->title_w) { PaintTitle (Tmp_win); flush_expose (Event.xany.window); return; } else if (Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w) && ! Scr->NoIconTitlebar && ! LookInList (Scr->NoIconTitle, Tmp_win->full_name, &Tmp_win->class)) { PaintIcon (Tmp_win); flush_expose (Event.xany.window); return; } else if (Tmp_win->titlebuttons) { int i; TBWindow *tbw; Window w = Event.xany.window; int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) { if (w == tbw->window) { PaintTitleButton (Tmp_win, tbw); flush_expose (tbw->window); return; } } } for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { if (Tmp_win == vs->wsw->twm_win) { WMgrHandleExposeEvent (vs, &Event); flush_expose (Event.xany.window); return; } } if (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) { PaintOccupyWindow (); flush_expose (Event.xany.window); return; } else if (Tmp_win->iconmanagerlist) { WList *iconmanagerlist = Tmp_win->iconmanagerlist; if (Event.xany.window == iconmanagerlist->w) { int offs; DrawIconManagerBorder(iconmanagerlist, True); FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back); offs = Scr->use3Diconmanagers ? Scr->IconManagerShadowDepth : 2; if (Scr->use3Diconmanagers && (Scr->Monochrome != COLOR)) XmbDrawImageString(dpy, Event.xany.window, Scr->IconManagerFont.font_set, Scr->NormalGC, iconmgr_textx, Scr->IconManagerFont.y + offs + 2, Tmp_win->icon_name, strlen(Tmp_win->icon_name)); else XmbDrawString(dpy, Event.xany.window, Scr->IconManagerFont.font_set, Scr->NormalGC, iconmgr_textx, Scr->IconManagerFont.y + offs + 2, Tmp_win->icon_name, strlen(Tmp_win->icon_name)); flush_expose (Event.xany.window); return; } if (Event.xany.window == iconmanagerlist->icon) { if (Scr->use3Diconmanagers && iconmanagerlist->iconifypm) { XCopyArea(dpy, iconmanagerlist->iconifypm, iconmanagerlist->icon, Scr->NormalGC, 0, 0, iconifybox_width, iconifybox_height, 0, 0); } else { FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back); XCopyPlane(dpy, Scr->siconifyPm, iconmanagerlist->icon, Scr->NormalGC, 0,0, iconifybox_width, iconifybox_height, 0, 0, 1); } flush_expose (Event.xany.window); return; } } } } static void remove_window_from_ring (TwmWindow *tmp) { TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next; if (enter_win == tmp) { enter_flag = FALSE; enter_win = NULL; } if (raise_win == Tmp_win) raise_win = NULL; if (leave_win == tmp) { leave_flag = FALSE; leave_win = NULL; } if (lower_win == Tmp_win) lower_win = NULL; /* * 1. Unlink window * 2. If window was only thing in ring, null out ring * 3. If window was ring leader, set to next (or null) */ if (prev) prev->ring.next = next; if (next) next->ring.prev = prev; if (Scr->Ring == tmp) Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL); if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring; } /*********************************************************************** * * Procedure: * HandleDestroyNotify - DestroyNotify event handler * *********************************************************************** */ void HandleDestroyNotify(void) { /* * Warning, this is also called by HandleUnmapNotify; if it ever needs to * look at the event, HandleUnmapNotify will have to mash the UnmapNotify * into a DestroyNotify. */ if (Tmp_win == NULL) return; RemoveWindowFromRegion (Tmp_win); #ifdef GNOME GnomeDeleteClientWindow (Tmp_win); /* Fix the gnome client list */ #endif /* GNOME */ if (Tmp_win == Scr->Focus) { Scr->Focus = (TwmWindow*) NULL; FocusOnRoot(); } if (Scr->SaveWorkspaceFocus) { struct WorkSpace *ws; for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { if (ws->save_focus == Tmp_win) ws->save_focus = NULL; } } XDeleteContext(dpy, Tmp_win->w, TwmContext); XDeleteContext(dpy, Tmp_win->w, ScreenContext); XDeleteContext(dpy, Tmp_win->frame, TwmContext); XDeleteContext(dpy, Tmp_win->frame, ScreenContext); if (Tmp_win->icon && Tmp_win->icon->w) { XDeleteContext(dpy, Tmp_win->icon->w, TwmContext); XDeleteContext(dpy, Tmp_win->icon->w, ScreenContext); } if (Tmp_win->title_height) { int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; XDeleteContext(dpy, Tmp_win->title_w, TwmContext); XDeleteContext(dpy, Tmp_win->title_w, ScreenContext); if (Tmp_win->hilite_wl) { XDeleteContext(dpy, Tmp_win->hilite_wl, TwmContext); XDeleteContext(dpy, Tmp_win->hilite_wl, ScreenContext); } if (Tmp_win->hilite_wr) { XDeleteContext(dpy, Tmp_win->hilite_wr, TwmContext); XDeleteContext(dpy, Tmp_win->hilite_wr, ScreenContext); } if (Tmp_win->lolite_wr) { XDeleteContext(dpy, Tmp_win->lolite_wr, TwmContext); XDeleteContext(dpy, Tmp_win->lolite_wr, ScreenContext); } if (Tmp_win->lolite_wl) { XDeleteContext(dpy, Tmp_win->lolite_wl, TwmContext); XDeleteContext(dpy, Tmp_win->lolite_wl, ScreenContext); } if (Tmp_win->titlebuttons) { int i; for (i = 0; i < nb; i++) { XDeleteContext (dpy, Tmp_win->titlebuttons[i].window, TwmContext); XDeleteContext (dpy, Tmp_win->titlebuttons[i].window, ScreenContext); } } /* * The hilite_wl etc windows don't need to be XDestroyWindow()ed * since that will happen when the parent is destroyed (??) */ } if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps) { InstallColormaps(DestroyNotify, &Scr->RootColormaps); } /* * TwmWindows contain the following pointers * * 1. full_name * 2. name * 3. icon_name * 4. wmhints * 5. class.res_name * 6. class.res_class * 7. list * 8. iconmgrp * 9. cwins * 10. titlebuttons * 11. window ring * 12. squeeze_info (delete if squeeze_info_copied) * 13. HiliteImage * 14. iconslist */ WMapDestroyWindow (Tmp_win); if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray); /* * According to the manual page, the following destroys all child windows * of the frame too, which is most of the windows we're concerned with, so * anything related to them must be done before here. * Icons are not child windows. */ XDestroyWindow(dpy, Tmp_win->frame); if (Tmp_win->icon) { if (Tmp_win->icon->w && !Tmp_win->icon_not_ours) { XDestroyWindow(dpy, Tmp_win->icon->w); IconDown (Tmp_win); } free (Tmp_win->icon); Tmp_win->icon = NULL; } Tmp_win->occupation = 0; RemoveIconManager(Tmp_win); /* 7 */ if (Scr->FirstWindow == Tmp_win) Scr->FirstWindow = Tmp_win->next; if (Tmp_win->prev != NULL) Tmp_win->prev->next = Tmp_win->next; if (Tmp_win->next != NULL) Tmp_win->next->prev = Tmp_win->prev; if (Tmp_win->auto_raise) Scr->NumAutoRaises--; if (Tmp_win->auto_lower) Scr->NumAutoLowers--; if (Tmp_win->frame == lowerontop) lowerontop = -1; free_window_names (Tmp_win, True, True, True); /* 1, 2, 3 */ if (Tmp_win->wmhints) /* 4 */ XFree ((char *)Tmp_win->wmhints); if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName) /* 5 */ XFree ((char *)Tmp_win->class.res_name); if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */ XFree ((char *)Tmp_win->class.res_class); free_cwins (Tmp_win); /* 9 */ if (Tmp_win->titlebuttons) { /* 10 */ free(Tmp_win->titlebuttons); Tmp_win->titlebuttons = NULL; } remove_window_from_ring (Tmp_win); /* 11 */ if (Tmp_win->squeeze_info_copied) { /* 12 */ free(Tmp_win->squeeze_info); Tmp_win->squeeze_info = NULL; } DeleteHighlightWindows(Tmp_win); /* 13 */ DeleteIconsList (Tmp_win); /* 14 */ free((char *)Tmp_win); Tmp_win = NULL; if (Scr->ClickToFocus || Scr->SloppyFocus) set_last_window (Scr->currentvs->wsw->currentwspc); } void HandleCreateNotify(void) { #ifdef DEBUG_EVENTS fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window); fflush(stderr); XBell(dpy, 0); XSync(dpy, 0); #endif } /*********************************************************************** * * Procedure: * HandleMapRequest - MapRequest event handler * *********************************************************************** */ void HandleMapRequest(void) { int zoom_save; Event.xany.window = Event.xmaprequest.window; Tmp_win = GetTwmWindow(Event.xany.window); /* If the window has never been mapped before ... */ if (Tmp_win == NULL) { /* Add decorations. */ Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL); if (Tmp_win == NULL) return; #ifdef GNOME GnomeAddClientWindow (Tmp_win); /* add the new window to the gnome client list */ #endif /* GNOME */ } else { /* * If the window has been unmapped by the client, it won't be listed * in the icon manager. Add it again, if requested. */ if (Tmp_win->iconmanagerlist == NULL) (void) AddIconManager (Tmp_win); } if (Tmp_win->iconmgr) return; if (Tmp_win->squeezed) return; if (Scr->WindowMask) XRaiseWindow (dpy, Scr->WindowMask); /* If it's not merely iconified, and we have hints, use them. */ if (! Tmp_win->isicon) { int state; Window icon; state = NormalState; /* use WM_STATE if enabled */ if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) && (state == NormalState || state == IconicState || state == InactiveState))) { if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint)) state = Tmp_win->wmhints->initial_state; } switch (state) { case DontCareState: case NormalState: case ZoomState: if (Tmp_win->StartSqueezed) Squeeze (Tmp_win); else XMapWindow(dpy, Tmp_win->w); XMapWindow(dpy, Tmp_win->frame); SetMapStateProp(Tmp_win, NormalState); SetRaiseWindow (Tmp_win); Tmp_win->mapped = TRUE; if (Scr->ClickToFocus && Tmp_win->wmhints && Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime); /* kai */ if (Scr->AutoFocusToTransients && Tmp_win->transient && Tmp_win->wmhints && Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime); break; case InactiveState: Tmp_win->mapped = TRUE; if (Tmp_win->UnmapByMovingFarAway) { XMoveWindow (dpy, Tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1); XMapWindow (dpy, Tmp_win->w); XMapWindow (dpy, Tmp_win->frame); } if (Tmp_win->StartSqueezed) Squeeze (Tmp_win); break; case IconicState: zoom_save = Scr->DoZoom; Scr->DoZoom = FALSE; Iconify(Tmp_win, -100, -100); Scr->DoZoom = zoom_save; break; } } /* If no hints, or currently an icon, just "deiconify" */ else { if (1/*OCCUPY (Tmp_win, Scr->workSpaceMgr.activeWSPC)*/) { if (Tmp_win->StartSqueezed) Squeeze (Tmp_win); DeIconify(Tmp_win); SetRaiseWindow (Tmp_win); } else { Tmp_win->mapped = TRUE; } } if (Tmp_win->mapped) WMapMapWindow (Tmp_win); MaybeAnimate = True; } void SimulateMapRequest (Window w) { Event.xmaprequest.window = w; HandleMapRequest (); } /*********************************************************************** * * Procedure: * HandleMapNotify - MapNotify event handler * *********************************************************************** */ void HandleMapNotify(void) { if (Tmp_win == NULL) return; /* * Need to do the grab to avoid race condition of having server send * MapNotify to client before the frame gets mapped; this is bad because * the client would think that the window has a chance of being viewable * when it really isn't. */ XGrabServer (dpy); if (Tmp_win->icon && Tmp_win->icon->w) XUnmapWindow(dpy, Tmp_win->icon->w); if (Tmp_win->title_w) XMapSubwindows(dpy, Tmp_win->title_w); XMapSubwindows(dpy, Tmp_win->frame); if (Scr->Focus != Tmp_win && Tmp_win->hilite_wl) XUnmapWindow(dpy, Tmp_win->hilite_wl); if (Scr->Focus != Tmp_win && Tmp_win->hilite_wr) XUnmapWindow(dpy, Tmp_win->hilite_wr); if (Scr->Focus == Tmp_win && Tmp_win->lolite_wl) XUnmapWindow(dpy, Tmp_win->lolite_wl); if (Scr->Focus == Tmp_win && Tmp_win->lolite_wr) XUnmapWindow(dpy, Tmp_win->lolite_wr); XMapWindow(dpy, Tmp_win->frame); XUngrabServer (dpy); XFlush (dpy); Tmp_win->mapped = TRUE; Tmp_win->isicon = FALSE; Tmp_win->icon_on = FALSE; } /*********************************************************************** * * Procedure: * HandleUnmapNotify - UnmapNotify event handler * *********************************************************************** */ void HandleUnmapNotify(void) { int dstx, dsty; Window dumwin; /* * The July 27, 1988 ICCCM spec states that a client wishing to switch * to WithdrawnState should send a synthetic UnmapNotify with the * event field set to (pseudo-)root, in case the window is already * unmapped (which is the case for twm for IconicState). Unfortunately, * we looked for the TwmContext using that field, so try the window * field also. */ if (Tmp_win == NULL) { Event.xany.window = Event.xunmap.window; Tmp_win = GetTwmWindow(Event.xany.window); } if (Tmp_win == NULL || Event.xunmap.window == Tmp_win->frame || (Tmp_win->icon && Event.xunmap.window == Tmp_win->icon->w) || (!Tmp_win->mapped && !Tmp_win->isicon)) return; /* if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->isicon)) return; */ /* * The program may have unmapped the client window, from either * NormalState or IconicState. Handle the transition to WithdrawnState. * * We need to reparent the window back to the root (so that twm exiting * won't cause it to get mapped) and then throw away all state (pretend * that we've received a DestroyNotify). */ /* Is it the correct behaviour ??? XDeleteProperty (dpy, Tmp_win->w, _XA_WM_OCCUPATION); */ XGrabServer (dpy); if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root, 0, 0, &dstx, &dsty, &dumwin)) { XEvent ev; Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window, ReparentNotify, &ev); SetMapStateProp (Tmp_win, WithdrawnState); if (reparented) { if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy, Event.xunmap.window, Tmp_win->old_bw); if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint)) XUnmapWindow (dpy, Tmp_win->wmhints->icon_window); } else { XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root, dstx, dsty); RestoreWithdrawnLocation (Tmp_win); } XRemoveFromSaveSet (dpy, Event.xunmap.window); XSelectInput (dpy, Event.xunmap.window, NoEventMask); HandleDestroyNotify (); /* do not need to mash event before */ } /* else window no longer exists and we'll get a destroy notify */ XUngrabServer (dpy); XFlush (dpy); } /*********************************************************************** * * Procedure: * HandleMotionNotify - MotionNotify event handler * *********************************************************************** */ void HandleMotionNotify(void) { if (ResizeWindow != (Window) 0) { XQueryPointer( dpy, Event.xany.window, &(Event.xmotion.root), &JunkChild, &(Event.xmotion.x_root), &(Event.xmotion.y_root), &(Event.xmotion.x), &(Event.xmotion.y), &JunkMask); FixRootEvent (&Event); /* Set WindowMoved appropriately so that f.deltastop will work with resize as well as move. */ if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta) WindowMoved = TRUE; Tmp_win = GetTwmWindow(ResizeWindow); if (Tmp_win && Tmp_win->winbox) { XTranslateCoordinates (dpy, Scr->Root, Tmp_win->winbox->window, Event.xmotion.x_root, Event.xmotion.y_root, &(Event.xmotion.x_root), &(Event.xmotion.y_root), &JunkChild); } DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win); } else if (Scr->BorderCursors && Tmp_win && Event.xany.window == Tmp_win->frame) { SetBorderCursor (Tmp_win, Event.xmotion.x, Event.xmotion.y); } } /*********************************************************************** * * Procedure: * HandleButtonRelease - ButtonRelease event handler * *********************************************************************** */ void HandleButtonRelease(void) { int xl, yt, w, h; unsigned mask; #ifdef GNOME if (GnomeProxyButtonPress == Event.xbutton.button) { GnomeProxyButtonPress = -1; XSendEvent (dpy, Scr->currentvs->wsw->w, False, SubstructureNotifyMask, &Event); } #endif /* GNOME */ if (InfoLines) /* delete info box on 2nd button release */ if (Context == C_IDENTIFY) { XUnmapWindow(dpy, Scr->InfoWindow); InfoLines = 0; Context = C_NO_CONTEXT; } if (DragWindow != None) { MoveOutline(Scr->XineramaRoot, 0, 0, 0, 0, 0, 0); Tmp_win = GetTwmWindow(DragWindow); if (Tmp_win->winbox) { XTranslateCoordinates (dpy, Scr->Root, Tmp_win->winbox->window, Event.xbutton.x_root, Event.xbutton.y_root, &(Event.xbutton.x_root), &(Event.xbutton.y_root), &JunkChild); } if (DragWindow == Tmp_win->frame) { xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw; yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw; w = DragWidth + 2 * Tmp_win->frame_bw; h = DragHeight + 2 * Tmp_win->frame_bw; } else { xl = Event.xbutton.x_root - DragX - DragBW; yt = Event.xbutton.y_root - DragY - DragBW; w = DragWidth + 2 * DragBW; h = DragHeight + 2 * DragBW; } if (ConstMove) { if (ConstMoveDir == MOVE_HORIZ) yt = ConstMoveY; if (ConstMoveDir == MOVE_VERT) xl = ConstMoveX; if (ConstMoveDir == MOVE_NONE) { yt = ConstMoveY; xl = ConstMoveX; } } if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) TryToGrid (Tmp_win, &xl, &yt); if (MoveFunction == F_MOVEPUSH && Scr->OpaqueMove && DragWindow == Tmp_win->frame) TryToPush (Tmp_win, xl, yt, 0); if (MoveFunction == F_MOVEPACK || (MoveFunction == F_MOVEPUSH && DragWindow == Tmp_win->frame)) TryToPack (Tmp_win, &xl, &yt); if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) { ConstrainByBorders (Tmp_win, &xl, w, &yt, h); } CurrentDragX = xl; CurrentDragY = yt; /* * sometimes getScreenOf() replies with the wrong window when moving * y to a negative number. Need to figure out why... [XXX] */ if(xl < 0 || yt < 0 || xl > Scr->rootw || yt > Scr->rooth) { int odestx, odesty; int destx, desty; Window cr; virtualScreen *newvs; XTranslateCoordinates(dpy, Tmp_win->vs->window, Scr->XineramaRoot, xl, yt, &odestx, &odesty, &cr); newvs = findIfVScreenOf(odestx, odesty); if(newvs && newvs->wsw && newvs->wsw->currentwspc) { XTranslateCoordinates(dpy, Scr->XineramaRoot, newvs->window, odestx, odesty, &destx, &desty, &cr); AddToWorkSpace(newvs->wsw->currentwspc->name, Tmp_win); RemoveFromWorkSpace(Tmp_win->vs->wsw->currentwspc->name, Tmp_win); xl = destx; yt = desty; } } if (DragWindow == Tmp_win->frame) SetupWindow (Tmp_win, xl, yt, Tmp_win->frame_width, Tmp_win->frame_height, -1); else XMoveWindow (dpy, DragWindow, xl, yt); if (!Scr->NoRaiseMove) /* && !Scr->OpaqueMove) opaque already did */ RaiseFrame(DragWindow); if (!Scr->OpaqueMove) UninstallRootColormap(); else XSync(dpy, 0); if (Scr->NumAutoRaises) { enter_flag = TRUE; enter_win = NULL; raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove) ? Tmp_win : NULL); } /* CCC equivalent code for auto lower not needed? */ #if 0 if (Scr->NumAutoLowers) { leave_flag = TRUE; leave_win = NULL; lower_win = ((DragWindow == Tmp_win->frame) ? Tmp_win : NULL); } #endif DragWindow = (Window) 0; ConstMove = FALSE; } if (ResizeWindow != (Window) 0) { EndResize(); } if (ActiveMenu != NULL && RootFunction == 0) { if (ActiveItem) { int func = ActiveItem->func; Action = ActiveItem->action; switch (func) { case F_TITLE: if (Scr->StayUpMenus) { ButtonPressed = -1; if (Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) { WarpCursorToDefaultEntry (ActiveMenu); } return; } break; case F_MOVE: case F_FORCEMOVE: case F_DESTROY: case F_DELETE: case F_DELETEORDESTROY: ButtonPressed = -1; break; case F_CIRCLEUP: case F_CIRCLEDOWN: case F_REFRESH: case F_WARPTOSCREEN: PopDownMenu(); break; default: break; } if (func != F_PIN && func != F_MENU) PopDownMenu(); ExecuteFunction(func, Action, ButtonWindow ? ButtonWindow->frame : None, ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE); Context = C_NO_CONTEXT; ButtonWindow = NULL; /* if we are not executing a defered command, then take down the * menu */ if (ActiveMenu) PopDownMenu(); } else if (Scr->StayUpMenus && !ActiveMenu->entered) { ButtonPressed = -1; if (Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) { WarpCursorToDefaultEntry (ActiveMenu); } return; } else PopDownMenu(); } mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask); switch (Event.xbutton.button) { case Button1: mask &= ~Button1Mask; break; case Button2: mask &= ~Button2Mask; break; case Button3: mask &= ~Button3Mask; break; case Button4: mask &= ~Button4Mask; break; case Button5: mask &= ~Button5Mask; break; } if (RootFunction != 0 || ResizeWindow != None || DragWindow != None) ButtonPressed = -1; if (AlternateKeymap || AlternateContext) { ButtonPressed = -1; return; } if (RootFunction == 0 && (Event.xbutton.state & mask) == 0 && DragWindow == None && ResizeWindow == None) { XUngrabPointer(dpy, CurrentTime); XUngrabServer(dpy); XFlush(dpy); EventHandler[EnterNotify] = HandleEnterNotify; EventHandler[LeaveNotify] = HandleLeaveNotify; ButtonPressed = -1; if (DownIconManager) { DownIconManager->down = FALSE; if (Scr->Highlight) DrawIconManagerBorder(DownIconManager, False); DownIconManager = NULL; } Cancel = FALSE; } } static void do_menu (MenuRoot *menu, /* menu to pop up */ Window w) /* invoking window or None */ { int x = Event.xbutton.x_root; int y = Event.xbutton.y_root; Bool center; if (!Scr->NoGrabServer) XGrabServer(dpy); if (w) { int h = Scr->TBInfo.width - Scr->TBInfo.border; Window child; (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child); center = False; } else { center = True; } if (PopUpMenu (menu, x, y, center)) { UpdateMenu(); } else { XBell (dpy, 0); } } static void do_key_menu (MenuRoot *menu, /* menu to pop up */ Window w) /* invoking window or None */ { int x = Event.xkey.x_root; int y = Event.xkey.y_root; Bool center; /* I don't think this is necessary. if (!Scr->NoGrabServer) XGrabServer(dpy); */ if (w) { int h = Scr->TBInfo.width - Scr->TBInfo.border; Window child; (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child); center = False; } else { center = True; } if (PopUpMenu (menu, x, y, center)) { UpdateMenu(); } else { XBell (dpy, 0); } } /*********************************************************************** * * Procedure: * HandleButtonPress - ButtonPress event handler * *********************************************************************** */ void HandleButtonPress(void) { unsigned int modifier; Cursor cur; MenuRoot *mr; FuncButton *tmp = 0; int func = 0; Window w; GnomeProxyButtonPress = -1; /* pop down the menu, if any */ if (XFindContext (dpy, Event.xbutton.window, MenuContext, (XPointer *) &mr) != XCSUCCESS) { mr = (MenuRoot*) 0; } if (ActiveMenu && (! ActiveMenu->pinned) && (Event.xbutton.subwindow != ActiveMenu->w)) { PopDownMenu(); return; } if ((ActiveMenu != NULL) && (RootFunction != 0) && (mr != ActiveMenu)) PopDownMenu(); XSync(dpy, 0); /* XXX - remove? */ if (ButtonPressed != -1 && !InfoLines) /* want menus if we have info box */ { /* we got another butt press in addition to one still held * down, we need to cancel the operation we were doing */ Cancel = TRUE; CurrentDragX = origDragX; CurrentDragY = origDragY; if (!menuFromFrameOrWindowOrTitlebar) { if (Scr->OpaqueMove && DragWindow != None) { XMoveWindow (dpy, DragWindow, origDragX, origDragY); } else { MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); } } XUnmapWindow(dpy, Scr->SizeWindow); if (!Scr->OpaqueMove) UninstallRootColormap(); ResizeWindow = None; DragWindow = None; cur = LeftButt; if (Event.xbutton.button == Button2) cur = MiddleButt; else if (Event.xbutton.button >= Button3) cur = RightButt; XGrabPointer(dpy, Scr->Root, True, ButtonReleaseMask | ButtonPressMask, GrabModeAsync, GrabModeAsync, Scr->Root, cur, CurrentTime); return; } else ButtonPressed = Event.xbutton.button; if ((ActiveMenu != NULL) && (ActiveMenu->pinned)) { if (Event.xbutton.window == ActiveMenu->w) { modifier = (Event.xbutton.state & mods_used); modifier = set_mask_ignore (modifier); if ((ActiveItem && (ActiveItem->func == F_TITLE)) || (modifier == 8)) { MoveMenu (&Event); /*ButtonPressed = -1;*/ } } Context = C_ROOT; return; } if (ResizeWindow != None || DragWindow != None || ActiveMenu != NULL) return; /* check the title bar buttons */ if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons) { register int i; register TBWindow *tbw; register TitleButtonFunc *tbf; int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; modifier = Event.xbutton.state & mods_used; modifier = set_mask_ignore (modifier); for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) { if (Event.xany.window == tbw->window) { for (tbf = tbw->info->funs; tbf; tbf = tbf->next) { if (tbf->num == ButtonPressed && tbf->mods == modifier) { switch (tbf->func) { case F_MENU : Context = C_TITLE; ButtonEvent = Event; ButtonWindow = Tmp_win; do_menu (tbf->menuroot, tbw->window); break; default : ExecuteFunction (tbf->func, tbf->action, Event.xany.window, Tmp_win, &Event, C_TITLE, FALSE); } return; } } } } } Context = C_NO_CONTEXT; if (Event.xany.window == Scr->InfoWindow) Context = C_IDENTIFY; if (Event.xany.window == Scr->Root) { if (AlternateContext) { XUngrabPointer (dpy, CurrentTime); XUngrabKeyboard (dpy, CurrentTime); AlternateContext = False; Context = C_ALTERNATE; } else if (AlternateKeymap && Event.xbutton.subwindow) { int dx, dy; Window child; w = Event.xbutton.subwindow; Tmp_win = GetTwmWindow(w); if (Tmp_win) { Event.xany.window = Tmp_win->frame; XTranslateCoordinates (dpy, Scr->Root, Tmp_win->frame, Event.xbutton.x, Event.xbutton.y, &dx, &dy, &child); Event.xbutton.x = dx; Event.xbutton.x = dy; Event.xbutton.subwindow = child; } } else Context = C_ROOT; } if (Tmp_win) { if (Tmp_win->iconmanagerlist && (RootFunction != 0) && ((Event.xany.window == Tmp_win->iconmanagerlist->icon) || (Event.xany.window == Tmp_win->iconmanagerlist->w))) { Tmp_win = Tmp_win->iconmanagerlist->iconmgr->twm_win; if (Tmp_win) { XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w, Event.xbutton.x, Event.xbutton.y, &JunkX, &JunkY, &JunkChild); Event.xbutton.x = JunkX - Tmp_win->frame_bw3D; Event.xbutton.y = JunkY - Tmp_win->title_height - Tmp_win->frame_bw3D; Event.xany.window = Tmp_win->w; Context = C_WINDOW; } } else if (Event.xany.window == Tmp_win->title_w) { if (Scr->ClickToFocus && Tmp_win->wmhints && Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime); Context = C_TITLE; } else if (Event.xany.window == Tmp_win->w) { if (Scr->ClickToFocus || Scr->RaiseOnClick) { if (Scr->ClickToFocus && Tmp_win->wmhints && Tmp_win->wmhints->input) { SetFocus (Tmp_win, CurrentTime); } if (Scr->RaiseOnClick) { RaiseWindow (Tmp_win); WMapRaise (Tmp_win); } XSync (dpy, 0); XAllowEvents (dpy, ReplayPointer, CurrentTime); XSync (dpy, 0); ButtonPressed = -1; return; } else { printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n"); Context = C_WINDOW; } } else if (Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w)) { Context = C_ICON; } else if (Event.xany.window == Tmp_win->frame) { /* since we now place a button grab on the frame instead * of the window, (see GrabButtons() in add_window.c), we * need to figure out where the pointer exactly is before * assigning Context. If the pointer is on the application * window we will change the event structure to look as if * it came from the application window. */ if (Event.xbutton.subwindow == Tmp_win->w) { XTranslateCoordinates (dpy, Event.xany.window, Tmp_win->w, Event.xbutton.x, Event.xbutton.y, &Event.xbutton.x, &Event.xbutton.y, &JunkChild); Event.xbutton.window = Tmp_win->w; if (Tmp_win->iswinbox && JunkChild) { XTranslateCoordinates (dpy, Tmp_win->w, JunkChild, Event.xbutton.x, Event.xbutton.y, &JunkX, &JunkY, &JunkChild); if (JunkChild && (Tmp_win = GetTwmWindow(JunkChild))) { Event.xany.window = JunkChild; Event.xbutton.x = JunkX; Event.xbutton.y = JunkY; } } Context = C_WINDOW; } else if (Event.xbutton.subwindow && (Event.xbutton.subwindow == Tmp_win->title_w)) { Context = C_TITLE; } else { Context = C_FRAME; } if (Scr->ClickToFocus && Tmp_win->wmhints && Tmp_win->wmhints->input) SetFocus (Tmp_win, CurrentTime); } else if (Tmp_win->wspmgr || (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) { Context = C_WINDOW; } else if (Tmp_win->iconmanagerlist) { if ((Event.xany.window == Tmp_win->iconmanagerlist->icon) || (Event.xany.window == Tmp_win->iconmanagerlist->w)) { Tmp_win->iconmanagerlist->down = TRUE; if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->iconmanagerlist, False); DownIconManager = Tmp_win->iconmanagerlist; Context = C_ICONMGR; } } } /* this section of code checks to see if we were in the middle of * a command executed from a menu */ if (RootFunction != 0) { if (Event.xany.window == Scr->Root) { Window win; /* if the window was the Root, we don't know for sure it * it was the root. We must check to see if it happened to be * inside of a client that was getting button press events. */ XTranslateCoordinates(dpy, Scr->Root, Scr->Root, Event.xbutton.x, Event.xbutton.y, &JunkX, &JunkY, &Event.xany.window); if (Event.xany.window != 0 && (Tmp_win = GetTwmWindow(Event.xany.window))) { if (Tmp_win && Tmp_win->iswinbox) { XTranslateCoordinates (dpy, Scr->Root, Event.xany.window, JunkX, JunkY, &JunkX, &JunkY, &win); XTranslateCoordinates (dpy, Event.xany.window, win, JunkX, JunkY, &JunkX, &JunkY, &win); if (win != 0) Event.xany.window = win; } } if (Event.xany.window == 0 || !(Tmp_win = GetTwmWindow(Event.xany.window))) { RootFunction = 0; XBell(dpy, 0); return; } XTranslateCoordinates(dpy, Scr->Root, Event.xany.window, Event.xbutton.x, Event.xbutton.y, &JunkX, &JunkY, &JunkChild); Event.xbutton.x = JunkX; Event.xbutton.y = JunkY; Context = C_WINDOW; } else if (mr != (MenuRoot*) 0) { RootFunction = 0; XBell(dpy, 0); return; } /* make sure we are not trying to move an identify window */ if (Event.xany.window != Scr->InfoWindow) ExecuteFunction(RootFunction, Action, Event.xany.window, Tmp_win, &Event, Context, FALSE); RootFunction = 0; return; } ButtonEvent = Event; ButtonWindow = Tmp_win; /* if we get to here, we have to execute a function or pop up a * menu */ modifier = (Event.xbutton.state | AlternateKeymap) & mods_used; modifier = set_mask_ignore (modifier); if (AlternateKeymap) { XUngrabPointer (dpy, CurrentTime); XUngrabKeyboard (dpy, CurrentTime); AlternateKeymap = 0; } if ((Context == C_NO_CONTEXT) || (Context == C_IDENTIFY)) return; RootFunction = 0; /* see if there already is a key defined for this context */ for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) { if ((tmp->num == Event.xbutton.button) && (tmp->cont == Context) && (tmp->mods == modifier)) break; } if (tmp) { func = tmp->func; switch (func) { case F_MENU : do_menu (tmp->menu, (Window) None); break; default : if (func != 0) { Action = tmp->item ? tmp->item->action : NULL; ExecuteFunction (func, Action, Event.xany.window, Tmp_win, &Event, Context, FALSE); } } } else { if (Tmp_win == Scr->currentvs->wsw->twm_win) { WMgrHandleButtonEvent (Scr->currentvs, &Event); return; } } if (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) { OccupyHandleButtonEvent (&Event); } else if (func == 0 && Scr->DefaultFunction.func != 0) { if (Scr->DefaultFunction.func == F_MENU) { do_menu (Scr->DefaultFunction.menu, (Window) None); } else { Action = Scr->DefaultFunction.item ? Scr->DefaultFunction.item->action : NULL; ExecuteFunction(Scr->DefaultFunction.func, Action, Event.xany.window, Tmp_win, &Event, Context, FALSE); } } #ifdef GNOME1 /* Makes DeferExecution (in menus.c) fail. TODO. */ else { /* GNOME: Pass on the event to any applications listening for root window clicks */ GnomeProxyButtonPress = Event.xbutton.button; ButtonPressed = -1; XUngrabPointer (dpy, CurrentTime); XSendEvent (dpy, Scr->currentvs->wsw->twm_win->w, False, SubstructureNotifyMask, &Event); } #endif /* GNOME1 */ } /*********************************************************************** * * Procedure: * HENQueueScanner - EnterNotify event q scanner * * Looks at the queued events and determines if any matching * LeaveNotify events or EnterEvents deriving from the * termination of a grab are behind this event to allow * skipping of unnecessary processing. * *********************************************************************** */ typedef struct HENScanArgs { Window w; /* Window we are currently entering */ Bool leaves; /* Any LeaveNotifies found for this window */ Bool inferior; /* Was NotifyInferior the mode for LeaveNotify */ Bool enters; /* Any EnterNotify events with NotifyUngrab */ } HENScanArgs; /* ARGSUSED*/ static Bool HENQueueScanner(Display *display, XEvent *ev, char *_args) { HENScanArgs *args = (void *)_args; if (ev->type == LeaveNotify) { if (ev->xcrossing.window == args->w && ev->xcrossing.mode == NotifyNormal) { args->leaves = True; /* * Only the last event found matters for the Inferior field. */ args->inferior = (ev->xcrossing.detail == NotifyInferior); } } else if (ev->type == EnterNotify) { if (ev->xcrossing.mode == NotifyUngrab) args->enters = True; } return (False); } /*********************************************************************** * * Procedure: * HandleEnterNotify - EnterNotify event handler * *********************************************************************** */ void HandleEnterNotify(void) { MenuRoot *mr, *tmp; XEnterWindowEvent *ewp = &Event.xcrossing; HENScanArgs scanArgs; XEvent dummy; virtualScreen *vs; /* * if we aren't in the middle of menu processing */ if (!ActiveMenu) { /* * We're not interested in pseudo Enter/Leave events generated * from grab initiations. */ if (ewp->mode == NotifyGrab) return; /* * Scan for Leave and Enter Notify events to see if we can avoid some * unnecessary processing. */ scanArgs.w = ewp->window; scanArgs.leaves = scanArgs.enters = False; (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs); /* * if entering root window, restore twm default colormap so that * titlebars are legible */ if (ewp->window == Scr->Root) { Window forus_ret; int focus_rev; if (!scanArgs.leaves && !scanArgs.enters) { InstallColormaps(EnterNotify, &Scr->RootColormaps); } if (! Scr->FocusRoot) return; XGetInputFocus (dpy, &forus_ret, &focus_rev); if ((forus_ret != PointerRoot) && (forus_ret != None)) { SetFocus ((TwmWindow *) NULL, Event.xcrossing.time); } return; } for (vs = Scr->vScreenList; vs != NULL; vs = vs->next) { if (ewp->window == vs->window) { Scr->Root = vs->window; Scr->rootx = Scr->crootx + vs->x; Scr->rooty = Scr->crooty + vs->y; Scr->rootw = vs->w; Scr->rooth = vs->h; Scr->currentvs = vs; /*fprintf (stderr, "entering new vs : 0x%x, 0x%x, %d, %d, %d, %d\n", vs, Scr->Root, vs->x, vs->y, vs->w, vs->h);*/ return; } } /* Handle RaiseDelay, if any..... */ if (RaiseDelay > 0) { if (Tmp_win && Tmp_win->auto_raise && (!Tmp_win->iconmanagerlist || Tmp_win->iconmanagerlist->w != ewp->window)) { ColormapWindow *cwin; #ifdef VMS float timeout = 0.0125; #else static struct timeval tout, timeout = {0,12500}; #endif if (XFindContext(dpy, Tmp_win->w, ColormapContext, (XPointer *)&cwin) == XCNOENT) { cwin = (ColormapWindow *)NULL; } if ((ewp->detail != NotifyInferior || Tmp_win->frame == ewp->window) && (!cwin || cwin->visibility != VisibilityUnobscured)) { int x, y, px, py, d, i; Window w; XQueryPointer(dpy, Scr->Root, &w, &w, &px, &py, &d, &d, (unsigned int *)&d); /* The granularity of RaiseDelay is about 25 ms. * The timeout variable is set to 12.5 ms since we * pass this way twice each time a twm window is * entered. */ for (i = 25; i < RaiseDelay; i += 25) { #ifdef VMS lib$wait(&timeout); #else tout = timeout; select(0, 0, 0, 0, &tout); #endif /* Did we leave this window already? */ scanArgs.w = ewp->window; scanArgs.leaves = scanArgs.enters = False; (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs); if (scanArgs.leaves && !scanArgs.inferior) return; XQueryPointer(dpy, Scr->Root, &w, &w, &x, &y, &d, &d, (unsigned int *)&d); /* Has the pointer moved? If so reset the loop cnt. * We want the pointer to be still for RaiseDelay * milliseconds before terminating the loop */ if (x != px || y != py) { i = 0; px = x; py = y; } } } } /* * Scan for Leave and Enter Notify events to see if we can avoid some * unnecessary processing. */ scanArgs.w = ewp->window; scanArgs.leaves = scanArgs.enters = False; (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs); /* * if entering root window, restore twm default colormap so that * titlebars are legible */ if (ewp->window == Scr->Root) { if (!scanArgs.leaves && !scanArgs.enters) { InstallColormaps(EnterNotify, &Scr->RootColormaps); } return; } } /* End of RaiseDelay modification. */ /* * if we have an event for a specific one of our windows */ if (Tmp_win) { /* * If currently in PointerRoot mode (indicated by FocusRoot), then * focus on this window */ if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) { Bool accinput; if (Scr->ShrinkIconTitles && Tmp_win->icon && ewp->window == Tmp_win->icon->w && ewp->detail != NotifyInferior) { if (Scr->AutoRaiseIcons) XRaiseWindow (dpy, Tmp_win->icon->w); ExpandIconTitle (Tmp_win); return; } if (Tmp_win->iconmanagerlist) CurrentIconManagerEntry (Tmp_win->iconmanagerlist); accinput = Tmp_win->mapped && Tmp_win->wmhints && Tmp_win->wmhints->input; if (Tmp_win->iconmanagerlist && ewp->window == Tmp_win->iconmanagerlist->w && !accinput && Tmp_win->iconmanagerlist->iconmgr && Tmp_win->iconmanagerlist->iconmgr->twm_win) { SetFocus(Tmp_win->iconmanagerlist->iconmgr->twm_win, CurrentTime); return; } if (Tmp_win->mapped) { /* * unhighlight old focus window */ /* * If entering the frame or the icon manager, then do * "window activation things": * * 1. * 2. install frame colormap * 3. * 4. focus on client window to forward typing * 4a. same as 4 but for icon mgr w/with NoTitleFocus * 5. send WM_TAKE_FOCUS if requested */ if (Scr->BorderCursors && ewp->window == Tmp_win->frame) { SetBorderCursor (Tmp_win, ewp->x, ewp->y); } if (ewp->window == Tmp_win->frame || (Scr->IconManagerFocus && Tmp_win->iconmanagerlist && ewp->window == Tmp_win->iconmanagerlist->w)) { if (!scanArgs.leaves && !scanArgs.enters) { InstallColormaps (EnterNotify, /* 2 */ &Scr->RootColormaps); } /* * Event is in the frame or the icon mgr: * * "4" -- TitleFocus is set: windows should get * focus as long as they accept input. * * "4a" - If TitleFocus is not set, windows should get * the focus if the event was in the icon mgr * (as long as they accept input). * */ /* If the window takes input... */ if (Tmp_win->wmhints && Tmp_win->wmhints->input) { /* if 4 or 4a, focus on the window */ if (Scr->TitleFocus || (Tmp_win->iconmanagerlist && (Tmp_win->iconmanagerlist->w == ewp->window))) { SetFocus (Tmp_win, ewp->time); } } if (Scr->TitleFocus && (Tmp_win->protocols & DoesWmTakeFocus)){ /* 5 */ /* for both locally or globally active */ SendTakeFocusMessage (Tmp_win, ewp->time); } else if (!Scr->TitleFocus && Tmp_win->wmhints && Tmp_win->wmhints->input && Event.xcrossing.focus) { SynthesiseFocusIn(Tmp_win->w); } } else if (ewp->window == Tmp_win->w) { /* * If we are entering the application window, install * its colormap(s). */ if (Scr->BorderCursors) SetBorderCursor (Tmp_win, -1000, -1000); if (!scanArgs.leaves || scanArgs.inferior) { InstallWindowColormaps(EnterNotify, Tmp_win); } if (Event.xcrossing.focus) { SynthesiseFocusIn(Tmp_win->w); } /* must deal with WM_TAKE_FOCUS clients now, if we're not in TitleFocus mode */ if (!(Scr->TitleFocus) && (Tmp_win->protocols & DoesWmTakeFocus)) { /* locally active clients need help from WM to get the input focus */ if (Tmp_win->wmhints && Tmp_win->wmhints->input) SetFocus(Tmp_win, ewp->time); /* for both locally & globally active clnts */ SendTakeFocusMessage(Tmp_win, ewp->time); } } } /* end if Tmp_win->mapped */ if (Tmp_win->wmhints != NULL && ewp->window == Tmp_win->wmhints->icon_window && (!scanArgs.leaves || scanArgs.inferior)) { InstallWindowColormaps(EnterNotify, Tmp_win); } } /* end if FocusRoot */ else if (Scr->BorderCursors && (ewp->window == Tmp_win->w)) { SetBorderCursor (Tmp_win, -1000, -1000); } /* * If this window is to be autoraised, mark it so */ if (Tmp_win->auto_raise) { enter_win = Tmp_win; if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win); } else if (enter_flag && raise_win == Tmp_win) enter_win = Tmp_win; /* * set ring leader */ if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win)) Scr->RingLeader = Tmp_win; XSync (dpy, 0); return; } /* end if Tmp_win */ } /* end if !ActiveMenu */ /* * Find the menu that we are dealing with now; punt if unknown */ if (XFindContext (dpy, ewp->window, MenuContext, (XPointer *)&mr) != XCSUCCESS) return; if (! ActiveMenu && mr->pinned && (RootFunction == 0)) { PopUpMenu (mr, 0, 0, 0); Context = C_ROOT; UpdateMenu (); return; } mr->entered = TRUE; if (RootFunction == 0) { for (tmp = ActiveMenu; tmp; tmp = tmp->prev) { if (tmp == mr) break; } if (! tmp) return; for (tmp = ActiveMenu; tmp != mr; tmp = tmp->prev) { if (tmp->pinned) break; HideMenu (tmp); MenuDepth--; } UninstallRootColormap (); if (ActiveItem) { ActiveItem->state = 0; PaintEntry (ActiveMenu, ActiveItem, False); } ActiveItem = NULL; ActiveMenu = mr; if (1/*Scr->StayUpMenus*/) { int i, x, y, x_root, y_root, entry; MenuItem *mi; XQueryPointer (dpy, ActiveMenu->w, &JunkRoot, &JunkChild, &x_root, &y_root, &x, &y, &JunkMask); if ((x > 0) && (y > 0) && (x < ActiveMenu->width) && (y < ActiveMenu->height)) { entry = y / Scr->EntryHeight; for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next) { if (i == entry) break; } if (mi) { ActiveItem = mi; ActiveItem->state = 1; PaintEntry (ActiveMenu, ActiveItem, False); } } } if (ActiveMenu->pinned) XUngrabPointer(dpy, CurrentTime); } return; } /*********************************************************************** * * Procedure: * HLNQueueScanner - LeaveNotify event q scanner * * Looks at the queued events and determines if any * EnterNotify events are behind this event to allow * skipping of unnecessary processing. * *********************************************************************** */ typedef struct HLNScanArgs { Window w; /* The window getting the LeaveNotify */ Bool enters; /* Any EnterNotify event at all */ Bool matches; /* Any matching EnterNotify events */ } HLNScanArgs; /* ARGSUSED*/ static Bool HLNQueueScanner(Display *display, XEvent *ev, char *_args) { HLNScanArgs *args = (void *)_args; if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) { args->enters = True; if (ev->xcrossing.window == args->w) args->matches = True; } return (False); } /*********************************************************************** * * Procedure: * HandleLeaveNotify - LeaveNotify event handler * *********************************************************************** */ void HandleLeaveNotify(void) { HLNScanArgs scanArgs; XEvent dummy; if (ActiveMenu && ActiveMenu->pinned && (Event.xcrossing.window == ActiveMenu->w)) { PopDownMenu (); } if (Tmp_win != NULL) { Bool inicon; /* * We're not interested in pseudo Enter/Leave events generated * from grab initiations and terminations. */ if (Event.xcrossing.mode != NotifyNormal) return; if (Scr->ShrinkIconTitles && Tmp_win->icon && Event.xcrossing.window == Tmp_win->icon->w && Event.xcrossing.detail != NotifyInferior) { ShrinkIconTitle (Tmp_win); return; } inicon = (Tmp_win->iconmanagerlist && Tmp_win->iconmanagerlist->w == Event.xcrossing.window); if (Scr->RingLeader && Scr->RingLeader == Tmp_win && (Event.xcrossing.detail != NotifyInferior && Event.xcrossing.window != Tmp_win->w)) { #ifdef DEBUG fprintf(stderr, "HandleLeaveNotify: Event.xcrossing.window %x != Tmp_win->w %x\n", Event.xcrossing.window, Tmp_win->w); #endif if (!inicon) { if (Event.xcrossing.window != Tmp_win->frame /*was: Tmp_win->mapped*/) { Tmp_win->ring.cursor_valid = False; #ifdef DEBUG fprintf(stderr, "HandleLeaveNotify: cursor_valid = False\n"); #endif } else { /* Event.xcrossing.window == Tmp_win->frame */ Tmp_win->ring.cursor_valid = True; Tmp_win->ring.curs_x = (Event.xcrossing.x_root - Tmp_win->frame_x); Tmp_win->ring.curs_y = (Event.xcrossing.y_root - Tmp_win->frame_y); #ifdef DEBUG fprintf(stderr, "HandleLeaveNotify: cursor_valid = True; x = %d (%d-%d), y = %d (%d-%d)\n", Tmp_win->ring.curs_x, Event.xcrossing.x_root, Tmp_win->frame_x, Tmp_win->ring.curs_y, Event.xcrossing.y_root, Tmp_win->frame_y); #endif } } Scr->RingLeader = (TwmWindow *) NULL; } if (Scr->FocusRoot) { if (Event.xcrossing.detail != NotifyInferior) { /* * Scan for EnterNotify events to see if we can avoid some * unnecessary processing. */ scanArgs.w = Event.xcrossing.window; scanArgs.enters = scanArgs.matches = False; (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner, (char *) &scanArgs); if (Event.xcrossing.window == Tmp_win->frame && !scanArgs.matches) { if (Scr->TitleFocus || Tmp_win->protocols & DoesWmTakeFocus) SetFocus ((TwmWindow *) NULL, Event.xcrossing.time); /* pretend there was a focus out as sometimes * we don't get one. */ if ( Event.xcrossing.focus) SynthesiseFocusOut(Tmp_win->w); } else if (Scr->IconManagerFocus && inicon) { if (! Tmp_win->mapped || ! Tmp_win->wmhints || ! Tmp_win->wmhints->input) { return; } if (Scr->TitleFocus || Tmp_win->protocols & DoesWmTakeFocus) SetFocus ((TwmWindow *) NULL, Event.xcrossing.time); if (Event.xcrossing.focus) SynthesiseFocusOut (Tmp_win->w); } else if (Event.xcrossing.window == Tmp_win->w && !scanArgs.enters) { InstallColormaps(LeaveNotify, &Scr->RootColormaps); } } } /* Autolower modification. */ if (Tmp_win->auto_lower) { leave_win = Tmp_win; if (leave_flag == FALSE) AutoLowerWindow (Tmp_win); } else if (leave_flag && lower_win == Tmp_win) leave_win = Tmp_win; XSync (dpy, 0); return; } } /*********************************************************************** * * Procedure: * HandleConfigureRequest - ConfigureRequest event handler * *********************************************************************** */ void HandleConfigureRequest(void) { XWindowChanges xwc; unsigned long xwcm; int x, y, width, height, bw; int gravx, gravy; XConfigureRequestEvent *cre = &Event.xconfigurerequest; Bool sendEvent; #ifdef DEBUG_EVENTS fprintf(stderr, "ConfigureRequest\n"); if (cre->value_mask & CWX) fprintf(stderr, " x = %d\n", cre->x); if (cre->value_mask & CWY) fprintf(stderr, " y = %d\n", cre->y); if (cre->value_mask & CWWidth) fprintf(stderr, " width = %d\n", cre->width); if (cre->value_mask & CWHeight) fprintf(stderr, " height = %d\n", cre->height); if (cre->value_mask & CWSibling) fprintf(stderr, " above = 0x%x\n", cre->above); if (cre->value_mask & CWStackMode) fprintf(stderr, " stack = %d\n", cre->detail); #endif /* * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will * be wrong */ Event.xany.window = cre->window; /* mash parent field */ Tmp_win = GetTwmWindow(cre->window); /* * According to the July 27, 1988 ICCCM draft, we should ignore size and * position fields in the WM_NORMAL_HINTS property when we map a window. * Instead, we'll read the current geometry. Therefore, we should respond * to configuration requests for windows which have never been mapped. */ if (!Tmp_win || (Tmp_win->icon && (Tmp_win->icon->w == cre->window))) { xwcm = cre->value_mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); xwc.x = cre->x; xwc.y = cre->y; xwc.width = cre->width; xwc.height = cre->height; xwc.border_width = cre->border_width; XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc); return; } sendEvent = False; if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) { TwmWindow *otherwin; xwc.sibling = (((cre->value_mask & CWSibling) && (otherwin = GetTwmWindow(cre->above))) ? otherwin->frame : cre->above); xwc.stack_mode = cre->detail; XConfigureWindow (dpy, Tmp_win->frame, cre->value_mask & (CWSibling | CWStackMode), &xwc); sendEvent = True; } /* Don't modify frame_XXX fields before calling SetupWindow! */ x = Tmp_win->frame_x; y = Tmp_win->frame_y; width = Tmp_win->frame_width; height = Tmp_win->frame_height; bw = Tmp_win->frame_bw; /* * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the * configure request are for the upper-left outer corner of the window. * This means that we need to adjust for the additional title height as * well as for any border width changes that we decide to allow. The * current window gravity is to be used in computing the adjustments, just * as when initially locating the window. Note that if we do decide to * allow border width changes, we will need to send the synthetic * ConfigureNotify event. */ GetGravityOffsets (Tmp_win, &gravx, &gravy); if (cre->value_mask & CWBorderWidth) { int bwdelta = cre->border_width - Tmp_win->old_bw; /* posit growth */ if (bwdelta && Scr->ClientBorderWidth) { /* if change allowed */ x += gravx * bwdelta; /* change default values only */ y += gravy * bwdelta; /* ditto */ bw = cre->border_width; if (Tmp_win->title_height) height += bwdelta; x += (gravx < 0) ? bwdelta : -bwdelta; y += (gravy < 0) ? bwdelta : -bwdelta; } Tmp_win->old_bw = cre->border_width; /* for restoring */ } if (cre->value_mask & CWX) { /* override even if border change */ x = cre->x - bw; x -= ((gravx < 0) ? 0 : Tmp_win->frame_bw3D); } if (cre->value_mask & CWY) { y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw; y -= ((gravy < 0) ? 0 : Tmp_win->frame_bw3D); } if (cre->value_mask & CWWidth) { width = cre->width + 2 * Tmp_win->frame_bw3D; } if (cre->value_mask & CWHeight) { height = cre->height + Tmp_win->title_height + 2 * Tmp_win->frame_bw3D; } if (width != Tmp_win->frame_width || height != Tmp_win->frame_height) Tmp_win->zoomed = ZOOM_NONE; /* Workaround for Java 1.4 bug that freezes the application whenever * a new window is displayed. (When UsePPosition is on and either * UseThreeDBorders or BorderWidth 0 is set.) */ if (!bw) sendEvent = True; /* * SetupWindow (x,y) are the location of the upper-left outer corner and * are passed directly to XMoveResizeWindow (frame). The (width,height) * are the inner size of the frame. The inner width is the same as the * requested client window width; the inner height is the same as the * requested client window height plus any title bar slop. */ SetupFrame (Tmp_win, x, y, width, height, bw, sendEvent); } /*********************************************************************** * * Procedure: * HandleShapeNotify - shape notification event handler * *********************************************************************** */ void HandleShapeNotify (void) { XShapeEvent *sev = (XShapeEvent *) &Event; if (Tmp_win == NULL) return; if (sev->kind != ShapeBounding) return; if (!Tmp_win->wShaped && sev->shaped) { XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None, ShapeSet); } Tmp_win->wShaped = sev->shaped; SetFrameShape (Tmp_win); } /*********************************************************************** * * Procedure: * HandleUnknown - unknown event handler * *********************************************************************** */ void HandleUnknown(void) { #ifdef DEBUG_EVENTS fprintf(stderr, "type = %d\n", Event.type); #endif } /*********************************************************************** * * Procedure: * Transient - checks to see if the window is a transient * * Returned Value: * TRUE - window is a transient * FALSE - window is not a transient * * Inputs: * w - the window to check * *********************************************************************** */ int Transient(Window w, Window *propw) { return (XGetTransientForHint(dpy, w, propw)); } /*********************************************************************** * * Procedure: * FindScreenInfo - get ScreenInfo struct associated with a given window * * Returned Value: * ScreenInfo struct * * Inputs: * w - the window * *********************************************************************** */ ScreenInfo *FindScreenInfo(Window w) { XWindowAttributes attr; int scrnum; attr.screen = NULL; if (XGetWindowAttributes(dpy, w, &attr)) { for (scrnum = 0; scrnum < NumScreens; scrnum++) { if (ScreenList[scrnum] != NULL && (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) == attr.screen)) return ScreenList[scrnum]; } } return NULL; } static void flush_expose (Window w) { XEvent dummy; /* SUPPRESS 530 */ while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ; } /*********************************************************************** * * Procedure: * InstallWindowColormaps - install the colormaps for one twm window * * Inputs: * type - type of event that caused the installation * tmp - for a subset of event types, the address of the * window structure, whose colormaps are to be installed. * *********************************************************************** */ int InstallWindowColormaps (int type, TwmWindow *tmp) { if (tmp) { return InstallColormaps (type, &tmp->cmaps); } else { return InstallColormaps (type, NULL); } } int InstallColormaps (int type, Colormaps *cmaps) { int i, j, n, number_cwins, state; ColormapWindow **cwins, *cwin, **maxcwin = NULL; TwmColormap *cmap; char *row, *scoreboard; switch (type) { case EnterNotify: case LeaveNotify: case DestroyNotify: default: /* Save the colormap to be loaded for when force loading of * root colormap(s) ends. */ Scr->cmapInfo.pushed_cmaps = cmaps; /* Don't load any new colormap if root colormap(s) has been * force loaded. */ if (Scr->cmapInfo.root_pushes) return (0); /* Don't reload the current window colormap list. if (Scr->cmapInfo.cmaps == cmaps) return (0); */ if (Scr->cmapInfo.cmaps) { for (i = Scr->cmapInfo.cmaps->number_cwins, cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++) { (*cwins)->colormap->state &= ~CM_INSTALLABLE; } } Scr->cmapInfo.cmaps = cmaps; break; case PropertyNotify: case VisibilityNotify: case ColormapNotify: break; } number_cwins = Scr->cmapInfo.cmaps->number_cwins; cwins = Scr->cmapInfo.cmaps->cwins; scoreboard = Scr->cmapInfo.cmaps->scoreboard; ColortableThrashing = FALSE; /* in case installation aborted */ state = CM_INSTALLED; for (i = n = 0; i < number_cwins; i++) { cwins[i]->colormap->state &= ~CM_INSTALL; } for (i = n = 0; i < number_cwins && n < Scr->cmapInfo.maxCmaps; i++) { cwin = cwins[i]; cmap = cwin->colormap; if (cmap->state & CM_INSTALL) continue; cmap->state |= CM_INSTALLABLE; cmap->w = cwin->w; if (cwin->visibility != VisibilityFullyObscured) { row = scoreboard + (i*(i-1)/2); for (j = 0; j < i; j++) if (row[j] && (cwins[j]->colormap->state & CM_INSTALL)) break; if (j != i) continue; n++; maxcwin = &cwins[i]; state &= (cmap->state & CM_INSTALLED); cmap->state |= CM_INSTALL; } } Scr->cmapInfo.first_req = NextRequest(dpy); for ( ; n > 0 && maxcwin >= &cwins[0]; maxcwin--) { cmap = (*maxcwin)->colormap; if (cmap->state & CM_INSTALL) { cmap->state &= ~CM_INSTALL; if (!(state & CM_INSTALLED)) { cmap->install_req = NextRequest(dpy); /* printf ("XInstallColormap : %x, %x\n", cmap, cmap->c); */ XInstallColormap(dpy, cmap->c); } cmap->state |= CM_INSTALLED; n--; } } return (1); } /*********************************************************************** * * Procedures: * nstallRootColormap - Force (un)loads root colormap(s) * * These matching routines provide a mechanism to insure that * the root colormap(s) is installed during operations like * rubber banding or menu display that require colors from * that colormap. Calls may be nested arbitrarily deeply, * as long as there is one UninstallRootColormap call per * InstallRootColormap call. * * The final UninstallRootColormap will cause the colormap list * which would otherwise have be loaded to be loaded, unless * Enter or Leave Notify events are queued, indicating some * other colormap list would potentially be loaded anyway. *********************************************************************** */ void InstallRootColormap(void) { Colormaps *tmp; if (Scr->cmapInfo.root_pushes == 0) { /* * The saving and restoring of cmapInfo.pushed_window here * is a slimy way to remember the actual pushed list and * not that of the root window. */ tmp = Scr->cmapInfo.pushed_cmaps; InstallColormaps(0, &Scr->RootColormaps); Scr->cmapInfo.pushed_cmaps = tmp; } Scr->cmapInfo.root_pushes++; } /* ARGSUSED*/ static Bool UninstallRootColormapQScanner(Display *display, XEvent *ev, char *args) { if (!*args) { if (ev->type == EnterNotify) { if (ev->xcrossing.mode != NotifyGrab) *args = 1; } else if (ev->type == LeaveNotify) { if (ev->xcrossing.mode == NotifyNormal) *args = 1; } } return (False); } void UninstallRootColormap(void) { char args; XEvent dummy; if (Scr->cmapInfo.root_pushes) Scr->cmapInfo.root_pushes--; if (!Scr->cmapInfo.root_pushes) { /* * If we have subsequent Enter or Leave Notify events, * we can skip the reload of pushed colormaps. */ XSync (dpy, 0); args = 0; (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args); if (!args) InstallColormaps(0, Scr->cmapInfo.pushed_cmaps); } } void ConfigureRootWindow (XEvent *ev) { Window root, child; int x, y; unsigned int w, h, bw, d, oldw, oldh; XGetGeometry (dpy, Scr->CaptiveRoot, &root, &x, &y, &w, &h, &bw, &d); XTranslateCoordinates (dpy, Scr->CaptiveRoot, root, 0, 0, &Scr->crootx, &Scr->crooty, &child); oldw = Scr->crootw; oldh = Scr->crooth; Scr->crootw = ev->xconfigure.width; Scr->crooth = ev->xconfigure.height; /* fprintf (stderr, "ConfigureRootWindow: cx = %d, cy = %d, cw = %d, ch = %d\n", Scr->crootx, Scr->crooty, Scr->crootw, Scr->crooth); */ if (Scr->currentvs) { Scr->rootx = Scr->crootx + Scr->currentvs->x; Scr->rooty = Scr->crooty + Scr->currentvs->y; } Scr->rootw = Scr->crootw; Scr->rooth = Scr->crooth; if (captive && ((Scr->crootw != oldw) || (Scr->crooth != oldh))) { twmrc_error_prefix (); fprintf (stderr, "You cannot change root window geometry with virtual screens active,\n"); fprintf (stderr, "from now on, the ctwm behaviour is unpredictable.\n"); } } static void dumpevent (XEvent *e) { char *name = "Unknown event"; if (! tracefile) return; switch (e->type) { case KeyPress: name = "KeyPress"; break; case KeyRelease: name = "KeyRelease"; break; case ButtonPress: name = "ButtonPress"; break; case ButtonRelease: name = "ButtonRelease"; break; case MotionNotify: name = "MotionNotify"; break; case EnterNotify: name = "EnterNotify"; break; case LeaveNotify: name = "LeaveNotify"; break; case FocusIn: name = "FocusIn"; break; case FocusOut: name = "FocusOut"; break; case KeymapNotify: name = "KeymapNotify"; break; case Expose: name = "Expose"; break; case GraphicsExpose: name = "GraphicsExpose"; break; case NoExpose: name = "NoExpose"; break; case VisibilityNotify: name = "VisibilityNotify"; break; case CreateNotify: name = "CreateNotify"; break; case DestroyNotify: name = "DestroyNotify"; break; case UnmapNotify: name = "UnmapNotify"; break; case MapNotify: name = "MapNotify"; break; case MapRequest: name = "MapRequest"; break; case ReparentNotify: name = "ReparentNotify"; break; case ConfigureNotify: name = "ConfigureNotify"; break; case ConfigureRequest: name = "ConfigureRequest"; break; case GravityNotify: name = "GravityNotify"; break; case ResizeRequest: name = "ResizeRequest"; break; case CirculateNotify: name = "CirculateNotify"; break; case CirculateRequest: name = "CirculateRequest"; break; case PropertyNotify: name = "PropertyNotify"; break; case SelectionClear: name = "SelectionClear"; break; case SelectionRequest: name = "SelectionRequest"; break; case SelectionNotify: name = "SelectionNotify"; break; case ColormapNotify: name = "ColormapNotify"; break; case ClientMessage: name = "ClientMessage"; break; case MappingNotify: name = "MappingNotify"; break; } fprintf (tracefile, "event: %s in window 0x%x\n", name, (unsigned int)e->xany.window); switch (e->type) { case KeyPress: case KeyRelease: fprintf (tracefile, " : +%d,+%d (+%d,+%d) state=%d, keycode=%d\n", e->xkey.x, e->xkey.y, e->xkey.x_root, e->xkey.y_root, e->xkey.state, e->xkey.keycode); break; case ButtonPress: case ButtonRelease: fprintf (tracefile, " : +%d,+%d (+%d,+%d) state=%d, button=%d\n", e->xbutton.x, e->xbutton.y, e->xbutton.x_root, e->xbutton.y_root, e->xbutton.state, e->xbutton.button); break; } }