CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/event_handlers.c
Go to the documentation of this file.
1/*
2 * Copyright 1988 by Evans & Sutherland Computer Corporation,
3 * Salt Lake City, Utah
4 * Portions Copyright 1989 by the Massachusetts Institute of Technology
5 * Cambridge, Massachusetts
6 *
7 * Copyright 1992 Claude Lecommandeur.
8 */
9
10/***********************************************************************
11 *
12 * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $
13 *
14 * twm event handling
15 *
16 * 17-Nov-87 Thomas E. LaStrange File created
17 *
18 * Do the necessary modification to be integrated in ctwm.
19 * Can no longer be used for the standard twm.
20 *
21 * 22-April-92 Claude Lecommandeur.
22 *
23 *
24 ***********************************************************************/
25
26#include "ctwm.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <sys/time.h>
31
32#include <X11/Xatom.h>
33#include <X11/extensions/shape.h>
34
35#include "add_window.h"
36#include "animate.h"
37#include "clicktofocus.h"
38#include "colormaps.h"
39#include "ctwm_atoms.h"
40#include "ctwm_shutdown.h"
41#include "events.h"
42#include "event_handlers.h"
43#include "event_internal.h"
44#include "event_names.h"
45#include "functions.h"
46#include "functions_defs.h"
47#include "gram.tab.h"
48#include "iconmgr.h"
49#include "icons.h"
50#include "image.h"
51#include "list.h"
52#include "occupation.h"
53#include "otp.h"
54#include "parse.h"
55#include "screen.h"
56#include "util.h"
57#include "vscreen.h"
58#include "win_decorations.h"
59#include "win_iconify.h"
60#include "win_ops.h"
61#include "win_regions.h"
62#include "win_resize.h"
63#include "win_ring.h"
64#include "win_utils.h"
65#include "workspace_manager.h"
66#include "workspace_utils.h"
67
68
69static void do_key_menu(MenuRoot *menu, /* menu to pop up */
70 Window w); /* invoking window or None */
71
72/* Only called from HandleFocusChange() */
73static void HandleFocusIn(void);
74static void HandleFocusOut(void);
75
76/*
77 * This currently needs to live in the broader scope because of how it's
78 * used in deferred function handling.
79 */
80static char *Action;
81
82static TwmWindow *ButtonWindow; /* button press window structure */
83
85
86
87static unsigned int set_mask_ignore(unsigned int modifier)
88{
89 modifier &= ~Scr->IgnoreModifier;
90
91 return modifier;
92}
93
94
95/***********************************************************************
96 *
97 * Procedure:
98 * HandleColormapNotify - colormap notify event handler
99 *
100 * This procedure handles both a client changing its own colormap, and
101 * a client explicitly installing its colormap itself (only the window
102 * manager should do that, so we must set it correctly).
103 *
104 ***********************************************************************
105 */
106
108{
110 ColormapWindow *cwin, **cwins;
112 int lost, won, n, number_cwins;
113
114 /* if (! Tmp_win) return; */
116 (XPointer *)&cwin) == XCNOENT) {
117 return;
118 }
119 cmap = cwin->colormap;
120
121 if(cevent->new) {
122 if(XFindContext(dpy, cevent->colormap, ColormapContext,
123 (XPointer *)&cwin->colormap) == XCNOENT) {
124 cwin->colormap = CreateTwmColormap(cevent->colormap);
125 }
126 else {
127 cwin->colormap->refcnt++;
128 }
129
130 cmap->refcnt--;
131
132 if(cevent->state == ColormapUninstalled) {
133 cmap->state &= ~CM_INSTALLED;
134 }
135 else {
136 cmap->state |= CM_INSTALLED;
137 }
138
139 if(cmap->state & CM_INSTALLABLE) {
141 }
142
143 if(cmap->refcnt == 0) {
145 free(cmap);
146 }
147
148 return;
149 }
150
151 if(cevent->state == ColormapUninstalled &&
152 (cmap->state & CM_INSTALLABLE)) {
153 if(!(cmap->state & CM_INSTALLED)) {
154 return;
155 }
156 cmap->state &= ~CM_INSTALLED;
157
159 ColortableThrashing = true;
160 XSync(dpy, 0);
161 }
162
163 if(cevent->serial >= Scr->cmapInfo.first_req) {
164 number_cwins = Scr->cmapInfo.cmaps->number_cwins;
165
166 /*
167 * Find out which colortables collided.
168 */
169
170 cwins = Scr->cmapInfo.cmaps->cwins;
171 for(lost = won = -1, n = 0;
172 (lost == -1 || won == -1) && n < number_cwins;
173 n++) {
174 if(lost == -1 && cwins[n] == cwin) {
175 lost = n; /* This is the window which lost its colormap */
176 continue;
177 }
178
179 if(won == -1 &&
180 cwins[n]->colormap->install_req == cevent->serial) {
181 won = n; /* This is the window whose colormap caused */
182 continue; /* the de-install of the previous colormap */
183 }
184 }
185
186 /*
187 ** Cases are:
188 ** Both the request and the window were found:
189 ** One of the installs made honoring the WM_COLORMAP
190 ** property caused another of the colormaps to be
191 ** de-installed, just mark the scoreboard.
192 **
193 ** Only the request was found:
194 ** One of the installs made honoring the WM_COLORMAP
195 ** property caused a window not in the WM_COLORMAP
196 ** list to lose its map. This happens when the map
197 ** it is losing is one which is trying to be installed,
198 ** but is getting getting de-installed by another map
199 ** in this case, we'll get a scoreable event later,
200 ** this one is meaningless.
201 **
202 ** Neither the request nor the window was found:
203 ** Somebody called installcolormap, but it doesn't
204 ** affect the WM_COLORMAP windows. This case will
205 ** probably never occur.
206 **
207 ** Only the window was found:
208 ** One of the WM_COLORMAP windows lost its colormap
209 ** but it wasn't one of the requests known. This is
210 ** probably because someone did an "InstallColormap".
211 ** The colormap policy is "enforced" by re-installing
212 ** the colormaps which are believed to be correct.
213 */
214
215 if(won != -1) {
216 if(lost != -1) {
217 /* lower diagonal index calculation */
218 if(lost > won) {
219 n = lost * (lost - 1) / 2 + won;
220 }
221 else {
222 n = won * (won - 1) / 2 + lost;
223 }
224 Scr->cmapInfo.cmaps->scoreboard[n] = 1;
225 }
226 else {
227 /*
228 ** One of the cwin installs caused one of the cwin
229 ** colormaps to be de-installed, so I'm sure to get an
230 ** UninstallNotify for the cwin I know about later.
231 ** I haven't got it yet, or the test of CM_INSTALLED
232 ** above would have failed. Turning the CM_INSTALLED
233 ** bit back on makes sure we get back here to score
234 ** the collision.
235 */
236 cmap->state |= CM_INSTALLED;
237 }
238 }
239 else if(lost != -1) {
241 }
242 else {
243 ColortableThrashing = false; /* Gross Hack for HP WABI. CL. */
244 }
245 }
246 }
247
248 else if(cevent->state == ColormapUninstalled) {
249 cmap->state &= ~CM_INSTALLED;
250 }
251
252 else if(cevent->state == ColormapInstalled) {
253 cmap->state |= CM_INSTALLED;
254 }
255}
256
257
258/*
259 * LastFocusEvent -- skip over focus in/out events for this
260 * window.
261 */
262
264{
265 static XEvent current;
266 XEvent *last, new;
267
268 new = *first;
269 last = NULL;
270
271 do {
272 if((new.type == FocusIn || new.type == FocusOut)
273 && new.xfocus.mode == NotifyNormal
274 && (new.xfocus.detail == NotifyNonlinear
275 || new.xfocus.detail == NotifyPointer
276 || new.xfocus.detail == NotifyAncestor
277 || (new.xfocus.detail == NotifyNonlinearVirtual)
278 )) {
279 current = new;
280 last = &current;
281 }
282
283#ifdef TRACE_FOCUS
284 fprintf(stderr, "%s(): Focus%s 0x%x mode=%d, detail=%d\n",
285 __func__, new.xfocus.type == FocusIn ? "In" : "Out",
286 Tmp_win, new.xfocus.mode, new.xfocus.detail);
287#endif
288
289 }
290 while(XCheckWindowEvent(dpy, w, FocusChangeMask, &new));
291 return last;
292}
293
294
295/*
296 * Focus change handlers.
297 *
298 * Depending on how events get called, these are sometimes redundant, as
299 * the Enter event handler does practically all of this anyway. But
300 * there are presumably ways we can wind up Focus'ing a window without
301 * Enter'ing it as well.
302 *
303 * It's also a little convoluted how these wind up getting called. With
304 * most events, we call a handler, then handle that event. However, with
305 * focus, we troll through our list of pending Focus-related events for
306 * the window and just handle the last one, since some could pile up
307 * fast. That means that, even if we get called for a FocusIn event,
308 * there might be a FocusOut later in the queue, and _that_'s the one we
309 * pick up and handle, and we discard the rest [for that window]. So,
310 * the event handling code calls a single entry point for both types, and
311 * then it figures out which backend handler to actually fire.
312 */
313void
315{
316 XEvent *event;
317
318 /* If there's no event window, nothing to do */
319 if(!Tmp_win) {
320 return;
321 }
322
323 /*
324 * Consume all the focus events for the window we're called about and
325 * grab the last one to process.
326 *
327 * XXX It should be guaranteed that the window in the X event in our
328 * global Event is the same as Tmp_win->w as the event dispatcher
329 * sets it so. Maybe we should do both checks on the same var for
330 * consistency though?
331 *
332 * It's not immediately clear how this can wind up returning nothing,
333 * but if it does, we don't have anything to do either.
334 */
335 event = LastFocusEvent(Event.xany.window, &Event);
336 if(event == NULL) {
337 return;
338 }
339
340 /*
341 * Icon managers don't do anything with focus events on themselves,
342 * so just skip back if this is one. Done after LastFocusEvent()
343 * call for efficiency, so we don't fall into this func multiple
344 * times if multiple events are queued for it.
345 */
346 if(Tmp_win->isiconmgr) {
347 return;
348 }
349
350#ifdef TRACE_FOCUS
351 fprintf(stderr, "HandleFocus%s(): 0x%x (0x%x, 0x%x), mode=%d, "
352 "detail=%d\n",
353 (event->type == FocusIn ? "In" : "Out"),
354 Tmp_win, Tmp_win->w, event->window, event->mode,
355 event->detail);
356#endif
357
358 /* And call actual handler */
359 if(event->type == FocusIn) {
361 }
362 else {
364 }
365}
366
367
368static void
370{
371 if(! Tmp_win->wmhints->input) {
372 return;
373 }
374 if(Scr->Focus == Tmp_win) {
375 return;
376 }
377
378#ifdef EWMH
379 // Handle focus-dependent re-stacking of what we're moving out of.
380 if(Scr->Focus && OtpIsFocusDependent(Scr->Focus)) {
381 OtpUnfocusWindow(Scr->Focus);
382 // NULL's Scr->Focus
383 }
384#endif
385
388 }
390
391#ifdef EWMH
392 // Handle focus-dependent re-stacking of what we're moving in to.
395 // Sets Scr->Focus
396 }
397#endif
398
399 // Redundant in EWMH case
400 Scr->Focus = Tmp_win;
401}
402
403
404static void
406{
407 if(Scr->Focus != Tmp_win) {
408 return;
409 }
410 if(Scr->SloppyFocus) {
411 return;
412 }
415 }
417
418#ifdef EWMH
419 /*
420 * X-ref HandleFocusIn() comment. FocusOut is only leaving a window,
421 * not entering a new one, so there's only one we may need to
422 * restack.
423 */
424 if(Scr->Focus && OtpIsFocusDependent(Scr->Focus)) {
425 OtpUnfocusWindow(Scr->Focus);
426 // NULL's Scr->Focus
427 }
428#endif
429
430 // Redundant in EWMH case
431 Scr->Focus = NULL;
432}
433
434
435
436/*
437 * Only sent if SubstructureNotifyMask is selected on the (root) window.
438 */
440{
441 VirtualScreen *vs;
442#ifdef DEBUG_EVENTS
443 fprintf(stderr, "HandleCirculateNotify\n");
444 fprintf(stderr, "event=%x window=%x place=%d\n",
445 (unsigned)Event.xcirculate.event,
446 (unsigned)Event.xcirculate.window,
447 Event.xcirculate.place);
448#endif
449
450 for(vs = Scr->vScreenList; vs; vs = vs->next) {
451 if(Event.xcirculate.event == vs->window) {
452 TwmWindow *twm_win = GetTwmWindow(Event.xcirculate.window);
453
454 if(twm_win) {
455 WinType wt;
456
457 if(Event.xcirculate.window == twm_win->frame) {
458 wt = WinWin;
459 }
460 else if(twm_win->icon &&
461 Event.xcirculate.window == twm_win->icon->w) {
462 wt = IconWin;
463 }
464 else {
465 return;
466 }
467
469 twm_win, wt,
470 Event.xcirculate.place);
471 }
472 }
473 }
474}
475
476/***********************************************************************
477 *
478 * Procedure:
479 * HandleVisibilityNotify - visibility notify event handler
480 *
481 * This routine keeps track of visibility events so that colormap
482 * installation can keep the maximum number of useful colormaps
483 * installed at one time.
484 *
485 ***********************************************************************
486 */
487
489{
493
495 (XPointer *)&cwin) == XCNOENT) {
496 return;
497 }
498
499 /*
500 * when Saber complains about retreiving an <int> from an <unsigned int>
501 * just type "touch vevent->state" and "cont"
502 */
503 cmap = cwin->colormap;
504 if((cmap->state & CM_INSTALLABLE) &&
505 vevent->state != cwin->visibility &&
506 (vevent->state == VisibilityFullyObscured ||
507 cwin->visibility == VisibilityFullyObscured) &&
508 cmap->w == cwin->w) {
509 cwin->visibility = vevent->state;
511 }
512 else {
513 cwin->visibility = vevent->state;
514 }
515}
516
517
518/***********************************************************************
519 *
520 * Procedure:
521 * HandleKeyRelease - key release event handler
522 *
523 ***********************************************************************
524 */
525
527{
528 if(Tmp_win == Scr->currentvs->wsw->twm_win) {
529 WMgrHandleKeyReleaseEvent(Scr->currentvs, &Event);
530 }
531}
532
533
534
535/*
536 * HandleKeyPress - key press event handler
537 *
538 * When a key is pressed, we may do various things with it. If we're in
539 * a menu, various keybindings move around in it, others get silently
540 * ignored. Else, we look through the various bindings set in the config
541 * file and invoke whatever should be. If none of that matches, and it
542 * seems like some window should have focus, pass the event down to that
543 * window.
544 */
546{
547 /*
548 * If the Info window (f.identify/f.version) is currently up, any key
549 * press will drop it away.
550 */
551 if(Scr->InfoWindow.mapped) {
552 XUnmapWindow(dpy, Scr->InfoWindow.win);
553 Scr->InfoWindow.mapped = false;
554 }
555
556
557 /*
558 * If a menu is up, we interpret various keys as moving around or
559 * doing things in the menu. No other key bindings or usages are
560 * considered.
561 */
562 if(ActiveMenu != NULL) {
563 MenuItem *item;
564 char *keynam;
565 KeySym keysym;
567
568 item = NULL;
569
570 /* What key was pressed? */
571 keysym = XLookupKeysym((XKeyEvent *) &Event, 0);
572 if(! keysym) {
573 return;
574 }
575 keynam = XKeysymToString(keysym);
576 if(! keynam) {
577 return;
578 }
579
580
581 /*
582 * Initial handling of the various keystrokes. Most keys are
583 * completely handled here; we only descend out into later for
584 * for Return/Right keys that do invoke-y stuff on menu entries.
585 */
586 if(keysym == XK_Down || keysym == XK_space) {
587 /*
588 * Down or Spacebar moves us to the next entry in the menu,
589 * looping back around to the top when it falls off the
590 * bottom.
591 *
592 * Start with our X and (current+height)Y, then wrap around
593 * to the top (Y)/into the menu (X) as necessary.
594 */
595 int xx = Event.xkey.x;
596 int yy = Event.xkey.y + Scr->EntryHeight;
597 int wx, wy;
599 if((wy < 0) || (wy > ActiveMenu->height)) {
600 yy -= (wy - (Scr->EntryHeight / 2) - 2);
601 }
602 if((wx < 0) || (wx > ActiveMenu->width)) {
603 xx -= (wx - (ActiveMenu->width / 2));
604 }
605
606 /*
607 * Move the pointer there. We'll get a Motion notify from
608 * the X server as a result, which will fall into the loop in
609 * UpdateMenu() and handle re-highlighting etc.
610 */
611 XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
613 return;
614 }
615 else if(keysym == XK_Up || keysym == XK_BackSpace) {
616 /*
617 * Up/Backspace move up an entry, with details similar in
618 * reverse to the above.
619 */
620 int xx = Event.xkey.x;
621 int yy = Event.xkey.y - Scr->EntryHeight;
622 int wx, wy;
624 if((wy < 0) || (wy > ActiveMenu->height)) {
625 yy -= (wy - ActiveMenu->height + (Scr->EntryHeight / 2) + 2);
626 }
627 if((wx < 0) || (wx > ActiveMenu->width)) {
628 xx -= (wx - (ActiveMenu->width / 2));
629 }
630 XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
632 return;
633 }
634 else if(keysym == XK_Right || keysym == XK_Return) {
635 /*
636 * Right/Return mean we're invoking some entry item, so we
637 * take note of where we are for activating at the end of
638 * this set of conditionals.
639 *
640 * Follow this down into the following if(item) block for
641 * details, particularly in the subtle differences between
642 * Right and Return on f.menu entries.
643 */
644 item = ActiveItem;
645 }
646 else if(keysym == XK_Left || keysym == XK_Escape) {
647 /*
648 * Left/Escape back up to a higher menu level, or out totally
649 * from the top.
650 */
651 MenuRoot *menu;
652
653 /* Leave pinned menus alone though */
654 if(ActiveMenu->pinned) {
655 return;
656 }
657
658 /* Top-level? Clear out and leave menu mode totally. */
659 if(!ActiveMenu->prev || MenuDepth == 1) {
660 PopDownMenu();
662 return;
663 }
664
665 /*
666 * We're in a sub level. Figure out various stuff for where
667 * we are and where we should be in the up-level, clear out
668 * the windows for this level, and warp us up there.
669 */
670 int xx = Event.xkey.x;
671 int yy = Event.xkey.y;
672 int wx, wy;
673 menu = ActiveMenu->prev;
674 XTranslateCoordinates(dpy, Scr->Root, menu->w, xx, yy, &wx, &wy, &junkW);
675 xx -= (wx - (menu->width / 2));
676 if(menu->lastactive)
677 yy -= (wy - menu->lastactive->item_num * Scr->EntryHeight -
678 (Scr->EntryHeight / 2) - 2);
679 else {
680 yy -= (wy - (Scr->EntryHeight / 2) - 2);
681 }
683 if(Scr->Shadow) {
685 }
686 XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
687 menu->width, menu->height, xx, yy);
688 return;
689 }
690 else if(strlen(keynam) == 1) {
691 /*
692 * This would mean pressing a more normal (e.g., letter/num)
693 * key. These find the first entry starting with a matching
694 * character and jump to it.
695 */
697 int xx = Event.xkey.x;
698 int yy = Event.xkey.y;
699 int wx, wy;
700
702 item = startitem->next;
703 if(item == NULL) {
704 item = ActiveMenu->first;
705 }
706 unsigned int keymod = (Event.xkey.state & mods_used);
708
709 while(item != startitem) {
710 bool matched = false;
711 size_t offset = 0;
712 switch(item->item [0]) {
713 case '^' :
714 if((keymod & ControlMask) &&
715 (keynam [0] == Tolower(item->item [1]))) {
716 matched = true;
717 }
718 break;
719 case '~' :
720 if((keymod & Mod1Mask) &&
721 (keynam [0] == Tolower(item->item [1]))) {
722 matched = true;
723 }
724 break;
725 case ' ' :
726 offset = 1;
727 default :
728 if(((Scr->IgnoreCaseInMenuSelection) &&
729 (keynam [0] == Tolower(item->item [offset]))) ||
730
731 ((keymod & ShiftMask) && Isupper(item->item [offset]) &&
732 (keynam [0] == Tolower(item->item [offset]))) ||
733
734 (!(keymod & ShiftMask) && Islower(item->item [offset]) &&
735 (keynam [0] == item->item [offset]))) {
736 matched = true;
737 }
738 break;
739 }
740 if(matched) {
741 break;
742 }
743 item = item->next;
744 if(item == NULL) {
745 item = ActiveMenu->first;
746 }
747 }
748 if(item == startitem) {
749 return;
750 }
751 wx = ActiveMenu->width / 2;
752 wy = (item->item_num * Scr->EntryHeight) + (Scr->EntryHeight / 2) + 2;
754 XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
756 return;
757 }
758 else {
759 /* Other keys get ignored */
760 return;
761 }
762
763
764 /*
765 * So if we get here, the key pressed was a Right/Return on an
766 * entry to select it (chosen entry now in item). Every other
767 * case is have been completely handled in the block above and
768 * would have already returned.
769 *
770 * So item should always be the entry we just tried to invoke.
771 * I'm not sure how it could be empty, but if it is, we just hop
772 * ourselves out of the menu. Otherwise, we do whatever we want
773 * to do with the entry type we're on.
774 */
775 if(item) {
776 switch(item->func) {
777 /* f.nop and f.title, we just silently let pass */
778 case 0 :
779 case F_TITLE :
780 break;
781
782 /* If it's a f.menu, there's more magic to do */
783 case F_MENU: {
784 /*
785 * Return is treated separately from Right. It
786 * "invokes" the menu item, which immediately calls
787 * whatever the default menu entry is (which may be
788 * nothing).
789 */
790 if(!strcmp(keynam, "Return")) {
791 if(ActiveMenu == Scr->Workspaces) {
792 /*
793 * f.menu "TwmWorkspaces". The "invocation"
794 * of this jumps to the workspace in
795 * question, as if it were a default entry of
796 * f.gotoworkspace.
797 *
798 * XXX Grody magic. Maybe this should be
799 * unwound to a default entry...
800 */
801 PopDownMenu();
803 GotoWorkSpaceByName(Scr->currentvs, item->action + 8);
804 }
805 else {
806 /*
807 * Calling the f.menu handler invokes the
808 * default action. We handle popping out of
809 * menus ourselves.
810 */
811 ExecuteFunction(item->func, item->action,
813 ButtonWindow, &Event, Context, false);
814 PopDownMenu();
815 }
816
817 /*
818 * Whatever invocation Return does is done, so we
819 * are too.
820 */
821 return;
822 }
823
824 /*
825 * Right arrow causes opening up a sub-f.menu. Open
826 * it up in the appropriate place, [re-]set
827 * highlights, and call do_key_menu() to do a lot of
828 * the internals of it.
829 */
830 int xx = Event.xkey.x;
831 int yy = Event.xkey.y;
832 int wx, wy;
834 &wx, &wy, &junkW);
835 if(ActiveItem) {
836 ActiveItem->state = 0;
839 }
840 xx -= (wx - ActiveMenu->width);
841 yy -= (wy - item->item_num * Scr->EntryHeight - (Scr->EntryHeight / 2) - 2);
842 Event.xkey.x_root = xx;
843 Event.xkey.y_root = yy;
844 XWarpPointer(dpy, Scr->Root, Scr->Root, Event.xkey.x, Event.xkey.y,
846 if(ActiveMenu == Scr->Workspaces) {
848 }
849 do_key_menu(item->sub, None);
851 break;
852 }
853
854 /*
855 * Any other f.something. Pop down the menu (unless
856 * we're trying to pin it up), and invoke the function.
857 */
858 default :
859 if(item->func != F_PIN) {
860 PopDownMenu();
861 }
862 ExecuteFunction(item->func, item->action,
864 ButtonWindow, &Event, Context, false);
865 }
866
867 /* Done whatever invocation of the entry we need */
868 }
869 else {
870 /* Was no item; pop out of the menu */
871 PopDownMenu();
873 }
874
875 /*
876 * We're done handling the keypress in a menu, so there's nothing
877 * else to do.
878 */
879 return;
880 }
881
882
883 /*
884 * Not in a menu, so we loop through our various bindings. First,
885 * figure out what context we're in. This goes in a global var,
886 * presumably because stuff way down the chain of invoking some item
887 * may need to refer up to it.
888 */
890 if(Event.xany.window == Scr->Root) {
891 if(AlternateContext) {
894 AlternateContext = false;
896 }
897 else if(AlternateKeymap && Event.xkey.subwindow) {
898 Tmp_win = GetTwmWindow(Event.xkey.subwindow);
899 if(Tmp_win) {
900 Event.xany.window = Tmp_win->w;
901 }
902 }
903 else {
904 Context = C_ROOT;
905 }
906 }
907 if(Tmp_win) {
908 if(0) {
909 /* Dummy to simplify constructions of else if's */
910 }
911#ifdef EWMH_DESKTOP_ROOT
912 else if(Tmp_win->ewmhWindowType == wt_Desktop) {
913 fprintf(stderr, "HandleKeyPress: wt_Desktop -> C_ROOT\n");
914 Context = C_ROOT;
915 }
916#endif
917 else if(Event.xany.window == Tmp_win->title_w) {
919 }
920 else if(Event.xany.window == Tmp_win->w) {
922 }
923 else if(Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w)) {
924 Context = C_ICON;
925 }
926 else if(Event.xany.window == Tmp_win->frame) {
928 }
929 else if(Tmp_win->iconmanagerlist) {
930 if(Event.xany.window == Tmp_win->iconmanagerlist->w ||
931 Event.xany.window == Tmp_win->iconmanagerlist->icon) {
933 }
934 }
935 if(Tmp_win->iswspmgr) {
937 }
938 }
939
940 /*
941 * We've figured out the Context. Now see what modifiers we might
942 * have set...
943 */
944 unsigned int modifier = (Event.xkey.state | AlternateKeymap) & mods_used;
946 if(AlternateKeymap) {
949 AlternateKeymap = 0;
950 }
951
952
953 /*
954 * Loop over our key bindings and do its thing if we find a matching
955 * one.
956 */
957 for(FuncKey *key = Scr->FuncKeyRoot.next; key != NULL; key = key->next) {
958 /*
959 * Is this what we're trying to invoke? Gotta be the right key,
960 * and right modifier; those are easy.
961 *
962 * Context is tougher; that has to match what we're expecting as
963 * well, except in the case of C_NAME, which we always have to
964 * check to see if it'll match any windows. So if we have the
965 * right key and modifier, and it's a C_NAME context, it's a
966 * "maybe" match and we have to go through the checks.
967 */
968 if(key->keycode != Event.xkey.keycode ||
969 key->mods != modifier ||
970 (key->cont != Context && key->cont != C_NAME)) {
971 /* Nope, not yet */
972 continue;
973 }
974
975 /* 'k, it's a match (or potential match, in C_NAME case) */
976
977 /*
978 * Weed out the functions that don't make sense to execute from a
979 * key press
980 *
981 * TODO: add keyboard moving/resizing of windows.
982 */
983 if(key->func == F_MOVE || key->func == F_RESIZE) {
984 return;
985 }
986
987 if(key->cont != C_NAME) {
988 /* Normal context binding; do what it wants */
989 if(key->func == F_MENU) {
990 /*
991 * f.menu doesn't call the f.menu handler; we directly
992 * do_key_menu() to pull it up.
993 *
994 * Note this is "we called f.menu from a keybinding", not
995 * "we hit f.menu inside a menu we had up"; that's above.
996 */
998 do_key_menu(key->menu, (Window) None);
999 }
1000 else {
1001#ifdef EWMH_DESKTOP_ROOT
1002 if(Context == C_ROOT && Tmp_win != NULL) {
1003 Context = C_WINDOW;
1004 fprintf(stderr, "HandleKeyPress: wt_Desktop -> C_WINDOW\n");
1005 }
1006#endif /* EWMH */
1007 ExecuteFunction(key->func, key->action, Event.xany.window,
1008 Tmp_win, &Event, Context, false);
1011 }
1012 }
1013 return;
1014 }
1015 else {
1016 /*
1017 * By-name binding (i.e., quoted string for the context
1018 * argument in config; see the manual). Find windows
1019 * matching that name and invoke on them, if any.
1020 *
1021 * This is the 'maybe' case above; we don't know whether this
1022 * does something until we try it. If we don't get a match,
1023 * we loop back around and keep going through our functions
1024 * until we do.
1025 */
1026 bool matched = false;
1027 const size_t len = strlen(key->win_name);
1028
1029 /* try and match the name first */
1030 for(Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
1031 Tmp_win = Tmp_win->next) {
1032 if(!strncmp(key->win_name, Tmp_win->name, len)) {
1033 matched = true;
1034 ExecuteFunction(key->func, key->action, Tmp_win->frame,
1035 Tmp_win, &Event, C_FRAME, false);
1038 }
1039 }
1040 }
1041
1042 /* now try the res_name */
1043 if(!matched) {
1044 for(Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
1045 Tmp_win = Tmp_win->next) {
1046 if(!strncmp(key->win_name, Tmp_win->class.res_name, len)) {
1047 matched = true;
1048 ExecuteFunction(key->func, key->action, Tmp_win->frame,
1049 Tmp_win, &Event, C_FRAME, false);
1052 }
1053 }
1054 }
1055 }
1056
1057 /* now try the res_class */
1058 if(!matched) {
1059 for(Tmp_win = Scr->FirstWindow; Tmp_win != NULL;
1060 Tmp_win = Tmp_win->next) {
1061 if(!strncmp(key->win_name, Tmp_win->class.res_class, len)) {
1062 matched = true;
1063 ExecuteFunction(key->func, key->action, Tmp_win->frame,
1064 Tmp_win, &Event, C_FRAME, false);
1067 }
1068 }
1069 }
1070 }
1071
1072 /*
1073 * If we wound up invoking something, we're done, so return.
1074 * If we didn't, we fall through to the next loop through our
1075 * defined bindings.
1076 *
1077 * By-name bindings are unique in this; normal contexts
1078 * couldn't have multiple matches, so that side of things
1079 * finishes when it deals with its found match. But with
1080 * by-name we could have multiple bindings of a given
1081 * button/modifier with different names, so we have to go
1082 * back around to the next run through the for() loop.
1083 */
1084 if(matched) {
1085 return;
1086 }
1087 } // regular context or by-name?
1088 } // Loop over all bindings
1089
1090
1091 /*
1092 * If we get here, no function key was bound to the key. Send it to
1093 * the client if it was in a window we know about. Mostly this
1094 * doesn't happen; clients with focus get their events more directly,
1095 * but special cases may cause this.
1096 */
1097 if(Tmp_win) {
1098 if(Context == C_WORKSPACE) {
1099 WMgrHandleKeyPressEvent(Scr->currentvs, &Event);
1100 return;
1101 }
1102 if(Context == C_ICON ||
1103 Context == C_FRAME ||
1104 Context == C_TITLE ||
1105 Context == C_ICONMGR) {
1106 Event.xkey.window = Tmp_win->w;
1108 }
1109 }
1110
1111
1112 /* And done */
1113}
1114
1115
1116
1117/***********************************************************************
1118 *
1119 * Procedure:
1120 * HandlePropertyNotify - property notify event handler
1121 *
1122 ***********************************************************************
1123 */
1124
1126{
1127 Atom actual = None;
1128 int actual_format;
1129 unsigned long nitems, bytesafter;
1130 unsigned long valuemask; /* mask for create windows */
1131 XSetWindowAttributes attributes; /* attributes for create windows */
1132 Pixmap pm;
1133 Icon *icon;
1134
1135
1136 /* watch for standard colormap changes */
1137 if(Event.xproperty.window == Scr->Root) {
1138
1139 if(Event.xproperty.atom == XA_WM_CURRENTWORKSPACE) {
1140 unsigned char *prop;
1141 switch(Event.xproperty.state) {
1142 case PropertyNewValue:
1144 0L, 200L, False, XA_STRING, &actual, &actual_format,
1145 &nitems, &bytesafter, &prop) == Success) {
1146 if(nitems == 0) {
1147 return;
1148 }
1149 GotoWorkSpaceByName(Scr->vScreenList, (char *)prop);
1150 XFree(prop);
1151 }
1152 return;
1153
1154 default:
1155 return;
1156 }
1157 }
1158 switch(Event.xproperty.state) {
1159 case PropertyNewValue: {
1160 XStandardColormap *maps = NULL;
1161 int nmaps;
1162
1163 if(XGetRGBColormaps(dpy, Scr->Root, &maps, &nmaps,
1164 Event.xproperty.atom)) {
1165 /* if got one, then replace any existing entry */
1166 InsertRGBColormap(Event.xproperty.atom, maps, nmaps, true);
1167 }
1168 return;
1169 }
1170
1171 case PropertyDelete:
1172 RemoveRGBColormap(Event.xproperty.atom);
1173 return;
1174 }
1175 }
1176
1177 if(!Tmp_win) {
1178 return; /* unknown window */
1179 }
1180
1181#define MAX_NAME_LEN 200L /* truncate to this many */
1182
1183 switch(Event.xproperty.atom) {
1184 case XA_WM_NAME: {
1186 if(prop == NULL) {
1187 // Clear
1191 return;
1192 }
1193
1194 if(Tmp_win->names.wm_name != NULL
1195 && strcmp(Tmp_win->names.wm_name, prop) == 0) {
1196 /* No change, just free and skip out */
1197 free(prop);
1198 return;
1199 }
1200
1201 /* It's changing, free the old and bring in the new */
1204
1205 /* Kick the reset process */
1207
1208 break;
1209 }
1210
1211 case XA_WM_ICON_NAME: {
1213 if(prop == NULL) {
1214 // Clear
1218 return;
1219 }
1220
1221 /* No change? Nothing to do. */
1223 && strcmp(Tmp_win->names.wm_icon_name, prop) == 0) {
1224 free(prop);
1225 return;
1226 }
1227
1228 /* It's changing, free the old and bring in the new */
1231
1232 /* And show the new */
1234
1235 break;
1236 }
1237
1238 case XA_WM_HINTS: {
1239 {
1240 XWMHints *nhints = XGetWMHints(dpy, Event.xany.window);
1241 if(!nhints) {
1242 /*
1243 * I guess this means that window removed the
1244 * property completely. Just keep using what we
1245 * already have for it though; we gotta have
1246 * something, and whatever it last said is probably
1247 * more reasonable than getting completely new
1248 * synthetic hints anyway.
1249 */
1250 break;
1251 }
1252
1255 }
1256
1257 icon = Tmp_win->icon;
1258
1259 /*
1260 * If there already is an icon found in a way that has priority
1261 * over these hints, disable the flags and remove them from
1262 * consideration, now and in the future.
1263 */
1264 if(Tmp_win->forced ||
1265 (icon && icon->match == match_net_wm_icon)) {
1267 }
1268
1269 if(Tmp_win->wmhints->flags & IconWindowHint) {
1270 if(icon && icon->w) {
1271 int icon_x, icon_y;
1272
1273 /*
1274 * There's already an icon window.
1275 * Try to find out where it is; if we succeed, move the new
1276 * window to where the old one is.
1277 */
1278 if(XGetGeometry(dpy, icon->w, &JunkRoot, &icon_x,
1279 &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
1280 /*
1281 * Move the new icon window to where the old one was.
1282 */
1283 XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
1284 icon_y);
1285 }
1286
1287 /*
1288 * If the window is iconic, map the new icon window.
1289 */
1290 if(Tmp_win->isicon) {
1291 XMapWindow(dpy, Tmp_win->wmhints->icon_window);
1292 }
1293
1294 /*
1295 * Now, if the old window isn't ours, unmap it, otherwise
1296 * just get rid of it completely.
1297 */
1298 if(icon->w_not_ours) {
1299 if(icon->w != Tmp_win->wmhints->icon_window) {
1300 XUnmapWindow(dpy, icon->w);
1301 }
1302 }
1303 else {
1304 XDestroyWindow(dpy, icon->w);
1305 }
1306
1307 /*
1308 * The new icon window isn't our window, so note that fact
1309 * so that we don't treat it as ours.
1310 */
1311 icon->w_not_ours = true;
1312
1313 /*
1314 * Now make the new window the icon window for this window,
1315 * and set it up to work as such (select for key presses
1316 * and button presses/releases, set up the contexts for it,
1317 * and define the cursor for it).
1318 */
1319 icon->w = Tmp_win->wmhints->icon_window;
1320 XSelectInput(dpy, icon->w,
1324 XDefineCursor(dpy, icon->w, Scr->IconCursor);
1325 }
1326 }
1327
1328 if(icon && icon->w &&
1329 (Tmp_win->wmhints->flags & IconPixmapHint)) {
1330 int x;
1331 unsigned int IconDepth;
1332
1333 if(!XGetGeometry(dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
1334 &JunkX, &JunkY, (unsigned int *)&icon->width,
1335 (unsigned int *)&icon->height, &JunkBW,
1336 &IconDepth)) {
1337 return;
1338 }
1339
1340 pm = XCreatePixmap(dpy, Scr->Root, icon->width,
1341 icon->height, Scr->d_depth);
1342
1343 FB(icon->iconc.fore, icon->iconc.back);
1344
1345 if(IconDepth == Scr->d_depth)
1346 XCopyArea(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
1347 0, 0, icon->width, icon->height, 0, 0);
1348 else
1349 XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
1350 0, 0, icon->width, icon->height, 0, 0, 1);
1351
1352 if(icon->image) {
1353 /* Release the existing Image: it may be a shared one (UnknownIcon) */
1354 ReleaseIconImage(icon);
1355 /* conjure up a new Image */
1356 Image *image = AllocImage();
1357 image->pixmap = pm;
1358 image->width = icon->width;
1359 image->height = icon->height;
1360 icon->image = image;
1362 }
1363
1365 attributes.background_pixmap = pm;
1366
1367 if(icon->bm_w) {
1368 XDestroyWindow(dpy, icon->bm_w);
1369 }
1370
1371 x = GetIconOffset(icon);
1372 icon->bm_w =
1373 XCreateWindow(dpy, icon->w, x, 0,
1374 icon->width,
1375 icon->height,
1376 0, Scr->d_depth,
1377 CopyFromParent, Scr->d_visual,
1379
1380 if(!(Tmp_win->wmhints->flags & IconMaskHint)) {
1382
1383 rect.x = x;
1384 rect.y = 0;
1385 rect.width = icon->width;
1386 rect.height = icon->height;
1388 0, &rect, 1, ShapeUnion, 0);
1389 }
1390 XMapSubwindows(dpy, icon->w);
1392 }
1393 if(icon && icon->w &&
1394 (Tmp_win->wmhints->flags & IconMaskHint) &&
1395 icon->match == match_icon_pixmap_hint) {
1396 /* Only set the mask if the pixmap came from a WM_HINTS too,
1397 * for easier resource management.
1398 */
1399 int x;
1400 Pixmap mask;
1401 GC gc;
1402 unsigned int IconWidth, IconHeight, IconDepth;
1403
1404 if(!XGetGeometry(dpy, Tmp_win->wmhints->icon_mask, &JunkRoot,
1406 &IconDepth)) {
1407 return;
1408 }
1409 if(IconDepth != 1) {
1410 return;
1411 }
1412
1413 mask = XCreatePixmap(dpy, Scr->Root, IconWidth, IconHeight, 1);
1414 if(!mask) {
1415 return;
1416 }
1417 gc = XCreateGC(dpy, mask, 0, NULL);
1418 if(!gc) {
1419 return;
1420 }
1421 XCopyArea(dpy, Tmp_win->wmhints->icon_mask, mask, gc,
1422 0, 0, IconWidth, IconHeight, 0, 0);
1423 XFreeGC(dpy, gc);
1424 x = GetIconOffset(icon);
1425 XShapeCombineMask(dpy, icon->bm_w, ShapeBounding, 0, 0, mask,
1426 ShapeSet);
1427 XShapeCombineMask(dpy, icon->w, ShapeBounding, x, 0, mask,
1428 ShapeSet);
1429 if(icon->image) {
1430 if(icon->image->mask) {
1431 XFreePixmap(dpy, icon->image->mask);
1432 }
1433 icon->image->mask = mask;
1435 }
1436 }
1437 if(Tmp_win->wmhints->flags & IconPixmapHint) {
1439 }
1440
1441 break;
1442 }
1443
1444 case XA_WM_NORMAL_HINTS: {
1446 break;
1447 }
1448 default: {
1449 if(Event.xproperty.atom == XA_WM_COLORMAP_WINDOWS) {
1450 FetchWmColormapWindows(Tmp_win); /* frees old data */
1451 break;
1452 }
1453 else if(Event.xproperty.atom == XA_WM_PROTOCOLS) {
1455 break;
1456 }
1457 else if(Event.xproperty.atom == XA_WM_OCCUPATION) {
1458 unsigned char *prop;
1459 if(XGetWindowProperty(dpy, Tmp_win->w, Event.xproperty.atom, 0L, MAX_NAME_LEN,
1460 False,
1462 &bytesafter, &prop) != Success ||
1463 actual == None) {
1464 return;
1465 }
1467 XFree(prop);
1468 }
1469 else if(Event.xproperty.atom == XA_CTWM_WM_NAME) {
1471 if(prop == NULL) {
1472 // Clearing
1476 return;
1477 }
1478
1481 prop) == 0) {
1482 /* No change, just free and skip out */
1483 free(prop);
1484 return;
1485 }
1486
1487 /* It's changing, free the old and bring in the new */
1490
1491 /* Kick the reset process */
1493
1494 return;
1495 }
1496 else if(Event.xproperty.atom == XA_CTWM_WM_ICON_NAME) {
1499 if(prop == NULL) {
1500 // Clearing
1504 return;
1505 }
1506
1509 prop) == 0) {
1510 /* No change, just free and skip out */
1511 free(prop);
1512 return;
1513 }
1514
1515 /* It's changing, free the old and bring in the new */
1518
1519 /* Kick the reset process */
1521
1522 break;
1523 }
1524#ifdef EWMH
1525 else if(EwmhHandlePropertyNotify(&Event.xproperty, Tmp_win)) {
1526 /* event handled */
1527 }
1528#endif /* EWMH */
1529 break;
1530 }
1531 }
1532}
1533
1534
1535/***********************************************************************
1536 *
1537 * Procedure:
1538 * HandleClientMessage - client message event handler
1539 *
1540 ***********************************************************************
1541 */
1542
1544{
1545
1546 if(Event.xclient.message_type == XA_WM_CHANGE_STATE) {
1547 if(Tmp_win != NULL) {
1548 if(Event.xclient.data.l[0] == IconicState && !Tmp_win->isicon) {
1549 XEvent button;
1551 &(button.xmotion.x_root),
1552 &(button.xmotion.y_root),
1553 &JunkX, &JunkY, &JunkMask);
1554
1555 ExecuteFunction(F_ICONIFY, NULL, Event.xany.window,
1556 Tmp_win, &button, FRAME, false);
1558 }
1559 }
1560 return;
1561 }
1562
1563#ifdef EWMH
1564 if(EwmhClientMessage(&Event.xclient)) {
1565 return;
1566 }
1567#endif
1568
1569 else if((Event.xclient.message_type == XA_WM_PROTOCOLS) &&
1570 (Event.xclient.data.l[0] == XA_WM_END_OF_ANIMATION)) {
1571 if(Animating > 0) {
1572 Animating--;
1573 }
1574 else {
1575 fprintf(stderr, "!! end of unknown animation !!\n");
1576 }
1577 }
1578}
1579
1580
1581/***********************************************************************
1582 *
1583 * Procedure:
1584 * HandleExpose - expose event handler
1585 *
1586 ***********************************************************************
1587 */
1588
1589static void flush_expose(Window w);
1590
1592{
1593 MenuRoot *tmp;
1594 VirtualScreen *vs;
1595
1596 if(XFindContext(dpy, Event.xany.window, MenuContext, (XPointer *)&tmp) == 0) {
1597 PaintMenu(tmp, &Event);
1598 return;
1599 }
1600
1601 if(Event.xexpose.count != 0) {
1602 return;
1603 }
1604
1605 if(Event.xany.window == Scr->InfoWindow.win && Scr->InfoWindow.mapped) {
1607 flush_expose(Event.xany.window);
1608 }
1609 else if(Tmp_win != NULL) {
1610 if(Scr->use3Dborders && (Event.xany.window == Tmp_win->frame)) {
1611 PaintBorders(Tmp_win, ((Tmp_win == Scr->Focus) ? true : false));
1612 flush_expose(Event.xany.window);
1613 return;
1614 }
1615 else if(Event.xany.window == Tmp_win->title_w) {
1617 flush_expose(Event.xany.window);
1618 return;
1619 }
1620 else if(Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w) &&
1621 ! Scr->NoIconTitlebar &&
1622 ! LookInList(Scr->NoIconTitle, Tmp_win->name, &Tmp_win->class)) {
1624 flush_expose(Event.xany.window);
1625 return;
1626 }
1627 else if(Tmp_win->titlebuttons) {
1628 int i;
1629 TBWindow *tbw;
1630 Window w = Event.xany.window;
1631 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1632
1633 /*
1634 * This looks an awful lot like a manual reimplementation of
1635 * PaintTitleButtons(). It's not quite though, it's just
1636 * looking up one button to paint it. And it would be a
1637 * little grody trying to shoehorn it in.
1638 */
1639 for(i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
1640 if(w == tbw->window) {
1642 flush_expose(tbw->window);
1643 return;
1644 }
1645 }
1646 }
1647 for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1648 if(Tmp_win == vs->wsw->twm_win) {
1650 flush_expose(Event.xany.window);
1651 return;
1652 }
1653 }
1654 if(Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1655 /*
1656 * The occupyWindow has a bunch of sub-windows for each
1657 * button in it, and each of them wind up getting Expose
1658 * events kicked for them. The upshot is that we re-paint
1659 * the occupy window once for itself, and then once for each
1660 * button inside it. We'll always get one for the window
1661 * itself, so just paint it for that one, and ignore the rest
1662 * of the events.
1663 *
1664 * XXX Maybe a better solution is just to mask off Expose
1665 * events for the other windows...
1666 */
1667 if(Event.xany.window == Scr->workSpaceMgr.occupyWindow->w) {
1669 flush_expose(Event.xany.window);
1670 }
1671 return;
1672 }
1673 else if(Tmp_win->iconmanagerlist) {
1674 WList *iconmanagerlist = Tmp_win->iconmanagerlist;
1675
1676 if(Event.xany.window == iconmanagerlist->w) {
1678 flush_expose(Event.xany.window);
1679 return;
1680 }
1681 else if(Event.xany.window == iconmanagerlist->icon) {
1683 flush_expose(Event.xany.window);
1684 return;
1685 }
1686 }
1687 }
1688}
1689
1690
1692{
1693 if(enter_win == tmp) {
1694 enter_flag = false;
1695 enter_win = NULL;
1696 }
1697 if(raise_win == Tmp_win) {
1698 raise_win = NULL;
1699 }
1700 if(leave_win == tmp) {
1701 leave_flag = false;
1702 leave_win = NULL;
1703 }
1704 if(lower_win == Tmp_win) {
1705 lower_win = NULL;
1706 }
1707
1709}
1710
1711
1712/***********************************************************************
1713 *
1714 * Procedure:
1715 * HandleDestroyNotify - DestroyNotify event handler
1716 *
1717 ***********************************************************************
1718 */
1719
1721{
1722 /*
1723 * Warning, this is also called by HandleUnmapNotify; if it ever needs to
1724 * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
1725 * into a DestroyNotify.
1726 */
1727
1728 if(Tmp_win == NULL) {
1729 return;
1730 }
1731
1733
1734 if(Tmp_win->icon != NULL) {
1736 }
1738
1739#ifdef EWMH
1740 /* Remove the old window from the EWMH client list */
1743#endif /* EWMH */
1744 if(Tmp_win == Scr->Focus) {
1745 Scr->Focus = NULL;
1746 FocusOnRoot();
1747 }
1748 if(Scr->SaveWorkspaceFocus) {
1749 struct WorkSpace *ws;
1750 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1751 if(ws->save_focus == Tmp_win) {
1752 ws->save_focus = NULL;
1753 }
1754 }
1755 }
1760 if(Tmp_win->icon && Tmp_win->icon->w) {
1763 }
1764 if(Tmp_win->title_height) {
1765 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1766
1769 if(Tmp_win->hilite_wl) {
1772 }
1773 if(Tmp_win->hilite_wr) {
1776 }
1777 if(Tmp_win->lolite_wr) {
1780 }
1781 if(Tmp_win->lolite_wl) {
1784 }
1785 if(Tmp_win->titlebuttons) {
1786 int i;
1787
1788 for(i = 0; i < nb; i++) {
1790 TwmContext);
1793 }
1794 }
1795 /*
1796 * The hilite_wl etc windows don't need to be XDestroyWindow()ed
1797 * since that will happen when the parent is destroyed (??)
1798 */
1799 }
1800
1801 if(Scr->cmapInfo.cmaps == &Tmp_win->cmaps) {
1802 InstallColormaps(DestroyNotify, &Scr->RootColormaps);
1803 }
1804
1805 /*
1806 * TwmWindows contain the following pointers
1807 *
1808 * 1. (obsolete)
1809 * 2. name
1810 * 3. icon_name
1811 * 4. wmhints
1812 * 5. class.res_name
1813 * 6. class.res_class
1814 * 7. list
1815 * 8. iconmgrp
1816 * 9. cwins
1817 * 10. titlebuttons
1818 * 11. window ring
1819 * 12. squeeze_info (delete if squeeze_info_copied)
1820 * 13. HiliteImage
1821 * 14. iconslist
1822 */
1824 if(Tmp_win->gray) {
1826 }
1827
1828 /*
1829 * According to the manual page, the following destroys all child windows
1830 * of the frame too, which is most of the windows we're concerned with, so
1831 * anything related to them must be done before here.
1832 * Icons are not child windows.
1833 */
1835 DeleteIconsList(Tmp_win); /* 14 */
1836 if(Tmp_win->icon) {
1837 Icon *icon = Tmp_win->icon;
1838 if(icon->w && !icon->w_not_ours) {
1840 }
1841 DeleteIcon(icon);
1842 Tmp_win->icon = NULL;
1843 }
1844 Tmp_win->occupation = 0;
1845 RemoveIconManager(Tmp_win); /* 7 */
1846 if(Scr->FirstWindow == Tmp_win) {
1847 Scr->FirstWindow = Tmp_win->next;
1848 }
1849 if(Tmp_win->prev != NULL) {
1851 }
1852 if(Tmp_win->next != NULL) {
1854 }
1855 if(Tmp_win->auto_raise) {
1856 Scr->NumAutoRaises--;
1857 }
1858 if(Tmp_win->auto_lower) {
1859 Scr->NumAutoLowers--;
1860 }
1861
1866#ifdef EWMH
1867 FreeWMPropertyString(Tmp_win->names.net_wm_name); // 2
1868 FreeWMPropertyString(Tmp_win->names.net_wm_icon_name); // 3
1869#endif
1870
1871 XFree(Tmp_win->wmhints); /* 4 */
1872 if(Tmp_win->class.res_name && Tmp_win->class.res_name != NoName) { /* 5 */
1873 XFree(Tmp_win->class.res_name);
1874 }
1875 if(Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) { /* 6 */
1876 XFree(Tmp_win->class.res_class);
1877 }
1878 free_cwins(Tmp_win); /* 9 */
1879 if(Tmp_win->titlebuttons) { /* 10 */
1882 }
1883
1885 if(Tmp_win->squeeze_info_copied) { /* 12 */
1888 }
1890
1891 free(Tmp_win);
1892 Tmp_win = NULL;
1893
1894 if(Scr->ClickToFocus || Scr->SloppyFocus) {
1895 set_last_window(Scr->currentvs->wsw->currentwspc);
1896 }
1897}
1898
1899
1900void
1902{
1903#ifdef DEBUG_EVENTS
1904 fprintf(stderr, "CreateNotify w = 0x%x\n",
1905 (unsigned)Event.xcreatewindow.window);
1906 fflush(stderr);
1907 XBell(dpy, 0);
1908 XSync(dpy, 0);
1909#endif
1910}
1911
1912
1913/***********************************************************************
1914 *
1915 * Procedure:
1916 * HandleMapRequest - MapRequest event handler
1917 *
1918 ***********************************************************************
1919 */
1920
1922{
1923 int zoom_save;
1924
1925 Event.xany.window = Event.xmaprequest.window;
1926 Tmp_win = GetTwmWindow(Event.xany.window);
1927
1928 /* If the window has never been mapped before ... */
1929 if(Tmp_win == NULL) {
1930 /* Add decorations. */
1931 VirtualScreen *vs = Scr->currentvs;
1932
1933 Tmp_win = AddWindow(Event.xany.window,
1934 AWT_NORMAL,
1935 NULL,
1936 vs);
1937 if(Tmp_win == NULL) {
1938 return;
1939 }
1940#ifdef EWMH
1941 /* add the new window to the EWMH client list */
1944
1945 /* Tell it whatever we think of it */
1947#endif /* EWMH */
1948 }
1949 else {
1950 /*
1951 * If the window has been unmapped by the client, it won't be listed
1952 * in the icon manager. Add it again, if requested.
1953 */
1954 if(Tmp_win->iconmanagerlist == NULL) {
1956 }
1957 }
1958
1959 if(Tmp_win->isiconmgr) {
1960 return;
1961 }
1962 if(Tmp_win->squeezed) {
1963 return;
1964 }
1965
1966 if(Scr->WindowMask) {
1967 XRaiseWindow(dpy, Scr->WindowMask);
1968 }
1969
1970 /* If it's not merely iconified, and we have hints, use them. */
1971 if(! Tmp_win->isicon) {
1972 int state;
1973 Window icon;
1974
1975 state = NormalState;
1976 /* use WM_STATE if enabled */
1977 if(!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
1978 (state == NormalState || state == IconicState || state == InactiveState))) {
1979 if(Tmp_win->wmhints->flags & StateHint) {
1980 state = Tmp_win->wmhints->initial_state;
1981 }
1982 }
1983 switch(state) {
1984 case DontCareState:
1985 case NormalState:
1986 case ZoomState:
1987 if(Tmp_win->StartSqueezed) {
1989 }
1990 else {
1992 }
1996 Tmp_win->mapped = true;
1997 if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
1999 }
2000 /* kai */
2001 if(Scr->AutoFocusToTransients &&
2003 Tmp_win->wmhints->input) {
2005 }
2006 break;
2007
2008 case InactiveState:
2009 if(!OCCUPY(Tmp_win, Scr->currentvs->wsw->currentwspc) &&
2010 HandlingEvents && /* to avoid warping during startup */
2011 LookInList(Scr->WarpOnDeIconify, Tmp_win->name, &Tmp_win->class)) {
2012 if(!Scr->NoRaiseDeicon) {
2014 }
2015 AddToWorkSpace(Scr->currentvs->wsw->currentwspc->name, Tmp_win);
2016 }
2017 Tmp_win->mapped = true;
2019 XMoveWindow(dpy, Tmp_win->frame, Scr->rootw + 1, Scr->rooth + 1);
2022 }
2023 if(Tmp_win->StartSqueezed) {
2025 }
2026 break;
2027
2028 case IconicState:
2029 zoom_save = Scr->DoZoom;
2030 Scr->DoZoom = false;
2031 Iconify(Tmp_win, -100, -100);
2032 Scr->DoZoom = zoom_save;
2033 break;
2034 }
2035 }
2036 /* If no hints, or currently an icon, just "deiconify" */
2037 else {
2038 if(!OCCUPY(Tmp_win, Scr->currentvs->wsw->currentwspc) &&
2039 LookInList(Scr->WarpOnDeIconify, Tmp_win->name, &Tmp_win->class)) {
2040 AddToWorkSpace(Scr->currentvs->wsw->currentwspc->name, Tmp_win);
2041 }
2042 if(1/*OCCUPY (Tmp_win, Scr->workSpaceMgr.activeWSPC)*/) {
2043 if(Tmp_win->StartSqueezed) {
2045 }
2048 }
2049 else {
2050 Tmp_win->mapped = true;
2051 }
2052 }
2053 if(Tmp_win->mapped) {
2055 }
2056 MaybeAnimate = true;
2057}
2058
2059
2060/***********************************************************************
2061 *
2062 * Procedure:
2063 * HandleMapNotify - MapNotify event handler
2064 *
2065 ***********************************************************************
2066 */
2067
2069{
2070 if(Tmp_win == NULL) {
2071 return;
2072 }
2073
2074 /*
2075 * Need to do the grab to avoid race condition of having server send
2076 * MapNotify to client before the frame gets mapped; this is bad because
2077 * the client would think that the window has a chance of being viewable
2078 * when it really isn't.
2079 */
2081
2082 // Mapping the window, hide its icon
2083 if(Tmp_win->icon && Tmp_win->icon->w) {
2085 }
2086
2087 // Map up everything inside the frame (not the frame itself, so if it
2088 // wasn't already up, nothing will show yet)
2090
2091 // Choose which of the hi/lolite's should be left up, based on the
2092 // focus
2093 if(Scr->Focus != Tmp_win) {
2094 if(Tmp_win->hilite_wl) {
2096 }
2097 if(Tmp_win->hilite_wr) {
2099 }
2100 }
2101 else {
2102 if(Tmp_win->lolite_wl) {
2104 }
2105 if(Tmp_win->lolite_wr) {
2107 }
2108 }
2109
2110 // Now map the frame itself (which brings all the rest into view)
2112
2114 XFlush(dpy);
2115
2116 // Set the flags
2117 Tmp_win->mapped = true;
2118 Tmp_win->isicon = false;
2119 Tmp_win->icon_on = false;
2120}
2121
2122
2123/***********************************************************************
2124 *
2125 * Procedure:
2126 * HandleUnmapNotify - UnmapNotify event handler
2127 *
2128 ***********************************************************************
2129 */
2130
2132{
2133 int dstx, dsty;
2134 Window dumwin;
2135
2136 /*
2137 * The July 27, 1988 ICCCM spec states that a client wishing to switch
2138 * to WithdrawnState should send a synthetic UnmapNotify with the
2139 * event field set to (pseudo-)root, in case the window is already
2140 * unmapped (which is the case for twm for IconicState). Unfortunately,
2141 * we looked for the TwmContext using that field, so try the window
2142 * field also.
2143 */
2144 if(Tmp_win == NULL) {
2145 Event.xany.window = Event.xunmap.window;
2146 Tmp_win = GetTwmWindow(Event.xany.window);
2147 }
2148
2149 if(Tmp_win == NULL || Event.xunmap.window == Tmp_win->frame ||
2150 (Tmp_win->icon && Event.xunmap.window == Tmp_win->icon->w) ||
2151 (!Tmp_win->mapped && !Tmp_win->isicon)) {
2152 return;
2153 }
2154 /*
2155 if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->isicon))
2156 return;
2157 */
2158 /*
2159 * The program may have unmapped the client window, from either
2160 * NormalState or IconicState. Handle the transition to WithdrawnState.
2161 *
2162 * We need to reparent the window back to the root (so that twm exiting
2163 * won't cause it to get mapped) and then throw away all state (pretend
2164 * that we've received a DestroyNotify).
2165 */
2166 /* Is it the correct behaviour ???
2167 XDeleteProperty (dpy, Tmp_win->w, XA_WM_OCCUPATION);
2168 */
2169#ifdef EWMH
2171#endif /* EWMH */
2173 if(XTranslateCoordinates(dpy, Event.xunmap.window, Tmp_win->attr.root,
2174 0, 0, &dstx, &dsty, &dumwin)) {
2175 XEvent ev;
2177 ReparentNotify, &ev);
2179 if(reparented) {
2180 // It got reparented, get rid of our alterations.
2181 if(Tmp_win->old_bw) {
2183 Event.xunmap.window,
2184 Tmp_win->old_bw);
2185 }
2186 if(Tmp_win->wmhints->flags & IconWindowHint) {
2187 XUnmapWindow(dpy, Tmp_win->wmhints->icon_window);
2188 }
2189 }
2190 else {
2191 // Didn't get reparented, so we should do it ourselves
2192 XReparentWindow(dpy, Event.xunmap.window, Tmp_win->attr.root,
2193 dstx, dsty);
2194 // XXX Need to think more about just what the roots and
2195 // coords are here...
2197 }
2198 XRemoveFromSaveSet(dpy, Event.xunmap.window);
2199 XSelectInput(dpy, Event.xunmap.window, NoEventMask);
2200 HandleDestroyNotify(); /* do not need to mash event before */
2201 } /* else window no longer exists and we'll get a destroy notify */
2203 XFlush(dpy);
2204}
2205
2206
2207/***********************************************************************
2208 *
2209 * Procedure:
2210 * HandleMotionNotify - MotionNotify event handler
2211 *
2212 ***********************************************************************
2213 */
2214
2216{
2217 if(ResizeWindow != (Window) 0) {
2218 XQueryPointer(dpy, Event.xany.window,
2219 &(Event.xmotion.root), &JunkChild,
2220 &(Event.xmotion.x_root), &(Event.xmotion.y_root),
2221 &(Event.xmotion.x), &(Event.xmotion.y),
2222 &JunkMask);
2223
2225 /* Set WindowMoved appropriately so that f.deltastop will
2226 work with resize as well as move. */
2227 if(abs(Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
2228 || abs(Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta) {
2229 WindowMoved = true;
2230 }
2231
2233#ifdef WINBOX
2234 if(Tmp_win && Tmp_win->winbox) {
2235 XTranslateCoordinates(dpy, Scr->Root, Tmp_win->winbox->window,
2236 Event.xmotion.x_root, Event.xmotion.y_root,
2237 &(Event.xmotion.x_root), &(Event.xmotion.y_root), &JunkChild);
2238 }
2239#endif
2240 DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
2241 }
2242 else if(Scr->BorderCursors && Tmp_win && Event.xany.window == Tmp_win->frame) {
2243 SetBorderCursor(Tmp_win, Event.xmotion.x, Event.xmotion.y);
2244 }
2245}
2246
2247
2248/***********************************************************************
2249 *
2250 * Procedure:
2251 * HandleButtonRelease - ButtonRelease event handler
2252 *
2253 ***********************************************************************
2254 */
2256{
2257 int xl, yt, w, h;
2258 unsigned mask;
2259
2260 if(Scr->InfoWindow.mapped) { /* delete info box on 2nd button release */
2261 if(Context == C_IDENTIFY) {
2262 XUnmapWindow(dpy, Scr->InfoWindow.win);
2263 Scr->InfoWindow.mapped = false;
2265 }
2266 }
2267
2268 if(DragWindow != None) {
2269 MoveOutline(Scr->XineramaRoot, 0, 0, 0, 0, 0, 0);
2270
2272#ifdef WINBOX
2273 if(Tmp_win->winbox) {
2274 XTranslateCoordinates(dpy, Scr->Root, Tmp_win->winbox->window,
2275 Event.xbutton.x_root, Event.xbutton.y_root,
2276 &(Event.xbutton.x_root), &(Event.xbutton.y_root), &JunkChild);
2277 }
2278#endif
2279 if(DragWindow == Tmp_win->frame) {
2280 xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
2281 yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
2282 w = DragWidth + 2 * Tmp_win->frame_bw;
2283 h = DragHeight + 2 * Tmp_win->frame_bw;
2284 }
2285 else {
2286 xl = Event.xbutton.x_root - DragX - DragBW;
2287 yt = Event.xbutton.y_root - DragY - DragBW;
2288 w = DragWidth + 2 * DragBW;
2289 h = DragHeight + 2 * DragBW;
2290 }
2291
2292 if(ConstMove) {
2293 if(ConstMoveDir == MOVE_HORIZ) {
2294 yt = ConstMoveY;
2295 }
2296
2297 if(ConstMoveDir == MOVE_VERT) {
2298 xl = ConstMoveX;
2299 }
2300
2301 if(ConstMoveDir == MOVE_NONE) {
2302 yt = ConstMoveY;
2303 xl = ConstMoveX;
2304 }
2305 }
2306
2307 if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
2308 TryToGrid(Tmp_win, &xl, &yt);
2309 }
2310 if(MoveFunction == F_MOVEPUSH &&
2311 Scr->OpaqueMove &&
2312 DragWindow == Tmp_win->frame) {
2314 }
2315 if(MoveFunction == F_MOVEPACK ||
2317 DragWindow == Tmp_win->frame)) {
2318 TryToPack(Tmp_win, &xl, &yt);
2319 }
2320 if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
2321 ConstrainByBorders(Tmp_win, &xl, w, &yt, h);
2322 }
2323
2324 CurrentDragX = xl;
2325 CurrentDragY = yt;
2326#ifdef VSCREEN
2327 /*
2328 * sometimes getScreenOf() replies with the wrong window when moving
2329 * y to a negative number. Need to figure out why... [XXX]
2330 * It seems to be because the first XTranslateCoordinates() doesn't
2331 * translate the coordinates to be relative to XineramaRoot.
2332 * That in turn is probably because a window is visible in a ws or
2333 * vs where it shouldn't (inconsistent with its occupation).
2334 * A problem of this kind was fixed with f.adoptwindow but remains
2335 * with f.hypermove.
2336 * As a result, the window remains in the original vs/ws and
2337 * is irretrievably moved out of view. [Rhialto]
2338 */
2339 if(xl < 0 || yt < 0 || xl > Scr->rootw || yt > Scr->rooth) {
2340 int odestx, odesty;
2341 int destx, desty;
2342 Window cr;
2344
2346 Scr->XineramaRoot, xl, yt, &odestx, &odesty, &cr);
2347
2349
2350 if(newvs && newvs->wsw && newvs->wsw->currentwspc) {
2351 XTranslateCoordinates(dpy, Scr->XineramaRoot,
2352 newvs->window, odestx, odesty,
2353 &destx, &desty, &cr);
2354 AddToWorkSpace(newvs->wsw->currentwspc->name, Tmp_win);
2356 xl = destx;
2357 yt = desty;
2358 }
2359 }
2360#endif
2361 if(DragWindow == Tmp_win->frame) {
2364 }
2365 else {
2367 if(DragWindow == Tmp_win->icon->w) {
2368 Tmp_win->icon->w_x = xl;
2369 Tmp_win->icon->w_y = yt;
2370 }
2371 }
2372
2373 if(!Scr->NoRaiseMove) { /* && !Scr->OpaqueMove) opaque already did */
2374 if(DragWindow == Tmp_win->frame) {
2376 }
2377 else if(Tmp_win->icon && DragWindow == Tmp_win->icon->w) {
2379 }
2380 else {
2381 fprintf(stderr, "ERROR -- events.c:2815\n");
2382 }
2383 }
2384
2385 if(!Scr->OpaqueMove) {
2387 }
2388 else {
2389 XSync(dpy, 0);
2390 }
2391
2392 if(Scr->NumAutoRaises) {
2393 enter_flag = true;
2394 enter_win = NULL;
2395 raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
2396 ? Tmp_win : NULL);
2397 }
2398
2399 /* CCC equivalent code for auto lower not needed? */
2400
2401#if 0
2402 if(Scr->NumAutoLowers) {
2403 leave_flag = true;
2404 leave_win = NULL;
2406 ? Tmp_win : NULL);
2407 }
2408#endif
2409
2410 DragWindow = (Window) 0;
2411 ConstMove = false;
2412 }
2413
2414 if(ResizeWindow != (Window) 0) {
2415 EndResize();
2416 }
2417
2418 if(ActiveMenu != NULL && RootFunction == 0) {
2419 if(ActiveItem) {
2420 int func = ActiveItem->func;
2422 switch(func) {
2423 case F_TITLE:
2424 if(Scr->StayUpMenus) {
2425 ButtonPressed = -1;
2426 if(Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) {
2428 }
2429 return;
2430 }
2431 break;
2432 case F_MOVE:
2433 case F_FORCEMOVE:
2434 case F_DESTROY:
2435 case F_DELETE:
2436 case F_DELETEORDESTROY:
2437 ButtonPressed = -1;
2438 break;
2439 case F_CIRCLEUP:
2440 case F_CIRCLEDOWN:
2441 case F_REFRESH:
2442 case F_WARPTOSCREEN:
2443 PopDownMenu();
2444 break;
2445 default:
2446 break;
2447 }
2448 if(func != F_PIN && func != F_MENU) {
2449 PopDownMenu();
2450 }
2451 ExecuteFunction(func, Action,
2453 ButtonWindow, &Event, Context, true);
2456
2457 /* if we are not executing a defered command, then take down the
2458 * menu
2459 */
2460 if(ActiveMenu) {
2461 PopDownMenu();
2462 }
2463 }
2464 else if(Scr->StayUpMenus && !ActiveMenu->entered) {
2465 ButtonPressed = -1;
2466 if(Scr->WarpToDefaultMenuEntry && ActiveMenu->defaultitem) {
2468 }
2469 return;
2470 }
2471 else {
2472 PopDownMenu();
2473 }
2474 }
2475
2477 switch(Event.xbutton.button) {
2478 case Button1:
2479 mask &= ~Button1Mask;
2480 break;
2481 case Button2:
2482 mask &= ~Button2Mask;
2483 break;
2484 case Button3:
2485 mask &= ~Button3Mask;
2486 break;
2487 case Button4:
2488 mask &= ~Button4Mask;
2489 break;
2490 case Button5:
2491 mask &= ~Button5Mask;
2492 break;
2493 }
2494
2495 if(RootFunction != 0 ||
2496 ResizeWindow != None ||
2497 DragWindow != None) {
2498 ButtonPressed = -1;
2499 }
2500
2502 ButtonPressed = -1;
2503 return;
2504 }
2505
2506 if(RootFunction == 0 &&
2507 (Event.xbutton.state & mask) == 0 &&
2508 DragWindow == None &&
2509 ResizeWindow == None) {
2512 XFlush(dpy);
2515 ButtonPressed = -1;
2516 if(DownIconManager) {
2517 DownIconManager->down = false;
2518 if(Scr->Highlight) {
2520 }
2522 }
2523 Cancel = false;
2524 }
2525}
2526
2527
2528/*
2529 * Pop up a submenu as a result of moving the mouse right on its entry.
2530 */
2531static void do_menu(MenuRoot *menu, /* menu to pop up */
2532 Window w) /* invoking window or None */
2533{
2534 int x = Event.xbutton.x_root;
2535 int y = Event.xbutton.y_root;
2536 bool center;
2537
2538 if(!Scr->NoGrabServer) {
2540 }
2541 if(w) {
2542 int h = Scr->TBInfo.width - Scr->TBInfo.border;
2543 Window child;
2544
2545 XTranslateCoordinates(dpy, w, Scr->Root, 0, h, &x, &y, &child);
2546 center = false;
2547 }
2548 else {
2549 center = true;
2550 }
2551 if(PopUpMenu(menu, x, y, center)) {
2552 UpdateMenu();
2553 }
2554 else {
2555 XBell(dpy, 0);
2556 }
2557}
2558
2559
2560/*
2561 * Pop up a submenu as a result of hitting the Right arrow key while on
2562 * its entry. We should try folding these two together a bit more.
2563 */
2564static void do_key_menu(MenuRoot *menu, /* menu to pop up */
2565 Window w) /* invoking window or None */
2566{
2567 int x = Event.xkey.x_root;
2568 int y = Event.xkey.y_root;
2569 bool center;
2570
2571 /* I don't think this is necessary.
2572 if (!Scr->NoGrabServer) XGrabServer(dpy);
2573 */
2574 if(w) {
2575 int h = Scr->TBInfo.width - Scr->TBInfo.border;
2576 Window child;
2577
2578 XTranslateCoordinates(dpy, w, Scr->Root, 0, h, &x, &y, &child);
2579 center = false;
2580 }
2581 else {
2582 center = true;
2583 }
2584 if(PopUpMenu(menu, x, y, center)) {
2585 /*
2586 * Note: UpdateMenu() has the internal re-capture of the event
2587 * loop to handle in-menu stuff, so this won't actually return
2588 * until we somehow exit out of that [sub]menu.
2589 */
2590 UpdateMenu();
2591 }
2592 else {
2593 XBell(dpy, 0);
2594 }
2595
2596}
2597
2598
2599/***********************************************************************
2600 *
2601 * Procedure:
2602 * HandleButtonPress - ButtonPress event handler
2603 *
2604 ***********************************************************************
2605 */
2607{
2608 unsigned int modifier;
2609 Cursor cur;
2610 MenuRoot *mr;
2611 FuncButton *tmp = 0;
2612 int func = 0;
2613 Window w;
2614
2615
2616 /* pop down the menu, if any */
2617
2618 if(XFindContext(dpy, Event.xbutton.window, MenuContext,
2619 (XPointer *) &mr) != XCSUCCESS) {
2620 mr = NULL;
2621 }
2622 if(ActiveMenu && (! ActiveMenu->pinned) &&
2623 (Event.xbutton.subwindow != ActiveMenu->w)) {
2624 PopDownMenu();
2625 return;
2626 }
2627 if((ActiveMenu != NULL) && (RootFunction != 0) && (mr != ActiveMenu)) {
2628 PopDownMenu();
2629 }
2630
2631 XSync(dpy, 0);
2632 /* XXX - remove? */
2633
2634 /* want menus if we have info box */
2635 if(ButtonPressed != -1 && !Scr->InfoWindow.mapped) {
2636 /* we got another butt press in addition to one still held
2637 * down, we need to cancel the operation we were doing
2638 */
2639 Cancel = true;
2643 if(Scr->OpaqueMove && DragWindow != None) {
2645 }
2646 else {
2647 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
2648 }
2649 }
2650 XUnmapWindow(dpy, Scr->SizeWindow);
2651 if(!Scr->OpaqueMove) {
2653 }
2655 DragWindow = None;
2656 cur = LeftButt;
2657 if(Event.xbutton.button == Button2) {
2658 cur = MiddleButt;
2659 }
2660 else if(Event.xbutton.button >= Button3) {
2661 cur = RightButt;
2662 }
2663
2664 XGrabPointer(dpy, Scr->Root, True,
2667 Scr->Root, cur, CurrentTime);
2668
2669 return;
2670 }
2671 else {
2672 ButtonPressed = Event.xbutton.button;
2673 }
2674
2675 if((ActiveMenu != NULL) && (ActiveMenu->pinned)) {
2676 if(Event.xbutton.window == ActiveMenu->w) {
2677 modifier = (Event.xbutton.state & mods_used);
2679 if((ActiveItem && (ActiveItem->func == F_TITLE)) || (modifier == Mod1Mask)) {
2680 MoveMenu(&Event);
2681 /*ButtonPressed = -1;*/
2682 }
2683 }
2684 Context = C_ROOT;
2685 return;
2686 }
2687
2688 if(ResizeWindow != None ||
2689 DragWindow != None ||
2690 ActiveMenu != NULL) {
2691 return;
2692 }
2693
2694 /* check the title bar buttons */
2696 int i;
2697 TBWindow *tbw;
2699 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
2700
2701 modifier = Event.xbutton.state & mods_used;
2703
2704 for(i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
2705 if(Event.xany.window == tbw->window) {
2706 for(tbf = tbw->info->funs; tbf; tbf = tbf->next) {
2707 if(tbf->num == ButtonPressed
2708 && tbf->mods == modifier) {
2709 switch(tbf->func) {
2710 /*
2711 * Opening up a menu doesn't use the f.menu
2712 * handler, we use our do_menu(); x-ref
2713 * comments in the handler for details.
2714 */
2715 case F_MENU :
2716 Context = C_TITLE;
2718 do_menu(tbf->menuroot, tbw->window);
2719 break;
2720
2721 default :
2722 ExecuteFunction(tbf->func, tbf->action,
2723 Event.xany.window, Tmp_win,
2724 &Event, C_TITLE, false);
2725 }
2726 return;
2727 }
2728 }
2729 }
2730 }
2731 }
2732
2734
2735 if(Event.xany.window == Scr->InfoWindow.win) {
2737 }
2738
2739 if(Event.xany.window == Scr->Root) {
2740 if(AlternateContext) {
2743 AlternateContext = false;
2745 }
2746 else if(AlternateKeymap && Event.xbutton.subwindow) {
2747 int dx, dy;
2748 Window child;
2749
2750 w = Event.xbutton.subwindow;
2751 Tmp_win = GetTwmWindow(w);
2752 if(Tmp_win) {
2753 Event.xany.window = Tmp_win->frame;
2755 Event.xbutton.x, Event.xbutton.y, &dx, &dy, &child);
2756 Event.xbutton.x = dx;
2757 Event.xbutton.x = dy;
2758 Event.xbutton.subwindow = child;
2759 }
2760 }
2761 else {
2762 Context = C_ROOT;
2763 }
2764 }
2765 if(Tmp_win) {
2766 if(Tmp_win->iconmanagerlist && (RootFunction != 0) &&
2767 ((Event.xany.window == Tmp_win->iconmanagerlist->icon) ||
2768 (Event.xany.window == Tmp_win->iconmanagerlist->w))) {
2769 int x, y;
2770
2772 XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
2773 Event.xbutton.x, Event.xbutton.y,
2774 &x, &y, &JunkChild);
2775
2776 Event.xbutton.x = x - Tmp_win->frame_bw3D;
2777 Event.xbutton.y = y - Tmp_win->title_height - Tmp_win->frame_bw3D;
2778 Event.xany.window = Tmp_win->w;
2779 Context = C_WINDOW;
2780 }
2781#ifdef EWMH_DESKTOP_ROOT
2782 else if(Tmp_win->ewmhWindowType == wt_Desktop) {
2783 fprintf(stderr, "HandleButtonPress: wt_Desktop -> C_ROOT\n");
2784 Context = C_ROOT;
2785 }
2786#endif
2787 else if(Event.xany.window == Tmp_win->title_w) {
2788 if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
2790 }
2791 Context = C_TITLE;
2792 }
2793 else if(Event.xany.window == Tmp_win->w) {
2794 if(Scr->ClickToFocus || Scr->RaiseOnClick) {
2795 if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
2797 }
2798 if(Scr->RaiseOnClick) {
2801 }
2802 XSync(dpy, 0);
2804 XSync(dpy, 0);
2805 ButtonPressed = -1;
2806 return;
2807 }
2808 else {
2809 printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
2810 Context = C_WINDOW;
2811 }
2812 }
2813 else if(Tmp_win->icon && (Event.xany.window == Tmp_win->icon->w)) {
2814 Context = C_ICON;
2815 }
2816 else if(Event.xany.window == Tmp_win->frame) {
2817 Window chwin;
2818
2819 /* since we now place a button grab on the frame instead
2820 * of the window, (see GrabButtons() in add_window.c), we
2821 * need to figure out where the pointer exactly is before
2822 * assigning Context. If the pointer is on the application
2823 * window we will change the event structure to look as if
2824 * it came from the application window.
2825 */
2826 if(Event.xbutton.subwindow == Tmp_win->w) {
2827 XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
2828 Event.xbutton.x, Event.xbutton.y,
2829 &Event.xbutton.x, &Event.xbutton.y,
2830 &chwin);
2831 Event.xbutton.window = Tmp_win->w;
2832
2833#ifdef WINBOX
2834 if(Tmp_win->iswinbox && chwin) {
2835 int x, y;
2836 TwmWindow *wtmp;
2838 Event.xbutton.x, Event.xbutton.y,
2839 &x, &y, &chwin);
2840 if(chwin && (wtmp = GetTwmWindow(chwin))) {
2841 Event.xany.window = chwin;
2842 Event.xbutton.x = x;
2843 Event.xbutton.y = y;
2844 Tmp_win = wtmp;
2845 }
2846 }
2847#endif
2848 Context = C_WINDOW;
2849 }
2850 else if(Event.xbutton.subwindow
2851 && (Event.xbutton.subwindow == Tmp_win->title_w)) {
2852 Context = C_TITLE;
2853 }
2854 else {
2855 Context = C_FRAME;
2856 }
2857
2858 if(Scr->ClickToFocus && Tmp_win->wmhints->input) {
2860 }
2861 }
2862 else if(Tmp_win->iswspmgr ||
2863 (Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
2864 /*Context = C_WINDOW; probably a typo */
2866 }
2867 else if(Tmp_win->iconmanagerlist) {
2868 if((Event.xany.window == Tmp_win->iconmanagerlist->icon) ||
2869 (Event.xany.window == Tmp_win->iconmanagerlist->w)) {
2870 Tmp_win->iconmanagerlist->down = true;
2871 if(Scr->Highlight) {
2873 }
2876 }
2877 }
2878 }
2879
2880 /* this section of code checks to see if we were in the middle of
2881 * a command executed from a menu
2882 */
2883 if(RootFunction != 0) {
2884 if(Event.xany.window == Scr->Root) {
2885 int x, y;
2886
2887 /* if the window was the Root, we don't know for sure it
2888 * it was the root. We must check to see if it happened to be
2889 * inside of a client that was getting button press events.
2890 */
2891 XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
2892 Event.xbutton.x,
2893 Event.xbutton.y,
2894 &x, &y, &Event.xany.window);
2895
2896 if(Event.xany.window != 0 &&
2897 (Tmp_win = GetTwmWindow(Event.xany.window))) {
2898#ifdef WINBOX
2899 if(Tmp_win->iswinbox) {
2900 Window win;
2901 XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
2902 x, y, &x, &y, &win);
2903 XTranslateCoordinates(dpy, Event.xany.window, win,
2904 x, y, &x, &y, &win);
2905 if(win != 0) {
2906 Event.xany.window = win;
2907 }
2908 }
2909#endif
2910 }
2911 if(Event.xany.window == 0 ||
2912 !(Tmp_win = GetTwmWindow(Event.xany.window))) {
2913 RootFunction = 0;
2914 XBell(dpy, 0);
2915 return;
2916 }
2917 XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
2918 Event.xbutton.x,
2919 Event.xbutton.y,
2920 &x, &y, &JunkChild);
2921
2922 Event.xbutton.x = x;
2923 Event.xbutton.y = y;
2924 Context = C_WINDOW;
2925 }
2926 else if(mr != NULL) {
2927 RootFunction = 0;
2928 XBell(dpy, 0);
2929 return;
2930 }
2931
2932 /* make sure we are not trying to move an identify window */
2933 if(Event.xany.window != Scr->InfoWindow.win) {
2934 /*
2935 * X-ref comment at top of file about Action; this is where
2936 * we need to use its broader lifespan.
2937 */
2939 Tmp_win, &Event, Context, false);
2940 }
2941
2942 RootFunction = 0;
2943 return;
2944 }
2945
2947
2948 /* if we get to here, we have to execute a function or pop up a
2949 * menu
2950 */
2951 modifier = (Event.xbutton.state | AlternateKeymap) & mods_used;
2953 if(AlternateKeymap) {
2956 AlternateKeymap = 0;
2957 }
2958 if((Context == C_NO_CONTEXT) || (Context == C_IDENTIFY)) {
2959 return;
2960 }
2961
2962 RootFunction = 0;
2963
2964 /* see if there already is a key defined for this context */
2965 for(tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
2966 if((tmp->num == Event.xbutton.button) &&
2967 (tmp->cont == Context) && (tmp->mods == modifier)) {
2968 break;
2969 }
2970 }
2971 if(tmp) {
2972 func = tmp->func;
2973 switch(func) {
2974 /*
2975 * f.menu isn't invoked, it's handle magically. Other funcs
2976 * we just invoke. X-ref the f.menu handler for details.
2977 */
2978 case F_MENU :
2979 do_menu(tmp->menu, (Window) None);
2980 break;
2981
2982 default :
2983 if(func != 0) {
2984 Action = tmp->item ? tmp->item->action : NULL;
2985#ifdef EWMH_DESKTOP_ROOT
2986 if(Context == C_ROOT && Tmp_win != NULL) {
2987 Context = C_WINDOW;
2988 fprintf(stderr, "HandleButtonPress: wt_Desktop -> C_WINDOW\n");
2989 }
2990#endif /* EWMH */
2991 ExecuteFunction(func,
2992 Action, Event.xany.window, Tmp_win, &Event, Context, false);
2993 }
2994 }
2995 }
2996 else {
2997 if(Tmp_win == Scr->currentvs->wsw->twm_win) {
2998 WMgrHandleButtonEvent(Scr->currentvs, &Event);
2999 return;
3000 }
3001 }
3002 if(Tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
3004 }
3005 else if(func == 0 && Scr->DefaultFunction.func != 0) {
3006 if(Scr->DefaultFunction.func == F_MENU) {
3007 do_menu(Scr->DefaultFunction.menu, (Window) None);
3008 }
3009 else {
3010 Action = Scr->DefaultFunction.item ?
3011 Scr->DefaultFunction.item->action : NULL;
3012 ExecuteFunction(Scr->DefaultFunction.func, Action,
3013 Event.xany.window, Tmp_win, &Event, Context, false);
3014 }
3015 }
3016}
3017
3018
3019/***********************************************************************
3020 *
3021 * Procedure:
3022 * HENQueueScanner - EnterNotify event q scanner
3023 *
3024 * Looks at the queued events and determines if any matching
3025 * LeaveNotify events or EnterEvents deriving from the
3026 * termination of a grab are behind this event to allow
3027 * skipping of unnecessary processing.
3028 *
3029 ***********************************************************************
3030 */
3031
3032typedef struct HENScanArgs {
3033 Window w; /* Window we are currently entering */
3034 Bool leaves; /* Any LeaveNotifies found for this window */
3035 Bool inferior; /* Was NotifyInferior the mode for LeaveNotify */
3036 Bool enters; /* Any EnterNotify events with NotifyUngrab */
3038
3039/* ARGSUSED*/
3041{
3042 HENScanArgs *args = (void *)_args;
3043
3044 if(ev->type == LeaveNotify) {
3045 if(ev->xcrossing.window == args->w &&
3046 ev->xcrossing.mode == NotifyNormal) {
3047 args->leaves = True;
3048 /*
3049 * Only the last event found matters for the Inferior field.
3050 */
3051 args->inferior =
3052 (ev->xcrossing.detail == NotifyInferior);
3053 }
3054 }
3055 else if(ev->type == EnterNotify) {
3056 if(ev->xcrossing.mode == NotifyUngrab) {
3057 args->enters = True;
3058 }
3059 }
3060
3061 return (False);
3062}
3063
3064
3065/***********************************************************************
3066 *
3067 * Procedure:
3068 * HandleEnterNotify - EnterNotify event handler
3069 *
3070 ***********************************************************************
3071 */
3072
3074{
3075 MenuRoot *mr, *tmp;
3076 XEnterWindowEvent *ewp = &Event.xcrossing;
3078 XEvent dummy;
3079 VirtualScreen *vs;
3080
3081 /*
3082 * if we aren't in the middle of menu processing
3083 */
3084 if(!ActiveMenu) {
3085 /*
3086 * We're not interested in pseudo Enter/Leave events generated
3087 * from grab initiations.
3088 */
3089 if(ewp->mode == NotifyGrab) {
3090 return;
3091 }
3092
3093 /*
3094 * Scan for Leave and Enter Notify events to see if we can avoid some
3095 * unnecessary processing.
3096 */
3097 scanArgs.w = ewp->window;
3098 scanArgs.leaves = scanArgs.enters = False;
3100
3101 /*
3102 * if entering root window, restore twm default colormap so that
3103 * titlebars are legible
3104 */
3105 if(ewp->window == Scr->Root) {
3107 int focus_rev;
3108
3109 if(!scanArgs.leaves && !scanArgs.enters) {
3110 InstallColormaps(EnterNotify, &Scr->RootColormaps);
3111 }
3112 if(! Scr->FocusRoot) {
3113 return;
3114 }
3116 if((forus_ret != PointerRoot) && (forus_ret != None)) {
3117 SetFocus(NULL, Event.xcrossing.time);
3118 }
3119 return;
3120 }
3121 for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
3122 if(ewp->window == vs->window) {
3123 Scr->Root = vs->window;
3124#ifdef CAPTIVE
3125 Scr->rootx = Scr->crootx + vs->x;
3126 Scr->rooty = Scr->crooty + vs->y;
3127#else
3128 Scr->rootx = vs->x;
3129 Scr->rooty = vs->y;
3130#endif
3131 Scr->rootw = vs->w;
3132 Scr->rooth = vs->h;
3133 Scr->currentvs = vs;
3134#if 0
3135 fprintf(stderr, "entering new vs : %p, 0x%lx, %d, %d, %d, %d\n",
3136 vs, Scr->Root, vs->x, vs->y, vs->w, vs->h);
3137#endif
3138 return;
3139 }
3140 }
3141
3142 /* Handle RaiseDelay, if any.....
3143 */
3144 if(RaiseDelay > 0) {
3145 if(Tmp_win && Tmp_win->auto_raise &&
3147 Tmp_win->iconmanagerlist->w != ewp->window)) {
3149 static struct timeval tout, timeout = {0, 12500};
3150
3152 (XPointer *)&cwin) == XCNOENT) {
3153 cwin = NULL;
3154 }
3155
3156 if((ewp->detail != NotifyInferior
3157 || Tmp_win->frame == ewp->window)
3158 && (!cwin || cwin->visibility != VisibilityUnobscured)) {
3159 int x, y, px, py, d, i;
3160 Window w;
3161
3162 XQueryPointer(dpy, Scr->Root, &w, &w, &px, &py,
3163 &d, &d, (unsigned int *)&d);
3164
3165 /* The granularity of RaiseDelay is about 25 ms.
3166 * The timeout variable is set to 12.5 ms since we
3167 * pass this way twice each time a twm window is
3168 * entered.
3169 */
3170 for(i = 25; i < RaiseDelay; i += 25) {
3171 tout = timeout;
3172 select(0, NULL, NULL, NULL, &tout);
3173 /* Did we leave this window already? */
3174 scanArgs.w = ewp->window;
3175 scanArgs.leaves = scanArgs.enters = False;
3177 (void *) &scanArgs);
3178 if(scanArgs.leaves && !scanArgs.inferior) {
3179 return;
3180 }
3181
3182 XQueryPointer(dpy, Scr->Root, &w, &w, &x, &y,
3183 &d, &d, (unsigned int *)&d);
3184
3185 /* Has the pointer moved? If so reset the loop cnt.
3186 * We want the pointer to be still for RaiseDelay
3187 * milliseconds before terminating the loop
3188 */
3189 if(x != px || y != py) {
3190 i = 0;
3191 px = x;
3192 py = y;
3193 }
3194 }
3195 }
3196 }
3197
3198 /*
3199 * Scan for Leave and Enter Notify events to see if we can avoid some
3200 * unnecessary processing.
3201 */
3202 scanArgs.w = ewp->window;
3203 scanArgs.leaves = scanArgs.enters = False;
3205
3206 /*
3207 * if entering root window, restore twm default colormap so that
3208 * titlebars are legible
3209 */
3210 if(ewp->window == Scr->Root) {
3211 if(!scanArgs.leaves && !scanArgs.enters) {
3212 InstallColormaps(EnterNotify, &Scr->RootColormaps);
3213 }
3214 return;
3215 }
3216 }
3217 /* End of RaiseDelay modification. */
3218
3219 /*
3220 * if we have an event for a specific one of our windows
3221 */
3222 if(Tmp_win) {
3223 /*
3224 * If currently in PointerRoot mode (indicated by FocusRoot), then
3225 * focus on this window
3226 */
3227 if(Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
3228 bool accinput;
3229
3230 if(Scr->ShrinkIconTitles &&
3231 Tmp_win->icon &&
3232 ewp->window == Tmp_win->icon->w &&
3233 ewp->detail != NotifyInferior) {
3234 if(Scr->AutoRaiseIcons) {
3236 }
3238 return;
3239 }
3240
3243 }
3244
3245 accinput = Tmp_win->mapped && Tmp_win->wmhints->input;
3247 ewp->window == Tmp_win->iconmanagerlist->w &&
3248 !accinput &&
3252 CurrentTime);
3253 return;
3254 }
3255
3256 if(Tmp_win->mapped) {
3257 /*
3258 * unhighlight old focus window
3259 */
3260
3261 /*
3262 * If entering the frame or the icon manager, then do
3263 * "window activation things":
3264 *
3265 * 1. <highlighting is not done here any more>
3266 * 2. install frame colormap
3267 * 3. <frame and highlight border not set here>
3268 * 4. focus on client window to forward typing
3269 * 4a. same as 4 but for icon mgr w/with NoTitleFocus
3270 * 5. send WM_TAKE_FOCUS if requested
3271 */
3272 if(Scr->BorderCursors && ewp->window == Tmp_win->frame) {
3273 SetBorderCursor(Tmp_win, ewp->x, ewp->y);
3274 }
3275 if(ewp->window == Tmp_win->frame ||
3276 (Scr->IconManagerFocus &&
3278 ewp->window == Tmp_win->iconmanagerlist->w)) {
3279
3280 if(!scanArgs.leaves && !scanArgs.enters) {
3282 &Scr->RootColormaps);
3283 }
3284
3285 /*
3286 * Event is in the frame or the icon mgr:
3287 *
3288 * "4" -- TitleFocus is set: windows should get
3289 * focus as long as they accept input.
3290 *
3291 * "4a" - If TitleFocus is not set, windows should get
3292 * the focus if the event was in the icon mgr
3293 * (as long as they accept input).
3294 *
3295 */
3296
3297 /* If the window takes input... */
3298 if(Tmp_win->wmhints->input) {
3299
3300 /* if 4 or 4a, focus on the window */
3301 if(Scr->TitleFocus ||
3303 (Tmp_win->iconmanagerlist->w == ewp->window))) {
3304 SetFocus(Tmp_win, ewp->time);
3305 }
3306 }
3307
3308 if(Scr->TitleFocus &&
3309 (Tmp_win->protocols & DoesWmTakeFocus)) { /* 5 */
3310
3311 /* for both locally or globally active */
3313 }
3314 else if(!Scr->TitleFocus
3315 && Tmp_win->wmhints->input
3316 && Event.xcrossing.focus) {
3318 }
3319
3320 }
3321 else if(ewp->window == Tmp_win->w) {
3322 /*
3323 * If we are entering the application window, install
3324 * its colormap(s).
3325 */
3326 if(Scr->BorderCursors) {
3327 SetBorderCursor(Tmp_win, -1000, -1000);
3328 }
3329 if(!scanArgs.leaves || scanArgs.inferior) {
3331 }
3332
3333 if(Event.xcrossing.focus) {
3335 }
3336
3337 /* must deal with WM_TAKE_FOCUS clients now, if
3338 we're not in TitleFocus mode */
3339
3340 if(!(Scr->TitleFocus) &&
3342
3343 /* locally active clients need help from WM
3344 to get the input focus */
3345
3346 if(Tmp_win->wmhints->input) {
3347 SetFocus(Tmp_win, ewp->time);
3348 }
3349
3350 /* for both locally & globally active clnts */
3351
3353 }
3354 }
3355 } /* end if Tmp_win->mapped */
3356 if(ewp->window == Tmp_win->wmhints->icon_window &&
3357 (!scanArgs.leaves || scanArgs.inferior)) {
3359 }
3360 } /* end if FocusRoot */
3361 else if(Scr->BorderCursors && (ewp->window == Tmp_win->w)) {
3362 SetBorderCursor(Tmp_win, -1000, -1000);
3363 }
3364 /*
3365 * If this window is to be autoraised, mark it so
3366 */
3367 if(Tmp_win->auto_raise) {
3369 if(enter_flag == false) {
3371 }
3372 }
3373 else if(enter_flag && raise_win == Tmp_win) {
3375 }
3376 /*
3377 * set ring leader
3378 */
3380 Scr->RingLeader = Tmp_win;
3381 }
3382 XSync(dpy, 0);
3383 return;
3384 } /* end if Tmp_win */
3385 } /* end if !ActiveMenu */
3386
3387 /*
3388 * Find the menu that we are dealing with now; punt if unknown
3389 */
3390 if(XFindContext(dpy, ewp->window, MenuContext, (XPointer *)&mr) != XCSUCCESS) {
3391 return;
3392 }
3393
3394 if(! ActiveMenu && mr->pinned && (RootFunction == 0)) {
3395 PopUpMenu(mr, 0, 0, false);
3396 Context = C_ROOT;
3397 UpdateMenu();
3398 return;
3399 }
3400 mr->entered = true;
3401 if(RootFunction == 0) {
3402 for(tmp = ActiveMenu; tmp; tmp = tmp->prev) {
3403 if(tmp == mr) {
3404 break;
3405 }
3406 }
3407 if(! tmp) {
3408 return;
3409 }
3410
3411 for(tmp = ActiveMenu; tmp != mr; tmp = tmp->prev) {
3412 if(tmp->pinned) {
3413 break;
3414 }
3415 HideMenu(tmp);
3416 MenuDepth--;
3417 }
3419
3420 if(ActiveItem) {
3421 ActiveItem->state = 0;
3423 }
3424 ActiveItem = NULL;
3425 ActiveMenu = mr;
3426 if(1/*Scr->StayUpMenus*/) {
3427 int i, x, y, x_root, y_root, entry;
3428 MenuItem *mi;
3429
3431 &x, &y, &JunkMask);
3432 if((x > 0) && (y > 0) && (x < ActiveMenu->width) && (y < ActiveMenu->height)) {
3433 entry = y / Scr->EntryHeight;
3434 for(i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi = mi->next) {
3435 if(i == entry) {
3436 break;
3437 }
3438 }
3439 if(mi) {
3440 ActiveItem = mi;
3441 ActiveItem->state = 1;
3443 }
3444 }
3445 }
3446 if(ActiveMenu->pinned) {
3448 }
3449 }
3450 return;
3451}
3452
3453
3454/***********************************************************************
3455 *
3456 * Procedure:
3457 * HLNQueueScanner - LeaveNotify event q scanner
3458 *
3459 * Looks at the queued events and determines if any
3460 * EnterNotify events are behind this event to allow
3461 * skipping of unnecessary processing.
3462 *
3463 ***********************************************************************
3464 */
3465
3466typedef struct HLNScanArgs {
3467 Window w; /* The window getting the LeaveNotify */
3468 Bool enters; /* Any EnterNotify event at all */
3469 Bool matches; /* Any matching EnterNotify events */
3471
3472/* ARGSUSED*/
3474{
3475 HLNScanArgs *args = (void *)_args;
3476
3477 if(ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
3478 args->enters = True;
3479 if(ev->xcrossing.window == args->w) {
3480 args->matches = True;
3481 }
3482 }
3483
3484 return (False);
3485}
3486
3487
3488/***********************************************************************
3489 *
3490 * Procedure:
3491 * HandleLeaveNotify - LeaveNotify event handler
3492 *
3493 ***********************************************************************
3494 */
3495
3497{
3498 bool inicon;
3499
3501 && (Event.xcrossing.window == ActiveMenu->w)) {
3502 PopDownMenu();
3503 }
3504
3505 if(Tmp_win == NULL) {
3506 /* No window to be Leave'ing, so nothing much to do... */
3507 return;
3508 }
3509
3510 /*
3511 * We're not interested in pseudo Enter/Leave events generated
3512 * from grab initiations and terminations.
3513 */
3514 if(Event.xcrossing.mode != NotifyNormal) {
3515 return;
3516 }
3517
3518 if(Scr->ShrinkIconTitles &&
3519 Tmp_win->icon &&
3520 Event.xcrossing.window == Tmp_win->icon->w &&
3521 Event.xcrossing.detail != NotifyInferior) {
3523 return;
3524 }
3525
3526 // Are we Leave'ing the icon manager entry for the Tmp_win in
3527 // question, or some other part of the window itself?
3529 Tmp_win->iconmanagerlist->w == Event.xcrossing.window);
3530
3531 if(Scr->RingLeader && Scr->RingLeader == Tmp_win &&
3532 (Event.xcrossing.detail != NotifyInferior &&
3533 Event.xcrossing.window != Tmp_win->w)) {
3534#ifdef DEBUG
3536 "HandleLeaveNotify: Event.xcrossing.window %x != Tmp_win->w %x\n",
3537 Event.xcrossing.window, Tmp_win->w);
3538#endif
3539 if(!inicon) {
3540 if(Event.xcrossing.window != Tmp_win->frame /*was: Tmp_win->mapped*/) {
3541 Tmp_win->ring.cursor_valid = false;
3542#ifdef DEBUG
3543 fprintf(stderr, "HandleLeaveNotify: cursor_valid = false\n");
3544#endif
3545 }
3546 else { /* Event.xcrossing.window == Tmp_win->frame */
3547 Tmp_win->ring.cursor_valid = true;
3548 Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
3549 Tmp_win->frame_x);
3550 Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
3551 Tmp_win->frame_y);
3552#ifdef DEBUG
3554 "HandleLeaveNotify: cursor_valid = true; x = %d (%d-%d), y = %d (%d-%d)\n",
3555 Tmp_win->ring.curs_x, Event.xcrossing.x_root, Tmp_win->frame_x,
3556 Tmp_win->ring.curs_y, Event.xcrossing.y_root, Tmp_win->frame_y);
3557#endif
3558 }
3559 }
3560 Scr->RingLeader = NULL;
3561 }
3562
3563
3564 /*
3565 * Are we moving focus based on the leave? There are 2 steps to
3566 * this:
3567 * - Scr->FocusRoot is our "are we automatically changing focus
3568 * based on the leave" flag. This gets unset when ClickToFocus
3569 * is config'd or a window is f.focus'd.
3570 * - Then we check the detail for the focus leaving. We're only
3571 * getting here for normal entry/exits. Most cases outside of
3572 * the icon manager peek ahead in the event queue for any
3573 * Enter's, and don't do anything if there are; if there were,
3574 * we'd be moving the focus when we get them, so no point doing
3575 * it twice. So the remainder here assumes there aren't any
3576 * Enters waiting.
3577 *
3578 * See
3579 * <https://www.x.org/releases/X11R7.7/doc/libX11/libX11/libX11.html#Normal_EntryExit_Events>
3580 * for details of the cases. So, when do we want to un-set the
3581 * focus? Let's look at each doc'd value...
3582 * - NotifyAncestor means we're leaving a subwindow for its
3583 * parent. That means the root, so, yep, we want to yield
3584 * focus up to it.
3585 * - NotifyNonLinear means we're leaving a window for something
3586 * that isn't a parent or child. So we should probably yield
3587 * focus in this case too.
3588 * - NotifyInferior means we're leaving a window for a
3589 * subwindow of it. From the WM perspective, that means
3590 * we're leaving focus where it was.
3591 * - NotifyVirtual means we're in the middle of an ascending
3592 * sequence. Nothing to do; the Ancestor handling already
3593 * did the job.
3594 * - NotifyNonLinearVirtual is another "in the middle" case, so
3595 * we skip handling there too; the endpoints will do
3596 * whatever's necessary.
3597 */
3598 if(Scr->FocusRoot
3599 && Event.xcrossing.detail != NotifyInferior
3600 && Event.xcrossing.detail != NotifyVirtual
3601 && Event.xcrossing.detail != NotifyNonlinearVirtual
3602 ) {
3604 XEvent dummy;
3605
3606 /*
3607 * Scan for EnterNotify events to see if we can avoid some
3608 * unnecessary processing.
3609 */
3610 scanArgs.w = Event.xcrossing.window;
3611 scanArgs.enters = scanArgs.matches = False;
3613 (char *) &scanArgs);
3614
3615 if((inicon && Scr->IconManagerFocus)
3616 || (Event.xcrossing.window == Tmp_win->frame
3617 && !scanArgs.matches)
3618 ) {
3619 // Defocusing window because we moved out of its entry in an
3620 // icon manager, or because we moved out of its frame.
3621
3622 // Nothing to do if we were in the icon manager, and the
3623 // window's either unmapped or doesn't accept input. XXX Is
3624 // the inicon flag needed here? If it's not mapped, we
3625 // presumably couldn't have gotten a Leave on its frame
3626 // anyway, and if it's not accepting input, we probably don't
3627 // need to focus out anyway? Left conditional because this
3628 // matches historical behavior prior to some rework here, but
3629 // revisit.
3630 if(inicon && (!Tmp_win->mapped || !Tmp_win->wmhints->input)) {
3631 return;
3632 }
3633
3634 // Shift away focus
3635 if(Scr->TitleFocus || Tmp_win->protocols & DoesWmTakeFocus) {
3636 SetFocus(NULL, Event.xcrossing.time);
3637 }
3638
3639 // If we're in the icon manager, we need to take a FocusOut
3640 // event for the window, since it wouldn't have gotten one.
3641 // If we're in the frame, we fake one anyway as historical
3642 // code says "pretend there was a focus out as sometimes we
3643 // don't get one".
3644 if(Event.xcrossing.focus) {
3646 }
3647 }
3648 else if(Event.xcrossing.window == Tmp_win->w && !scanArgs.enters) {
3649 // Flipping colormaps around because we moved out of the
3650 // window.
3651 InstallColormaps(LeaveNotify, &Scr->RootColormaps);
3652 }
3653 }
3654
3655 /* Autolower modification. */
3656 if(Tmp_win->auto_lower) {
3658 if(leave_flag == false) {
3660 }
3661 }
3662 else if(leave_flag && lower_win == Tmp_win) {
3664 }
3665
3666 XSync(dpy, 0);
3667 return;
3668}
3669
3670
3671/***********************************************************************
3672 *
3673 * Procedure:
3674 * HandleConfigureRequest - ConfigureRequest event handler
3675 *
3676 ***********************************************************************
3677 */
3678
3680{
3682 unsigned long xwcm;
3683 int x, y, width, height, bw;
3684 int gravx, gravy;
3685 XConfigureRequestEvent *cre = &Event.xconfigurerequest;
3686 bool sendEvent;
3687
3688#ifdef DEBUG_EVENTS
3689 fprintf(stderr, "ConfigureRequest\n");
3690 if(cre->value_mask & CWX) {
3691 fprintf(stderr, " x = %d\n", cre->x);
3692 }
3693 if(cre->value_mask & CWY) {
3694 fprintf(stderr, " y = %d\n", cre->y);
3695 }
3696 if(cre->value_mask & CWWidth) {
3697 fprintf(stderr, " width = %d\n", cre->width);
3698 }
3699 if(cre->value_mask & CWHeight) {
3700 fprintf(stderr, " height = %d\n", cre->height);
3701 }
3702 if(cre->value_mask & CWSibling) {
3703 fprintf(stderr, " above = 0x%x\n", (unsigned)cre->above);
3704 }
3705 if(cre->value_mask & CWStackMode) {
3706 fprintf(stderr, " stack = %d\n", cre->detail);
3707 }
3708#endif
3709
3710 /*
3711 * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
3712 * be wrong
3713 */
3714 Event.xany.window = cre->window; /* mash parent field */
3715 Tmp_win = GetTwmWindow(cre->window);
3716
3717 /*
3718 * According to the July 27, 1988 ICCCM draft, we should ignore size and
3719 * position fields in the WM_NORMAL_HINTS property when we map a window.
3720 * Instead, we'll read the current geometry. Therefore, we should respond
3721 * to configuration requests for windows which have never been mapped.
3722 */
3723 if(!Tmp_win || (Tmp_win->icon && (Tmp_win->icon->w == cre->window))) {
3724 xwcm = cre->value_mask &
3726 xwc.x = cre->x;
3727 xwc.y = cre->y;
3728 xwc.width = cre->width;
3729 xwc.height = cre->height;
3730 xwc.border_width = cre->border_width;
3731 XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
3732 return;
3733 }
3734
3735 sendEvent = false;
3736 if((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
3738
3739 if(cre->value_mask & CWSibling) {
3740 otherwin = GetTwmWindow(cre->above);
3741 if(otherwin) {
3743 }
3744 else {
3745 fprintf(stderr, "XConfigureRequest: unkown otherwin\n");
3746 }
3747 }
3748 else {
3749 switch(cre->detail) {
3750 case TopIf:
3751 case Above:
3753 break;
3754 case BottomIf:
3755 case Below:
3757 break;
3758 case Opposite:
3760 break;
3761 default:
3762 ;
3763 }
3764 }
3765 sendEvent = true;
3766 }
3767
3768
3769 /* Don't modify frame_XXX fields before calling SetupWindow! */
3770 x = Tmp_win->frame_x;
3771 y = Tmp_win->frame_y;
3772 width = Tmp_win->frame_width;
3773 height = Tmp_win->frame_height;
3774 bw = Tmp_win->frame_bw;
3775
3776 /*
3777 * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
3778 * configure request are for the upper-left outer corner of the window.
3779 * This means that we need to adjust for the additional title height as
3780 * well as for any border width changes that we decide to allow. The
3781 * current window gravity is to be used in computing the adjustments, just
3782 * as when initially locating the window. Note that if we do decide to
3783 * allow border width changes, we will need to send the synthetic
3784 * ConfigureNotify event.
3785 */
3787
3788 if(cre->value_mask & CWBorderWidth) {
3789 int bwdelta = cre->border_width - Tmp_win->old_bw; /* posit growth */
3790 if(bwdelta && Scr->ClientBorderWidth) { /* if change allowed */
3791 x += gravx * bwdelta; /* change default values only */
3792 y += gravy * bwdelta; /* ditto */
3793 bw = cre->border_width;
3794 if(Tmp_win->title_height) {
3795 height += bwdelta;
3796 }
3797 x += (gravx < 0) ? bwdelta : -bwdelta;
3798 y += (gravy < 0) ? bwdelta : -bwdelta;
3799 }
3800 Tmp_win->old_bw = cre->border_width; /* for restoring */
3801 }
3802
3803 if((cre->value_mask & CWX)) { /* override even if border change */
3804 x = cre->x - bw;
3805 x -= ((gravx < 0) ? 0 : Tmp_win->frame_bw3D);
3806 }
3807 if((cre->value_mask & CWY)) {
3808 y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
3809 y -= ((gravy < 0) ? 0 : Tmp_win->frame_bw3D);
3810 }
3811
3812 if(cre->value_mask & CWWidth) {
3813 width = cre->width + 2 * Tmp_win->frame_bw3D;
3814 }
3815 if(cre->value_mask & CWHeight) {
3816 height = cre->height + Tmp_win->title_height + 2 * Tmp_win->frame_bw3D;
3817 }
3818
3819 if(width != Tmp_win->frame_width || height != Tmp_win->frame_height) {
3820 unzoom(Tmp_win);
3821 }
3822
3823 /* Workaround for Java 1.4 bug that freezes the application whenever
3824 * a new window is displayed. (When UsePPosition is on and either
3825 * UseThreeDBorders or BorderWidth 0 is set.)
3826 */
3827 if(!bw) {
3828 sendEvent = true;
3829 }
3830
3831 /*
3832 * SetupWindow (x,y) are the location of the upper-left outer corner and
3833 * are passed directly to XMoveResizeWindow (frame). The (width,height)
3834 * are the inner size of the frame. The inner width is the same as the
3835 * requested client window width; the inner height is the same as the
3836 * requested client window height plus any title bar slop.
3837 */
3838#ifdef DEBUG_EVENTS
3839 fprintf(stderr, "SetupFrame(x=%d, y=%d, width=%d, height=%d, bw=%d)\n",
3840 x, y, width, height, bw);
3841#endif
3842 SetupFrame(Tmp_win, x, y, width, height, bw, sendEvent);
3843}
3844
3845
3846/***********************************************************************
3847 *
3848 * Procedure:
3849 * HandleShapeNotify - shape notification event handler
3850 *
3851 ***********************************************************************
3852 */
3853void
3855{
3857
3858 if(Tmp_win == NULL) {
3859 return;
3860 }
3861 if(sev->kind != ShapeBounding) {
3862 return;
3863 }
3864 if(!Tmp_win->wShaped && sev->shaped) {
3866 ShapeSet);
3867 }
3868 Tmp_win->wShaped = sev->shaped;
3870}
3871
3872/***********************************************************************
3873 *
3874 * Procedure:
3875 * HandleSelectionClear - selection lost event handler
3876 *
3877 ***********************************************************************
3878 */
3879#ifdef EWMH
3880void
3882{
3884
3885 if(sev->window == Scr->icccm_Window) {
3887 }
3888}
3889#endif
3890
3891
3892/***********************************************************************
3893 *
3894 * Procedure:
3895 * HandleUnknown - unknown event handler
3896 *
3897 ***********************************************************************
3898 */
3899
3901{
3902#ifdef DEBUG_EVENTS
3903 fprintf(stderr, "HandleUnknown: Event.type = %d\n", Event.type);
3904#endif
3905}
3906
3907
3908static void flush_expose(Window w)
3909{
3910 XEvent dummy;
3911
3912 while(XCheckTypedWindowEvent(dpy, w, Expose, &dummy)) {
3913 /* nada */;
3914 }
3915}
3916
3917
3918/* Util func used a few times above */
3919static void
static int PlaceX
Definition add_window.c:82
char NoName[]
Definition add_window.c:89
TwmWindow * AddWindow(Window w, AWType wtype, IconMgr *iconp, VirtualScreen *vs)
Definition add_window.c:113
@ AWT_NORMAL
Definition add_window.h:24
int Animating
Definition animate.c:30
bool MaybeAnimate
Definition animate.c:33
void set_last_window(WorkSpace *current)
bool ColortableThrashing
Definition event_core.c:90
void FetchWmColormapWindows(TwmWindow *tmp)
Definition colormaps.c:354
bool InstallWindowColormaps(int type, TwmWindow *tmp)
Definition colormaps.c:39
void free_cwins(TwmWindow *tmp)
Definition colormaps.c:676
void RemoveRGBColormap(Atom a)
Definition colormaps.c:605
bool InstallColormaps(int type, Colormaps *cmaps)
Definition colormaps.c:51
void UninstallRootColormap(void)
Definition colormaps.c:213
TwmColormap * CreateTwmColormap(Colormap c)
Definition colormaps.c:246
void InsertRGBColormap(Atom a, XStandardColormap *maps, int nmaps, bool replace)
Definition colormaps.c:555
bool RestartPreviousState
Definition ctwm_main.c:151
XContext MenuContext
Definition ctwm_main.c:120
#define C_WORKSPACE
Definition ctwm.h:84
int JunkY
Definition ctwm.h:358
Cursor LeftButt
Definition ctwm_main.c:117
#define OCCUPY(w, b)
Definition ctwm.h:369
#define C_IDENTIFY
Definition ctwm.h:82
#define CM_INSTALLED
Definition ctwm.h:267
bool HandlingEvents
Definition ctwm_main.c:131
unsigned int JunkBW
Definition ctwm.h:359
unsigned int JunkWidth
Definition ctwm_main.c:144
Window JunkRoot
Definition ctwm_main.c:142
XContext ScreenContext
Definition ctwm_main.c:121
int JunkX
Definition ctwm_main.c:143
#define C_NAME
Definition ctwm.h:81
Display * dpy
Definition ctwm_main.c:84
#define C_ROOT
Definition ctwm.h:78
XContext TwmContext
Definition ctwm_main.c:119
#define C_ALTERNATE
Definition ctwm.h:83
unsigned int JunkMask
Definition ctwm.h:359
#define C_TITLE
Definition ctwm.h:76
#define C_WINDOW
Definition ctwm.h:75
XContext ColormapContext
Definition ctwm_main.c:122
Cursor MiddleButt
Definition ctwm_main.c:116
#define FB(fix_fore, fix_back)
Definition ctwm.h:119
#define C_FRAME
Definition ctwm.h:79
#define C_ICONMGR
Definition ctwm.h:80
Window JunkChild
Definition ctwm.h:357
#define DoesWmTakeFocus
Definition ctwm.h:322
Window ResizeWindow
Definition ctwm_main.c:85
#define C_NO_CONTEXT
Definition ctwm.h:74
unsigned int JunkHeight
Definition ctwm.h:359
Cursor RightButt
Definition ctwm_main.c:115
#define C_ICON
Definition ctwm.h:77
#define CM_INSTALLABLE
Definition ctwm.h:266
unsigned int JunkDepth
Definition ctwm.h:359
#define Scr
void RestoreWinConfig(TwmWindow *tmp)
Put a window back where it should be if we don't (any longer) control it and reparent it back up to t...
unsigned int DragBW
Definition event_core.c:75
int CurrentDragY
Definition event_core.c:77
int CurrentDragX
Definition event_core.c:76
bool Cancel
Definition event_core.c:94
int origDragX
Definition event_core.c:69
unsigned int DragWidth
Definition event_core.c:73
bool leave_flag
Definition event_core.c:83
TwmWindow * lower_win
Definition event_core.c:84
unsigned int DragHeight
Definition event_core.c:74
int origDragY
Definition event_core.c:70
bool enter_flag
Definition event_core.c:82
TwmWindow * raise_win
Definition event_core.c:84
int DragY
Definition event_core.c:72
TwmWindow * Tmp_win
Definition event_core.c:91
TwmWindow * enter_win
Definition event_core.c:84
XEvent Event
Definition event_core.c:66
event_proc EventHandler[256]
Definition event_core.c:64
int ButtonPressed
Definition event_core.c:93
Window DragWindow
Definition event_core.c:68
int DragX
Definition event_core.c:71
int Context
Definition event_core.c:65
TwmWindow * leave_win
Definition event_core.c:84
void HandleVisibilityNotify(void)
void HandleKeyRelease(void)
void HandleEnterNotify(void)
void HandleUnmapNotify(void)
static unsigned int set_mask_ignore(unsigned int modifier)
static void HandleFocusOut(void)
void HandleMapRequest(void)
void HandleClientMessage(void)
void HandleConfigureRequest(void)
void HandlePropertyNotify(void)
void HandleFocusChange(void)
void HandleCreateNotify(void)
static void HandleFocusIn(void)
static XEvent * LastFocusEvent(Window w, XEvent *first)
void HandleMapNotify(void)
static void flush_expose(Window w)
static void SendTakeFocusMessage(TwmWindow *tmp, Time timestamp)
void HandleDestroyNotify(void)
void HandleCirculateNotify(void)
static void remove_window_from_ring(TwmWindow *tmp)
void HandleKeyPress(void)
void HandleUnknown(void)
static void do_menu(MenuRoot *menu, Window w)
void HandleLeaveNotify(void)
void HandleButtonRelease(void)
void HandleShapeNotify(void)
void HandleButtonPress(void)
struct HLNScanArgs HLNScanArgs
static TwmWindow * ButtonWindow
void HandleColormapNotify(void)
static void do_key_menu(MenuRoot *menu, Window w)
void HandleMotionNotify(void)
void HandleExpose(void)
struct HENScanArgs HENScanArgs
static Bool HENQueueScanner(Display *display, XEvent *ev, char *_args)
static char * Action
#define MAX_NAME_LEN
static Bool HLNQueueScanner(Display *display, XEvent *ev, char *_args)
void SynthesiseFocusOut(Window w)
void SetRaiseWindow(TwmWindow *tmp)
Definition event_utils.c:42
void SynthesiseFocusIn(Window w)
void AutoLowerWindow(TwmWindow *tmp)
Definition event_utils.c:71
void AutoPopupMaybe(TwmWindow *tmp)
Definition event_utils.c:54
void FixRootEvent(XEvent *e)
void AutoRaiseWindow(TwmWindow *tmp)
Definition event_utils.c:27
void EwmhUnmapNotify(TwmWindow *twm_win)
Definition ewmh.c:1689
bool EwmhClientMessage(XClientMessageEvent *msg)
Definition ewmh.c:561
void EwmhSelectionClear(XSelectionClearEvent *sev)
Definition ewmh.c:546
int EwmhHandlePropertyNotify(XPropertyEvent *event, TwmWindow *twm_win)
Definition ewmh.c:1403
void EwmhAddClientWindow(TwmWindow *new_win)
Definition ewmh.c:1701
void EwmhDeleteClientWindow(TwmWindow *old_win)
Definition ewmh.c:1738
void EwmhSet_NET_WM_STATE(TwmWindow *twm_win, int changes)
Definition ewmh.c:2137
void EwmhSet_NET_CLIENT_LIST_STACKING(void)
Definition ewmh.c:1782
@ wt_Desktop
Definition ewmh.h:18
#define EWMH_STATE_ALL
Definition ewmh.h:43
void ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
Definition functions.c:99
bool WindowMoved
Definition functions.c:52
int RootFunction
Definition functions.c:45
@ MOVE_VERT
Definition functions.h:16
@ MOVE_NONE
Definition functions.h:15
@ MOVE_HORIZ
Definition functions.h:17
void draw_info_window(void)
CMoveDir ConstMoveDir
int frame_x
X position on screen of frame.
Window hilite_wl
Left hilite window in titlebar.
Window lolite_wl
Left lolite window in titlebar.
Window hilite_wr
Right hilite window in titlebar.
int frame_y
Y position on screen of frame.
Window frame
The X window for the overall frame.
Window lolite_wr
Right lolite window in titlebar.
int frame_bw
2d border width.
TBWindow * titlebuttons
Button windows in the titlebar.
unsigned int title_height
Height of the full title bar.
Window title_w
The title bar Window.
unsigned int frame_width
Width of frame.
Pixmap gray
Pixmap to which the border is set to when window isn't focused.
unsigned int frame_height
Height of frame.
int frame_bw3D
3d border width.
WList * DownIconManager
Definition iconmgr.c:54
void DrawIconManagerBorder(WList *tmp, bool fill)
Definition iconmgr.c:1050
void RemoveIconManager(TwmWindow *tmp_win)
Definition iconmgr.c:982
void ShowIconifiedIcon(TwmWindow *tmp_win)
Definition iconmgr.c:1294
void CurrentIconManagerEntry(WList *current)
Definition iconmgr.c:1030
void DrawIconManagerIconName(TwmWindow *tmp_win)
Definition iconmgr.c:1247
WList * AddIconManager(TwmWindow *tmp_win)
Definition iconmgr.c:697
void ReleaseIconImage(Icon *icon)
Definition icons.c:831
void DeleteIcon(Icon *icon)
Definition icons.c:814
void DeleteIconsList(TwmWindow *tmp_win)
Definition icons.c:782
void RedoIconName(TwmWindow *win)
Definition icons.c:1244
void ExpandIconTitle(TwmWindow *tmp_win)
Definition icons.c:1053
void IconDown(TwmWindow *tmp_win)
Definition icons.c:915
void ShrinkIconTitle(TwmWindow *tmp_win)
Definition icons.c:1021
void PaintIcon(TwmWindow *tmp_win)
Definition icons.c:967
int GetIconOffset(Icon *icon)
Definition icons.c:1128
@ match_net_wm_icon
Definition icons.h:22
@ match_icon_pixmap_hint
Definition icons.h:21
Image * AllocImage(void)
Definition image.c:158
void * LookInList(name_list *list_head, const char *name, XClassHint *class)
Definition list.c:101
int y
Definition menus.c:70
void HideMenu(MenuRoot *menu)
Definition menus.c:1476
bool menuFromFrameOrWindowOrTitlebar
Definition menus.c:60
void PaintMenu(MenuRoot *mr, XEvent *e)
Definition menus.c:419
int x
Definition menus.c:69
void MoveMenu(XEvent *eventp)
Definition menus.c:1538
MenuItem * ActiveItem
Definition menus.c:59
char * CurrentSelectedWorkspace
Definition menus.c:61
MenuRoot * ActiveMenu
Definition menus.c:58
void WarpCursorToDefaultEntry(MenuRoot *menu)
Definition menus.c:1626
bool PopUpMenu(MenuRoot *menu, int x, int y, bool center)
Definition menus.c:1130
void PaintEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
Definition menus.c:242
void PopDownMenu(void)
Definition menus.c:1442
bool AlternateContext
Definition menus.c:65
int MenuDepth
Definition menus.c:67
int AlternateKeymap
Definition menus.c:64
void UpdateMenu(void)
Definition menus.c:487
void OccupyHandleButtonEvent(XEvent *event)
Definition occupation.c:985
void RemoveFromWorkSpace(char *wname, TwmWindow *twm_win)
Definition occupation.c:309
unsigned int GetMaskFromProperty(unsigned char *_prop, unsigned long len)
void PaintOccupyWindow(void)
Definition occupation.c:954
void AddToWorkSpace(char *wname, TwmWindow *twm_win)
Definition occupation.c:283
void ChangeOccupation(TwmWindow *tmp_win, int newoccupation)
void OtpUnfocusWindow(TwmWindow *twm_win)
Unfocus a window.
Definition otp.c:1753
void OtpHandleCirculateNotify(VirtualScreen *vs, TwmWindow *twm_win, WinType wintype, int place)
Definition otp.c:877
void OtpLower(TwmWindow *twm_win, WinType wintype)
Definition otp.c:777
void OtpFocusWindow(TwmWindow *twm_win)
Focus a window.
Definition otp.c:1774
void OtpRemove(TwmWindow *twm_win, WinType wintype)
Definition otp.c:1094
void OtpForcePlacement(TwmWindow *twm_win, int where, TwmWindow *other_win)
Definition otp.c:990
bool OtpIsFocusDependent(TwmWindow *twm_win)
Definition otp.c:1883
void OtpRaise(TwmWindow *twm_win, WinType wintype)
Definition otp.c:763
void OtpRaiseLower(TwmWindow *twm_win, WinType wintype)
Definition otp.c:791
WinType
Definition otp.h:14
@ WinWin
Definition otp.h:14
@ IconWin
Definition otp.h:14
int RaiseDelay
Definition parse.c:94
static int len
Definition parse.c:75
unsigned int mods_used
Definition parse_yacc.c:30
Pixel back
Definition ctwm.h:141
Pixel fore
Definition ctwm.h:141
struct FuncKey * next
Definition menus.h:108
TwmWindow * twm_win
Definition iconmgr.h:45
Definition icons.h:26
int w_y
Definition icons.h:35
bool w_not_ours
Definition icons.h:45
ColorPair iconc
Definition icons.h:41
int height
Definition icons.h:39
Image * image
Definition icons.h:31
Window w
Definition icons.h:28
int w_x
Definition icons.h:34
Window bm_w
Definition icons.h:30
int width
Definition icons.h:38
Matchtype match
Definition icons.h:27
Definition image.h:9
Pixmap mask
Definition image.h:11
int height
Definition image.h:13
Pixmap pixmap
Definition image.h:10
int width
Definition image.h:12
bool state
Definition menus.h:60
struct MenuItem * next
Definition menus.h:49
short func
Definition menus.h:59
short item_num
Definition menus.h:57
char * action
Definition menus.h:54
short x
Definition menus.h:58
char * item
Definition menus.h:53
struct MenuRoot * sub
Definition menus.h:51
short height
Definition menus.h:78
Window shadow
Definition menus.h:75
short width
Definition menus.h:79
struct MenuItem * defaultitem
Definition menus.h:70
struct MenuRoot * prev
Definition menus.h:71
bool entered
Definition menus.h:82
struct MenuItem * first
Definition menus.h:67
struct MenuItem * lastactive
Definition menus.h:69
Window w
Definition menus.h:74
bool pinned
Definition menus.h:85
Window window
Definition ctwm.h:165
int state
Definition ctwm.h:259
char * ctwm_wm_icon_name
Icon name from override CTWM_WM_ICON_NAME property.
char * wm_name
Name from ICCCM WM_NAME property.
char * wm_icon_name
Icon name from WM_ICON_NAME property.
char * ctwm_wm_name
Name from override CTWM_WM_NAME property.
int curs_x
Stored cursor position in the window.
int curs_y
Stored cursor position in the window.
bool cursor_valid
Whether curs_x and curs_y are usable.
Info and control for every X Window we take over.
unsigned long protocols
Which protocols this window handles.
struct TwmWindow * next
Next TwmWindow on the Screen.
bool iswspmgr
This is a workspace manager window.
bool wShaped
This window is Shape'd.
bool isiconmgr
This is an icon manager window.
XWMHints * wmhints
Window manager hints.
Window w
The actual X Window handle.
bool auto_raise
Should we auto-raise this window ?
bool stackmode
Honor stackmode requests.
bool istransient
This is a transient window.
int old_bw
Original window border width before we took it over and made our own bordering.
struct TwmWindow::_ring ring
Window ring connectivity. "
char * name
Current window name. Points into TwmWindow::names.
bool auto_lower
Should we auto-lower this window ?
struct Icon * icon
The current icon.
bool squeeze_info_copied
Should ->squeeze_info be free()'d?
int occupation
Workspaces the window is in (bitmap)
SqueezeInfo * squeeze_info
Control info for title squeezing.
struct VirtualScreen * vs
Where the window is currently mapped (may be NULL)
bool mapped
Is the window mapped ?
bool icon_on
Is the icon visible.
XClassHint class
Window class info. From XGetClassHint().
Colormaps cmaps
colormaps for this application
struct WList * iconmanagerlist
List of the icon managers the window is in.
bool forced
Has had an icon forced upon it.
struct TwmWindow::_names names
Various sources of window/icon names. "
struct TwmWindow * prev
Previous TwmWindow on the Screen.
XWindowAttributes attr
Window attributes from XGetWindowAttributes()
bool UnmapByMovingFarAway
bool isicon
Is the window an icon now ?
bool squeezed
Is the window squeezed ?
struct VirtualScreen * next
Definition vscreen.h:12
struct WorkSpaceWindow * wsw
Definition vscreen.h:11
Window window
Definition vscreen.h:9
struct IconMgr * iconmgr
Definition iconmgr.h:22
Window icon
Definition iconmgr.h:24
bool down
Definition iconmgr.h:33
Window w
Definition iconmgr.h:23
WorkSpace * currentwspc
TwmWindow * save_focus
#define Islower(c)
Definition util.h:53
#define Isupper(c)
Definition util.h:54
#define Tolower(c)
Definition util.h:55
void SetBorderCursor(TwmWindow *tmp_win, int x, int y)
void PaintTitle(TwmWindow *tmp_win)
void SetFrameShape(TwmWindow *tmp)
void PaintTitleButton(TwmWindow *tmp_win, TBWindow *tbw)
void SetupWindow(TwmWindow *tmp_win, int x, int y, int w, int h, int bw)
void PaintBorders(TwmWindow *tmp_win, bool focus)
void SetupFrame(TwmWindow *tmp_win, int x, int y, int w, int h, int bw, bool sendEvent)
void DeleteHighlightWindows(TwmWindow *tmp_win)
void Iconify(TwmWindow *tmp_win, int def_x, int def_y)
Definition win_iconify.c:45
void DeIconify(TwmWindow *tmp_win)
void Squeeze(TwmWindow *tmp_win)
Definition win_ops.c:223
void SetFocusVisualAttributes(TwmWindow *tmp_win, bool focus)
Definition win_ops.c:30
void SetFocus(TwmWindow *tmp_win, Time tim)
Definition win_ops.c:128
void FocusOnRoot(void)
Definition win_ops.c:189
void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
Definition win_ops.c:317
void AutoSqueeze(TwmWindow *tmp_win)
Definition win_ops.c:205
void RemoveWindowFromRegion(TwmWindow *tmp_win)
void unzoom(TwmWindow *tmp_win)
void EndResize(void)
Definition win_resize.c:633
void DoResize(int x_root, int y_root, TwmWindow *tmp_win)
Definition win_resize.c:439
void UnlinkWindowFromRing(TwmWindow *win)
Definition win_ring.c:26
#define WindowIsOnRing(win)
Definition win_ring.h:10
void apply_window_icon_name(TwmWindow *win)
[Re]set and apply changes to a window's icon name.
Definition win_utils.c:1349
void GetWindowSizeHints(TwmWindow *tmp)
Definition win_utils.c:41
void send_clientmessage(Window w, Atom a, Time timestamp)
Definition win_utils.c:996
XWMHints * munge_wmhints(TwmWindow *win, XWMHints *hints)
Perform whatever adaptations of WM_HINTS info we do.
Definition win_utils.c:1059
void FreeWMPropertyString(char *prop)
Definition win_utils.c:327
bool GetWMState(Window w, int *statep, Window *iwp)
Definition win_utils.c:429
TwmWindow * GetTwmWindow(Window w)
Definition win_utils.c:190
void ConstrainByBorders(TwmWindow *twmwin, int *left, int width, int *top, int height)
Definition win_utils.c:825
void FetchWmProtocols(TwmWindow *tmp)
Definition win_utils.c:108
void SetMapStateProp(TwmWindow *tmp_win, int state)
Definition win_utils.c:415
void TryToPush(TwmWindow *tmp_win, int x, int y)
Definition win_utils.c:617
void apply_window_name(TwmWindow *win)
[Re]set and apply changes to a window's name.
Definition win_utils.c:1187
void TryToGrid(TwmWindow *tmp_win, int *x, int *y)
Definition win_utils.c:705
void TryToPack(TwmWindow *tmp_win, int *x, int *y)
Definition win_utils.c:560
char * GetWMPropertyString(Window w, Atom prop)
Definition win_utils.c:222
void GetGravityOffsets(TwmWindow *tmp, int *xp, int *yp)
Definition win_utils.c:149
void WMapRemoveWindow(TwmWindow *win)
void WMgrHandleKeyPressEvent(VirtualScreen *vs, XEvent *event)
void WMapMapWindow(TwmWindow *win)
void WMapRaise(TwmWindow *win)
void WMgrHandleExposeEvent(VirtualScreen *vs, XEvent *event)
void WMgrHandleKeyReleaseEvent(VirtualScreen *vs, XEvent *event)
void WMgrHandleButtonEvent(VirtualScreen *vs, XEvent *event)
void GotoWorkSpaceByName(VirtualScreen *vs, const char *wname)