2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2009 Kim Woelders
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 #include "windowmatch.h"
42 #include <X11/Xutil.h>
43 #include <X11/extensions/shape.h>
45 #define EWIN_TOP_EVENT_MASK \
46 (/* ButtonPressMask | ButtonReleaseMask | */ \
47 EnterWindowMask | LeaveWindowMask /* | PointerMotionMask */ /* | \
48 StructureNotifyMask */)
50 #define EWIN_CONTAINER_EVENT_MASK \
51 (SubstructureNotifyMask | SubstructureRedirectMask)
53 #define EWIN_CLIENT_EVENT_MASK \
54 (/* EnterWindowMask | LeaveWindowMask | */ FocusChangeMask | \
55 /* StructureNotifyMask | */ ResizeRedirectMask | \
56 PropertyChangeMask | ColormapChangeMask | VisibilityChangeMask)
58 static int EwinSlideIn(void *data);
60 static void EwinChangesStart(EWin * ewin);
61 static void EwinChangesProcess(EWin * ewin);
63 static void EwinHandleEventsToplevel(Win win, XEvent * ev, void *prm);
64 static void EwinHandleEventsContainer(Win win, XEvent * ev, void *prm);
65 static void EwinHandleEventsClient(Win win, XEvent * ev, void *prm);
67 static void EwinUnmap2(EWin * ewin);
70 EwinGetClientXwin(const EWin * ewin)
72 Win win = EwinGetClientWin(ewin);
74 return (win) ? WinGetXwin(win) : None;
78 EwinGetContainerXwin(const EWin * ewin)
80 Win win = EwinGetContainerWin(ewin);
82 return (win) ? WinGetXwin(win) : None;
90 ewin = ECALLOC(EWin, 1);
93 ewin->state.state = (Mode.wm.startup) ? EWIN_STATE_STARTUP : EWIN_STATE_NEW;
95 ewin->o.stacked = -1; /* Not placed on desk yet */
96 EoSetDesk(ewin, DesksGetCurrent());
101 ewin->update.shape = 1;
102 ewin->update.border = 1;
103 ewin->save_max.x = ewin->save_max.y = ewin->save_max.w = ewin->save_max.h =
105 ewin->save_fs.x = ewin->save_fs.y = ewin->save_fs.w = ewin->save_fs.h = -1;
106 ewin->save_fs.layer = -1;
108 ewin->icccm.need_input = 1;
110 ewin->icccm.width_min = 0;
111 ewin->icccm.height_min = 0;
112 ewin->icccm.width_max = 65535;
113 ewin->icccm.height_max = 65535;
114 ewin->icccm.base_w = 0;
115 ewin->icccm.base_h = 0;
116 ewin->icccm.w_inc = 1;
117 ewin->icccm.h_inc = 1;
118 ewin->icccm.aspect_min = 0.0;
119 ewin->icccm.aspect_max = 65535.0;
120 ewin->icccm.grav = NorthWestGravity;
122 #if 0 /* ENABLE_GNOME - Not actually used */
123 ewin->expanded_width = -1;
124 ewin->expanded_height = -1;
129 ewin->place.gravity = -1;
131 ewin->ewmh.opacity = 0; /* If 0, ignore */
132 ewin->props.focused_opacity = 0;
138 EwinGetAttributes(EWin * ewin, Win win, Window xwin)
140 XWindowAttributes xwa;
144 win = ERegisterWindow(xwin, NULL);
149 EGetWindowAttributes(win, &xwa);
151 ewin->client.win = win;
152 ewin->client.x = ewin->save_max.x = ewin->save_fs.x = xwa.x;
153 ewin->client.y = ewin->save_max.y = ewin->save_fs.y = xwa.y;
154 ewin->client.w = ewin->save_max.w = ewin->save_fs.w = xwa.width;
155 ewin->client.h = ewin->save_max.h = ewin->save_fs.h = xwa.height;
156 ewin->client.bw = xwa.border_width;
157 ewin->client.cmap = xwa.colormap;
159 if (EDebug(EDBUG_TYPE_SNAPS))
160 Eprintf("Snap get attr %#lx: %4d+%4d %4dx%4d: %s\n",
161 EwinGetClientXwin(ewin), ewin->client.x, ewin->client.y,
162 ewin->client.w, ewin->client.h, EwinGetTitle(ewin));
168 EwinGetHints(EWin * ewin)
170 if (EDebug(EDBUG_TYPE_EWINS))
171 Eprintf("EwinGetHints %#lx\n", EwinGetClientXwin(ewin));
173 ICCCM_GetTitle(ewin);
174 ICCCM_GetHints(ewin);
175 ICCCM_GetGeoms(ewin);
176 MWM_GetHints(ewin, 0);
177 ICCCM_GetInfo(ewin); /* NB! Need group info first */
178 HintsGetWindowHints(ewin);
179 SessionGetInfo(ewin);
183 EwinHintsInferProps(EWin * ewin)
185 if (ewin->ewmh.type.b.desktop)
188 if (!ewin->state.identified)
189 EoSetSticky(ewin, 1);
190 ewin->props.focusclick = 1;
191 ewin->props.skip_focuslist = 1;
192 EwinInhSetUser(ewin, move, 1);
193 EwinInhSetUser(ewin, size, 1);
194 ewin->props.donthide = 1;
195 ewin->props.no_border = 1;
197 if (ewin->ewmh.type.b.dock)
199 ewin->props.skip_ext_task = 1;
200 ewin->props.skip_winlist = 1;
201 ewin->props.skip_focuslist = 1;
202 if (!ewin->state.identified)
203 EoSetSticky(ewin, 1);
204 ewin->props.donthide = 1;
206 if (ewin->ewmh.type.b.utility)
208 /* Epplets hit this */
209 ewin->props.skip_ext_task = 1;
210 ewin->props.skip_winlist = 1;
211 ewin->props.skip_focuslist = 1;
212 ewin->props.never_use_area = 1;
213 ewin->props.donthide = 1;
218 EwinManage(EWin * ewin)
220 XSetWindowAttributes att;
224 if (ewin->client.w <= 0)
225 ewin->client.w = 100;
226 if (ewin->client.h <= 0)
227 ewin->client.h = 100;
229 if (ewin->state.docked)
230 ewin->inh_wm.b.border = 1;
232 frame = EoGetWin(ewin);
235 type = (ewin->props.no_argb) ? WIN_TYPE_NO_ARGB : WIN_TYPE_CLIENT;
237 ECreateObjectWindow(VROOT, ewin->client.x, ewin->client.y,
238 ewin->client.w, ewin->client.h, 0, type,
239 EwinGetClientWin(ewin));
240 ewin->win_container =
241 ECreateWindow(frame, 0, 0, ewin->client.w, ewin->client.h, 0);
243 EoInit(ewin, EOBJ_TYPE_EWIN, frame, ewin->client.x, ewin->client.y,
244 ewin->client.w, ewin->client.h, 1, NULL);
246 EobjListFocusAdd(&ewin->o, 1);
247 EobjListOrderAdd(&ewin->o);
249 EventCallbackRegister(EoGetWin(ewin), 0,
250 EwinHandleEventsToplevel, ewin);
251 EventCallbackRegister(ewin->win_container, 0,
252 EwinHandleEventsContainer, ewin);
253 EventCallbackRegister(EwinGetClientWin(ewin), 0,
254 EwinHandleEventsClient, ewin);
257 att.event_mask = EWIN_CONTAINER_EVENT_MASK;
258 att.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
259 EChangeWindowAttributes(ewin->win_container,
260 CWEventMask | CWDontPropagate, &att);
261 EMapWindow(ewin->win_container);
263 att.event_mask = EWIN_TOP_EVENT_MASK;
264 att.do_not_propagate_mask =
265 ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
266 EChangeWindowAttributes(EoGetWin(ewin), CWEventMask | CWDontPropagate, &att);
268 ewin->client.event_mask = EWIN_CLIENT_EVENT_MASK;
269 ESelectInput(EwinGetClientWin(ewin), ewin->client.event_mask);
271 if (EDebug(EDBUG_TYPE_EWINS))
272 Eprintf("EwinManage %#lx frame=%#lx cont=%#lx st=%d\n",
273 EwinGetClientXwin(ewin), EoGetXwin(ewin),
274 EwinGetContainerXwin(ewin), ewin->state.state);
276 if (!EwinIsInternal(ewin))
278 XShapeSelectInput(disp, EwinGetClientXwin(ewin), ShapeNotifyMask);
279 ESetWindowBorderWidth(EwinGetClientWin(ewin), 0);
283 ICCCM_AdoptStart(ewin);
285 /* We must reparent after getting original window position */
286 EReparentWindow(EwinGetClientWin(ewin), ewin->win_container, 0, 0);
288 EwinUpdateShapeInfo(ewin);
290 ModulesSignal(ESIGNAL_EWIN_CREATE, ewin);
294 * Derive frame window geometry from client window properties
297 EwinSetGeometry(EWin * ewin)
299 int x, y, l, r, t, b;
302 grav = (ewin->state.identified) ? StaticGravity : ewin->icccm.grav;
304 EwinGetPosition(ewin, ewin->client.x, ewin->client.y, grav, &x, &y);
306 l = ewin->border->border.left;
307 r = ewin->border->border.right;
308 t = ewin->border->border.top;
309 b = ewin->border->border.bottom;
311 ewin->client.x = x + l;
312 ewin->client.y = y + t;
314 EoMoveResize(ewin, x, y, ewin->client.w + l + r, ewin->client.h + t + b);
318 EwinConfigure(EWin * ewin)
320 EwinStateUpdate(ewin);
322 if (!EwinIsInternal(ewin) && Mode.wm.startup)
323 EHintsGetInfo(ewin); /* E restart hints */
324 EwinHintsInferProps(ewin);
325 SnapshotEwinApply(ewin); /* Apply saved settings */
327 if (ewin->save_fs.layer < 0)
328 ewin->save_fs.layer = EoGetLayer(ewin);
330 EwinStateUpdate(ewin); /* Update after snaps etc. */
334 EwinBorderSelect(ewin); /* Select border before calculating geometry */
335 EwinSetGeometry(ewin); /* Calculate window geometry before border parts */
336 EwinBorderSetTo(ewin, NULL);
338 if (!ewin->props.no_button_grabs)
339 GrabButtonGrabs(EoGetWin(ewin));
341 if (ewin->state.shaded)
342 EwinInstantShade(ewin, 1);
344 EwinUpdateOpacity(ewin);
346 HintsSetWindowState(ewin);
347 HintsSetWindowOpacity(ewin);
349 HintsSetClientList();
351 if (EDebug(EDBUG_TYPE_EWINS))
352 Eprintf("EwinConfigure %#lx st=%d: %s\n", EwinGetClientXwin(ewin),
353 ewin->state.state, EwinGetTitle(ewin));
357 EwinCleanup(EWin * ewin)
359 EwinBorderDetach(ewin);
363 EwinDestroy(EWin * ewin)
371 if (ewin->state.state == EWIN_STATE_MAPPED)
374 if (EDebug(EDBUG_TYPE_EWINS))
375 Eprintf("EwinDestroy %#lx st=%d: %s\n", EwinGetClientXwin(ewin),
376 ewin->state.state, EwinGetTitle(ewin));
378 EventCallbackUnregister(EoGetWin(ewin), 0, EwinHandleEventsToplevel, ewin);
379 EventCallbackUnregister(ewin->win_container, 0, EwinHandleEventsContainer,
381 EventCallbackUnregister(EwinGetClientWin(ewin), 0, EwinHandleEventsClient,
383 if (!EwinIsInternal(ewin))
384 EUnregisterWindow(EwinGetClientWin(ewin));
386 SnapshotEwinUnmatch(ewin);
388 ModulesSignal(ESIGNAL_EWIN_DESTROY, ewin);
390 lst = EwinListTransientFor(ewin, &num);
391 for (i = 0; i < num; i++)
393 lst[i]->icccm.transient_count--;
394 if (lst[i]->icccm.transient_count < 0) /* Paranoia? */
395 lst[i]->icccm.transient_count = 0;
400 EobjListOrderDel(&ewin->o);
401 EobjListFocusDel(&ewin->o);
404 HintsSetClientList();
406 Efree(ewin->icccm.wm_icon_name);
407 Efree(ewin->icccm.wm_role);
408 Efree(ewin->icccm.wm_command);
409 Efree(ewin->icccm.wm_machine);
410 Efree(ewin->ewmh.wm_name);
411 Efree(ewin->ewmh.wm_icon_name);
412 Efree(ewin->ewmh.wm_icon);
414 Efree(ewin->session_id);
415 FreePmapMask(&ewin->mini_pmm);
416 GroupsEwinRemove(ewin);
422 DetermineEwinFloat(EWin * ewin, int dx, int dy)
425 int x, y, w, h, xd, yd;
428 dsk = EoGetDesk(ewin);
437 if ((dsk->num != 0) && (EoIsFloating(ewin) < 2) &&
438 ((xd != 0) || (yd != 0) || (DesksGetCurrent() != dsk)))
440 switch (Conf.desks.dragdir)
444 ((x + dx + w <= WinGetW(VROOT)) &&
445 (DesktopAt(xd + x + dx + w - 1, yd) != dsk))))
449 if (((x + dx + w > WinGetW(VROOT)) ||
450 ((x + dx >= 0) && (DesktopAt(xd + x + dx, yd) != dsk))))
455 ((y + dy + h <= WinGetH(VROOT)) &&
456 (DesktopAt(xd, yd + y + dy + h - 1) != dsk))))
460 if (((y + dy + h > WinGetH(VROOT)) ||
461 ((y + dy >= 0) && (DesktopAt(xd, yd + y + dy) != dsk))))
467 EwinOpFloatAt(ewin, OPSRC_USER, x + xd, y + yd);
472 GetEwinPointerInClient(void)
475 EWin *const *lst, *ewin;
479 dsk = DesktopAt(Mode.events.cx, Mode.events.cy);
480 EQueryPointer(EoGetWin(dsk), &px, &py, NULL, NULL);
482 lst = EwinListGetForDesk(&num, dsk);
483 for (i = 0; i < num; i++)
492 if ((px >= x) && (py >= y) && (px < (x + w)) && (py < (y + h)) &&
503 return Mode.focuswin;
511 ewin = Mode.context_ewin;
519 Eprintf("GetContextEwin %#lx %s\n", EwinGetClientXwin(ewin),
526 SetContextEwin(EWin * ewin)
528 if (ewin && ewin->type == EWIN_TYPE_MENU)
531 Eprintf("SetContextEwin %#lx %s\n", EwinGetClientXwin(ewin),
534 Mode.context_ewin = ewin;
538 * Derive frame window position from client window and border properties
541 EwinGetPosition(const EWin * ewin, int x, int y, int grav, int *px, int *py)
543 int bw, bd_lr, bd_tb;
545 bw = ewin->client.bw;
546 bd_lr = ewin->border->border.left + ewin->border->border.right;
547 bd_tb = ewin->border->border.top + ewin->border->border.bottom;
550 grav = ewin->icccm.grav;
554 case NorthWestGravity:
556 case SouthWestGravity:
564 case NorthEastGravity:
566 case SouthEastGravity:
570 x -= ewin->border->border.left;
578 case NorthWestGravity:
580 case NorthEastGravity:
588 case SouthWestGravity:
590 case SouthEastGravity:
594 y -= ewin->border->border.top;
605 EwinUpdateShapeInfo(EWin * ewin)
609 EShapeSetShape(ewin->win_container, 0, 0, EwinGetClientWin(ewin));
612 if (EDebug(EX_EVENT_SHAPE_NOTIFY))
613 Eprintf("EwinUpdateShapeInfo %#lx cont=%#lx shaped=%d\n",
614 EwinGetClientXwin(ewin), EwinGetContainerXwin(ewin),
619 EwinPropagateShapes(EWin * ewin)
621 if (!EoIsShown(ewin))
624 if (ewin->state.docked)
627 if (!ewin->update.shape)
630 if (EDebug(EX_EVENT_SHAPE_NOTIFY))
631 Eprintf("EwinPropagateShapes %#lx frame=%#lx shaped=%d\n",
632 EwinGetClientXwin(ewin), EoGetXwin(ewin), ewin->state.shaped);
634 EoShapeUpdate(ewin, 1);
635 ewin->update.shape = 0;
639 EwinStateUpdate(EWin * ewin)
641 ewin->state.inhibit_actions = ewin->props.no_actions;
642 ewin->state.inhibit_focus = !ewin->icccm.need_input ||
643 EwinInhGetWM(ewin, focus) || ewin->state.iconified;
645 ewin->state.inhibit_move =
646 EwinInhGetUser(ewin, move) || ewin->state.fullscreen;
647 ewin->state.inhibit_resize = ewin->state.iconified || ewin->state.shaded ||
648 (ewin->props.no_resize_h && ewin->props.no_resize_v) ||
649 EwinInhGetUser(ewin, size) || ewin->state.fullscreen;
650 ewin->state.inhibit_iconify = EwinInhGetWM(ewin, iconify);
651 ewin->state.inhibit_shade = ewin->state.no_border ||
652 ewin->state.iconified || ewin->state.fullscreen;
653 ewin->state.inhibit_stick = 0;
654 ewin->state.inhibit_max_hor = ewin->state.inhibit_resize ||
655 ewin->props.no_resize_h || ewin->state.fullscreen;
656 ewin->state.inhibit_max_ver = ewin->state.inhibit_resize ||
657 ewin->props.no_resize_v || ewin->state.fullscreen;
658 ewin->state.inhibit_fullscreeen =
659 ewin->state.inhibit_move || ewin->state.inhibit_resize;
660 ewin->state.inhibit_change_desk = ewin->state.iconified;
661 ewin->state.inhibit_close = EwinInhGetApp(ewin, close) ||
662 EwinInhGetUser(ewin, close);
664 ewin->state.donthide = ewin->props.donthide ||
665 ewin->props.skip_ext_task || ewin->props.skip_winlist ||
666 ewin->props.skip_focuslist;
668 SnapshotEwinUpdate(ewin, SNAP_USE_FLAGS);
672 AddToFamily(EWin * ewin, Window xwin)
676 int i, k, num, fx, fy, x, y;
677 char doslide, manplace;
685 ewin = EwinCreate(EWIN_TYPE_NORMAL);
689 if (EwinGetAttributes(ewin, NULL, xwin))
691 Eprintf("Window is gone %#lx\n", xwin);
692 /* We got here by MapRequest. DestroyNotify should follow. */
697 WindowMatchEwinOps(ewin); /* Window matches */
701 /* if it hasn't been planted on a desktop - assign it the current desktop */
702 dsk = EoGetDesk(ewin);
704 /* if is an afterstep/windowmaker dock app - dock it */
705 if (Conf.dock.enable && ewin->state.docked)
709 if (ewin->icccm.transient)
711 if (ewin->icccm.transient_for == None ||
712 ewin->icccm.transient_for == WinGetXwin(VROOT))
714 /* Group transient */
715 ewin->icccm.transient_for = WinGetXwin(VROOT);
719 /* Don't treat this as a normal transient */
720 ewin->icccm.transient = -1;
722 else if (ewin->icccm.transient_for == EwinGetClientXwin(ewin))
724 /* Some apps actually do this. Why? */
725 ewin->icccm.transient = 0;
729 /* Regular transient */
732 if (ewin->icccm.transient)
734 /* Tag the parent window if this is a transient */
735 lst = EwinListTransientFor(ewin, &num);
736 for (i = 0; i < num; i++)
738 lst[i]->icccm.transient_count++;
739 if (EoGetLayer(ewin) < EoGetLayer(lst[i]))
740 EoSetLayer(ewin, EoGetLayer(lst[i]));
745 EoSetSticky(ewin, EoIsSticky(lst[0]));
750 /* No parents? - not a transient */
751 ewin->icccm.transient = 0;
758 if (ewin->icccm.transient && Conf.focus.transientsfollowleader)
763 ewin2 = EwinFindByClient(ewin->icccm.group);
767 lst2 = EwinListGetAll(&num);
768 for (i = 0; i < num; i++)
770 if ((lst2[i]->state.iconified) ||
771 (ewin->icccm.group != lst2[i]->icccm.group))
781 dsk = EoGetDesk(ewin2);
782 if (!Mode.wm.startup && Conf.focus.switchfortransientmap &&
783 !ewin->state.iconified)
784 DeskGotoByEwin(ewin2);
788 if (ewin->state.fullscreen)
790 EwinOpFullscreen(ewin, OPSRC_WM, 2);
791 ewin->state.placed = 1;
792 EwinMoveToDesktopAt(ewin, dsk, EoGetX(ewin), EoGetY(ewin));
797 if (!ewin->state.identified &&
798 (ewin->state.maximized_horz || ewin->state.maximized_vert))
802 /* New client requested maximisation */
803 hor = ewin->state.maximized_horz;
804 ver = ewin->state.maximized_vert;
805 ewin->state.maximized_horz = ewin->state.maximized_vert = 0;
806 MaxSizeHV(ewin, "absolute", hor, ver);
807 /* Set old state to current maximized one */
808 ewin->save_max.x = EoGetX(ewin);
809 ewin->save_max.y = EoGetY(ewin);
810 ewin->save_max.w = ewin->client.w;
811 ewin->save_max.h = ewin->client.h;
812 ewin->state.placed = 0;
816 EwinResize(ewin, ewin->client.w, ewin->client.h);
819 doslide = manplace = 0;
820 if (Mode.place.enable_features > 0)
822 /* if set for borderless then dont slide it in */
823 if (Conf.place.slidein && !Mode.place.doing_slide &&
824 !ewin->state.no_border && dsk == DesksGetCurrent())
827 if (Conf.place.manual && !Mode.place.doing_manual &&
828 !ewin->state.placed && !ewin->icccm.transient)
830 if (GrabPointerSet(VROOT, ECSR_GRAB, 0) == GrabSuccess)
835 /* if it hasn't been placed yet.... find a spot for it */
836 if ((!ewin->state.placed) && (!manplace))
838 /* Place the window below the mouse pointer */
839 if (Conf.place.manual_mouse_pointer)
843 /* if the loser has manual placement on and the app asks to be on */
844 /* a desktop, then send E to that desktop so the user can place */
845 /* the window there */
848 EventsGetXY(&cx, &cy);
850 /* try to center the window on the mouse pointer */
851 cx -= EoGetW(ewin) / 2;
852 cy -= EoGetH(ewin) / 2;
854 /* keep it all on this screen if possible */
855 cx = MIN(cx, WinGetW(VROOT) - EoGetW(ewin));
856 cy = MIN(cy, WinGetH(VROOT) - EoGetH(ewin));
860 /* this works for me... */
864 else if (ewin->ewmh.type.b.dialog)
866 /* Center unplaced dialogs on parent(if transient) or root */
870 if (EwinGetTransientFor(ewin) != None)
871 ewin2 = EwinFindByClient(EwinGetTransientFor(ewin));
872 parent = (ewin2) ? EoGetWin(ewin) : VROOT;
873 x = (WinGetW(parent) - EoGetW(ewin)) / 2;
874 y = (WinGetH(parent) - EoGetH(ewin)) / 2;
878 ArrangeEwinXY(ewin, &x, &y);
880 ewin->state.placed = 1;
883 /* if the window asked to be iconified at the start */
884 if (ewin->icccm.start_iconified)
886 EwinMoveToDesktopAt(ewin, dsk, x, y);
887 ewin->state.state = EWIN_STATE_MAPPED;
889 ewin->state.state = EWIN_STATE_ICONIC;
893 /* if we should slide it in and are not currently in the middle of a slide */
894 if ((manplace) && (!ewin->state.placed))
898 /* if the loser has manual placement on and the app asks to be on */
899 /* a desktop, then send E to that desktop so the user can place */
900 /* the window there */
903 EQueryPointer(NULL, &rx, &ry, NULL, NULL);
906 ewin->state.placed = 1;
907 x = Mode.events.cx + 1;
908 y = Mode.events.cy + 1;
909 EwinMoveToDesktopAt(ewin, dsk, x, y);
910 EwinMove(ewin, x, y);
912 GrabPointerSet(VROOT, ECSR_GRAB, 0);
913 Mode.place.doing_manual = 1;
914 EoSetFloating(ewin, 1); /* Causes reparenting to root */
915 ActionMoveStart(ewin, 0, 0, 0);
925 fx = (rand() % (WinGetW(VROOT))) - EoGetW(ewin);
930 fx = (rand() % (WinGetW(VROOT)));
936 fy = (rand() % (WinGetH(VROOT)));
941 fy = (rand() % (WinGetH(VROOT))) - EoGetH(ewin);
943 Mode.place.doing_slide = 1;
944 ewin->state.animated = 1;
947 EwinMoveToDesktopAt(ewin, dsk, fx, fy);
951 TIMER_ADD(slide_timer, 0.05, EwinSlideIn, ewin);
955 EwinMoveToDesktopAt(ewin, dsk, x, y);
964 AddInternalToFamily(Win win, const char *bname, int type,
965 const EWinOps * ops, void *ptr)
971 ewin = EwinCreate(type);
975 ewin->props.donthide = 1;
976 EwinGetAttributes(ewin, win, None);
977 WindowMatchEwinOps(ewin); /* Window matches */
982 if (ops && ops->Init)
983 ops->Init(ewin); /* Type specific initialisation */
986 ewin->border = BorderFind(bname);
991 Eprintf("Desk=%d, layer=%d, sticky=%d, floating=%d\n",
992 EoGetDesk(ewin), EoGetLayer(ewin), EoIsSticky(ewin),
1003 EwinUnmap1(EWin * ewin)
1005 /* The client may have been unmapped but the frame is not yet */
1007 if (GetZoomEWin() == ewin)
1012 if (Mode.place.doing_slide)
1014 #if 0 /* No event processing during slides - No use doing this here */
1015 DrawEwinShape(ewin, Conf.slidemode, ewin->shape_x, ewin->shape_y,
1016 ewin->client.w, ewin->client.h, 2);
1018 #if 0 /* FIXME - Do this right */
1019 RemoveTimerEvent("Slide");
1020 Mode.place.doing_slide = 0;
1027 EwinUnmap2(EWin * ewin)
1029 /* The frame has been unmapped */
1031 FocusToEWin(ewin, FOCUS_EWIN_UNMAP);
1032 if (ewin == Mode.mouse_over_ewin)
1033 Mode.mouse_over_ewin = NULL;
1034 if (ewin == Mode.context_ewin)
1035 Mode.context_ewin = NULL;
1037 ModulesSignal(ESIGNAL_EWIN_UNMAP, ewin);
1041 EwinWithdraw(EWin * ewin, Win to)
1046 /* Only external clients should go here */
1048 if (EDebug(EDBUG_TYPE_EWINS))
1049 Eprintf("EwinWithdraw %#lx st=%d: %s\n", EwinGetClientXwin(ewin),
1050 ewin->state.state, EwinGetTitle(ewin));
1054 ESelectInput(EwinGetClientWin(ewin), NoEventMask);
1055 XShapeSelectInput(disp, EwinGetClientXwin(ewin), NoEventMask);
1057 if (EXWindowGetParent(EwinGetClientXwin(ewin)) == EwinGetContainerXwin(ewin))
1059 /* Park the client window on the new root */
1062 ETranslateCoordinates(EwinGetClientWin(ewin), VROOT,
1063 -ewin->border->border.left,
1064 -ewin->border->border.top, &x, &y, &win);
1065 EReparentWindow(EwinGetClientWin(ewin), to, x, y);
1066 HintsDelWindowHints(ewin);
1068 ICCCM_Withdraw(ewin);
1075 EwinEventMapRequest(EWin * ewin, Window win)
1079 if (ewin->state.state == EWIN_STATE_ICONIC)
1080 EwinDeIconify(ewin);
1081 else if (ewin->state.state == EWIN_STATE_WITHDRAWN)
1082 AddToFamily(ewin, win);
1085 Eprintf("AddToFamily: Already managing %s %#lx\n", "A",
1086 EwinGetClientXwin(ewin));
1087 EReparentWindow(EwinGetClientWin(ewin), ewin->win_container, 0, 0);
1092 /* Check if we are already managing it */
1093 ewin = EwinFindByClient(win);
1095 /* Some clients MapRequest more than once ?!? */
1098 Eprintf("AddToFamily: Already managing %s %#lx\n", "B",
1099 EwinGetClientXwin(ewin));
1100 EReparentWindow(EwinGetClientWin(ewin), ewin->win_container, 0, 0);
1104 AddToFamily(NULL, win);
1109 EwinEventDestroy(EWin * ewin)
1111 if (EDebug(EDBUG_TYPE_EWINS))
1112 Eprintf("EwinEventDestroy %#lx st=%d: %s\n", EwinGetClientXwin(ewin),
1113 ewin->state.state, EwinGetTitle(ewin));
1119 EwinEventReparent(EWin * ewin)
1125 /* Refetch parent window. We cannot rely on the one in the event. */
1129 parent = EXWindowGetParent(EwinGetClientXwin(ewin));
1130 if (EDebug(EDBUG_TYPE_EWINS))
1131 Eprintf("EwinEventReparent %#lx st=%d parent=%#lx: %s\n",
1132 EwinGetClientXwin(ewin), ewin->state.state, parent,
1133 EwinGetTitle(ewin));
1134 if (parent != EwinGetContainerXwin(ewin))
1141 EwinEventMap(EWin * ewin, XEvent * ev)
1145 /* Catch clients setting OR without proper withdrawal (just unmap/map) */
1146 if (ev->xmap.override_redirect)
1149 old_state = ewin->state.state;
1150 ewin->state.state = EWIN_STATE_MAPPED;
1152 if (EDebug(EDBUG_TYPE_EWINS))
1153 Eprintf("EwinEventMap %#lx st=%d: %s\n", EwinGetClientXwin(ewin),
1154 ewin->state.state, EwinGetTitle(ewin));
1156 /* If first time we may want to focus it (unless during startup) */
1157 if (old_state == EWIN_STATE_NEW)
1158 FocusToEWin(ewin, FOCUS_EWIN_NEW);
1160 FocusToEWin(ewin, FOCUS_SET);
1162 ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin);
1166 EwinEventUnmap(EWin * ewin, XEvent * ev)
1168 if (EDebug(EDBUG_TYPE_EWINS))
1169 Eprintf("EwinEventUnmap %#lx st=%d: %s\n", EwinGetClientXwin(ewin),
1170 ewin->state.state, EwinGetTitle(ewin));
1172 if (ewin->state.state == EWIN_STATE_STARTUP ||
1173 ewin->state.state == EWIN_STATE_NEW)
1176 /* We get here after reparenting to container and occasionally in
1177 * other(?) situations */
1178 Eprintf("EwinEventUnmap %#lx: Ignoring bogus Unmap event\n",
1179 EwinGetClientXwin(ewin));
1184 /* Ignore synthetic events */
1185 if (ev->xany.send_event)
1188 if (ewin->state.state == EWIN_STATE_WITHDRAWN)
1191 if (ewin->state.iconified)
1192 ewin->state.state = EWIN_STATE_ICONIC;
1194 ewin->state.state = EWIN_STATE_WITHDRAWN;
1197 EWindowSetMapped(EwinGetClientWin(ewin), 0);
1201 if (ewin->state.state == EWIN_STATE_ICONIC)
1204 if (EwinIsInternal(ewin))
1206 #if 1 /* FIXME - Remove? */
1207 /* We should never get here */
1208 Eprintf("FIXME: This cannot happen (%s)\n", EoGetName(ewin));
1216 EwinWithdraw(ewin, VROOT);
1220 EwinEventConfigureRequest(EWin * ewin, XEvent * ev)
1224 int x = 0, y = 0, w = 0, h = 0;
1234 /* This is shady - some clients send root coords, some use the
1235 * ICCCM ones sent by us */
1236 if (!EwinInhGetApp(ewin, move))
1238 #if 1 /* FIXME - ??? */
1239 if (ev->xconfigurerequest.value_mask & CWX)
1240 x = ev->xconfigurerequest.x;
1241 if (ev->xconfigurerequest.value_mask & CWY)
1242 y = ev->xconfigurerequest.y;
1244 if (ev->xconfigurerequest.value_mask & CWX)
1245 x = ev->xconfigurerequest.x - EoGetX(EoGetDesk(ewin));
1246 if (ev->xconfigurerequest.value_mask & CWY)
1247 y = ev->xconfigurerequest.y - EoGetY(EoGetDesk(ewin));
1250 if (!EwinInhGetApp(ewin, size))
1252 if (ev->xconfigurerequest.value_mask & CWWidth)
1253 w = ev->xconfigurerequest.width;
1254 if (ev->xconfigurerequest.value_mask & CWHeight)
1255 h = ev->xconfigurerequest.height;
1257 if (ev->xconfigurerequest.value_mask & CWSibling)
1258 winrel = ev->xconfigurerequest.above;
1259 if (ev->xconfigurerequest.value_mask & CWStackMode)
1261 ewin2 = EwinFindByClient(winrel);
1263 winrel = EoGetXwin(ewin2);
1264 xwc.sibling = winrel;
1265 xwc.stack_mode = ev->xconfigurerequest.detail;
1266 if (Mode.mode == MODE_NONE)
1268 if (xwc.stack_mode == Above)
1270 else if (xwc.stack_mode == Below)
1275 if (ev->xconfigurerequest.value_mask & (CWX | CWY))
1277 /* Correct position taking gravity into account */
1278 EwinGetPosition(ewin, x, y, 0, &x, &y);
1281 Mode.move.check = 0; /* Don't restrict client requests */
1282 EwinMoveResize(ewin, x, y, w, h);
1283 Mode.move.check = 1;
1288 xwc.x = ev->xconfigurerequest.x;
1289 xwc.y = ev->xconfigurerequest.y;
1290 xwc.width = ev->xconfigurerequest.width;
1291 xwc.height = ev->xconfigurerequest.height;
1292 xwc.border_width = ev->xconfigurerequest.border_width;
1293 xwc.sibling = ev->xconfigurerequest.above;
1294 xwc.stack_mode = ev->xconfigurerequest.detail;
1295 XConfigureWindow(disp, ev->xconfigurerequest.window,
1296 ev->xconfigurerequest.value_mask, &xwc);
1301 EwinEventResizeRequest(EWin * ewin, XEvent * ev)
1305 EwinResize(ewin, ev->xresizerequest.width, ev->xresizerequest.height);
1310 XResizeWindow(disp, ev->xresizerequest.window,
1311 ev->xresizerequest.width, ev->xresizerequest.height);
1316 EwinEventCirculateRequest(EWin * ewin, XEvent * ev)
1320 if (ev->xcirculaterequest.place == PlaceOnTop)
1327 if (ev->xcirculaterequest.place == PlaceOnTop)
1328 XRaiseWindow(disp, ev->xcirculaterequest.window);
1330 XLowerWindow(disp, ev->xcirculaterequest.window);
1335 EwinEventPropertyNotify(EWin * ewin, XEvent * ev)
1337 if (EwinIsInternal(ewin))
1341 EwinChangesStart(ewin);
1343 HintsProcessPropertyChange(ewin, ev);
1344 EwinStateUpdate(ewin);
1346 EwinChangesProcess(ewin);
1351 EwinEventShapeChange(EWin * ewin, XEvent * ev)
1353 #define se ((XShapeEvent *)ev)
1354 if (EDebug(EX_EVENT_SHAPE_NOTIFY))
1355 Eprintf("EwinEventShapeChange %#lx %s: state.shaped=%d ev->shaped=%d\n",
1356 EwinGetClientXwin(ewin), EoGetName(ewin), ewin->state.shaped,
1358 if (!se->shaped && !ewin->state.shaped)
1360 EwinUpdateShapeInfo(ewin);
1361 ewin->update.shape = 1;
1362 EwinPropagateShapes(ewin);
1367 EwinEventVisibility(EWin * ewin, int state)
1369 ewin->state.visibility = state;
1373 EwinReparent(EWin * ewin, Win parent)
1375 EwinWithdraw(ewin, parent);
1379 EwinRaise(EWin * ewin)
1381 static int call_depth = 0;
1385 if (call_depth > 256)
1389 num = EoRaise(ewin);
1391 if (EDebug(EDBUG_TYPE_RAISELOWER))
1392 Eprintf("EwinRaise(%d) %#lx %s n=%d\n", call_depth,
1393 EwinGetClientXwin(ewin), EwinGetTitle(ewin), num);
1395 if (num == 0) /* Quit if stacking is unchanged */
1398 lst = EwinListTransients(ewin, &num, 1);
1399 for (i = 0; i < num; i++)
1403 if (call_depth == 1)
1405 ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin);
1414 EwinLower(EWin * ewin)
1416 static int call_depth = 0;
1420 if (call_depth > 256)
1424 num = EoLower(ewin);
1426 if (EDebug(EDBUG_TYPE_RAISELOWER))
1427 Eprintf("EwinLower(%d) %#lx %s n=%d\n", call_depth,
1428 EwinGetClientXwin(ewin), EwinGetTitle(ewin), num);
1430 if (num == 0) /* Quit if stacking is unchanged */
1433 lst = EwinListTransientFor(ewin, &num);
1434 for (i = 0; i < num; i++)
1438 if (call_depth == 1)
1440 ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin);
1449 EwinShow(EWin * ewin)
1451 if (EoIsShown(ewin))
1454 if (EwinGetClientWin(ewin))
1456 #if 0 /* FIXME - Why? */
1457 if (ewin->state.shaded)
1458 EMoveResizeWindow(ewin->win_container, -30, -30, 1, 1);
1460 EMapWindow(EwinGetClientWin(ewin));
1463 if (ewin->update.shape)
1466 EwinPropagateShapes(ewin);
1472 EwinStateUpdate(ewin);
1474 if (ewin->place.gravity < 0)
1475 EwinSetPlacementGravity(ewin, EoGetX(ewin), EoGetY(ewin));
1479 EwinHide(EWin * ewin)
1481 if (!EwinIsInternal(ewin) && (!EoIsShown(ewin) || !EwinIsMapped(ewin)))
1486 EUnmapWindow(EwinGetClientWin(ewin));
1491 EwinStateUpdate(ewin);
1493 if (!EwinIsInternal(ewin) || ewin->state.iconified)
1496 if (EwinGetClientWin(ewin))
1498 ESelectInput(EwinGetClientWin(ewin), NoEventMask);
1499 XShapeSelectInput(disp, EwinGetClientXwin(ewin), NoEventMask);
1502 if (ewin->ops && ewin->ops->Close)
1503 ewin->ops->Close(ewin);
1509 EwinKill(EWin * ewin)
1511 if (EwinIsInternal(ewin))
1514 XKillClient(disp, EwinGetClientXwin(ewin));
1516 #if 0 /* Wait for unmap/destroy for now */
1526 EwinSetTitle(EWin * ewin, const char *title)
1528 HintsSetWindowName(EwinGetClientWin(ewin), title);
1530 _EFDUP(ewin->o.icccm.wm_name, title);
1531 _EFDUP(ewin->ewmh.wm_name, title);
1535 EwinSetClass(EWin * ewin, const char *name, const char *clss)
1537 HintsSetWindowClass(EwinGetClientWin(ewin), name, clss);
1539 _EFDUP(ewin->o.icccm.wm_res_name, name);
1540 _EFDUP(ewin->o.icccm.wm_res_class, clss);
1544 EwinGetTitle(const EWin * ewin)
1550 name = ewin->ewmh.wm_name;
1553 name = EwinGetIcccmName(ewin);
1558 return (name && name[0]) ? name : NULL;
1562 EwinGetIconName(const EWin * ewin)
1566 name = ewin->ewmh.wm_icon_name;
1569 name = ewin->icccm.wm_icon_name;
1573 return EwinGetTitle(ewin);
1576 return (name && strlen(name)) ? name : NULL;
1580 EwinBorderGetName(const EWin * ewin)
1582 return (ewin->border) ? BorderGetName(ewin->border) : "?";
1586 EwinBorderGetSize(const EWin * ewin, int *bl, int *br, int *bt, int *bb)
1588 const Border *b = ewin->border;
1592 *bl = *br = *bt = *bb = 0;
1596 *bl = b->border.left;
1597 *br = b->border.right;
1598 *bt = b->border.top;
1599 *bb = b->border.bottom;
1603 EwinBorderUpdateState(EWin * ewin)
1605 EwinBorderDraw(ewin, 0, 0);
1609 EwinIsOnScreen(const EWin * ewin)
1613 if (EoIsSticky(ewin))
1615 if (EoGetDesk(ewin) != DesksGetCurrent())
1623 if (x + w <= 0 || x >= WinGetW(VROOT) || y + h <= 0 || y >= WinGetH(VROOT))
1630 * Save current position in absolute viewport coordinates
1633 EwinRememberPositionSet(EWin * ewin)
1637 ewin->req_x = EoGetX(ewin);
1638 ewin->req_y = EoGetY(ewin);
1639 if (!EoIsSticky(ewin))
1641 DeskGetArea(EoGetDesk(ewin), &ax, &ay);
1642 ewin->req_x += ax * WinGetW(VROOT);
1643 ewin->req_y += ay * WinGetH(VROOT);
1648 * Get saved position in relative viewport coordinates
1651 EwinRememberPositionGet(EWin * ewin, Desk * dsk, int *px, int *py)
1657 if (!EoIsSticky(ewin))
1659 DeskGetArea(dsk, &ax, &ay);
1660 x -= ax * WinGetW(VROOT);
1661 y -= ay * WinGetH(VROOT);
1669 * Set placement gravity
1672 EwinSetPlacementGravity(EWin * ewin, int x, int y)
1674 int w, h, ax, ay, wd, hd;
1677 dsk = EoGetDesk(ewin);
1680 DeskGetArea(dsk, &ax, &ay);
1685 /* Get relative area */
1686 ewin->place.ax = ewin->area_x;
1687 ewin->place.ay = ewin->area_y;
1688 ax = ewin->place.ax - ax;
1689 ay = ewin->place.ay - ay;
1694 if (x <= (wd - w) / 2)
1696 if (y <= (hd - h) / 2)
1698 ewin->place.gravity = EWIN_GRAVITY_NW;
1704 ewin->place.gravity = EWIN_GRAVITY_SW;
1706 ewin->place.gy = hd - (y + h);
1711 if (y <= (hd - h) / 2)
1713 ewin->place.gravity = EWIN_GRAVITY_NE;
1714 ewin->place.gx = wd - (x + w);
1719 ewin->place.gravity = EWIN_GRAVITY_SE;
1720 ewin->place.gx = wd - (x + w);
1721 ewin->place.gy = hd - (y + h);
1726 Eprintf("Set gravity %d,%d %d,%d %d %d,%d %d,%d: %s\n", ax, ay, x, y,
1727 ewin->place.gravity, ewin->place.ax, ewin->place.ay,
1728 ewin->place.gx, ewin->place.gy, EwinGetTitle(ewin));
1733 EwinReposition(EWin * ewin)
1735 int wdo, hdo, wdn, hdn;
1736 int x, y, w, h, ax, ay, xn, yn;
1738 wdo = Mode.screen.w_old;
1739 hdo = Mode.screen.h_old;
1740 wdn = WinGetW(VROOT);
1741 hdn = WinGetH(VROOT);
1748 /* Get relative area */
1749 if (EoIsSticky(ewin))
1755 DeskGetArea(EoGetDesk(ewin), &ax, &ay);
1756 ax = ewin->place.ax - ax;
1757 ay = ewin->place.ay - ay;
1763 /* Reposition to same distance from screen edges determined by
1764 * placement gravity.
1765 * Fall back to left/top if this causes left/top to go offscreen */
1766 switch (ewin->place.gravity)
1769 case EWIN_GRAVITY_NW:
1770 case EWIN_GRAVITY_SW:
1771 xn = ewin->place.gx;
1773 case EWIN_GRAVITY_NE:
1774 case EWIN_GRAVITY_SE:
1775 xn = wdn - w - ewin->place.gx;
1778 if (x > 0 && xn < 0)
1781 switch (ewin->place.gravity)
1784 case EWIN_GRAVITY_NW:
1785 case EWIN_GRAVITY_NE:
1786 yn = ewin->place.gy;
1788 case EWIN_GRAVITY_SW:
1789 case EWIN_GRAVITY_SE:
1790 yn = hdn - h - ewin->place.gy;
1793 if (y > 0 && yn < 0)
1797 Eprintf("Reposition %d,%d -> %d,%d: %s\n", x, y, xn, yn, EwinGetTitle(ewin));
1803 EwinMove(ewin, xn, yn);
1807 EwinWarpTo(EWin * ewin)
1809 if (ewin == Mode.mouse_over_ewin)
1812 if (ewin->state.iconified)
1815 EXWarpPointer(EoGetXwin(ewin), EoGetW(ewin) / 2, EoGetH(ewin) / 2);
1816 Mode.mouse_over_ewin = ewin;
1823 unsigned char inh_app;
1824 unsigned char inh_user;
1825 unsigned char inh_wm;
1835 unsigned autoshade:1;
1840 unsigned no_shadow:1;
1846 EwinFlagsEncode(const EWin * ewin, unsigned int *flags)
1852 fm.f.inh_app = ewin->inh_app.all;
1853 fm.f.inh_user = ewin->inh_user.all;
1854 fm.f.inh_wm = ewin->inh_wm.all;
1857 fm2.f.nua = ewin->props.never_use_area;
1858 fm2.f.ctf = ewin->props.focusclick;
1859 fm2.f.nbg = ewin->props.no_button_grabs;
1860 fm2.f.autoshade = ewin->props.autoshade;
1862 fm2.f.no_fade = !EoGetFade(ewin);
1863 fm2.f.no_shadow = !EoGetShadow(ewin);
1871 EwinFlagsDecode(EWin * ewin, const unsigned int *flags)
1877 ewin->inh_app.all = fm.f.inh_app;
1878 ewin->inh_user.all = fm.f.inh_user;
1879 ewin->inh_wm.all = fm.f.inh_wm;
1882 ewin->props.never_use_area = fm2.f.nua;
1883 ewin->props.focusclick = fm2.f.ctf;
1884 ewin->props.no_button_grabs = fm2.f.nbg;
1885 ewin->props.autoshade = fm2.f.autoshade;
1887 EoSetFade(ewin, !fm2.f.no_fade);
1888 EoSetShadow(ewin, !fm2.f.no_shadow);
1893 EwinUpdateOpacity(EWin * ewin)
1895 unsigned int opacity;
1898 if (ewin->state.moving || ewin->state.resizing)
1899 opacity = OpacityFromPercent(Conf.opacity.movres);
1900 else if (ewin->state.active)
1901 opacity = ewin->props.focused_opacity;
1903 opacity = ewin->ewmh.opacity;
1905 opacity = ewin->state.active ?
1906 OpacityFromPercent(Conf.opacity.focused) :
1907 OpacityFromPercent(Conf.opacity.unfocused);
1909 opacity = 0xffffffff; /* Fallback */
1911 EoChangeOpacity(ewin, opacity);
1918 EwinSlideIn(void *data)
1920 EWin *ewin = (EWin *) data;
1923 if (!EwinFindByPtr(ewin))
1926 SlideEwinTo(ewin, EoGetX(ewin), EoGetY(ewin), ewin->req_x, ewin->req_y,
1927 Conf.place.slidespeedmap, Conf.place.slidemode);
1930 Mode.place.doing_slide = 0;
1945 EwinChange(EWin * ewin __UNUSED__, unsigned int flag)
1947 EWinChanges.flags |= flag;
1951 EwinChangesStart(EWin * ewin)
1953 EWinChanges.flags = 0;
1954 /* Brute force :) */
1955 EWinChanges.ewin_old = *ewin;
1959 EwinChangesProcess(EWin * ewin)
1961 if (!EWinChanges.flags)
1964 if (EWinChanges.flags & EWIN_CHANGE_NAME)
1966 EwinBorderUpdateInfo(ewin);
1967 EwinBorderCalcSizes(ewin, 1);
1970 if (EWinChanges.flags & EWIN_CHANGE_DESKTOP)
1974 desk = EoGetDesk(ewin);
1975 pdesk = EoGetDesk(&EWinChanges.ewin_old);
1976 if (desk != pdesk && !EoIsSticky(ewin))
1978 EoSetDesk(ewin, pdesk);
1979 EwinMoveToDesktop(ewin, desk);
1983 if (EWinChanges.flags & EWIN_CHANGE_ICON_PMAP)
1985 ModulesSignal(ESIGNAL_EWIN_CHANGE_ICON, ewin);
1988 if (EWinChanges.flags & EWIN_CHANGE_OPACITY)
1990 EoChangeOpacity(ewin, ewin->ewmh.opacity);
1991 SnapshotEwinUpdate(ewin, SNAP_USE_OPACITY);
1994 if (EWinChanges.flags & EWIN_CHANGE_ATTENTION)
1996 HintsSetWindowState(ewin);
1999 EWinChanges.flags = 0;
2003 EwinListTransients(const EWin * ewin, int *num, int group)
2005 EWin *const *ewins, **lst, *ew;
2011 if (EwinGetTransientCount(ewin) <= 0)
2014 ewins = EwinListGetAll(&n);
2016 /* Find regular transients */
2017 for (i = 0; i < n; i++)
2021 /* Skip self-reference */
2025 if (EwinGetTransientFor(ew) == EwinGetClientXwin(ewin))
2027 lst = EREALLOC(EWin *, lst, j + 1);
2035 /* Group transients (if ewin is not a transient) */
2036 if (EwinIsTransient(ewin))
2039 for (i = 0; i < n; i++)
2043 /* Skip self-reference */
2047 if (EwinGetTransientFor(ew) == WinGetXwin(VROOT) &&
2048 EwinGetWindowGroup(ew) == EwinGetWindowGroup(ewin))
2050 lst = EREALLOC(EWin *, lst, j + 1);
2061 EwinListTransientFor(const EWin * ewin, int *num)
2063 EWin *const *ewins, **lst, *ew;
2069 if (!EwinIsTransient(ewin))
2072 ewins = EwinListGetAll(&n);
2073 for (i = 0; i < n; i++)
2077 /* Skip self-reference */
2081 /* Regular parent or if root trans, top level group members */
2082 if ((EwinGetTransientFor(ewin) == EwinGetClientXwin(ew)) ||
2083 (!EwinIsTransient(ew) &&
2084 EwinGetTransientFor(ewin) == WinGetXwin(VROOT) &&
2085 EwinGetWindowGroup(ew) == EwinGetWindowGroup(ewin)))
2087 lst = EREALLOC(EWin *, lst, j + 1);
2098 EwinsTouch(Desk * dsk)
2101 EWin *const *lst, *ewin;
2104 lst = EwinListGetAll(&num);
2106 lst = EwinListGetForDesk(&num, dsk);
2108 for (i = num - 1; i >= 0; i--)
2111 if (EwinIsMapped(ewin) && EwinIsOnScreen(ewin))
2112 #if 1 /* FIXME - Which one? */
2113 EwinMove(ewin, EoGetX(ewin), EoGetY(ewin));
2115 EwinResize(ewin, ewin->client.w, ewin->client.h);
2121 EwinsReposition(void)
2126 lst = EwinListGetAll(&num);
2127 for (i = num - 1; i >= 0; i--)
2128 EwinReposition(lst[i]);
2132 EwinsMoveStickyToDesk(Desk * dsk)
2134 EWin *const *lst, *ewin;
2137 lst = EwinListStackGet(&num);
2138 for (i = 0; i < num; i++)
2140 ewin = lst[num - 1 - i];
2141 if (!EoIsSticky(ewin) && !EoIsFloating(ewin))
2143 if (EwinIsTransientChild(ewin))
2146 EwinMoveToDesktop(ewin, dsk);
2153 Window *xwins, xwin, par, rt;
2154 XWindowAttributes attr;
2155 unsigned int i, num;
2157 #ifdef USE_EXT_INIT_WIN
2158 Window init_win = ExtInitWinGet();
2163 XQueryTree(disp, WinGetXwin(VROOT), &rt, &par, &xwins, &num);
2167 for (i = 0; i < num; i++)
2171 /* Skip if already "known" */
2172 if (EobjListStackFind(xwin))
2175 if (!XGetWindowAttributes(disp, xwin, &attr))
2178 if (attr.map_state == IsUnmapped)
2181 if (attr.override_redirect)
2183 XUnmapWindow(disp, xwin); /* Makes the CM catch it on map */
2184 XMapRaised(disp, xwin);
2185 #ifdef USE_EXT_INIT_WIN
2187 XRaiseWindow(disp, init_win);
2192 AddToFamily(NULL, xwin);
2202 EWin *const *lst, *ewin;
2204 if (EDebug(EDBUG_TYPE_SESSION))
2205 Eprintf("EwinsSetFree\n");
2207 EHintsSetInfoOnAll();
2209 lst = EwinListStackGet(&num);
2210 for (i = num - 1; i >= 0; i--)
2213 if (EwinIsInternal(ewin))
2216 if (ewin->state.iconified)
2217 ICCCM_DeIconify(ewin);
2219 /* This makes E determine the client window stacking at exit */
2220 EwinInstantUnShade(ewin);
2221 EReparentWindow(EwinGetClientWin(ewin), RROOT,
2222 ewin->client.x, ewin->client.y);
2231 ActionsCheck(const char *which, EWin * ewin, XEvent * ev)
2235 if (Mode.action_inhibit) /* Probably not here */
2238 ac = ActionclassFind(which);
2242 if (ev->type == ButtonPress)
2244 GrabPointerSet(EoGetWin(ewin), ECSR_GRAB, 0);
2245 FocusToEWin(ewin, FOCUS_CLICK);
2247 else if (ev->type == ButtonRelease)
2249 GrabPointerRelease();
2252 return ActionclassEvent(ac, ev, ewin);
2255 #define DEBUG_EWIN_EVENTS 0
2257 EwinHandleEventsToplevel(Win win __UNUSED__, XEvent * ev, void *prm)
2259 EWin *ewin = (EWin *) prm;
2264 ActionsHandleKey(XLookupKeysym(&ev->xkey, 0));
2267 ActionsCheck("BUTTONBINDINGS", ewin, ev);
2271 ActionsCheck("BUTTONBINDINGS", ewin, ev);
2272 BorderCheckState(ewin, ev);
2275 FocusHandleEnter(ewin, ev);
2278 FocusHandleLeave(ewin, ev);
2281 ActionsHandleMotion();
2284 #if DEBUG_EWIN_EVENTS
2285 Eprintf("EwinHandleEventsToplevel: type=%2d win=%#lx: %s\n",
2286 ev->type, EwinGetClientXwin(ewin), EwinGetTitle(ewin));
2293 EwinHandleEventsContainer(Win win __UNUSED__, XEvent * ev, void *prm)
2295 EWin *ewin = (EWin *) prm;
2298 Eprintf("EwinHandleEventsContainer: type=%2d win=%#lx: %s\n",
2299 ev->type, EwinGetClientXwin(ewin), EwinGetTitle(ewin));
2304 FocusHandleClick(ewin, EwinGetContainerWin(ewin));
2308 if (ev->xmaprequest.window != EwinGetClientXwin(ewin))
2310 EwinEventMapRequest(ewin, ev->xmaprequest.window);
2312 case ConfigureRequest:
2313 if (ev->xconfigurerequest.window != EwinGetClientXwin(ewin))
2315 EwinEventConfigureRequest(ewin, ev);
2318 if (ev->xresizerequest.window != EwinGetClientXwin(ewin))
2320 EwinEventResizeRequest(ewin, ev);
2322 case CirculateRequest:
2323 if (ev->xcirculaterequest.window != EwinGetClientXwin(ewin))
2325 EwinEventCirculateRequest(ewin, ev);
2329 if (ev->xdestroywindow.window != EwinGetClientXwin(ewin))
2331 EwinEventDestroy(ewin);
2334 case EX_EVENT_UNMAP_GONE:
2335 if (ev->xunmap.window != EwinGetClientXwin(ewin))
2340 if (ev->xunmap.window != EwinGetClientXwin(ewin))
2343 EwinEventUnmap(ewin, ev);
2347 if (ev->xmap.window != EwinGetClientXwin(ewin))
2349 EwinEventMap(ewin, ev);
2352 case EX_EVENT_REPARENT_GONE:
2353 if (ev->xreparent.window != EwinGetClientXwin(ewin))
2357 case ReparentNotify:
2358 if (ev->xreparent.window != EwinGetClientXwin(ewin))
2361 EwinEventReparent(ewin);
2364 case EX_EVENT_MAP_GONE:
2366 case ConfigureNotify:
2370 Eprintf("EwinHandleEventsContainer: type=%2d win=%#lx: %s\n",
2371 ev->type, EwinGetClientXwin(ewin), EwinGetTitle(ewin));
2377 EwinHandleEventsClient(Win win __UNUSED__, XEvent * ev, void *prm)
2379 EWin *ewin = (EWin *) prm;
2385 if (ev->xfocus.detail == NotifyInferior)
2387 if (ewin->border->aclass)
2388 ActionclassEvent(ewin->border->aclass, ev, ewin);
2389 FocusHandleChange(ewin, ev);
2391 case ConfigureNotify:
2394 case VisibilityNotify:
2395 EwinEventVisibility(ewin, ev->xvisibility.state);
2398 case PropertyNotify:
2399 EwinEventPropertyNotify(ewin, ev);
2403 HintsProcessClientClientMessage(ewin, &(ev->xclient));
2406 case EX_EVENT_SHAPE_NOTIFY:
2407 EwinEventShapeChange(ewin, ev);
2411 #if DEBUG_EWIN_EVENTS
2412 Eprintf("EwinHandleEventsClient: type=%2d win=%#lx: %s\n",
2413 ev->type, EwinGetClientXwin(ewin), EwinGetTitle(ewin));
2420 EwinHandleEventsRoot(Win win __UNUSED__, XEvent * ev, void *prm __UNUSED__)
2427 EwinEventMapRequest(NULL, ev->xmaprequest.window);
2429 case ConfigureRequest:
2431 Eprintf("EwinHandleEventsRoot ConfigureRequest %#lx\n",
2432 ev->xconfigurerequest.window);
2434 ewin = EwinFindByClient(ev->xconfigurerequest.window);
2435 EwinEventConfigureRequest(ewin, ev);
2439 Eprintf("EwinHandleEventsRoot ResizeRequest %#lx\n",
2440 ev->xresizerequest.window);
2442 ewin = EwinFindByClient(ev->xresizerequest.window);
2443 EwinEventResizeRequest(ewin, ev);
2445 case CirculateRequest:
2447 Eprintf("EwinHandleEventsRoot CirculateRequest %#lx\n",
2448 ev->xcirculaterequest.window);
2450 EwinEventCirculateRequest(NULL, ev);
2454 case EX_EVENT_UNMAP_GONE:
2455 /* Catch clients unmapped after MapRequest but before being reparented */
2456 ewin = EwinFindByClient(ev->xunmap.window);
2459 if (ev->type == EX_EVENT_UNMAP_GONE)
2461 EwinEventUnmap(ewin, ev);
2465 /* Catch clients destroyed after MapRequest but before being reparented */
2466 ewin = EwinFindByClient(ev->xdestroywindow.window);
2469 EwinEventDestroy(ewin);
2472 case ReparentNotify:
2473 case EX_EVENT_REPARENT_GONE:
2474 ewin = EwinFindByClient(ev->xreparent.window);
2477 if (ev->type == EX_EVENT_REPARENT_GONE)
2479 EwinEventReparent(ewin);
2483 HintsProcessRootClientMessage(&(ev->xclient));
2488 Eprintf("EwinHandleEventsRoot: type=%2d win=%#lx\n",
2489 ev->type, ev->xany.window);
2498 EventCallbackRegister(VROOT, 0, EwinHandleEventsRoot, NULL);
2507 EwinsSighan(int sig, void *prm)
2519 case ESIGNAL_DESK_RESIZE:
2522 case ESIGNAL_THEME_TRANS_CHANGE:
2523 EwinsTouch(DesksGetCurrent());
2525 case ESIGNAL_BACKGROUND_CHANGE:
2526 EwinsTouch((Desk *) prm);
2532 static const IpcItem EwinsIpcArray[] = {
2534 #define N_IPC_FUNCS (sizeof(EwinsIpcArray)/sizeof(IpcItem))
2536 #define N_IPC_FUNCS 0
2537 #define EwinsIpcArray NULL
2543 extern const EModule ModEwins;
2544 const EModule ModEwins = {
2547 {N_IPC_FUNCS, EwinsIpcArray}