/** Send a delete message to a client. */ void DeleteClient(ClientNode *np) { Assert(np); ReadWMProtocols(np->window, &np->state); if(np->state.status & STAT_DELETE) { SendClientMessage(np->window, ATOM_WM_PROTOCOLS, ATOM_WM_DELETE_WINDOW); } else { KillClient(np); } }
/** Destroy a swallow tray component. */ void Destroy(TrayComponentType *cp) { ClientProtocolType protocols; /* Destroy the window if there is one. */ if(cp->window) { JXReparentWindow(display, cp->window, rootWindow, 0, 0); JXRemoveFromSaveSet(display, cp->window); protocols = ReadWMProtocols(cp->window); if(protocols & PROT_DELETE) { SendClientMessage(cp->window, ATOM_WM_PROTOCOLS, ATOM_WM_DELETE_WINDOW); } else { JXKillClient(display, cp->window); } } }
/** 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; }
/** Handle a property notify event. */ char HandlePropertyNotify(const XPropertyEvent *event) { ClientNode *np = FindClientByWindow(event->window); if(np) { char changed = 0; switch(event->atom) { case XA_WM_NAME: ReadWMName(np); changed = 1; break; case XA_WM_NORMAL_HINTS: ReadWMNormalHints(np); if(ConstrainSize(np)) { ResetBorder(np); } changed = 1; break; case XA_WM_HINTS: if(np->state.status & STAT_URGENT) { UnregisterCallback(SignalUrgent, np); } ReadWMHints(np->window, &np->state, 1); if(np->state.status & STAT_URGENT) { RegisterCallback(URGENCY_DELAY, SignalUrgent, np); } WriteState(np); break; case XA_WM_TRANSIENT_FOR: JXGetTransientForHint(display, np->window, &np->owner); break; case XA_WM_ICON_NAME: case XA_WM_CLIENT_MACHINE: break; default: if(event->atom == atoms[ATOM_WM_COLORMAP_WINDOWS]) { ReadWMColormaps(np); UpdateClientColormap(np); } else if(event->atom == atoms[ATOM_WM_PROTOCOLS]) { ReadWMProtocols(np->window, &np->state); } else if(event->atom == atoms[ATOM_NET_WM_ICON]) { LoadIcon(np); changed = 1; } else if(event->atom == atoms[ATOM_NET_WM_NAME]) { ReadWMName(np); changed = 1; } else if(event->atom == atoms[ATOM_NET_WM_STRUT_PARTIAL]) { ReadClientStrut(np); } else if(event->atom == atoms[ATOM_NET_WM_STRUT]) { ReadClientStrut(np); } else if(event->atom == atoms[ATOM_MOTIF_WM_HINTS]) { UpdateState(np); WriteState(np); ResetBorder(np); changed = 1; } else if(event->atom == atoms[ATOM_NET_WM_WINDOW_OPACITY]) { ReadWMOpacity(np->window, &np->state.opacity); if(np->parent != None) { SetOpacity(np, np->state.opacity, 1); } } break; } if(changed) { DrawBorder(np); RequireTaskUpdate(); RequirePagerUpdate(); } if(np->state.status & STAT_WMDIALOG) { return 0; } else { return 1; } } return 1; }