aewl

annotate client.c @ 27:f96fb3fd8203

added grid mode on Mod1Mask g
author Anselm R. Garbe <garbeam@wmii.de>
date Wed, 12 Jul 2006 16:00:51 +0200
parents e8f627998d6f
children 3dceb132082d
rev   line source
garbeam@5 1 /*
garbeam@5 2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
garbeam@5 3 * See LICENSE file for license details.
garbeam@5 4 */
garbeam@5 5
garbeam@27 6 #include <math.h>
garbeam@10 7 #include <stdlib.h>
garbeam@5 8 #include <string.h>
garbeam@5 9 #include <X11/Xatom.h>
garbeam@5 10
garbeam@5 11 #include "util.h"
garbeam@5 12 #include "wm.h"
garbeam@5 13
garbeam@27 14 void
garbeam@27 15 arrange(void *aux)
garbeam@27 16 {
garbeam@27 17 Client *c;
garbeam@27 18 int n, cols, rows, gw, gh, i, j;
garbeam@27 19 float rt, fd;
garbeam@27 20
garbeam@27 21 if(!clients)
garbeam@27 22 return;
garbeam@27 23 for(n = 0, c = clients; c; c = c->next, n++);
garbeam@27 24 rt = sqrt(n);
garbeam@27 25 if(modff(rt, &fd) < 0.5)
garbeam@27 26 rows = floor(rt);
garbeam@27 27 else
garbeam@27 28 rows = ceil(rt);
garbeam@27 29 if(rows * rows < n)
garbeam@27 30 cols = rows + 1;
garbeam@27 31 else
garbeam@27 32 cols = rows;
garbeam@27 33
garbeam@27 34 gw = (sw - 1) / cols;
garbeam@27 35 gh = (sh - bh - 1) / rows;
garbeam@27 36
garbeam@27 37 for(i = j = 0, c = clients; c; c = c->next) {
garbeam@27 38 c->x = i * gw;
garbeam@27 39 c->y = j * gh + bh;
garbeam@27 40 c->w = gw;
garbeam@27 41 c->h = gh;
garbeam@27 42 resize(c);
garbeam@27 43 if(++i == cols) {
garbeam@27 44 j++;
garbeam@27 45 i = 0;
garbeam@27 46 }
garbeam@27 47 }
garbeam@27 48 }
garbeam@27 49
garbeam@27 50 void
garbeam@27 51 sel(void *aux)
garbeam@27 52 {
garbeam@27 53 const char *arg = aux;
garbeam@27 54 Client *c = NULL;
garbeam@27 55
garbeam@27 56 if(!arg || !stack)
garbeam@27 57 return;
garbeam@27 58 if(!strncmp(arg, "next", 5))
garbeam@27 59 c = stack->snext ? stack->snext : stack;
garbeam@27 60 else if(!strncmp(arg, "prev", 5))
garbeam@27 61 for(c = stack; c && c->snext; c = c->snext);
garbeam@27 62 if(!c)
garbeam@27 63 c = stack;
garbeam@27 64 raise(c);
garbeam@27 65 focus(c);
garbeam@27 66 }
garbeam@27 67
garbeam@27 68 void
garbeam@27 69 kill(void *aux)
garbeam@27 70 {
garbeam@27 71 Client *c = stack;
garbeam@27 72
garbeam@27 73 if(!c)
garbeam@27 74 return;
garbeam@27 75 if(c->proto & WM_PROTOCOL_DELWIN)
garbeam@27 76 send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
garbeam@27 77 else
garbeam@27 78 XKillClient(dpy, c->win);
garbeam@27 79 }
garbeam@27 80
garbeam@26 81 static void
garbeam@26 82 resize_title(Client *c)
garbeam@26 83 {
garbeam@26 84 c->tw = textw(&brush.font, c->name) + bh;
garbeam@26 85 if(c->tw > c->w)
garbeam@26 86 c->tw = c->w + 2;
garbeam@26 87 c->tx = c->x + c->w - c->tw + 2;
garbeam@26 88 c->ty = c->y;
garbeam@26 89 XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
garbeam@26 90 }
garbeam@18 91
garbeam@13 92 void
garbeam@13 93 update_name(Client *c)
garbeam@5 94 {
garbeam@5 95 XTextProperty name;
garbeam@5 96 int n;
garbeam@7 97 char **list = NULL;
garbeam@5 98
garbeam@5 99 name.nitems = 0;
garbeam@5 100 c->name[0] = 0;
garbeam@5 101 XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
garbeam@5 102 if(!name.nitems)
garbeam@5 103 XGetWMName(dpy, c->win, &name);
garbeam@5 104 if(!name.nitems)
garbeam@5 105 return;
garbeam@5 106 if(name.encoding == XA_STRING)
garbeam@5 107 strncpy(c->name, (char *)name.value, sizeof(c->name));
garbeam@5 108 else {
garbeam@5 109 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
garbeam@5 110 && n > 0 && *list)
garbeam@5 111 {
garbeam@5 112 strncpy(c->name, *list, sizeof(c->name));
garbeam@5 113 XFreeStringList(list);
garbeam@5 114 }
garbeam@5 115 }
garbeam@5 116 XFree(name.value);
garbeam@26 117 resize_title(c);
garbeam@5 118 }
garbeam@5 119
garbeam@10 120 void
garbeam@20 121 update_size(Client *c)
garbeam@20 122 {
garbeam@20 123 XSizeHints size;
garbeam@20 124 long msize;
garbeam@20 125 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
garbeam@20 126 size.flags = PSize;
garbeam@20 127 c->flags = size.flags;
garbeam@21 128 if(c->flags & PBaseSize) {
garbeam@21 129 c->basew = size.base_width;
garbeam@21 130 c->baseh = size.base_height;
garbeam@21 131 }
garbeam@21 132 else
garbeam@21 133 c->basew = c->baseh = 0;
garbeam@21 134 if(c->flags & PResizeInc) {
garbeam@21 135 c->incw = size.width_inc;
garbeam@21 136 c->inch = size.height_inc;
garbeam@21 137 }
garbeam@21 138 else
garbeam@21 139 c->incw = c->inch = 0;
garbeam@21 140 if(c->flags & PMaxSize) {
garbeam@21 141 c->maxw = size.max_width;
garbeam@21 142 c->maxh = size.max_height;
garbeam@21 143 }
garbeam@21 144 else
garbeam@21 145 c->maxw = c->maxh = 0;
garbeam@21 146 if(c->flags & PMinSize) {
garbeam@21 147 c->minw = size.min_width;
garbeam@21 148 c->minh = size.min_height;
garbeam@21 149 }
garbeam@21 150 else
garbeam@21 151 c->minw = c->minh = 0;
garbeam@20 152 }
garbeam@20 153
garbeam@20 154 void
garbeam@26 155 raise(Client *c)
garbeam@26 156 {
garbeam@26 157 XRaiseWindow(dpy, c->win);
garbeam@26 158 XRaiseWindow(dpy, c->title);
garbeam@26 159 }
garbeam@26 160
garbeam@26 161 void
garbeam@26 162 lower(Client *c)
garbeam@26 163 {
garbeam@26 164 XLowerWindow(dpy, c->title);
garbeam@26 165 XLowerWindow(dpy, c->win);
garbeam@26 166 }
garbeam@26 167
garbeam@26 168 void
garbeam@13 169 focus(Client *c)
garbeam@13 170 {
garbeam@21 171 Client **l, *old;
garbeam@21 172
garbeam@21 173 old = stack;
garbeam@26 174 for(l = &stack; *l && *l != c; l = &(*l)->snext);
garbeam@13 175 eassert(*l == c);
garbeam@13 176 *l = c->snext;
garbeam@13 177 c->snext = stack;
garbeam@13 178 stack = c;
garbeam@21 179 if(old && old != c) {
garbeam@21 180 XMapWindow(dpy, old->title);
garbeam@21 181 draw_client(old);
garbeam@21 182 }
garbeam@21 183 XUnmapWindow(dpy, c->title);
garbeam@27 184 draw_client(c);
garbeam@26 185 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
garbeam@13 186 XFlush(dpy);
garbeam@13 187 }
garbeam@13 188
garbeam@13 189 void
garbeam@10 190 manage(Window w, XWindowAttributes *wa)
garbeam@5 191 {
garbeam@10 192 Client *c, **l;
garbeam@5 193 XSetWindowAttributes twa;
garbeam@5 194
garbeam@5 195 c = emallocz(sizeof(Client));
garbeam@5 196 c->win = w;
garbeam@22 197 c->tx = c->x = wa->x;
garbeam@22 198 c->ty = c->y = wa->y;
garbeam@26 199 if(c->y < bh)
garbeam@26 200 c->ty = c->y += bh;
garbeam@22 201 c->tw = c->w = wa->width;
garbeam@20 202 c->h = wa->height;
garbeam@26 203 c->th = bh;
garbeam@20 204 update_size(c);
garbeam@19 205 XSetWindowBorderWidth(dpy, c->win, 1);
garbeam@22 206 XSetWindowBorder(dpy, c->win, brush.border);
garbeam@26 207 XSelectInput(dpy, c->win,
garbeam@26 208 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
garbeam@5 209 XGetTransientForHint(dpy, c->win, &c->trans);
garbeam@5 210 twa.override_redirect = 1;
garbeam@5 211 twa.background_pixmap = ParentRelative;
garbeam@23 212 twa.event_mask = ExposureMask;
garbeam@5 213
garbeam@22 214 c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
garbeam@20 215 0, DefaultDepth(dpy, screen), CopyFromParent,
garbeam@5 216 DefaultVisual(dpy, screen),
garbeam@5 217 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
garbeam@21 218 update_name(c);
garbeam@5 219
garbeam@10 220 for(l=&clients; *l; l=&(*l)->next);
garbeam@10 221 c->next = *l; /* *l == nil */
garbeam@10 222 *l = c;
garbeam@13 223 c->snext = stack;
garbeam@13 224 stack = c;
garbeam@26 225 XMapRaised(dpy, c->win);
garbeam@26 226 XMapRaised(dpy, c->title);
garbeam@19 227 XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
garbeam@19 228 GrabModeAsync, GrabModeSync, None, None);
garbeam@19 229 XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
garbeam@19 230 GrabModeAsync, GrabModeSync, None, None);
garbeam@19 231 XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
garbeam@18 232 GrabModeAsync, GrabModeSync, None, None);
garbeam@21 233 resize(c);
garbeam@13 234 focus(c);
garbeam@5 235 }
garbeam@9 236
garbeam@18 237 void
garbeam@18 238 resize(Client *c)
garbeam@18 239 {
garbeam@18 240 XConfigureEvent e;
garbeam@18 241
garbeam@26 242 resize_title(c);
garbeam@20 243 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
garbeam@18 244 e.type = ConfigureNotify;
garbeam@18 245 e.event = c->win;
garbeam@18 246 e.window = c->win;
garbeam@20 247 e.x = c->x;
garbeam@20 248 e.y = c->y;
garbeam@20 249 e.width = c->w;
garbeam@20 250 e.height = c->h;
garbeam@19 251 e.border_width = 0;
garbeam@18 252 e.above = None;
garbeam@18 253 e.override_redirect = False;
garbeam@18 254 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
garbeam@18 255 XFlush(dpy);
garbeam@18 256 }
garbeam@18 257
garbeam@10 258 static int
garbeam@10 259 dummy_error_handler(Display *dpy, XErrorEvent *error)
garbeam@10 260 {
garbeam@10 261 return 0;
garbeam@10 262 }
garbeam@10 263
garbeam@10 264 void
garbeam@10 265 unmanage(Client *c)
garbeam@10 266 {
garbeam@10 267 Client **l;
garbeam@10 268
garbeam@10 269 XGrabServer(dpy);
garbeam@10 270 XSetErrorHandler(dummy_error_handler);
garbeam@10 271
garbeam@18 272 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
garbeam@10 273 XDestroyWindow(dpy, c->title);
garbeam@10 274
garbeam@10 275 for(l=&clients; *l && *l != c; l=&(*l)->next);
garbeam@10 276 eassert(*l == c);
garbeam@10 277 *l = c->next;
garbeam@13 278 for(l=&stack; *l && *l != c; l=&(*l)->snext);
garbeam@13 279 eassert(*l == c);
garbeam@13 280 *l = c->snext;
garbeam@10 281 free(c);
garbeam@10 282
garbeam@10 283 XFlush(dpy);
garbeam@10 284 XSetErrorHandler(error_handler);
garbeam@10 285 XUngrabServer(dpy);
garbeam@14 286 if(stack)
garbeam@14 287 focus(stack);
garbeam@10 288 }
garbeam@10 289
garbeam@23 290 Client *
garbeam@23 291 gettitle(Window w)
garbeam@23 292 {
garbeam@23 293 Client *c;
garbeam@23 294 for(c = clients; c; c = c->next)
garbeam@23 295 if(c->title == w)
garbeam@23 296 return c;
garbeam@23 297 return NULL;
garbeam@23 298 }
garbeam@10 299
garbeam@9 300 Client *
garbeam@9 301 getclient(Window w)
garbeam@9 302 {
garbeam@9 303 Client *c;
garbeam@9 304 for(c = clients; c; c = c->next)
garbeam@9 305 if(c->win == w)
garbeam@9 306 return c;
garbeam@9 307 return NULL;
garbeam@9 308 }
garbeam@13 309
garbeam@14 310 void
garbeam@14 311 draw_client(Client *c)
garbeam@14 312 {
garbeam@26 313 if(c == stack) {
garbeam@21 314 draw_bar();
garbeam@26 315 return;
garbeam@26 316 }
garbeam@14 317
garbeam@26 318 brush.x = brush.y = 0;
garbeam@26 319 brush.w = c->tw;
garbeam@26 320 brush.h = c->th;
garbeam@14 321
garbeam@21 322 draw(dpy, &brush, True, c->name);
garbeam@22 323 XCopyArea(dpy, brush.drawable, c->title, brush.gc,
garbeam@22 324 0, 0, c->tw, c->th, 0, 0);
garbeam@21 325 XFlush(dpy);
garbeam@14 326 }