/** Determine if this is a window to be swallowed, if it is, swallow it. */ int CheckSwallowMap(const XMapEvent *event) { SwallowNode *np; XClassHint hint; XWindowAttributes attr; for(np = swallowNodes; np; np = np->next) { if(np->cp->window != None) { continue; } Assert(np->cp->tray->window != None); if(JXGetClassHint(display, event->window, &hint)) { if(!strcmp(hint.res_name, np->name)) { /* Swallow the window. */ JXSelectInput(display, event->window, StructureNotifyMask | ResizeRedirectMask); JXAddToSaveSet(display, event->window); JXSetWindowBorder(display, event->window, colors[COLOR_TRAY_BG]); JXReparentWindow(display, event->window, np->cp->tray->window, 0, 0); JXMapRaised(display, event->window); JXFree(hint.res_name); JXFree(hint.res_class); np->cp->window = event->window; /* Update the size. */ JXGetWindowAttributes(display, event->window, &attr); np->border = attr.border_width; if(!np->userWidth) { np->cp->requestedWidth = attr.width + 2 * np->border; } if(!np->userHeight) { np->cp->requestedHeight = attr.height + 2 * np->border; } ResizeTray(np->cp->tray); return 1; } else { JXFree(hint.res_name); JXFree(hint.res_class); } } } return 0; }
/** Read a window atom. */ char GetWindowAtom(Window window, AtomType atom, Window *value) { unsigned long count; int status; unsigned long extra; Atom realType; int realFormat; unsigned char *data; char ret; Assert(window != None); Assert(value); status = JXGetWindowProperty(display, window, atoms[atom], 0, 1, False, XA_WINDOW, &realType, &realFormat, &count, &extra, &data); ret = 0; if(status == Success && realFormat != 0 && data) { if(count == 1) { *value = *(Window*)data; ret = 1; } JXFree(data); } return ret; }
/** Read the protocols hint for a window. */ void ReadWMProtocols(Window w, ClientState *state) { unsigned long count, x; int status; unsigned long extra; Atom realType; int realFormat; unsigned char *temp; Atom *p; Assert(w != None); state->status &= ~STAT_TAKEFOCUS; state->status &= ~STAT_DELETE; status = JXGetWindowProperty(display, w, atoms[ATOM_WM_PROTOCOLS], 0, 32, False, XA_ATOM, &realType, &realFormat, &count, &extra, &temp); p = (Atom*)temp; if(status != Success || realFormat == 0 || !p) { return; } for(x = 0; x < count; x++) { if(p[x] == atoms[ATOM_WM_DELETE_WINDOW]) { state->status |= STAT_DELETE; } else if(p[x] == atoms[ATOM_WM_TAKE_FOCUS]) { state->status |= STAT_TAKEFOCUS; } } JXFree(p); }
/** Read the WM state for a window. */ void ReadWMState(Window win, ClientState *state) { Status status; unsigned long count; unsigned long extra; Atom realType; int realFormat; unsigned long *temp; status = JXGetWindowProperty(display, win, atoms[ATOM_WM_STATE], 0, 2, False, atoms[ATOM_WM_STATE], &realType, &realFormat, &count, &extra, (unsigned char**)&temp); if(JLIKELY(status == Success && realFormat == 32 && count == 2)) { switch(temp[0]) { case IconicState: state->status |= STAT_MINIMIZED; break; case WithdrawnState: state->status &= ~STAT_MAPPED; break; default: break; } JXFree(temp); } }
/** Read the WM hints for a window. */ void ReadWMHints(Window win, ClientState *state, char alreadyMapped) { XWMHints *wmhints; Assert(win != None); Assert(state); state->status |= STAT_CANFOCUS; wmhints = JXGetWMHints(display, win); if(wmhints) { if(!alreadyMapped && (wmhints->flags & StateHint)) { switch(wmhints->initial_state) { case IconicState: state->status |= STAT_MINIMIZED; break; default: break; } } if((wmhints->flags & InputHint) && wmhints->input == False) { state->status &= ~STAT_CANFOCUS; } if(wmhints->flags & XUrgencyHint) { state->status |= STAT_URGENT; } else { state->status &= ~(STAT_URGENT | STAT_FLASH); } JXFree(wmhints); } }
/** Read _MOTIF_WM_HINTS */ void ReadMotifHints(Window win, ClientState *state) { PropMwmHints *mhints; Atom type; unsigned long itemCount, bytesLeft; unsigned char *data; int format; Assert(win != None); Assert(state); if(JXGetWindowProperty(display, win, atoms[ATOM_MOTIF_WM_HINTS], 0L, 20L, False, atoms[ATOM_MOTIF_WM_HINTS], &type, &format, &itemCount, &bytesLeft, &data) != Success || format == 0) { return; } mhints = (PropMwmHints*)data; if(mhints) { if((mhints->flags & MWM_HINTS_FUNCTIONS) && !(mhints->functions & MWM_FUNC_ALL)) { if(!(mhints->functions & MWM_FUNC_RESIZE)) { state->border &= ~BORDER_RESIZE; } if(!(mhints->functions & MWM_FUNC_MOVE)) { state->border &= ~BORDER_MOVE; } if(!(mhints->functions & MWM_FUNC_MINIMIZE)) { state->border &= ~BORDER_MIN; } if(!(mhints->functions & MWM_FUNC_MAXIMIZE)) { state->border &= ~BORDER_MAX; } if(!(mhints->functions & MWM_FUNC_CLOSE)) { state->border &= ~BORDER_CLOSE; } } if((mhints->flags & MWM_HINTS_DECORATIONS) && !(mhints->decorations & MWM_DECOR_ALL)) { if(!(mhints->decorations & MWM_DECOR_BORDER)) { state->border &= ~BORDER_OUTLINE; } if(!(mhints->decorations & MWM_DECOR_TITLE)) { state->border &= ~BORDER_TITLE; } } JXFree(mhints); } }
/** Read the icon property from a client. */ void ReadNetWMIcon(ClientNode *np) { unsigned long count; int status; unsigned long extra; Atom realType; int realFormat; unsigned char *data; status = JXGetWindowProperty(display, np->window, atoms[ATOM_NET_WM_ICON], 0, 256 * 256 * 4, False, XA_CARDINAL, &realType, &realFormat, &count, &extra, &data); if(status == Success && realFormat != 0 && data) { np->icon = CreateIconFromBinary((unsigned long*)data, count); JXFree(data); } }
/** Startup screens. */ void StartupScreens() { #ifdef USE_XINERAMA XineramaScreenInfo *info; int x; if(XineramaIsActive(display)) { info = XineramaQueryScreens(display, &screenCount); screens = Allocate(sizeof(ScreenType) * screenCount); for(x = 0; x < screenCount; x++) { screens[x].index = x; screens[x].x = info[x].x_org; screens[x].y = info[x].y_org; screens[x].width = info[x].width; screens[x].height = info[x].height; } JXFree(info); } else { screenCount = 1; screens = Allocate(sizeof(ScreenType)); screens->index = 0; screens->x = 0; screens->y = 0; screens->width = rootWidth; screens->height = rootHeight; } #else screenCount = 1; screens = Allocate(sizeof(ScreenType)); screens->index = 0; screens->x = 0; screens->y = 0; screens->width = rootWidth; screens->height = rootHeight; #endif /* USE_XINERAMA */ }
/** Read the icon WMHint property from a client. */ void ReadWMHintIcon(ClientNode *np) { XWMHints *hints; hints = JXGetWMHints(display, np->window); if(hints) { Drawable d = None; Pixmap mask = None; if(hints->flags & IconMaskHint) { mask = hints->icon_mask; } if(hints->flags & IconPixmapHint) { d = hints->icon_pixmap; } if(d != None) { np->icon = CreateIconFromDrawable(d, mask); } JXFree(hints); } }
/** Read the icon property from a client. */ IconNode *ReadNetWMIcon(Window win) { static const long MAX_LENGTH = 1 << 20; IconNode *icon = NULL; unsigned long count; int status; unsigned long extra; Atom realType; int realFormat; unsigned char *data; status = JXGetWindowProperty(display, win, atoms[ATOM_NET_WM_ICON], 0, MAX_LENGTH, False, XA_CARDINAL, &realType, &realFormat, &count, &extra, &data); if(status == Success && realFormat != 0 && data) { icon = CreateIconFromBinary((unsigned long*)data, count); JXFree(data); } return icon; }
/** Read the icon WMHint property from a client. */ IconNode *ReadWMHintIcon(Window win) { IconNode *icon = NULL; XWMHints *hints = JXGetWMHints(display, win); if(hints) { Drawable d = None; Pixmap mask = None; if(hints->flags & IconMaskHint) { mask = hints->icon_mask; } if(hints->flags & IconPixmapHint) { d = hints->icon_pixmap; } if(d != None) { icon = CreateIconFromDrawable(d, mask); } JXFree(hints); } return icon; }
/** Read colormap information for a client. */ void ReadWMColormaps(ClientNode *np) { Window *windows; ColormapNode *cp; int count; Assert(np); if(JXGetWMColormapWindows(display, np->window, &windows, &count)) { if(count > 0) { int x; /* Free old colormaps. */ while(np->colormaps) { cp = np->colormaps->next; Release(np->colormaps); np->colormaps = cp; } /* Put the maps in the list in order so they will come out in * reverse order. This way they will be installed with the * most important last. * Keep track of at most colormapCount colormaps for each * window to avoid doing extra work. */ count = Min(colormapCount, count); for(x = 0; x < count; x++) { cp = Allocate(sizeof(ColormapNode)); cp->window = windows[x]; cp->next = np->colormaps; np->colormaps = cp; } JXFree(windows); } } }
/** Load windows that are already mapped. */ void StartupClients(void) { XWindowAttributes attr; Window rootReturn, parentReturn, *childrenReturn; unsigned int childrenCount; unsigned int x; clientCount = 0; activeClient = NULL; currentDesktop = 0; /* Clear out the client lists. */ for(x = 0; x < LAYER_COUNT; x++) { nodes[x] = NULL; nodeTail[x] = NULL; } /* Query client windows. */ JXQueryTree(display, rootWindow, &rootReturn, &parentReturn, &childrenReturn, &childrenCount); /* Add each client. */ for(x = 0; x < childrenCount; x++) { if(JXGetWindowAttributes(display, childrenReturn[x], &attr)) { if(attr.override_redirect == False && attr.map_state == IsViewable) { AddClientWindow(childrenReturn[x], 1, 1); } } } JXFree(childrenReturn); LoadFocus(); RequireTaskUpdate(); RequirePagerUpdate(); }
/** Handle a client message. */ void HandleClientMessage(const XClientMessageEvent *event) { ClientNode *np; long mask, flags; #ifdef DEBUG char *atomName; #endif np = FindClientByWindow(event->window); if(np) { if(event->message_type == atoms[ATOM_WIN_STATE]) { mask = event->data.l[0]; flags = event->data.l[1]; if(mask & WIN_STATE_STICKY) { if(flags & WIN_STATE_STICKY) { SetClientSticky(np, 1); } else { SetClientSticky(np, 0); } } if(mask & WIN_STATE_HIDDEN) { if(flags & WIN_STATE_HIDDEN) { np->state.status |= STAT_NOLIST; } else { np->state.status &= ~STAT_NOLIST; } UpdateTaskBar(); UpdatePager(); } } else if(event->message_type == atoms[ATOM_WIN_LAYER]) { SetClientLayer(np, event->data.l[0]); } else if(event->message_type == atoms[ATOM_WM_CHANGE_STATE]) { if(np->controller) { (np->controller)(0); } switch(event->data.l[0]) { case WithdrawnState: SetClientWithdrawn(np); break; case IconicState: MinimizeClient(np); break; case NormalState: RestoreClient(np, 1); break; default: break; } } else if(event->message_type == atoms[ATOM_NET_ACTIVE_WINDOW]) { RestoreClient(np, 1); FocusClient(np); } else if(event->message_type == atoms[ATOM_NET_WM_DESKTOP]) { if(event->data.l[0] == ~0L) { SetClientSticky(np, 1); } else { if(np->controller) { (np->controller)(0); } if(event->data.l[0] >= 0 && event->data.l[0] < (long)desktopCount) { np->state.status &= ~STAT_STICKY; SetClientDesktop(np, event->data.l[0]); } } } else if(event->message_type == atoms[ATOM_NET_CLOSE_WINDOW]) { DeleteClient(np); } else if(event->message_type == atoms[ATOM_NET_MOVERESIZE_WINDOW]) { HandleNetMoveResize(event, np); } else if(event->message_type == atoms[ATOM_NET_WM_STATE]) { HandleNetWMState(event, np); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to client: %s", atomName); JXFree(atomName); #endif } } else if(event->window == rootWindow) { if(event->message_type == atoms[ATOM_JWM_RESTART]) { Restart(); } else if(event->message_type == atoms[ATOM_JWM_EXIT]) { Exit(); } else if(event->message_type == atoms[ATOM_NET_CURRENT_DESKTOP]) { ChangeDesktop(event->data.l[0]); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to root: %s", atomName); JXFree(atomName); #endif } } else if(event->message_type == atoms[ATOM_NET_SYSTEM_TRAY_OPCODE]) { HandleDockEvent(event); } }
/** Determine the title to display for a client. */ void ReadWMName(ClientNode *np) { unsigned long count; int status; unsigned long extra; Atom realType; int realFormat; unsigned char *name; if(np->name) { Release(np->name); } status = JXGetWindowProperty(display, np->window, atoms[ATOM_NET_WM_NAME], 0, 1024, False, atoms[ATOM_UTF8_STRING], &realType, &realFormat, &count, &extra, &name); if(status != Success || realFormat == 0) { np->name = NULL; } else { const size_t size = strlen((char*)name) + 1; np->name = Allocate(size); memcpy(np->name, name, size); JXFree(name); np->name = ConvertFromUTF8(np->name); } #ifdef USE_XUTF8 if(!np->name) { status = JXGetWindowProperty(display, np->window, XA_WM_NAME, 0, 1024, False, atoms[ATOM_COMPOUND_TEXT], &realType, &realFormat, &count, &extra, &name); if(status == Success && realFormat == 8) { char **tlist; XTextProperty tprop; int tcount; tprop.value = name; tprop.encoding = atoms[ATOM_COMPOUND_TEXT]; tprop.format = realFormat; tprop.nitems = strlen((char*)name); if(XmbTextPropertyToTextList(display, &tprop, &tlist, &tcount) == Success && tcount > 0) { const size_t len = strlen(tlist[0]) + 1; np->name = Allocate(len); memcpy(np->name, tlist[0], len); XFreeStringList(tlist); } JXFree(name); } } #endif if(!np->name) { char *temp = NULL; if(JXFetchName(display, np->window, &temp)) { const size_t len = strlen(temp) + 1; np->name = Allocate(len); memcpy(np->name, temp, len); JXFree(temp); } } }
/** Read all hints needed to determine the current window state. */ ClientState ReadWindowState(Window win, char alreadyMapped) { ClientState result; Status status; unsigned long count, x; unsigned long extra; Atom realType; int realFormat; unsigned char *temp; Atom *state; unsigned long card; Window utwin; Assert(win != None); result.status = STAT_MAPPED; result.maxFlags = MAX_NONE; result.border = BORDER_DEFAULT; result.layer = LAYER_NORMAL; result.defaultLayer = LAYER_NORMAL; result.desktop = currentDesktop; result.opacity = UINT_MAX; ReadWMProtocols(win, &result); ReadWMHints(win, &result, alreadyMapped); ReadWMState(win, &result); ReadMotifHints(win, &result); ReadWMOpacity(win, &result.opacity); /* _NET_WM_DESKTOP */ if(GetCardinalAtom(win, ATOM_NET_WM_DESKTOP, &card)) { if(card == ~0UL) { result.status |= STAT_STICKY; } else if(card < settings.desktopCount) { result.desktop = card; } else { result.desktop = settings.desktopCount - 1; } } /* _NET_WM_STATE */ status = JXGetWindowProperty(display, win, atoms[ATOM_NET_WM_STATE], 0, 32, False, XA_ATOM, &realType, &realFormat, &count, &extra, &temp); if(status == Success && realFormat != 0) { if(count > 0) { state = (Atom*)temp; for(x = 0; x < count; x++) { if(state[x] == atoms[ATOM_NET_WM_STATE_STICKY]) { result.status |= STAT_STICKY; } else if(state[x] == atoms[ATOM_NET_WM_STATE_SHADED]) { result.status |= STAT_SHADED; } else if(state[x] == atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT]) { result.maxFlags |= MAX_VERT; } else if(state[x] == atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) { result.maxFlags |= MAX_HORIZ; } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_TOP]) { result.maxFlags |= MAX_TOP; } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_BOTTOM]) { result.maxFlags |= MAX_BOTTOM; } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_LEFT]) { result.maxFlags |= MAX_LEFT; } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_RIGHT]) { result.maxFlags |= MAX_RIGHT; } else if(state[x] == atoms[ATOM_NET_WM_STATE_FULLSCREEN]) { result.status |= STAT_FULLSCREEN; } else if(state[x] == atoms[ATOM_NET_WM_STATE_HIDDEN]) { result.status |= STAT_MINIMIZED; } else if(state[x] == atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR]) { result.status |= STAT_NOLIST; } else if(state[x] == atoms[ATOM_NET_WM_STATE_SKIP_PAGER]) { result.status |= STAT_NOPAGER; } else if(state[x] == atoms[ATOM_NET_WM_STATE_ABOVE]) { result.layer = LAYER_ABOVE; } else if(state[x] == atoms[ATOM_NET_WM_STATE_BELOW]) { result.layer = LAYER_BELOW; } else if(state[x] == atoms[ATOM_NET_WM_STATE_DEMANDS_ATTENTION]) { result.status |= STAT_URGENT; } } } if(temp) { JXFree(temp); } } /* _NET_WM_WINDOW_TYPE */ status = JXGetWindowProperty(display, win, atoms[ATOM_NET_WM_WINDOW_TYPE], 0, 32, False, XA_ATOM, &realType, &realFormat, &count, &extra, &temp); if(status == Success && realFormat != 0) { /* Loop until we hit a window type we recognize. */ state = (Atom*)temp; for(x = 0; x < count; x++) { if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_NORMAL]) { break; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DESKTOP]) { result.defaultLayer = LAYER_DESKTOP; result.border = BORDER_NONE; result.status |= STAT_STICKY; result.status |= STAT_NOLIST; result.status |= STAT_NOFOCUS; break; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK]) { result.border = BORDER_NONE; result.defaultLayer = LAYER_ABOVE; result.status |= STAT_NOFOCUS; break; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH]) { result.border = BORDER_NONE; break; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG]) { result.border &= ~BORDER_MIN; result.border &= ~BORDER_MAX; break; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_MENU]) { result.border &= ~BORDER_MAX; result.status |= STAT_NOLIST; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION]) { result.border = BORDER_NONE; result.status |= STAT_NOLIST; result.status |= STAT_NOFOCUS; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_TOOLBAR]) { result.border &= ~BORDER_MAX; result.defaultLayer = LAYER_ABOVE; result.status |= STAT_STICKY; result.status |= STAT_NOLIST; result.status |= STAT_NOFOCUS; } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY]) { result.border &= ~BORDER_MAX; result.status |= STAT_NOFOCUS; } else { Debug("Unknown _NET_WM_WINDOW_TYPE: %lu", state[x]); } } if(temp) { JXFree(temp); } } /* _NET_WM_USER_TIME_WINDOW */ if(!GetWindowAtom(win, ATOM_NET_WM_USER_TIME_WINDOW, &utwin)) { utwin = win; } /* _NET_WM_USER_TIME */ if(GetCardinalAtom(utwin, ATOM_NET_WM_USER_TIME, &card)) { if(card == 0) { result.status |= STAT_NOFOCUS; } } /* Use the default layer if the layer wasn't set explicitly. */ if(result.layer == LAYER_NORMAL) { result.layer = result.defaultLayer; } /* Check if this window uses the shape extension. */ if(CheckShape(win)) { result.status |= STAT_SHAPED; } return result; }
/** Add client specified struts to our list. */ void ReadClientStrut(ClientNode *np) { BoundingBox box; int status; Atom actualType; int actualFormat; unsigned long count; unsigned long bytesLeft; unsigned char *value; long *lvalue; long leftWidth, rightWidth, topHeight, bottomHeight; char updated; updated = DoRemoveClientStrut(np); box.x = 0; box.y = 0; box.width = 0; box.height = 0; /* First try to read _NET_WM_STRUT_PARTIAL */ /* Format is: * left_width, right_width, top_width, bottom_width, * left_start_y, left_end_y, right_start_y, right_end_y, * top_start_x, top_end_x, bottom_start_x, bottom_end_x */ status = JXGetWindowProperty(display, np->window, atoms[ATOM_NET_WM_STRUT_PARTIAL], 0, 12, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesLeft, &value); if(status == Success && actualFormat != 0) { if(count == 12) { long leftStart, leftStop; long rightStart, rightStop; long topStart, topStop; long bottomStart, bottomStop; lvalue = (long*)value; leftWidth = lvalue[0]; rightWidth = lvalue[1]; topHeight = lvalue[2]; bottomHeight = lvalue[3]; leftStart = lvalue[4]; leftStop = lvalue[5]; rightStart = lvalue[6]; rightStop = lvalue[7]; topStart = lvalue[8]; topStop = lvalue[9]; bottomStart = lvalue[10]; bottomStop = lvalue[11]; if(leftWidth > 0) { box.x = 0; box.y = leftStart; box.height = leftStop - leftStart; box.width = leftWidth; InsertStrut(&box, np); } if(rightWidth > 0) { box.x = rootWidth - rightWidth; box.y = rightStart; box.height = rightStop - rightStart; box.width = rightWidth; InsertStrut(&box, np); } if(topHeight > 0) { box.x = topStart; box.y = 0; box.height = topHeight; box.width = topStop - topStart; InsertStrut(&box, np); } if(bottomHeight > 0) { box.x = bottomStart; box.y = rootHeight - bottomHeight; box.width = bottomStop - bottomStart; box.height = bottomHeight; InsertStrut(&box, np); } } JXFree(value); SetWorkarea(); return; } /* Next try to read _NET_WM_STRUT */ /* Format is: left_width, right_width, top_width, bottom_width */ status = JXGetWindowProperty(display, np->window, atoms[ATOM_NET_WM_STRUT], 0, 4, False, XA_CARDINAL, &actualType, &actualFormat, &count, &bytesLeft, &value); if(status == Success && actualFormat != 0) { if(count == 4) { lvalue = (long*)value; leftWidth = lvalue[0]; rightWidth = lvalue[1]; topHeight = lvalue[2]; bottomHeight = lvalue[3]; if(leftWidth > 0) { box.x = 0; box.y = 0; box.width = leftWidth; box.height = rootHeight; InsertStrut(&box, np); } if(rightWidth > 0) { box.x = rootWidth - rightWidth; box.y = 0; box.width = rightWidth; box.height = rootHeight; InsertStrut(&box, np); } if(topHeight > 0) { box.x = 0; box.y = 0; box.width = rootWidth; box.height = topHeight; InsertStrut(&box, np); } if(bottomHeight > 0) { box.x = 0; box.y = rootHeight - bottomHeight; box.width = rootWidth; box.height = bottomHeight; InsertStrut(&box, np); } } JXFree(value); SetWorkarea(); return; } /* Struts were removed. */ if(updated) { SetWorkarea(); } }
/** Remove a client window from management. */ void RemoveClient(ClientNode *np) { ColormapNode *cp; Assert(np); Assert(np->window != None); /* Remove this client from the client list */ if(np->next) { np->next->prev = np->prev; } else { nodeTail[np->state.layer] = np->prev; } if(np->prev) { np->prev->next = np->next; } else { nodes[np->state.layer] = np->next; } clientCount -= 1; XDeleteContext(display, np->window, clientContext); if(np->parent != None) { XDeleteContext(display, np->parent, frameContext); } if(np->state.status & STAT_URGENT) { UnregisterCallback(SignalUrgent, np); } /* Make sure this client isn't active */ if(activeClient == np && !shouldExit) { FocusNextStacked(np); } if(activeClient == np) { /* Must be the last client. */ SetWindowAtom(rootWindow, ATOM_NET_ACTIVE_WINDOW, None); activeClient = NULL; JXSetInputFocus(display, rootWindow, RevertToParent, eventTime); } /* If the window manager is exiting (ie, not the client), then * reparent etc. */ if(shouldExit && !(np->state.status & STAT_WMDIALOG)) { if(np->state.maxFlags) { np->x = np->oldx; np->y = np->oldy; np->width = np->oldWidth; np->height = np->oldHeight; JXMoveResizeWindow(display, np->window, np->x, np->y, np->width, np->height); } GravitateClient(np, 1); if(!(np->state.status & STAT_MAPPED) && (np->state.status & (STAT_MINIMIZED | STAT_SHADED))) { JXMapWindow(display, np->window); } JXUngrabButton(display, AnyButton, AnyModifier, np->window); JXReparentWindow(display, np->window, rootWindow, np->x, np->y); JXRemoveFromSaveSet(display, np->window); } /* Destroy the parent */ if(np->parent) { JXDestroyWindow(display, np->parent); } if(np->name) { Release(np->name); } if(np->instanceName) { JXFree(np->instanceName); } if(np->className) { JXFree(np->className); } RemoveClientFromTaskBar(np); RemoveClientStrut(np); while(np->colormaps) { cp = np->colormaps->next; Release(np->colormaps); np->colormaps = cp; } DestroyIcon(np->icon); Release(np); RequireRestack(); }
/** Handle a client message. */ void HandleClientMessage(const XClientMessageEvent *event) { ClientNode *np; #ifdef DEBUG char *atomName; #endif np = FindClientByWindow(event->window); if(np) { if(event->message_type == atoms[ATOM_WM_CHANGE_STATE]) { if(np->controller) { (np->controller)(0); } switch(event->data.l[0]) { case WithdrawnState: SetClientWithdrawn(np); break; case IconicState: MinimizeClient(np, 1); break; case NormalState: RestoreClient(np, 1); break; default: break; } } else if(event->message_type == atoms[ATOM_NET_ACTIVE_WINDOW]) { RestoreClient(np, 1); UnshadeClient(np); FocusClient(np); } else if(event->message_type == atoms[ATOM_NET_WM_DESKTOP]) { if(event->data.l[0] == ~0L) { SetClientSticky(np, 1); } else { if(np->controller) { (np->controller)(0); } if( event->data.l[0] >= 0 && event->data.l[0] < (long)settings.desktopCount) { np->state.status &= ~STAT_STICKY; SetClientDesktop(np, event->data.l[0]); } } } else if(event->message_type == atoms[ATOM_NET_CLOSE_WINDOW]) { DeleteClient(np); } else if(event->message_type == atoms[ATOM_NET_MOVERESIZE_WINDOW]) { HandleNetMoveResize(event, np); } else if(event->message_type == atoms[ATOM_NET_WM_MOVERESIZE]) { HandleNetWMMoveResize(event, np); } else if(event->message_type == atoms[ATOM_NET_RESTACK_WINDOW]) { HandleNetRestack(event, np); } else if(event->message_type == atoms[ATOM_NET_WM_STATE]) { HandleNetWMState(event, np); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to client: %s", atomName); JXFree(atomName); #endif } } else if(event->window == rootWindow) { if(event->message_type == atoms[ATOM_JWM_RESTART]) { Restart(); } else if(event->message_type == atoms[ATOM_JWM_EXIT]) { Exit(); } else if(event->message_type == atoms[ATOM_JWM_RELOAD]) { ReloadMenu(); } else if(event->message_type == atoms[ATOM_NET_CURRENT_DESKTOP]) { ChangeDesktop(event->data.l[0]); } else if(event->message_type == atoms[ATOM_NET_SHOWING_DESKTOP]) { ShowDesktop(); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to root: %s", atomName); JXFree(atomName); #endif } } else if(event->message_type == atoms[ATOM_NET_REQUEST_FRAME_EXTENTS]) { HandleFrameExtentsRequest(event); } else if(event->message_type == atoms[ATOM_NET_SYSTEM_TRAY_OPCODE]) { HandleDockEvent(event); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("ClientMessage to unknown window (0x%x): %s", event->window, atomName); JXFree(atomName); #endif } }