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