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