xdock.c (10042B)
1 #include "shod.h" 2 3 /* decorate dock */ 4 void 5 dockdecorate(void) 6 { 7 if (dock.pw != dock.w || dock.ph != dock.h || dock.pix == None) 8 pixmapnew(&dock.pix, dock.win, dock.w, dock.h); 9 dock.pw = dock.w; 10 dock.ph = dock.h; 11 drawdock(dock.pix, dock.w, dock.h); 12 drawcommit(dock.pix, dock.win); 13 } 14 15 /* configure dockapp window */ 16 void 17 dockappconfigure(struct Dockapp *dapp, unsigned int valuemask, XWindowChanges *wc) 18 { 19 if (dapp == NULL) 20 return; 21 if (valuemask & CWWidth) 22 dapp->w = wc->width; 23 if (valuemask & CWHeight) 24 dapp->h = wc->height; 25 switch (config.dockgravity[0]) { 26 case 'N': 27 case 'S': 28 if (dapp->state & SHRUNK) 29 dapp->slotsize = dapp->w; 30 else 31 dapp->slotsize = (dapp->w / config.dockspace + (dapp->w % config.dockspace ? 1 : 0)) * config.dockspace; 32 dapp->h = min(config.dockwidth, dapp->h); 33 break; 34 case 'W': 35 case 'E': 36 default: 37 if (dapp->state & SHRUNK) 38 dapp->slotsize = dapp->h; 39 else 40 dapp->slotsize = (dapp->h / config.dockspace + (dapp->h % config.dockspace ? 1 : 0)) * config.dockspace; 41 dapp->w = min(config.dockwidth, dapp->w); 42 break; 43 } 44 } 45 46 static void 47 dockappinsert(struct Dockapp *dapp) 48 { 49 struct Object *prev; 50 51 if (dapp->dockpos == 0) { 52 TAILQ_INSERT_TAIL(&dock.dappq, (struct Object *)dapp, entry); 53 } else { 54 TAILQ_FOREACH_REVERSE(prev, &dock.dappq, Queue, entry) 55 if (((struct Dockapp *)prev)->dockpos <= dapp->dockpos) 56 break; 57 if (prev != NULL) { 58 TAILQ_INSERT_AFTER(&dock.dappq, prev, (struct Object *)dapp, entry); 59 } else { 60 TAILQ_INSERT_HEAD(&dock.dappq, (struct Object *)dapp, entry); 61 } 62 } 63 dockappconfigure( 64 dapp, 65 CWWidth | CWHeight, 66 &(XWindowChanges){ 67 .width = dapp->w, 68 .height = dapp->h, 69 } 70 ); 71 } 72 73 /* create dockapp */ 74 static void 75 dockappnew(Window win, int w, int h, int dockpos, int state, int ignoreunmap) 76 { 77 struct Dockapp *dapp; 78 79 dapp = emalloc(sizeof(*dapp)); 80 *dapp = (struct Dockapp){ 81 .obj.type = TYPE_DOCKAPP, 82 .obj.win = win, 83 .x = 0, 84 .y = 0, 85 .w = w, 86 .h = h, 87 .ignoreunmap = ignoreunmap, 88 .dockpos = dockpos, 89 .state = state, 90 }; 91 dockappinsert(dapp); 92 } 93 94 /* compute dockapp position given its width or height */ 95 static int 96 dockapppos(int pos) 97 { 98 return max(0, config.dockwidth / 2 - pos / 2); 99 } 100 101 /* update dock position; create it, if necessary */ 102 static void 103 dockupdateresizeable(void) 104 { 105 struct Monitor *mon; 106 struct Object *p; 107 struct Dockapp *dapp; 108 int size; 109 110 mon = TAILQ_FIRST(&wm.monq); 111 size = 0; 112 TAILQ_FOREACH(p, &dock.dappq, entry) { 113 dapp = (struct Dockapp *)p; 114 switch (config.dockgravity[0]) { 115 case 'N': 116 if (dapp->state & RESIZED) 117 dapp->h = config.dockwidth; 118 dapp->x = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->w) / 2); 119 dapp->y = DOCKBORDER + dockapppos(dapp->h); 120 break; 121 case 'S': 122 if (dapp->state & RESIZED) 123 dapp->h = config.dockwidth; 124 dapp->x = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->w) / 2); 125 dapp->y = DOCKBORDER + dockapppos(dapp->h); 126 break; 127 case 'W': 128 if (dapp->state & RESIZED) 129 dapp->w = config.dockwidth; 130 dapp->x = DOCKBORDER + dockapppos(dapp->w); 131 dapp->y = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->h) / 2); 132 break; 133 case 'E': 134 default: 135 if (dapp->state & RESIZED) 136 dapp->w = config.dockwidth; 137 dapp->x = DOCKBORDER + dockapppos(dapp->w); 138 dapp->y = DOCKBORDER + size + max(0, (dapp->slotsize - dapp->h) / 2); 139 break; 140 } 141 size += dapp->slotsize; 142 } 143 if (size == 0) { 144 XUnmapWindow(dpy, dock.win); 145 dock.mapped = 0; 146 return; 147 } 148 dock.mapped = 1; 149 size += DOCKBORDER * 2; 150 switch (config.dockgravity[0]) { 151 case 'N': 152 dock.h = config.dockwidth; 153 dock.x = mon->mx; 154 dock.y = mon->my; 155 break; 156 case 'S': 157 dock.h = config.dockwidth; 158 dock.x = mon->mx; 159 dock.y = mon->my + mon->mh - config.dockwidth; 160 break; 161 case 'W': 162 dock.w = config.dockwidth; 163 dock.x = mon->mx; 164 dock.y = mon->my; 165 break; 166 case 'E': 167 default: 168 dock.w = config.dockwidth; 169 dock.x = mon->mx + mon->mw - config.dockwidth; 170 dock.h = min(size, mon->mh); 171 dock.y = mon->my + mon->mh / 2 - size / 2; 172 break; 173 } 174 if (config.dockgravity[0] == 'N' || config.dockgravity[0] == 'S') { 175 switch (config.dockgravity[1]) { 176 case 'F': 177 dock.x = mon->mx; 178 dock.w = mon->mw; 179 break; 180 case 'W': 181 dock.w = min(size, mon->mw); 182 dock.x = mon->mx; 183 break; 184 case 'E': 185 dock.w = min(size, mon->mw); 186 dock.x = mon->mx + mon->mw - size; 187 break; 188 default: 189 dock.w = min(size, mon->mw); 190 dock.x = mon->mx + mon->mw / 2 - size / 2; 191 break; 192 } 193 } else if (config.dockgravity[0] != '\0') { 194 switch (config.dockgravity[1]) { 195 case 'F': 196 dock.h = mon->mh; 197 dock.y = mon->my; 198 break; 199 case 'N': 200 dock.h = min(size, mon->mh); 201 dock.y = mon->my; 202 break; 203 case 'S': 204 dock.h = min(size, mon->mh); 205 dock.y = mon->my + mon->mh - size; 206 break; 207 default: 208 dock.h = min(size, mon->mh); 209 dock.y = mon->my + mon->mh / 2 - size / 2; 210 break; 211 } 212 } 213 TAILQ_FOREACH(p, &dock.dappq, entry) { 214 dapp = (struct Dockapp *)p; 215 XMoveResizeWindow(dpy, dapp->obj.win, dapp->x, dapp->y, dapp->w, dapp->h); 216 winnotify(dapp->obj.win, dock.x + dapp->x, dock.y + dapp->y, dapp->w, dapp->h); 217 } 218 } 219 220 /* update dock position; create it, if necessary */ 221 static void 222 dockupdatefull(void) 223 { 224 struct Object *p; 225 struct Monitor *mon; 226 struct Dockapp *dapp; 227 int part, nextend, size; 228 int i, n; 229 230 mon = TAILQ_FIRST(&wm.monq); 231 if (TAILQ_FIRST(&dock.dappq) == NULL) { 232 XUnmapWindow(dpy, dock.win); 233 dock.mapped = 0; 234 return; 235 } 236 dock.mapped = 1; 237 switch (config.dockgravity[0]) { 238 case 'N': 239 dock.x = mon->mx; 240 dock.y = mon->my; 241 dock.w = mon->mw; 242 dock.h = config.dockwidth; 243 part = dock.w; 244 break; 245 case 'S': 246 dock.x = mon->mx; 247 dock.y = mon->my + mon->mh - config.dockwidth; 248 dock.w = mon->mw; 249 dock.h = config.dockwidth; 250 part = dock.w; 251 break; 252 case 'W': 253 dock.x = mon->mx; 254 dock.y = mon->my; 255 dock.w = config.dockwidth; 256 dock.h = mon->mh; 257 part = dock.h; 258 break; 259 case 'E': 260 default: 261 dock.x = mon->mx + mon->mw - config.dockwidth; 262 dock.y = mon->my; 263 dock.w = config.dockwidth; 264 dock.h = mon->mh; 265 part = dock.h; 266 break; 267 } 268 nextend = 0; 269 size = 0; 270 TAILQ_FOREACH(p, &dock.dappq, entry) { 271 dapp = (struct Dockapp *)p; 272 if (dapp->state & EXTEND) { 273 nextend++; 274 } else { 275 size += dapp->slotsize; 276 } 277 } 278 part = max(part - size, 1); 279 if (nextend > 0) 280 part /= nextend; 281 i = 0; 282 size = 0; 283 TAILQ_FOREACH(p, &dock.dappq, entry) { 284 dapp = (struct Dockapp *)p; 285 switch (config.dockgravity[0]) { 286 case 'N': 287 if (dapp->state & RESIZED) 288 dapp->h = config.dockwidth - DOCKBORDER; 289 if (dapp->state & EXTEND) { 290 dapp->w = max(1, (i + 1) * part - i * part); 291 n = dapp->w; 292 } else { 293 n = dapp->slotsize; 294 } 295 dapp->x = size + max(0, (n - dapp->w) / 2); 296 dapp->y = DOCKBORDER + dockapppos(dapp->h); 297 break; 298 case 'S': 299 if (dapp->state & RESIZED) 300 dapp->h = config.dockwidth - DOCKBORDER; 301 if (dapp->state & EXTEND) { 302 dapp->w = max(1, (i + 1) * part - i * part); 303 n = dapp->w; 304 } else { 305 n = dapp->slotsize; 306 } 307 dapp->x = size + max(0, (n - dapp->w) / 2); 308 dapp->y = DOCKBORDER + dockapppos(dapp->h); 309 break; 310 case 'W': 311 if (dapp->state & RESIZED) 312 dapp->w = config.dockwidth - DOCKBORDER; 313 if (dapp->state & EXTEND) { 314 dapp->h = max(1, (i + 1) * part - i * part); 315 n = dapp->h; 316 } else { 317 n = dapp->slotsize; 318 } 319 dapp->x = DOCKBORDER + dockapppos(dapp->w); 320 dapp->y = size + max(0, (n - dapp->h) / 2); 321 break; 322 case 'E': 323 default: 324 if (dapp->state & RESIZED) 325 dapp->w = config.dockwidth - DOCKBORDER; 326 if (dapp->state & EXTEND) { 327 dapp->h = max(1, (i + 1) * part - i * part); 328 n = dapp->h; 329 } else { 330 n = dapp->slotsize; 331 } 332 dapp->x = DOCKBORDER + dockapppos(dapp->w); 333 dapp->y = size + max(0, (n - dapp->h) / 2); 334 break; 335 } 336 XMoveResizeWindow(dpy, dapp->obj.win, dapp->x, dapp->y, dapp->w, dapp->h); 337 winnotify(dapp->obj.win, dock.x + dapp->x, dock.y + dapp->y, dapp->w, dapp->h); 338 size += n; 339 } 340 } 341 342 /* update dock position; create it, if necessary */ 343 void 344 dockupdate(void) 345 { 346 Window wins[2]; 347 348 if (TAILQ_EMPTY(&dock.dappq)) { 349 XUnmapWindow(dpy, dock.win); 350 return; 351 } 352 if (config.dockgravity[0] != '\0' && (config.dockgravity[1] == 'F' || config.dockgravity[1] == 'f')) { 353 dockupdatefull(); 354 } else { 355 dockupdateresizeable(); 356 } 357 dockdecorate(); 358 wins[0] = wm.layers[LAYER_DOCK].frame; 359 wins[1] = dock.win; 360 XMoveResizeWindow(dpy, dock.win, dock.x, dock.y, dock.w, dock.h); 361 XRestackWindows(dpy, wins, 2); 362 XMapWindow(dpy, dock.win); 363 XMapSubwindows(dpy, dock.win); 364 } 365 366 /* map dockapp window */ 367 void 368 managedockapp(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap) 369 { 370 (void)tab; 371 (void)mon; 372 (void)desk; 373 (void)leader; 374 XReparentWindow(dpy, win, dock.win, 0, 0); 375 dockappnew(win, rect.width, rect.height, rect.x, state, ignoreunmap); 376 dockupdate(); 377 monupdatearea(); 378 } 379 380 /* delete dockapp */ 381 int 382 unmanagedockapp(struct Object *obj, int ignoreunmap) 383 { 384 struct Dockapp *dapp; 385 386 dapp = (struct Dockapp *)obj; 387 if (ignoreunmap && dapp->ignoreunmap) { 388 dapp->ignoreunmap--; 389 return 0; 390 } 391 TAILQ_REMOVE(&dock.dappq, (struct Object *)dapp, entry); 392 XReparentWindow(dpy, dapp->obj.win, root, 0, 0); 393 free(dapp); 394 dockupdate(); 395 monupdatearea(); 396 return 0; 397 } 398 399 void 400 dockreset(void) 401 { 402 struct Queue dappq; 403 struct Object *obj; 404 struct Dockapp *dapp; 405 Window win, dummyw; 406 struct Tab *dummyt; 407 XRectangle rect; 408 int state, desk; 409 410 if (TAILQ_EMPTY(&dock.dappq)) { 411 XUnmapWindow(dpy, dock.win); 412 return; 413 } 414 TAILQ_INIT(&dappq); 415 while ((obj = TAILQ_FIRST(&dock.dappq)) != NULL) { 416 TAILQ_REMOVE(&dock.dappq, obj, entry); 417 TAILQ_INSERT_TAIL(&dappq, obj, entry); 418 } 419 while ((obj = TAILQ_FIRST(&dappq)) != NULL) { 420 TAILQ_REMOVE(&dappq, obj, entry); 421 win = obj->win; 422 dapp = (struct Dockapp *)obj; 423 if (getwintype(&win, &dummyw, &dummyt, &state, &rect, &desk) == TYPE_DOCKAPP) { 424 if (rect.x > 0) { 425 dapp->dockpos = rect.x; 426 } 427 if (state != 0) { 428 dapp->state = state; 429 } 430 } 431 dockappinsert(dapp); 432 } 433 dockupdate(); 434 }