xhints.c (8586B)
1 #include "shod.h" 2 3 /* get window name */ 4 static char * 5 getwinname(Window win) 6 { 7 XTextProperty tprop; 8 char **list = NULL; 9 char *name = NULL; 10 unsigned char *p = NULL; 11 unsigned long size, dl; 12 int di; 13 Atom da; 14 15 if (XGetWindowProperty(dpy, win, atoms[_NET_WM_NAME], 0L, NAMEMAXLEN, False, atoms[UTF8_STRING], 16 &da, &di, &size, &dl, &p) == Success && p) { 17 name = estrndup((char *)p, NAMEMAXLEN); 18 XFree(p); 19 } else if (XGetWMName(dpy, win, &tprop) && 20 XmbTextPropertyToTextList(dpy, &tprop, &list, &di) == Success && 21 di > 0 && list && *list) { 22 name = estrndup(*list, NAMEMAXLEN); 23 XFreeStringList(list); 24 XFree(tprop.value); 25 } 26 return name; 27 } 28 29 /* check if given geometry is obscured by containers above it */ 30 static int 31 isobscured(struct Container *c, struct Monitor *mon, int desk, int x, int y, int w, int h) 32 { 33 x = max(x, mon->wx); 34 y = max(y, mon->wy); 35 w = min(x + w, mon->wx + mon->ww) - x; 36 h = min(y + h, mon->wy + mon->wh) - y; 37 if (config.disablehidden || c == NULL) 38 return 0; 39 if (w <= 0 || h <= 0) 40 return 1; 41 while ((c = TAILQ_PREV(c, ContainerQueue, raiseentry)) != NULL) { 42 if (ISDUMMY(c) || !containerisvisible(c, mon, desk)) 43 continue; 44 return isobscured(c, mon, desk, x, y, w, c->y - y) && 45 isobscured(c, mon, desk, x, y, c->x - x, h) && 46 isobscured(c, mon, desk, x, c->y + c->h, w, y + h - (c->y + c->h)) && 47 isobscured(c, mon, desk, c->x + c->w, y, x + w - (c->x + c->w), h); 48 } 49 return 0; 50 } 51 52 /* set desktop for a given window */ 53 void 54 ewmhsetdesktop(Window win, long d) 55 { 56 XChangeProperty(dpy, win, atoms[_NET_WM_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&d, 1); 57 } 58 59 /* initialize ewmh hints */ 60 void 61 ewmhinit(const char *wmname) 62 { 63 /* set window and property that indicates that the wm is ewmh compliant */ 64 XChangeProperty(dpy, wm.checkwin, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.checkwin, 1); 65 XChangeProperty(dpy, wm.checkwin, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, PropModeReplace, (unsigned char *)wmname, strlen(wmname)); 66 XChangeProperty(dpy, root, atoms[_NET_SUPPORTING_WM_CHECK], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&wm.checkwin, 1); 67 68 /* set properties that the window manager supports */ 69 XChangeProperty(dpy, root, atoms[_NET_SUPPORTED], XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, NATOMS); 70 XDeleteProperty(dpy, root, atoms[_NET_CLIENT_LIST]); 71 72 /* set number of desktops */ 73 XChangeProperty(dpy, root, atoms[_NET_NUMBER_OF_DESKTOPS], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&config.ndesktops, 1); 74 } 75 76 /* set current desktop hint */ 77 void 78 ewmhsetcurrentdesktop(unsigned long n) 79 { 80 XChangeProperty(dpy, root, atoms[_NET_CURRENT_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&n, 1); 81 } 82 83 /* set showing desktop hint */ 84 void 85 ewmhsetshowingdesktop(int n) 86 { 87 XChangeProperty(dpy, root, atoms[_NET_SHOWING_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&n, 1); 88 } 89 90 /* set stacking list of clients hint */ 91 void 92 ewmhsetclients(void) 93 { 94 Window *wins = NULL; 95 Window *cnts = NULL; 96 struct Container *c; 97 struct Column *col; 98 struct Row *row; 99 struct Object *p; 100 struct Tab *t; 101 int prevobscured, i, j = 0; 102 103 if (wm.nclients < 1) { 104 XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0); 105 XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, NULL, 0); 106 XChangeProperty(dpy, root, atoms[_SHOD_CONTAINER_LIST], XA_WINDOW, 32, PropModeReplace, NULL, 0); 107 return; 108 } 109 wins = ecalloc(wm.nclients, sizeof *wins); 110 cnts = ecalloc(wm.nclients, sizeof *cnts); 111 i = wm.nclients; 112 TAILQ_FOREACH(c, &wm.stackq, raiseentry) { 113 if (ISDUMMY(c)) 114 continue; 115 cnts[j++] = c->selcol->selrow->seltab->obj.win; 116 prevobscured = c->isobscured; 117 if (!config.disablehidden) 118 c->isobscured = isobscured(c, c->mon, c->desk, c->x, c->y, c->w, c->h); 119 TAILQ_FOREACH(col, &c->colq, entry) { 120 if (col->selrow->seltab != NULL) 121 wins[--i] = col->selrow->seltab->obj.win; 122 TAILQ_FOREACH(p, &col->selrow->tabq, entry) { 123 t = (struct Tab *)p; 124 if (t != col->selrow->seltab) { 125 wins[--i] = t->obj.win; 126 } 127 } 128 TAILQ_FOREACH(row, &col->rowq, entry) { 129 if (row == col->selrow) 130 continue; 131 if (row->seltab != NULL) 132 wins[--i] = row->seltab->obj.win; 133 TAILQ_FOREACH(p, &row->tabq, entry) { 134 t = (struct Tab *)p; 135 if (t != row->seltab) { 136 wins[--i] = t->obj.win; 137 } 138 } 139 } 140 } 141 if (prevobscured != c->isobscured) { 142 ewmhsetstate(c); 143 } 144 } 145 XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins, wm.nclients-i); 146 XChangeProperty(dpy, root, atoms[_NET_CLIENT_LIST_STACKING], XA_WINDOW, 32, PropModeReplace, (unsigned char *)wins+i, wm.nclients-i); 147 XChangeProperty(dpy, root, atoms[_SHOD_CONTAINER_LIST], XA_WINDOW, 32, PropModeReplace, (unsigned char *)cnts, j); 148 free(wins); 149 free(cnts); 150 } 151 152 /* set active window hint */ 153 void 154 ewmhsetactivewindow(Window w) 155 { 156 XChangeProperty(dpy, root, atoms[_NET_ACTIVE_WINDOW], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1); 157 } 158 159 /* set desktop for all windows in a container */ 160 void 161 ewmhsetwmdesktop(struct Container *c) 162 { 163 struct Object *t; 164 unsigned long n; 165 166 n = (c->issticky || c->isminimized) ? 0xFFFFFFFF : (unsigned long)c->desk; 167 TAB_FOREACH_BEGIN(c, t){ 168 ewmhsetdesktop(t->win, n); 169 }TAB_FOREACH_END 170 } 171 172 /* set frames of window */ 173 void 174 ewmhsetframeextents(Window win, int b, int t) 175 { 176 unsigned long data[4]; 177 178 data[0] = data[1] = data[3] = b; 179 data[2] = b + t; 180 XChangeProperty(dpy, win, atoms[_NET_FRAME_EXTENTS], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 4); 181 } 182 183 /* set state of windows */ 184 void 185 ewmhsetstate(struct Container *c) 186 { 187 struct Object *t; 188 Atom data[9]; 189 int n = 0; 190 191 if (c == NULL) 192 return; 193 if (c == wm.focused) 194 data[n++] = atoms[_NET_WM_STATE_FOCUSED]; 195 if (c->isfullscreen) 196 data[n++] = atoms[_NET_WM_STATE_FULLSCREEN]; 197 if (c->issticky) 198 data[n++] = atoms[_NET_WM_STATE_STICKY]; 199 if (c->isshaded) 200 data[n++] = atoms[_NET_WM_STATE_SHADED]; 201 if (c->isminimized || c->isobscured) 202 data[n++] = atoms[_NET_WM_STATE_HIDDEN]; 203 if (c->ismaximized) { 204 data[n++] = atoms[_NET_WM_STATE_MAXIMIZED_VERT]; 205 data[n++] = atoms[_NET_WM_STATE_MAXIMIZED_HORZ]; 206 } 207 if (c->abovebelow > 0) 208 data[n++] = atoms[_NET_WM_STATE_ABOVE]; 209 else if (c->abovebelow < 0) 210 data[n++] = atoms[_NET_WM_STATE_BELOW]; 211 TAB_FOREACH_BEGIN(c, t){ 212 XChangeProperty(dpy, t->win, atoms[_NET_WM_STATE], XA_ATOM, 32, PropModeReplace, (unsigned char *)data, n); 213 }TAB_FOREACH_END 214 } 215 216 /* set icccm wmstate */ 217 void 218 icccmwmstate(Window win, int state) 219 { 220 long data[2]; 221 222 data[0] = state; 223 data[1] = None; 224 XChangeProperty(dpy, win, atoms[WM_STATE], atoms[WM_STATE], 32, PropModeReplace, (unsigned char *)&data, 2); 225 } 226 227 /* delete window state property */ 228 void 229 icccmdeletestate(Window win) 230 { 231 XDeleteProperty(dpy, win, atoms[WM_STATE]); 232 } 233 234 /* set group of windows in client */ 235 void 236 shodgrouptab(struct Container *c) 237 { 238 struct Object *t; 239 240 TAB_FOREACH_BEGIN(c, t){ 241 XChangeProperty(dpy, t->win, atoms[_SHOD_GROUP_TAB], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&row->seltab->obj.win, 1); 242 }TAB_FOREACH_END 243 } 244 245 /* set group of windows in client */ 246 void 247 shodgroupcontainer(struct Container *c) 248 { 249 struct Object *t; 250 251 TAB_FOREACH_BEGIN(c, t){ 252 XChangeProperty(dpy, t->win, atoms[_SHOD_GROUP_CONTAINER], XA_WINDOW, 32, PropModeReplace, (unsigned char *)&c->selcol->selrow->seltab->obj.win, 1); 253 }TAB_FOREACH_END 254 } 255 256 /* update tab title */ 257 void 258 winupdatetitle(Window win, char **name) 259 { 260 free(*name); 261 *name = getwinname(win); 262 } 263 264 /* notify window of configuration changing */ 265 void 266 winnotify(Window win, int x, int y, int w, int h) 267 { 268 XConfigureEvent ce; 269 270 ce.type = ConfigureNotify; 271 ce.display = dpy; 272 ce.x = x; 273 ce.y = y; 274 ce.width = w; 275 ce.height = h; 276 ce.border_width = 0; 277 ce.above = None; 278 ce.override_redirect = False; 279 ce.event = win; 280 ce.window = win; 281 XSendEvent(dpy, win, False, StructureNotifyMask, (XEvent *)&ce); 282 } 283 284 /* send a WM_DELETE message to client */ 285 void 286 winclose(Window win) 287 { 288 XEvent ev; 289 290 ev.type = ClientMessage; 291 ev.xclient.window = win; 292 ev.xclient.message_type = atoms[WM_PROTOCOLS]; 293 ev.xclient.format = 32; 294 ev.xclient.data.l[0] = atoms[WM_DELETE_WINDOW]; 295 ev.xclient.data.l[1] = CurrentTime; 296 297 /* 298 * communicate with the given Client, kindly telling it to 299 * close itself and terminate any associated processes using 300 * the WM_DELETE_WINDOW protocol 301 */ 302 XSendEvent(dpy, win, False, NoEventMask, &ev); 303 }