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 = ¤t; 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