/** 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 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 _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); } }
/** 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; }
/** 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(); } }