/* * Copyright (C) 2000-2005 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2005 Kim Woelders * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of the Software, its documentation and marketing & publicity * materials, and acknowledgment shall be given in the documentation, materials * and software packages that this Software was used. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "E.h" #include "ecompmgr.h" #include "snaps.h" #include #define EWIN_TOP_EVENT_MASK \ (ButtonPressMask | ButtonReleaseMask | \ EnterWindowMask | LeaveWindowMask | PointerMotionMask /* | \ StructureNotifyMask */) #define EWIN_CONTAINER_EVENT_MASK \ (/* ButtonPressMask | ButtonReleaseMask | */ \ /* StructureNotifyMask | ResizeRedirectMask | */ \ SubstructureNotifyMask | SubstructureRedirectMask) #define EWIN_CLIENT_EVENT_MASK \ (EnterWindowMask | LeaveWindowMask | FocusChangeMask | \ /* StructureNotifyMask | */ ResizeRedirectMask | \ PropertyChangeMask | ColormapChangeMask | VisibilityChangeMask) static void EwinHandleEventsToplevel(XEvent * ev, void *prm); static void EwinHandleEventsContainer(XEvent * ev, void *prm); static void EwinHandleEventsClient(XEvent * ev, void *prm); static void EwinEventsConfigure(EWin * ewin, int mode) { long emask; emask = (mode) ? ~((long)0) : ~(EnterWindowMask | LeaveWindowMask); ESelectInput(EoGetWin(ewin), EWIN_TOP_EVENT_MASK & emask); ESelectInput(ewin->client.win, ewin->client.event_mask & emask); EwinBorderEventsConfigure(ewin, mode); } static EWin * EwinCreate(Window win, int type) { EWin *ewin; XSetWindowAttributes att; ewin = Ecalloc(1, sizeof(EWin)); ewin->type = type; ewin->state = (Mode.wm.startup) ? EWIN_STATE_STARTUP : EWIN_STATE_NEW; ewin->ld = -1; ewin->lx = -1; ewin->ly = -1; ewin->lw = -1; ewin->lh = -1; ewin->client.x = -1; ewin->client.y = -1; ewin->client.w = -1; ewin->client.h = -1; ewin->client.need_input = 1; ewin->client.aspect_min = 0.0; ewin->client.aspect_max = 65535.0; ewin->client.w_inc = 1; ewin->client.h_inc = 1; ewin->client.width.max = 65535; ewin->client.height.max = 65535; ewin->client.mwm_decor_border = 1; ewin->client.mwm_decor_resizeh = 1; ewin->client.mwm_decor_title = 1; ewin->client.mwm_decor_menu = 1; ewin->client.mwm_decor_minimize = 1; ewin->client.mwm_decor_maximize = 1; ewin->client.mwm_func_resize = 1; ewin->client.mwm_func_move = 1; ewin->client.mwm_func_minimize = 1; ewin->client.mwm_func_maximize = 1; ewin->client.mwm_func_close = 1; EoSetWin(ewin, ECreateWindow(VRoot.win, -10, -10, 1, 1, 1)); ewin->win_container = ECreateWindow(EoGetWin(ewin), 0, 0, 1, 1, 0); #if 0 /* ENABLE_GNOME - Not actually used */ ewin->expanded_width = -1; ewin->expanded_height = -1; #endif ewin->area_x = -1; ewin->area_y = -1; EobjInit(&ewin->o, EOBJ_TYPE_EWIN, -1, -1, -1, -1); EoSetDesk(ewin, DesksGetCurrent()); EoSetLayer(ewin, 4); ewin->props.opacity = 0xFFFFFFFF; att.event_mask = EWIN_CONTAINER_EVENT_MASK; att.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; EChangeWindowAttributes(ewin->win_container, CWEventMask | CWDontPropagate, &att); EMapWindow(ewin->win_container); att.event_mask = EWIN_TOP_EVENT_MASK; att.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; EChangeWindowAttributes(EoGetWin(ewin), CWEventMask | CWDontPropagate, &att); ewin->client.win = win; FocusEwinSetGrabs(ewin); GrabButtonGrabs(ewin); EobjListStackAdd(&ewin->o, 0); EobjListFocusAdd(&ewin->o, 0); ewin->client.event_mask = EWIN_CLIENT_EVENT_MASK; AddItem(ewin, "EWIN", win, LIST_TYPE_EWIN); XShapeSelectInput(disp, win, ShapeNotifyMask); if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("EwinCreate %#lx frame=%#lx state=%d\n", ewin->client.win, EoGetWin(ewin), ewin->state); EventCallbackRegister(EoGetWin(ewin), 0, EwinHandleEventsToplevel, ewin); EventCallbackRegister(ewin->win_container, 0, EwinHandleEventsContainer, ewin); ERegisterWindow(ewin->client.win); EventCallbackRegister(ewin->client.win, 0, EwinHandleEventsClient, ewin); if (!EwinIsInternal(ewin)) { XSetWindowBorderWidth(disp, win, 0); ewin->client.bw = 0; } ModulesSignal(ESIGNAL_EWIN_CREATE, ewin); return ewin; } static void EwinCleanup(EWin * ewin) { EwinBorderDetach(ewin); } static void EwinDestroy(EWin * ewin) { EWin **lst; int i, num; if (!ewin) return; if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("EwinDestroy %#lx %s state=%d\n", ewin->client.win, EwinGetName(ewin), ewin->state); /* FIXME - Fading */ ECompMgrWinDel(&ewin->o, True, False); RemoveItem(NULL, ewin->client.win, LIST_FINDBY_ID, LIST_TYPE_EWIN); EventCallbackUnregister(EoGetWin(ewin), 0, EwinHandleEventsToplevel, ewin); EventCallbackUnregister(ewin->win_container, 0, EwinHandleEventsContainer, ewin); EventCallbackUnregister(ewin->client.win, 0, EwinHandleEventsClient, ewin); if (!EwinIsInternal(ewin)) EUnregisterWindow(ewin->client.win); EobjListStackDel(&ewin->o); EobjListFocusDel(&ewin->o); HintsSetClientList(); SnapshotEwinUnmatch(ewin); ModulesSignal(ESIGNAL_EWIN_DESTROY, ewin); lst = EwinListTransientFor(ewin, &num); for (i = 0; i < num; i++) { lst[i]->has_transients--; if (lst[i]->has_transients < 0) /* Paranoia? */ lst[i]->has_transients = 0; } if (lst) Efree(lst); EwinCleanup(ewin); if (ewin->icccm.wm_name) Efree(ewin->icccm.wm_name); if (ewin->icccm.wm_res_class) Efree(ewin->icccm.wm_res_class); if (ewin->icccm.wm_res_name) Efree(ewin->icccm.wm_res_name); if (ewin->icccm.wm_role) Efree(ewin->icccm.wm_role); if (ewin->icccm.wm_command) Efree(ewin->icccm.wm_command); if (ewin->icccm.wm_machine) Efree(ewin->icccm.wm_machine); #if ENABLE_EWMH if (ewin->ewmh.wm_name) Efree(ewin->ewmh.wm_name); if (ewin->ewmh.wm_icon_name) Efree(ewin->ewmh.wm_icon_name); #endif if (ewin->icccm.wm_icon_name) Efree(ewin->icccm.wm_icon_name); if (EoGetWin(ewin)) EDestroyWindow(EoGetWin(ewin)); if (ewin->bits) Efree(ewin->bits); if (ewin->session_id) Efree(ewin->session_id); FreePmapMask(&ewin->mini_pmm); if (ewin->icon_image) { imlib_context_set_image(ewin->icon_image); imlib_free_image_and_decache(); } GroupsEwinRemove(ewin); Efree(ewin); } void DetermineEwinFloat(EWin * ewin, int dx, int dy) { char dofloat = 0; int desk, x, y, w, h, xd, yd; desk = EoGetDesk(ewin); x = EoGetX(ewin); y = EoGetY(ewin); w = EoGetW(ewin); h = EoGetH(ewin); xd = DeskGetX(desk); yd = DeskGetY(desk); if ((desk != 0) && (EoIsFloating(ewin) < 2) && ((xd != 0) || (yd != 0) || (DesksGetCurrent() != desk))) { switch (Conf.desks.dragdir) { case 0: if (((x + dx < 0) || ((x + dx + w <= VRoot.w) && ((DesktopAt(xd + x + dx + w - 1, yd) != desk))))) dofloat = 1; break; case 1: if (((x + dx + w > VRoot.w) || ((x + dx >= 0) && ((DesktopAt(xd + x + dx, yd) != desk))))) dofloat = 1; break; case 2: if (((y + dy < 0) || ((y + dy + h <= VRoot.h) && ((DesktopAt(xd, yd + y + dy + h - 1) != desk))))) dofloat = 1; break; case 3: if (((y + dy + h > VRoot.h) || ((y + dy >= 0) && ((DesktopAt(xd, yd + y + dy) != desk))))) dofloat = 1; break; } if (dofloat) FloatEwinAt(ewin, x + xd, y + yd); } } EWin * GetEwinByCurrentPointer(void) { Window rt, ch; int dum, x, y; unsigned int mr; XQueryPointer(disp, DeskGetWin(DesksGetCurrent()), &rt, &ch, &x, &y, &dum, &dum, &mr); return FindEwinByBase(ch); } EWin * GetEwinPointerInClient(void) { Window rt, ch; int dum, px, py, desk; EWin *const *lst, *ewin; int i, num; desk = DesktopAt(Mode.x, Mode.y); XQueryPointer(disp, DeskGetWin(desk), &rt, &ch, &dum, &dum, &px, &py, (unsigned int *)&dum); px -= DeskGetX(desk); py -= DeskGetY(desk); lst = EwinListGetForDesk(&num, desk); for (i = 0; i < num; i++) { int x, y, w, h; ewin = lst[i]; x = EoGetX(ewin); y = EoGetY(ewin); w = EoGetW(ewin); h = EoGetH(ewin); if ((px >= x) && (py >= y) && (px < (x + w)) && (py < (y + h)) && EwinIsMapped(ewin)) return ewin; } return NULL; } EWin * GetFocusEwin(void) { return Mode.focuswin; } EWin * GetContextEwin(void) { EWin *ewin; #if 0 ewin = Mode.mouse_over_ewin; if (ewin && ewin->type != EWIN_TYPE_MENU) return ewin; #endif ewin = Mode.context_ewin; if (ewin) goto done; ewin = Mode.focuswin; if (ewin && ewin->type != EWIN_TYPE_MENU) goto done; ewin = NULL; done: #if 0 Eprintf("GetContextEwin %#lx %s\n", EwinGetClientWin(ewin), EwinGetName(ewin)); #endif return ewin; } void SetContextEwin(EWin * ewin) { if (ewin && ewin->type == EWIN_TYPE_MENU) return; #if 0 Eprintf("SetContextEwin %#lx %s\n", EwinGetClientWin(ewin), EwinGetName(ewin)); #endif Mode.context_ewin = ewin; } static void EwinDetermineArea(EWin * ewin) { int ax, ay; DeskGetArea(EoGetDesk(ewin), &ax, &ay); ax = (EoGetX(ewin) + (EoGetW(ewin) / 2) + (ax * VRoot.w)) / VRoot.w; ay = (EoGetY(ewin) + (EoGetH(ewin) / 2) + (ay * VRoot.h)) / VRoot.h; AreaFix(&ax, &ay); if (ax != ewin->area_x || ay != ewin->area_y) { ewin->area_x = ax; ewin->area_y = ay; HintsSetWindowArea(ewin); } } /* * Derive frame window position from client window and border properties */ static void EwinGetPosition(const EWin * ewin, int *px, int *py) { int x, y, bw, frame_lr, frame_tb; x = ewin->client.x; y = ewin->client.y; bw = ewin->client.bw; frame_lr = ewin->border->border.left + ewin->border->border.right; frame_tb = ewin->border->border.top + ewin->border->border.bottom; switch (ewin->client.grav) { case NorthWestGravity: case SouthWestGravity: case WestGravity: x -= bw; break; case NorthEastGravity: case EastGravity: case SouthEastGravity: x -= frame_lr / 2; break; case NorthGravity: case CenterGravity: case SouthGravity: x -= frame_lr - bw; break; case StaticGravity: x -= ewin->border->border.left; break; default: break; } switch (ewin->client.grav) { case NorthWestGravity: case NorthGravity: case NorthEastGravity: y -= bw; break; case WestGravity: case CenterGravity: case EastGravity: y -= frame_tb / 2; break; case SouthWestGravity: case SouthGravity: case SouthEastGravity: y -= frame_tb - bw; break; case StaticGravity: y -= ewin->border->border.top; break; default: break; } *px = x; *py = y; } /* * Derive frame window geometry from client window properties */ static void EwinGetGeometry(EWin * ewin) { int x, y; EwinGetPosition(ewin, &x, &y); ewin->client.x = x + ewin->border->border.left; ewin->client.y = y + ewin->border->border.top; EoSetX(ewin, ewin->shape_x = x); EoSetY(ewin, ewin->shape_y = y); EoSetW(ewin, ewin->client.w + ewin->border->border.left + ewin->border->border.right); EoSetH(ewin, ewin->client.h + ewin->border->border.top + ewin->border->border.bottom); } void EwinPropagateShapes(EWin * ewin) { if (!ewin->docked) PropagateShapes(EoGetWin(ewin)); } static void EwinAdopt(EWin * ewin) { /* We must reparent after getting original window position */ EReparentWindow(ewin->client.win, ewin->win_container, 0, 0); ICCCM_Adopt(ewin); } static EWin * Adopt(EWin * ewin, Window win) { if (ewin) EwinCleanup(ewin); else ewin = EwinCreate(win, EWIN_TYPE_NORMAL); ICCCM_AdoptStart(ewin); ICCCM_GetTitle(ewin, 0); ICCCM_GetHints(ewin, 0); ICCCM_GetInfo(ewin, 0); ICCCM_GetColormap(ewin); ICCCM_GetShapeInfo(ewin); ICCCM_GetGeoms(ewin, 0); HintsGetWindowHints(ewin); SessionGetInfo(ewin, 0); #if 0 /* Do we want this? */ MatchEwinToSM(ewin); #endif WindowMatchEwinOps(ewin); /* Window matches */ SnapshotEwinMatch(ewin); /* Saved settings */ if (Mode.wm.startup) EHintsGetInfo(ewin); /* E restart hints */ ICCCM_MatchSize(ewin); EwinAdopt(ewin); EwinBorderSelect(ewin); /* Select border before calculating geometry */ EwinGetGeometry(ewin); /* Calculate window geometry before border parts */ EwinBorderSetTo(ewin, NULL); EwinEventsConfigure(ewin, 1); if (ewin->shaded) EwinInstantShade(ewin, 1); HintsSetWindowState(ewin); HintsSetClientList(); if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("Adopt %#lx %s state=%d\n", ewin->client.win, EwinGetName(ewin), ewin->state); return ewin; } static EWin * AdoptInternal(Window win, Border * border, int type, void (*init) (EWin * ewin, void *ptr), void *ptr) { EWin *ewin; ewin = EwinCreate(win, type); ewin->border = border; if (init) init(ewin, ptr); /* Type specific initialisation */ ICCCM_AdoptStart(ewin); ICCCM_GetTitle(ewin, 0); ICCCM_GetInfo(ewin, 0); ICCCM_GetShapeInfo(ewin); ICCCM_GetGeoms(ewin, 0); WindowMatchEwinOps(ewin); /* Window matches */ SnapshotEwinMatch(ewin); /* Saved settings */ ICCCM_MatchSize(ewin); EwinAdopt(ewin); EwinBorderSelect(ewin); EwinGetGeometry(ewin); EwinBorderSetTo(ewin, NULL); EwinEventsConfigure(ewin, 1); if (ewin->shaded) EwinInstantShade(ewin, 1); HintsSetWindowState(ewin); HintsSetClientList(); return ewin; } void AddToFamily(EWin * ewin, Window win) { EWin *ewin2; EWin **lst; int i, k, num, fx, fy, x, y, desk; char doslide, manplace; ecore_x_grab(); if (!WinExists(win)) { Eprintf("Window is gone %#lx\n", win); ecore_x_ungrab(); return; } /* adopt the new baby */ ewin = Adopt(ewin, win); /* if it hasn't been planted on a desktop - assign it the current desktop */ desk = EoGetDesk(ewin); /* if is an afterstep/windowmaker dock app - dock it */ if (Conf.dock.enable && ewin->docked) { DockIt(ewin); ewin->props.donthide = 1; ewin->focusclick = 1; } doslide = Conf.mapslide && !Mode.wm.startup; /* if set for borderless then dont slide it in */ if ((!ewin->client.mwm_decor_title) && (!ewin->client.mwm_decor_border)) doslide = 0; ewin2 = NULL; if (ewin->client.transient) { if (ewin->client.transient_for == None || ewin->client.transient_for == VRoot.win) { /* Group transient */ ewin->client.transient_for = VRoot.win; #if 0 /* Maybe? */ ewin->layer++; #endif /* Don't treat this as a normal transient */ ewin->client.transient = -1; } else if (ewin->client.transient_for == ewin->client.win) { /* Some apps actually do this. Why? */ ewin->client.transient = 0; } else { /* Regular transient */ } if (ewin->client.transient) { /* Tag the parent window if this is a transient */ lst = EwinListTransientFor(ewin, &num); for (i = 0; i < num; i++) { lst[i]->has_transients++; if (EoGetLayer(ewin) < EoGetLayer(lst[i])) EoSetLayer(ewin, EoGetLayer(lst[i])); } if (lst) { ewin2 = lst[0]; EoSetSticky(ewin, EoIsSticky(lst[0])); Efree(lst); } else { /* No parents? - not a transient */ ewin->client.transient = 0; } } } if (ewin->client.transient && Conf.focus.transientsfollowleader) { EWin *const *lst2; if (!ewin2) ewin2 = FindItem(NULL, ewin->client.group, LIST_FINDBY_ID, LIST_TYPE_EWIN); if (!ewin2) { lst2 = EwinListGetAll(&num); for (i = 0; i < num; i++) { if ((lst2[i]->iconified) || (ewin->client.group != lst2[i]->client.group)) continue; ewin2 = lst2[i]; break; } } if (ewin2) { desk = EoGetDesk(ewin2); if (!Mode.wm.startup && Conf.focus.switchfortransientmap && !ewin->iconified) DeskGotoByEwin(ewin2); } } if (ewin->st.fullscreen) { ewin->st.fullscreen = 0; EwinSetFullscreen(ewin, 1); ewin->client.already_placed = 1; ShowEwin(ewin); ecore_x_ungrab(); return; } ResizeEwin(ewin, ewin->client.w, ewin->client.h); manplace = 0; if ((!ewin->client.transient) && (Conf.place.manual) && (!ewin->client.already_placed) && (!Mode.wm.startup) && (!Mode.place)) { char cangrab; cangrab = GrabPointerSet(VRoot.win, ECSR_GRAB, 0); if (cangrab == GrabSuccess) manplace = 1; } /* if it hasn't been placed yet.... find a spot for it */ x = EoGetX(ewin); y = EoGetY(ewin); if ((!ewin->client.already_placed) && (!manplace)) { /* Place the window below the mouse pointer */ if (Conf.place.manual_mouse_pointer) { int rx, ry, wx, wy; unsigned int mask; Window junk, root_return; int newWinX = 0, newWinY = 0; /* if the loser has manual placement on and the app asks to be on */ /* a desktop, then send E to that desktop so the user can place */ /* the window there */ DeskGoto(desk); XQueryPointer(disp, VRoot.win, &root_return, &junk, &rx, &ry, &wx, &wy, &mask); Mode.x = rx; Mode.y = ry; ewin->client.already_placed = 1; /* try to center the window on the mouse pointer */ newWinX = rx; newWinY = ry; if (EoGetW(ewin)) newWinX -= EoGetW(ewin) / 2; if (EoGetH(ewin)) newWinY -= EoGetH(ewin) / 2; /* keep it all on this screen if possible */ newWinX = MIN(newWinX, VRoot.w - EoGetW(ewin)); newWinY = MIN(newWinY, VRoot.h - EoGetH(ewin)); newWinX = MAX(newWinX, 0); newWinY = MAX(newWinY, 0); /* this works for me... */ EoSetX(ewin, x = newWinX); EoSetY(ewin, y = newWinY); } else { ewin->client.already_placed = 1; ArrangeEwinXY(ewin, &x, &y); } } /* Force reparent if not on desk 0 */ EoSetDesk(ewin, 0); /* if the window asked to be iconified at the start */ if (ewin->client.start_iconified) { #if 0 /* FIXME - Remove? */ EwinBorderDraw(ewin, 1, 1, 0); #endif MoveEwinToDesktopAt(ewin, desk, x, y); ecore_x_ungrab(); ewin->state = EWIN_STATE_MAPPED; EwinIconify(ewin); ewin->state = EWIN_STATE_ICONIC; return; } /* if we should slide it in and are not currently in the middle of a slide */ if ((manplace) && (!ewin->client.already_placed)) { int rx, ry, wx, wy; unsigned int mask; Window junk, root_return; #if 0 /* FIXME: Disable for now */ /* if the loser has manual placement on and the app asks to be on */ /* a desktop, then send E to that desktop so the user can place */ /* the window there */ DeskGoto(desk); #endif XQueryPointer(disp, VRoot.win, &root_return, &junk, &rx, &ry, &wx, &wy, &mask); Mode.x = rx; Mode.y = ry; ewin->client.already_placed = 1; x = Mode.x + 1; y = Mode.y + 1; #if 0 /* FIXME - Remove? */ EwinBorderDraw(ewin, 1, 1, 0); #endif MoveEwinToDesktop(ewin, desk); RaiseEwin(ewin); MoveEwin(ewin, x, y); RaiseEwin(ewin); ShowEwin(ewin); GrabPointerSet(VRoot.win, ECSR_GRAB, 0); Mode.have_place_grab = 1; Mode.place = 1; ecore_x_ungrab(); EoSetFloating(ewin, 1); /* Causes reparenting to root */ ActionMoveStart(ewin, 1, 0, 0); return; } else if ((doslide) && (!Mode.doingslide)) { MoveEwin(ewin, VRoot.w, VRoot.h); k = rand() % 4; if (k == 0) { fx = (rand() % (VRoot.w)) - EoGetW(ewin); fy = -EoGetH(ewin); } else if (k == 1) { fx = (rand() % (VRoot.w)); fy = VRoot.h; } else if (k == 2) { fx = -EoGetW(ewin); fy = (rand() % (VRoot.h)); } else { fx = VRoot.w; fy = (rand() % (VRoot.h)) - EoGetH(ewin); } #if 0 /* FIXME - Remove? */ EwinBorderDraw(ewin, 1, 1, 0); #endif MoveEwinToDesktop(ewin, desk); RaiseEwin(ewin); MoveEwin(ewin, fx, fy); ShowEwin(ewin); SlideEwinTo(ewin, fx, fy, x, y, Conf.slidespeedmap); MoveEwinToDesktopAt(ewin, desk, x, y); } else { #if 0 /* FIXME - Remove? */ EwinBorderDraw(ewin, 1, 1, 0); #endif MoveEwinToDesktopAt(ewin, desk, x, y); RaiseEwin(ewin); ShowEwin(ewin); } EwinDetermineArea(ewin); ecore_x_ungrab(); } EWin * AddInternalToFamily(Window win, const char *bname, int type, void *ptr, void (*init) (EWin * ewin, void *ptr)) { EWin *ewin; Border *b; b = NULL; if (bname) { b = FindItem(bname, 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER); if (!b) b = FindItem("DEFAULT", 0, LIST_FINDBY_NAME, LIST_TYPE_BORDER); } ecore_x_grab(); ewin = AdoptInternal(win, b, type, init, ptr); #if 0 Eprintf("Desk=%d, layer=%d, sticky=%d, floating=%d\n", EoGetDesk(ewin), EoGetLayer(ewin), EoIsSticky(ewin), EoIsFloating(ewin)); #endif #if 0 /* FIXME - Remove? */ EwinBorderDraw(ewin, 1, 1, 1); #endif EwinConformToDesktop(ewin); EwinDetermineArea(ewin); ecore_x_ungrab(); return ewin; } static void EwinWithdraw(EWin * ewin) { Window win; int x, y; if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("EwinWithdraw %#lx %s state=%d\n", ewin->client.win, EwinGetName(ewin), ewin->state); ecore_x_grab(); /* Park the client window on the root */ x = ewin->client.x; y = ewin->client.y; XTranslateCoordinates(disp, ewin->client.win, VRoot.win, -ewin->border->border.left, -ewin->border->border.top, &x, &y, &win); EReparentWindow(ewin->client.win, VRoot.win, x, y); ICCCM_Withdraw(ewin); HintsDelWindowHints(ewin); ecore_x_sync(); ecore_x_ungrab(); if (EwinIsInternal(ewin)) EwinDestroy(ewin); } void EwinConformToDesktop(EWin * ewin) { Window dwin; dwin = DeskGetWin(EoGetDesk(ewin)); if ((ewin->iconified) && (ewin->parent != dwin)) { ewin->parent = dwin; EReparentWindow(EoGetWin(ewin), dwin, EoGetX(ewin), EoGetY(ewin)); RaiseEwin(ewin); ICCCM_Configure(ewin); } else if (EoIsFloating(ewin)) { if ((ewin->parent != VRoot.win) && (EoIsFloating(ewin) == 2)) { ewin->parent = VRoot.win; EReparentWindow(EoGetWin(ewin), VRoot.win, EoGetX(ewin), EoGetY(ewin)); EoSetDesk(ewin, 0); } RaiseEwin(ewin); ICCCM_Configure(ewin); EdgeWindowsShow(); } else if (ewin->parent != dwin) { ewin->parent = dwin; EReparentWindow(EoGetWin(ewin), dwin, EoGetX(ewin), EoGetY(ewin)); RaiseEwin(ewin); MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin)); } else { RaiseEwin(ewin); MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin)); } /* FIXME - This should not be necessary. It is when a new window is added as * the only one in the lowest layer (e.g. desktop type). * In stead EobjListStackAdd() should mark the object stack dirty. */ StackDesktop(EoGetDesk(ewin)); EwinDetermineArea(ewin); HintsSetWindowDesktop(ewin); } void EwinReparent(EWin * ewin, Window parent) { EReparentWindow(ewin->client.win, parent, 0, 0); } static void EwinEventMapRequest(EWin * ewin, Window win) { if (ewin) { if (ewin->state == EWIN_STATE_ICONIC) EwinDeIconify(ewin); if (ewin->state == EWIN_STATE_WITHDRAWN) AddToFamily(ewin, win); else Eprintf("AddToFamily: Already managing %s %#lx\n", "A", ewin->client.win); } else { /* Check if we are already managing it */ ewin = FindItem(NULL, win, LIST_FINDBY_ID, LIST_TYPE_EWIN); /* Some clients MapRequest more than once ?!? */ if (ewin) { Eprintf("AddToFamily: Already managing %s %#lx\n", "B", ewin->client.win); ShowEwin(ewin); } else AddToFamily(NULL, win); } } static void EwinEventDestroy(EWin * ewin) { if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("EwinEventDestroy %#lx %s state=%d\n", ewin->client.win, EwinGetName(ewin), ewin->state); EwinDestroy(ewin); } static void EwinEventMap(EWin * ewin) { int old_state = ewin->state; ewin->state = EWIN_STATE_MAPPED; if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("EwinEventMap %#lx %s state=%d\n", ewin->client.win, EwinGetName(ewin), ewin->state); /* If first time we may want to focus it (unless during startup) */ if (old_state == EWIN_STATE_NEW) FocusToEWin(ewin, FOCUS_EWIN_NEW); else FocusToEWin(ewin, FOCUS_SET); ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin); } static void EwinEventUnmap(EWin * ewin) { if (GetZoomEWin() == ewin) Zoom(NULL); if (EventDebug(EDBUG_TYPE_EWINS)) Eprintf("EwinEventUnmap %#lx %s state=%d\n", ewin->client.win, EwinGetName(ewin), ewin->state); if (ewin->state == EWIN_STATE_WITHDRAWN) return; if (ewin->iconified) ewin->state = EWIN_STATE_ICONIC; else ewin->state = EWIN_STATE_WITHDRAWN; ewin->shown = 0; ActionsEnd(ewin); if (ewin == GetContextEwin()) SlideoutsHide(); if (ewin == Mode.focuswin) FocusToEWin(ewin, FOCUS_EWIN_GONE); if (ewin == Mode.mouse_over_ewin) Mode.mouse_over_ewin = NULL; if (ewin == Mode.context_ewin) Mode.context_ewin = NULL; if (Mode.doingslide) { DrawEwinShape(ewin, Conf.slidemode, ewin->shape_x, ewin->shape_y, ewin->client.w, ewin->client.h, 2); Mode.doingslide = 0; } /* FIXME - This is to sync the client.win EXID mapped state */ EUnmapWindow(ewin->client.win); EUnmapWindow(EoGetWin(ewin)); ModulesSignal(ESIGNAL_EWIN_UNMAP, ewin); if (ewin->iconified) return; if (ewin->Close) ewin->Close(ewin); if (WinGetParent(ewin->client.win) == ewin->win_container) EwinWithdraw(ewin); } static void EwinEventConfigureRequest(EWin * ewin, XEvent * ev) { Window win, winrel; EWin *ewin2; int x = 0, y = 0, w = 0, h = 0; XWindowChanges xwc; win = ev->xconfigurerequest.window; if (ewin) { x = EoGetX(ewin); y = EoGetY(ewin); w = ewin->client.w; h = ewin->client.h; winrel = 0; if (ev->xconfigurerequest.value_mask & CWX) x = ev->xconfigurerequest.x; if (ev->xconfigurerequest.value_mask & CWY) y = ev->xconfigurerequest.y; if (ev->xconfigurerequest.value_mask & CWWidth) w = ev->xconfigurerequest.width; if (ev->xconfigurerequest.value_mask & CWHeight) h = ev->xconfigurerequest.height; if (ev->xconfigurerequest.value_mask & CWSibling) winrel = ev->xconfigurerequest.above; if (ev->xconfigurerequest.value_mask & CWStackMode) { ewin2 = FindItem(NULL, winrel, LIST_FINDBY_ID, LIST_TYPE_EWIN); if (ewin2) winrel = EoGetWin(ewin2); xwc.sibling = winrel; xwc.stack_mode = ev->xconfigurerequest.detail; if (Mode.mode == MODE_NONE) { if (xwc.stack_mode == Above) RaiseEwin(ewin); else if (xwc.stack_mode == Below) LowerEwin(ewin); } /* else * XConfigureWindow(disp, EoGetWin(ewin), * ev->xconfigurerequest.value_mask & * (CWSibling | CWStackMode), &xwc); */ } #if 0 /* Let's try disabling this */ /* this ugly workaround here is because x11amp is very brain-dead */ /* and sets its minunum and maximm sizes the same - fair enough */ /* to ensure it doesnt get resized - BUT hwne it shades itself */ /* it resizes down to a smaller size - of course keeping the */ /* minimum and maximim size same - E unconditionally disallows any */ /* client window to be resized outside of its constraints */ /* (any client could do this resize - not just x11amp thus E is */ /* imposing the hints x11amp set up - this works around by */ /* modifying the constraints to fit what the app requested */ if (w < ewin->client.width.min) ewin->client.width.min = w; if (w > ewin->client.width.max) ewin->client.width.max = w; if (h < ewin->client.height.min) ewin->client.height.min = h; if (h > ewin->client.height.max) ewin->client.height.max = h; #endif if (ev->xconfigurerequest.value_mask & (CWX | CWY)) { /* Correct position taking gravity into account */ ewin->client.x = x; ewin->client.y = y; EwinGetPosition(ewin, &x, &y); } Mode.move.check = 0; /* Don't restrict client requests */ MoveResizeEwin(ewin, x, y, w, h); Mode.move.check = 1; { char pshaped; pshaped = ewin->client.shaped; ICCCM_GetShapeInfo(ewin); if (pshaped != ewin->client.shaped) { SyncBorderToEwin(ewin); EwinPropagateShapes(ewin); } } ReZoom(ewin); } else { xwc.x = ev->xconfigurerequest.x; xwc.y = ev->xconfigurerequest.y; xwc.width = ev->xconfigurerequest.width; xwc.height = ev->xconfigurerequest.height; xwc.border_width = ev->xconfigurerequest.border_width; xwc.sibling = ev->xconfigurerequest.above; xwc.stack_mode = ev->xconfigurerequest.detail; EConfigureWindow(win, ev->xconfigurerequest.value_mask, &xwc); } } static void EwinEventResizeRequest(EWin * ewin, XEvent * ev) { Window win; int w, h; win = ev->xresizerequest.window; if (ewin) { w = ev->xresizerequest.width; h = ev->xresizerequest.height; ResizeEwin(ewin, w, h); { char pshaped; pshaped = ewin->client.shaped; ICCCM_GetShapeInfo(ewin); if (pshaped != ewin->client.shaped) { SyncBorderToEwin(ewin); EwinPropagateShapes(ewin); } } ReZoom(ewin); } else { EResizeWindow(win, ev->xresizerequest.width, ev->xresizerequest.height); } } static void EwinEventCirculateRequest(EWin * ewin, XEvent * ev) { Window win; win = ev->xcirculaterequest.window; if (ewin) { if (ev->xcirculaterequest.place == PlaceOnTop) RaiseEwin(ewin); else LowerEwin(ewin); } else { if (ev->xcirculaterequest.place == PlaceOnTop) ERaiseWindow(win); else ELowerWindow(win); } } static void EwinEventPropertyNotify(EWin * ewin, XEvent * ev) { ecore_x_grab(); EwinChangesStart(ewin); HintsProcessPropertyChange(ewin, ev->xproperty.atom); SessionGetInfo(ewin, ev->xproperty.atom); SyncBorderToEwin(ewin); EwinChangesProcess(ewin); ecore_x_ungrab(); } static void EwinEventShapeChange(EWin * ewin) { const Border *b; b = ewin->border; SyncBorderToEwin(ewin); if (ewin->border == b) EwinPropagateShapes(ewin); } static void EwinEventVisibility(EWin * ewin, int state) { ewin->visibility = state; } void EwinRefresh(EWin * ewin) { if (!ewin) return; if (TransparencyEnabled()) EwinBorderDraw(ewin, 0, 1, 0); /* Update the border */ if (ewin->Refresh) ewin->Refresh(ewin); } void EwinUpdateAfterMoveResize(EWin * ewin, int resize) { if (!ewin) return; EwinDetermineArea(ewin); if (TransparencyEnabled()) EwinBorderDraw(ewin, resize, 1, 0); /* Update the border */ if (ewin->MoveResize) ewin->MoveResize(ewin, resize); SnapshotEwinUpdate(ewin, SNAP_USE_POS | SNAP_USE_SIZE); ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin); } #if 0 /* Unused */ void FloatEwin(EWin * ewin) { static int call_depth = 0; EWin **lst; int i, num; call_depth++; if (call_depth > 256) return; EoSetFloating(ewin, 1); EoSetDesk(ewin, 0); EwinConformToDesktop(ewin); RaiseEwin(ewin); lst = EwinListTransients(ewin, &num, 0); for (i = 0; i < num; i++) FloatEwin(lst[i]); if (lst) Efree(lst); call_depth--; } #endif void FloatEwinAt(EWin * ewin, int x, int y) { static int call_depth = 0; int dx, dy; EWin **lst; int i, num; call_depth++; if (call_depth > 256) return; if (EoIsFloating(ewin)) { /* Reparenting to root moves the desktop-relative coordinates */ dx = DeskGetX(EoGetDesk(ewin)); dy = DeskGetY(EoGetDesk(ewin)); ewin->shape_x += dx; ewin->shape_y += dy; ewin->req_x += dx; ewin->req_y += dy; EoSetFloating(ewin, 2); } else { ewin->ld = EoGetDesk(ewin); EoSetFloating(ewin, 1); } dx = x - EoGetX(ewin); dy = y - EoGetY(ewin); EoSetX(ewin, x); EoSetY(ewin, y); EwinConformToDesktop(ewin); lst = EwinListTransients(ewin, &num, 0); for (i = 0; i < num; i++) FloatEwinAt(lst[i], EoGetX(lst[i]) + dx, EoGetY(lst[i]) + dy); if (lst) Efree(lst); call_depth--; } /* * Place particular EWin at appropriate location in the window stack */ static void RestackEwin(EWin * ewin) { EWin *const *lst; int i, num; XWindowChanges xwc; unsigned int value_mask; if (EventDebug(EDBUG_TYPE_STACKING)) Eprintf("RestackEwin %#lx %s\n", ewin->client.win, EwinGetName(ewin)); lst = EwinListGetForDesk(&num, EoGetDesk(ewin)); if (num < 2) goto done; for (i = 0; i < num; i++) if (lst[i] == ewin) break; if (i < num - 1) { xwc.stack_mode = Above; xwc.sibling = EoGetWin(lst[i + 1]); } else { xwc.stack_mode = Below; xwc.sibling = EoGetWin(lst[i - 1]); } value_mask = CWSibling | CWStackMode; if (EventDebug(EDBUG_TYPE_STACKING)) Eprintf("RestackEwin %#10lx %s %#10lx\n", EoGetWin(ewin), (xwc.stack_mode == Above) ? "Above" : "Below", xwc.sibling); XConfigureWindow(disp, EoGetWin(ewin), value_mask, &xwc); HintsSetClientStacking(); ModulesSignal(ESIGNAL_EWIN_CHANGE, ewin); done: ; } void RaiseEwin(EWin * ewin) { static int call_depth = 0; EWin **lst; int i, num; if (call_depth > 256) return; call_depth++; if (EventDebug(EDBUG_TYPE_RAISELOWER)) Eprintf("RaiseEwin(%d) %#lx %s\n", call_depth, ewin->client.win, EwinGetName(ewin)); if (EoGetWin(ewin)) { num = EwinListStackRaise(ewin); if (num == 0) /* Quit if stacking is unchanged */ goto done; lst = EwinListTransients(ewin, &num, 1); for (i = 0; i < num; i++) RaiseEwin(lst[i]); if (lst) Efree(lst); if (call_depth == 1) { if (num > 0) StackDesktop(EoGetDesk(ewin)); /* Do the full stacking */ else RestackEwin(ewin); /* Restack this one only */ } } done: call_depth--; } void LowerEwin(EWin * ewin) { static int call_depth = 0; EWin **lst; int i, num; if (call_depth > 256) return; call_depth++; if (EventDebug(EDBUG_TYPE_RAISELOWER)) Eprintf("LowerEwin(%d) %#lx %s\n", call_depth, ewin->client.win, EwinGetName(ewin)); if (EoGetWin(ewin)) { num = EwinListStackLower(ewin); if (num == 0) /* Quit if stacking is unchanged */ goto done; lst = EwinListTransientFor(ewin, &num); for (i = 0; i < num; i++) LowerEwin(lst[i]); if (lst) Efree(lst); if (call_depth == 1) { if (num > 0) StackDesktop(EoGetDesk(ewin)); /* Do the full stacking */ else RestackEwin(ewin); /* Restack this one only */ } } done: call_depth--; } void ShowEwin(EWin * ewin) { if (ewin->shown) return; ewin->shown = 1; if (ewin->client.win) { if (ewin->shaded) EMoveResizeWindow(ewin->win_container, -30, -30, 1, 1); EMapWindow(ewin->client.win); } if (EoGetWin(ewin)) EMapWindow(EoGetWin(ewin)); } void HideEwin(EWin * ewin) { if (!ewin->shown || !EwinIsMapped(ewin)) return; ewin->shown = 0; if (GetZoomEWin() == ewin) Zoom(NULL); EUnmapWindow(ewin->client.win); if (EoGetWin(ewin)) EUnmapWindow(EoGetWin(ewin)); } Window EwinGetClientWin(const EWin * ewin) { return (ewin) ? ewin->client.win : None; } const char * EwinGetName(const EWin * ewin) { const char *name; if (!ewin) return NULL; #if ENABLE_EWMH name = ewin->ewmh.wm_name; if (name) goto done; #endif name = ewin->icccm.wm_name; if (name) goto done; done: return (name && name[0]) ? name : NULL; } const char * EwinGetIconName(const EWin * ewin) { const char *name; #if ENABLE_EWMH name = ewin->ewmh.wm_icon_name; if (name) goto done; #endif name = ewin->icccm.wm_icon_name; if (name) goto done; return EwinGetName(ewin); done: return (name && strlen(name)) ? name : NULL; } int EwinIsOnScreen(EWin * ewin) { int x, y, w, h; if (EoIsSticky(ewin)) return 1; if (EoGetDesk(ewin) != DesksGetCurrent()) return 0; x = EoGetX(ewin); y = EoGetY(ewin); w = EoGetW(ewin); h = EoGetH(ewin); if (x + w <= 0 || x >= VRoot.w || y + h <= 0 || y >= VRoot.h) return 0; return 1; } /* * Save current position in absolute viewport coordinates */ void EwinRememberPositionSet(EWin * ewin) { int ax, ay; ewin->req_x = EoGetX(ewin); ewin->req_y = EoGetY(ewin); if (!EoIsSticky(ewin)) { DeskGetArea(EoGetDesk(ewin), &ax, &ay); ewin->req_x += ax * VRoot.w; ewin->req_y += ay * VRoot.h; } } /* * Get saved position in relative viewport coordinates */ void EwinRememberPositionGet(EWin * ewin, int *px, int *py) { int x, y, ax, ay; x = ewin->req_x; y = ewin->req_y; if (!EoIsSticky(ewin)) { DeskGetArea(EoGetDesk(ewin), &ax, &ay); x -= ax * VRoot.w; y -= ay * VRoot.h; } *px = x; *py = y; } /* * Change requests */ static struct { unsigned int flags; EWin ewin_old; } EWinChanges; void EwinChange(EWin * ewin, unsigned int flag) { EWinChanges.flags |= flag; return; ewin = NULL; } void EwinChangesStart(EWin * ewin) { EWinChanges.flags = 0; /* Brute force :) */ EWinChanges.ewin_old = *ewin; } void EwinChangesProcess(EWin * ewin) { if (!EWinChanges.flags) return; if (EWinChanges.flags & EWIN_CHANGE_NAME) { EwinBorderUpdateInfo(ewin); EwinBorderCalcSizes(ewin); } if (EWinChanges.flags & EWIN_CHANGE_DESKTOP) { int desk, pdesk; desk = EoGetDesk(ewin); pdesk = EoGetDesk(&EWinChanges.ewin_old); if (desk != pdesk && !EoIsSticky(ewin)) { EoSetDesk(ewin, pdesk); MoveEwinToDesktop(ewin, desk); } } if (EWinChanges.flags & EWIN_CHANGE_ICON_PMAP) { ModulesSignal(ESIGNAL_EWIN_CHANGE_ICON, ewin); } EWinChanges.flags = 0; } void EwinsEventsConfigure(int mode) { EWin *const *lst, *ewin; int i, num; lst = EwinListGetAll(&num); for (i = 0; i < num; i++) { ewin = lst[i]; EwinEventsConfigure(lst[i], mode); /* This is a hack. Maybe we should do something with expose events. */ if (mode) if (Mode.mode == MODE_DESKSWITCH && EoIsSticky(ewin) && ewin->shown) EwinRefresh(ewin); } } static void EwinsTouch(void) { int i, num; EWin *const *lst, *ewin; lst = EwinListStackGet(&num); for (i = num - 1; i >= 0; i--) { ewin = lst[i]; if (EwinIsMapped(ewin)) MoveEwin(ewin, EoGetX(ewin), EoGetY(ewin)); } } void EwinsSetFree(void) { int i, num; EWin *const *lst, *ewin; if (EventDebug(EDBUG_TYPE_SESSION)) Eprintf("EwinsSetFree\n"); lst = EwinListStackGet(&num); for (i = num - 1; i >= 0; i--) { ewin = lst[i]; if (EwinIsInternal(ewin)) continue; if (ewin->iconified) ICCCM_DeIconify(ewin); /* This makes E determine the client window stacking at exit */ EwinInstantUnShade(ewin); EReparentWindow(ewin->client.win, VRoot.win, ewin->client.x, ewin->client.y); } } /* * Event handlers */ static int ActionsCheck(const char *which, EWin * ewin, XEvent * ev) { ActionClass *ac; if (Mode.action_inhibit) /* Probably not here */ return 0; ac = FindItem(which, 0, LIST_FINDBY_NAME, LIST_TYPE_ACLASS); if (!ac) return 0; if (ev->type == ButtonPress) GrabPointerSet(EoGetWin(ewin), ECSR_GRAB, 0); else if (ev->type == ButtonRelease) GrabPointerRelease(); return EventAclass(ev, ewin, ac); } #define DEBUG_EWIN_EVENTS 0 static void EwinHandleEventsToplevel(XEvent * ev, void *prm) { EWin *ewin = (EWin *) prm; switch (ev->type) { case ButtonPress: ActionsCheck("BUTTONBINDINGS", ewin, ev); break; case ButtonRelease: ActionsCheck("BUTTONBINDINGS", ewin, ev); break; case EnterNotify: FocusHandleEnter(ewin, ev); break; case LeaveNotify: FocusHandleLeave(ewin, ev); break; case MotionNotify: break; default: #if DEBUG_EWIN_EVENTS Eprintf("EwinHandleEventsToplevel: type=%2d win=%#lx: %s\n", ev->type, ewin->client.win, EwinGetName(ewin)); #endif break; } } static void EwinHandleEventsContainer(XEvent * ev, void *prm) { EWin *ewin = (EWin *) prm; #if 0 Eprintf("EwinHandleEventsContainer: type=%2d win=%#lx: %s\n", ev->type, ewin->client.win, EwinGetName(ewin)); #endif switch (ev->type) { case ButtonPress: FocusHandleClick(ewin, ev->xany.window); break; case MapRequest: EwinEventMapRequest(ewin, ev->xmaprequest.window); break; case ConfigureRequest: EwinEventConfigureRequest(ewin, ev); break; case ResizeRequest: EwinEventResizeRequest(ewin, ev); break; case CirculateRequest: EwinEventCirculateRequest(ewin, ev); break; case DestroyNotify: EwinEventDestroy(ewin); break; case UnmapNotify: #if 0 if (ewin->state == EWIN_STATE_NEW) { Eprintf("EwinEventUnmap %#lx: Ignoring bogus Unmap event\n", ewin->client.win); break; } #endif EwinEventUnmap(ewin); break; case MapNotify: EwinEventMap(ewin); break; case ReparentNotify: /* Check if window parent hasn't changed already (compress?) */ if (WinGetParent(ev->xreparent.window) != ev->xreparent.parent) break; if (ev->xreparent.parent != ewin->win_container) EwinEventDestroy(ewin); break; case GravityNotify: case ConfigureNotify: break; default: Eprintf("EwinHandleEventsContainer: type=%2d win=%#lx: %s\n", ev->type, ewin->client.win, EwinGetName(ewin)); break; } } static void EwinHandleEventsClient(XEvent * ev, void *prm) { EWin *ewin = (EWin *) prm; switch (ev->type) { case ButtonPress: case ButtonRelease: case MotionNotify: case EnterNotify: case LeaveNotify: case FocusIn: case FocusOut: case ConfigureNotify: case GravityNotify: break; case VisibilityNotify: EwinEventVisibility(ewin, ev->xvisibility.state); break; #if 0 /* FIXME - Remove? */ case DestroyNotify: EwinEventDestroy(ewin); break; case UnmapNotify: #if 0 if (ewin->state == EWIN_STATE_NEW) { Eprintf("EwinEventUnmap %#lx: Ignoring bogus Unmap event\n", ewin->client.win); break; } #endif EwinEventUnmap(ewin); break; case MapNotify: EwinEventMap(ewin); break; case ReparentNotify: /* Check if window parent hasn't changed already (compress?) */ if (WinGetParent(ev->xreparent.window) != ev->xreparent.parent) break; if (ev->xreparent.parent == VRoot.win) EwinEventDestroy(ewin); break; #endif #if 0 case ConfigureRequest: if (ev->xconfigurerequest.window == ewin->client.win) EwinEventConfigureRequest(ewin, ev); break; case ResizeRequest: if (ev->xresizerequest.window == ewin->client.win) EwinEventResizeRequest(ewin, ev); break; case CirculateRequest: EwinEventCirculateRequest(ewin, ev); break; #endif case PropertyNotify: EwinEventPropertyNotify(ewin, ev); break; case EX_EVENT_SHAPE_NOTIFY: EwinEventShapeChange(ewin); default: #if DEBUG_EWIN_EVENTS Eprintf("EwinHandleEventsClient: type=%2d win=%#lx: %s\n", ev->type, ewin->client.win, EwinGetName(ewin)); #endif break; } } static void EwinHandleEventsRoot(XEvent * ev, void *prm __UNUSED__) { EWin *ewin; switch (ev->type) { case EnterNotify: FocusHandleEnter(NULL, ev); break; case LeaveNotify: FocusHandleLeave(NULL, ev); break; case MapRequest: EwinEventMapRequest(NULL, ev->xmaprequest.window); break; case ConfigureRequest: #if 0 Eprintf("EwinHandleEventsRoot ConfigureRequest %#lx\n", ev->xconfigurerequest.window); #endif ewin = FindItem(NULL, ev->xconfigurerequest.window, LIST_FINDBY_ID, LIST_TYPE_EWIN); EwinEventConfigureRequest(ewin, ev); break; case ResizeRequest: #if 0 Eprintf("EwinHandleEventsRoot ResizeRequest %#lx\n", ev->xresizerequest.window); #endif ewin = FindItem(NULL, ev->xresizerequest.window, LIST_FINDBY_ID, LIST_TYPE_EWIN); EwinEventResizeRequest(ewin, ev); break; case CirculateRequest: #if 0 Eprintf("EwinHandleEventsRoot CirculateRequest %#lx\n", ev->xcirculaterequest.window); #endif EwinEventCirculateRequest(NULL, ev); break; case UnmapNotify: /* Catch clients unmapped after MapRequest but before being reparented */ ewin = FindItem(NULL, ev->xunmap.window, LIST_FINDBY_ID, LIST_TYPE_EWIN); if (ewin) EwinEventUnmap(ewin); break; case DestroyNotify: /* Catch clients destroyed after MapRequest but before being reparented */ ewin = FindItem(NULL, ev->xdestroywindow.window, LIST_FINDBY_ID, LIST_TYPE_EWIN); if (!ewin) ewin = FindEwinByBase(ev->xdestroywindow.window); if (ewin) EwinEventDestroy(ewin); break; default: #if 0 Eprintf("EwinHandleEventsRoot: type=%2d win=%#lx\n", ev->type, ev->xany.window); #endif break; } } static void EwinsInit(void) { EventCallbackRegister(VRoot.win, 0, EwinHandleEventsRoot, NULL); } /* * Ewins module * This is the WM. */ static void EwinsSighan(int sig, void *prm __UNUSED__) { switch (sig) { case ESIGNAL_INIT: EwinsInit(); break; #if 0 case ESIGNAL_CONFIGURE: if (!Conf.mapslide || Mode.wm.restart) MapUnmap(1); break; case ESIGNAL_START: if (Conf.mapslide && !Mode.wm.restart) MapUnmap(1); break; #endif case ESIGNAL_DESK_RESIZE: EwinsTouch(); break; } } #if 0 IpcItem EwinsIpcArray[] = { }; #define N_IPC_FUNCS (sizeof(EwinsIpcArray)/sizeof(IpcItem)) #else #define N_IPC_FUNCS 0 #define EwinsIpcArray NULL #endif /* * Module descriptor */ EModule ModEwins = { "ewins", NULL, EwinsSighan, {N_IPC_FUNCS, EwinsIpcArray} , {0, NULL} };