10bbfda8aSnia/*
20bbfda8aSnia *       Copyright 1988 by Evans & Sutherland Computer Corporation,
30bbfda8aSnia *                          Salt Lake City, Utah
40bbfda8aSnia *  Portions Copyright 1989 by the Massachusetts Institute of Technology
50bbfda8aSnia *                        Cambridge, Massachusetts
60bbfda8aSnia *
70bbfda8aSnia * Copyright 1992 Claude Lecommandeur.
80bbfda8aSnia */
90bbfda8aSnia
100bbfda8aSnia/***********************************************************************
110bbfda8aSnia *
120bbfda8aSnia * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $
130bbfda8aSnia *
140bbfda8aSnia * twm event handling
150bbfda8aSnia *
160bbfda8aSnia * 17-Nov-87 Thomas E. LaStrange                File created
170bbfda8aSnia *
180bbfda8aSnia * Do the necessary modification to be integrated in ctwm.
190bbfda8aSnia * Can no longer be used for the standard twm.
200bbfda8aSnia *
210bbfda8aSnia * 22-April-92 Claude Lecommandeur.
220bbfda8aSnia *
230bbfda8aSnia *
240bbfda8aSnia ***********************************************************************/
250bbfda8aSnia
260bbfda8aSnia#include "ctwm.h"
270bbfda8aSnia
280bbfda8aSnia#include <stdio.h>
290bbfda8aSnia#include <stdlib.h>
300bbfda8aSnia#include <sys/time.h>
310bbfda8aSnia
320bbfda8aSnia#include <X11/Xatom.h>
330bbfda8aSnia#include <X11/extensions/shape.h>
340bbfda8aSnia
350bbfda8aSnia#include "add_window.h"
360bbfda8aSnia#include "animate.h"
370bbfda8aSnia#include "clicktofocus.h"
380bbfda8aSnia#include "colormaps.h"
390bbfda8aSnia#include "ctwm_atoms.h"
40b18c2d1eSnia#include "ctwm_shutdown.h"
410bbfda8aSnia#include "events.h"
420bbfda8aSnia#include "event_handlers.h"
430bbfda8aSnia#include "event_internal.h"
440bbfda8aSnia#include "event_names.h"
450bbfda8aSnia#include "functions.h"
460bbfda8aSnia#include "functions_defs.h"
470bbfda8aSnia#include "gram.tab.h"
480bbfda8aSnia#include "iconmgr.h"
490bbfda8aSnia#include "icons.h"
500bbfda8aSnia#include "image.h"
510bbfda8aSnia#include "list.h"
520bbfda8aSnia#include "occupation.h"
530bbfda8aSnia#include "otp.h"
540bbfda8aSnia#include "parse.h"
550bbfda8aSnia#include "screen.h"
560bbfda8aSnia#include "util.h"
570bbfda8aSnia#include "vscreen.h"
580bbfda8aSnia#include "win_decorations.h"
590bbfda8aSnia#include "win_iconify.h"
600bbfda8aSnia#include "win_ops.h"
610bbfda8aSnia#include "win_regions.h"
620bbfda8aSnia#include "win_resize.h"
63b18c2d1eSnia#include "win_ring.h"
640bbfda8aSnia#include "win_utils.h"
650bbfda8aSnia#include "workspace_manager.h"
660bbfda8aSnia#include "workspace_utils.h"
670bbfda8aSnia
680bbfda8aSnia
690bbfda8aSniastatic void do_key_menu(MenuRoot *menu,         /* menu to pop up */
700bbfda8aSnia                        Window w);             /* invoking window or None */
710bbfda8aSnia
720bbfda8aSnia/* Only called from HandleFocusChange() */
730bbfda8aSniastatic void HandleFocusIn(void);
740bbfda8aSniastatic void HandleFocusOut(void);
750bbfda8aSnia
760bbfda8aSnia/*
770bbfda8aSnia * This currently needs to live in the broader scope because of how it's
780bbfda8aSnia * used in deferred function handling.
790bbfda8aSnia */
800bbfda8aSniastatic char *Action;
810bbfda8aSnia
820bbfda8aSniastatic TwmWindow *ButtonWindow; /* button press window structure */
830bbfda8aSnia
840bbfda8aSniastatic void SendTakeFocusMessage(TwmWindow *tmp, Time timestamp);
850bbfda8aSnia
860bbfda8aSnia
870bbfda8aSniastatic unsigned int set_mask_ignore(unsigned int modifier)
880bbfda8aSnia{
890bbfda8aSnia	modifier &= ~Scr->IgnoreModifier;
900bbfda8aSnia
910bbfda8aSnia	return modifier;
920bbfda8aSnia}
930bbfda8aSnia
940bbfda8aSnia
950bbfda8aSnia/***********************************************************************
960bbfda8aSnia *
970bbfda8aSnia *  Procedure:
980bbfda8aSnia *      HandleColormapNotify - colormap notify event handler
990bbfda8aSnia *
1000bbfda8aSnia * This procedure handles both a client changing its own colormap, and
1010bbfda8aSnia * a client explicitly installing its colormap itself (only the window
1020bbfda8aSnia * manager should do that, so we must set it correctly).
1030bbfda8aSnia *
1040bbfda8aSnia ***********************************************************************
1050bbfda8aSnia */
1060bbfda8aSnia
1070bbfda8aSniavoid HandleColormapNotify(void)
1080bbfda8aSnia{
1090bbfda8aSnia	XColormapEvent *cevent = (XColormapEvent *) &Event;
1100bbfda8aSnia	ColormapWindow *cwin, **cwins;
1110bbfda8aSnia	TwmColormap *cmap;
1120bbfda8aSnia	int lost, won, n, number_cwins;
1130bbfda8aSnia
1140bbfda8aSnia	/*    if (! Tmp_win) return; */
1150bbfda8aSnia	if(XFindContext(dpy, cevent->window, ColormapContext,
1160bbfda8aSnia	                (XPointer *)&cwin) == XCNOENT) {
1170bbfda8aSnia		return;
1180bbfda8aSnia	}
1190bbfda8aSnia	cmap = cwin->colormap;
1200bbfda8aSnia
1210bbfda8aSnia	if(cevent->new) {
1220bbfda8aSnia		if(XFindContext(dpy, cevent->colormap, ColormapContext,
1230bbfda8aSnia		                (XPointer *)&cwin->colormap) == XCNOENT) {
1240bbfda8aSnia			cwin->colormap = CreateTwmColormap(cevent->colormap);
1250bbfda8aSnia		}
1260bbfda8aSnia		else {
1270bbfda8aSnia			cwin->colormap->refcnt++;
1280bbfda8aSnia		}
1290bbfda8aSnia
1300bbfda8aSnia		cmap->refcnt--;
1310bbfda8aSnia
1320bbfda8aSnia		if(cevent->state == ColormapUninstalled) {
1330bbfda8aSnia			cmap->state &= ~CM_INSTALLED;
1340bbfda8aSnia		}
1350bbfda8aSnia		else {
1360bbfda8aSnia			cmap->state |= CM_INSTALLED;
1370bbfda8aSnia		}
1380bbfda8aSnia
1390bbfda8aSnia		if(cmap->state & CM_INSTALLABLE) {
1400bbfda8aSnia			InstallColormaps(ColormapNotify, NULL);
1410bbfda8aSnia		}
1420bbfda8aSnia
1430bbfda8aSnia		if(cmap->refcnt == 0) {
1440bbfda8aSnia			XDeleteContext(dpy, cmap->c, ColormapContext);
1450bbfda8aSnia			free(cmap);
1460bbfda8aSnia		}
1470bbfda8aSnia
1480bbfda8aSnia		return;
1490bbfda8aSnia	}
1500bbfda8aSnia
1510bbfda8aSnia	if(cevent->state == ColormapUninstalled &&
1520bbfda8aSnia	                (cmap->state & CM_INSTALLABLE)) {
1530bbfda8aSnia		if(!(cmap->state & CM_INSTALLED)) {
1540bbfda8aSnia			return;
1550bbfda8aSnia		}
1560bbfda8aSnia		cmap->state &= ~CM_INSTALLED;
1570bbfda8aSnia
1580bbfda8aSnia		if(!ColortableThrashing) {
1590bbfda8aSnia			ColortableThrashing = true;
1600bbfda8aSnia			XSync(dpy, 0);
1610bbfda8aSnia		}
1620bbfda8aSnia
1630bbfda8aSnia		if(cevent->serial >= Scr->cmapInfo.first_req) {
1640bbfda8aSnia			number_cwins = Scr->cmapInfo.cmaps->number_cwins;
1650bbfda8aSnia
1660bbfda8aSnia			/*
1670bbfda8aSnia			 * Find out which colortables collided.
1680bbfda8aSnia			 */
1690bbfda8aSnia
1700bbfda8aSnia			cwins = Scr->cmapInfo.cmaps->cwins;
1710bbfda8aSnia			for(lost = won = -1, n = 0;
1720bbfda8aSnia			                (lost == -1 || won == -1) && n < number_cwins;
1730bbfda8aSnia			                n++) {
1740bbfda8aSnia				if(lost == -1 && cwins[n] == cwin) {
1750bbfda8aSnia					lost = n;   /* This is the window which lost its colormap */
1760bbfda8aSnia					continue;
1770bbfda8aSnia				}
1780bbfda8aSnia
1790bbfda8aSnia				if(won == -1 &&
1800bbfda8aSnia				                cwins[n]->colormap->install_req == cevent->serial) {
1810bbfda8aSnia					won = n;    /* This is the window whose colormap caused */
1820bbfda8aSnia					continue;   /* the de-install of the previous colormap */
1830bbfda8aSnia				}
1840bbfda8aSnia			}
1850bbfda8aSnia
1860bbfda8aSnia			/*
1870bbfda8aSnia			** Cases are:
1880bbfda8aSnia			** Both the request and the window were found:
1890bbfda8aSnia			**          One of the installs made honoring the WM_COLORMAP
1900bbfda8aSnia			**          property caused another of the colormaps to be
1910bbfda8aSnia			**          de-installed, just mark the scoreboard.
1920bbfda8aSnia			**
1930bbfda8aSnia			** Only the request was found:
1940bbfda8aSnia			**          One of the installs made honoring the WM_COLORMAP
1950bbfda8aSnia			**          property caused a window not in the WM_COLORMAP
1960bbfda8aSnia			**          list to lose its map.  This happens when the map
1970bbfda8aSnia			**          it is losing is one which is trying to be installed,
1980bbfda8aSnia			**          but is getting getting de-installed by another map
1990bbfda8aSnia			**          in this case, we'll get a scoreable event later,
2000bbfda8aSnia			**          this one is meaningless.
2010bbfda8aSnia			**
2020bbfda8aSnia			** Neither the request nor the window was found:
2030bbfda8aSnia			**          Somebody called installcolormap, but it doesn't
2040bbfda8aSnia			**          affect the WM_COLORMAP windows.  This case will
2050bbfda8aSnia			**          probably never occur.
2060bbfda8aSnia			**
2070bbfda8aSnia			** Only the window was found:
2080bbfda8aSnia			**          One of the WM_COLORMAP windows lost its colormap
2090bbfda8aSnia			**          but it wasn't one of the requests known.  This is
2100bbfda8aSnia			**          probably because someone did an "InstallColormap".
2110bbfda8aSnia			**          The colormap policy is "enforced" by re-installing
2120bbfda8aSnia			**          the colormaps which are believed to be correct.
2130bbfda8aSnia			*/
2140bbfda8aSnia
2150bbfda8aSnia			if(won != -1) {
2160bbfda8aSnia				if(lost != -1) {
2170bbfda8aSnia					/* lower diagonal index calculation */
2180bbfda8aSnia					if(lost > won) {
2190bbfda8aSnia						n = lost * (lost - 1) / 2 + won;
2200bbfda8aSnia					}
2210bbfda8aSnia					else {
2220bbfda8aSnia						n = won * (won - 1) / 2 + lost;
2230bbfda8aSnia					}
2240bbfda8aSnia					Scr->cmapInfo.cmaps->scoreboard[n] = 1;
2250bbfda8aSnia				}
2260bbfda8aSnia				else {
2270bbfda8aSnia					/*
2280bbfda8aSnia					** One of the cwin installs caused one of the cwin
2290bbfda8aSnia					** colormaps to be de-installed, so I'm sure to get an
2300bbfda8aSnia					** UninstallNotify for the cwin I know about later.
2310bbfda8aSnia					** I haven't got it yet, or the test of CM_INSTALLED
2320bbfda8aSnia					** above would have failed.  Turning the CM_INSTALLED
2330bbfda8aSnia					** bit back on makes sure we get back here to score
2340bbfda8aSnia					** the collision.
2350bbfda8aSnia					*/
2360bbfda8aSnia					cmap->state |= CM_INSTALLED;
2370bbfda8aSnia				}
2380bbfda8aSnia			}
2390bbfda8aSnia			else if(lost != -1) {
2400bbfda8aSnia				InstallColormaps(ColormapNotify, NULL);
2410bbfda8aSnia			}
2420bbfda8aSnia			else {
2430bbfda8aSnia				ColortableThrashing = false; /* Gross Hack for HP WABI. CL. */
2440bbfda8aSnia			}
2450bbfda8aSnia		}
2460bbfda8aSnia	}
2470bbfda8aSnia
2480bbfda8aSnia	else if(cevent->state == ColormapUninstalled) {
2490bbfda8aSnia		cmap->state &= ~CM_INSTALLED;
2500bbfda8aSnia	}
2510bbfda8aSnia
2520bbfda8aSnia	else if(cevent->state == ColormapInstalled) {
2530bbfda8aSnia		cmap->state |= CM_INSTALLED;
2540bbfda8aSnia	}
2550bbfda8aSnia}
2560bbfda8aSnia
2570bbfda8aSnia
2580bbfda8aSnia/*
2590bbfda8aSnia * LastFocusEvent -- skip over focus in/out events for this
2600bbfda8aSnia *              window.
2610bbfda8aSnia */
2620bbfda8aSnia
2630bbfda8aSniastatic XEvent *LastFocusEvent(Window w, XEvent *first)
2640bbfda8aSnia{
2650bbfda8aSnia	static XEvent current;
2660bbfda8aSnia	XEvent *last, new;
2670bbfda8aSnia
2680bbfda8aSnia	new = *first;
2690bbfda8aSnia	last = NULL;
2700bbfda8aSnia
2710bbfda8aSnia	do {
2720bbfda8aSnia		if((new.type == FocusIn || new.type == FocusOut)
2730bbfda8aSnia		                && new.xfocus.mode == NotifyNormal
2740bbfda8aSnia		                && (new.xfocus.detail == NotifyNonlinear
2750bbfda8aSnia		                    || new.xfocus.detail == NotifyPointer
2760bbfda8aSnia		                    || new.xfocus.detail == NotifyAncestor
2770bbfda8aSnia		                    || (new.xfocus.detail == NotifyNonlinearVirtual)
2780bbfda8aSnia		                   )) {
2790bbfda8aSnia			current = new;
2800bbfda8aSnia			last = &current;
2810bbfda8aSnia		}
2820bbfda8aSnia
2830bbfda8aSnia#ifdef TRACE_FOCUS
2840bbfda8aSnia		fprintf(stderr, "%s(): Focus%s 0x%x mode=%d, detail=%d\n",
2850bbfda8aSnia		        __func__, new.xfocus.type == FocusIn ? "In" : "Out",
2860bbfda8aSnia		        Tmp_win, new.xfocus.mode, new.xfocus.detail);
2870bbfda8aSnia#endif
2880bbfda8aSnia
2890bbfda8aSnia	}
2900bbfda8aSnia	while(XCheckWindowEvent(dpy, w, FocusChangeMask, &new));
2910bbfda8aSnia	return last;
2920bbfda8aSnia}
2930bbfda8aSnia
2940bbfda8aSnia
2950bbfda8aSnia/*
2960bbfda8aSnia * Focus change handlers.
2970bbfda8aSnia *
2980bbfda8aSnia * Depending on how events get called, these are sometimes redundant, as
2990bbfda8aSnia * the Enter event handler does practically all of this anyway.  But
3000bbfda8aSnia * there are presumably ways we can wind up Focus'ing a window without
3010bbfda8aSnia * Enter'ing it as well.
3020bbfda8aSnia *
3030bbfda8aSnia * It's also a little convoluted how these wind up getting called.  With
3040bbfda8aSnia * most events, we call a handler, then handle that event.  However, with
3050bbfda8aSnia * focus, we troll through our list of pending Focus-related events for
3060bbfda8aSnia * the window and just handle the last one, since some could pile up
3070bbfda8aSnia * fast.  That means that, even if we get called for a FocusIn event,
3080bbfda8aSnia * there might be a FocusOut later in the queue, and _that_'s the one we
3090bbfda8aSnia * pick up and handle, and we discard the rest [for that window].  So,
3100bbfda8aSnia * the event handling code calls a single entry point for both types, and
3110bbfda8aSnia * then it figures out which backend handler to actually fire.
3120bbfda8aSnia */
3130bbfda8aSniavoid
3140bbfda8aSniaHandleFocusChange(void)
3150bbfda8aSnia{
3160bbfda8aSnia	XEvent *event;
3170bbfda8aSnia
3180bbfda8aSnia	/* If there's no event window, nothing to do */
3190bbfda8aSnia	if(!Tmp_win) {
3200bbfda8aSnia		return;
3210bbfda8aSnia	}
3220bbfda8aSnia
3230bbfda8aSnia	/*
3240bbfda8aSnia	 * Consume all the focus events for the window we're called about and
3250bbfda8aSnia	 * grab the last one to process.
3260bbfda8aSnia	 *
3270bbfda8aSnia	 * XXX It should be guaranteed that the window in the X event in our
3280bbfda8aSnia	 * global Event is the same as Tmp_win->w as the event dispatcher
3290bbfda8aSnia	 * sets it so.  Maybe we should do both checks on the same var for
3300bbfda8aSnia	 * consistency though?
3310bbfda8aSnia	 *
3320bbfda8aSnia	 * It's not immediately clear how this can wind up returning nothing,
3330bbfda8aSnia	 * but if it does, we don't have anything to do either.
3340bbfda8aSnia	 */
3350bbfda8aSnia	event = LastFocusEvent(Event.xany.window, &Event);
3360bbfda8aSnia	if(event == NULL) {
3370bbfda8aSnia		return;
3380bbfda8aSnia	}
3390bbfda8aSnia
3400bbfda8aSnia	/*
3410bbfda8aSnia	 * Icon managers don't do anything with focus events on themselves,
3420bbfda8aSnia	 * so just skip back if this is one.  Done after LastFocusEvent()
3430bbfda8aSnia	 * call for efficiency, so we don't fall into this func multiple
3440bbfda8aSnia	 * times if multiple events are queued for it.
3450bbfda8aSnia	 */
3460bbfda8aSnia	if(Tmp_win->isiconmgr) {
3470bbfda8aSnia		return;
3480bbfda8aSnia	}
3490bbfda8aSnia
3500bbfda8aSnia#ifdef TRACE_FOCUS
3510bbfda8aSnia	fprintf(stderr, "HandleFocus%s(): 0x%x (0x%x, 0x%x), mode=%d, "
3520bbfda8aSnia	        "detail=%d\n",
3530bbfda8aSnia	        (event->type == FocusIn ? "In" : "Out"),
3540bbfda8aSnia	        Tmp_win, Tmp_win->w, event->window, event->mode,
3550bbfda8aSnia	        event->detail);
3560bbfda8aSnia#endif
3570bbfda8aSnia
3580bbfda8aSnia	/* And call actual handler */
3590bbfda8aSnia	if(event->type == FocusIn) {
3600bbfda8aSnia		HandleFocusIn();
3610bbfda8aSnia	}
3620bbfda8aSnia	else {
3630bbfda8aSnia		HandleFocusOut();
3640bbfda8aSnia	}
3650bbfda8aSnia}
3660bbfda8aSnia
3670bbfda8aSnia
3680bbfda8aSniastatic void
3690bbfda8aSniaHandleFocusIn(void)
3700bbfda8aSnia{
3710bbfda8aSnia	if(! Tmp_win->wmhints->input) {
3720bbfda8aSnia		return;
3730bbfda8aSnia	}
3740bbfda8aSnia	if(Scr->Focus == Tmp_win) {
3750bbfda8aSnia		return;
3760bbfda8aSnia	}
3770bbfda8aSnia
3780bbfda8aSnia#ifdef EWMH
3790bbfda8aSnia	// Handle focus-dependent re-stacking of what we're moving out of.
3800bbfda8aSnia	if(Scr->Focus && OtpIsFocusDependent(Scr->Focus)) {
3810bbfda8aSnia		OtpUnfocusWindow(Scr->Focus);
3820bbfda8aSnia		// NULL's Scr->Focus
3830bbfda8aSnia	}
3840bbfda8aSnia#endif
3850bbfda8aSnia
3860bbfda8aSnia	if(Tmp_win->AutoSqueeze && Tmp_win->squeezed) {
3870bbfda8aSnia		AutoSqueeze(Tmp_win);
3880bbfda8aSnia	}
3890bbfda8aSnia	SetFocusVisualAttributes(Tmp_win, true);
3900bbfda8aSnia
3910bbfda8aSnia#ifdef EWMH
3920bbfda8aSnia	// Handle focus-dependent re-stacking of what we're moving in to.
3930bbfda8aSnia	if(Tmp_win && OtpIsFocusDependent(Tmp_win)) {
3940bbfda8aSnia		OtpFocusWindow(Tmp_win);
3950bbfda8aSnia		// Sets Scr->Focus
3960bbfda8aSnia	}
3970bbfda8aSnia#endif
3980bbfda8aSnia
3990bbfda8aSnia	// Redundant in EWMH case
4000bbfda8aSnia	Scr->Focus = Tmp_win;
4010bbfda8aSnia}
4020bbfda8aSnia
4030bbfda8aSnia
4040bbfda8aSniastatic void
4050bbfda8aSniaHandleFocusOut(void)
4060bbfda8aSnia{
4070bbfda8aSnia	if(Scr->Focus != Tmp_win) {
4080bbfda8aSnia		return;
4090bbfda8aSnia	}
4100bbfda8aSnia	if(Scr->SloppyFocus) {
4110bbfda8aSnia		return;
4120bbfda8aSnia	}
4130bbfda8aSnia	if(Tmp_win->AutoSqueeze && !Tmp_win->squeezed) {
4140bbfda8aSnia		AutoSqueeze(Tmp_win);
4150bbfda8aSnia	}
4160bbfda8aSnia	SetFocusVisualAttributes(Tmp_win, false);
4170bbfda8aSnia
4180bbfda8aSnia#ifdef EWMH
4190bbfda8aSnia	/*
4200bbfda8aSnia	 * X-ref HandleFocusIn() comment.  FocusOut is only leaving a window,
4210bbfda8aSnia	 * not entering a new one, so there's only one we may need to
4220bbfda8aSnia	 * restack.
4230bbfda8aSnia	 */
4240bbfda8aSnia	if(Scr->Focus && OtpIsFocusDependent(Scr->Focus)) {
4250bbfda8aSnia		OtpUnfocusWindow(Scr->Focus);
4260bbfda8aSnia		// NULL's Scr->Focus
4270bbfda8aSnia	}
4280bbfda8aSnia#endif
4290bbfda8aSnia
4300bbfda8aSnia	// Redundant in EWMH case
4310bbfda8aSnia	Scr->Focus = NULL;
4320bbfda8aSnia}
4330bbfda8aSnia
4340bbfda8aSnia
4350bbfda8aSnia
4360bbfda8aSnia/*
4370bbfda8aSnia * Only sent if SubstructureNotifyMask is selected on the (root) window.
4380bbfda8aSnia */
439b18c2d1eSniavoid HandleCirculateNotify(void)
4400bbfda8aSnia{
4410bbfda8aSnia	VirtualScreen *vs;
4420bbfda8aSnia#ifdef DEBUG_EVENTS
4430bbfda8aSnia	fprintf(stderr, "HandleCirculateNotify\n");
4440bbfda8aSnia	fprintf(stderr, "event=%x window=%x place=%d\n",
4450bbfda8aSnia	        (unsigned)Event.xcirculate.event,
4460bbfda8aSnia	        (unsigned)Event.xcirculate.window,
4470bbfda8aSnia	        Event.xcirculate.place);
4480bbfda8aSnia#endif
4490bbfda8aSnia
4500bbfda8aSnia	for(vs = Scr->vScreenList; vs; vs = vs->next) {
4510bbfda8aSnia		if(Event.xcirculate.event == vs->window) {
4520bbfda8aSnia			TwmWindow *twm_win = GetTwmWindow(Event.xcirculate.window);
4530bbfda8aSnia
4540bbfda8aSnia			if(twm_win) {
4550bbfda8aSnia				WinType wt;
4560bbfda8aSnia
4570bbfda8aSnia				if(Event.xcirculate.window == twm_win->frame) {
4580bbfda8aSnia					wt = WinWin;
4590bbfda8aSnia				}
4600bbfda8aSnia				else if(twm_win->icon &&
4610bbfda8aSnia				                Event.xcirculate.window == twm_win->icon->w) {
4620bbfda8aSnia					wt = IconWin;
4630bbfda8aSnia				}
4640bbfda8aSnia				else {
4650bbfda8aSnia					return;
4660bbfda8aSnia				}
4670bbfda8aSnia
4680bbfda8aSnia				OtpHandleCirculateNotify(vs,
4690bbfda8aSnia				                         twm_win, wt,
4700bbfda8aSnia				                         Event.xcirculate.place);
4710bbfda8aSnia			}
4720bbfda8aSnia		}
4730bbfda8aSnia	}
4740bbfda8aSnia}
4750bbfda8aSnia
4760bbfda8aSnia/***********************************************************************
4770bbfda8aSnia *
4780bbfda8aSnia *  Procedure:
4790bbfda8aSnia *      HandleVisibilityNotify - visibility notify event handler
4800bbfda8aSnia *
4810bbfda8aSnia * This routine keeps track of visibility events so that colormap
4820bbfda8aSnia * installation can keep the maximum number of useful colormaps
4830bbfda8aSnia * installed at one time.
4840bbfda8aSnia *
4850bbfda8aSnia ***********************************************************************
4860bbfda8aSnia */
4870bbfda8aSnia
4880bbfda8aSniavoid HandleVisibilityNotify(void)
4890bbfda8aSnia{
4900bbfda8aSnia	XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
4910bbfda8aSnia	ColormapWindow *cwin;
4920bbfda8aSnia	TwmColormap *cmap;
4930bbfda8aSnia
4940bbfda8aSnia	if(XFindContext(dpy, vevent->window, ColormapContext,
4950bbfda8aSnia	                (XPointer *)&cwin) == XCNOENT) {
4960bbfda8aSnia		return;
4970bbfda8aSnia	}
4980bbfda8aSnia
4990bbfda8aSnia	/*
5000bbfda8aSnia	 * when Saber complains about retreiving an <int> from an <unsigned int>
5010bbfda8aSnia	 * just type "touch vevent->state" and "cont"
5020bbfda8aSnia	 */
5030bbfda8aSnia	cmap = cwin->colormap;
5040bbfda8aSnia	if((cmap->state & CM_INSTALLABLE) &&
5050bbfda8aSnia	                vevent->state != cwin->visibility &&
5060bbfda8aSnia	                (vevent->state == VisibilityFullyObscured ||
5070bbfda8aSnia	                 cwin->visibility == VisibilityFullyObscured) &&
5080bbfda8aSnia	                cmap->w == cwin->w) {
5090bbfda8aSnia		cwin->visibility = vevent->state;
5100bbfda8aSnia		InstallWindowColormaps(VisibilityNotify, NULL);
5110bbfda8aSnia	}
5120bbfda8aSnia	else {
5130bbfda8aSnia		cwin->visibility = vevent->state;
5140bbfda8aSnia	}
5150bbfda8aSnia}
5160bbfda8aSnia
5170bbfda8aSnia
5180bbfda8aSnia/***********************************************************************
5190bbfda8aSnia *
5200bbfda8aSnia *  Procedure:
5210bbfda8aSnia *      HandleKeyRelease - key release event handler
5220bbfda8aSnia *
5230bbfda8aSnia ***********************************************************************
5240bbfda8aSnia */
5250bbfda8aSnia
5260bbfda8aSniavoid HandleKeyRelease(void)
5270bbfda8aSnia{
5280bbfda8aSnia	if(Tmp_win == Scr->currentvs->wsw->twm_win) {
5290bbfda8aSnia		WMgrHandleKeyReleaseEvent(Scr->currentvs, &Event);
5300bbfda8aSnia	}
5310bbfda8aSnia}
5320bbfda8aSnia
5330bbfda8aSnia
5340bbfda8aSnia
5350bbfda8aSnia/*
5360bbfda8aSnia * HandleKeyPress - key press event handler
5370bbfda8aSnia *
5380bbfda8aSnia * When a key is pressed, we may do various things with it.  If we're in
5390bbfda8aSnia * a menu, various keybindings move around in it, others get silently
5400bbfda8aSnia * ignored.  Else, we look through the various bindings set in the config
5410bbfda8aSnia * file and invoke whatever should be.  If none of that matches, and it
5420bbfda8aSnia * seems like some window should have focus, pass the event down to that
5430bbfda8aSnia * window.
5440bbfda8aSnia */
5450bbfda8aSniavoid HandleKeyPress(void)
5460bbfda8aSnia{
5470bbfda8aSnia	/*
5480bbfda8aSnia	 * If the Info window (f.identify/f.version) is currently up, any key
5490bbfda8aSnia	 * press will drop it away.
5500bbfda8aSnia	 */
5510bbfda8aSnia	if(Scr->InfoWindow.mapped) {
5520bbfda8aSnia		XUnmapWindow(dpy, Scr->InfoWindow.win);
5530bbfda8aSnia		Scr->InfoWindow.mapped = false;
5540bbfda8aSnia	}
5550bbfda8aSnia
5560bbfda8aSnia
5570bbfda8aSnia	/*
5580bbfda8aSnia	 * If a menu is up, we interpret various keys as moving around or
5590bbfda8aSnia	 * doing things in the menu.  No other key bindings or usages are
5600bbfda8aSnia	 * considered.
5610bbfda8aSnia	 */
5620bbfda8aSnia	if(ActiveMenu != NULL) {
5630bbfda8aSnia		MenuItem *item;
5640bbfda8aSnia		char *keynam;
5650bbfda8aSnia		KeySym keysym;
5660bbfda8aSnia		Window junkW;
5670bbfda8aSnia
5680bbfda8aSnia		item = NULL;
5690bbfda8aSnia
5700bbfda8aSnia		/* What key was pressed? */
5710bbfda8aSnia		keysym = XLookupKeysym((XKeyEvent *) &Event, 0);
5720bbfda8aSnia		if(! keysym) {
5730bbfda8aSnia			return;
5740bbfda8aSnia		}
5750bbfda8aSnia		keynam = XKeysymToString(keysym);
5760bbfda8aSnia		if(! keynam) {
5770bbfda8aSnia			return;
5780bbfda8aSnia		}
5790bbfda8aSnia
5800bbfda8aSnia
5810bbfda8aSnia		/*
5820bbfda8aSnia		 * Initial handling of the various keystrokes.  Most keys are
5830bbfda8aSnia		 * completely handled here; we only descend out into later for
5840bbfda8aSnia		 * for Return/Right keys that do invoke-y stuff on menu entries.
5850bbfda8aSnia		 */
5860bbfda8aSnia		if(keysym == XK_Down || keysym == XK_space) {
5870bbfda8aSnia			/*
5880bbfda8aSnia			 * Down or Spacebar moves us to the next entry in the menu,
5890bbfda8aSnia			 * looping back around to the top when it falls off the
5900bbfda8aSnia			 * bottom.
5910bbfda8aSnia			 *
5920bbfda8aSnia			 * Start with our X and (current+height)Y, then wrap around
5930bbfda8aSnia			 * to the top (Y)/into the menu (X) as necessary.
5940bbfda8aSnia			 */
5950bbfda8aSnia			int xx = Event.xkey.x;
5960bbfda8aSnia			int yy = Event.xkey.y + Scr->EntryHeight;
5970bbfda8aSnia			int wx, wy;
5980bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW);
5990bbfda8aSnia			if((wy < 0) || (wy > ActiveMenu->height)) {
6000bbfda8aSnia				yy -= (wy - (Scr->EntryHeight / 2) - 2);
6010bbfda8aSnia			}
6020bbfda8aSnia			if((wx < 0) || (wx > ActiveMenu->width)) {
6030bbfda8aSnia				xx -= (wx - (ActiveMenu->width / 2));
6040bbfda8aSnia			}
6050bbfda8aSnia
6060bbfda8aSnia			/*
6070bbfda8aSnia			 * Move the pointer there.  We'll get a Motion notify from
6080bbfda8aSnia			 * the X server as a result, which will fall into the loop in
6090bbfda8aSnia			 * UpdateMenu() and handle re-highlighting etc.
6100bbfda8aSnia			 */
6110bbfda8aSnia			XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
6120bbfda8aSnia			             ActiveMenu->width, ActiveMenu->height, xx, yy);
6130bbfda8aSnia			return;
6140bbfda8aSnia		}
6150bbfda8aSnia		else if(keysym == XK_Up || keysym == XK_BackSpace) {
6160bbfda8aSnia			/*
6170bbfda8aSnia			 * Up/Backspace move up an entry, with details similar in
6180bbfda8aSnia			 * reverse to the above.
6190bbfda8aSnia			 */
6200bbfda8aSnia			int xx = Event.xkey.x;
6210bbfda8aSnia			int yy = Event.xkey.y - Scr->EntryHeight;
6220bbfda8aSnia			int wx, wy;
6230bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, ActiveMenu->w, xx, yy, &wx, &wy, &junkW);
6240bbfda8aSnia			if((wy < 0) || (wy > ActiveMenu->height)) {
6250bbfda8aSnia				yy -= (wy - ActiveMenu->height + (Scr->EntryHeight / 2) + 2);
6260bbfda8aSnia			}
6270bbfda8aSnia			if((wx < 0) || (wx > ActiveMenu->width)) {
6280bbfda8aSnia				xx -= (wx - (ActiveMenu->width / 2));
6290bbfda8aSnia			}
6300bbfda8aSnia			XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
6310bbfda8aSnia			             ActiveMenu->width, ActiveMenu->height, xx, yy);
6320bbfda8aSnia			return;
6330bbfda8aSnia		}
6340bbfda8aSnia		else if(keysym == XK_Right || keysym == XK_Return) {
6350bbfda8aSnia			/*
6360bbfda8aSnia			 * Right/Return mean we're invoking some entry item, so we
6370bbfda8aSnia			 * take note of where we are for activating at the end of
6380bbfda8aSnia			 * this set of conditionals.
6390bbfda8aSnia			 *
6400bbfda8aSnia			 * Follow this down into the following if(item) block for
6410bbfda8aSnia			 * details, particularly in the subtle differences between
6420bbfda8aSnia			 * Right and Return on f.menu entries.
6430bbfda8aSnia			 */
6440bbfda8aSnia			item = ActiveItem;
6450bbfda8aSnia		}
6460bbfda8aSnia		else if(keysym == XK_Left || keysym == XK_Escape) {
6470bbfda8aSnia			/*
6480bbfda8aSnia			 * Left/Escape back up to a higher menu level, or out totally
6490bbfda8aSnia			 * from the top.
6500bbfda8aSnia			 */
6510bbfda8aSnia			MenuRoot *menu;
6520bbfda8aSnia
6530bbfda8aSnia			/* Leave pinned menus alone though */
6540bbfda8aSnia			if(ActiveMenu->pinned) {
6550bbfda8aSnia				return;
6560bbfda8aSnia			}
6570bbfda8aSnia
6580bbfda8aSnia			/* Top-level?  Clear out and leave menu mode totally. */
6590bbfda8aSnia			if(!ActiveMenu->prev || MenuDepth == 1) {
6600bbfda8aSnia				PopDownMenu();
6610bbfda8aSnia				XUngrabPointer(dpy, CurrentTime);
6620bbfda8aSnia				return;
6630bbfda8aSnia			}
6640bbfda8aSnia
6650bbfda8aSnia			/*
6660bbfda8aSnia			 * We're in a sub level.  Figure out various stuff for where
6670bbfda8aSnia			 * we are and where we should be in the up-level, clear out
6680bbfda8aSnia			 * the windows for this level, and warp us up there.
6690bbfda8aSnia			 */
6700bbfda8aSnia			int xx = Event.xkey.x;
6710bbfda8aSnia			int yy = Event.xkey.y;
6720bbfda8aSnia			int wx, wy;
6730bbfda8aSnia			menu = ActiveMenu->prev;
6740bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, menu->w, xx, yy, &wx, &wy, &junkW);
6750bbfda8aSnia			xx -= (wx - (menu->width / 2));
6760bbfda8aSnia			if(menu->lastactive)
6770bbfda8aSnia				yy -= (wy - menu->lastactive->item_num * Scr->EntryHeight -
6780bbfda8aSnia				       (Scr->EntryHeight / 2) - 2);
6790bbfda8aSnia			else {
6800bbfda8aSnia				yy -= (wy - (Scr->EntryHeight / 2) - 2);
6810bbfda8aSnia			}
6820bbfda8aSnia			XUnmapWindow(dpy, ActiveMenu->w);
6830bbfda8aSnia			if(Scr->Shadow) {
6840bbfda8aSnia				XUnmapWindow(dpy, ActiveMenu->shadow);
6850bbfda8aSnia			}
6860bbfda8aSnia			XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
6870bbfda8aSnia			             menu->width, menu->height, xx, yy);
6880bbfda8aSnia			return;
6890bbfda8aSnia		}
6900bbfda8aSnia		else if(strlen(keynam) == 1) {
6910bbfda8aSnia			/*
6920bbfda8aSnia			 * This would mean pressing a more normal (e.g., letter/num)
6930bbfda8aSnia			 * key.  These find the first entry starting with a matching
6940bbfda8aSnia			 * character and jump to it.
6950bbfda8aSnia			 */
6960bbfda8aSnia			MenuItem *startitem;
6970bbfda8aSnia			int xx = Event.xkey.x;
6980bbfda8aSnia			int yy = Event.xkey.y;
6990bbfda8aSnia			int wx, wy;
7000bbfda8aSnia
7010bbfda8aSnia			startitem = ActiveItem ? ActiveItem : ActiveMenu->first;
7020bbfda8aSnia			item = startitem->next;
7030bbfda8aSnia			if(item == NULL) {
7040bbfda8aSnia				item = ActiveMenu->first;
7050bbfda8aSnia			}
7060bbfda8aSnia			unsigned int keymod = (Event.xkey.state & mods_used);
7070bbfda8aSnia			keymod = set_mask_ignore(keymod);
7080bbfda8aSnia
7090bbfda8aSnia			while(item != startitem) {
7100bbfda8aSnia				bool matched = false;
7110bbfda8aSnia				size_t offset = 0;
7120bbfda8aSnia				switch(item->item [0]) {
7130bbfda8aSnia					case '^' :
7140bbfda8aSnia						if((keymod & ControlMask) &&
7150bbfda8aSnia						                (keynam [0] == Tolower(item->item [1]))) {
7160bbfda8aSnia							matched = true;
7170bbfda8aSnia						}
7180bbfda8aSnia						break;
7190bbfda8aSnia					case '~' :
7200bbfda8aSnia						if((keymod & Mod1Mask) &&
7210bbfda8aSnia						                (keynam [0] == Tolower(item->item [1]))) {
7220bbfda8aSnia							matched = true;
7230bbfda8aSnia						}
7240bbfda8aSnia						break;
7250bbfda8aSnia					case ' ' :
7260bbfda8aSnia						offset = 1;
7270bbfda8aSnia					default :
7280bbfda8aSnia						if(((Scr->IgnoreCaseInMenuSelection) &&
7290bbfda8aSnia						                (keynam [0] == Tolower(item->item [offset]))) ||
7300bbfda8aSnia
7310bbfda8aSnia						                ((keymod & ShiftMask) && Isupper(item->item [offset]) &&
7320bbfda8aSnia						                 (keynam [0] == Tolower(item->item [offset]))) ||
7330bbfda8aSnia
7340bbfda8aSnia						                (!(keymod & ShiftMask) && Islower(item->item [offset]) &&
7350bbfda8aSnia						                 (keynam [0] == item->item [offset]))) {
7360bbfda8aSnia							matched = true;
7370bbfda8aSnia						}
7380bbfda8aSnia						break;
7390bbfda8aSnia				}
7400bbfda8aSnia				if(matched) {
7410bbfda8aSnia					break;
7420bbfda8aSnia				}
7430bbfda8aSnia				item = item->next;
7440bbfda8aSnia				if(item == NULL) {
7450bbfda8aSnia					item = ActiveMenu->first;
7460bbfda8aSnia				}
7470bbfda8aSnia			}
7480bbfda8aSnia			if(item == startitem) {
7490bbfda8aSnia				return;
7500bbfda8aSnia			}
7510bbfda8aSnia			wx = ActiveMenu->width / 2;
7520bbfda8aSnia			wy = (item->item_num * Scr->EntryHeight) + (Scr->EntryHeight / 2) + 2;
7530bbfda8aSnia			XTranslateCoordinates(dpy, ActiveMenu->w, Scr->Root, wx, wy, &xx, &yy, &junkW);
7540bbfda8aSnia			XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
7550bbfda8aSnia			             ActiveMenu->width, ActiveMenu->height, xx, yy);
7560bbfda8aSnia			return;
7570bbfda8aSnia		}
7580bbfda8aSnia		else {
7590bbfda8aSnia			/* Other keys get ignored */
7600bbfda8aSnia			return;
7610bbfda8aSnia		}
7620bbfda8aSnia
7630bbfda8aSnia
7640bbfda8aSnia		/*
7650bbfda8aSnia		 * So if we get here, the key pressed was a Right/Return on an
7660bbfda8aSnia		 * entry to select it (chosen entry now in item).  Every other
7670bbfda8aSnia		 * case is have been completely handled in the block above and
7680bbfda8aSnia		 * would have already returned.
7690bbfda8aSnia		 *
7700bbfda8aSnia		 * So item should always be the entry we just tried to invoke.
7710bbfda8aSnia		 * I'm not sure how it could be empty, but if it is, we just hop
7720bbfda8aSnia		 * ourselves out of the menu.  Otherwise, we do whatever we want
7730bbfda8aSnia		 * to do with the entry type we're on.
7740bbfda8aSnia		 */
7750bbfda8aSnia		if(item) {
7760bbfda8aSnia			switch(item->func) {
7770bbfda8aSnia				/* f.nop and f.title, we just silently let pass */
7780bbfda8aSnia				case 0 :
7790bbfda8aSnia				case F_TITLE :
7800bbfda8aSnia					break;
7810bbfda8aSnia
7820bbfda8aSnia				/* If it's a f.menu, there's more magic to do */
7830bbfda8aSnia				case F_MENU: {
7840bbfda8aSnia					/*
7850bbfda8aSnia					 * Return is treated separately from Right.  It
7860bbfda8aSnia					 * "invokes" the menu item, which immediately calls
7870bbfda8aSnia					 * whatever the default menu entry is (which may be
7880bbfda8aSnia					 * nothing).
7890bbfda8aSnia					 */
7900bbfda8aSnia					if(!strcmp(keynam, "Return")) {
7910bbfda8aSnia						if(ActiveMenu == Scr->Workspaces) {
7920bbfda8aSnia							/*
7930bbfda8aSnia							 * f.menu "TwmWorkspaces".  The "invocation"
7940bbfda8aSnia							 * of this jumps to the workspace in
7950bbfda8aSnia							 * question, as if it were a default entry of
7960bbfda8aSnia							 * f.gotoworkspace.
7970bbfda8aSnia							 *
7980bbfda8aSnia							 * XXX Grody magic.  Maybe this should be
7990bbfda8aSnia							 * unwound to a default entry...
8000bbfda8aSnia							 */
8010bbfda8aSnia							PopDownMenu();
8020bbfda8aSnia							XUngrabPointer(dpy, CurrentTime);
8030bbfda8aSnia							GotoWorkSpaceByName(Scr->currentvs, item->action + 8);
8040bbfda8aSnia						}
8050bbfda8aSnia						else {
8060bbfda8aSnia							/*
8070bbfda8aSnia							 * Calling the f.menu handler invokes the
8080bbfda8aSnia							 * default action.  We handle popping out of
8090bbfda8aSnia							 * menus ourselves.
8100bbfda8aSnia							 */
8110bbfda8aSnia							ExecuteFunction(item->func, item->action,
8120bbfda8aSnia							                ButtonWindow ? ButtonWindow->frame : None,
8130bbfda8aSnia							                ButtonWindow, &Event, Context, false);
8140bbfda8aSnia							PopDownMenu();
8150bbfda8aSnia						}
8160bbfda8aSnia
8170bbfda8aSnia						/*
8180bbfda8aSnia						 * Whatever invocation Return does is done, so we
8190bbfda8aSnia						 * are too.
8200bbfda8aSnia						 */
8210bbfda8aSnia						return;
8220bbfda8aSnia					}
8230bbfda8aSnia
8240bbfda8aSnia					/*
8250bbfda8aSnia					 * Right arrow causes opening up a sub-f.menu.  Open
8260bbfda8aSnia					 * it up in the appropriate place, [re-]set
8270bbfda8aSnia					 * highlights, and call do_key_menu() to do a lot of
8280bbfda8aSnia					 * the internals of it.
8290bbfda8aSnia					 */
8300bbfda8aSnia					int xx = Event.xkey.x;
8310bbfda8aSnia					int yy = Event.xkey.y;
8320bbfda8aSnia					int wx, wy;
8330bbfda8aSnia					XTranslateCoordinates(dpy, Scr->Root, ActiveMenu->w, xx, yy,
8340bbfda8aSnia					                      &wx, &wy, &junkW);
8350bbfda8aSnia					if(ActiveItem) {
8360bbfda8aSnia						ActiveItem->state = 0;
8370bbfda8aSnia						PaintEntry(ActiveMenu, ActiveItem, false);
8380bbfda8aSnia						ActiveItem = NULL;
8390bbfda8aSnia					}
8400bbfda8aSnia					xx -= (wx - ActiveMenu->width);
8410bbfda8aSnia					yy -= (wy - item->item_num * Scr->EntryHeight - (Scr->EntryHeight / 2) - 2);
8420bbfda8aSnia					Event.xkey.x_root = xx;
8430bbfda8aSnia					Event.xkey.y_root = yy;
8440bbfda8aSnia					XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
8450bbfda8aSnia					             ActiveMenu->width, ActiveMenu->height, xx, yy);
8460bbfda8aSnia					if(ActiveMenu == Scr->Workspaces) {
8470bbfda8aSnia						CurrentSelectedWorkspace = item->item;
8480bbfda8aSnia					}
8490bbfda8aSnia					do_key_menu(item->sub, None);
8500bbfda8aSnia					CurrentSelectedWorkspace = NULL;
8510bbfda8aSnia					break;
8520bbfda8aSnia				}
8530bbfda8aSnia
8540bbfda8aSnia				/*
8550bbfda8aSnia				 * Any other f.something.  Pop down the menu (unless
8560bbfda8aSnia				 * we're trying to pin it up), and invoke the function.
8570bbfda8aSnia				 */
8580bbfda8aSnia				default :
8590bbfda8aSnia					if(item->func != F_PIN) {
8600bbfda8aSnia						PopDownMenu();
8610bbfda8aSnia					}
8620bbfda8aSnia					ExecuteFunction(item->func, item->action,
8630bbfda8aSnia					                ButtonWindow ? ButtonWindow->frame : None,
8640bbfda8aSnia					                ButtonWindow, &Event, Context, false);
8650bbfda8aSnia			}
8660bbfda8aSnia
8670bbfda8aSnia			/* Done whatever invocation of the entry we need */
8680bbfda8aSnia		}
8690bbfda8aSnia		else {
8700bbfda8aSnia			/* Was no item; pop out of the menu */
8710bbfda8aSnia			PopDownMenu();
8720bbfda8aSnia			XUngrabPointer(dpy, CurrentTime);
8730bbfda8aSnia		}
8740bbfda8aSnia
8750bbfda8aSnia		/*
8760bbfda8aSnia		 * We're done handling the keypress in a menu, so there's nothing
8770bbfda8aSnia		 * else to do.
8780bbfda8aSnia		 */
8790bbfda8aSnia		return;
8800bbfda8aSnia	}
8810bbfda8aSnia
8820bbfda8aSnia
8830bbfda8aSnia	/*
8840bbfda8aSnia	 * Not in a menu, so we loop through our various bindings.  First,
8850bbfda8aSnia	 * figure out what context we're in.  This goes in a global var,
8860bbfda8aSnia	 * presumably because stuff way down the chain of invoking some item
8870bbfda8aSnia	 * may need to refer up to it.
8880bbfda8aSnia	 */
8890bbfda8aSnia	Context = C_NO_CONTEXT;
8900bbfda8aSnia	if(Event.xany.window == Scr->Root) {
8910bbfda8aSnia		if(AlternateContext) {
8920bbfda8aSnia			XUngrabPointer(dpy, CurrentTime);
8930bbfda8aSnia			XUngrabKeyboard(dpy, CurrentTime);
8940bbfda8aSnia			AlternateContext = false;
8950bbfda8aSnia			Context = C_ALTERNATE;
8960bbfda8aSnia		}
8970bbfda8aSnia		else if(AlternateKeymap && Event.xkey.subwindow) {
8980bbfda8aSnia			Tmp_win = GetTwmWindow(Event.xkey.subwindow);
8990bbfda8aSnia			if(Tmp_win) {
9000bbfda8aSnia				Event.xany.window = Tmp_win->w;
9010bbfda8aSnia			}
9020bbfda8aSnia		}
9030bbfda8aSnia		else {
9040bbfda8aSnia			Context = C_ROOT;
9050bbfda8aSnia		}
9060bbfda8aSnia	}
9070bbfda8aSnia	if(Tmp_win) {
9080bbfda8aSnia		if(0) {
9090bbfda8aSnia			/* Dummy to simplify constructions of else if's */
9100bbfda8aSnia		}
9110bbfda8aSnia#ifdef EWMH_DESKTOP_ROOT
9120bbfda8aSnia		else if(Tmp_win->ewmhWindowType == wt_Desktop) {
9130bbfda8aSnia			fprintf(stderr, "HandleKeyPress: wt_Desktop -> C_ROOT\n");
9140bbfda8aSnia			Context = C_ROOT;
9150bbfda8aSnia		}
9160bbfda8aSnia#endif
9170bbfda8aSnia		else if(Event.xany.window == Tmp_win->title_w) {
9180bbfda8aSnia			Context = C_TITLE;
9190bbfda8aSnia		}
9200bbfda8aSnia		else if(Event.xany.window == Tmp_win->w) {
9210bbfda8aSnia			Context = C_WINDOW;
9220bbfda8aSnia		}
9230bbfda8aSnia		else if(Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w)) {
9240bbfda8aSnia			Context = C_ICON;
9250bbfda8aSnia		}
9260bbfda8aSnia		else if(Event.xany.window == Tmp_win->frame) {
9270bbfda8aSnia			Context = C_FRAME;
9280bbfda8aSnia		}
9290bbfda8aSnia		else if(Tmp_win->iconmanagerlist) {
9300bbfda8aSnia			if(Event.xany.window == Tmp_win->iconmanagerlist->w ||
9310bbfda8aSnia			                Event.xany.window == Tmp_win->iconmanagerlist->icon) {
9320bbfda8aSnia				Context = C_ICONMGR;
9330bbfda8aSnia			}
9340bbfda8aSnia		}
9350bbfda8aSnia		if(Tmp_win->iswspmgr) {
9360bbfda8aSnia			Context = C_WORKSPACE;
9370bbfda8aSnia		}
9380bbfda8aSnia	}
9390bbfda8aSnia
9400bbfda8aSnia	/*
9410bbfda8aSnia	 * We've figured out the Context.  Now see what modifiers we might
9420bbfda8aSnia	 * have set...
9430bbfda8aSnia	 */
9440bbfda8aSnia	unsigned int modifier = (Event.xkey.state | AlternateKeymap) & mods_used;
9450bbfda8aSnia	modifier = set_mask_ignore(modifier);
9460bbfda8aSnia	if(AlternateKeymap) {
9470bbfda8aSnia		XUngrabPointer(dpy, CurrentTime);
9480bbfda8aSnia		XUngrabKeyboard(dpy, CurrentTime);
9490bbfda8aSnia		AlternateKeymap = 0;
9500bbfda8aSnia	}
9510bbfda8aSnia
9520bbfda8aSnia
9530bbfda8aSnia	/*
9540bbfda8aSnia	 * Loop over our key bindings and do its thing if we find a matching
9550bbfda8aSnia	 * one.
9560bbfda8aSnia	 */
9570bbfda8aSnia	for(FuncKey *key = Scr->FuncKeyRoot.next; key != NULL; key = key->next) {
9580bbfda8aSnia		/*
9590bbfda8aSnia		 * Is this what we're trying to invoke?  Gotta be the right key,
9600bbfda8aSnia		 * and right modifier; those are easy.
9610bbfda8aSnia		 *
9620bbfda8aSnia		 * Context is tougher; that has to match what we're expecting as
9630bbfda8aSnia		 * well, except in the case of C_NAME, which we always have to
9640bbfda8aSnia		 * check to see if it'll match any windows.  So if we have the
9650bbfda8aSnia		 * right key and modifier, and it's a C_NAME context, it's a
9660bbfda8aSnia		 * "maybe" match and we have to go through the checks.
9670bbfda8aSnia		 */
9680bbfda8aSnia		if(key->keycode != Event.xkey.keycode ||
9690bbfda8aSnia		                key->mods != modifier ||
9700bbfda8aSnia		                (key->cont != Context && key->cont != C_NAME)) {
9710bbfda8aSnia			/* Nope, not yet */
9720bbfda8aSnia			continue;
9730bbfda8aSnia		}
9740bbfda8aSnia
9750bbfda8aSnia		/* 'k, it's a match (or potential match, in C_NAME case) */
9760bbfda8aSnia
9770bbfda8aSnia		/*
9780bbfda8aSnia		 * Weed out the functions that don't make sense to execute from a
9790bbfda8aSnia		 * key press
9800bbfda8aSnia		 *
9810bbfda8aSnia		 * TODO: add keyboard moving/resizing of windows.
9820bbfda8aSnia		 */
9830bbfda8aSnia		if(key->func == F_MOVE || key->func == F_RESIZE) {
9840bbfda8aSnia			return;
9850bbfda8aSnia		}
9860bbfda8aSnia
9870bbfda8aSnia		if(key->cont != C_NAME) {
9880bbfda8aSnia			/* Normal context binding; do what it wants */
9890bbfda8aSnia			if(key->func == F_MENU) {
9900bbfda8aSnia				/*
9910bbfda8aSnia				 * f.menu doesn't call the f.menu handler; we directly
9920bbfda8aSnia				 * do_key_menu() to pull it up.
9930bbfda8aSnia				 *
9940bbfda8aSnia				 * Note this is "we called f.menu from a keybinding", not
9950bbfda8aSnia				 * "we hit f.menu inside a menu we had up"; that's above.
9960bbfda8aSnia				 */
9970bbfda8aSnia				ButtonWindow = Tmp_win;
9980bbfda8aSnia				do_key_menu(key->menu, (Window) None);
9990bbfda8aSnia			}
10000bbfda8aSnia			else {
10010bbfda8aSnia#ifdef EWMH_DESKTOP_ROOT
10020bbfda8aSnia				if(Context == C_ROOT && Tmp_win != NULL) {
10030bbfda8aSnia					Context = C_WINDOW;
10040bbfda8aSnia					fprintf(stderr, "HandleKeyPress: wt_Desktop -> C_WINDOW\n");
10050bbfda8aSnia				}
10060bbfda8aSnia#endif /* EWMH */
10070bbfda8aSnia				ExecuteFunction(key->func, key->action, Event.xany.window,
10080bbfda8aSnia				                Tmp_win, &Event, Context, false);
10090bbfda8aSnia				if(!AlternateKeymap && !AlternateContext) {
10100bbfda8aSnia					XUngrabPointer(dpy, CurrentTime);
10110bbfda8aSnia				}
10120bbfda8aSnia			}
10130bbfda8aSnia			return;
10140bbfda8aSnia		}
10150bbfda8aSnia		else {
10160bbfda8aSnia			/*
10170bbfda8aSnia			 * By-name binding (i.e., quoted string for the context
10180bbfda8aSnia			 * argument in config; see the manual).  Find windows
10190bbfda8aSnia			 * matching that name and invoke on them, if any.
10200bbfda8aSnia			 *
10210bbfda8aSnia			 * This is the 'maybe' case above; we don't know whether this
10220bbfda8aSnia			 * does something until we try it.  If we don't get a match,
10230bbfda8aSnia			 * we loop back around and keep going through our functions
10240bbfda8aSnia			 * until we do.
10250bbfda8aSnia			 */
10260bbfda8aSnia			bool matched = false;
10270bbfda8aSnia			const size_t len = strlen(key->win_name);
10280bbfda8aSnia
10290bbfda8aSnia			/* try and match the name first */
10300bbfda8aSnia			for(Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
10310bbfda8aSnia			                Tmp_win = Tmp_win->next) {
10320bbfda8aSnia				if(!strncmp(key->win_name, Tmp_win->name, len)) {
10330bbfda8aSnia					matched = true;
10340bbfda8aSnia					ExecuteFunction(key->func, key->action, Tmp_win->frame,
10350bbfda8aSnia					                Tmp_win, &Event, C_FRAME, false);
10360bbfda8aSnia					if(!AlternateKeymap && !AlternateContext) {
10370bbfda8aSnia						XUngrabPointer(dpy, CurrentTime);
10380bbfda8aSnia					}
10390bbfda8aSnia				}
10400bbfda8aSnia			}
10410bbfda8aSnia
10420bbfda8aSnia			/* now try the res_name */
10430bbfda8aSnia			if(!matched) {
10440bbfda8aSnia				for(Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
10450bbfda8aSnia				                Tmp_win = Tmp_win->next) {
10460bbfda8aSnia					if(!strncmp(key->win_name, Tmp_win->class.res_name, len)) {
10470bbfda8aSnia						matched = true;
10480bbfda8aSnia						ExecuteFunction(key->func, key->action, Tmp_win->frame,
10490bbfda8aSnia						                Tmp_win, &Event, C_FRAME, false);
10500bbfda8aSnia						if(!AlternateKeymap && !AlternateContext) {
10510bbfda8aSnia							XUngrabPointer(dpy, CurrentTime);
10520bbfda8aSnia						}
10530bbfda8aSnia					}
10540bbfda8aSnia				}
10550bbfda8aSnia			}
10560bbfda8aSnia
10570bbfda8aSnia			/* now try the res_class */
10580bbfda8aSnia			if(!matched) {
10590bbfda8aSnia				for(Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
10600bbfda8aSnia				                Tmp_win = Tmp_win->next) {
10610bbfda8aSnia					if(!strncmp(key->win_name, Tmp_win->class.res_class, len)) {
10620bbfda8aSnia						matched = true;
10630bbfda8aSnia						ExecuteFunction(key->func, key->action, Tmp_win->frame,
10640bbfda8aSnia						                Tmp_win, &Event, C_FRAME, false);
10650bbfda8aSnia						if(!AlternateKeymap && !AlternateContext) {
10660bbfda8aSnia							XUngrabPointer(dpy, CurrentTime);
10670bbfda8aSnia						}
10680bbfda8aSnia					}
10690bbfda8aSnia				}
10700bbfda8aSnia			}
10710bbfda8aSnia
10720bbfda8aSnia			/*
10730bbfda8aSnia			 * If we wound up invoking something, we're done, so return.
10740bbfda8aSnia			 * If we didn't, we fall through to the next loop through our
10750bbfda8aSnia			 * defined bindings.
10760bbfda8aSnia			 *
10770bbfda8aSnia			 * By-name bindings are unique in this; normal contexts
10780bbfda8aSnia			 * couldn't have multiple matches, so that side of things
10790bbfda8aSnia			 * finishes when it deals with its found match.  But with
10800bbfda8aSnia			 * by-name we could have multiple bindings of a given
10810bbfda8aSnia			 * button/modifier with different names, so we have to go
10820bbfda8aSnia			 * back around to the next run through the for() loop.
10830bbfda8aSnia			 */
10840bbfda8aSnia			if(matched) {
10850bbfda8aSnia				return;
10860bbfda8aSnia			}
10870bbfda8aSnia		} // regular context or by-name?
10880bbfda8aSnia	} // Loop over all bindings
10890bbfda8aSnia
10900bbfda8aSnia
10910bbfda8aSnia	/*
10920bbfda8aSnia	 * If we get here, no function key was bound to the key.  Send it to
10930bbfda8aSnia	 * the client if it was in a window we know about.  Mostly this
10940bbfda8aSnia	 * doesn't happen; clients with focus get their events more directly,
10950bbfda8aSnia	 * but special cases may cause this.
10960bbfda8aSnia	 */
10970bbfda8aSnia	if(Tmp_win) {
10980bbfda8aSnia		if(Context == C_WORKSPACE) {
10990bbfda8aSnia			WMgrHandleKeyPressEvent(Scr->currentvs, &Event);
11000bbfda8aSnia			return;
11010bbfda8aSnia		}
11020bbfda8aSnia		if(Context == C_ICON ||
11030bbfda8aSnia		                Context == C_FRAME ||
11040bbfda8aSnia		                Context == C_TITLE ||
11050bbfda8aSnia		                Context == C_ICONMGR) {
11060bbfda8aSnia			Event.xkey.window = Tmp_win->w;
11070bbfda8aSnia			XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
11080bbfda8aSnia		}
11090bbfda8aSnia	}
11100bbfda8aSnia
11110bbfda8aSnia
11120bbfda8aSnia	/* And done */
11130bbfda8aSnia}
11140bbfda8aSnia
11150bbfda8aSnia
11160bbfda8aSnia
11170bbfda8aSnia/***********************************************************************
11180bbfda8aSnia *
11190bbfda8aSnia *  Procedure:
11200bbfda8aSnia *      HandlePropertyNotify - property notify event handler
11210bbfda8aSnia *
11220bbfda8aSnia ***********************************************************************
11230bbfda8aSnia */
11240bbfda8aSnia
11250bbfda8aSniavoid HandlePropertyNotify(void)
11260bbfda8aSnia{
11270bbfda8aSnia	Atom actual = None;
11280bbfda8aSnia	int actual_format;
11290bbfda8aSnia	unsigned long nitems, bytesafter;
11300bbfda8aSnia	unsigned long valuemask;            /* mask for create windows */
11310bbfda8aSnia	XSetWindowAttributes attributes;    /* attributes for create windows */
11320bbfda8aSnia	Pixmap pm;
11330bbfda8aSnia	Icon *icon;
11340bbfda8aSnia
11350bbfda8aSnia
11360bbfda8aSnia	/* watch for standard colormap changes */
11370bbfda8aSnia	if(Event.xproperty.window == Scr->Root) {
11380bbfda8aSnia
11390bbfda8aSnia		if(Event.xproperty.atom == XA_WM_CURRENTWORKSPACE) {
11400bbfda8aSnia			unsigned char *prop;
11410bbfda8aSnia			switch(Event.xproperty.state) {
11420bbfda8aSnia				case PropertyNewValue:
11430bbfda8aSnia					if(XGetWindowProperty(dpy, Scr->Root, XA_WM_CURRENTWORKSPACE,
11440bbfda8aSnia					                      0L, 200L, False, XA_STRING, &actual, &actual_format,
11450bbfda8aSnia					                      &nitems, &bytesafter, &prop) == Success) {
11460bbfda8aSnia						if(nitems == 0) {
11470bbfda8aSnia							return;
11480bbfda8aSnia						}
11490bbfda8aSnia						GotoWorkSpaceByName(Scr->vScreenList, (char *)prop);
11500bbfda8aSnia						XFree(prop);
11510bbfda8aSnia					}
11520bbfda8aSnia					return;
11530bbfda8aSnia
11540bbfda8aSnia				default:
11550bbfda8aSnia					return;
11560bbfda8aSnia			}
11570bbfda8aSnia		}
11580bbfda8aSnia		switch(Event.xproperty.state) {
11590bbfda8aSnia			case PropertyNewValue: {
11600bbfda8aSnia				XStandardColormap *maps = NULL;
11610bbfda8aSnia				int nmaps;
11620bbfda8aSnia
11630bbfda8aSnia				if(XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps,
11640bbfda8aSnia				                    Event.xproperty.atom)) {
11650bbfda8aSnia					/* if got one, then replace any existing entry */
11660bbfda8aSnia					InsertRGBColormap(Event.xproperty.atom, maps, nmaps, true);
11670bbfda8aSnia				}
11680bbfda8aSnia				return;
11690bbfda8aSnia			}
11700bbfda8aSnia
11710bbfda8aSnia			case PropertyDelete:
11720bbfda8aSnia				RemoveRGBColormap(Event.xproperty.atom);
11730bbfda8aSnia				return;
11740bbfda8aSnia		}
11750bbfda8aSnia	}
11760bbfda8aSnia
11770bbfda8aSnia	if(!Tmp_win) {
11780bbfda8aSnia		return;        /* unknown window */
11790bbfda8aSnia	}
11800bbfda8aSnia
11810bbfda8aSnia#define MAX_NAME_LEN 200L               /* truncate to this many */
11820bbfda8aSnia
11830bbfda8aSnia	switch(Event.xproperty.atom) {
11840bbfda8aSnia		case XA_WM_NAME: {
11850bbfda8aSnia			char *prop = GetWMPropertyString(Tmp_win->w, XA_WM_NAME);
11860bbfda8aSnia			if(prop == NULL) {
11870bbfda8aSnia				// Clear
11880bbfda8aSnia				FreeWMPropertyString(Tmp_win->names.wm_name);
11890bbfda8aSnia				Tmp_win->names.wm_name = NULL;
11900bbfda8aSnia				apply_window_name(Tmp_win);
11910bbfda8aSnia				return;
11920bbfda8aSnia			}
11930bbfda8aSnia
11940bbfda8aSnia			if(Tmp_win->names.wm_name != NULL
11950bbfda8aSnia			                && strcmp(Tmp_win->names.wm_name, prop) == 0) {
11960bbfda8aSnia				/* No change, just free and skip out */
11970bbfda8aSnia				free(prop);
11980bbfda8aSnia				return;
11990bbfda8aSnia			}
12000bbfda8aSnia
12010bbfda8aSnia			/* It's changing, free the old and bring in the new */
12020bbfda8aSnia			FreeWMPropertyString(Tmp_win->names.wm_name);
12030bbfda8aSnia			Tmp_win->names.wm_name = prop;
12040bbfda8aSnia
12050bbfda8aSnia			/* Kick the reset process */
12060bbfda8aSnia			apply_window_name(Tmp_win);
12070bbfda8aSnia
12080bbfda8aSnia			break;
12090bbfda8aSnia		}
12100bbfda8aSnia
12110bbfda8aSnia		case XA_WM_ICON_NAME: {
12120bbfda8aSnia			char *prop = GetWMPropertyString(Tmp_win->w, XA_WM_ICON_NAME);
12130bbfda8aSnia			if(prop == NULL) {
12140bbfda8aSnia				// Clear
12150bbfda8aSnia				FreeWMPropertyString(Tmp_win->names.wm_icon_name);
12160bbfda8aSnia				Tmp_win->names.wm_icon_name = NULL;
12170bbfda8aSnia				apply_window_icon_name(Tmp_win);
12180bbfda8aSnia				return;
12190bbfda8aSnia			}
12200bbfda8aSnia
12210bbfda8aSnia			/* No change?  Nothing to do. */
12220bbfda8aSnia			if(Tmp_win->names.wm_icon_name != NULL
12230bbfda8aSnia			                && strcmp(Tmp_win->names.wm_icon_name, prop) == 0) {
12240bbfda8aSnia				free(prop);
12250bbfda8aSnia				return;
12260bbfda8aSnia			}
12270bbfda8aSnia
12280bbfda8aSnia			/* It's changing, free the old and bring in the new */
12290bbfda8aSnia			FreeWMPropertyString(Tmp_win->names.wm_icon_name);
12300bbfda8aSnia			Tmp_win->names.wm_icon_name = prop;
12310bbfda8aSnia
12320bbfda8aSnia			/* And show the new */
12330bbfda8aSnia			apply_window_icon_name(Tmp_win);
12340bbfda8aSnia
12350bbfda8aSnia			break;
12360bbfda8aSnia		}
12370bbfda8aSnia
12380bbfda8aSnia		case XA_WM_HINTS: {
12390bbfda8aSnia			{
12400bbfda8aSnia				XWMHints *nhints = XGetWMHints(dpy, Event.xany.window);
12410bbfda8aSnia				if(!nhints) {
12420bbfda8aSnia					/*
12430bbfda8aSnia					 * I guess this means that window removed the
12440bbfda8aSnia					 * property completely.  Just keep using what we
12450bbfda8aSnia					 * already have for it though; we gotta have
12460bbfda8aSnia					 * something, and whatever it last said is probably
12470bbfda8aSnia					 * more reasonable than getting completely new
12480bbfda8aSnia					 * synthetic hints anyway.
12490bbfda8aSnia					 */
12500bbfda8aSnia					break;
12510bbfda8aSnia				}
12520bbfda8aSnia
12530bbfda8aSnia				XFree(Tmp_win->wmhints);
12540bbfda8aSnia				Tmp_win->wmhints = munge_wmhints(Tmp_win, nhints);
12550bbfda8aSnia			}
12560bbfda8aSnia
12570bbfda8aSnia			icon = Tmp_win->icon;
12580bbfda8aSnia
12590bbfda8aSnia			/*
12600bbfda8aSnia			 * If there already is an icon found in a way that has priority
12610bbfda8aSnia			 * over these hints, disable the flags and remove them from
12620bbfda8aSnia			 * consideration, now and in the future.
12630bbfda8aSnia			 */
12640bbfda8aSnia			if(Tmp_win->forced ||
12650bbfda8aSnia			                (icon && icon->match == match_net_wm_icon)) {
12660bbfda8aSnia				Tmp_win->wmhints->flags &= ~(IconWindowHint | IconPixmapHint | IconMaskHint);
12670bbfda8aSnia			}
12680bbfda8aSnia
12690bbfda8aSnia			if(Tmp_win->wmhints->flags & IconWindowHint) {
12700bbfda8aSnia				if(icon && icon->w) {
12710bbfda8aSnia					int icon_x, icon_y;
12720bbfda8aSnia
12730bbfda8aSnia					/*
12740bbfda8aSnia					 * There's already an icon window.
12750bbfda8aSnia					 * Try to find out where it is; if we succeed, move the new
12760bbfda8aSnia					 * window to where the old one is.
12770bbfda8aSnia					 */
12780bbfda8aSnia					if(XGetGeometry(dpy, icon->w, &JunkRoot, &icon_x,
12790bbfda8aSnia					                &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
12800bbfda8aSnia						/*
12810bbfda8aSnia						 * Move the new icon window to where the old one was.
12820bbfda8aSnia						 */
12830bbfda8aSnia						XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
12840bbfda8aSnia						            icon_y);
12850bbfda8aSnia					}
12860bbfda8aSnia
12870bbfda8aSnia					/*
12880bbfda8aSnia					 * If the window is iconic, map the new icon window.
12890bbfda8aSnia					 */
12900bbfda8aSnia					if(Tmp_win->isicon) {
12910bbfda8aSnia						XMapWindow(dpy, Tmp_win->wmhints->icon_window);
12920bbfda8aSnia					}
12930bbfda8aSnia
12940bbfda8aSnia					/*
12950bbfda8aSnia					 * Now, if the old window isn't ours, unmap it, otherwise
12960bbfda8aSnia					 * just get rid of it completely.
12970bbfda8aSnia					 */
12980bbfda8aSnia					if(icon->w_not_ours) {
12990bbfda8aSnia						if(icon->w != Tmp_win->wmhints->icon_window) {
13000bbfda8aSnia							XUnmapWindow(dpy, icon->w);
13010bbfda8aSnia						}
13020bbfda8aSnia					}
13030bbfda8aSnia					else {
13040bbfda8aSnia						XDestroyWindow(dpy, icon->w);
13050bbfda8aSnia					}
13060bbfda8aSnia
13070bbfda8aSnia					/*
13080bbfda8aSnia					 * The new icon window isn't our window, so note that fact
13090bbfda8aSnia					 * so that we don't treat it as ours.
13100bbfda8aSnia					 */
13110bbfda8aSnia					icon->w_not_ours = true;
13120bbfda8aSnia
13130bbfda8aSnia					/*
13140bbfda8aSnia					 * Now make the new window the icon window for this window,
13150bbfda8aSnia					 * and set it up to work as such (select for key presses
13160bbfda8aSnia					 * and button presses/releases, set up the contexts for it,
13170bbfda8aSnia					 * and define the cursor for it).
13180bbfda8aSnia					 */
13190bbfda8aSnia					icon->w = Tmp_win->wmhints->icon_window;
13200bbfda8aSnia					XSelectInput(dpy, icon->w,
13210bbfda8aSnia					             KeyPressMask | ButtonPressMask | ButtonReleaseMask);
13220bbfda8aSnia					XSaveContext(dpy, icon->w, TwmContext, (XPointer)Tmp_win);
13230bbfda8aSnia					XSaveContext(dpy, icon->w, ScreenContext, (XPointer)Scr);
13240bbfda8aSnia					XDefineCursor(dpy, icon->w, Scr->IconCursor);
13250bbfda8aSnia				}
13260bbfda8aSnia			}
13270bbfda8aSnia
13280bbfda8aSnia			if(icon && icon->w &&
13290bbfda8aSnia			                (Tmp_win->wmhints->flags & IconPixmapHint)) {
13300bbfda8aSnia				int x;
13310bbfda8aSnia				unsigned int IconDepth;
13320bbfda8aSnia
13330bbfda8aSnia				if(!XGetGeometry(dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
13340bbfda8aSnia				                 &JunkX, &JunkY, (unsigned int *)&icon->width,
13350bbfda8aSnia				                 (unsigned int *)&icon->height, &JunkBW,
13360bbfda8aSnia				                 &IconDepth)) {
13370bbfda8aSnia					return;
13380bbfda8aSnia				}
13390bbfda8aSnia
13400bbfda8aSnia				pm = XCreatePixmap(dpy, Scr->Root, icon->width,
13410bbfda8aSnia				                   icon->height, Scr->d_depth);
13420bbfda8aSnia
13430bbfda8aSnia				FB(icon->iconc.fore, icon->iconc.back);
13440bbfda8aSnia
13450bbfda8aSnia				if(IconDepth == Scr->d_depth)
13460bbfda8aSnia					XCopyArea(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
13470bbfda8aSnia					          0, 0, icon->width, icon->height, 0, 0);
13480bbfda8aSnia				else
13490bbfda8aSnia					XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
13500bbfda8aSnia					           0, 0, icon->width, icon->height, 0, 0, 1);
13510bbfda8aSnia
13520bbfda8aSnia				if(icon->image) {
13530bbfda8aSnia					/* Release the existing Image: it may be a shared one (UnknownIcon) */
13540bbfda8aSnia					ReleaseIconImage(icon);
13550bbfda8aSnia					/* conjure up a new Image */
13560bbfda8aSnia					Image *image = AllocImage();
13570bbfda8aSnia					image->pixmap = pm;
13580bbfda8aSnia					image->width  = icon->width;
13590bbfda8aSnia					image->height = icon->height;
13600bbfda8aSnia					icon->image = image;
13610bbfda8aSnia					icon->match = match_icon_pixmap_hint;
13620bbfda8aSnia				}
13630bbfda8aSnia
13640bbfda8aSnia				valuemask = CWBackPixmap;
13650bbfda8aSnia				attributes.background_pixmap = pm;
13660bbfda8aSnia
13670bbfda8aSnia				if(icon->bm_w) {
13680bbfda8aSnia					XDestroyWindow(dpy, icon->bm_w);
13690bbfda8aSnia				}
13700bbfda8aSnia
13710bbfda8aSnia				x = GetIconOffset(icon);
13720bbfda8aSnia				icon->bm_w =
13730bbfda8aSnia				        XCreateWindow(dpy, icon->w, x, 0,
13740bbfda8aSnia				                      icon->width,
13750bbfda8aSnia				                      icon->height,
13760bbfda8aSnia				                      0, Scr->d_depth,
13770bbfda8aSnia				                      CopyFromParent, Scr->d_visual,
13780bbfda8aSnia				                      valuemask, &attributes);
13790bbfda8aSnia
13800bbfda8aSnia				if(!(Tmp_win->wmhints->flags & IconMaskHint)) {
13810bbfda8aSnia					XRectangle rect;
13820bbfda8aSnia
13830bbfda8aSnia					rect.x      = x;
13840bbfda8aSnia					rect.y      = 0;
13850bbfda8aSnia					rect.width  = icon->width;
13860bbfda8aSnia					rect.height = icon->height;
13870bbfda8aSnia					XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0,
13880bbfda8aSnia					                        0, &rect, 1, ShapeUnion, 0);
13890bbfda8aSnia				}
13900bbfda8aSnia				XMapSubwindows(dpy, icon->w);
13910bbfda8aSnia				RedoIconName(Tmp_win);
13920bbfda8aSnia			}
13930bbfda8aSnia			if(icon && icon->w &&
13940bbfda8aSnia			                (Tmp_win->wmhints->flags & IconMaskHint) &&
13950bbfda8aSnia			                icon->match == match_icon_pixmap_hint) {
13960bbfda8aSnia				/* Only set the mask if the pixmap came from a WM_HINTS too,
13970bbfda8aSnia				 * for easier resource management.
13980bbfda8aSnia				 */
13990bbfda8aSnia				int x;
14000bbfda8aSnia				Pixmap mask;
14010bbfda8aSnia				GC gc;
14020bbfda8aSnia				unsigned int IconWidth, IconHeight, IconDepth;
14030bbfda8aSnia
14040bbfda8aSnia				if(!XGetGeometry(dpy, Tmp_win->wmhints->icon_mask, &JunkRoot,
14050bbfda8aSnia				                 &JunkX, &JunkY, &IconWidth, &IconHeight, &JunkBW,
14060bbfda8aSnia				                 &IconDepth)) {
14070bbfda8aSnia					return;
14080bbfda8aSnia				}
14090bbfda8aSnia				if(IconDepth != 1) {
14100bbfda8aSnia					return;
14110bbfda8aSnia				}
14120bbfda8aSnia
14130bbfda8aSnia				mask = XCreatePixmap(dpy, Scr->Root, IconWidth, IconHeight, 1);
14140bbfda8aSnia				if(!mask) {
14150bbfda8aSnia					return;
14160bbfda8aSnia				}
14170bbfda8aSnia				gc = XCreateGC(dpy, mask, 0, NULL);
14180bbfda8aSnia				if(!gc) {
14190bbfda8aSnia					return;
14200bbfda8aSnia				}
14210bbfda8aSnia				XCopyArea(dpy, Tmp_win->wmhints->icon_mask, mask, gc,
14220bbfda8aSnia				          0, 0, IconWidth, IconHeight, 0, 0);
14230bbfda8aSnia				XFreeGC(dpy, gc);
14240bbfda8aSnia				x = GetIconOffset(icon);
14250bbfda8aSnia				XShapeCombineMask(dpy, icon->bm_w, ShapeBounding, 0, 0, mask,
14260bbfda8aSnia				                  ShapeSet);
14270bbfda8aSnia				XShapeCombineMask(dpy, icon->w,    ShapeBounding, x, 0, mask,
14280bbfda8aSnia				                  ShapeSet);
14290bbfda8aSnia				if(icon->image) {
14300bbfda8aSnia					if(icon->image->mask) {
14310bbfda8aSnia						XFreePixmap(dpy, icon->image->mask);
14320bbfda8aSnia					}
14330bbfda8aSnia					icon->image->mask = mask;
14340bbfda8aSnia					RedoIconName(Tmp_win);
14350bbfda8aSnia				}
14360bbfda8aSnia			}
14370bbfda8aSnia			if(Tmp_win->wmhints->flags & IconPixmapHint) {
14380bbfda8aSnia				AutoPopupMaybe(Tmp_win);
14390bbfda8aSnia			}
14400bbfda8aSnia
14410bbfda8aSnia			break;
14420bbfda8aSnia		}
14430bbfda8aSnia
14440bbfda8aSnia		case XA_WM_NORMAL_HINTS: {
14450bbfda8aSnia			GetWindowSizeHints(Tmp_win);
14460bbfda8aSnia			break;
14470bbfda8aSnia		}
14480bbfda8aSnia		default: {
14490bbfda8aSnia			if(Event.xproperty.atom == XA_WM_COLORMAP_WINDOWS) {
14500bbfda8aSnia				FetchWmColormapWindows(Tmp_win);    /* frees old data */
14510bbfda8aSnia				break;
14520bbfda8aSnia			}
14530bbfda8aSnia			else if(Event.xproperty.atom == XA_WM_PROTOCOLS) {
14540bbfda8aSnia				FetchWmProtocols(Tmp_win);
14550bbfda8aSnia				break;
14560bbfda8aSnia			}
14570bbfda8aSnia			else if(Event.xproperty.atom == XA_WM_OCCUPATION) {
14580bbfda8aSnia				unsigned char *prop;
14590bbfda8aSnia				if(XGetWindowProperty(dpy, Tmp_win->w, Event.xproperty.atom, 0L, MAX_NAME_LEN,
14600bbfda8aSnia				                      False,
14610bbfda8aSnia				                      XA_STRING, &actual, &actual_format, &nitems,
14620bbfda8aSnia				                      &bytesafter, &prop) != Success ||
14630bbfda8aSnia				                actual == None) {
14640bbfda8aSnia					return;
14650bbfda8aSnia				}
14660bbfda8aSnia				ChangeOccupation(Tmp_win, GetMaskFromProperty(prop, nitems));
14670bbfda8aSnia				XFree(prop);
14680bbfda8aSnia			}
14690bbfda8aSnia			else if(Event.xproperty.atom == XA_CTWM_WM_NAME) {
14700bbfda8aSnia				char *prop = GetWMPropertyString(Tmp_win->w, XA_CTWM_WM_NAME);
14710bbfda8aSnia				if(prop == NULL) {
14720bbfda8aSnia					// Clearing
14730bbfda8aSnia					FreeWMPropertyString(Tmp_win->names.ctwm_wm_name);
14740bbfda8aSnia					Tmp_win->names.ctwm_wm_name = NULL;
14750bbfda8aSnia					apply_window_name(Tmp_win);
14760bbfda8aSnia					return;
14770bbfda8aSnia				}
14780bbfda8aSnia
14790bbfda8aSnia				if(Tmp_win->names.ctwm_wm_name != NULL
14800bbfda8aSnia				                && strcmp(Tmp_win->names.ctwm_wm_name,
14810bbfda8aSnia				                          prop) == 0) {
14820bbfda8aSnia					/* No change, just free and skip out */
14830bbfda8aSnia					free(prop);
14840bbfda8aSnia					return;
14850bbfda8aSnia				}
14860bbfda8aSnia
14870bbfda8aSnia				/* It's changing, free the old and bring in the new */
14880bbfda8aSnia				FreeWMPropertyString(Tmp_win->names.ctwm_wm_name);
14890bbfda8aSnia				Tmp_win->names.ctwm_wm_name = prop;
14900bbfda8aSnia
14910bbfda8aSnia				/* Kick the reset process */
14920bbfda8aSnia				apply_window_name(Tmp_win);
14930bbfda8aSnia
14940bbfda8aSnia				return;
14950bbfda8aSnia			}
14960bbfda8aSnia			else if(Event.xproperty.atom == XA_CTWM_WM_ICON_NAME) {
14970bbfda8aSnia				char *prop = GetWMPropertyString(Tmp_win->w,
14980bbfda8aSnia				                                 XA_CTWM_WM_ICON_NAME);
14990bbfda8aSnia				if(prop == NULL) {
15000bbfda8aSnia					// Clearing
15010bbfda8aSnia					FreeWMPropertyString(Tmp_win->names.ctwm_wm_icon_name);
15020bbfda8aSnia					Tmp_win->names.ctwm_wm_icon_name = NULL;
15030bbfda8aSnia					apply_window_icon_name(Tmp_win);
15040bbfda8aSnia					return;
15050bbfda8aSnia				}
15060bbfda8aSnia
15070bbfda8aSnia				if(Tmp_win->names.ctwm_wm_icon_name != NULL
15080bbfda8aSnia				                && strcmp(Tmp_win->names.ctwm_wm_icon_name,
15090bbfda8aSnia				                          prop) == 0) {
15100bbfda8aSnia					/* No change, just free and skip out */
15110bbfda8aSnia					free(prop);
15120bbfda8aSnia					return;
15130bbfda8aSnia				}
15140bbfda8aSnia
15150bbfda8aSnia				/* It's changing, free the old and bring in the new */
15160bbfda8aSnia				FreeWMPropertyString(Tmp_win->names.ctwm_wm_icon_name);
15170bbfda8aSnia				Tmp_win->names.ctwm_wm_icon_name = prop;
15180bbfda8aSnia
15190bbfda8aSnia				/* Kick the reset process */
15200bbfda8aSnia				apply_window_icon_name(Tmp_win);
15210bbfda8aSnia
15220bbfda8aSnia				break;
15230bbfda8aSnia			}
15240bbfda8aSnia#ifdef EWMH
15250bbfda8aSnia			else if(EwmhHandlePropertyNotify(&Event.xproperty, Tmp_win)) {
15260bbfda8aSnia				/* event handled */
15270bbfda8aSnia			}
15280bbfda8aSnia#endif /* EWMH */
15290bbfda8aSnia			break;
15300bbfda8aSnia		}
15310bbfda8aSnia	}
15320bbfda8aSnia}
15330bbfda8aSnia
15340bbfda8aSnia
15350bbfda8aSnia/***********************************************************************
15360bbfda8aSnia *
15370bbfda8aSnia *  Procedure:
15380bbfda8aSnia *      HandleClientMessage - client message event handler
15390bbfda8aSnia *
15400bbfda8aSnia ***********************************************************************
15410bbfda8aSnia */
15420bbfda8aSnia
15430bbfda8aSniavoid HandleClientMessage(void)
15440bbfda8aSnia{
15450bbfda8aSnia
15460bbfda8aSnia	if(Event.xclient.message_type == XA_WM_CHANGE_STATE) {
15470bbfda8aSnia		if(Tmp_win != NULL) {
15480bbfda8aSnia			if(Event.xclient.data.l[0] == IconicState && !Tmp_win->isicon) {
15490bbfda8aSnia				XEvent button;
15500bbfda8aSnia				XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild,
15510bbfda8aSnia				              &(button.xmotion.x_root),
15520bbfda8aSnia				              &(button.xmotion.y_root),
15530bbfda8aSnia				              &JunkX, &JunkY, &JunkMask);
15540bbfda8aSnia
15550bbfda8aSnia				ExecuteFunction(F_ICONIFY, NULL, Event.xany.window,
15560bbfda8aSnia				                Tmp_win, &button, FRAME, false);
15570bbfda8aSnia				XUngrabPointer(dpy, CurrentTime);
15580bbfda8aSnia			}
15590bbfda8aSnia		}
15600bbfda8aSnia		return;
15610bbfda8aSnia	}
15620bbfda8aSnia
15630bbfda8aSnia#ifdef EWMH
15640bbfda8aSnia	if(EwmhClientMessage(&Event.xclient)) {
15650bbfda8aSnia		return;
15660bbfda8aSnia	}
15670bbfda8aSnia#endif
15680bbfda8aSnia
15690bbfda8aSnia	else if((Event.xclient.message_type == XA_WM_PROTOCOLS) &&
15700bbfda8aSnia	                (Event.xclient.data.l[0] == XA_WM_END_OF_ANIMATION)) {
15710bbfda8aSnia		if(Animating > 0) {
15720bbfda8aSnia			Animating--;
15730bbfda8aSnia		}
15740bbfda8aSnia		else {
15750bbfda8aSnia			fprintf(stderr, "!! end of unknown animation !!\n");
15760bbfda8aSnia		}
15770bbfda8aSnia	}
15780bbfda8aSnia}
15790bbfda8aSnia
15800bbfda8aSnia
15810bbfda8aSnia/***********************************************************************
15820bbfda8aSnia *
15830bbfda8aSnia *  Procedure:
15840bbfda8aSnia *      HandleExpose - expose event handler
15850bbfda8aSnia *
15860bbfda8aSnia ***********************************************************************
15870bbfda8aSnia */
15880bbfda8aSnia
15890bbfda8aSniastatic void flush_expose(Window w);
15900bbfda8aSnia
15910bbfda8aSniavoid HandleExpose(void)
15920bbfda8aSnia{
15930bbfda8aSnia	MenuRoot *tmp;
15940bbfda8aSnia	VirtualScreen *vs;
15950bbfda8aSnia
15960bbfda8aSnia	if(XFindContext(dpy, Event.xany.window, MenuContext, (XPointer *)&tmp) == 0) {
15970bbfda8aSnia		PaintMenu(tmp, &Event);
15980bbfda8aSnia		return;
15990bbfda8aSnia	}
16000bbfda8aSnia
16010bbfda8aSnia	if(Event.xexpose.count != 0) {
16020bbfda8aSnia		return;
16030bbfda8aSnia	}
16040bbfda8aSnia
16050bbfda8aSnia	if(Event.xany.window == Scr->InfoWindow.win && Scr->InfoWindow.mapped) {
16060bbfda8aSnia		draw_info_window();
16070bbfda8aSnia		flush_expose(Event.xany.window);
16080bbfda8aSnia	}
16090bbfda8aSnia	else if(Tmp_win != NULL) {
16100bbfda8aSnia		if(Scr->use3Dborders && (Event.xany.window == Tmp_win->frame)) {
16110bbfda8aSnia			PaintBorders(Tmp_win, ((Tmp_win == Scr->Focus) ? true : false));
16120bbfda8aSnia			flush_expose(Event.xany.window);
16130bbfda8aSnia			return;
16140bbfda8aSnia		}
16150bbfda8aSnia		else if(Event.xany.window == Tmp_win->title_w) {
16160bbfda8aSnia			PaintTitle(Tmp_win);
16170bbfda8aSnia			flush_expose(Event.xany.window);
16180bbfda8aSnia			return;
16190bbfda8aSnia		}
16200bbfda8aSnia		else if(Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w) &&
16210bbfda8aSnia		                ! Scr->NoIconTitlebar &&
16220bbfda8aSnia		                ! LookInList(Scr->NoIconTitle, Tmp_win->name, &Tmp_win->class)) {
16230bbfda8aSnia			PaintIcon(Tmp_win);
16240bbfda8aSnia			flush_expose(Event.xany.window);
16250bbfda8aSnia			return;
16260bbfda8aSnia		}
16270bbfda8aSnia		else if(Tmp_win->titlebuttons) {
16280bbfda8aSnia			int i;
16290bbfda8aSnia			TBWindow *tbw;
16300bbfda8aSnia			Window w = Event.xany.window;
16310bbfda8aSnia			int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
16320bbfda8aSnia
16330bbfda8aSnia			/*
16340bbfda8aSnia			 * This looks an awful lot like a manual reimplementation of
16350bbfda8aSnia			 * PaintTitleButtons().  It's not quite though, it's just
16360bbfda8aSnia			 * looking up one button to paint it.  And it would be a
16370bbfda8aSnia			 * little grody trying to shoehorn it in.
16380bbfda8aSnia			 */
16390bbfda8aSnia			for(i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
16400bbfda8aSnia				if(w == tbw->window) {
16410bbfda8aSnia					PaintTitleButton(Tmp_win, tbw);
16420bbfda8aSnia					flush_expose(tbw->window);
16430bbfda8aSnia					return;
16440bbfda8aSnia				}
16450bbfda8aSnia			}
16460bbfda8aSnia		}
16470bbfda8aSnia		for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
16480bbfda8aSnia			if(Tmp_win == vs->wsw->twm_win) {
16490bbfda8aSnia				WMgrHandleExposeEvent(vs, &Event);
16500bbfda8aSnia				flush_expose(Event.xany.window);
16510bbfda8aSnia				return;
16520bbfda8aSnia			}
16530bbfda8aSnia		}
16540bbfda8aSnia		if(Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
16550bbfda8aSnia			/*
16560bbfda8aSnia			 * The occupyWindow has a bunch of sub-windows for each
16570bbfda8aSnia			 * button in it, and each of them wind up getting Expose
16580bbfda8aSnia			 * events kicked for them.  The upshot is that we re-paint
16590bbfda8aSnia			 * the occupy window once for itself, and then once for each
16600bbfda8aSnia			 * button inside it.  We'll always get one for the window
16610bbfda8aSnia			 * itself, so just paint it for that one, and ignore the rest
16620bbfda8aSnia			 * of the events.
16630bbfda8aSnia			 *
16640bbfda8aSnia			 * XXX Maybe a better solution is just to mask off Expose
16650bbfda8aSnia			 * events for the other windows...
16660bbfda8aSnia			 */
16670bbfda8aSnia			if(Event.xany.window == Scr->workSpaceMgr.occupyWindow->w) {
16680bbfda8aSnia				PaintOccupyWindow();
16690bbfda8aSnia				flush_expose(Event.xany.window);
16700bbfda8aSnia			}
16710bbfda8aSnia			return;
16720bbfda8aSnia		}
16730bbfda8aSnia		else if(Tmp_win->iconmanagerlist) {
16740bbfda8aSnia			WList *iconmanagerlist = Tmp_win->iconmanagerlist;
16750bbfda8aSnia
16760bbfda8aSnia			if(Event.xany.window == iconmanagerlist->w) {
16770bbfda8aSnia				DrawIconManagerIconName(Tmp_win);
16780bbfda8aSnia				flush_expose(Event.xany.window);
16790bbfda8aSnia				return;
16800bbfda8aSnia			}
16810bbfda8aSnia			else if(Event.xany.window == iconmanagerlist->icon) {
16820bbfda8aSnia				ShowIconifiedIcon(Tmp_win);
16830bbfda8aSnia				flush_expose(Event.xany.window);
16840bbfda8aSnia				return;
16850bbfda8aSnia			}
16860bbfda8aSnia		}
16870bbfda8aSnia	}
16880bbfda8aSnia}
16890bbfda8aSnia
16900bbfda8aSnia
16910bbfda8aSniastatic void remove_window_from_ring(TwmWindow *tmp)
16920bbfda8aSnia{
16930bbfda8aSnia	if(enter_win == tmp) {
16940bbfda8aSnia		enter_flag = false;
16950bbfda8aSnia		enter_win = NULL;
16960bbfda8aSnia	}
16970bbfda8aSnia	if(raise_win == Tmp_win) {
16980bbfda8aSnia		raise_win = NULL;
16990bbfda8aSnia	}
17000bbfda8aSnia	if(leave_win == tmp) {
17010bbfda8aSnia		leave_flag = false;
17020bbfda8aSnia		leave_win = NULL;
17030bbfda8aSnia	}
17040bbfda8aSnia	if(lower_win == Tmp_win) {
17050bbfda8aSnia		lower_win = NULL;
17060bbfda8aSnia	}
17070bbfda8aSnia
1708b18c2d1eSnia	UnlinkWindowFromRing(tmp);
17090bbfda8aSnia}
17100bbfda8aSnia
17110bbfda8aSnia
17120bbfda8aSnia/***********************************************************************
17130bbfda8aSnia *
17140bbfda8aSnia *  Procedure:
17150bbfda8aSnia *      HandleDestroyNotify - DestroyNotify event handler
17160bbfda8aSnia *
17170bbfda8aSnia ***********************************************************************
17180bbfda8aSnia */
17190bbfda8aSnia
17200bbfda8aSniavoid HandleDestroyNotify(void)
17210bbfda8aSnia{
17220bbfda8aSnia	/*
17230bbfda8aSnia	 * Warning, this is also called by HandleUnmapNotify; if it ever needs to
17240bbfda8aSnia	 * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
17250bbfda8aSnia	 * into a DestroyNotify.
17260bbfda8aSnia	 */
17270bbfda8aSnia
17280bbfda8aSnia	if(Tmp_win == NULL) {
17290bbfda8aSnia		return;
17300bbfda8aSnia	}
17310bbfda8aSnia
17320bbfda8aSnia	RemoveWindowFromRegion(Tmp_win);
17330bbfda8aSnia
17340bbfda8aSnia	if(Tmp_win->icon != NULL) {
17350bbfda8aSnia		OtpRemove(Tmp_win, IconWin);
17360bbfda8aSnia	}
17370bbfda8aSnia	OtpRemove(Tmp_win, WinWin);
17380bbfda8aSnia
17390bbfda8aSnia#ifdef EWMH
17400bbfda8aSnia	/* Remove the old window from the EWMH client list */
17410bbfda8aSnia	EwmhDeleteClientWindow(Tmp_win);
17420bbfda8aSnia	EwmhSet_NET_CLIENT_LIST_STACKING();
17430bbfda8aSnia#endif /* EWMH */
17440bbfda8aSnia	if(Tmp_win == Scr->Focus) {
17450bbfda8aSnia		Scr->Focus = NULL;
17460bbfda8aSnia		FocusOnRoot();
17470bbfda8aSnia	}
17480bbfda8aSnia	if(Scr->SaveWorkspaceFocus) {
17490bbfda8aSnia		struct WorkSpace *ws;
17500bbfda8aSnia		for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
17510bbfda8aSnia			if(ws->save_focus == Tmp_win) {
17520bbfda8aSnia				ws->save_focus = NULL;
17530bbfda8aSnia			}
17540bbfda8aSnia		}
17550bbfda8aSnia	}
17560bbfda8aSnia	XDeleteContext(dpy, Tmp_win->w, TwmContext);
17570bbfda8aSnia	XDeleteContext(dpy, Tmp_win->w, ScreenContext);
17580bbfda8aSnia	XDeleteContext(dpy, Tmp_win->frame, TwmContext);
17590bbfda8aSnia	XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
17600bbfda8aSnia	if(Tmp_win->icon && Tmp_win->icon->w) {
17610bbfda8aSnia		XDeleteContext(dpy, Tmp_win->icon->w, TwmContext);
17620bbfda8aSnia		XDeleteContext(dpy, Tmp_win->icon->w, ScreenContext);
17630bbfda8aSnia	}
17640bbfda8aSnia	if(Tmp_win->title_height) {
17650bbfda8aSnia		int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
17660bbfda8aSnia
17670bbfda8aSnia		XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
17680bbfda8aSnia		XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
17690bbfda8aSnia		if(Tmp_win->hilite_wl) {
17700bbfda8aSnia			XDeleteContext(dpy, Tmp_win->hilite_wl, TwmContext);
17710bbfda8aSnia			XDeleteContext(dpy, Tmp_win->hilite_wl, ScreenContext);
17720bbfda8aSnia		}
17730bbfda8aSnia		if(Tmp_win->hilite_wr) {
17740bbfda8aSnia			XDeleteContext(dpy, Tmp_win->hilite_wr, TwmContext);
17750bbfda8aSnia			XDeleteContext(dpy, Tmp_win->hilite_wr, ScreenContext);
17760bbfda8aSnia		}
17770bbfda8aSnia		if(Tmp_win->lolite_wr) {
17780bbfda8aSnia			XDeleteContext(dpy, Tmp_win->lolite_wr, TwmContext);
17790bbfda8aSnia			XDeleteContext(dpy, Tmp_win->lolite_wr, ScreenContext);
17800bbfda8aSnia		}
17810bbfda8aSnia		if(Tmp_win->lolite_wl) {
17820bbfda8aSnia			XDeleteContext(dpy, Tmp_win->lolite_wl, TwmContext);
17830bbfda8aSnia			XDeleteContext(dpy, Tmp_win->lolite_wl, ScreenContext);
17840bbfda8aSnia		}
17850bbfda8aSnia		if(Tmp_win->titlebuttons) {
17860bbfda8aSnia			int i;
17870bbfda8aSnia
17880bbfda8aSnia			for(i = 0; i < nb; i++) {
17890bbfda8aSnia				XDeleteContext(dpy, Tmp_win->titlebuttons[i].window,
17900bbfda8aSnia				               TwmContext);
17910bbfda8aSnia				XDeleteContext(dpy, Tmp_win->titlebuttons[i].window,
17920bbfda8aSnia				               ScreenContext);
17930bbfda8aSnia			}
17940bbfda8aSnia		}
17950bbfda8aSnia		/*
17960bbfda8aSnia		 * The hilite_wl etc windows don't need to be XDestroyWindow()ed
17970bbfda8aSnia		 * since that will happen when the parent is destroyed (??)
17980bbfda8aSnia		 */
17990bbfda8aSnia	}
18000bbfda8aSnia
18010bbfda8aSnia	if(Scr->cmapInfo.cmaps == &Tmp_win->cmaps) {
18020bbfda8aSnia		InstallColormaps(DestroyNotify, &Scr->RootColormaps);
18030bbfda8aSnia	}
18040bbfda8aSnia
18050bbfda8aSnia	/*
18060bbfda8aSnia	 * TwmWindows contain the following pointers
18070bbfda8aSnia	 *
18080bbfda8aSnia	 *     1.  (obsolete)
18090bbfda8aSnia	 *     2.  name
18100bbfda8aSnia	 *     3.  icon_name
18110bbfda8aSnia	 *     4.  wmhints
18120bbfda8aSnia	 *     5.  class.res_name
18130bbfda8aSnia	 *     6.  class.res_class
18140bbfda8aSnia	 *     7.  list
18150bbfda8aSnia	 *     8.  iconmgrp
18160bbfda8aSnia	 *     9.  cwins
18170bbfda8aSnia	 *     10. titlebuttons
18180bbfda8aSnia	 *     11. window ring
18190bbfda8aSnia	 *     12. squeeze_info (delete if squeeze_info_copied)
18200bbfda8aSnia	 *     13. HiliteImage
18210bbfda8aSnia	 *     14. iconslist
18220bbfda8aSnia	 */
18230bbfda8aSnia	WMapRemoveWindow(Tmp_win);
18240bbfda8aSnia	if(Tmp_win->gray) {
18250bbfda8aSnia		XFreePixmap(dpy, Tmp_win->gray);
18260bbfda8aSnia	}
18270bbfda8aSnia
18280bbfda8aSnia	/*
18290bbfda8aSnia	 * According to the manual page, the following destroys all child windows
18300bbfda8aSnia	 * of the frame too, which is most of the windows we're concerned with, so
18310bbfda8aSnia	 * anything related to them must be done before here.
18320bbfda8aSnia	 * Icons are not child windows.
18330bbfda8aSnia	 */
18340bbfda8aSnia	XDestroyWindow(dpy, Tmp_win->frame);
18350bbfda8aSnia	DeleteIconsList(Tmp_win);                                   /* 14 */
18360bbfda8aSnia	if(Tmp_win->icon) {
18370bbfda8aSnia		Icon *icon = Tmp_win->icon;
18380bbfda8aSnia		if(icon->w && !icon->w_not_ours) {
18390bbfda8aSnia			IconDown(Tmp_win);
18400bbfda8aSnia		}
18410bbfda8aSnia		DeleteIcon(icon);
18420bbfda8aSnia		Tmp_win->icon = NULL;
18430bbfda8aSnia	}
18440bbfda8aSnia	Tmp_win->occupation = 0;
18450bbfda8aSnia	RemoveIconManager(Tmp_win);                                 /* 7 */
18460bbfda8aSnia	if(Scr->FirstWindow == Tmp_win) {
18470bbfda8aSnia		Scr->FirstWindow = Tmp_win->next;
18480bbfda8aSnia	}
18490bbfda8aSnia	if(Tmp_win->prev != NULL) {
18500bbfda8aSnia		Tmp_win->prev->next = Tmp_win->next;
18510bbfda8aSnia	}
18520bbfda8aSnia	if(Tmp_win->next != NULL) {
18530bbfda8aSnia		Tmp_win->next->prev = Tmp_win->prev;
18540bbfda8aSnia	}
18550bbfda8aSnia	if(Tmp_win->auto_raise) {
18560bbfda8aSnia		Scr->NumAutoRaises--;
18570bbfda8aSnia	}
18580bbfda8aSnia	if(Tmp_win->auto_lower) {
18590bbfda8aSnia		Scr->NumAutoLowers--;
18600bbfda8aSnia	}
18610bbfda8aSnia
18620bbfda8aSnia	FreeWMPropertyString(Tmp_win->names.ctwm_wm_name); // 2
18630bbfda8aSnia	FreeWMPropertyString(Tmp_win->names.wm_name);      // 2
18640bbfda8aSnia	FreeWMPropertyString(Tmp_win->names.ctwm_wm_icon_name); // 3
18650bbfda8aSnia	FreeWMPropertyString(Tmp_win->names.wm_icon_name); // 3
18660bbfda8aSnia#ifdef EWMH
18670bbfda8aSnia	FreeWMPropertyString(Tmp_win->names.net_wm_name);      // 2
18680bbfda8aSnia	FreeWMPropertyString(Tmp_win->names.net_wm_icon_name); // 3
18690bbfda8aSnia#endif
18700bbfda8aSnia
18710bbfda8aSnia	XFree(Tmp_win->wmhints);                                    /* 4 */
18720bbfda8aSnia	if(Tmp_win->class.res_name && Tmp_win->class.res_name != NoName) { /* 5 */
18730bbfda8aSnia		XFree(Tmp_win->class.res_name);
18740bbfda8aSnia	}
18750bbfda8aSnia	if(Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) { /* 6 */
18760bbfda8aSnia		XFree(Tmp_win->class.res_class);
18770bbfda8aSnia	}
18780bbfda8aSnia	free_cwins(Tmp_win);                                        /* 9 */
18790bbfda8aSnia	if(Tmp_win->titlebuttons) {                                 /* 10 */
18800bbfda8aSnia		free(Tmp_win->titlebuttons);
18810bbfda8aSnia		Tmp_win->titlebuttons = NULL;
18820bbfda8aSnia	}
18830bbfda8aSnia
18840bbfda8aSnia	remove_window_from_ring(Tmp_win);                           /* 11 */
18850bbfda8aSnia	if(Tmp_win->squeeze_info_copied) {                          /* 12 */
18860bbfda8aSnia		free(Tmp_win->squeeze_info);
18870bbfda8aSnia		Tmp_win->squeeze_info = NULL;
18880bbfda8aSnia	}
18890bbfda8aSnia	DeleteHighlightWindows(Tmp_win);                            /* 13 */
18900bbfda8aSnia
18910bbfda8aSnia	free(Tmp_win);
18920bbfda8aSnia	Tmp_win = NULL;
18930bbfda8aSnia
18940bbfda8aSnia	if(Scr->ClickToFocus || Scr->SloppyFocus) {
18950bbfda8aSnia		set_last_window(Scr->currentvs->wsw->currentwspc);
18960bbfda8aSnia	}
18970bbfda8aSnia}
18980bbfda8aSnia
18990bbfda8aSnia
19000bbfda8aSniavoid
19010bbfda8aSniaHandleCreateNotify(void)
19020bbfda8aSnia{
19030bbfda8aSnia#ifdef DEBUG_EVENTS
19040bbfda8aSnia	fprintf(stderr, "CreateNotify w = 0x%x\n",
19050bbfda8aSnia	        (unsigned)Event.xcreatewindow.window);
19060bbfda8aSnia	fflush(stderr);
19070bbfda8aSnia	XBell(dpy, 0);
19080bbfda8aSnia	XSync(dpy, 0);
19090bbfda8aSnia#endif
19100bbfda8aSnia}
19110bbfda8aSnia
19120bbfda8aSnia
19130bbfda8aSnia/***********************************************************************
19140bbfda8aSnia *
19150bbfda8aSnia *  Procedure:
19160bbfda8aSnia *      HandleMapRequest - MapRequest event handler
19170bbfda8aSnia *
19180bbfda8aSnia ***********************************************************************
19190bbfda8aSnia */
19200bbfda8aSnia
19210bbfda8aSniavoid HandleMapRequest(void)
19220bbfda8aSnia{
19230bbfda8aSnia	int zoom_save;
19240bbfda8aSnia
19250bbfda8aSnia	Event.xany.window = Event.xmaprequest.window;
19260bbfda8aSnia	Tmp_win = GetTwmWindow(Event.xany.window);
19270bbfda8aSnia
19280bbfda8aSnia	/* If the window has never been mapped before ... */
19290bbfda8aSnia	if(Tmp_win == NULL) {
19300bbfda8aSnia		/* Add decorations. */
19310bbfda8aSnia		VirtualScreen *vs = Scr->currentvs;
19320bbfda8aSnia
19330bbfda8aSnia		Tmp_win = AddWindow(Event.xany.window,
19340bbfda8aSnia		                    AWT_NORMAL,
19350bbfda8aSnia		                    NULL,
19360bbfda8aSnia		                    vs);
19370bbfda8aSnia		if(Tmp_win == NULL) {
19380bbfda8aSnia			return;
19390bbfda8aSnia		}
19400bbfda8aSnia#ifdef EWMH
19410bbfda8aSnia		/* add the new window to the EWMH client list */
19420bbfda8aSnia		EwmhAddClientWindow(Tmp_win);
19430bbfda8aSnia		EwmhSet_NET_CLIENT_LIST_STACKING();
19440bbfda8aSnia
19450bbfda8aSnia		/* Tell it whatever we think of it */
19460bbfda8aSnia		EwmhSet_NET_WM_STATE(Tmp_win, EWMH_STATE_ALL);
19470bbfda8aSnia#endif /* EWMH */
19480bbfda8aSnia	}
19490bbfda8aSnia	else {
19500bbfda8aSnia		/*
19510bbfda8aSnia		 * If the window has been unmapped by the client, it won't be listed
19520bbfda8aSnia		 * in the icon manager.  Add it again, if requested.
19530bbfda8aSnia		 */
19540bbfda8aSnia		if(Tmp_win->iconmanagerlist == NULL) {
19550bbfda8aSnia			AddIconManager(Tmp_win);
19560bbfda8aSnia		}
19570bbfda8aSnia	}
19580bbfda8aSnia
19590bbfda8aSnia	if(Tmp_win->isiconmgr) {
19600bbfda8aSnia		return;
19610bbfda8aSnia	}
19620bbfda8aSnia	if(Tmp_win->squeezed) {
19630bbfda8aSnia		return;
19640bbfda8aSnia	}
19650bbfda8aSnia
19660bbfda8aSnia	if(Scr->WindowMask) {
19670bbfda8aSnia		XRaiseWindow(dpy, Scr->WindowMask);
19680bbfda8aSnia	}
19690bbfda8aSnia
19700bbfda8aSnia	/* If it's not merely iconified, and we have hints, use them. */
19710bbfda8aSnia	if(! Tmp_win->isicon) {
19720bbfda8aSnia		int state;
19730bbfda8aSnia		Window icon;
19740bbfda8aSnia
19750bbfda8aSnia		state = NormalState;
19760bbfda8aSnia		/* use WM_STATE if enabled */
19770bbfda8aSnia		if(!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
19780bbfda8aSnia		                (state == NormalState || state == IconicState || state == InactiveState))) {
19790bbfda8aSnia			if(Tmp_win->wmhints->flags & StateHint) {
19800bbfda8aSnia				state = Tmp_win->wmhints->initial_state;
19810bbfda8aSnia			}
19820bbfda8aSnia		}
19830bbfda8aSnia		switch(state) {
19840bbfda8aSnia			case DontCareState:
19850bbfda8aSnia			case NormalState:
19860bbfda8aSnia			case ZoomState:
19870bbfda8aSnia				if(Tmp_win->StartSqueezed) {
19880bbfda8aSnia					Squeeze(Tmp_win);
19890bbfda8aSnia				}
19900bbfda8aSnia				else {
19910bbfda8aSnia					XMapWindow(dpy, Tmp_win->w);
19920bbfda8aSnia				}
19930bbfda8aSnia				XMapWindow(dpy, Tmp_win->frame);
19940bbfda8aSnia				SetMapStateProp(Tmp_win, NormalState);
19950bbfda8aSnia				SetRaiseWindow(Tmp_win);
19960bbfda8aSnia				Tmp_win->mapped = true;
19970bbfda8aSnia				if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
19980bbfda8aSnia					SetFocus(Tmp_win, CurrentTime);
19990bbfda8aSnia				}
20000bbfda8aSnia				/* kai */
20010bbfda8aSnia				if(Scr->AutoFocusToTransients &&
20020bbfda8aSnia				                Tmp_win->istransient &&
20030bbfda8aSnia				                Tmp_win->wmhints->input) {
20040bbfda8aSnia					SetFocus(Tmp_win, CurrentTime);
20050bbfda8aSnia				}
20060bbfda8aSnia				break;
20070bbfda8aSnia
20080bbfda8aSnia			case InactiveState:
20090bbfda8aSnia				if(!OCCUPY(Tmp_win, Scr->currentvs->wsw->currentwspc) &&
20100bbfda8aSnia				                HandlingEvents && /* to avoid warping during startup */
20110bbfda8aSnia				                LookInList(Scr->WarpOnDeIconify, Tmp_win->name, &Tmp_win->class)) {
20120bbfda8aSnia					if(!Scr->NoRaiseDeicon) {
20130bbfda8aSnia						OtpRaise(Tmp_win, WinWin);
20140bbfda8aSnia					}
20150bbfda8aSnia					AddToWorkSpace(Scr->currentvs->wsw->currentwspc->name, Tmp_win);
20160bbfda8aSnia				}
20170bbfda8aSnia				Tmp_win->mapped = true;
20180bbfda8aSnia				if(Tmp_win->UnmapByMovingFarAway) {
20190bbfda8aSnia					XMoveWindow(dpy, Tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1);
20200bbfda8aSnia					XMapWindow(dpy, Tmp_win->w);
20210bbfda8aSnia					XMapWindow(dpy, Tmp_win->frame);
20220bbfda8aSnia				}
20230bbfda8aSnia				if(Tmp_win->StartSqueezed) {
20240bbfda8aSnia					Squeeze(Tmp_win);
20250bbfda8aSnia				}
20260bbfda8aSnia				break;
20270bbfda8aSnia
20280bbfda8aSnia			case IconicState:
20290bbfda8aSnia				zoom_save = Scr->DoZoom;
20300bbfda8aSnia				Scr->DoZoom = false;
20310bbfda8aSnia				Iconify(Tmp_win, -100, -100);
20320bbfda8aSnia				Scr->DoZoom = zoom_save;
20330bbfda8aSnia				break;
20340bbfda8aSnia		}
20350bbfda8aSnia	}
20360bbfda8aSnia	/* If no hints, or currently an icon, just "deiconify" */
20370bbfda8aSnia	else {
20380bbfda8aSnia		if(!OCCUPY(Tmp_win, Scr->currentvs->wsw->currentwspc) &&
20390bbfda8aSnia		                LookInList(Scr->WarpOnDeIconify, Tmp_win->name, &Tmp_win->class)) {
20400bbfda8aSnia			AddToWorkSpace(Scr->currentvs->wsw->currentwspc->name, Tmp_win);
20410bbfda8aSnia		}
20420bbfda8aSnia		if(1/*OCCUPY (Tmp_win, Scr->workSpaceMgr.activeWSPC)*/) {
20430bbfda8aSnia			if(Tmp_win->StartSqueezed) {
20440bbfda8aSnia				Squeeze(Tmp_win);
20450bbfda8aSnia			}
20460bbfda8aSnia			DeIconify(Tmp_win);
20470bbfda8aSnia			SetRaiseWindow(Tmp_win);
20480bbfda8aSnia		}
20490bbfda8aSnia		else {
20500bbfda8aSnia			Tmp_win->mapped = true;
20510bbfda8aSnia		}
20520bbfda8aSnia	}
20530bbfda8aSnia	if(Tmp_win->mapped) {
20540bbfda8aSnia		WMapMapWindow(Tmp_win);
20550bbfda8aSnia	}
20560bbfda8aSnia	MaybeAnimate = true;
20570bbfda8aSnia}
20580bbfda8aSnia
20590bbfda8aSnia
20600bbfda8aSnia/***********************************************************************
20610bbfda8aSnia *
20620bbfda8aSnia *  Procedure:
20630bbfda8aSnia *      HandleMapNotify - MapNotify event handler
20640bbfda8aSnia *
20650bbfda8aSnia ***********************************************************************
20660bbfda8aSnia */
20670bbfda8aSnia
20680bbfda8aSniavoid HandleMapNotify(void)
20690bbfda8aSnia{
20700bbfda8aSnia	if(Tmp_win == NULL) {
20710bbfda8aSnia		return;
20720bbfda8aSnia	}
20730bbfda8aSnia
20740bbfda8aSnia	/*
20750bbfda8aSnia	 * Need to do the grab to avoid race condition of having server send
20760bbfda8aSnia	 * MapNotify to client before the frame gets mapped; this is bad because
20770bbfda8aSnia	 * the client would think that the window has a chance of being viewable
20780bbfda8aSnia	 * when it really isn't.
20790bbfda8aSnia	 */
20800bbfda8aSnia	XGrabServer(dpy);
2081b18c2d1eSnia
2082b18c2d1eSnia	// Mapping the window, hide its icon
20830bbfda8aSnia	if(Tmp_win->icon && Tmp_win->icon->w) {
20840bbfda8aSnia		XUnmapWindow(dpy, Tmp_win->icon->w);
20850bbfda8aSnia	}
2086b18c2d1eSnia
2087b18c2d1eSnia	// Map up everything inside the frame (not the frame itself, so if it
2088b18c2d1eSnia	// wasn't already up, nothing will show yet)
20890bbfda8aSnia	XMapSubwindows(dpy, Tmp_win->frame);
2090b18c2d1eSnia
2091b18c2d1eSnia	// Choose which of the hi/lolite's should be left up, based on the
2092b18c2d1eSnia	// focus
2093b18c2d1eSnia	if(Scr->Focus != Tmp_win) {
2094b18c2d1eSnia		if(Tmp_win->hilite_wl) {
2095b18c2d1eSnia			XUnmapWindow(dpy, Tmp_win->hilite_wl);
2096b18c2d1eSnia		}
2097b18c2d1eSnia		if(Tmp_win->hilite_wr) {
2098b18c2d1eSnia			XUnmapWindow(dpy, Tmp_win->hilite_wr);
2099b18c2d1eSnia		}
21000bbfda8aSnia	}
2101b18c2d1eSnia	else {
2102b18c2d1eSnia		if(Tmp_win->lolite_wl) {
2103b18c2d1eSnia			XUnmapWindow(dpy, Tmp_win->lolite_wl);
2104b18c2d1eSnia		}
2105b18c2d1eSnia		if(Tmp_win->lolite_wr) {
2106b18c2d1eSnia			XUnmapWindow(dpy, Tmp_win->lolite_wr);
2107b18c2d1eSnia		}
21080bbfda8aSnia	}
21090bbfda8aSnia
2110b18c2d1eSnia	// Now map the frame itself (which brings all the rest into view)
21110bbfda8aSnia	XMapWindow(dpy, Tmp_win->frame);
2112b18c2d1eSnia
21130bbfda8aSnia	XUngrabServer(dpy);
21140bbfda8aSnia	XFlush(dpy);
2115b18c2d1eSnia
2116b18c2d1eSnia	// Set the flags
21170bbfda8aSnia	Tmp_win->mapped = true;
21180bbfda8aSnia	Tmp_win->isicon = false;
21190bbfda8aSnia	Tmp_win->icon_on = false;
21200bbfda8aSnia}
21210bbfda8aSnia
21220bbfda8aSnia
21230bbfda8aSnia/***********************************************************************
21240bbfda8aSnia *
21250bbfda8aSnia *  Procedure:
21260bbfda8aSnia *      HandleUnmapNotify - UnmapNotify event handler
21270bbfda8aSnia *
21280bbfda8aSnia ***********************************************************************
21290bbfda8aSnia */
21300bbfda8aSnia
21310bbfda8aSniavoid HandleUnmapNotify(void)
21320bbfda8aSnia{
21330bbfda8aSnia	int dstx, dsty;
21340bbfda8aSnia	Window dumwin;
21350bbfda8aSnia
21360bbfda8aSnia	/*
21370bbfda8aSnia	 * The July 27, 1988 ICCCM spec states that a client wishing to switch
21380bbfda8aSnia	 * to WithdrawnState should send a synthetic UnmapNotify with the
21390bbfda8aSnia	 * event field set to (pseudo-)root, in case the window is already
21400bbfda8aSnia	 * unmapped (which is the case for twm for IconicState).  Unfortunately,
21410bbfda8aSnia	 * we looked for the TwmContext using that field, so try the window
21420bbfda8aSnia	 * field also.
21430bbfda8aSnia	 */
21440bbfda8aSnia	if(Tmp_win == NULL) {
21450bbfda8aSnia		Event.xany.window = Event.xunmap.window;
21460bbfda8aSnia		Tmp_win = GetTwmWindow(Event.xany.window);
21470bbfda8aSnia	}
21480bbfda8aSnia
21490bbfda8aSnia	if(Tmp_win == NULL || Event.xunmap.window == Tmp_win->frame ||
21500bbfda8aSnia	                (Tmp_win->icon && Event.xunmap.window == Tmp_win->icon->w) ||
21510bbfda8aSnia	                (!Tmp_win->mapped && !Tmp_win->isicon)) {
21520bbfda8aSnia		return;
21530bbfda8aSnia	}
21540bbfda8aSnia	/*
21550bbfda8aSnia	    if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->isicon))
21560bbfda8aSnia	        return;
21570bbfda8aSnia	*/
21580bbfda8aSnia	/*
21590bbfda8aSnia	 * The program may have unmapped the client window, from either
21600bbfda8aSnia	 * NormalState or IconicState.  Handle the transition to WithdrawnState.
21610bbfda8aSnia	 *
21620bbfda8aSnia	 * We need to reparent the window back to the root (so that twm exiting
21630bbfda8aSnia	 * won't cause it to get mapped) and then throw away all state (pretend
21640bbfda8aSnia	 * that we've received a DestroyNotify).
21650bbfda8aSnia	 */
21660bbfda8aSnia	/* Is it the correct behaviour ???
21670bbfda8aSnia	    XDeleteProperty (dpy, Tmp_win->w, XA_WM_OCCUPATION);
21680bbfda8aSnia	*/
21690bbfda8aSnia#ifdef EWMH
21700bbfda8aSnia	EwmhUnmapNotify(Tmp_win);
21710bbfda8aSnia#endif /* EWMH */
21720bbfda8aSnia	XGrabServer(dpy);
21730bbfda8aSnia	if(XTranslateCoordinates(dpy, Event.xunmap.window, Tmp_win->attr.root,
21740bbfda8aSnia	                         0, 0, &dstx, &dsty, &dumwin)) {
21750bbfda8aSnia		XEvent ev;
21760bbfda8aSnia		Bool reparented = XCheckTypedWindowEvent(dpy, Event.xunmap.window,
21770bbfda8aSnia		                  ReparentNotify, &ev);
21780bbfda8aSnia		SetMapStateProp(Tmp_win, WithdrawnState);
21790bbfda8aSnia		if(reparented) {
2180b18c2d1eSnia			// It got reparented, get rid of our alterations.
2181b18c2d1eSnia			if(Tmp_win->old_bw) {
2182b18c2d1eSnia				XSetWindowBorderWidth(dpy,
2183b18c2d1eSnia				                      Event.xunmap.window,
2184b18c2d1eSnia				                      Tmp_win->old_bw);
2185b18c2d1eSnia			}
21860bbfda8aSnia			if(Tmp_win->wmhints->flags & IconWindowHint) {
21870bbfda8aSnia				XUnmapWindow(dpy, Tmp_win->wmhints->icon_window);
21880bbfda8aSnia			}
21890bbfda8aSnia		}
21900bbfda8aSnia		else {
2191b18c2d1eSnia			// Didn't get reparented, so we should do it ourselves
21920bbfda8aSnia			XReparentWindow(dpy, Event.xunmap.window, Tmp_win->attr.root,
21930bbfda8aSnia			                dstx, dsty);
2194b18c2d1eSnia			// XXX Need to think more about just what the roots and
2195b18c2d1eSnia			// coords are here...
2196b18c2d1eSnia			RestoreWinConfig(Tmp_win);
21970bbfda8aSnia		}
21980bbfda8aSnia		XRemoveFromSaveSet(dpy, Event.xunmap.window);
21990bbfda8aSnia		XSelectInput(dpy, Event.xunmap.window, NoEventMask);
22000bbfda8aSnia		HandleDestroyNotify();          /* do not need to mash event before */
22010bbfda8aSnia	} /* else window no longer exists and we'll get a destroy notify */
22020bbfda8aSnia	XUngrabServer(dpy);
22030bbfda8aSnia	XFlush(dpy);
22040bbfda8aSnia}
22050bbfda8aSnia
22060bbfda8aSnia
22070bbfda8aSnia/***********************************************************************
22080bbfda8aSnia *
22090bbfda8aSnia *  Procedure:
22100bbfda8aSnia *      HandleMotionNotify - MotionNotify event handler
22110bbfda8aSnia *
22120bbfda8aSnia ***********************************************************************
22130bbfda8aSnia */
22140bbfda8aSnia
22150bbfda8aSniavoid HandleMotionNotify(void)
22160bbfda8aSnia{
22170bbfda8aSnia	if(ResizeWindow != (Window) 0) {
22180bbfda8aSnia		XQueryPointer(dpy, Event.xany.window,
22190bbfda8aSnia		              &(Event.xmotion.root), &JunkChild,
22200bbfda8aSnia		              &(Event.xmotion.x_root), &(Event.xmotion.y_root),
22210bbfda8aSnia		              &(Event.xmotion.x), &(Event.xmotion.y),
22220bbfda8aSnia		              &JunkMask);
22230bbfda8aSnia
22240bbfda8aSnia		FixRootEvent(&Event);
22250bbfda8aSnia		/* Set WindowMoved appropriately so that f.deltastop will
22260bbfda8aSnia		   work with resize as well as move. */
22270bbfda8aSnia		if(abs(Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
22280bbfda8aSnia		                || abs(Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta) {
22290bbfda8aSnia			WindowMoved = true;
22300bbfda8aSnia		}
22310bbfda8aSnia
22320bbfda8aSnia		Tmp_win = GetTwmWindow(ResizeWindow);
2233b18c2d1eSnia#ifdef WINBOX
22340bbfda8aSnia		if(Tmp_win && Tmp_win->winbox) {
22350bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, Tmp_win->winbox->window,
22360bbfda8aSnia			                      Event.xmotion.x_root, Event.xmotion.y_root,
22370bbfda8aSnia			                      &(Event.xmotion.x_root), &(Event.xmotion.y_root), &JunkChild);
22380bbfda8aSnia		}
2239b18c2d1eSnia#endif
22400bbfda8aSnia		DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
22410bbfda8aSnia	}
22420bbfda8aSnia	else if(Scr->BorderCursors && Tmp_win && Event.xany.window == Tmp_win->frame) {
22430bbfda8aSnia		SetBorderCursor(Tmp_win, Event.xmotion.x, Event.xmotion.y);
22440bbfda8aSnia	}
22450bbfda8aSnia}
22460bbfda8aSnia
22470bbfda8aSnia
22480bbfda8aSnia/***********************************************************************
22490bbfda8aSnia *
22500bbfda8aSnia *  Procedure:
22510bbfda8aSnia *      HandleButtonRelease - ButtonRelease event handler
22520bbfda8aSnia *
22530bbfda8aSnia ***********************************************************************
22540bbfda8aSnia */
22550bbfda8aSniavoid HandleButtonRelease(void)
22560bbfda8aSnia{
22570bbfda8aSnia	int xl, yt, w, h;
22580bbfda8aSnia	unsigned mask;
22590bbfda8aSnia
22600bbfda8aSnia	if(Scr->InfoWindow.mapped) {  /* delete info box on 2nd button release */
22610bbfda8aSnia		if(Context == C_IDENTIFY) {
22620bbfda8aSnia			XUnmapWindow(dpy, Scr->InfoWindow.win);
22630bbfda8aSnia			Scr->InfoWindow.mapped = false;
22640bbfda8aSnia			Context = C_NO_CONTEXT;
22650bbfda8aSnia		}
22660bbfda8aSnia	}
22670bbfda8aSnia
22680bbfda8aSnia	if(DragWindow != None) {
22690bbfda8aSnia		MoveOutline(Scr->XineramaRoot, 0, 0, 0, 0, 0, 0);
22700bbfda8aSnia
22710bbfda8aSnia		Tmp_win = GetTwmWindow(DragWindow);
2272b18c2d1eSnia#ifdef WINBOX
22730bbfda8aSnia		if(Tmp_win->winbox) {
22740bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, Tmp_win->winbox->window,
22750bbfda8aSnia			                      Event.xbutton.x_root, Event.xbutton.y_root,
22760bbfda8aSnia			                      &(Event.xbutton.x_root), &(Event.xbutton.y_root), &JunkChild);
22770bbfda8aSnia		}
2278b18c2d1eSnia#endif
22790bbfda8aSnia		if(DragWindow == Tmp_win->frame) {
22800bbfda8aSnia			xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
22810bbfda8aSnia			yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
22820bbfda8aSnia			w = DragWidth + 2 * Tmp_win->frame_bw;
22830bbfda8aSnia			h = DragHeight + 2 * Tmp_win->frame_bw;
22840bbfda8aSnia		}
22850bbfda8aSnia		else {
22860bbfda8aSnia			xl = Event.xbutton.x_root - DragX - DragBW;
22870bbfda8aSnia			yt = Event.xbutton.y_root - DragY - DragBW;
22880bbfda8aSnia			w = DragWidth + 2 * DragBW;
22890bbfda8aSnia			h = DragHeight + 2 * DragBW;
22900bbfda8aSnia		}
22910bbfda8aSnia
22920bbfda8aSnia		if(ConstMove) {
22930bbfda8aSnia			if(ConstMoveDir == MOVE_HORIZ) {
22940bbfda8aSnia				yt = ConstMoveY;
22950bbfda8aSnia			}
22960bbfda8aSnia
22970bbfda8aSnia			if(ConstMoveDir == MOVE_VERT) {
22980bbfda8aSnia				xl = ConstMoveX;
22990bbfda8aSnia			}
23000bbfda8aSnia
23010bbfda8aSnia			if(ConstMoveDir == MOVE_NONE) {
23020bbfda8aSnia				yt = ConstMoveY;
23030bbfda8aSnia				xl = ConstMoveX;
23040bbfda8aSnia			}
23050bbfda8aSnia		}
23060bbfda8aSnia
23070bbfda8aSnia		if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
23080bbfda8aSnia			TryToGrid(Tmp_win, &xl, &yt);
23090bbfda8aSnia		}
23100bbfda8aSnia		if(MoveFunction == F_MOVEPUSH &&
23110bbfda8aSnia		                Scr->OpaqueMove &&
23120bbfda8aSnia		                DragWindow == Tmp_win->frame) {
23130bbfda8aSnia			TryToPush(Tmp_win, xl, yt);
23140bbfda8aSnia		}
23150bbfda8aSnia		if(MoveFunction == F_MOVEPACK ||
23160bbfda8aSnia		                (MoveFunction == F_MOVEPUSH &&
23170bbfda8aSnia		                 DragWindow == Tmp_win->frame)) {
23180bbfda8aSnia			TryToPack(Tmp_win, &xl, &yt);
23190bbfda8aSnia		}
23200bbfda8aSnia		if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
23210bbfda8aSnia			ConstrainByBorders(Tmp_win, &xl, w, &yt, h);
23220bbfda8aSnia		}
23230bbfda8aSnia
23240bbfda8aSnia		CurrentDragX = xl;
23250bbfda8aSnia		CurrentDragY = yt;
2326b18c2d1eSnia#ifdef VSCREEN
23270bbfda8aSnia		/*
23280bbfda8aSnia		 * sometimes getScreenOf() replies with the wrong window when moving
23290bbfda8aSnia		 * y to a negative number.  Need to figure out why... [XXX]
23300bbfda8aSnia		 * It seems to be because the first XTranslateCoordinates() doesn't
23310bbfda8aSnia		 * translate the coordinates to be relative to XineramaRoot.
23320bbfda8aSnia		 * That in turn is probably because a window is visible in a ws or
23330bbfda8aSnia		 * vs where it shouldn't (inconsistent with its occupation).
23340bbfda8aSnia		 * A problem of this kind was fixed with f.adoptwindow but remains
23350bbfda8aSnia		 * with f.hypermove.
23360bbfda8aSnia		 * As a result, the window remains in the original vs/ws and
23370bbfda8aSnia		 * is irretrievably moved out of view. [Rhialto]
23380bbfda8aSnia		 */
23390bbfda8aSnia		if(xl < 0 || yt < 0 || xl > Scr->rootw || yt > Scr->rooth) {
23400bbfda8aSnia			int odestx, odesty;
23410bbfda8aSnia			int destx, desty;
23420bbfda8aSnia			Window cr;
23430bbfda8aSnia			VirtualScreen *newvs;
23440bbfda8aSnia
23450bbfda8aSnia			XTranslateCoordinates(dpy, Tmp_win->vs->window,
23460bbfda8aSnia			                      Scr->XineramaRoot, xl, yt, &odestx, &odesty, &cr);
23470bbfda8aSnia
23480bbfda8aSnia			newvs = findIfVScreenOf(odestx, odesty);
23490bbfda8aSnia
23500bbfda8aSnia			if(newvs && newvs->wsw && newvs->wsw->currentwspc) {
23510bbfda8aSnia				XTranslateCoordinates(dpy, Scr->XineramaRoot,
23520bbfda8aSnia				                      newvs->window, odestx, odesty,
23530bbfda8aSnia				                      &destx, &desty, &cr);
23540bbfda8aSnia				AddToWorkSpace(newvs->wsw->currentwspc->name, Tmp_win);
23550bbfda8aSnia				RemoveFromWorkSpace(Tmp_win->vs->wsw->currentwspc->name, Tmp_win);
23560bbfda8aSnia				xl = destx;
23570bbfda8aSnia				yt = desty;
23580bbfda8aSnia			}
23590bbfda8aSnia		}
2360b18c2d1eSnia#endif
23610bbfda8aSnia		if(DragWindow == Tmp_win->frame) {
23620bbfda8aSnia			SetupWindow(Tmp_win, xl, yt,
23630bbfda8aSnia			            Tmp_win->frame_width, Tmp_win->frame_height, -1);
23640bbfda8aSnia		}
23650bbfda8aSnia		else {
23660bbfda8aSnia			XMoveWindow(dpy, DragWindow, xl, yt);
23670bbfda8aSnia			if(DragWindow == Tmp_win->icon->w) {
23680bbfda8aSnia				Tmp_win->icon->w_x = xl;
23690bbfda8aSnia				Tmp_win->icon->w_y = yt;
23700bbfda8aSnia			}
23710bbfda8aSnia		}
23720bbfda8aSnia
23730bbfda8aSnia		if(!Scr->NoRaiseMove) {  /* && !Scr->OpaqueMove)    opaque already did */
23740bbfda8aSnia			if(DragWindow == Tmp_win->frame) {
23750bbfda8aSnia				OtpRaise(Tmp_win, WinWin);
23760bbfda8aSnia			}
23770bbfda8aSnia			else if(Tmp_win->icon && DragWindow == Tmp_win->icon->w) {
23780bbfda8aSnia				OtpRaise(Tmp_win, IconWin);
23790bbfda8aSnia			}
23800bbfda8aSnia			else {
23810bbfda8aSnia				fprintf(stderr, "ERROR -- events.c:2815\n");
23820bbfda8aSnia			}
23830bbfda8aSnia		}
23840bbfda8aSnia
23850bbfda8aSnia		if(!Scr->OpaqueMove) {
23860bbfda8aSnia			UninstallRootColormap();
23870bbfda8aSnia		}
23880bbfda8aSnia		else {
23890bbfda8aSnia			XSync(dpy, 0);
23900bbfda8aSnia		}
23910bbfda8aSnia
23920bbfda8aSnia		if(Scr->NumAutoRaises) {
23930bbfda8aSnia			enter_flag = true;
23940bbfda8aSnia			enter_win = NULL;
23950bbfda8aSnia			raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
23960bbfda8aSnia			             ? Tmp_win : NULL);
23970bbfda8aSnia		}
23980bbfda8aSnia
23990bbfda8aSnia		/* CCC equivalent code for auto lower not needed? */
24000bbfda8aSnia
24010bbfda8aSnia#if 0
24020bbfda8aSnia		if(Scr->NumAutoLowers) {
24030bbfda8aSnia			leave_flag = true;
24040bbfda8aSnia			leave_win = NULL;
24050bbfda8aSnia			lower_win = ((DragWindow == Tmp_win->frame)
24060bbfda8aSnia			             ? Tmp_win : NULL);
24070bbfda8aSnia		}
24080bbfda8aSnia#endif
24090bbfda8aSnia
24100bbfda8aSnia		DragWindow = (Window) 0;
24110bbfda8aSnia		ConstMove = false;
24120bbfda8aSnia	}
24130bbfda8aSnia
24140bbfda8aSnia	if(ResizeWindow != (Window) 0) {
24150bbfda8aSnia		EndResize();
24160bbfda8aSnia	}
24170bbfda8aSnia
24180bbfda8aSnia	if(ActiveMenu != NULL && RootFunction == 0) {
24190bbfda8aSnia		if(ActiveItem) {
24200bbfda8aSnia			int func = ActiveItem->func;
24210bbfda8aSnia			Action = ActiveItem->action;
24220bbfda8aSnia			switch(func) {
24230bbfda8aSnia				case F_TITLE:
24240bbfda8aSnia					if(Scr->StayUpMenus)   {
24250bbfda8aSnia						ButtonPressed = -1;
24260bbfda8aSnia						if(Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) {
24270bbfda8aSnia							WarpCursorToDefaultEntry(ActiveMenu);
24280bbfda8aSnia						}
24290bbfda8aSnia						return;
24300bbfda8aSnia					}
24310bbfda8aSnia					break;
24320bbfda8aSnia				case F_MOVE:
24330bbfda8aSnia				case F_FORCEMOVE:
24340bbfda8aSnia				case F_DESTROY:
24350bbfda8aSnia				case F_DELETE:
24360bbfda8aSnia				case F_DELETEORDESTROY:
24370bbfda8aSnia					ButtonPressed = -1;
24380bbfda8aSnia					break;
24390bbfda8aSnia				case F_CIRCLEUP:
24400bbfda8aSnia				case F_CIRCLEDOWN:
24410bbfda8aSnia				case F_REFRESH:
24420bbfda8aSnia				case F_WARPTOSCREEN:
24430bbfda8aSnia					PopDownMenu();
24440bbfda8aSnia					break;
24450bbfda8aSnia				default:
24460bbfda8aSnia					break;
24470bbfda8aSnia			}
24480bbfda8aSnia			if(func != F_PIN && func != F_MENU) {
24490bbfda8aSnia				PopDownMenu();
24500bbfda8aSnia			}
24510bbfda8aSnia			ExecuteFunction(func, Action,
24520bbfda8aSnia			                ButtonWindow ? ButtonWindow->frame : None,
24530bbfda8aSnia			                ButtonWindow, &Event, Context, true);
24540bbfda8aSnia			Context = C_NO_CONTEXT;
24550bbfda8aSnia			ButtonWindow = NULL;
24560bbfda8aSnia
24570bbfda8aSnia			/* if we are not executing a defered command, then take down the
24580bbfda8aSnia			 * menu
24590bbfda8aSnia			 */
24600bbfda8aSnia			if(ActiveMenu) {
24610bbfda8aSnia				PopDownMenu();
24620bbfda8aSnia			}
24630bbfda8aSnia		}
24640bbfda8aSnia		else if(Scr->StayUpMenus && !ActiveMenu->entered) {
24650bbfda8aSnia			ButtonPressed = -1;
24660bbfda8aSnia			if(Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) {
24670bbfda8aSnia				WarpCursorToDefaultEntry(ActiveMenu);
24680bbfda8aSnia			}
24690bbfda8aSnia			return;
24700bbfda8aSnia		}
24710bbfda8aSnia		else {
24720bbfda8aSnia			PopDownMenu();
24730bbfda8aSnia		}
24740bbfda8aSnia	}
24750bbfda8aSnia
24760bbfda8aSnia	mask = (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask);
24770bbfda8aSnia	switch(Event.xbutton.button) {
24780bbfda8aSnia		case Button1:
24790bbfda8aSnia			mask &= ~Button1Mask;
24800bbfda8aSnia			break;
24810bbfda8aSnia		case Button2:
24820bbfda8aSnia			mask &= ~Button2Mask;
24830bbfda8aSnia			break;
24840bbfda8aSnia		case Button3:
24850bbfda8aSnia			mask &= ~Button3Mask;
24860bbfda8aSnia			break;
24870bbfda8aSnia		case Button4:
24880bbfda8aSnia			mask &= ~Button4Mask;
24890bbfda8aSnia			break;
24900bbfda8aSnia		case Button5:
24910bbfda8aSnia			mask &= ~Button5Mask;
24920bbfda8aSnia			break;
24930bbfda8aSnia	}
24940bbfda8aSnia
24950bbfda8aSnia	if(RootFunction != 0 ||
24960bbfda8aSnia	                ResizeWindow != None ||
24970bbfda8aSnia	                DragWindow != None) {
24980bbfda8aSnia		ButtonPressed = -1;
24990bbfda8aSnia	}
25000bbfda8aSnia
25010bbfda8aSnia	if(AlternateKeymap || AlternateContext) {
25020bbfda8aSnia		ButtonPressed = -1;
25030bbfda8aSnia		return;
25040bbfda8aSnia	}
25050bbfda8aSnia
25060bbfda8aSnia	if(RootFunction == 0 &&
25070bbfda8aSnia	                (Event.xbutton.state & mask) == 0 &&
25080bbfda8aSnia	                DragWindow == None &&
25090bbfda8aSnia	                ResizeWindow == None) {
25100bbfda8aSnia		XUngrabPointer(dpy, CurrentTime);
25110bbfda8aSnia		XUngrabServer(dpy);
25120bbfda8aSnia		XFlush(dpy);
25130bbfda8aSnia		EventHandler[EnterNotify] = HandleEnterNotify;
25140bbfda8aSnia		EventHandler[LeaveNotify] = HandleLeaveNotify;
25150bbfda8aSnia		ButtonPressed = -1;
25160bbfda8aSnia		if(DownIconManager) {
25170bbfda8aSnia			DownIconManager->down = false;
25180bbfda8aSnia			if(Scr->Highlight) {
25190bbfda8aSnia				DrawIconManagerBorder(DownIconManager, false);
25200bbfda8aSnia			}
25210bbfda8aSnia			DownIconManager = NULL;
25220bbfda8aSnia		}
25230bbfda8aSnia		Cancel = false;
25240bbfda8aSnia	}
25250bbfda8aSnia}
25260bbfda8aSnia
25270bbfda8aSnia
25280bbfda8aSnia/*
25290bbfda8aSnia * Pop up a submenu as a result of moving the mouse right on its entry.
25300bbfda8aSnia */
25310bbfda8aSniastatic void do_menu(MenuRoot *menu,     /* menu to pop up */
25320bbfda8aSnia                    Window w)          /* invoking window or None */
25330bbfda8aSnia{
25340bbfda8aSnia	int x = Event.xbutton.x_root;
25350bbfda8aSnia	int y = Event.xbutton.y_root;
25360bbfda8aSnia	bool center;
25370bbfda8aSnia
25380bbfda8aSnia	if(!Scr->NoGrabServer) {
25390bbfda8aSnia		XGrabServer(dpy);
25400bbfda8aSnia	}
25410bbfda8aSnia	if(w) {
25420bbfda8aSnia		int h = Scr->TBInfo.width - Scr->TBInfo.border;
25430bbfda8aSnia		Window child;
25440bbfda8aSnia
25450bbfda8aSnia		XTranslateCoordinates(dpy, w, Scr->Root, 0, h, &x, &y, &child);
25460bbfda8aSnia		center = false;
25470bbfda8aSnia	}
25480bbfda8aSnia	else {
25490bbfda8aSnia		center = true;
25500bbfda8aSnia	}
25510bbfda8aSnia	if(PopUpMenu(menu, x, y, center)) {
25520bbfda8aSnia		UpdateMenu();
25530bbfda8aSnia	}
25540bbfda8aSnia	else {
25550bbfda8aSnia		XBell(dpy, 0);
25560bbfda8aSnia	}
25570bbfda8aSnia}
25580bbfda8aSnia
25590bbfda8aSnia
25600bbfda8aSnia/*
25610bbfda8aSnia * Pop up a submenu as a result of hitting the Right arrow key while on
25620bbfda8aSnia * its entry.  We should try folding these two together a bit more.
25630bbfda8aSnia */
25640bbfda8aSniastatic void do_key_menu(MenuRoot *menu,         /* menu to pop up */
25650bbfda8aSnia                        Window w)              /* invoking window or None */
25660bbfda8aSnia{
25670bbfda8aSnia	int x = Event.xkey.x_root;
25680bbfda8aSnia	int y = Event.xkey.y_root;
25690bbfda8aSnia	bool center;
25700bbfda8aSnia
25710bbfda8aSnia	/* I don't think this is necessary.
25720bbfda8aSnia	    if (!Scr->NoGrabServer) XGrabServer(dpy);
25730bbfda8aSnia	*/
25740bbfda8aSnia	if(w) {
25750bbfda8aSnia		int h = Scr->TBInfo.width - Scr->TBInfo.border;
25760bbfda8aSnia		Window child;
25770bbfda8aSnia
25780bbfda8aSnia		XTranslateCoordinates(dpy, w, Scr->Root, 0, h, &x, &y, &child);
25790bbfda8aSnia		center = false;
25800bbfda8aSnia	}
25810bbfda8aSnia	else {
25820bbfda8aSnia		center = true;
25830bbfda8aSnia	}
25840bbfda8aSnia	if(PopUpMenu(menu, x, y, center)) {
25850bbfda8aSnia		/*
25860bbfda8aSnia		 * Note: UpdateMenu() has the internal re-capture of the event
25870bbfda8aSnia		 * loop to handle in-menu stuff, so this won't actually return
25880bbfda8aSnia		 * until we somehow exit out of that [sub]menu.
25890bbfda8aSnia		 */
25900bbfda8aSnia		UpdateMenu();
25910bbfda8aSnia	}
25920bbfda8aSnia	else {
25930bbfda8aSnia		XBell(dpy, 0);
25940bbfda8aSnia	}
25950bbfda8aSnia
25960bbfda8aSnia}
25970bbfda8aSnia
25980bbfda8aSnia
25990bbfda8aSnia/***********************************************************************
26000bbfda8aSnia *
26010bbfda8aSnia *  Procedure:
26020bbfda8aSnia *      HandleButtonPress - ButtonPress event handler
26030bbfda8aSnia *
26040bbfda8aSnia ***********************************************************************
26050bbfda8aSnia */
26060bbfda8aSniavoid HandleButtonPress(void)
26070bbfda8aSnia{
26080bbfda8aSnia	unsigned int modifier;
26090bbfda8aSnia	Cursor cur;
26100bbfda8aSnia	MenuRoot *mr;
26110bbfda8aSnia	FuncButton *tmp = 0;
26120bbfda8aSnia	int func = 0;
26130bbfda8aSnia	Window w;
26140bbfda8aSnia
26150bbfda8aSnia
26160bbfda8aSnia	/* pop down the menu, if any */
26170bbfda8aSnia
26180bbfda8aSnia	if(XFindContext(dpy, Event.xbutton.window, MenuContext,
26190bbfda8aSnia	                (XPointer *) &mr) != XCSUCCESS) {
26200bbfda8aSnia		mr = NULL;
26210bbfda8aSnia	}
26220bbfda8aSnia	if(ActiveMenu && (! ActiveMenu->pinned) &&
26230bbfda8aSnia	                (Event.xbutton.subwindow != ActiveMenu->w)) {
26240bbfda8aSnia		PopDownMenu();
26250bbfda8aSnia		return;
26260bbfda8aSnia	}
26270bbfda8aSnia	if((ActiveMenu != NULL) && (RootFunction != 0) && (mr != ActiveMenu)) {
26280bbfda8aSnia		PopDownMenu();
26290bbfda8aSnia	}
26300bbfda8aSnia
26310bbfda8aSnia	XSync(dpy, 0);
26320bbfda8aSnia	/* XXX - remove? */
26330bbfda8aSnia
26340bbfda8aSnia	/* want menus if we have info box */
26350bbfda8aSnia	if(ButtonPressed != -1 && !Scr->InfoWindow.mapped) {
26360bbfda8aSnia		/* we got another butt press in addition to one still held
26370bbfda8aSnia		 * down, we need to cancel the operation we were doing
26380bbfda8aSnia		 */
26390bbfda8aSnia		Cancel = true;
26400bbfda8aSnia		CurrentDragX = origDragX;
26410bbfda8aSnia		CurrentDragY = origDragY;
26420bbfda8aSnia		if(!menuFromFrameOrWindowOrTitlebar) {
26430bbfda8aSnia			if(Scr->OpaqueMove && DragWindow != None) {
26440bbfda8aSnia				XMoveWindow(dpy, DragWindow, origDragX, origDragY);
26450bbfda8aSnia			}
26460bbfda8aSnia			else {
26470bbfda8aSnia				MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
26480bbfda8aSnia			}
26490bbfda8aSnia		}
26500bbfda8aSnia		XUnmapWindow(dpy, Scr->SizeWindow);
26510bbfda8aSnia		if(!Scr->OpaqueMove) {
26520bbfda8aSnia			UninstallRootColormap();
26530bbfda8aSnia		}
26540bbfda8aSnia		ResizeWindow = None;
26550bbfda8aSnia		DragWindow = None;
26560bbfda8aSnia		cur = LeftButt;
26570bbfda8aSnia		if(Event.xbutton.button == Button2) {
26580bbfda8aSnia			cur = MiddleButt;
26590bbfda8aSnia		}
26600bbfda8aSnia		else if(Event.xbutton.button >= Button3) {
26610bbfda8aSnia			cur = RightButt;
26620bbfda8aSnia		}
26630bbfda8aSnia
26640bbfda8aSnia		XGrabPointer(dpy, Scr->Root, True,
26650bbfda8aSnia		             ButtonReleaseMask | ButtonPressMask,
26660bbfda8aSnia		             GrabModeAsync, GrabModeAsync,
26670bbfda8aSnia		             Scr->Root, cur, CurrentTime);
26680bbfda8aSnia
26690bbfda8aSnia		return;
26700bbfda8aSnia	}
26710bbfda8aSnia	else {
26720bbfda8aSnia		ButtonPressed = Event.xbutton.button;
26730bbfda8aSnia	}
26740bbfda8aSnia
26750bbfda8aSnia	if((ActiveMenu != NULL) && (ActiveMenu->pinned)) {
26760bbfda8aSnia		if(Event.xbutton.window == ActiveMenu->w) {
26770bbfda8aSnia			modifier = (Event.xbutton.state & mods_used);
26780bbfda8aSnia			modifier = set_mask_ignore(modifier);
26790bbfda8aSnia			if((ActiveItem && (ActiveItem->func == F_TITLE)) || (modifier == Mod1Mask)) {
26800bbfda8aSnia				MoveMenu(&Event);
26810bbfda8aSnia				/*ButtonPressed = -1;*/
26820bbfda8aSnia			}
26830bbfda8aSnia		}
26840bbfda8aSnia		Context = C_ROOT;
26850bbfda8aSnia		return;
26860bbfda8aSnia	}
26870bbfda8aSnia
26880bbfda8aSnia	if(ResizeWindow != None ||
26890bbfda8aSnia	                DragWindow != None  ||
26900bbfda8aSnia	                ActiveMenu != NULL) {
26910bbfda8aSnia		return;
26920bbfda8aSnia	}
26930bbfda8aSnia
26940bbfda8aSnia	/* check the title bar buttons */
26950bbfda8aSnia	if(Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons) {
26960bbfda8aSnia		int i;
26970bbfda8aSnia		TBWindow *tbw;
26980bbfda8aSnia		TitleButtonFunc *tbf;
26990bbfda8aSnia		int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
27000bbfda8aSnia
27010bbfda8aSnia		modifier = Event.xbutton.state & mods_used;
27020bbfda8aSnia		modifier = set_mask_ignore(modifier);
27030bbfda8aSnia
27040bbfda8aSnia		for(i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
27050bbfda8aSnia			if(Event.xany.window == tbw->window) {
27060bbfda8aSnia				for(tbf = tbw->info->funs; tbf; tbf = tbf->next) {
27070bbfda8aSnia					if(tbf->num == ButtonPressed
27080bbfda8aSnia					                && tbf->mods == modifier) {
27090bbfda8aSnia						switch(tbf->func) {
27100bbfda8aSnia							/*
27110bbfda8aSnia							 * Opening up a menu doesn't use the f.menu
27120bbfda8aSnia							 * handler, we use our do_menu(); x-ref
27130bbfda8aSnia							 * comments in the handler for details.
27140bbfda8aSnia							 */
27150bbfda8aSnia							case F_MENU :
27160bbfda8aSnia								Context = C_TITLE;
27170bbfda8aSnia								ButtonWindow = Tmp_win;
27180bbfda8aSnia								do_menu(tbf->menuroot, tbw->window);
27190bbfda8aSnia								break;
27200bbfda8aSnia
27210bbfda8aSnia							default :
27220bbfda8aSnia								ExecuteFunction(tbf->func, tbf->action,
27230bbfda8aSnia								                Event.xany.window, Tmp_win,
27240bbfda8aSnia								                &Event, C_TITLE, false);
27250bbfda8aSnia						}
27260bbfda8aSnia						return;
27270bbfda8aSnia					}
27280bbfda8aSnia				}
27290bbfda8aSnia			}
27300bbfda8aSnia		}
27310bbfda8aSnia	}
27320bbfda8aSnia
27330bbfda8aSnia	Context = C_NO_CONTEXT;
27340bbfda8aSnia
27350bbfda8aSnia	if(Event.xany.window == Scr->InfoWindow.win) {
27360bbfda8aSnia		Context = C_IDENTIFY;
27370bbfda8aSnia	}
27380bbfda8aSnia
27390bbfda8aSnia	if(Event.xany.window == Scr->Root) {
27400bbfda8aSnia		if(AlternateContext) {
27410bbfda8aSnia			XUngrabPointer(dpy, CurrentTime);
27420bbfda8aSnia			XUngrabKeyboard(dpy, CurrentTime);
27430bbfda8aSnia			AlternateContext = false;
27440bbfda8aSnia			Context = C_ALTERNATE;
27450bbfda8aSnia		}
27460bbfda8aSnia		else if(AlternateKeymap && Event.xbutton.subwindow) {
27470bbfda8aSnia			int dx, dy;
27480bbfda8aSnia			Window child;
27490bbfda8aSnia
27500bbfda8aSnia			w = Event.xbutton.subwindow;
27510bbfda8aSnia			Tmp_win = GetTwmWindow(w);
27520bbfda8aSnia			if(Tmp_win) {
27530bbfda8aSnia				Event.xany.window    = Tmp_win->frame;
27540bbfda8aSnia				XTranslateCoordinates(dpy, Scr->Root, Tmp_win->frame,
27550bbfda8aSnia				                      Event.xbutton.x, Event.xbutton.y, &dx, &dy, &child);
27560bbfda8aSnia				Event.xbutton.x = dx;
27570bbfda8aSnia				Event.xbutton.x = dy;
27580bbfda8aSnia				Event.xbutton.subwindow = child;
27590bbfda8aSnia			}
27600bbfda8aSnia		}
27610bbfda8aSnia		else {
27620bbfda8aSnia			Context = C_ROOT;
27630bbfda8aSnia		}
27640bbfda8aSnia	}
27650bbfda8aSnia	if(Tmp_win) {
27660bbfda8aSnia		if(Tmp_win->iconmanagerlist && (RootFunction != 0) &&
27670bbfda8aSnia		                ((Event.xany.window == Tmp_win->iconmanagerlist->icon) ||
27680bbfda8aSnia		                 (Event.xany.window == Tmp_win->iconmanagerlist->w))) {
27690bbfda8aSnia			int x, y;
27700bbfda8aSnia
27710bbfda8aSnia			Tmp_win = Tmp_win->iconmanagerlist->iconmgr->twm_win;
27720bbfda8aSnia			XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
27730bbfda8aSnia			                      Event.xbutton.x, Event.xbutton.y,
27740bbfda8aSnia			                      &x, &y, &JunkChild);
27750bbfda8aSnia
27760bbfda8aSnia			Event.xbutton.x = x - Tmp_win->frame_bw3D;
27770bbfda8aSnia			Event.xbutton.y = y - Tmp_win->title_height - Tmp_win->frame_bw3D;
27780bbfda8aSnia			Event.xany.window = Tmp_win->w;
27790bbfda8aSnia			Context = C_WINDOW;
27800bbfda8aSnia		}
27810bbfda8aSnia#ifdef EWMH_DESKTOP_ROOT
27820bbfda8aSnia		else if(Tmp_win->ewmhWindowType == wt_Desktop) {
27830bbfda8aSnia			fprintf(stderr, "HandleButtonPress: wt_Desktop -> C_ROOT\n");
27840bbfda8aSnia			Context = C_ROOT;
27850bbfda8aSnia		}
27860bbfda8aSnia#endif
27870bbfda8aSnia		else if(Event.xany.window == Tmp_win->title_w) {
27880bbfda8aSnia			if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
27890bbfda8aSnia				SetFocus(Tmp_win, CurrentTime);
27900bbfda8aSnia			}
27910bbfda8aSnia			Context = C_TITLE;
27920bbfda8aSnia		}
27930bbfda8aSnia		else if(Event.xany.window == Tmp_win->w) {
27940bbfda8aSnia			if(Scr->ClickToFocus || Scr->RaiseOnClick) {
27950bbfda8aSnia				if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
27960bbfda8aSnia					SetFocus(Tmp_win, CurrentTime);
27970bbfda8aSnia				}
27980bbfda8aSnia				if(Scr->RaiseOnClick) {
27990bbfda8aSnia					OtpRaise(Tmp_win, WinWin);
28000bbfda8aSnia					WMapRaise(Tmp_win);
28010bbfda8aSnia				}
28020bbfda8aSnia				XSync(dpy, 0);
28030bbfda8aSnia				XAllowEvents(dpy, ReplayPointer, CurrentTime);
28040bbfda8aSnia				XSync(dpy, 0);
28050bbfda8aSnia				ButtonPressed = -1;
28060bbfda8aSnia				return;
28070bbfda8aSnia			}
28080bbfda8aSnia			else {
28090bbfda8aSnia				printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
28100bbfda8aSnia				Context = C_WINDOW;
28110bbfda8aSnia			}
28120bbfda8aSnia		}
28130bbfda8aSnia		else if(Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w)) {
28140bbfda8aSnia			Context = C_ICON;
28150bbfda8aSnia		}
28160bbfda8aSnia		else if(Event.xany.window == Tmp_win->frame) {
28170bbfda8aSnia			Window chwin;
28180bbfda8aSnia
28190bbfda8aSnia			/* since we now place a button grab on the frame instead
28200bbfda8aSnia			 * of the window, (see GrabButtons() in add_window.c), we
28210bbfda8aSnia			 * need to figure out where the pointer exactly is before
28220bbfda8aSnia			 * assigning Context.  If the pointer is on the application
28230bbfda8aSnia			 * window we will change the event structure to look as if
28240bbfda8aSnia			 * it came from the application window.
28250bbfda8aSnia			 */
28260bbfda8aSnia			if(Event.xbutton.subwindow == Tmp_win->w) {
28270bbfda8aSnia				XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
28280bbfda8aSnia				                      Event.xbutton.x, Event.xbutton.y,
28290bbfda8aSnia				                      &Event.xbutton.x, &Event.xbutton.y,
28300bbfda8aSnia				                      &chwin);
28310bbfda8aSnia				Event.xbutton.window = Tmp_win->w;
28320bbfda8aSnia
2833b18c2d1eSnia#ifdef WINBOX
28340bbfda8aSnia				if(Tmp_win->iswinbox && chwin) {
28350bbfda8aSnia					int x, y;
2836b18c2d1eSnia					TwmWindow *wtmp;
28370bbfda8aSnia					XTranslateCoordinates(dpy, Tmp_win->w, chwin,
28380bbfda8aSnia					                      Event.xbutton.x, Event.xbutton.y,
28390bbfda8aSnia					                      &x, &y, &chwin);
2840b18c2d1eSnia					if(chwin && (wtmp = GetTwmWindow(chwin))) {
28410bbfda8aSnia						Event.xany.window = chwin;
28420bbfda8aSnia						Event.xbutton.x   = x;
28430bbfda8aSnia						Event.xbutton.y   = y;
2844b18c2d1eSnia						Tmp_win = wtmp;
28450bbfda8aSnia					}
28460bbfda8aSnia				}
2847b18c2d1eSnia#endif
28480bbfda8aSnia				Context = C_WINDOW;
28490bbfda8aSnia			}
28500bbfda8aSnia			else if(Event.xbutton.subwindow
28510bbfda8aSnia			                && (Event.xbutton.subwindow == Tmp_win->title_w)) {
28520bbfda8aSnia				Context = C_TITLE;
28530bbfda8aSnia			}
28540bbfda8aSnia			else {
28550bbfda8aSnia				Context = C_FRAME;
28560bbfda8aSnia			}
2857b18c2d1eSnia
28580bbfda8aSnia			if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
28590bbfda8aSnia				SetFocus(Tmp_win, CurrentTime);
28600bbfda8aSnia			}
28610bbfda8aSnia		}
28620bbfda8aSnia		else if(Tmp_win->iswspmgr ||
28630bbfda8aSnia		                (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
28640bbfda8aSnia			/*Context = C_WINDOW; probably a typo */
28650bbfda8aSnia			Context = C_WORKSPACE;
28660bbfda8aSnia		}
28670bbfda8aSnia		else if(Tmp_win->iconmanagerlist) {
28680bbfda8aSnia			if((Event.xany.window == Tmp_win->iconmanagerlist->icon) ||
28690bbfda8aSnia			                (Event.xany.window == Tmp_win->iconmanagerlist->w)) {
28700bbfda8aSnia				Tmp_win->iconmanagerlist->down = true;
28710bbfda8aSnia				if(Scr->Highlight) {
28720bbfda8aSnia					DrawIconManagerBorder(Tmp_win->iconmanagerlist, false);
28730bbfda8aSnia				}
28740bbfda8aSnia				DownIconManager = Tmp_win->iconmanagerlist;
28750bbfda8aSnia				Context = C_ICONMGR;
28760bbfda8aSnia			}
28770bbfda8aSnia		}
28780bbfda8aSnia	}
28790bbfda8aSnia
28800bbfda8aSnia	/* this section of code checks to see if we were in the middle of
28810bbfda8aSnia	 * a command executed from a menu
28820bbfda8aSnia	 */
28830bbfda8aSnia	if(RootFunction != 0) {
28840bbfda8aSnia		if(Event.xany.window == Scr->Root) {
28850bbfda8aSnia			int x, y;
28860bbfda8aSnia
28870bbfda8aSnia			/* if the window was the Root, we don't know for sure it
28880bbfda8aSnia			 * it was the root.  We must check to see if it happened to be
28890bbfda8aSnia			 * inside of a client that was getting button press events.
28900bbfda8aSnia			 */
28910bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
28920bbfda8aSnia			                      Event.xbutton.x,
28930bbfda8aSnia			                      Event.xbutton.y,
28940bbfda8aSnia			                      &x, &y, &Event.xany.window);
28950bbfda8aSnia
28960bbfda8aSnia			if(Event.xany.window != 0 &&
28970bbfda8aSnia			                (Tmp_win = GetTwmWindow(Event.xany.window))) {
2898b18c2d1eSnia#ifdef WINBOX
28990bbfda8aSnia				if(Tmp_win->iswinbox) {
2900b18c2d1eSnia					Window win;
29010bbfda8aSnia					XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
29020bbfda8aSnia					                      x, y, &x, &y, &win);
29030bbfda8aSnia					XTranslateCoordinates(dpy, Event.xany.window, win,
29040bbfda8aSnia					                      x, y, &x, &y, &win);
29050bbfda8aSnia					if(win != 0) {
29060bbfda8aSnia						Event.xany.window = win;
29070bbfda8aSnia					}
29080bbfda8aSnia				}
2909b18c2d1eSnia#endif
29100bbfda8aSnia			}
29110bbfda8aSnia			if(Event.xany.window == 0 ||
29120bbfda8aSnia			                !(Tmp_win = GetTwmWindow(Event.xany.window))) {
29130bbfda8aSnia				RootFunction = 0;
29140bbfda8aSnia				XBell(dpy, 0);
29150bbfda8aSnia				return;
29160bbfda8aSnia			}
29170bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
29180bbfda8aSnia			                      Event.xbutton.x,
29190bbfda8aSnia			                      Event.xbutton.y,
29200bbfda8aSnia			                      &x, &y, &JunkChild);
29210bbfda8aSnia
29220bbfda8aSnia			Event.xbutton.x = x;
29230bbfda8aSnia			Event.xbutton.y = y;
29240bbfda8aSnia			Context = C_WINDOW;
29250bbfda8aSnia		}
29260bbfda8aSnia		else if(mr != NULL) {
29270bbfda8aSnia			RootFunction = 0;
29280bbfda8aSnia			XBell(dpy, 0);
29290bbfda8aSnia			return;
29300bbfda8aSnia		}
29310bbfda8aSnia
29320bbfda8aSnia		/* make sure we are not trying to move an identify window */
29330bbfda8aSnia		if(Event.xany.window != Scr->InfoWindow.win) {
29340bbfda8aSnia			/*
29350bbfda8aSnia			 * X-ref comment at top of file about Action; this is where
29360bbfda8aSnia			 * we need to use its broader lifespan.
29370bbfda8aSnia			 */
29380bbfda8aSnia			ExecuteFunction(RootFunction, Action, Event.xany.window,
29390bbfda8aSnia			                Tmp_win, &Event, Context, false);
29400bbfda8aSnia		}
29410bbfda8aSnia
29420bbfda8aSnia		RootFunction = 0;
29430bbfda8aSnia		return;
29440bbfda8aSnia	}
29450bbfda8aSnia
29460bbfda8aSnia	ButtonWindow = Tmp_win;
29470bbfda8aSnia
29480bbfda8aSnia	/* if we get to here, we have to execute a function or pop up a
29490bbfda8aSnia	 * menu
29500bbfda8aSnia	 */
29510bbfda8aSnia	modifier = (Event.xbutton.state | AlternateKeymap) & mods_used;
29520bbfda8aSnia	modifier = set_mask_ignore(modifier);
29530bbfda8aSnia	if(AlternateKeymap) {
29540bbfda8aSnia		XUngrabPointer(dpy, CurrentTime);
29550bbfda8aSnia		XUngrabKeyboard(dpy, CurrentTime);
29560bbfda8aSnia		AlternateKeymap = 0;
29570bbfda8aSnia	}
29580bbfda8aSnia	if((Context == C_NO_CONTEXT) || (Context == C_IDENTIFY)) {
29590bbfda8aSnia		return;
29600bbfda8aSnia	}
29610bbfda8aSnia
29620bbfda8aSnia	RootFunction = 0;
29630bbfda8aSnia
29640bbfda8aSnia	/* see if there already is a key defined for this context */
29650bbfda8aSnia	for(tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
29660bbfda8aSnia		if((tmp->num  == Event.xbutton.button) &&
29670bbfda8aSnia		                (tmp->cont == Context) && (tmp->mods == modifier)) {
29680bbfda8aSnia			break;
29690bbfda8aSnia		}
29700bbfda8aSnia	}
29710bbfda8aSnia	if(tmp) {
29720bbfda8aSnia		func = tmp->func;
29730bbfda8aSnia		switch(func) {
29740bbfda8aSnia			/*
29750bbfda8aSnia			 * f.menu isn't invoked, it's handle magically.  Other funcs
29760bbfda8aSnia			 * we just invoke.  X-ref the f.menu handler for details.
29770bbfda8aSnia			 */
29780bbfda8aSnia			case F_MENU :
29790bbfda8aSnia				do_menu(tmp->menu, (Window) None);
29800bbfda8aSnia				break;
29810bbfda8aSnia
29820bbfda8aSnia			default :
29830bbfda8aSnia				if(func != 0) {
29840bbfda8aSnia					Action = tmp->item ? tmp->item->action : NULL;
29850bbfda8aSnia#ifdef EWMH_DESKTOP_ROOT
29860bbfda8aSnia					if(Context == C_ROOT && Tmp_win != NULL) {
29870bbfda8aSnia						Context = C_WINDOW;
29880bbfda8aSnia						fprintf(stderr, "HandleButtonPress: wt_Desktop -> C_WINDOW\n");
29890bbfda8aSnia					}
29900bbfda8aSnia#endif /* EWMH */
29910bbfda8aSnia					ExecuteFunction(func,
29920bbfda8aSnia					                Action, Event.xany.window, Tmp_win, &Event, Context, false);
29930bbfda8aSnia				}
29940bbfda8aSnia		}
29950bbfda8aSnia	}
29960bbfda8aSnia	else {
29970bbfda8aSnia		if(Tmp_win == Scr->currentvs->wsw->twm_win) {
29980bbfda8aSnia			WMgrHandleButtonEvent(Scr->currentvs, &Event);
29990bbfda8aSnia			return;
30000bbfda8aSnia		}
30010bbfda8aSnia	}
30020bbfda8aSnia	if(Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
30030bbfda8aSnia		OccupyHandleButtonEvent(&Event);
30040bbfda8aSnia	}
30050bbfda8aSnia	else if(func == 0 && Scr->DefaultFunction.func != 0) {
30060bbfda8aSnia		if(Scr->DefaultFunction.func == F_MENU) {
30070bbfda8aSnia			do_menu(Scr->DefaultFunction.menu, (Window) None);
30080bbfda8aSnia		}
30090bbfda8aSnia		else {
30100bbfda8aSnia			Action = Scr->DefaultFunction.item ?
30110bbfda8aSnia			         Scr->DefaultFunction.item->action : NULL;
30120bbfda8aSnia			ExecuteFunction(Scr->DefaultFunction.func, Action,
30130bbfda8aSnia			                Event.xany.window, Tmp_win, &Event, Context, false);
30140bbfda8aSnia		}
30150bbfda8aSnia	}
30160bbfda8aSnia}
30170bbfda8aSnia
30180bbfda8aSnia
30190bbfda8aSnia/***********************************************************************
30200bbfda8aSnia *
30210bbfda8aSnia *  Procedure:
30220bbfda8aSnia *      HENQueueScanner - EnterNotify event q scanner
30230bbfda8aSnia *
30240bbfda8aSnia *      Looks at the queued events and determines if any matching
30250bbfda8aSnia *      LeaveNotify events or EnterEvents deriving from the
30260bbfda8aSnia *      termination of a grab are behind this event to allow
30270bbfda8aSnia *      skipping of unnecessary processing.
30280bbfda8aSnia *
30290bbfda8aSnia ***********************************************************************
30300bbfda8aSnia */
30310bbfda8aSnia
30320bbfda8aSniatypedef struct HENScanArgs {
30330bbfda8aSnia	Window w;           /* Window we are currently entering */
30340bbfda8aSnia	Bool leaves;        /* Any LeaveNotifies found for this window */
30350bbfda8aSnia	Bool inferior;      /* Was NotifyInferior the mode for LeaveNotify */
30360bbfda8aSnia	Bool enters;        /* Any EnterNotify events with NotifyUngrab */
30370bbfda8aSnia} HENScanArgs;
30380bbfda8aSnia
30390bbfda8aSnia/* ARGSUSED*/
30400bbfda8aSniastatic Bool HENQueueScanner(Display *display, XEvent *ev, char *_args)
30410bbfda8aSnia{
30420bbfda8aSnia	HENScanArgs *args = (void *)_args;
30430bbfda8aSnia
30440bbfda8aSnia	if(ev->type == LeaveNotify) {
30450bbfda8aSnia		if(ev->xcrossing.window == args->w &&
30460bbfda8aSnia		                ev->xcrossing.mode == NotifyNormal) {
30470bbfda8aSnia			args->leaves = True;
30480bbfda8aSnia			/*
30490bbfda8aSnia			 * Only the last event found matters for the Inferior field.
30500bbfda8aSnia			 */
30510bbfda8aSnia			args->inferior =
30520bbfda8aSnia			        (ev->xcrossing.detail == NotifyInferior);
30530bbfda8aSnia		}
30540bbfda8aSnia	}
30550bbfda8aSnia	else if(ev->type == EnterNotify) {
30560bbfda8aSnia		if(ev->xcrossing.mode == NotifyUngrab) {
30570bbfda8aSnia			args->enters = True;
30580bbfda8aSnia		}
30590bbfda8aSnia	}
30600bbfda8aSnia
30610bbfda8aSnia	return (False);
30620bbfda8aSnia}
30630bbfda8aSnia
30640bbfda8aSnia
30650bbfda8aSnia/***********************************************************************
30660bbfda8aSnia *
30670bbfda8aSnia *  Procedure:
30680bbfda8aSnia *      HandleEnterNotify - EnterNotify event handler
30690bbfda8aSnia *
30700bbfda8aSnia ***********************************************************************
30710bbfda8aSnia */
30720bbfda8aSnia
30730bbfda8aSniavoid HandleEnterNotify(void)
30740bbfda8aSnia{
30750bbfda8aSnia	MenuRoot *mr, *tmp;
30760bbfda8aSnia	XEnterWindowEvent *ewp = &Event.xcrossing;
30770bbfda8aSnia	HENScanArgs scanArgs;
30780bbfda8aSnia	XEvent dummy;
30790bbfda8aSnia	VirtualScreen *vs;
30800bbfda8aSnia
30810bbfda8aSnia	/*
30820bbfda8aSnia	 * if we aren't in the middle of menu processing
30830bbfda8aSnia	 */
30840bbfda8aSnia	if(!ActiveMenu) {
30850bbfda8aSnia		/*
30860bbfda8aSnia		 * We're not interested in pseudo Enter/Leave events generated
30870bbfda8aSnia		 * from grab initiations.
30880bbfda8aSnia		 */
30890bbfda8aSnia		if(ewp->mode == NotifyGrab) {
30900bbfda8aSnia			return;
30910bbfda8aSnia		}
30920bbfda8aSnia
30930bbfda8aSnia		/*
30940bbfda8aSnia		 * Scan for Leave and Enter Notify events to see if we can avoid some
30950bbfda8aSnia		 * unnecessary processing.
30960bbfda8aSnia		 */
30970bbfda8aSnia		scanArgs.w = ewp->window;
30980bbfda8aSnia		scanArgs.leaves = scanArgs.enters = False;
30990bbfda8aSnia		XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs);
31000bbfda8aSnia
31010bbfda8aSnia		/*
31020bbfda8aSnia		 * if entering root window, restore twm default colormap so that
31030bbfda8aSnia		 * titlebars are legible
31040bbfda8aSnia		 */
31050bbfda8aSnia		if(ewp->window == Scr->Root) {
31060bbfda8aSnia			Window forus_ret;
31070bbfda8aSnia			int focus_rev;
31080bbfda8aSnia
31090bbfda8aSnia			if(!scanArgs.leaves && !scanArgs.enters) {
31100bbfda8aSnia				InstallColormaps(EnterNotify, &Scr->RootColormaps);
31110bbfda8aSnia			}
31120bbfda8aSnia			if(! Scr->FocusRoot) {
31130bbfda8aSnia				return;
31140bbfda8aSnia			}
31150bbfda8aSnia			XGetInputFocus(dpy, &forus_ret, &focus_rev);
31160bbfda8aSnia			if((forus_ret != PointerRoot) && (forus_ret != None)) {
31170bbfda8aSnia				SetFocus(NULL, Event.xcrossing.time);
31180bbfda8aSnia			}
31190bbfda8aSnia			return;
31200bbfda8aSnia		}
31210bbfda8aSnia		for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
31220bbfda8aSnia			if(ewp->window == vs->window) {
31230bbfda8aSnia				Scr->Root  = vs->window;
3124b18c2d1eSnia#ifdef CAPTIVE
31250bbfda8aSnia				Scr->rootx = Scr->crootx + vs->x;
31260bbfda8aSnia				Scr->rooty = Scr->crooty + vs->y;
3127b18c2d1eSnia#else
3128b18c2d1eSnia				Scr->rootx = vs->x;
3129b18c2d1eSnia				Scr->rooty = vs->y;
3130b18c2d1eSnia#endif
31310bbfda8aSnia				Scr->rootw = vs->w;
31320bbfda8aSnia				Scr->rooth = vs->h;
31330bbfda8aSnia				Scr->currentvs = vs;
31340bbfda8aSnia#if 0
3135b18c2d1eSnia				fprintf(stderr, "entering new vs : %p, 0x%lx, %d, %d, %d, %d\n",
31360bbfda8aSnia				        vs, Scr->Root, vs->x, vs->y, vs->w, vs->h);
31370bbfda8aSnia#endif
31380bbfda8aSnia				return;
31390bbfda8aSnia			}
31400bbfda8aSnia		}
31410bbfda8aSnia
31420bbfda8aSnia		/* Handle RaiseDelay, if any.....
31430bbfda8aSnia		 */
31440bbfda8aSnia		if(RaiseDelay > 0) {
31450bbfda8aSnia			if(Tmp_win && Tmp_win->auto_raise &&
31460bbfda8aSnia			                (!Tmp_win->iconmanagerlist ||
31470bbfda8aSnia			                 Tmp_win->iconmanagerlist->w != ewp->window)) {
31480bbfda8aSnia				ColormapWindow *cwin;
31490bbfda8aSnia				static struct timeval tout, timeout = {0, 12500};
31500bbfda8aSnia
31510bbfda8aSnia				if(XFindContext(dpy, Tmp_win->w, ColormapContext,
31520bbfda8aSnia				                (XPointer *)&cwin) == XCNOENT) {
31530bbfda8aSnia					cwin = NULL;
31540bbfda8aSnia				}
31550bbfda8aSnia
31560bbfda8aSnia				if((ewp->detail != NotifyInferior
31570bbfda8aSnia				                || Tmp_win->frame == ewp->window)
31580bbfda8aSnia				                && (!cwin || cwin->visibility != VisibilityUnobscured)) {
31590bbfda8aSnia					int x, y, px, py, d, i;
31600bbfda8aSnia					Window w;
31610bbfda8aSnia
31620bbfda8aSnia					XQueryPointer(dpy, Scr->Root, &w, &w, &px, &py,
31630bbfda8aSnia					              &d, &d, (unsigned int *)&d);
31640bbfda8aSnia
31650bbfda8aSnia					/* The granularity of RaiseDelay is about 25 ms.
31660bbfda8aSnia					 * The timeout variable is set to 12.5 ms since we
31670bbfda8aSnia					 * pass this way twice each time a twm window is
31680bbfda8aSnia					 * entered.
31690bbfda8aSnia					 */
31700bbfda8aSnia					for(i = 25; i < RaiseDelay; i += 25) {
31710bbfda8aSnia						tout = timeout;
31720bbfda8aSnia						select(0, NULL, NULL, NULL, &tout);
31730bbfda8aSnia						/* Did we leave this window already? */
31740bbfda8aSnia						scanArgs.w = ewp->window;
31750bbfda8aSnia						scanArgs.leaves = scanArgs.enters = False;
31760bbfda8aSnia						XCheckIfEvent(dpy, &dummy, HENQueueScanner,
31770bbfda8aSnia						              (void *) &scanArgs);
31780bbfda8aSnia						if(scanArgs.leaves && !scanArgs.inferior) {
31790bbfda8aSnia							return;
31800bbfda8aSnia						}
31810bbfda8aSnia
31820bbfda8aSnia						XQueryPointer(dpy, Scr->Root, &w, &w, &x, &y,
31830bbfda8aSnia						              &d, &d, (unsigned int *)&d);
31840bbfda8aSnia
31850bbfda8aSnia						/* Has the pointer moved?  If so reset the loop cnt.
31860bbfda8aSnia						 * We want the pointer to be still for RaiseDelay
31870bbfda8aSnia						 * milliseconds before terminating the loop
31880bbfda8aSnia						 */
31890bbfda8aSnia						if(x != px || y != py) {
31900bbfda8aSnia							i = 0;
31910bbfda8aSnia							px = x;
31920bbfda8aSnia							py = y;
31930bbfda8aSnia						}
31940bbfda8aSnia					}
31950bbfda8aSnia				}
31960bbfda8aSnia			}
31970bbfda8aSnia
31980bbfda8aSnia			/*
31990bbfda8aSnia			 * Scan for Leave and Enter Notify events to see if we can avoid some
32000bbfda8aSnia			 * unnecessary processing.
32010bbfda8aSnia			 */
32020bbfda8aSnia			scanArgs.w = ewp->window;
32030bbfda8aSnia			scanArgs.leaves = scanArgs.enters = False;
32040bbfda8aSnia			XCheckIfEvent(dpy, &dummy, HENQueueScanner, (void *) &scanArgs);
32050bbfda8aSnia
32060bbfda8aSnia			/*
32070bbfda8aSnia			 * if entering root window, restore twm default colormap so that
32080bbfda8aSnia			 * titlebars are legible
32090bbfda8aSnia			 */
32100bbfda8aSnia			if(ewp->window == Scr->Root) {
32110bbfda8aSnia				if(!scanArgs.leaves && !scanArgs.enters) {
32120bbfda8aSnia					InstallColormaps(EnterNotify, &Scr->RootColormaps);
32130bbfda8aSnia				}
32140bbfda8aSnia				return;
32150bbfda8aSnia			}
32160bbfda8aSnia		}
32170bbfda8aSnia		/* End of RaiseDelay modification. */
32180bbfda8aSnia
32190bbfda8aSnia		/*
32200bbfda8aSnia		 * if we have an event for a specific one of our windows
32210bbfda8aSnia		 */
32220bbfda8aSnia		if(Tmp_win) {
32230bbfda8aSnia			/*
32240bbfda8aSnia			 * If currently in PointerRoot mode (indicated by FocusRoot), then
32250bbfda8aSnia			 * focus on this window
32260bbfda8aSnia			 */
32270bbfda8aSnia			if(Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
32280bbfda8aSnia				bool accinput;
32290bbfda8aSnia
32300bbfda8aSnia				if(Scr->ShrinkIconTitles &&
32310bbfda8aSnia				                Tmp_win->icon &&
32320bbfda8aSnia				                ewp->window == Tmp_win->icon->w &&
32330bbfda8aSnia				                ewp->detail != NotifyInferior) {
32340bbfda8aSnia					if(Scr->AutoRaiseIcons) {
32350bbfda8aSnia						OtpRaise(Tmp_win, IconWin);
32360bbfda8aSnia					}
32370bbfda8aSnia					ExpandIconTitle(Tmp_win);
32380bbfda8aSnia					return;
32390bbfda8aSnia				}
32400bbfda8aSnia
32410bbfda8aSnia				if(Tmp_win->iconmanagerlist) {
32420bbfda8aSnia					CurrentIconManagerEntry(Tmp_win->iconmanagerlist);
32430bbfda8aSnia				}
32440bbfda8aSnia
32450bbfda8aSnia				accinput = Tmp_win->mapped && Tmp_win->wmhints->input;
32460bbfda8aSnia				if(Tmp_win->iconmanagerlist &&
32470bbfda8aSnia				                ewp->window == Tmp_win->iconmanagerlist->w &&
32480bbfda8aSnia				                !accinput &&
32490bbfda8aSnia				                Tmp_win->iconmanagerlist->iconmgr &&
32500bbfda8aSnia				                Tmp_win->iconmanagerlist->iconmgr->twm_win) {
32510bbfda8aSnia					SetFocus(Tmp_win->iconmanagerlist->iconmgr->twm_win,
32520bbfda8aSnia					         CurrentTime);
32530bbfda8aSnia					return;
32540bbfda8aSnia				}
32550bbfda8aSnia
32560bbfda8aSnia				if(Tmp_win->mapped) {
32570bbfda8aSnia					/*
32580bbfda8aSnia					 * unhighlight old focus window
32590bbfda8aSnia					 */
32600bbfda8aSnia
32610bbfda8aSnia					/*
32620bbfda8aSnia					 * If entering the frame or the icon manager, then do
32630bbfda8aSnia					 * "window activation things":
32640bbfda8aSnia					 *
32650bbfda8aSnia					 *     1.  <highlighting is not done here any more>
32660bbfda8aSnia					 *     2.  install frame colormap
32670bbfda8aSnia					 *     3.  <frame and highlight border not set here>
32680bbfda8aSnia					 *     4.  focus on client window to forward typing
32690bbfda8aSnia					 *     4a. same as 4 but for icon mgr w/with NoTitleFocus
32700bbfda8aSnia					 *     5.  send WM_TAKE_FOCUS if requested
32710bbfda8aSnia					 */
32720bbfda8aSnia					if(Scr->BorderCursors && ewp->window == Tmp_win->frame) {
32730bbfda8aSnia						SetBorderCursor(Tmp_win, ewp->x, ewp->y);
32740bbfda8aSnia					}
32750bbfda8aSnia					if(ewp->window == Tmp_win->frame ||
32760bbfda8aSnia					                (Scr->IconManagerFocus &&
32770bbfda8aSnia					                 Tmp_win->iconmanagerlist &&
32780bbfda8aSnia					                 ewp->window == Tmp_win->iconmanagerlist->w)) {
32790bbfda8aSnia
32800bbfda8aSnia						if(!scanArgs.leaves && !scanArgs.enters) {
32810bbfda8aSnia							InstallColormaps(EnterNotify,       /* 2 */
32820bbfda8aSnia							                 &Scr->RootColormaps);
32830bbfda8aSnia						}
32840bbfda8aSnia
32850bbfda8aSnia						/*
32860bbfda8aSnia						 * Event is in the frame or the icon mgr:
32870bbfda8aSnia						 *
32880bbfda8aSnia						 * "4" -- TitleFocus is set: windows should get
32890bbfda8aSnia						 *        focus as long as they accept input.
32900bbfda8aSnia						 *
32910bbfda8aSnia						 * "4a" - If TitleFocus is not set, windows should get
32920bbfda8aSnia						 *        the focus if the event was in the icon mgr
32930bbfda8aSnia						 *        (as long as they accept input).
32940bbfda8aSnia						 *
32950bbfda8aSnia						 */
32960bbfda8aSnia
32970bbfda8aSnia						/* If the window takes input... */
32980bbfda8aSnia						if(Tmp_win->wmhints->input) {
32990bbfda8aSnia
33000bbfda8aSnia							/* if 4 or 4a, focus on the window */
33010bbfda8aSnia							if(Scr->TitleFocus ||
33020bbfda8aSnia							                (Tmp_win->iconmanagerlist &&
33030bbfda8aSnia							                 (Tmp_win->iconmanagerlist->w == ewp->window))) {
33040bbfda8aSnia								SetFocus(Tmp_win, ewp->time);
33050bbfda8aSnia							}
33060bbfda8aSnia						}
33070bbfda8aSnia
33080bbfda8aSnia						if(Scr->TitleFocus &&
33090bbfda8aSnia						                (Tmp_win->protocols & DoesWmTakeFocus)) {   /* 5 */
33100bbfda8aSnia
33110bbfda8aSnia							/* for both locally or globally active */
33120bbfda8aSnia							SendTakeFocusMessage(Tmp_win, ewp->time);
33130bbfda8aSnia						}
33140bbfda8aSnia						else if(!Scr->TitleFocus
33150bbfda8aSnia						                && Tmp_win->wmhints->input
33160bbfda8aSnia						                && Event.xcrossing.focus) {
33170bbfda8aSnia							SynthesiseFocusIn(Tmp_win->w);
33180bbfda8aSnia						}
33190bbfda8aSnia
33200bbfda8aSnia					}
33210bbfda8aSnia					else if(ewp->window == Tmp_win->w) {
33220bbfda8aSnia						/*
33230bbfda8aSnia						 * If we are entering the application window, install
33240bbfda8aSnia						 * its colormap(s).
33250bbfda8aSnia						 */
33260bbfda8aSnia						if(Scr->BorderCursors) {
33270bbfda8aSnia							SetBorderCursor(Tmp_win, -1000, -1000);
33280bbfda8aSnia						}
33290bbfda8aSnia						if(!scanArgs.leaves || scanArgs.inferior) {
33300bbfda8aSnia							InstallWindowColormaps(EnterNotify, Tmp_win);
33310bbfda8aSnia						}
33320bbfda8aSnia
33330bbfda8aSnia						if(Event.xcrossing.focus) {
33340bbfda8aSnia							SynthesiseFocusIn(Tmp_win->w);
33350bbfda8aSnia						}
33360bbfda8aSnia
33370bbfda8aSnia						/* must deal with WM_TAKE_FOCUS clients now, if
33380bbfda8aSnia						   we're not in TitleFocus mode */
33390bbfda8aSnia
33400bbfda8aSnia						if(!(Scr->TitleFocus) &&
33410bbfda8aSnia						                (Tmp_win->protocols & DoesWmTakeFocus)) {
33420bbfda8aSnia
33430bbfda8aSnia							/* locally active clients need help from WM
33440bbfda8aSnia							   to get the input focus */
33450bbfda8aSnia
33460bbfda8aSnia							if(Tmp_win->wmhints->input) {
33470bbfda8aSnia								SetFocus(Tmp_win, ewp->time);
33480bbfda8aSnia							}
33490bbfda8aSnia
33500bbfda8aSnia							/* for both locally & globally active clnts */
33510bbfda8aSnia
33520bbfda8aSnia							SendTakeFocusMessage(Tmp_win, ewp->time);
33530bbfda8aSnia						}
33540bbfda8aSnia					}
33550bbfda8aSnia				}                       /* end if Tmp_win->mapped */
33560bbfda8aSnia				if(ewp->window == Tmp_win->wmhints->icon_window &&
33570bbfda8aSnia				                (!scanArgs.leaves || scanArgs.inferior)) {
33580bbfda8aSnia					InstallWindowColormaps(EnterNotify, Tmp_win);
33590bbfda8aSnia				}
33600bbfda8aSnia			}                           /* end if FocusRoot */
33610bbfda8aSnia			else if(Scr->BorderCursors && (ewp->window == Tmp_win->w)) {
33620bbfda8aSnia				SetBorderCursor(Tmp_win, -1000, -1000);
33630bbfda8aSnia			}
33640bbfda8aSnia			/*
33650bbfda8aSnia			 * If this window is to be autoraised, mark it so
33660bbfda8aSnia			 */
33670bbfda8aSnia			if(Tmp_win->auto_raise) {
33680bbfda8aSnia				enter_win = Tmp_win;
33690bbfda8aSnia				if(enter_flag == false) {
33700bbfda8aSnia					AutoRaiseWindow(Tmp_win);
33710bbfda8aSnia				}
33720bbfda8aSnia			}
33730bbfda8aSnia			else if(enter_flag && raise_win == Tmp_win) {
33740bbfda8aSnia				enter_win = Tmp_win;
33750bbfda8aSnia			}
33760bbfda8aSnia			/*
33770bbfda8aSnia			 * set ring leader
33780bbfda8aSnia			 */
3379b18c2d1eSnia			if(WindowIsOnRing(Tmp_win) && (!enter_flag || raise_win == enter_win)) {
33800bbfda8aSnia				Scr->RingLeader = Tmp_win;
33810bbfda8aSnia			}
33820bbfda8aSnia			XSync(dpy, 0);
33830bbfda8aSnia			return;
33840bbfda8aSnia		}                               /* end if Tmp_win */
33850bbfda8aSnia	}                                   /* end if !ActiveMenu */
33860bbfda8aSnia
33870bbfda8aSnia	/*
33880bbfda8aSnia	 * Find the menu that we are dealing with now; punt if unknown
33890bbfda8aSnia	 */
33900bbfda8aSnia	if(XFindContext(dpy, ewp->window, MenuContext, (XPointer *)&mr) != XCSUCCESS) {
33910bbfda8aSnia		return;
33920bbfda8aSnia	}
33930bbfda8aSnia
33940bbfda8aSnia	if(! ActiveMenu && mr->pinned && (RootFunction == 0)) {
33950bbfda8aSnia		PopUpMenu(mr, 0, 0, false);
33960bbfda8aSnia		Context = C_ROOT;
33970bbfda8aSnia		UpdateMenu();
33980bbfda8aSnia		return;
33990bbfda8aSnia	}
34000bbfda8aSnia	mr->entered = true;
34010bbfda8aSnia	if(RootFunction == 0) {
34020bbfda8aSnia		for(tmp = ActiveMenu; tmp; tmp = tmp->prev) {
34030bbfda8aSnia			if(tmp == mr) {
34040bbfda8aSnia				break;
34050bbfda8aSnia			}
34060bbfda8aSnia		}
34070bbfda8aSnia		if(! tmp) {
34080bbfda8aSnia			return;
34090bbfda8aSnia		}
34100bbfda8aSnia
34110bbfda8aSnia		for(tmp = ActiveMenu; tmp != mr; tmp = tmp->prev) {
34120bbfda8aSnia			if(tmp->pinned) {
34130bbfda8aSnia				break;
34140bbfda8aSnia			}
34150bbfda8aSnia			HideMenu(tmp);
34160bbfda8aSnia			MenuDepth--;
34170bbfda8aSnia		}
34180bbfda8aSnia		UninstallRootColormap();
34190bbfda8aSnia
34200bbfda8aSnia		if(ActiveItem) {
34210bbfda8aSnia			ActiveItem->state = 0;
34220bbfda8aSnia			PaintEntry(ActiveMenu, ActiveItem, false);
34230bbfda8aSnia		}
34240bbfda8aSnia		ActiveItem = NULL;
34250bbfda8aSnia		ActiveMenu = mr;
34260bbfda8aSnia		if(1/*Scr->StayUpMenus*/) {
34270bbfda8aSnia			int i, x, y, x_root, y_root, entry;
34280bbfda8aSnia			MenuItem *mi;
34290bbfda8aSnia
34300bbfda8aSnia			XQueryPointer(dpy, ActiveMenu->w, &JunkRoot, &JunkChild, &x_root, &y_root,
34310bbfda8aSnia			              &x, &y, &JunkMask);
34320bbfda8aSnia			if((x > 0) && (y > 0) && (x < ActiveMenu->width) && (y < ActiveMenu->height)) {
34330bbfda8aSnia				entry = y / Scr->EntryHeight;
34340bbfda8aSnia				for(i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi = mi->next) {
34350bbfda8aSnia					if(i == entry) {
34360bbfda8aSnia						break;
34370bbfda8aSnia					}
34380bbfda8aSnia				}
34390bbfda8aSnia				if(mi) {
34400bbfda8aSnia					ActiveItem = mi;
34410bbfda8aSnia					ActiveItem->state = 1;
34420bbfda8aSnia					PaintEntry(ActiveMenu, ActiveItem, false);
34430bbfda8aSnia				}
34440bbfda8aSnia			}
34450bbfda8aSnia		}
34460bbfda8aSnia		if(ActiveMenu->pinned) {
34470bbfda8aSnia			XUngrabPointer(dpy, CurrentTime);
34480bbfda8aSnia		}
34490bbfda8aSnia	}
34500bbfda8aSnia	return;
34510bbfda8aSnia}
34520bbfda8aSnia
34530bbfda8aSnia
34540bbfda8aSnia/***********************************************************************
34550bbfda8aSnia *
34560bbfda8aSnia *  Procedure:
34570bbfda8aSnia *      HLNQueueScanner - LeaveNotify event q scanner
34580bbfda8aSnia *
34590bbfda8aSnia *      Looks at the queued events and determines if any
34600bbfda8aSnia *      EnterNotify events are behind this event to allow
34610bbfda8aSnia *      skipping of unnecessary processing.
34620bbfda8aSnia *
34630bbfda8aSnia ***********************************************************************
34640bbfda8aSnia */
34650bbfda8aSnia
34660bbfda8aSniatypedef struct HLNScanArgs {
34670bbfda8aSnia	Window w;           /* The window getting the LeaveNotify */
34680bbfda8aSnia	Bool enters;        /* Any EnterNotify event at all */
34690bbfda8aSnia	Bool matches;       /* Any matching EnterNotify events */
34700bbfda8aSnia} HLNScanArgs;
34710bbfda8aSnia
34720bbfda8aSnia/* ARGSUSED*/
34730bbfda8aSniastatic Bool HLNQueueScanner(Display *display, XEvent *ev, char *_args)
34740bbfda8aSnia{
34750bbfda8aSnia	HLNScanArgs *args = (void *)_args;
34760bbfda8aSnia
34770bbfda8aSnia	if(ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
34780bbfda8aSnia		args->enters = True;
34790bbfda8aSnia		if(ev->xcrossing.window == args->w) {
34800bbfda8aSnia			args->matches = True;
34810bbfda8aSnia		}
34820bbfda8aSnia	}
34830bbfda8aSnia
34840bbfda8aSnia	return (False);
34850bbfda8aSnia}
34860bbfda8aSnia
34870bbfda8aSnia
34880bbfda8aSnia/***********************************************************************
34890bbfda8aSnia *
34900bbfda8aSnia *  Procedure:
34910bbfda8aSnia *      HandleLeaveNotify - LeaveNotify event handler
34920bbfda8aSnia *
34930bbfda8aSnia ***********************************************************************
34940bbfda8aSnia */
34950bbfda8aSnia
34960bbfda8aSniavoid HandleLeaveNotify(void)
34970bbfda8aSnia{
34980bbfda8aSnia	bool inicon;
34990bbfda8aSnia
35000bbfda8aSnia	if(ActiveMenu && ActiveMenu->pinned
35010bbfda8aSnia	                && (Event.xcrossing.window == ActiveMenu->w)) {
35020bbfda8aSnia		PopDownMenu();
35030bbfda8aSnia	}
35040bbfda8aSnia
35050bbfda8aSnia	if(Tmp_win == NULL) {
35060bbfda8aSnia		/* No window to be Leave'ing, so nothing much to do... */
35070bbfda8aSnia		return;
35080bbfda8aSnia	}
35090bbfda8aSnia
35100bbfda8aSnia	/*
35110bbfda8aSnia	 * We're not interested in pseudo Enter/Leave events generated
35120bbfda8aSnia	 * from grab initiations and terminations.
35130bbfda8aSnia	 */
35140bbfda8aSnia	if(Event.xcrossing.mode != NotifyNormal) {
35150bbfda8aSnia		return;
35160bbfda8aSnia	}
35170bbfda8aSnia
35180bbfda8aSnia	if(Scr->ShrinkIconTitles &&
35190bbfda8aSnia	                Tmp_win->icon &&
35200bbfda8aSnia	                Event.xcrossing.window == Tmp_win->icon->w &&
35210bbfda8aSnia	                Event.xcrossing.detail != NotifyInferior) {
35220bbfda8aSnia		ShrinkIconTitle(Tmp_win);
35230bbfda8aSnia		return;
35240bbfda8aSnia	}
35250bbfda8aSnia
35260bbfda8aSnia	// Are we Leave'ing the icon manager entry for the Tmp_win in
35270bbfda8aSnia	// question, or some other part of the window itself?
35280bbfda8aSnia	inicon = (Tmp_win->iconmanagerlist &&
35290bbfda8aSnia	          Tmp_win->iconmanagerlist->w == Event.xcrossing.window);
35300bbfda8aSnia
35310bbfda8aSnia	if(Scr->RingLeader && Scr->RingLeader == Tmp_win &&
35320bbfda8aSnia	                (Event.xcrossing.detail != NotifyInferior &&
35330bbfda8aSnia	                 Event.xcrossing.window != Tmp_win->w)) {
35340bbfda8aSnia#ifdef DEBUG
35350bbfda8aSnia		fprintf(stderr,
35360bbfda8aSnia		        "HandleLeaveNotify: Event.xcrossing.window %x != Tmp_win->w %x\n",
35370bbfda8aSnia		        Event.xcrossing.window, Tmp_win->w);
35380bbfda8aSnia#endif
35390bbfda8aSnia		if(!inicon) {
35400bbfda8aSnia			if(Event.xcrossing.window != Tmp_win->frame /*was: Tmp_win->mapped*/) {
35410bbfda8aSnia				Tmp_win->ring.cursor_valid = false;
35420bbfda8aSnia#ifdef DEBUG
35430bbfda8aSnia				fprintf(stderr, "HandleLeaveNotify: cursor_valid = false\n");
35440bbfda8aSnia#endif
35450bbfda8aSnia			}
35460bbfda8aSnia			else {          /* Event.xcrossing.window == Tmp_win->frame */
35470bbfda8aSnia				Tmp_win->ring.cursor_valid = true;
35480bbfda8aSnia				Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
35490bbfda8aSnia				                        Tmp_win->frame_x);
35500bbfda8aSnia				Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
35510bbfda8aSnia				                        Tmp_win->frame_y);
35520bbfda8aSnia#ifdef DEBUG
35530bbfda8aSnia				fprintf(stderr,
35540bbfda8aSnia				        "HandleLeaveNotify: cursor_valid = true; x = %d (%d-%d), y = %d (%d-%d)\n",
35550bbfda8aSnia				        Tmp_win->ring.curs_x, Event.xcrossing.x_root, Tmp_win->frame_x,
35560bbfda8aSnia				        Tmp_win->ring.curs_y, Event.xcrossing.y_root, Tmp_win->frame_y);
35570bbfda8aSnia#endif
35580bbfda8aSnia			}
35590bbfda8aSnia		}
35600bbfda8aSnia		Scr->RingLeader = NULL;
35610bbfda8aSnia	}
35620bbfda8aSnia
35630bbfda8aSnia
35640bbfda8aSnia	/*
35650bbfda8aSnia	 * Are we moving focus based on the leave?  There are 2 steps to
35660bbfda8aSnia	 * this:
35670bbfda8aSnia	 * - Scr->FocusRoot is our "are we automatically changing focus
35680bbfda8aSnia	 *   based on the leave" flag.  This gets unset when ClickToFocus
35690bbfda8aSnia	 *   is config'd or a window is f.focus'd.
35700bbfda8aSnia	 * - Then we check the detail for the focus leaving.  We're only
35710bbfda8aSnia	 *   getting here for normal entry/exits.  Most cases outside of
35720bbfda8aSnia	 *   the icon manager peek ahead in the event queue for any
35730bbfda8aSnia	 *   Enter's, and don't do anything if there are; if there were,
35740bbfda8aSnia	 *   we'd be moving the focus when we get them, so no point doing
35750bbfda8aSnia	 *   it twice.  So the remainder here assumes there aren't any
35760bbfda8aSnia	 *   Enters waiting.
35770bbfda8aSnia	 *
35780bbfda8aSnia	 *   See
35790bbfda8aSnia	 *   <https://www.x.org/releases/X11R7.7/doc/libX11/libX11/libX11.html#Normal_EntryExit_Events>
35800bbfda8aSnia	 *   for details of the cases.  So, when do we want to un-set the
35810bbfda8aSnia	 *   focus?  Let's look at each doc'd value...
35820bbfda8aSnia	 *   - NotifyAncestor means we're leaving a subwindow for its
35830bbfda8aSnia	 *     parent.  That means the root, so, yep, we want to yield
35840bbfda8aSnia	 *     focus up to it.
35850bbfda8aSnia	 *   - NotifyNonLinear means we're leaving a window for something
35860bbfda8aSnia	 *     that isn't a parent or child.  So we should probably yield
35870bbfda8aSnia	 *     focus in this case too.
35880bbfda8aSnia	 *   - NotifyInferior means we're leaving a window for a
35890bbfda8aSnia	 *     subwindow of it.  From the WM perspective, that means
35900bbfda8aSnia	 *     we're leaving focus where it was.
35910bbfda8aSnia	 *   - NotifyVirtual means we're in the middle of an ascending
35920bbfda8aSnia	 *     sequence.  Nothing to do; the Ancestor handling already
35930bbfda8aSnia	 *     did the job.
35940bbfda8aSnia	 *   - NotifyNonLinearVirtual is another "in the middle" case, so
35950bbfda8aSnia	 *     we skip handling there too; the endpoints will do
35960bbfda8aSnia	 *     whatever's necessary.
35970bbfda8aSnia	 */
35980bbfda8aSnia	if(Scr->FocusRoot
35990bbfda8aSnia	                && Event.xcrossing.detail != NotifyInferior
36000bbfda8aSnia	                && Event.xcrossing.detail != NotifyVirtual
36010bbfda8aSnia	                && Event.xcrossing.detail != NotifyNonlinearVirtual
36020bbfda8aSnia	  ) {
36030bbfda8aSnia		HLNScanArgs scanArgs;
36040bbfda8aSnia		XEvent dummy;
36050bbfda8aSnia
36060bbfda8aSnia		/*
36070bbfda8aSnia		 * Scan for EnterNotify events to see if we can avoid some
36080bbfda8aSnia		 * unnecessary processing.
36090bbfda8aSnia		 */
36100bbfda8aSnia		scanArgs.w = Event.xcrossing.window;
36110bbfda8aSnia		scanArgs.enters = scanArgs.matches = False;
36120bbfda8aSnia		XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
36130bbfda8aSnia		              (char *) &scanArgs);
36140bbfda8aSnia
36150bbfda8aSnia		if((inicon && Scr->IconManagerFocus)
36160bbfda8aSnia		                || (Event.xcrossing.window == Tmp_win->frame
36170bbfda8aSnia		                    && !scanArgs.matches)
36180bbfda8aSnia		  ) {
36190bbfda8aSnia			// Defocusing window because we moved out of its entry in an
36200bbfda8aSnia			// icon manager, or because we moved out of its frame.
36210bbfda8aSnia
36220bbfda8aSnia			// Nothing to do if we were in the icon manager, and the
36230bbfda8aSnia			// window's either unmapped or doesn't accept input.  XXX Is
36240bbfda8aSnia			// the inicon flag needed here?  If it's not mapped, we
36250bbfda8aSnia			// presumably couldn't have gotten a Leave on its frame
36260bbfda8aSnia			// anyway, and if it's not accepting input, we probably don't
36270bbfda8aSnia			// need to focus out anyway?  Left conditional because this
36280bbfda8aSnia			// matches historical behavior prior to some rework here, but
36290bbfda8aSnia			// revisit.
36300bbfda8aSnia			if(inicon && (!Tmp_win->mapped || !Tmp_win->wmhints->input)) {
36310bbfda8aSnia				return;
36320bbfda8aSnia			}
36330bbfda8aSnia
36340bbfda8aSnia			// Shift away focus
36350bbfda8aSnia			if(Scr->TitleFocus || Tmp_win->protocols & DoesWmTakeFocus) {
36360bbfda8aSnia				SetFocus(NULL, Event.xcrossing.time);
36370bbfda8aSnia			}
36380bbfda8aSnia
36390bbfda8aSnia			// If we're in the icon manager, we need to take a FocusOut
36400bbfda8aSnia			// event for the window, since it wouldn't have gotten one.
36410bbfda8aSnia			// If we're in the frame, we fake one anyway as historical
36420bbfda8aSnia			// code says "pretend there was a focus out as sometimes we
36430bbfda8aSnia			// don't get one".
36440bbfda8aSnia			if(Event.xcrossing.focus) {
36450bbfda8aSnia				SynthesiseFocusOut(Tmp_win->w);
36460bbfda8aSnia			}
36470bbfda8aSnia		}
36480bbfda8aSnia		else if(Event.xcrossing.window == Tmp_win->w && !scanArgs.enters) {
36490bbfda8aSnia			// Flipping colormaps around because we moved out of the
36500bbfda8aSnia			// window.
36510bbfda8aSnia			InstallColormaps(LeaveNotify, &Scr->RootColormaps);
36520bbfda8aSnia		}
36530bbfda8aSnia	}
36540bbfda8aSnia
36550bbfda8aSnia	/* Autolower modification. */
36560bbfda8aSnia	if(Tmp_win->auto_lower) {
36570bbfda8aSnia		leave_win = Tmp_win;
36580bbfda8aSnia		if(leave_flag == false) {
36590bbfda8aSnia			AutoLowerWindow(Tmp_win);
36600bbfda8aSnia		}
36610bbfda8aSnia	}
36620bbfda8aSnia	else if(leave_flag && lower_win == Tmp_win) {
36630bbfda8aSnia		leave_win = Tmp_win;
36640bbfda8aSnia	}
36650bbfda8aSnia
36660bbfda8aSnia	XSync(dpy, 0);
36670bbfda8aSnia	return;
36680bbfda8aSnia}
36690bbfda8aSnia
36700bbfda8aSnia
36710bbfda8aSnia/***********************************************************************
36720bbfda8aSnia *
36730bbfda8aSnia *  Procedure:
36740bbfda8aSnia *      HandleConfigureRequest - ConfigureRequest event handler
36750bbfda8aSnia *
36760bbfda8aSnia ***********************************************************************
36770bbfda8aSnia */
36780bbfda8aSnia
36790bbfda8aSniavoid HandleConfigureRequest(void)
36800bbfda8aSnia{
36810bbfda8aSnia	XWindowChanges xwc;
36820bbfda8aSnia	unsigned long xwcm;
36830bbfda8aSnia	int x, y, width, height, bw;
36840bbfda8aSnia	int gravx, gravy;
36850bbfda8aSnia	XConfigureRequestEvent *cre = &Event.xconfigurerequest;
36860bbfda8aSnia	bool sendEvent;
36870bbfda8aSnia
36880bbfda8aSnia#ifdef DEBUG_EVENTS
36890bbfda8aSnia	fprintf(stderr, "ConfigureRequest\n");
36900bbfda8aSnia	if(cre->value_mask & CWX) {
36910bbfda8aSnia		fprintf(stderr, "  x = %d\n", cre->x);
36920bbfda8aSnia	}
36930bbfda8aSnia	if(cre->value_mask & CWY) {
36940bbfda8aSnia		fprintf(stderr, "  y = %d\n", cre->y);
36950bbfda8aSnia	}
36960bbfda8aSnia	if(cre->value_mask & CWWidth) {
36970bbfda8aSnia		fprintf(stderr, "  width = %d\n", cre->width);
36980bbfda8aSnia	}
36990bbfda8aSnia	if(cre->value_mask & CWHeight) {
37000bbfda8aSnia		fprintf(stderr, "  height = %d\n", cre->height);
37010bbfda8aSnia	}
37020bbfda8aSnia	if(cre->value_mask & CWSibling) {
37030bbfda8aSnia		fprintf(stderr, "  above = 0x%x\n", (unsigned)cre->above);
37040bbfda8aSnia	}
37050bbfda8aSnia	if(cre->value_mask & CWStackMode) {
37060bbfda8aSnia		fprintf(stderr, "  stack = %d\n", cre->detail);
37070bbfda8aSnia	}
37080bbfda8aSnia#endif
37090bbfda8aSnia
37100bbfda8aSnia	/*
37110bbfda8aSnia	 * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
37120bbfda8aSnia	 * be wrong
37130bbfda8aSnia	 */
37140bbfda8aSnia	Event.xany.window = cre->window;    /* mash parent field */
37150bbfda8aSnia	Tmp_win = GetTwmWindow(cre->window);
37160bbfda8aSnia
37170bbfda8aSnia	/*
37180bbfda8aSnia	 * According to the July 27, 1988 ICCCM draft, we should ignore size and
37190bbfda8aSnia	 * position fields in the WM_NORMAL_HINTS property when we map a window.
37200bbfda8aSnia	 * Instead, we'll read the current geometry.  Therefore, we should respond
37210bbfda8aSnia	 * to configuration requests for windows which have never been mapped.
37220bbfda8aSnia	 */
37230bbfda8aSnia	if(!Tmp_win || (Tmp_win->icon && (Tmp_win->icon->w == cre->window))) {
37240bbfda8aSnia		xwcm = cre->value_mask &
37250bbfda8aSnia		       (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
37260bbfda8aSnia		xwc.x = cre->x;
37270bbfda8aSnia		xwc.y = cre->y;
37280bbfda8aSnia		xwc.width = cre->width;
37290bbfda8aSnia		xwc.height = cre->height;
37300bbfda8aSnia		xwc.border_width = cre->border_width;
37310bbfda8aSnia		XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
37320bbfda8aSnia		return;
37330bbfda8aSnia	}
37340bbfda8aSnia
37350bbfda8aSnia	sendEvent = false;
37360bbfda8aSnia	if((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
37370bbfda8aSnia		TwmWindow *otherwin;
37380bbfda8aSnia
37390bbfda8aSnia		if(cre->value_mask & CWSibling) {
37400bbfda8aSnia			otherwin = GetTwmWindow(cre->above);
37410bbfda8aSnia			if(otherwin) {
37420bbfda8aSnia				OtpForcePlacement(Tmp_win, cre->detail, otherwin);
37430bbfda8aSnia			}
37440bbfda8aSnia			else {
37450bbfda8aSnia				fprintf(stderr, "XConfigureRequest: unkown otherwin\n");
37460bbfda8aSnia			}
37470bbfda8aSnia		}
37480bbfda8aSnia		else {
37490bbfda8aSnia			switch(cre->detail) {
37500bbfda8aSnia				case TopIf:
37510bbfda8aSnia				case Above:
37520bbfda8aSnia					OtpRaise(Tmp_win, WinWin);
37530bbfda8aSnia					break;
37540bbfda8aSnia				case BottomIf:
37550bbfda8aSnia				case Below:
37560bbfda8aSnia					OtpLower(Tmp_win, WinWin);
37570bbfda8aSnia					break;
37580bbfda8aSnia				case Opposite:
37590bbfda8aSnia					OtpRaiseLower(Tmp_win, WinWin);
37600bbfda8aSnia					break;
37610bbfda8aSnia				default:
37620bbfda8aSnia					;
37630bbfda8aSnia			}
37640bbfda8aSnia		}
37650bbfda8aSnia		sendEvent = true;
37660bbfda8aSnia	}
37670bbfda8aSnia
37680bbfda8aSnia
37690bbfda8aSnia	/* Don't modify frame_XXX fields before calling SetupWindow! */
37700bbfda8aSnia	x = Tmp_win->frame_x;
37710bbfda8aSnia	y = Tmp_win->frame_y;
37720bbfda8aSnia	width = Tmp_win->frame_width;
37730bbfda8aSnia	height = Tmp_win->frame_height;
37740bbfda8aSnia	bw = Tmp_win->frame_bw;
37750bbfda8aSnia
37760bbfda8aSnia	/*
37770bbfda8aSnia	 * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
37780bbfda8aSnia	 * configure request are for the upper-left outer corner of the window.
37790bbfda8aSnia	 * This means that we need to adjust for the additional title height as
37800bbfda8aSnia	 * well as for any border width changes that we decide to allow.  The
37810bbfda8aSnia	 * current window gravity is to be used in computing the adjustments, just
37820bbfda8aSnia	 * as when initially locating the window.  Note that if we do decide to
37830bbfda8aSnia	 * allow border width changes, we will need to send the synthetic
37840bbfda8aSnia	 * ConfigureNotify event.
37850bbfda8aSnia	 */
37860bbfda8aSnia	GetGravityOffsets(Tmp_win, &gravx, &gravy);
37870bbfda8aSnia
37880bbfda8aSnia	if(cre->value_mask & CWBorderWidth) {
37890bbfda8aSnia		int bwdelta = cre->border_width - Tmp_win->old_bw;  /* posit growth */
37900bbfda8aSnia		if(bwdelta && Scr->ClientBorderWidth) {   /* if change allowed */
37910bbfda8aSnia			x += gravx * bwdelta;       /* change default values only */
37920bbfda8aSnia			y += gravy * bwdelta;       /* ditto */
37930bbfda8aSnia			bw = cre->border_width;
37940bbfda8aSnia			if(Tmp_win->title_height) {
37950bbfda8aSnia				height += bwdelta;
37960bbfda8aSnia			}
37970bbfda8aSnia			x += (gravx < 0) ? bwdelta : -bwdelta;
37980bbfda8aSnia			y += (gravy < 0) ? bwdelta : -bwdelta;
37990bbfda8aSnia		}
38000bbfda8aSnia		Tmp_win->old_bw = cre->border_width;  /* for restoring */
38010bbfda8aSnia	}
38020bbfda8aSnia
38030bbfda8aSnia	if((cre->value_mask & CWX)) {       /* override even if border change */
38040bbfda8aSnia		x = cre->x - bw;
38050bbfda8aSnia		x -= ((gravx < 0) ? 0 : Tmp_win->frame_bw3D);
38060bbfda8aSnia	}
38070bbfda8aSnia	if((cre->value_mask & CWY)) {
38080bbfda8aSnia		y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
38090bbfda8aSnia		y -= ((gravy < 0) ? 0 : Tmp_win->frame_bw3D);
38100bbfda8aSnia	}
38110bbfda8aSnia
38120bbfda8aSnia	if(cre->value_mask & CWWidth) {
38130bbfda8aSnia		width = cre->width + 2 * Tmp_win->frame_bw3D;
38140bbfda8aSnia	}
38150bbfda8aSnia	if(cre->value_mask & CWHeight) {
38160bbfda8aSnia		height = cre->height + Tmp_win->title_height + 2 * Tmp_win->frame_bw3D;
38170bbfda8aSnia	}
38180bbfda8aSnia
38190bbfda8aSnia	if(width != Tmp_win->frame_width || height != Tmp_win->frame_height) {
38200bbfda8aSnia		unzoom(Tmp_win);
38210bbfda8aSnia	}
38220bbfda8aSnia
38230bbfda8aSnia	/* Workaround for Java 1.4 bug that freezes the application whenever
38240bbfda8aSnia	 * a new window is displayed. (When UsePPosition is on and either
38250bbfda8aSnia	 * UseThreeDBorders or BorderWidth 0 is set.)
38260bbfda8aSnia	 */
38270bbfda8aSnia	if(!bw) {
38280bbfda8aSnia		sendEvent = true;
38290bbfda8aSnia	}
38300bbfda8aSnia
38310bbfda8aSnia	/*
38320bbfda8aSnia	 * SetupWindow (x,y) are the location of the upper-left outer corner and
38330bbfda8aSnia	 * are passed directly to XMoveResizeWindow (frame).  The (width,height)
38340bbfda8aSnia	 * are the inner size of the frame.  The inner width is the same as the
38350bbfda8aSnia	 * requested client window width; the inner height is the same as the
38360bbfda8aSnia	 * requested client window height plus any title bar slop.
38370bbfda8aSnia	 */
38380bbfda8aSnia#ifdef DEBUG_EVENTS
38390bbfda8aSnia	fprintf(stderr, "SetupFrame(x=%d, y=%d, width=%d, height=%d, bw=%d)\n",
38400bbfda8aSnia	        x, y, width, height, bw);
38410bbfda8aSnia#endif
38420bbfda8aSnia	SetupFrame(Tmp_win, x, y, width, height, bw, sendEvent);
38430bbfda8aSnia}
38440bbfda8aSnia
38450bbfda8aSnia
38460bbfda8aSnia/***********************************************************************
38470bbfda8aSnia *
38480bbfda8aSnia *  Procedure:
38490bbfda8aSnia *      HandleShapeNotify - shape notification event handler
38500bbfda8aSnia *
38510bbfda8aSnia ***********************************************************************
38520bbfda8aSnia */
38530bbfda8aSniavoid
38540bbfda8aSniaHandleShapeNotify(void)
38550bbfda8aSnia{
38560bbfda8aSnia	XShapeEvent     *sev = (XShapeEvent *) &Event;
38570bbfda8aSnia
38580bbfda8aSnia	if(Tmp_win == NULL) {
38590bbfda8aSnia		return;
38600bbfda8aSnia	}
38610bbfda8aSnia	if(sev->kind != ShapeBounding) {
38620bbfda8aSnia		return;
38630bbfda8aSnia	}
38640bbfda8aSnia	if(!Tmp_win->wShaped && sev->shaped) {
38650bbfda8aSnia		XShapeCombineMask(dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
38660bbfda8aSnia		                  ShapeSet);
38670bbfda8aSnia	}
38680bbfda8aSnia	Tmp_win->wShaped = sev->shaped;
38690bbfda8aSnia	SetFrameShape(Tmp_win);
38700bbfda8aSnia}
38710bbfda8aSnia
38720bbfda8aSnia/***********************************************************************
38730bbfda8aSnia *
38740bbfda8aSnia *  Procedure:
38750bbfda8aSnia *      HandleSelectionClear - selection lost event handler
38760bbfda8aSnia *
38770bbfda8aSnia ***********************************************************************
38780bbfda8aSnia */
38790bbfda8aSnia#ifdef EWMH
38800bbfda8aSniavoid
38810bbfda8aSniaHandleSelectionClear(void)
38820bbfda8aSnia{
38830bbfda8aSnia	XSelectionClearEvent    *sev = (XSelectionClearEvent *) &Event;
38840bbfda8aSnia
38850bbfda8aSnia	if(sev->window == Scr->icccm_Window) {
38860bbfda8aSnia		EwmhSelectionClear(sev);
38870bbfda8aSnia	}
38880bbfda8aSnia}
38890bbfda8aSnia#endif
38900bbfda8aSnia
38910bbfda8aSnia
38920bbfda8aSnia/***********************************************************************
38930bbfda8aSnia *
38940bbfda8aSnia *  Procedure:
38950bbfda8aSnia *      HandleUnknown - unknown event handler
38960bbfda8aSnia *
38970bbfda8aSnia ***********************************************************************
38980bbfda8aSnia */
38990bbfda8aSnia
39000bbfda8aSniavoid HandleUnknown(void)
39010bbfda8aSnia{
39020bbfda8aSnia#ifdef DEBUG_EVENTS
39030bbfda8aSnia	fprintf(stderr, "HandleUnknown: Event.type = %d\n", Event.type);
39040bbfda8aSnia#endif
39050bbfda8aSnia}
39060bbfda8aSnia
39070bbfda8aSnia
39080bbfda8aSniastatic void flush_expose(Window w)
39090bbfda8aSnia{
39100bbfda8aSnia	XEvent dummy;
39110bbfda8aSnia
39120bbfda8aSnia	while(XCheckTypedWindowEvent(dpy, w, Expose, &dummy)) {
39130bbfda8aSnia		/* nada */;
39140bbfda8aSnia	}
39150bbfda8aSnia}
39160bbfda8aSnia
39170bbfda8aSnia
39180bbfda8aSnia/* Util func used a few times above */
39190bbfda8aSniastatic void
39200bbfda8aSniaSendTakeFocusMessage(TwmWindow *tmp, Time timestamp)
39210bbfda8aSnia{
39220bbfda8aSnia	send_clientmessage(tmp->w, XA_WM_TAKE_FOCUS, timestamp);
39230bbfda8aSnia}
3924