diff options
| -rw-r--r-- | .clang-format | 6 | ||||
| -rw-r--r-- | src/config/config.def.h | 11 | ||||
| -rw-r--r-- | src/config/config.h | 11 | ||||
| -rw-r--r-- | src/core/dwm.c | 4535 | ||||
| -rw-r--r-- | src/core/dwm.h | 176 | ||||
| -rw-r--r-- | src/drw/drw.c | 744 | ||||
| -rw-r--r-- | src/drw/drw.h | 28 | ||||
| -rw-r--r-- | src/transient/transient.c | 75 | ||||
| -rw-r--r-- | src/util/util.c | 39 |
9 files changed, 2905 insertions, 2720 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b838e4d --- /dev/null +++ b/.clang-format | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | BasedOnStyle: LLVM | ||
| 2 | IndentWidth: 8 | ||
| 3 | UseTab: ForIndentation | ||
| 4 | BreakBeforeBraces: Linux | ||
| 5 | AllowShortIfStatementsOnASingleLine: false | ||
| 6 | ColumnLimit: 80 | ||
diff --git a/src/config/config.def.h b/src/config/config.def.h index 55fb083..3135869 100644 --- a/src/config/config.def.h +++ b/src/config/config.def.h | |||
| @@ -65,10 +65,13 @@ static const Layout layouts[] = { | |||
| 65 | /* key definitions */ | 65 | /* key definitions */ |
| 66 | #define MODKEY Mod4Mask | 66 | #define MODKEY Mod4Mask |
| 67 | #define TAGKEYS(KEY, TAG) \ | 67 | #define TAGKEYS(KEY, TAG) \ |
| 68 | {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ | 68 | {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ |
| 69 | {MODKEY | ControlMask, KEY, toggleview, {.ui = 1 << TAG}}, \ | 69 | {MODKEY | ControlMask, KEY, toggleview, {.ui = 1 << TAG}}, \ |
| 70 | {MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ | 70 | {MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ |
| 71 | {MODKEY | ControlMask | ShiftMask, KEY, toggletag, {.ui = 1 << TAG}}, | 71 | {MODKEY | ControlMask | ShiftMask, \ |
| 72 | KEY, \ | ||
| 73 | toggletag, \ | ||
| 74 | {.ui = 1 << TAG}}, | ||
| 72 | 75 | ||
| 73 | /* commands */ | 76 | /* commands */ |
| 74 | static char dmenumon[2] = "0"; | 77 | static char dmenumon[2] = "0"; |
diff --git a/src/config/config.h b/src/config/config.h index 55fb083..3135869 100644 --- a/src/config/config.h +++ b/src/config/config.h | |||
| @@ -65,10 +65,13 @@ static const Layout layouts[] = { | |||
| 65 | /* key definitions */ | 65 | /* key definitions */ |
| 66 | #define MODKEY Mod4Mask | 66 | #define MODKEY Mod4Mask |
| 67 | #define TAGKEYS(KEY, TAG) \ | 67 | #define TAGKEYS(KEY, TAG) \ |
| 68 | {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ | 68 | {MODKEY, KEY, view, {.ui = 1 << TAG}}, \ |
| 69 | {MODKEY | ControlMask, KEY, toggleview, {.ui = 1 << TAG}}, \ | 69 | {MODKEY | ControlMask, KEY, toggleview, {.ui = 1 << TAG}}, \ |
| 70 | {MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ | 70 | {MODKEY | ShiftMask, KEY, tag, {.ui = 1 << TAG}}, \ |
| 71 | {MODKEY | ControlMask | ShiftMask, KEY, toggletag, {.ui = 1 << TAG}}, | 71 | {MODKEY | ControlMask | ShiftMask, \ |
| 72 | KEY, \ | ||
| 73 | toggletag, \ | ||
| 74 | {.ui = 1 << TAG}}, | ||
| 72 | 75 | ||
| 73 | /* commands */ | 76 | /* commands */ |
| 74 | static char dmenumon[2] = "0"; | 77 | static char dmenumon[2] = "0"; |
diff --git a/src/core/dwm.c b/src/core/dwm.c index d3782cb..e16bc2f 100644 --- a/src/core/dwm.c +++ b/src/core/dwm.c | |||
| @@ -56,12 +56,12 @@ | |||
| 56 | /* macros */ | 56 | /* macros */ |
| 57 | #define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) | 57 | #define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) |
| 58 | #define CLEANMASK(mask) \ | 58 | #define CLEANMASK(mask) \ |
| 59 | (mask & ~(numlockmask | LockMask) & \ | 59 | (mask & ~(numlockmask | LockMask) & \ |
| 60 | (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | \ | 60 | (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | \ |
| 61 | Mod5Mask)) | 61 | Mod4Mask | Mod5Mask)) |
| 62 | #define INTERSECT(x, y, w, h, m) \ | 62 | #define INTERSECT(x, y, w, h, m) \ |
| 63 | (MAX(0, MIN((x) + (w), (m)->wx + (m)->ww) - MAX((x), (m)->wx)) * \ | 63 | (MAX(0, MIN((x) + (w), (m)->wx + (m)->ww) - MAX((x), (m)->wx)) * \ |
| 64 | MAX(0, MIN((y) + (h), (m)->wy + (m)->wh) - MAX((y), (m)->wy))) | 64 | MAX(0, MIN((y) + (h), (m)->wy + (m)->wh) - MAX((y), (m)->wy))) |
| 65 | #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) | 65 | #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
| 66 | #define LENGTH(X) (sizeof X / sizeof X[0]) | 66 | #define LENGTH(X) (sizeof X / sizeof X[0]) |
| 67 | #define MOUSEMASK (BUTTONMASK | PointerMotionMask) | 67 | #define MOUSEMASK (BUTTONMASK | PointerMotionMask) |
| @@ -88,514 +88,551 @@ | |||
| 88 | 88 | ||
| 89 | /* compile-time check if all tags fit into an unsigned int bit array. */ | 89 | /* compile-time check if all tags fit into an unsigned int bit array. */ |
| 90 | struct NumTags { | 90 | struct NumTags { |
| 91 | char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; | 91 | char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | /* function implementations */ | 94 | /* function implementations */ |
| 95 | void applyrules(Client *c) { | 95 | void applyrules(Client *c) |
| 96 | const char *class, *instance; | 96 | { |
| 97 | unsigned int i; | 97 | const char *class, *instance; |
| 98 | const Rule *r; | 98 | unsigned int i; |
| 99 | Monitor *m; | 99 | const Rule *r; |
| 100 | XClassHint ch = {NULL, NULL}; | 100 | Monitor *m; |
| 101 | 101 | XClassHint ch = {NULL, NULL}; | |
| 102 | /* rule matching */ | 102 | |
| 103 | c->isfloating = 0; | 103 | /* rule matching */ |
| 104 | c->tags = 0; | 104 | c->isfloating = 0; |
| 105 | XGetClassHint(dpy, c->win, &ch); | 105 | c->tags = 0; |
| 106 | class = ch.res_class ? ch.res_class : broken; | 106 | XGetClassHint(dpy, c->win, &ch); |
| 107 | instance = ch.res_name ? ch.res_name : broken; | 107 | class = ch.res_class ? ch.res_class : broken; |
| 108 | 108 | instance = ch.res_name ? ch.res_name : broken; | |
| 109 | for (i = 0; i < LENGTH(rules); i++) { | 109 | |
| 110 | r = &rules[i]; | 110 | for (i = 0; i < LENGTH(rules); i++) { |
| 111 | if ((!r->title || strstr(c->name, r->title)) && | 111 | r = &rules[i]; |
| 112 | (!r->class || strstr(class, r->class)) && | 112 | if ((!r->title || strstr(c->name, r->title)) && |
| 113 | (!r->instance || strstr(instance, r->instance))) { | 113 | (!r->class || strstr(class, r->class)) && |
| 114 | c->isterminal = r->isterminal; | 114 | (!r->instance || strstr(instance, r->instance))) { |
| 115 | c->noswallow = r->noswallow; | 115 | c->isterminal = r->isterminal; |
| 116 | c->isfloating = r->isfloating; | 116 | c->noswallow = r->noswallow; |
| 117 | c->tags |= r->tags; | 117 | c->isfloating = r->isfloating; |
| 118 | for (m = mons; m && m->num != r->monitor; m = m->next) | 118 | c->tags |= r->tags; |
| 119 | ; | 119 | for (m = mons; m && m->num != r->monitor; m = m->next) |
| 120 | if (m) | 120 | ; |
| 121 | c->mon = m; | 121 | if (m) |
| 122 | } | 122 | c->mon = m; |
| 123 | } | 123 | } |
| 124 | if (ch.res_class) | 124 | } |
| 125 | XFree(ch.res_class); | 125 | if (ch.res_class) |
| 126 | if (ch.res_name) | 126 | XFree(ch.res_class); |
| 127 | XFree(ch.res_name); | 127 | if (ch.res_name) |
| 128 | c->tags = | 128 | XFree(ch.res_name); |
| 129 | c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; | 129 | c->tags = c->tags & TAGMASK ? c->tags & TAGMASK |
| 130 | } | 130 | : c->mon->tagset[c->mon->seltags]; |
| 131 | 131 | } | |
| 132 | int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) { | 132 | |
| 133 | int baseismin; | 133 | int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) |
| 134 | Monitor *m = c->mon; | 134 | { |
| 135 | 135 | int baseismin; | |
| 136 | /* set minimum possible */ | 136 | Monitor *m = c->mon; |
| 137 | *w = MAX(1, *w); | 137 | |
| 138 | *h = MAX(1, *h); | 138 | /* set minimum possible */ |
| 139 | if (interact) { | 139 | *w = MAX(1, *w); |
| 140 | if (*x > sw) | 140 | *h = MAX(1, *h); |
| 141 | *x = sw - WIDTH(c); | 141 | if (interact) { |
| 142 | if (*y > sh) | 142 | if (*x > sw) |
| 143 | *y = sh - HEIGHT(c); | 143 | *x = sw - WIDTH(c); |
| 144 | if (*x + *w + 2 * c->bw < 0) | 144 | if (*y > sh) |
| 145 | *x = 0; | 145 | *y = sh - HEIGHT(c); |
| 146 | if (*y + *h + 2 * c->bw < 0) | 146 | if (*x + *w + 2 * c->bw < 0) |
| 147 | *y = 0; | 147 | *x = 0; |
| 148 | } else { | 148 | if (*y + *h + 2 * c->bw < 0) |
| 149 | if (*x >= m->wx + m->ww) | 149 | *y = 0; |
| 150 | *x = m->wx + m->ww - WIDTH(c); | 150 | } else { |
| 151 | if (*y >= m->wy + m->wh) | 151 | if (*x >= m->wx + m->ww) |
| 152 | *y = m->wy + m->wh - HEIGHT(c); | 152 | *x = m->wx + m->ww - WIDTH(c); |
| 153 | if (*x + *w + 2 * c->bw <= m->wx) | 153 | if (*y >= m->wy + m->wh) |
| 154 | *x = m->wx; | 154 | *y = m->wy + m->wh - HEIGHT(c); |
| 155 | if (*y + *h + 2 * c->bw <= m->wy) | 155 | if (*x + *w + 2 * c->bw <= m->wx) |
| 156 | *y = m->wy; | 156 | *x = m->wx; |
| 157 | } | 157 | if (*y + *h + 2 * c->bw <= m->wy) |
| 158 | if (*h < bh) | 158 | *y = m->wy; |
| 159 | *h = bh; | 159 | } |
| 160 | if (*w < bh) | 160 | if (*h < bh) |
| 161 | *w = bh; | 161 | *h = bh; |
| 162 | if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { | 162 | if (*w < bh) |
| 163 | if (!c->hintsvalid) | 163 | *w = bh; |
| 164 | updatesizehints(c); | 164 | if (resizehints || c->isfloating || |
| 165 | /* see last two sentences in ICCCM 4.1.2.3 */ | 165 | !c->mon->lt[c->mon->sellt]->arrange) { |
| 166 | baseismin = c->basew == c->minw && c->baseh == c->minh; | 166 | if (!c->hintsvalid) |
| 167 | if (!baseismin) { /* temporarily remove base dimensions */ | 167 | updatesizehints(c); |
| 168 | *w -= c->basew; | 168 | /* see last two sentences in ICCCM 4.1.2.3 */ |
| 169 | *h -= c->baseh; | 169 | baseismin = c->basew == c->minw && c->baseh == c->minh; |
| 170 | } | 170 | if (!baseismin) { /* temporarily remove base dimensions */ |
| 171 | /* adjust for aspect limits */ | 171 | *w -= c->basew; |
| 172 | if (c->mina > 0 && c->maxa > 0) { | 172 | *h -= c->baseh; |
| 173 | if (c->maxa < (float)*w / *h) | 173 | } |
| 174 | *w = *h * c->maxa + 0.5; | 174 | /* adjust for aspect limits */ |
| 175 | else if (c->mina < (float)*h / *w) | 175 | if (c->mina > 0 && c->maxa > 0) { |
| 176 | *h = *w * c->mina + 0.5; | 176 | if (c->maxa < (float)*w / *h) |
| 177 | } | 177 | *w = *h * c->maxa + 0.5; |
| 178 | if (baseismin) { /* increment calculation requires this */ | 178 | else if (c->mina < (float)*h / *w) |
| 179 | *w -= c->basew; | 179 | *h = *w * c->mina + 0.5; |
| 180 | *h -= c->baseh; | 180 | } |
| 181 | } | 181 | if (baseismin) { /* increment calculation requires this */ |
| 182 | /* adjust for increment value */ | 182 | *w -= c->basew; |
| 183 | if (c->incw) | 183 | *h -= c->baseh; |
| 184 | *w -= *w % c->incw; | 184 | } |
| 185 | if (c->inch) | 185 | /* adjust for increment value */ |
| 186 | *h -= *h % c->inch; | 186 | if (c->incw) |
| 187 | /* restore base dimensions */ | 187 | *w -= *w % c->incw; |
| 188 | *w = MAX(*w + c->basew, c->minw); | 188 | if (c->inch) |
| 189 | *h = MAX(*h + c->baseh, c->minh); | 189 | *h -= *h % c->inch; |
| 190 | if (c->maxw) | 190 | /* restore base dimensions */ |
| 191 | *w = MIN(*w, c->maxw); | 191 | *w = MAX(*w + c->basew, c->minw); |
| 192 | if (c->maxh) | 192 | *h = MAX(*h + c->baseh, c->minh); |
| 193 | *h = MIN(*h, c->maxh); | 193 | if (c->maxw) |
| 194 | } | 194 | *w = MIN(*w, c->maxw); |
| 195 | return *x != c->x || *y != c->y || *w != c->w || *h != c->h; | 195 | if (c->maxh) |
| 196 | } | 196 | *h = MIN(*h, c->maxh); |
| 197 | 197 | } | |
| 198 | void arrange(Monitor *m) { | 198 | return *x != c->x || *y != c->y || *w != c->w || *h != c->h; |
| 199 | if (m) | 199 | } |
| 200 | showhide(m->stack); | 200 | |
| 201 | else | 201 | void arrange(Monitor *m) |
| 202 | for (m = mons; m; m = m->next) | 202 | { |
| 203 | showhide(m->stack); | 203 | if (m) |
| 204 | if (m) { | 204 | showhide(m->stack); |
| 205 | arrangemon(m); | 205 | else |
| 206 | restack(m); | 206 | for (m = mons; m; m = m->next) |
| 207 | } else | 207 | showhide(m->stack); |
| 208 | for (m = mons; m; m = m->next) | 208 | if (m) { |
| 209 | arrangemon(m); | 209 | arrangemon(m); |
| 210 | } | 210 | restack(m); |
| 211 | 211 | } else | |
| 212 | void arrangemon(Monitor *m) { | 212 | for (m = mons; m; m = m->next) |
| 213 | strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); | 213 | arrangemon(m); |
| 214 | if (m->lt[m->sellt]->arrange) | 214 | } |
| 215 | m->lt[m->sellt]->arrange(m); | 215 | |
| 216 | } | 216 | void arrangemon(Monitor *m) |
| 217 | 217 | { | |
| 218 | void attach(Client *c) { | 218 | strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); |
| 219 | c->next = c->mon->clients; | 219 | if (m->lt[m->sellt]->arrange) |
| 220 | c->mon->clients = c; | 220 | m->lt[m->sellt]->arrange(m); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | void attachstack(Client *c) { | 223 | void attach(Client *c) |
| 224 | c->snext = c->mon->stack; | 224 | { |
| 225 | c->mon->stack = c; | 225 | c->next = c->mon->clients; |
| 226 | } | 226 | c->mon->clients = c; |
| 227 | 227 | } | |
| 228 | void swallow(Client *p, Client *c) { | 228 | |
| 229 | 229 | void attachstack(Client *c) | |
| 230 | if (c->noswallow || c->isterminal) | 230 | { |
| 231 | return; | 231 | c->snext = c->mon->stack; |
| 232 | if (c->noswallow && !swallowfloating && c->isfloating) | 232 | c->mon->stack = c; |
| 233 | return; | 233 | } |
| 234 | 234 | ||
| 235 | detach(c); | 235 | void swallow(Client *p, Client *c) |
| 236 | detachstack(c); | 236 | { |
| 237 | 237 | ||
| 238 | setclientstate(c, WithdrawnState); | 238 | if (c->noswallow || c->isterminal) |
| 239 | XUnmapWindow(dpy, p->win); | 239 | return; |
| 240 | 240 | if (c->noswallow && !swallowfloating && c->isfloating) | |
| 241 | p->swallowing = c; | 241 | return; |
| 242 | c->mon = p->mon; | 242 | |
| 243 | 243 | detach(c); | |
| 244 | Window w = p->win; | 244 | detachstack(c); |
| 245 | p->win = c->win; | 245 | |
| 246 | c->win = w; | 246 | setclientstate(c, WithdrawnState); |
| 247 | updatetitle(p); | 247 | XUnmapWindow(dpy, p->win); |
| 248 | XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); | 248 | |
| 249 | arrange(p->mon); | 249 | p->swallowing = c; |
| 250 | configure(p); | 250 | c->mon = p->mon; |
| 251 | updateclientlist(); | 251 | |
| 252 | } | 252 | Window w = p->win; |
| 253 | 253 | p->win = c->win; | |
| 254 | void unswallow(Client *c) { | 254 | c->win = w; |
| 255 | c->win = c->swallowing->win; | 255 | updatetitle(p); |
| 256 | 256 | XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); | |
| 257 | free(c->swallowing); | 257 | arrange(p->mon); |
| 258 | c->swallowing = NULL; | 258 | configure(p); |
| 259 | 259 | updateclientlist(); | |
| 260 | /* unfullscreen the client */ | 260 | } |
| 261 | setfullscreen(c, 0); | 261 | |
| 262 | updatetitle(c); | 262 | void unswallow(Client *c) |
| 263 | arrange(c->mon); | 263 | { |
| 264 | XMapWindow(dpy, c->win); | 264 | c->win = c->swallowing->win; |
| 265 | XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); | 265 | |
| 266 | setclientstate(c, NormalState); | 266 | free(c->swallowing); |
| 267 | focus(NULL); | 267 | c->swallowing = NULL; |
| 268 | arrange(c->mon); | 268 | |
| 269 | } | 269 | /* unfullscreen the client */ |
| 270 | 270 | setfullscreen(c, 0); | |
| 271 | void buttonpress(XEvent *e) { | 271 | updatetitle(c); |
| 272 | unsigned int i, x, click; | 272 | arrange(c->mon); |
| 273 | Arg arg = {0}; | 273 | XMapWindow(dpy, c->win); |
| 274 | Client *c; | 274 | XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
| 275 | Monitor *m; | 275 | setclientstate(c, NormalState); |
| 276 | XButtonPressedEvent *ev = &e->xbutton; | 276 | focus(NULL); |
| 277 | 277 | arrange(c->mon); | |
| 278 | click = ClkRootWin; | 278 | } |
| 279 | /* focus monitor if necessary */ | 279 | |
| 280 | if ((m = wintomon(ev->window)) && m != selmon) { | 280 | void buttonpress(XEvent *e) |
| 281 | unfocus(selmon->sel, 1); | 281 | { |
| 282 | selmon = m; | 282 | unsigned int i, x, click; |
| 283 | focus(NULL); | 283 | Arg arg = {0}; |
| 284 | } | 284 | Client *c; |
| 285 | if (ev->window == selmon->barwin) { | 285 | Monitor *m; |
| 286 | i = x = 0; | 286 | XButtonPressedEvent *ev = &e->xbutton; |
| 287 | unsigned int occ = 0; | 287 | |
| 288 | for (c = m->clients; c; c = c->next) | 288 | click = ClkRootWin; |
| 289 | occ |= c->tags; | 289 | /* focus monitor if necessary */ |
| 290 | do { | 290 | if ((m = wintomon(ev->window)) && m != selmon) { |
| 291 | /* Do not reserve space for vacant tags */ | 291 | unfocus(selmon->sel, 1); |
| 292 | if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) | 292 | selmon = m; |
| 293 | continue; | 293 | focus(NULL); |
| 294 | x += TEXTW(tags[i]); | 294 | } |
| 295 | } while (ev->x >= x && ++i < LENGTH(tags)); | 295 | if (ev->window == selmon->barwin) { |
| 296 | if (i < LENGTH(tags)) { | 296 | i = x = 0; |
| 297 | click = ClkTagBar; | 297 | unsigned int occ = 0; |
| 298 | arg.ui = 1 << i; | 298 | for (c = m->clients; c; c = c->next) |
| 299 | } else if (ev->x < x + TEXTW(selmon->ltsymbol)) | 299 | occ |= c->tags; |
| 300 | click = ClkLtSymbol; | 300 | do { |
| 301 | else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) | 301 | /* Do not reserve space for vacant tags */ |
| 302 | click = ClkStatusText; | 302 | if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) |
| 303 | else | 303 | continue; |
| 304 | click = ClkWinTitle; | 304 | x += TEXTW(tags[i]); |
| 305 | } else if ((c = wintoclient(ev->window))) { | 305 | } while (ev->x >= x && ++i < LENGTH(tags)); |
| 306 | focus(c); | 306 | if (i < LENGTH(tags)) { |
| 307 | restack(selmon); | 307 | click = ClkTagBar; |
| 308 | XAllowEvents(dpy, ReplayPointer, CurrentTime); | 308 | arg.ui = 1 << i; |
| 309 | click = ClkClientWin; | 309 | } else if (ev->x < x + TEXTW(selmon->ltsymbol)) |
| 310 | } | 310 | click = ClkLtSymbol; |
| 311 | for (i = 0; i < LENGTH(buttons); i++) | 311 | else if (ev->x > |
| 312 | if (click == buttons[i].click && buttons[i].func && | 312 | selmon->ww - (int)TEXTW(stext) - getsystraywidth()) |
| 313 | buttons[i].button == ev->button && | 313 | click = ClkStatusText; |
| 314 | CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) | 314 | else |
| 315 | buttons[i].func( | 315 | click = ClkWinTitle; |
| 316 | click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); | 316 | } else if ((c = wintoclient(ev->window))) { |
| 317 | } | 317 | focus(c); |
| 318 | 318 | restack(selmon); | |
| 319 | void checkotherwm(void) { | 319 | XAllowEvents(dpy, ReplayPointer, CurrentTime); |
| 320 | xerrorxlib = XSetErrorHandler(xerrorstart); | 320 | click = ClkClientWin; |
| 321 | /* this causes an error if some other window manager is running */ | 321 | } |
| 322 | XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); | 322 | for (i = 0; i < LENGTH(buttons); i++) |
| 323 | XSync(dpy, False); | 323 | if (click == buttons[i].click && buttons[i].func && |
| 324 | XSetErrorHandler(xerror); | 324 | buttons[i].button == ev->button && |
| 325 | XSync(dpy, False); | 325 | CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) |
| 326 | } | 326 | buttons[i].func(click == ClkTagBar && |
| 327 | 327 | buttons[i].arg.i == 0 | |
| 328 | void cleanup(void) { | 328 | ? &arg |
| 329 | Arg a = {.ui = ~0}; | 329 | : &buttons[i].arg); |
| 330 | Layout foo = {"", NULL}; | 330 | } |
| 331 | Monitor *m; | 331 | |
| 332 | size_t i; | 332 | void checkotherwm(void) |
| 333 | 333 | { | |
| 334 | view(&a); | 334 | xerrorxlib = XSetErrorHandler(xerrorstart); |
| 335 | selmon->lt[selmon->sellt] = &foo; | 335 | /* this causes an error if some other window manager is running */ |
| 336 | for (m = mons; m; m = m->next) | 336 | XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); |
| 337 | while (m->stack) | 337 | XSync(dpy, False); |
| 338 | unmanage(m->stack, 0); | 338 | XSetErrorHandler(xerror); |
| 339 | XUngrabKey(dpy, AnyKey, AnyModifier, root); | 339 | XSync(dpy, False); |
| 340 | while (mons) | 340 | } |
| 341 | cleanupmon(mons); | 341 | |
| 342 | 342 | void cleanup(void) | |
| 343 | if (showsystray) { | 343 | { |
| 344 | XUnmapWindow(dpy, systray->win); | 344 | Arg a = {.ui = ~0}; |
| 345 | XDestroyWindow(dpy, systray->win); | 345 | Layout foo = {"", NULL}; |
| 346 | free(systray); | 346 | Monitor *m; |
| 347 | } | 347 | size_t i; |
| 348 | 348 | ||
| 349 | for (i = 0; i < CurLast; i++) | 349 | view(&a); |
| 350 | drw_cur_free(drw, cursor[i]); | 350 | selmon->lt[selmon->sellt] = &foo; |
| 351 | for (i = 0; i < LENGTH(colors); i++) | 351 | for (m = mons; m; m = m->next) |
| 352 | free(scheme[i]); | 352 | while (m->stack) |
| 353 | free(scheme); | 353 | unmanage(m->stack, 0); |
| 354 | XDestroyWindow(dpy, wmcheckwin); | 354 | XUngrabKey(dpy, AnyKey, AnyModifier, root); |
| 355 | drw_free(drw); | 355 | while (mons) |
| 356 | XSync(dpy, False); | 356 | cleanupmon(mons); |
| 357 | XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); | 357 | |
| 358 | XDeleteProperty(dpy, root, netatom[NetActiveWindow]); | 358 | if (showsystray) { |
| 359 | } | 359 | XUnmapWindow(dpy, systray->win); |
| 360 | 360 | XDestroyWindow(dpy, systray->win); | |
| 361 | void cleanupmon(Monitor *mon) { | 361 | free(systray); |
| 362 | Monitor *m; | 362 | } |
| 363 | 363 | ||
| 364 | if (mon == mons) | 364 | for (i = 0; i < CurLast; i++) |
| 365 | mons = mons->next; | 365 | drw_cur_free(drw, cursor[i]); |
| 366 | else { | 366 | for (i = 0; i < LENGTH(colors); i++) |
| 367 | for (m = mons; m && m->next != mon; m = m->next) | 367 | free(scheme[i]); |
| 368 | ; | 368 | free(scheme); |
| 369 | m->next = mon->next; | 369 | XDestroyWindow(dpy, wmcheckwin); |
| 370 | } | 370 | drw_free(drw); |
| 371 | XUnmapWindow(dpy, mon->barwin); | 371 | XSync(dpy, False); |
| 372 | XDestroyWindow(dpy, mon->barwin); | 372 | XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
| 373 | free(mon); | 373 | XDeleteProperty(dpy, root, netatom[NetActiveWindow]); |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | void clientmessage(XEvent *e) { | 376 | void cleanupmon(Monitor *mon) |
| 377 | XWindowAttributes wa; | 377 | { |
| 378 | XSetWindowAttributes swa; | 378 | Monitor *m; |
| 379 | XClientMessageEvent *cme = &e->xclient; | 379 | |
| 380 | Client *c = wintoclient(cme->window); | 380 | if (mon == mons) |
| 381 | 381 | mons = mons->next; | |
| 382 | if (showsystray && cme->window == systray->win && | 382 | else { |
| 383 | cme->message_type == netatom[NetSystemTrayOP]) { | 383 | for (m = mons; m && m->next != mon; m = m->next) |
| 384 | /* add systray icons */ | 384 | ; |
| 385 | if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { | 385 | m->next = mon->next; |
| 386 | if (!(c = (Client *)calloc(1, sizeof(Client)))) | 386 | } |
| 387 | die("fatal: could not malloc() %u bytes\n", sizeof(Client)); | 387 | XUnmapWindow(dpy, mon->barwin); |
| 388 | if (!(c->win = cme->data.l[2])) { | 388 | XDestroyWindow(dpy, mon->barwin); |
| 389 | free(c); | 389 | free(mon); |
| 390 | return; | 390 | } |
| 391 | } | 391 | |
| 392 | c->mon = selmon; | 392 | void clientmessage(XEvent *e) |
| 393 | c->next = systray->icons; | 393 | { |
| 394 | systray->icons = c; | 394 | XWindowAttributes wa; |
| 395 | if (!XGetWindowAttributes(dpy, c->win, &wa)) { | 395 | XSetWindowAttributes swa; |
| 396 | /* use sane defaults */ | 396 | XClientMessageEvent *cme = &e->xclient; |
| 397 | wa.width = bh; | 397 | Client *c = wintoclient(cme->window); |
| 398 | wa.height = bh; | 398 | |
| 399 | wa.border_width = 0; | 399 | if (showsystray && cme->window == systray->win && |
| 400 | } | 400 | cme->message_type == netatom[NetSystemTrayOP]) { |
| 401 | c->x = c->oldx = c->y = c->oldy = 0; | 401 | /* add systray icons */ |
| 402 | c->w = c->oldw = wa.width; | 402 | if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { |
| 403 | c->h = c->oldh = wa.height; | 403 | if (!(c = (Client *)calloc(1, sizeof(Client)))) |
| 404 | c->oldbw = wa.border_width; | 404 | die("fatal: could not malloc() %u bytes\n", |
| 405 | c->bw = 0; | 405 | sizeof(Client)); |
| 406 | c->isfloating = True; | 406 | if (!(c->win = cme->data.l[2])) { |
| 407 | /* reuse tags field as mapped status */ | 407 | free(c); |
| 408 | c->tags = 1; | 408 | return; |
| 409 | updatesizehints(c); | 409 | } |
| 410 | updatesystrayicongeom(c, wa.width, wa.height); | 410 | c->mon = selmon; |
| 411 | XAddToSaveSet(dpy, c->win); | 411 | c->next = systray->icons; |
| 412 | XSelectInput(dpy, c->win, | 412 | systray->icons = c; |
| 413 | StructureNotifyMask | PropertyChangeMask | | 413 | if (!XGetWindowAttributes(dpy, c->win, &wa)) { |
| 414 | ResizeRedirectMask); | 414 | /* use sane defaults */ |
| 415 | XReparentWindow(dpy, c->win, systray->win, 0, 0); | 415 | wa.width = bh; |
| 416 | /* use parents background color */ | 416 | wa.height = bh; |
| 417 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; | 417 | wa.border_width = 0; |
| 418 | XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); | 418 | } |
| 419 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, | 419 | c->x = c->oldx = c->y = c->oldy = 0; |
| 420 | XEMBED_EMBEDDED_NOTIFY, 0, systray->win, | 420 | c->w = c->oldw = wa.width; |
| 421 | XEMBED_EMBEDDED_VERSION); | 421 | c->h = c->oldh = wa.height; |
| 422 | /* FIXME not sure if I have to send these events, too */ | 422 | c->oldbw = wa.border_width; |
| 423 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, | 423 | c->bw = 0; |
| 424 | XEMBED_FOCUS_IN, 0, systray->win, XEMBED_EMBEDDED_VERSION); | 424 | c->isfloating = True; |
| 425 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, | 425 | /* reuse tags field as mapped status */ |
| 426 | XEMBED_WINDOW_ACTIVATE, 0, systray->win, | 426 | c->tags = 1; |
| 427 | XEMBED_EMBEDDED_VERSION); | 427 | updatesizehints(c); |
| 428 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, | 428 | updatesystrayicongeom(c, wa.width, wa.height); |
| 429 | XEMBED_MODALITY_ON, 0, systray->win, XEMBED_EMBEDDED_VERSION); | 429 | XAddToSaveSet(dpy, c->win); |
| 430 | XSync(dpy, False); | 430 | XSelectInput(dpy, c->win, |
| 431 | resizebarwin(selmon); | 431 | StructureNotifyMask | PropertyChangeMask | |
| 432 | updatesystray(); | 432 | ResizeRedirectMask); |
| 433 | setclientstate(c, NormalState); | 433 | XReparentWindow(dpy, c->win, systray->win, 0, 0); |
| 434 | } | 434 | /* use parents background color */ |
| 435 | return; | 435 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
| 436 | } | 436 | XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); |
| 437 | 437 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, | |
| 438 | if (!c) | 438 | CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, |
| 439 | return; | 439 | systray->win, XEMBED_EMBEDDED_VERSION); |
| 440 | if (cme->message_type == netatom[NetWMState]) { | 440 | /* FIXME not sure if I have to send these events, too */ |
| 441 | if (cme->data.l[1] == netatom[NetWMFullscreen] || | 441 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, |
| 442 | cme->data.l[2] == netatom[NetWMFullscreen]) | 442 | CurrentTime, XEMBED_FOCUS_IN, 0, systray->win, |
| 443 | setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ | 443 | XEMBED_EMBEDDED_VERSION); |
| 444 | || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ | 444 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, |
| 445 | && !c->isfullscreen))); | 445 | CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, |
| 446 | } else if (cme->message_type == netatom[NetActiveWindow]) { | 446 | systray->win, XEMBED_EMBEDDED_VERSION); |
| 447 | if (c != selmon->sel && !c->isurgent) | 447 | sendevent(c->win, netatom[Xembed], StructureNotifyMask, |
| 448 | seturgent(c, 1); | 448 | CurrentTime, XEMBED_MODALITY_ON, 0, |
| 449 | } | 449 | systray->win, XEMBED_EMBEDDED_VERSION); |
| 450 | } | 450 | XSync(dpy, False); |
| 451 | 451 | resizebarwin(selmon); | |
| 452 | void configure(Client *c) { | 452 | updatesystray(); |
| 453 | XConfigureEvent ce; | 453 | setclientstate(c, NormalState); |
| 454 | 454 | } | |
| 455 | ce.type = ConfigureNotify; | 455 | return; |
| 456 | ce.display = dpy; | 456 | } |
| 457 | ce.event = c->win; | 457 | |
| 458 | ce.window = c->win; | 458 | if (!c) |
| 459 | ce.x = c->x; | 459 | return; |
| 460 | ce.y = c->y; | 460 | if (cme->message_type == netatom[NetWMState]) { |
| 461 | ce.width = c->w; | 461 | if (cme->data.l[1] == netatom[NetWMFullscreen] || |
| 462 | ce.height = c->h; | 462 | cme->data.l[2] == netatom[NetWMFullscreen]) |
| 463 | ce.border_width = c->bw; | 463 | setfullscreen( |
| 464 | ce.above = None; | 464 | c, |
| 465 | ce.override_redirect = False; | 465 | (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ |
| 466 | XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); | 466 | || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ |
| 467 | } | 467 | && !c->isfullscreen))); |
| 468 | 468 | } else if (cme->message_type == netatom[NetActiveWindow]) { | |
| 469 | void configurenotify(XEvent *e) { | 469 | if (c != selmon->sel && !c->isurgent) |
| 470 | Monitor *m; | 470 | seturgent(c, 1); |
| 471 | Client *c; | 471 | } |
| 472 | XConfigureEvent *ev = &e->xconfigure; | 472 | } |
| 473 | int dirty; | 473 | |
| 474 | 474 | void configure(Client *c) | |
| 475 | /* TODO: updategeom handling sucks, needs to be simplified */ | 475 | { |
| 476 | if (ev->window == root) { | 476 | XConfigureEvent ce; |
| 477 | dirty = (sw != ev->width || sh != ev->height); | 477 | |
| 478 | sw = ev->width; | 478 | ce.type = ConfigureNotify; |
| 479 | sh = ev->height; | 479 | ce.display = dpy; |
| 480 | if (updategeom() || dirty) { | 480 | ce.event = c->win; |
| 481 | drw_resize(drw, sw, bh); | 481 | ce.window = c->win; |
| 482 | updatebars(); | 482 | ce.x = c->x; |
| 483 | for (m = mons; m; m = m->next) { | 483 | ce.y = c->y; |
| 484 | for (c = m->clients; c; c = c->next) | 484 | ce.width = c->w; |
| 485 | if (c->isfullscreen) | 485 | ce.height = c->h; |
| 486 | resizeclient(c, m->mx, m->my, m->mw, m->mh); | 486 | ce.border_width = c->bw; |
| 487 | resizebarwin(m); | 487 | ce.above = None; |
| 488 | } | 488 | ce.override_redirect = False; |
| 489 | focus(NULL); | 489 | XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); |
| 490 | arrange(NULL); | 490 | } |
| 491 | } | 491 | |
| 492 | } | 492 | void configurenotify(XEvent *e) |
| 493 | } | 493 | { |
| 494 | 494 | Monitor *m; | |
| 495 | void configurerequest(XEvent *e) { | 495 | Client *c; |
| 496 | Client *c; | 496 | XConfigureEvent *ev = &e->xconfigure; |
| 497 | Monitor *m; | 497 | int dirty; |
| 498 | XConfigureRequestEvent *ev = &e->xconfigurerequest; | 498 | |
| 499 | XWindowChanges wc; | 499 | /* TODO: updategeom handling sucks, needs to be simplified */ |
| 500 | 500 | if (ev->window == root) { | |
| 501 | if ((c = wintoclient(ev->window))) { | 501 | dirty = (sw != ev->width || sh != ev->height); |
| 502 | if (ev->value_mask & CWBorderWidth) | 502 | sw = ev->width; |
| 503 | c->bw = ev->border_width; | 503 | sh = ev->height; |
| 504 | else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { | 504 | if (updategeom() || dirty) { |
| 505 | m = c->mon; | 505 | drw_resize(drw, sw, bh); |
| 506 | if (ev->value_mask & CWX) { | 506 | updatebars(); |
| 507 | c->oldx = c->x; | 507 | for (m = mons; m; m = m->next) { |
| 508 | c->x = m->mx + ev->x; | 508 | for (c = m->clients; c; c = c->next) |
| 509 | } | 509 | if (c->isfullscreen) |
| 510 | if (ev->value_mask & CWY) { | 510 | resizeclient(c, m->mx, m->my, |
| 511 | c->oldy = c->y; | 511 | m->mw, m->mh); |
| 512 | c->y = m->my + ev->y; | 512 | resizebarwin(m); |
| 513 | } | 513 | } |
| 514 | if (ev->value_mask & CWWidth) { | 514 | focus(NULL); |
| 515 | c->oldw = c->w; | 515 | arrange(NULL); |
| 516 | c->w = ev->width; | 516 | } |
| 517 | } | 517 | } |
| 518 | if (ev->value_mask & CWHeight) { | 518 | } |
| 519 | c->oldh = c->h; | 519 | |
| 520 | c->h = ev->height; | 520 | void configurerequest(XEvent *e) |
| 521 | } | 521 | { |
| 522 | if ((c->x + c->w) > m->mx + m->mw && c->isfloating) | 522 | Client *c; |
| 523 | c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ | 523 | Monitor *m; |
| 524 | if ((c->y + c->h) > m->my + m->mh && c->isfloating) | 524 | XConfigureRequestEvent *ev = &e->xconfigurerequest; |
| 525 | c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ | 525 | XWindowChanges wc; |
| 526 | if ((ev->value_mask & (CWX | CWY)) && | 526 | |
| 527 | !(ev->value_mask & (CWWidth | CWHeight))) | 527 | if ((c = wintoclient(ev->window))) { |
| 528 | configure(c); | 528 | if (ev->value_mask & CWBorderWidth) |
| 529 | if (ISVISIBLE(c)) | 529 | c->bw = ev->border_width; |
| 530 | XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); | 530 | else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { |
| 531 | } else | 531 | m = c->mon; |
| 532 | configure(c); | 532 | if (ev->value_mask & CWX) { |
| 533 | } else { | 533 | c->oldx = c->x; |
| 534 | wc.x = ev->x; | 534 | c->x = m->mx + ev->x; |
| 535 | wc.y = ev->y; | 535 | } |
| 536 | wc.width = ev->width; | 536 | if (ev->value_mask & CWY) { |
| 537 | wc.height = ev->height; | 537 | c->oldy = c->y; |
| 538 | wc.border_width = ev->border_width; | 538 | c->y = m->my + ev->y; |
| 539 | wc.sibling = ev->above; | 539 | } |
| 540 | wc.stack_mode = ev->detail; | 540 | if (ev->value_mask & CWWidth) { |
| 541 | XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); | 541 | c->oldw = c->w; |
| 542 | } | 542 | c->w = ev->width; |
| 543 | XSync(dpy, False); | 543 | } |
| 544 | } | 544 | if (ev->value_mask & CWHeight) { |
| 545 | 545 | c->oldh = c->h; | |
| 546 | Monitor *createmon(void) { | 546 | c->h = ev->height; |
| 547 | Monitor *m; | 547 | } |
| 548 | 548 | if ((c->x + c->w) > m->mx + m->mw && c->isfloating) | |
| 549 | m = ecalloc(1, sizeof(Monitor)); | 549 | c->x = |
| 550 | m->tagset[0] = m->tagset[1] = 1; | 550 | m->mx + |
| 551 | m->mfact = mfact; | 551 | (m->mw / 2 - |
| 552 | m->nmaster = nmaster; | 552 | WIDTH(c) / 2); /* center in x direction */ |
| 553 | m->showbar = showbar; | 553 | if ((c->y + c->h) > m->my + m->mh && c->isfloating) |
| 554 | m->topbar = topbar; | 554 | c->y = |
| 555 | m->gappih = gappih; | 555 | m->my + |
| 556 | m->gappiv = gappiv; | 556 | (m->mh / 2 - |
| 557 | m->gappoh = gappoh; | 557 | HEIGHT(c) / 2); /* center in y direction */ |
| 558 | m->gappov = gappov; | 558 | if ((ev->value_mask & (CWX | CWY)) && |
| 559 | m->lt[0] = &layouts[0]; | 559 | !(ev->value_mask & (CWWidth | CWHeight))) |
| 560 | m->lt[1] = &layouts[1 % LENGTH(layouts)]; | 560 | configure(c); |
| 561 | strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); | 561 | if (ISVISIBLE(c)) |
| 562 | return m; | 562 | XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, |
| 563 | } | 563 | c->h); |
| 564 | 564 | } else | |
| 565 | void destroynotify(XEvent *e) { | 565 | configure(c); |
| 566 | Client *c; | 566 | } else { |
| 567 | XDestroyWindowEvent *ev = &e->xdestroywindow; | 567 | wc.x = ev->x; |
| 568 | 568 | wc.y = ev->y; | |
| 569 | if ((c = wintoclient(ev->window))) | 569 | wc.width = ev->width; |
| 570 | unmanage(c, 1); | 570 | wc.height = ev->height; |
| 571 | else if ((c = wintosystrayicon(ev->window))) { | 571 | wc.border_width = ev->border_width; |
| 572 | removesystrayicon(c); | 572 | wc.sibling = ev->above; |
| 573 | resizebarwin(selmon); | 573 | wc.stack_mode = ev->detail; |
| 574 | updatesystray(); | 574 | XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); |
| 575 | } else if ((c = swallowingclient(ev->window))) | 575 | } |
| 576 | unmanage(c->swallowing, 1); | 576 | XSync(dpy, False); |
| 577 | } | 577 | } |
| 578 | 578 | ||
| 579 | void detach(Client *c) { | 579 | Monitor *createmon(void) |
| 580 | Client **tc; | 580 | { |
| 581 | 581 | Monitor *m; | |
| 582 | for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next) | 582 | |
| 583 | ; | 583 | m = ecalloc(1, sizeof(Monitor)); |
| 584 | *tc = c->next; | 584 | m->tagset[0] = m->tagset[1] = 1; |
| 585 | } | 585 | m->mfact = mfact; |
| 586 | 586 | m->nmaster = nmaster; | |
| 587 | void detachstack(Client *c) { | 587 | m->showbar = showbar; |
| 588 | Client **tc, *t; | 588 | m->topbar = topbar; |
| 589 | 589 | m->gappih = gappih; | |
| 590 | for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext) | 590 | m->gappiv = gappiv; |
| 591 | ; | 591 | m->gappoh = gappoh; |
| 592 | *tc = c->snext; | 592 | m->gappov = gappov; |
| 593 | 593 | m->lt[0] = &layouts[0]; | |
| 594 | if (c == c->mon->sel) { | 594 | m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
| 595 | for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext) | 595 | strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
| 596 | ; | 596 | return m; |
| 597 | c->mon->sel = t; | 597 | } |
| 598 | } | 598 | |
| 599 | void destroynotify(XEvent *e) | ||
| 600 | { | ||
| 601 | Client *c; | ||
| 602 | XDestroyWindowEvent *ev = &e->xdestroywindow; | ||
| 603 | |||
| 604 | if ((c = wintoclient(ev->window))) | ||
| 605 | unmanage(c, 1); | ||
| 606 | else if ((c = wintosystrayicon(ev->window))) { | ||
| 607 | removesystrayicon(c); | ||
| 608 | resizebarwin(selmon); | ||
| 609 | updatesystray(); | ||
| 610 | } else if ((c = swallowingclient(ev->window))) | ||
| 611 | unmanage(c->swallowing, 1); | ||
| 612 | } | ||
| 613 | |||
| 614 | void detach(Client *c) | ||
| 615 | { | ||
| 616 | Client **tc; | ||
| 617 | |||
| 618 | for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next) | ||
| 619 | ; | ||
| 620 | *tc = c->next; | ||
| 621 | } | ||
| 622 | |||
| 623 | void detachstack(Client *c) | ||
| 624 | { | ||
| 625 | Client **tc, *t; | ||
| 626 | |||
| 627 | for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext) | ||
| 628 | ; | ||
| 629 | *tc = c->snext; | ||
| 630 | |||
| 631 | if (c == c->mon->sel) { | ||
| 632 | for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext) | ||
| 633 | ; | ||
| 634 | c->mon->sel = t; | ||
| 635 | } | ||
| 599 | } | 636 | } |
| 600 | 637 | ||
| 601 | // Monitor *dirtomon(int dir) { | 638 | // Monitor *dirtomon(int dir) { |
| @@ -613,131 +650,143 @@ void detachstack(Client *c) { | |||
| 613 | // return m; | 650 | // return m; |
| 614 | // } | 651 | // } |
| 615 | 652 | ||
| 616 | void drawbar(Monitor *m) { | 653 | void drawbar(Monitor *m) |
| 617 | int x, w, tw = 0, stw = 0; | 654 | { |
| 618 | int boxs = drw->fonts->h / 9; | 655 | int x, w, tw = 0, stw = 0; |
| 619 | int boxw = drw->fonts->h / 6 + 2; | 656 | int boxs = drw->fonts->h / 9; |
| 620 | unsigned int i, occ = 0, urg = 0; | 657 | int boxw = drw->fonts->h / 6 + 2; |
| 621 | Client *c; | 658 | unsigned int i, occ = 0, urg = 0; |
| 622 | 659 | Client *c; | |
| 623 | if (!m->showbar) | 660 | |
| 624 | return; | 661 | if (!m->showbar) |
| 625 | 662 | return; | |
| 626 | if (showsystray && m == systraytomon(m) && !systrayonleft) | 663 | |
| 627 | stw = getsystraywidth(); | 664 | if (showsystray && m == systraytomon(m) && !systrayonleft) |
| 628 | 665 | stw = getsystraywidth(); | |
| 629 | /* draw status first so it can be overdrawn by tags later */ | 666 | |
| 630 | if (m == selmon) { /* status is only drawn on selected monitor */ | 667 | /* draw status first so it can be overdrawn by tags later */ |
| 631 | drw_setscheme(drw, scheme[SchemeNorm]); | 668 | if (m == selmon) { /* status is only drawn on selected monitor */ |
| 632 | tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ | 669 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 633 | drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); | 670 | tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ |
| 634 | } | 671 | drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, |
| 635 | 672 | 0); | |
| 636 | resizebarwin(m); | 673 | } |
| 637 | for (c = m->clients; c; c = c->next) { | 674 | |
| 638 | occ |= c->tags; | 675 | resizebarwin(m); |
| 639 | if (c->isurgent) | 676 | for (c = m->clients; c; c = c->next) { |
| 640 | urg |= c->tags; | 677 | occ |= c->tags; |
| 641 | } | 678 | if (c->isurgent) |
| 642 | x = 0; | 679 | urg |= c->tags; |
| 643 | for (i = 0; i < LENGTH(tags); i++) { | 680 | } |
| 644 | /* Do not draw vacant tags */ | 681 | x = 0; |
| 645 | if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) | 682 | for (i = 0; i < LENGTH(tags); i++) { |
| 646 | continue; | 683 | /* Do not draw vacant tags */ |
| 647 | w = TEXTW(tags[i]); | 684 | if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) |
| 648 | drw_setscheme( | 685 | continue; |
| 649 | drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); | 686 | w = TEXTW(tags[i]); |
| 650 | drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); | 687 | drw_setscheme( |
| 651 | if (occ & 1 << i) | 688 | drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel |
| 652 | drw_rect(drw, x + boxs, boxs, boxw, boxw, | 689 | : SchemeNorm]); |
| 653 | m == selmon && selmon->sel && selmon->sel->tags & 1 << i, | 690 | drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); |
| 654 | urg & 1 << i); | 691 | if (occ & 1 << i) |
| 655 | x += w; | 692 | drw_rect(drw, x + boxs, boxs, boxw, boxw, |
| 656 | } | 693 | m == selmon && selmon->sel && |
| 657 | w = TEXTW(m->ltsymbol); | 694 | selmon->sel->tags & 1 << i, |
| 658 | drw_setscheme(drw, scheme[SchemeNorm]); | 695 | urg & 1 << i); |
| 659 | x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); | 696 | x += w; |
| 660 | 697 | } | |
| 661 | if ((w = m->ww - tw - stw - x) > bh) { | 698 | w = TEXTW(m->ltsymbol); |
| 662 | if (m->sel) { | 699 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 663 | drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); | 700 | x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); |
| 664 | drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); | 701 | |
| 665 | if (m->sel->isfloating) | 702 | if ((w = m->ww - tw - stw - x) > bh) { |
| 666 | drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); | 703 | if (m->sel) { |
| 667 | } else { | 704 | drw_setscheme( |
| 668 | drw_setscheme(drw, scheme[SchemeNorm]); | 705 | drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); |
| 669 | drw_rect(drw, x, 0, w, bh, 1, 1); | 706 | drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); |
| 670 | } | 707 | if (m->sel->isfloating) |
| 671 | } | 708 | drw_rect(drw, x + boxs, boxs, boxw, boxw, |
| 672 | drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); | 709 | m->sel->isfixed, 0); |
| 673 | } | 710 | } else { |
| 674 | 711 | drw_setscheme(drw, scheme[SchemeNorm]); | |
| 675 | void drawbars(void) { | 712 | drw_rect(drw, x, 0, w, bh, 1, 1); |
| 676 | Monitor *m; | 713 | } |
| 677 | 714 | } | |
| 678 | for (m = mons; m; m = m->next) | 715 | drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); |
| 679 | drawbar(m); | 716 | } |
| 680 | } | 717 | |
| 681 | 718 | void drawbars(void) | |
| 682 | void enternotify(XEvent *e) { | 719 | { |
| 683 | Client *c; | 720 | Monitor *m; |
| 684 | Monitor *m; | 721 | |
| 685 | XCrossingEvent *ev = &e->xcrossing; | 722 | for (m = mons; m; m = m->next) |
| 686 | 723 | drawbar(m); | |
| 687 | if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && | 724 | } |
| 688 | ev->window != root) | 725 | |
| 689 | return; | 726 | void enternotify(XEvent *e) |
| 690 | c = wintoclient(ev->window); | 727 | { |
| 691 | m = c ? c->mon : wintomon(ev->window); | 728 | Client *c; |
| 692 | if (m != selmon) { | 729 | Monitor *m; |
| 693 | unfocus(selmon->sel, 1); | 730 | XCrossingEvent *ev = &e->xcrossing; |
| 694 | selmon = m; | 731 | |
| 695 | } else if (!c || c == selmon->sel) | 732 | if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && |
| 696 | return; | 733 | ev->window != root) |
| 697 | focus(c); | 734 | return; |
| 698 | } | 735 | c = wintoclient(ev->window); |
| 699 | 736 | m = c ? c->mon : wintomon(ev->window); | |
| 700 | void expose(XEvent *e) { | 737 | if (m != selmon) { |
| 701 | Monitor *m; | 738 | unfocus(selmon->sel, 1); |
| 702 | XExposeEvent *ev = &e->xexpose; | 739 | selmon = m; |
| 703 | 740 | } else if (!c || c == selmon->sel) | |
| 704 | if (ev->count == 0 && (m = wintomon(ev->window))) { | 741 | return; |
| 705 | drawbar(m); | 742 | focus(c); |
| 706 | if (m == selmon) | 743 | } |
| 707 | updatesystray(); | 744 | |
| 708 | } | 745 | void expose(XEvent *e) |
| 709 | } | 746 | { |
| 710 | 747 | Monitor *m; | |
| 711 | void focus(Client *c) { | 748 | XExposeEvent *ev = &e->xexpose; |
| 712 | if (!c || !ISVISIBLE(c)) | 749 | |
| 713 | for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext) | 750 | if (ev->count == 0 && (m = wintomon(ev->window))) { |
| 714 | ; | 751 | drawbar(m); |
| 715 | if (selmon->sel && selmon->sel != c) | 752 | if (m == selmon) |
| 716 | unfocus(selmon->sel, 0); | 753 | updatesystray(); |
| 717 | if (c) { | 754 | } |
| 718 | if (c->mon != selmon) | 755 | } |
| 719 | selmon = c->mon; | 756 | |
| 720 | if (c->isurgent) | 757 | void focus(Client *c) |
| 721 | seturgent(c, 0); | 758 | { |
| 722 | detachstack(c); | 759 | if (!c || !ISVISIBLE(c)) |
| 723 | attachstack(c); | 760 | for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext) |
| 724 | grabbuttons(c, 1); | 761 | ; |
| 725 | XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); | 762 | if (selmon->sel && selmon->sel != c) |
| 726 | setfocus(c); | 763 | unfocus(selmon->sel, 0); |
| 727 | } else { | 764 | if (c) { |
| 728 | XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); | 765 | if (c->mon != selmon) |
| 729 | XDeleteProperty(dpy, root, netatom[NetActiveWindow]); | 766 | selmon = c->mon; |
| 730 | } | 767 | if (c->isurgent) |
| 731 | selmon->sel = c; | 768 | seturgent(c, 0); |
| 732 | drawbars(); | 769 | detachstack(c); |
| 770 | attachstack(c); | ||
| 771 | grabbuttons(c, 1); | ||
| 772 | XSetWindowBorder(dpy, c->win, | ||
| 773 | scheme[SchemeSel][ColBorder].pixel); | ||
| 774 | setfocus(c); | ||
| 775 | } else { | ||
| 776 | XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); | ||
| 777 | XDeleteProperty(dpy, root, netatom[NetActiveWindow]); | ||
| 778 | } | ||
| 779 | selmon->sel = c; | ||
| 780 | drawbars(); | ||
| 733 | } | 781 | } |
| 734 | 782 | ||
| 735 | /* there are some broken focus acquiring clients needing extra handling */ | 783 | /* there are some broken focus acquiring clients needing extra handling */ |
| 736 | void focusin(XEvent *e) { | 784 | void focusin(XEvent *e) |
| 737 | XFocusChangeEvent *ev = &e->xfocus; | 785 | { |
| 786 | XFocusChangeEvent *ev = &e->xfocus; | ||
| 738 | 787 | ||
| 739 | if (selmon->sel && ev->window != selmon->sel->win) | 788 | if (selmon->sel && ev->window != selmon->sel->win) |
| 740 | setfocus(selmon->sel); | 789 | setfocus(selmon->sel); |
| 741 | } | 790 | } |
| 742 | 791 | ||
| 743 | // void focusmon(const Arg *arg) { | 792 | // void focusmon(const Arg *arg) { |
| @@ -778,127 +827,143 @@ void focusin(XEvent *e) { | |||
| 778 | // } | 827 | // } |
| 779 | // } | 828 | // } |
| 780 | 829 | ||
| 781 | Atom getatomprop(Client *c, Atom prop) { | 830 | Atom getatomprop(Client *c, Atom prop) |
| 782 | int di; | 831 | { |
| 783 | unsigned long dl; | 832 | int di; |
| 784 | unsigned char *p = NULL; | 833 | unsigned long dl; |
| 785 | Atom da, atom = None; | 834 | unsigned char *p = NULL; |
| 786 | 835 | Atom da, atom = None; | |
| 787 | /* FIXME getatomprop should return the number of items and a pointer to | 836 | |
| 788 | * the stored data instead of this workaround */ | 837 | /* FIXME getatomprop should return the number of items and a pointer to |
| 789 | Atom req = XA_ATOM; | 838 | * the stored data instead of this workaround */ |
| 790 | if (prop == xatom[XembedInfo]) | 839 | Atom req = XA_ATOM; |
| 791 | req = xatom[XembedInfo]; | 840 | if (prop == xatom[XembedInfo]) |
| 792 | 841 | req = xatom[XembedInfo]; | |
| 793 | if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, &da, | 842 | |
| 794 | &di, &dl, &dl, &p) == Success && | 843 | if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, |
| 795 | p) { | 844 | &da, &di, &dl, &dl, &p) == Success && |
| 796 | atom = *(Atom *)p; | 845 | p) { |
| 797 | if (da == xatom[XembedInfo] && dl == 2) | 846 | atom = *(Atom *)p; |
| 798 | atom = ((Atom *)p)[1]; | 847 | if (da == xatom[XembedInfo] && dl == 2) |
| 799 | XFree(p); | 848 | atom = ((Atom *)p)[1]; |
| 800 | } | 849 | XFree(p); |
| 801 | return atom; | 850 | } |
| 802 | } | 851 | return atom; |
| 803 | 852 | } | |
| 804 | unsigned int getsystraywidth() { | 853 | |
| 805 | unsigned int w = 0; | 854 | unsigned int getsystraywidth() |
| 806 | Client *i; | 855 | { |
| 807 | if (showsystray) | 856 | unsigned int w = 0; |
| 808 | for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next) | 857 | Client *i; |
| 809 | ; | 858 | if (showsystray) |
| 810 | return w ? w + systrayspacing : 1; | 859 | for (i = systray->icons; i; |
| 811 | } | 860 | w += i->w + systrayspacing, i = i->next) |
| 812 | 861 | ; | |
| 813 | int getrootptr(int *x, int *y) { | 862 | return w ? w + systrayspacing : 1; |
| 814 | int di; | 863 | } |
| 815 | unsigned int dui; | 864 | |
| 816 | Window dummy; | 865 | int getrootptr(int *x, int *y) |
| 817 | 866 | { | |
| 818 | return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); | 867 | int di; |
| 819 | } | 868 | unsigned int dui; |
| 820 | 869 | Window dummy; | |
| 821 | long getstate(Window w) { | 870 | |
| 822 | int format; | 871 | return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); |
| 823 | long result = -1; | 872 | } |
| 824 | unsigned char *p = NULL; | 873 | |
| 825 | unsigned long n, extra; | 874 | long getstate(Window w) |
| 826 | Atom real; | 875 | { |
| 827 | 876 | int format; | |
| 828 | if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, | 877 | long result = -1; |
| 829 | wmatom[WMState], &real, &format, &n, &extra, | 878 | unsigned char *p = NULL; |
| 830 | (unsigned char **)&p) != Success) | 879 | unsigned long n, extra; |
| 831 | return -1; | 880 | Atom real; |
| 832 | if (n != 0) | 881 | |
| 833 | result = *p; | 882 | if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, |
| 834 | XFree(p); | 883 | wmatom[WMState], &real, &format, &n, &extra, |
| 835 | return result; | 884 | (unsigned char **)&p) != Success) |
| 836 | } | 885 | return -1; |
| 837 | 886 | if (n != 0) | |
| 838 | int gettextprop(Window w, Atom atom, char *text, unsigned int size) { | 887 | result = *p; |
| 839 | char **list = NULL; | 888 | XFree(p); |
| 840 | int n; | 889 | return result; |
| 841 | XTextProperty name; | 890 | } |
| 842 | 891 | ||
| 843 | if (!text || size == 0) | 892 | int gettextprop(Window w, Atom atom, char *text, unsigned int size) |
| 844 | return 0; | 893 | { |
| 845 | text[0] = '\0'; | 894 | char **list = NULL; |
| 846 | if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) | 895 | int n; |
| 847 | return 0; | 896 | XTextProperty name; |
| 848 | if (name.encoding == XA_STRING) { | 897 | |
| 849 | strncpy(text, (char *)name.value, size - 1); | 898 | if (!text || size == 0) |
| 850 | } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && | 899 | return 0; |
| 851 | n > 0 && *list) { | 900 | text[0] = '\0'; |
| 852 | strncpy(text, *list, size - 1); | 901 | if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) |
| 853 | XFreeStringList(list); | 902 | return 0; |
| 854 | } | 903 | if (name.encoding == XA_STRING) { |
| 855 | text[size - 1] = '\0'; | 904 | strncpy(text, (char *)name.value, size - 1); |
| 856 | XFree(name.value); | 905 | } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= |
| 857 | return 1; | 906 | Success && |
| 858 | } | 907 | n > 0 && *list) { |
| 859 | 908 | strncpy(text, *list, size - 1); | |
| 860 | void grabbuttons(Client *c, int focused) { | 909 | XFreeStringList(list); |
| 861 | updatenumlockmask(); | 910 | } |
| 862 | { | 911 | text[size - 1] = '\0'; |
| 863 | unsigned int i, j; | 912 | XFree(name.value); |
| 864 | unsigned int modifiers[] = {0, LockMask, numlockmask, | 913 | return 1; |
| 865 | numlockmask | LockMask}; | 914 | } |
| 866 | XUngrabButton(dpy, AnyButton, AnyModifier, c->win); | 915 | |
| 867 | if (!focused) | 916 | void grabbuttons(Client *c, int focused) |
| 868 | XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, | 917 | { |
| 869 | GrabModeSync, GrabModeSync, None, None); | 918 | updatenumlockmask(); |
| 870 | for (i = 0; i < LENGTH(buttons); i++) | 919 | { |
| 871 | if (buttons[i].click == ClkClientWin) | 920 | unsigned int i, j; |
| 872 | for (j = 0; j < LENGTH(modifiers); j++) | 921 | unsigned int modifiers[] = {0, LockMask, numlockmask, |
| 873 | XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], | 922 | numlockmask | LockMask}; |
| 874 | c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, | 923 | XUngrabButton(dpy, AnyButton, AnyModifier, c->win); |
| 875 | None, None); | 924 | if (!focused) |
| 876 | } | 925 | XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, |
| 877 | } | 926 | BUTTONMASK, GrabModeSync, GrabModeSync, |
| 878 | 927 | None, None); | |
| 879 | void grabkeys(void) { | 928 | for (i = 0; i < LENGTH(buttons); i++) |
| 880 | updatenumlockmask(); | 929 | if (buttons[i].click == ClkClientWin) |
| 881 | { | 930 | for (j = 0; j < LENGTH(modifiers); j++) |
| 882 | unsigned int i, j, k; | 931 | XGrabButton(dpy, buttons[i].button, |
| 883 | unsigned int modifiers[] = {0, LockMask, numlockmask, | 932 | buttons[i].mask | |
| 884 | numlockmask | LockMask}; | 933 | modifiers[j], |
| 885 | int start, end, skip; | 934 | c->win, False, BUTTONMASK, |
| 886 | KeySym *syms; | 935 | GrabModeAsync, GrabModeSync, |
| 887 | 936 | None, None); | |
| 888 | XUngrabKey(dpy, AnyKey, AnyModifier, root); | 937 | } |
| 889 | XDisplayKeycodes(dpy, &start, &end); | 938 | } |
| 890 | syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip); | 939 | |
| 891 | if (!syms) | 940 | void grabkeys(void) |
| 892 | return; | 941 | { |
| 893 | for (k = start; k <= end; k++) | 942 | updatenumlockmask(); |
| 894 | for (i = 0; i < LENGTH(keys); i++) | 943 | { |
| 895 | /* skip modifier codes, we do that ourselves */ | 944 | unsigned int i, j, k; |
| 896 | if (keys[i].keysym == syms[(k - start) * skip]) | 945 | unsigned int modifiers[] = {0, LockMask, numlockmask, |
| 897 | for (j = 0; j < LENGTH(modifiers); j++) | 946 | numlockmask | LockMask}; |
| 898 | XGrabKey(dpy, k, keys[i].mod | modifiers[j], root, True, | 947 | int start, end, skip; |
| 899 | GrabModeAsync, GrabModeAsync); | 948 | KeySym *syms; |
| 900 | XFree(syms); | 949 | |
| 901 | } | 950 | XUngrabKey(dpy, AnyKey, AnyModifier, root); |
| 951 | XDisplayKeycodes(dpy, &start, &end); | ||
| 952 | syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip); | ||
| 953 | if (!syms) | ||
| 954 | return; | ||
| 955 | for (k = start; k <= end; k++) | ||
| 956 | for (i = 0; i < LENGTH(keys); i++) | ||
| 957 | /* skip modifier codes, we do that ourselves */ | ||
| 958 | if (keys[i].keysym == syms[(k - start) * skip]) | ||
| 959 | for (j = 0; j < LENGTH(modifiers); j++) | ||
| 960 | XGrabKey( | ||
| 961 | dpy, k, | ||
| 962 | keys[i].mod | modifiers[j], | ||
| 963 | root, True, GrabModeAsync, | ||
| 964 | GrabModeAsync); | ||
| 965 | XFree(syms); | ||
| 966 | } | ||
| 902 | } | 967 | } |
| 903 | 968 | ||
| 904 | // void incnmaster(const Arg *arg) { | 969 | // void incnmaster(const Arg *arg) { |
| @@ -908,133 +973,143 @@ void grabkeys(void) { | |||
| 908 | 973 | ||
| 909 | #ifdef XINERAMA | 974 | #ifdef XINERAMA |
| 910 | static int isuniquegeom(XineramaScreenInfo *unique, size_t n, | 975 | static int isuniquegeom(XineramaScreenInfo *unique, size_t n, |
| 911 | XineramaScreenInfo *info) { | 976 | XineramaScreenInfo *info) |
| 912 | while (n--) | 977 | { |
| 913 | if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org && | 978 | while (n--) |
| 914 | unique[n].width == info->width && unique[n].height == info->height) | 979 | if (unique[n].x_org == info->x_org && |
| 915 | return 0; | 980 | unique[n].y_org == info->y_org && |
| 916 | return 1; | 981 | unique[n].width == info->width && |
| 982 | unique[n].height == info->height) | ||
| 983 | return 0; | ||
| 984 | return 1; | ||
| 917 | } | 985 | } |
| 918 | #endif /* XINERAMA */ | 986 | #endif /* XINERAMA */ |
| 919 | 987 | ||
| 920 | void keypress(XEvent *e) { | 988 | void keypress(XEvent *e) |
| 921 | unsigned int i; | 989 | { |
| 922 | KeySym keysym; | 990 | unsigned int i; |
| 923 | XKeyEvent *ev; | 991 | KeySym keysym; |
| 924 | 992 | XKeyEvent *ev; | |
| 925 | ev = &e->xkey; | 993 | |
| 926 | keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); | 994 | ev = &e->xkey; |
| 927 | for (i = 0; i < LENGTH(keys); i++) | 995 | keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); |
| 928 | if (keysym == keys[i].keysym && | 996 | for (i = 0; i < LENGTH(keys); i++) |
| 929 | CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) && keys[i].func) | 997 | if (keysym == keys[i].keysym && |
| 930 | keys[i].func(&(keys[i].arg)); | 998 | CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) && |
| 931 | } | 999 | keys[i].func) |
| 932 | 1000 | keys[i].func(&(keys[i].arg)); | |
| 933 | void killclient(const Arg *arg) { | 1001 | } |
| 934 | if (!selmon->sel) | 1002 | |
| 935 | return; | 1003 | void killclient(const Arg *arg) |
| 936 | 1004 | { | |
| 937 | if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, | 1005 | if (!selmon->sel) |
| 938 | wmatom[WMDelete], CurrentTime, 0, 0, 0)) { | 1006 | return; |
| 939 | XGrabServer(dpy); | 1007 | |
| 940 | XSetErrorHandler(xerrordummy); | 1008 | if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, |
| 941 | XSetCloseDownMode(dpy, DestroyAll); | 1009 | wmatom[WMDelete], CurrentTime, 0, 0, 0)) { |
| 942 | XKillClient(dpy, selmon->sel->win); | 1010 | XGrabServer(dpy); |
| 943 | XSync(dpy, False); | 1011 | XSetErrorHandler(xerrordummy); |
| 944 | XSetErrorHandler(xerror); | 1012 | XSetCloseDownMode(dpy, DestroyAll); |
| 945 | XUngrabServer(dpy); | 1013 | XKillClient(dpy, selmon->sel->win); |
| 946 | } | 1014 | XSync(dpy, False); |
| 947 | } | 1015 | XSetErrorHandler(xerror); |
| 948 | 1016 | XUngrabServer(dpy); | |
| 949 | void manage(Window w, XWindowAttributes *wa) { | 1017 | } |
| 950 | Client *c, *t = NULL, *term = NULL; | 1018 | } |
| 951 | Window trans = None; | 1019 | |
| 952 | XWindowChanges wc; | 1020 | void manage(Window w, XWindowAttributes *wa) |
| 953 | 1021 | { | |
| 954 | c = ecalloc(1, sizeof(Client)); | 1022 | Client *c, *t = NULL, *term = NULL; |
| 955 | c->win = w; | 1023 | Window trans = None; |
| 956 | c->pid = winpid(w); | 1024 | XWindowChanges wc; |
| 957 | /* geometry */ | 1025 | |
| 958 | c->x = c->oldx = wa->x; | 1026 | c = ecalloc(1, sizeof(Client)); |
| 959 | c->y = c->oldy = wa->y; | 1027 | c->win = w; |
| 960 | c->w = c->oldw = wa->width; | 1028 | c->pid = winpid(w); |
| 961 | c->h = c->oldh = wa->height; | 1029 | /* geometry */ |
| 962 | c->oldbw = wa->border_width; | 1030 | c->x = c->oldx = wa->x; |
| 963 | 1031 | c->y = c->oldy = wa->y; | |
| 964 | updatetitle(c); | 1032 | c->w = c->oldw = wa->width; |
| 965 | if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { | 1033 | c->h = c->oldh = wa->height; |
| 966 | c->mon = t->mon; | 1034 | c->oldbw = wa->border_width; |
| 967 | c->tags = t->tags; | 1035 | |
| 968 | } else { | 1036 | updatetitle(c); |
| 969 | c->mon = selmon; | 1037 | if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { |
| 970 | applyrules(c); | 1038 | c->mon = t->mon; |
| 971 | term = termforwin(c); | 1039 | c->tags = t->tags; |
| 972 | } | 1040 | } else { |
| 973 | 1041 | c->mon = selmon; | |
| 974 | if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) | 1042 | applyrules(c); |
| 975 | c->x = c->mon->wx + c->mon->ww - WIDTH(c); | 1043 | term = termforwin(c); |
| 976 | if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh) | 1044 | } |
| 977 | c->y = c->mon->wy + c->mon->wh - HEIGHT(c); | 1045 | |
| 978 | c->x = MAX(c->x, c->mon->wx); | 1046 | if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) |
| 979 | c->y = MAX(c->y, c->mon->wy); | 1047 | c->x = c->mon->wx + c->mon->ww - WIDTH(c); |
| 980 | c->bw = borderpx; | 1048 | if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh) |
| 981 | 1049 | c->y = c->mon->wy + c->mon->wh - HEIGHT(c); | |
| 982 | wc.border_width = c->bw; | 1050 | c->x = MAX(c->x, c->mon->wx); |
| 983 | XConfigureWindow(dpy, w, CWBorderWidth, &wc); | 1051 | c->y = MAX(c->y, c->mon->wy); |
| 984 | XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); | 1052 | c->bw = borderpx; |
| 985 | configure(c); /* propagates border_width, if size doesn't change */ | 1053 | |
| 986 | updatewindowtype(c); | 1054 | wc.border_width = c->bw; |
| 987 | updatesizehints(c); | 1055 | XConfigureWindow(dpy, w, CWBorderWidth, &wc); |
| 988 | updatewmhints(c); | 1056 | XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); |
| 989 | XSelectInput(dpy, w, | 1057 | configure(c); /* propagates border_width, if size doesn't change */ |
| 990 | EnterWindowMask | FocusChangeMask | PropertyChangeMask | | 1058 | updatewindowtype(c); |
| 991 | StructureNotifyMask); | 1059 | updatesizehints(c); |
| 992 | grabbuttons(c, 0); | 1060 | updatewmhints(c); |
| 993 | if (!c->isfloating) | 1061 | XSelectInput(dpy, w, |
| 994 | c->isfloating = c->oldstate = trans != None || c->isfixed; | 1062 | EnterWindowMask | FocusChangeMask | PropertyChangeMask | |
| 995 | if (c->isfloating) | 1063 | StructureNotifyMask); |
| 996 | XRaiseWindow(dpy, c->win); | 1064 | grabbuttons(c, 0); |
| 997 | attach(c); | 1065 | if (!c->isfloating) |
| 998 | attachstack(c); | 1066 | c->isfloating = c->oldstate = trans != None || c->isfixed; |
| 999 | XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, | 1067 | if (c->isfloating) |
| 1000 | PropModeAppend, (unsigned char *)&(c->win), 1); | 1068 | XRaiseWindow(dpy, c->win); |
| 1001 | XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, | 1069 | attach(c); |
| 1002 | c->h); /* some windows require this */ | 1070 | attachstack(c); |
| 1003 | setclientstate(c, NormalState); | 1071 | XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, |
| 1004 | if (c->mon == selmon) | 1072 | PropModeAppend, (unsigned char *)&(c->win), 1); |
| 1005 | unfocus(selmon->sel, 0); | 1073 | XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, |
| 1006 | c->mon->sel = c; | 1074 | c->h); /* some windows require this */ |
| 1007 | arrange(c->mon); | 1075 | setclientstate(c, NormalState); |
| 1008 | XMapWindow(dpy, c->win); | 1076 | if (c->mon == selmon) |
| 1009 | if (term) | 1077 | unfocus(selmon->sel, 0); |
| 1010 | swallow(term, c); | 1078 | c->mon->sel = c; |
| 1011 | focus(NULL); | 1079 | arrange(c->mon); |
| 1012 | } | 1080 | XMapWindow(dpy, c->win); |
| 1013 | 1081 | if (term) | |
| 1014 | void mappingnotify(XEvent *e) { | 1082 | swallow(term, c); |
| 1015 | XMappingEvent *ev = &e->xmapping; | 1083 | focus(NULL); |
| 1016 | 1084 | } | |
| 1017 | XRefreshKeyboardMapping(ev); | 1085 | |
| 1018 | if (ev->request == MappingKeyboard) | 1086 | void mappingnotify(XEvent *e) |
| 1019 | grabkeys(); | 1087 | { |
| 1020 | } | 1088 | XMappingEvent *ev = &e->xmapping; |
| 1021 | 1089 | ||
| 1022 | void maprequest(XEvent *e) { | 1090 | XRefreshKeyboardMapping(ev); |
| 1023 | static XWindowAttributes wa; | 1091 | if (ev->request == MappingKeyboard) |
| 1024 | XMapRequestEvent *ev = &e->xmaprequest; | 1092 | grabkeys(); |
| 1025 | 1093 | } | |
| 1026 | Client *i; | 1094 | |
| 1027 | if ((i = wintosystrayicon(ev->window))) { | 1095 | void maprequest(XEvent *e) |
| 1028 | sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, | 1096 | { |
| 1029 | XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); | 1097 | static XWindowAttributes wa; |
| 1030 | resizebarwin(selmon); | 1098 | XMapRequestEvent *ev = &e->xmaprequest; |
| 1031 | updatesystray(); | 1099 | |
| 1032 | } | 1100 | Client *i; |
| 1033 | 1101 | if ((i = wintosystrayicon(ev->window))) { | |
| 1034 | if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) | 1102 | sendevent(i->win, netatom[Xembed], StructureNotifyMask, |
| 1035 | return; | 1103 | CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, |
| 1036 | if (!wintoclient(ev->window)) | 1104 | XEMBED_EMBEDDED_VERSION); |
| 1037 | manage(ev->window, &wa); | 1105 | resizebarwin(selmon); |
| 1106 | updatesystray(); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) | ||
| 1110 | return; | ||
| 1111 | if (!wintoclient(ev->window)) | ||
| 1112 | manage(ev->window, &wa); | ||
| 1038 | } | 1113 | } |
| 1039 | 1114 | ||
| 1040 | // void monocle(Monitor *m) { | 1115 | // void monocle(Monitor *m) { |
| @@ -1050,1402 +1125,1442 @@ void maprequest(XEvent *e) { | |||
| 1050 | // resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); | 1125 | // resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); |
| 1051 | // } | 1126 | // } |
| 1052 | 1127 | ||
| 1053 | void motionnotify(XEvent *e) { | 1128 | void motionnotify(XEvent *e) |
| 1054 | static Monitor *mon = NULL; | 1129 | { |
| 1055 | Monitor *m; | 1130 | static Monitor *mon = NULL; |
| 1056 | XMotionEvent *ev = &e->xmotion; | 1131 | Monitor *m; |
| 1057 | 1132 | XMotionEvent *ev = &e->xmotion; | |
| 1058 | if (ev->window != root) | 1133 | |
| 1059 | return; | 1134 | if (ev->window != root) |
| 1060 | if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { | 1135 | return; |
| 1061 | unfocus(selmon->sel, 1); | 1136 | if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { |
| 1062 | selmon = m; | 1137 | unfocus(selmon->sel, 1); |
| 1063 | focus(NULL); | 1138 | selmon = m; |
| 1064 | } | 1139 | focus(NULL); |
| 1065 | mon = m; | 1140 | } |
| 1066 | } | 1141 | mon = m; |
| 1067 | 1142 | } | |
| 1068 | void movemouse(const Arg *arg) { | 1143 | |
| 1069 | int x, y, ocx, ocy, nx, ny; | 1144 | void movemouse(const Arg *arg) |
| 1070 | Client *c; | 1145 | { |
| 1071 | Monitor *m; | 1146 | int x, y, ocx, ocy, nx, ny; |
| 1072 | XEvent ev; | 1147 | Client *c; |
| 1073 | Time lasttime = 0; | 1148 | Monitor *m; |
| 1074 | 1149 | XEvent ev; | |
| 1075 | if (!(c = selmon->sel)) | 1150 | Time lasttime = 0; |
| 1076 | return; | 1151 | |
| 1077 | if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ | 1152 | if (!(c = selmon->sel)) |
| 1078 | return; | 1153 | return; |
| 1079 | restack(selmon); | 1154 | if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ |
| 1080 | ocx = c->x; | 1155 | return; |
| 1081 | ocy = c->y; | 1156 | restack(selmon); |
| 1082 | if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, | 1157 | ocx = c->x; |
| 1083 | None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) | 1158 | ocy = c->y; |
| 1084 | return; | 1159 | if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, |
| 1085 | if (!getrootptr(&x, &y)) | 1160 | GrabModeAsync, None, cursor[CurMove]->cursor, |
| 1086 | return; | 1161 | CurrentTime) != GrabSuccess) |
| 1087 | do { | 1162 | return; |
| 1088 | XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); | 1163 | if (!getrootptr(&x, &y)) |
| 1089 | switch (ev.type) { | 1164 | return; |
| 1090 | case ConfigureRequest: | 1165 | do { |
| 1091 | case Expose: | 1166 | XMaskEvent(dpy, |
| 1092 | case MapRequest: | 1167 | MOUSEMASK | ExposureMask | SubstructureRedirectMask, |
| 1093 | handler[ev.type](&ev); | 1168 | &ev); |
| 1094 | break; | 1169 | switch (ev.type) { |
| 1095 | case MotionNotify: | 1170 | case ConfigureRequest: |
| 1096 | if ((ev.xmotion.time - lasttime) <= (1000 / 60)) | 1171 | case Expose: |
| 1097 | continue; | 1172 | case MapRequest: |
| 1098 | lasttime = ev.xmotion.time; | 1173 | handler[ev.type](&ev); |
| 1099 | 1174 | break; | |
| 1100 | nx = ocx + (ev.xmotion.x - x); | 1175 | case MotionNotify: |
| 1101 | ny = ocy + (ev.xmotion.y - y); | 1176 | if ((ev.xmotion.time - lasttime) <= (1000 / 60)) |
| 1102 | if (abs(selmon->wx - nx) < snap) | 1177 | continue; |
| 1103 | nx = selmon->wx; | 1178 | lasttime = ev.xmotion.time; |
| 1104 | else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) | 1179 | |
| 1105 | nx = selmon->wx + selmon->ww - WIDTH(c); | 1180 | nx = ocx + (ev.xmotion.x - x); |
| 1106 | if (abs(selmon->wy - ny) < snap) | 1181 | ny = ocy + (ev.xmotion.y - y); |
| 1107 | ny = selmon->wy; | 1182 | if (abs(selmon->wx - nx) < snap) |
| 1108 | else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) | 1183 | nx = selmon->wx; |
| 1109 | ny = selmon->wy + selmon->wh - HEIGHT(c); | 1184 | else if (abs((selmon->wx + selmon->ww) - |
| 1110 | if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && | 1185 | (nx + WIDTH(c))) < snap) |
| 1111 | (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) | 1186 | nx = selmon->wx + selmon->ww - WIDTH(c); |
| 1112 | togglefloating(NULL); | 1187 | if (abs(selmon->wy - ny) < snap) |
| 1113 | if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) | 1188 | ny = selmon->wy; |
| 1114 | resize(c, nx, ny, c->w, c->h, 1); | 1189 | else if (abs((selmon->wy + selmon->wh) - |
| 1115 | break; | 1190 | (ny + HEIGHT(c))) < snap) |
| 1116 | } | 1191 | ny = selmon->wy + selmon->wh - HEIGHT(c); |
| 1117 | } while (ev.type != ButtonRelease); | 1192 | if (!c->isfloating && |
| 1118 | XUngrabPointer(dpy, CurrentTime); | 1193 | selmon->lt[selmon->sellt]->arrange && |
| 1119 | if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { | 1194 | (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) |
| 1120 | sendmon(c, m); | 1195 | togglefloating(NULL); |
| 1121 | selmon = m; | 1196 | if (!selmon->lt[selmon->sellt]->arrange || |
| 1122 | focus(NULL); | 1197 | c->isfloating) |
| 1123 | } | 1198 | resize(c, nx, ny, c->w, c->h, 1); |
| 1124 | } | 1199 | break; |
| 1125 | 1200 | } | |
| 1126 | Client *nexttiled(Client *c) { | 1201 | } while (ev.type != ButtonRelease); |
| 1127 | for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next) | 1202 | XUngrabPointer(dpy, CurrentTime); |
| 1128 | ; | 1203 | if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { |
| 1129 | return c; | 1204 | sendmon(c, m); |
| 1130 | } | 1205 | selmon = m; |
| 1131 | 1206 | focus(NULL); | |
| 1132 | void pop(Client *c) { | 1207 | } |
| 1133 | detach(c); | 1208 | } |
| 1134 | attach(c); | 1209 | |
| 1135 | focus(c); | 1210 | Client *nexttiled(Client *c) |
| 1136 | arrange(c->mon); | 1211 | { |
| 1137 | } | 1212 | for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next) |
| 1138 | 1213 | ; | |
| 1139 | void propertynotify(XEvent *e) { | 1214 | return c; |
| 1140 | Client *c; | 1215 | } |
| 1141 | Window trans; | 1216 | |
| 1142 | XPropertyEvent *ev = &e->xproperty; | 1217 | void pop(Client *c) |
| 1143 | 1218 | { | |
| 1144 | if ((c = wintosystrayicon(ev->window))) { | 1219 | detach(c); |
| 1145 | if (ev->atom == XA_WM_NORMAL_HINTS) { | 1220 | attach(c); |
| 1146 | updatesizehints(c); | 1221 | focus(c); |
| 1147 | updatesystrayicongeom(c, c->w, c->h); | 1222 | arrange(c->mon); |
| 1148 | } else | 1223 | } |
| 1149 | updatesystrayiconstate(c, ev); | 1224 | |
| 1150 | resizebarwin(selmon); | 1225 | void propertynotify(XEvent *e) |
| 1151 | updatesystray(); | 1226 | { |
| 1152 | } | 1227 | Client *c; |
| 1153 | 1228 | Window trans; | |
| 1154 | if ((ev->window == root) && (ev->atom == XA_WM_NAME)) | 1229 | XPropertyEvent *ev = &e->xproperty; |
| 1155 | updatestatus(); | 1230 | |
| 1156 | else if (ev->state == PropertyDelete) | 1231 | if ((c = wintosystrayicon(ev->window))) { |
| 1157 | return; /* ignore */ | 1232 | if (ev->atom == XA_WM_NORMAL_HINTS) { |
| 1158 | else if ((c = wintoclient(ev->window))) { | 1233 | updatesizehints(c); |
| 1159 | switch (ev->atom) { | 1234 | updatesystrayicongeom(c, c->w, c->h); |
| 1160 | default: | 1235 | } else |
| 1161 | break; | 1236 | updatesystrayiconstate(c, ev); |
| 1162 | case XA_WM_TRANSIENT_FOR: | 1237 | resizebarwin(selmon); |
| 1163 | if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && | 1238 | updatesystray(); |
| 1164 | (c->isfloating = (wintoclient(trans)) != NULL)) | 1239 | } |
| 1165 | arrange(c->mon); | 1240 | |
| 1166 | break; | 1241 | if ((ev->window == root) && (ev->atom == XA_WM_NAME)) |
| 1167 | case XA_WM_NORMAL_HINTS: | 1242 | updatestatus(); |
| 1168 | c->hintsvalid = 0; | 1243 | else if (ev->state == PropertyDelete) |
| 1169 | break; | 1244 | return; /* ignore */ |
| 1170 | case XA_WM_HINTS: | 1245 | else if ((c = wintoclient(ev->window))) { |
| 1171 | updatewmhints(c); | 1246 | switch (ev->atom) { |
| 1172 | drawbars(); | 1247 | default: |
| 1173 | break; | 1248 | break; |
| 1174 | } | 1249 | case XA_WM_TRANSIENT_FOR: |
| 1175 | if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { | 1250 | if (!c->isfloating && |
| 1176 | updatetitle(c); | 1251 | (XGetTransientForHint(dpy, c->win, &trans)) && |
| 1177 | if (c == c->mon->sel) | 1252 | (c->isfloating = (wintoclient(trans)) != NULL)) |
| 1178 | drawbar(c->mon); | 1253 | arrange(c->mon); |
| 1179 | } | 1254 | break; |
| 1180 | if (ev->atom == netatom[NetWMWindowType]) | 1255 | case XA_WM_NORMAL_HINTS: |
| 1181 | updatewindowtype(c); | 1256 | c->hintsvalid = 0; |
| 1182 | } | 1257 | break; |
| 1258 | case XA_WM_HINTS: | ||
| 1259 | updatewmhints(c); | ||
| 1260 | drawbars(); | ||
| 1261 | break; | ||
| 1262 | } | ||
| 1263 | if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { | ||
| 1264 | updatetitle(c); | ||
| 1265 | if (c == c->mon->sel) | ||
| 1266 | drawbar(c->mon); | ||
| 1267 | } | ||
| 1268 | if (ev->atom == netatom[NetWMWindowType]) | ||
| 1269 | updatewindowtype(c); | ||
| 1270 | } | ||
| 1183 | } | 1271 | } |
| 1184 | 1272 | ||
| 1185 | void quit(const Arg *arg) { running = 0; } | 1273 | void quit(const Arg *arg) { running = 0; } |
| 1186 | 1274 | ||
| 1187 | Monitor *recttomon(int x, int y, int w, int h) { | 1275 | Monitor *recttomon(int x, int y, int w, int h) |
| 1188 | Monitor *m, *r = selmon; | 1276 | { |
| 1189 | int a, area = 0; | 1277 | Monitor *m, *r = selmon; |
| 1190 | 1278 | int a, area = 0; | |
| 1191 | for (m = mons; m; m = m->next) | 1279 | |
| 1192 | if ((a = INTERSECT(x, y, w, h, m)) > area) { | 1280 | for (m = mons; m; m = m->next) |
| 1193 | area = a; | 1281 | if ((a = INTERSECT(x, y, w, h, m)) > area) { |
| 1194 | r = m; | 1282 | area = a; |
| 1195 | } | 1283 | r = m; |
| 1196 | return r; | 1284 | } |
| 1197 | } | 1285 | return r; |
| 1198 | 1286 | } | |
| 1199 | void removesystrayicon(Client *i) { | 1287 | |
| 1200 | Client **ii; | 1288 | void removesystrayicon(Client *i) |
| 1201 | 1289 | { | |
| 1202 | if (!showsystray || !i) | 1290 | Client **ii; |
| 1203 | return; | 1291 | |
| 1204 | for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next) | 1292 | if (!showsystray || !i) |
| 1205 | ; | 1293 | return; |
| 1206 | if (ii) | 1294 | for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next) |
| 1207 | *ii = i->next; | 1295 | ; |
| 1208 | free(i); | 1296 | if (ii) |
| 1209 | } | 1297 | *ii = i->next; |
| 1210 | 1298 | free(i); | |
| 1211 | void resize(Client *c, int x, int y, int w, int h, int interact) { | 1299 | } |
| 1212 | if (applysizehints(c, &x, &y, &w, &h, interact)) | 1300 | |
| 1213 | resizeclient(c, x, y, w, h); | 1301 | void resize(Client *c, int x, int y, int w, int h, int interact) |
| 1214 | } | 1302 | { |
| 1215 | 1303 | if (applysizehints(c, &x, &y, &w, &h, interact)) | |
| 1216 | void resizebarwin(Monitor *m) { | 1304 | resizeclient(c, x, y, w, h); |
| 1217 | unsigned int w = m->ww; | 1305 | } |
| 1218 | if (showsystray && m == systraytomon(m) && !systrayonleft) | 1306 | |
| 1219 | w -= getsystraywidth(); | 1307 | void resizebarwin(Monitor *m) |
| 1220 | XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); | 1308 | { |
| 1221 | } | 1309 | unsigned int w = m->ww; |
| 1222 | 1310 | if (showsystray && m == systraytomon(m) && !systrayonleft) | |
| 1223 | void resizeclient(Client *c, int x, int y, int w, int h) { | 1311 | w -= getsystraywidth(); |
| 1224 | XWindowChanges wc; | 1312 | XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); |
| 1225 | 1313 | } | |
| 1226 | c->oldx = c->x; | 1314 | |
| 1227 | c->x = wc.x = x; | 1315 | void resizeclient(Client *c, int x, int y, int w, int h) |
| 1228 | c->oldy = c->y; | 1316 | { |
| 1229 | c->y = wc.y = y; | 1317 | XWindowChanges wc; |
| 1230 | c->oldw = c->w; | 1318 | |
| 1231 | c->w = wc.width = w; | 1319 | c->oldx = c->x; |
| 1232 | c->oldh = c->h; | 1320 | c->x = wc.x = x; |
| 1233 | c->h = wc.height = h; | 1321 | c->oldy = c->y; |
| 1234 | wc.border_width = c->bw; | 1322 | c->y = wc.y = y; |
| 1235 | XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, | 1323 | c->oldw = c->w; |
| 1236 | &wc); | 1324 | c->w = wc.width = w; |
| 1237 | configure(c); | 1325 | c->oldh = c->h; |
| 1238 | XSync(dpy, False); | 1326 | c->h = wc.height = h; |
| 1239 | } | 1327 | wc.border_width = c->bw; |
| 1240 | 1328 | XConfigureWindow(dpy, c->win, | |
| 1241 | void resizerequest(XEvent *e) { | 1329 | CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); |
| 1242 | XResizeRequestEvent *ev = &e->xresizerequest; | 1330 | configure(c); |
| 1243 | Client *i; | 1331 | XSync(dpy, False); |
| 1244 | 1332 | } | |
| 1245 | if ((i = wintosystrayicon(ev->window))) { | 1333 | |
| 1246 | updatesystrayicongeom(i, ev->width, ev->height); | 1334 | void resizerequest(XEvent *e) |
| 1247 | resizebarwin(selmon); | 1335 | { |
| 1248 | updatesystray(); | 1336 | XResizeRequestEvent *ev = &e->xresizerequest; |
| 1249 | } | 1337 | Client *i; |
| 1250 | } | 1338 | |
| 1251 | 1339 | if ((i = wintosystrayicon(ev->window))) { | |
| 1252 | void resizemouse(const Arg *arg) { | 1340 | updatesystrayicongeom(i, ev->width, ev->height); |
| 1253 | int ocx, ocy, nw, nh; | 1341 | resizebarwin(selmon); |
| 1254 | Client *c; | 1342 | updatesystray(); |
| 1255 | Monitor *m; | 1343 | } |
| 1256 | XEvent ev; | 1344 | } |
| 1257 | Time lasttime = 0; | 1345 | |
| 1258 | 1346 | void resizemouse(const Arg *arg) | |
| 1259 | if (!(c = selmon->sel)) | 1347 | { |
| 1260 | return; | 1348 | int ocx, ocy, nw, nh; |
| 1261 | if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ | 1349 | Client *c; |
| 1262 | return; | 1350 | Monitor *m; |
| 1263 | restack(selmon); | 1351 | XEvent ev; |
| 1264 | ocx = c->x; | 1352 | Time lasttime = 0; |
| 1265 | ocy = c->y; | 1353 | |
| 1266 | if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, | 1354 | if (!(c = selmon->sel)) |
| 1267 | None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) | 1355 | return; |
| 1268 | return; | 1356 | if (c->isfullscreen) /* no support resizing fullscreen windows by mouse |
| 1269 | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, | 1357 | */ |
| 1270 | c->h + c->bw - 1); | 1358 | return; |
| 1271 | do { | 1359 | restack(selmon); |
| 1272 | XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); | 1360 | ocx = c->x; |
| 1273 | switch (ev.type) { | 1361 | ocy = c->y; |
| 1274 | case ConfigureRequest: | 1362 | if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, |
| 1275 | case Expose: | 1363 | GrabModeAsync, None, cursor[CurResize]->cursor, |
| 1276 | case MapRequest: | 1364 | CurrentTime) != GrabSuccess) |
| 1277 | handler[ev.type](&ev); | 1365 | return; |
| 1278 | break; | 1366 | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, |
| 1279 | case MotionNotify: | 1367 | c->h + c->bw - 1); |
| 1280 | if ((ev.xmotion.time - lasttime) <= (1000 / 60)) | 1368 | do { |
| 1281 | continue; | 1369 | XMaskEvent(dpy, |
| 1282 | lasttime = ev.xmotion.time; | 1370 | MOUSEMASK | ExposureMask | SubstructureRedirectMask, |
| 1283 | 1371 | &ev); | |
| 1284 | nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); | 1372 | switch (ev.type) { |
| 1285 | nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); | 1373 | case ConfigureRequest: |
| 1286 | if (c->mon->wx + nw >= selmon->wx && | 1374 | case Expose: |
| 1287 | c->mon->wx + nw <= selmon->wx + selmon->ww && | 1375 | case MapRequest: |
| 1288 | c->mon->wy + nh >= selmon->wy && | 1376 | handler[ev.type](&ev); |
| 1289 | c->mon->wy + nh <= selmon->wy + selmon->wh) { | 1377 | break; |
| 1290 | if (!c->isfloating && selmon->lt[selmon->sellt]->arrange && | 1378 | case MotionNotify: |
| 1291 | (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) | 1379 | if ((ev.xmotion.time - lasttime) <= (1000 / 60)) |
| 1292 | togglefloating(NULL); | 1380 | continue; |
| 1293 | } | 1381 | lasttime = ev.xmotion.time; |
| 1294 | if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) | 1382 | |
| 1295 | resize(c, c->x, c->y, nw, nh, 1); | 1383 | nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); |
| 1296 | break; | 1384 | nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); |
| 1297 | } | 1385 | if (c->mon->wx + nw >= selmon->wx && |
| 1298 | } while (ev.type != ButtonRelease); | 1386 | c->mon->wx + nw <= selmon->wx + selmon->ww && |
| 1299 | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, | 1387 | c->mon->wy + nh >= selmon->wy && |
| 1300 | c->h + c->bw - 1); | 1388 | c->mon->wy + nh <= selmon->wy + selmon->wh) { |
| 1301 | XUngrabPointer(dpy, CurrentTime); | 1389 | if (!c->isfloating && |
| 1302 | while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)) | 1390 | selmon->lt[selmon->sellt]->arrange && |
| 1303 | ; | 1391 | (abs(nw - c->w) > snap || |
| 1304 | if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { | 1392 | abs(nh - c->h) > snap)) |
| 1305 | sendmon(c, m); | 1393 | togglefloating(NULL); |
| 1306 | selmon = m; | 1394 | } |
| 1307 | focus(NULL); | 1395 | if (!selmon->lt[selmon->sellt]->arrange || |
| 1308 | } | 1396 | c->isfloating) |
| 1309 | } | 1397 | resize(c, c->x, c->y, nw, nh, 1); |
| 1310 | 1398 | break; | |
| 1311 | void restack(Monitor *m) { | 1399 | } |
| 1312 | Client *c; | 1400 | } while (ev.type != ButtonRelease); |
| 1313 | XEvent ev; | 1401 | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, |
| 1314 | XWindowChanges wc; | 1402 | c->h + c->bw - 1); |
| 1315 | 1403 | XUngrabPointer(dpy, CurrentTime); | |
| 1316 | drawbar(m); | 1404 | while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)) |
| 1317 | if (!m->sel) | 1405 | ; |
| 1318 | return; | 1406 | if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { |
| 1319 | if (m->sel->isfloating || !m->lt[m->sellt]->arrange) | 1407 | sendmon(c, m); |
| 1320 | XRaiseWindow(dpy, m->sel->win); | 1408 | selmon = m; |
| 1321 | if (m->lt[m->sellt]->arrange) { | 1409 | focus(NULL); |
| 1322 | wc.stack_mode = Below; | 1410 | } |
| 1323 | wc.sibling = m->barwin; | 1411 | } |
| 1324 | for (c = m->stack; c; c = c->snext) | 1412 | |
| 1325 | if (!c->isfloating && ISVISIBLE(c)) { | 1413 | void restack(Monitor *m) |
| 1326 | XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc); | 1414 | { |
| 1327 | wc.sibling = c->win; | 1415 | Client *c; |
| 1328 | } | 1416 | XEvent ev; |
| 1329 | } | 1417 | XWindowChanges wc; |
| 1330 | XSync(dpy, False); | 1418 | |
| 1331 | while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)) | 1419 | drawbar(m); |
| 1332 | ; | 1420 | if (!m->sel) |
| 1333 | } | 1421 | return; |
| 1334 | 1422 | if (m->sel->isfloating || !m->lt[m->sellt]->arrange) | |
| 1335 | void run(void) { | 1423 | XRaiseWindow(dpy, m->sel->win); |
| 1336 | XEvent ev; | 1424 | if (m->lt[m->sellt]->arrange) { |
| 1337 | /* main event loop */ | 1425 | wc.stack_mode = Below; |
| 1338 | XSync(dpy, False); | 1426 | wc.sibling = m->barwin; |
| 1339 | while (running && !XNextEvent(dpy, &ev)) | 1427 | for (c = m->stack; c; c = c->snext) |
| 1340 | if (handler[ev.type]) | 1428 | if (!c->isfloating && ISVISIBLE(c)) { |
| 1341 | handler[ev.type](&ev); /* call handler */ | 1429 | XConfigureWindow(dpy, c->win, |
| 1342 | } | 1430 | CWSibling | CWStackMode, &wc); |
| 1343 | 1431 | wc.sibling = c->win; | |
| 1344 | void scan(void) { | 1432 | } |
| 1345 | unsigned int i, num; | 1433 | } |
| 1346 | Window d1, d2, *wins = NULL; | 1434 | XSync(dpy, False); |
| 1347 | XWindowAttributes wa; | 1435 | while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)) |
| 1348 | 1436 | ; | |
| 1349 | if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { | 1437 | } |
| 1350 | for (i = 0; i < num; i++) { | 1438 | |
| 1351 | if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect || | 1439 | void run(void) |
| 1352 | XGetTransientForHint(dpy, wins[i], &d1)) | 1440 | { |
| 1353 | continue; | 1441 | XEvent ev; |
| 1354 | if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) | 1442 | /* main event loop */ |
| 1355 | manage(wins[i], &wa); | 1443 | XSync(dpy, False); |
| 1356 | } | 1444 | while (running && !XNextEvent(dpy, &ev)) |
| 1357 | for (i = 0; i < num; i++) { /* now the transients */ | 1445 | if (handler[ev.type]) |
| 1358 | if (!XGetWindowAttributes(dpy, wins[i], &wa)) | 1446 | handler[ev.type](&ev); /* call handler */ |
| 1359 | continue; | 1447 | } |
| 1360 | if (XGetTransientForHint(dpy, wins[i], &d1) && | 1448 | |
| 1361 | (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) | 1449 | void scan(void) |
| 1362 | manage(wins[i], &wa); | 1450 | { |
| 1363 | } | 1451 | unsigned int i, num; |
| 1364 | if (wins) | 1452 | Window d1, d2, *wins = NULL; |
| 1365 | XFree(wins); | 1453 | XWindowAttributes wa; |
| 1366 | } | 1454 | |
| 1367 | } | 1455 | if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { |
| 1368 | 1456 | for (i = 0; i < num; i++) { | |
| 1369 | void sendmon(Client *c, Monitor *m) { | 1457 | if (!XGetWindowAttributes(dpy, wins[i], &wa) || |
| 1370 | if (c->mon == m) | 1458 | wa.override_redirect || |
| 1371 | return; | 1459 | XGetTransientForHint(dpy, wins[i], &d1)) |
| 1372 | unfocus(c, 1); | 1460 | continue; |
| 1373 | detach(c); | 1461 | if (wa.map_state == IsViewable || |
| 1374 | detachstack(c); | 1462 | getstate(wins[i]) == IconicState) |
| 1375 | c->mon = m; | 1463 | manage(wins[i], &wa); |
| 1376 | c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ | 1464 | } |
| 1377 | attach(c); | 1465 | for (i = 0; i < num; i++) { /* now the transients */ |
| 1378 | attachstack(c); | 1466 | if (!XGetWindowAttributes(dpy, wins[i], &wa)) |
| 1379 | focus(NULL); | 1467 | continue; |
| 1380 | arrange(NULL); | 1468 | if (XGetTransientForHint(dpy, wins[i], &d1) && |
| 1381 | } | 1469 | (wa.map_state == IsViewable || |
| 1382 | 1470 | getstate(wins[i]) == IconicState)) | |
| 1383 | void setclientstate(Client *c, long state) { | 1471 | manage(wins[i], &wa); |
| 1384 | long data[] = {state, None}; | 1472 | } |
| 1385 | 1473 | if (wins) | |
| 1386 | XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, | 1474 | XFree(wins); |
| 1387 | PropModeReplace, (unsigned char *)data, 2); | 1475 | } |
| 1476 | } | ||
| 1477 | |||
| 1478 | void sendmon(Client *c, Monitor *m) | ||
| 1479 | { | ||
| 1480 | if (c->mon == m) | ||
| 1481 | return; | ||
| 1482 | unfocus(c, 1); | ||
| 1483 | detach(c); | ||
| 1484 | detachstack(c); | ||
| 1485 | c->mon = m; | ||
| 1486 | c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ | ||
| 1487 | attach(c); | ||
| 1488 | attachstack(c); | ||
| 1489 | focus(NULL); | ||
| 1490 | arrange(NULL); | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | void setclientstate(Client *c, long state) | ||
| 1494 | { | ||
| 1495 | long data[] = {state, None}; | ||
| 1496 | |||
| 1497 | XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, | ||
| 1498 | PropModeReplace, (unsigned char *)data, 2); | ||
| 1388 | } | 1499 | } |
| 1389 | 1500 | ||
| 1390 | int sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, | 1501 | int sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, |
| 1391 | long d3, long d4) { | 1502 | long d3, long d4) |
| 1392 | int n; | 1503 | { |
| 1393 | Atom *protocols, mt; | 1504 | int n; |
| 1394 | int exists = 0; | 1505 | Atom *protocols, mt; |
| 1395 | XEvent ev; | 1506 | int exists = 0; |
| 1396 | 1507 | XEvent ev; | |
| 1397 | if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { | 1508 | |
| 1398 | mt = wmatom[WMProtocols]; | 1509 | if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { |
| 1399 | if (XGetWMProtocols(dpy, w, &protocols, &n)) { | 1510 | mt = wmatom[WMProtocols]; |
| 1400 | while (!exists && n--) | 1511 | if (XGetWMProtocols(dpy, w, &protocols, &n)) { |
| 1401 | exists = protocols[n] == proto; | 1512 | while (!exists && n--) |
| 1402 | XFree(protocols); | 1513 | exists = protocols[n] == proto; |
| 1403 | } | 1514 | XFree(protocols); |
| 1404 | } else { | 1515 | } |
| 1405 | exists = True; | 1516 | } else { |
| 1406 | mt = proto; | 1517 | exists = True; |
| 1407 | } | 1518 | mt = proto; |
| 1408 | 1519 | } | |
| 1409 | if (exists) { | 1520 | |
| 1410 | ev.type = ClientMessage; | 1521 | if (exists) { |
| 1411 | ev.xclient.window = w; | 1522 | ev.type = ClientMessage; |
| 1412 | ev.xclient.message_type = mt; | 1523 | ev.xclient.window = w; |
| 1413 | ev.xclient.format = 32; | 1524 | ev.xclient.message_type = mt; |
| 1414 | ev.xclient.data.l[0] = d0; | 1525 | ev.xclient.format = 32; |
| 1415 | ev.xclient.data.l[1] = d1; | 1526 | ev.xclient.data.l[0] = d0; |
| 1416 | ev.xclient.data.l[2] = d2; | 1527 | ev.xclient.data.l[1] = d1; |
| 1417 | ev.xclient.data.l[3] = d3; | 1528 | ev.xclient.data.l[2] = d2; |
| 1418 | ev.xclient.data.l[4] = d4; | 1529 | ev.xclient.data.l[3] = d3; |
| 1419 | XSendEvent(dpy, w, False, mask, &ev); | 1530 | ev.xclient.data.l[4] = d4; |
| 1420 | } | 1531 | XSendEvent(dpy, w, False, mask, &ev); |
| 1421 | return exists; | 1532 | } |
| 1422 | } | 1533 | return exists; |
| 1423 | 1534 | } | |
| 1424 | void setfocus(Client *c) { | 1535 | |
| 1425 | if (!c->neverfocus) { | 1536 | void setfocus(Client *c) |
| 1426 | XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); | 1537 | { |
| 1427 | XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW, 32, | 1538 | if (!c->neverfocus) { |
| 1428 | PropModeReplace, (unsigned char *)&(c->win), 1); | 1539 | XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
| 1429 | } | 1540 | XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW, |
| 1430 | sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], | 1541 | 32, PropModeReplace, (unsigned char *)&(c->win), |
| 1431 | CurrentTime, 0, 0, 0); | 1542 | 1); |
| 1432 | } | 1543 | } |
| 1433 | 1544 | sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], | |
| 1434 | void setfullscreen(Client *c, int fullscreen) { | 1545 | CurrentTime, 0, 0, 0); |
| 1435 | if (fullscreen && !c->isfullscreen) { | 1546 | } |
| 1436 | XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, | 1547 | |
| 1437 | PropModeReplace, (unsigned char *)&netatom[NetWMFullscreen], | 1548 | void setfullscreen(Client *c, int fullscreen) |
| 1438 | 1); | 1549 | { |
| 1439 | c->isfullscreen = 1; | 1550 | if (fullscreen && !c->isfullscreen) { |
| 1440 | c->oldstate = c->isfloating; | 1551 | XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, |
| 1441 | c->oldbw = c->bw; | 1552 | PropModeReplace, |
| 1442 | c->bw = 0; | 1553 | (unsigned char *)&netatom[NetWMFullscreen], 1); |
| 1443 | c->isfloating = 1; | 1554 | c->isfullscreen = 1; |
| 1444 | resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); | 1555 | c->oldstate = c->isfloating; |
| 1445 | XRaiseWindow(dpy, c->win); | 1556 | c->oldbw = c->bw; |
| 1446 | } else if (!fullscreen && c->isfullscreen) { | 1557 | c->bw = 0; |
| 1447 | XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, | 1558 | c->isfloating = 1; |
| 1448 | PropModeReplace, (unsigned char *)0, 0); | 1559 | resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
| 1449 | c->isfullscreen = 0; | 1560 | XRaiseWindow(dpy, c->win); |
| 1450 | c->isfloating = c->oldstate; | 1561 | } else if (!fullscreen && c->isfullscreen) { |
| 1451 | c->bw = c->oldbw; | 1562 | XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, |
| 1452 | c->x = c->oldx; | 1563 | PropModeReplace, (unsigned char *)0, 0); |
| 1453 | c->y = c->oldy; | 1564 | c->isfullscreen = 0; |
| 1454 | c->w = c->oldw; | 1565 | c->isfloating = c->oldstate; |
| 1455 | c->h = c->oldh; | 1566 | c->bw = c->oldbw; |
| 1456 | resizeclient(c, c->x, c->y, c->w, c->h); | 1567 | c->x = c->oldx; |
| 1457 | arrange(c->mon); | 1568 | c->y = c->oldy; |
| 1458 | } | 1569 | c->w = c->oldw; |
| 1459 | } | 1570 | c->h = c->oldh; |
| 1460 | 1571 | resizeclient(c, c->x, c->y, c->w, c->h); | |
| 1461 | // void setgaps(int oh, int ov, int ih, int iv) { | 1572 | arrange(c->mon); |
| 1462 | // if (oh < 0) | 1573 | } |
| 1463 | // oh = 0; | 1574 | } |
| 1464 | // if (ov < 0) | 1575 | |
| 1465 | // ov = 0; | 1576 | void setlayout(const Arg *arg) |
| 1466 | // if (ih < 0) | 1577 | { |
| 1467 | // ih = 0; | 1578 | if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
| 1468 | // if (iv < 0) | 1579 | selmon->sellt ^= 1; |
| 1469 | // iv = 0; | 1580 | if (arg && arg->v) |
| 1470 | // | 1581 | selmon->lt[selmon->sellt] = (Layout *)arg->v; |
| 1471 | // selmon->gappoh = oh; | 1582 | strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, |
| 1472 | // selmon->gappov = ov; | 1583 | sizeof selmon->ltsymbol); |
| 1473 | // selmon->gappih = ih; | 1584 | if (selmon->sel) |
| 1474 | // selmon->gappiv = iv; | 1585 | arrange(selmon); |
| 1475 | // arrange(selmon); | 1586 | else |
| 1476 | // } | 1587 | drawbar(selmon); |
| 1477 | 1588 | } | |
| 1478 | // void togglegaps(const Arg *arg) { | 1589 | |
| 1479 | // enablegaps = !enablegaps; | 1590 | void setup(void) |
| 1480 | // arrange(selmon); | 1591 | { |
| 1481 | // } | 1592 | int i; |
| 1482 | 1593 | XSetWindowAttributes wa; | |
| 1483 | // void defaultgaps(const Arg *arg) { setgaps(gappoh, gappov, gappih, gappiv); } | 1594 | Atom utf8string; |
| 1484 | // | 1595 | struct sigaction sa; |
| 1485 | // void incrgaps(const Arg *arg) { | 1596 | |
| 1486 | // setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, | 1597 | /* do not transform children into zombies when they terminate */ |
| 1487 | // selmon->gappih + arg->i, selmon->gappiv + arg->i); | 1598 | sigemptyset(&sa.sa_mask); |
| 1488 | // } | 1599 | sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; |
| 1489 | // | 1600 | sa.sa_handler = SIG_IGN; |
| 1490 | // void incrigaps(const Arg *arg) { | 1601 | sigaction(SIGCHLD, &sa, NULL); |
| 1491 | // setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, | 1602 | |
| 1492 | // selmon->gappiv + arg->i); | 1603 | /* clean up any zombies (inherited from .xinitrc etc) immediately */ |
| 1493 | // } | 1604 | while (waitpid(-1, NULL, WNOHANG) > 0) |
| 1494 | // | 1605 | ; |
| 1495 | // void incrogaps(const Arg *arg) { | 1606 | |
| 1496 | // setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih, | 1607 | /* init screen */ |
| 1497 | // selmon->gappiv); | 1608 | screen = DefaultScreen(dpy); |
| 1498 | // } | 1609 | sw = DisplayWidth(dpy, screen); |
| 1499 | 1610 | sh = DisplayHeight(dpy, screen); | |
| 1500 | // void incrohgaps(const Arg *arg) { | 1611 | root = RootWindow(dpy, screen); |
| 1501 | // setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih, | 1612 | drw = drw_create(dpy, screen, root, sw, sh); |
| 1502 | // selmon->gappiv); | 1613 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) |
| 1503 | // } | 1614 | die("no fonts could be loaded."); |
| 1504 | // | 1615 | lrpad = drw->fonts->h; |
| 1505 | // void incrovgaps(const Arg *arg) { | 1616 | bh = drw->fonts->h + 2; |
| 1506 | // setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, | 1617 | updategeom(); |
| 1507 | // selmon->gappiv); | 1618 | /* init atoms */ |
| 1508 | // } | 1619 | utf8string = XInternAtom(dpy, "UTF8_STRING", False); |
| 1509 | // | 1620 | wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
| 1510 | // void incrihgaps(const Arg *arg) { | 1621 | wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
| 1511 | // setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, | 1622 | wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
| 1512 | // selmon->gappiv); | 1623 | wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); |
| 1513 | // } | 1624 | netatom[NetActiveWindow] = |
| 1514 | // | 1625 | XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); |
| 1515 | // void incrivgaps(const Arg *arg) { | 1626 | netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
| 1516 | // setgaps(selmon->gappoh, selmon->gappov, selmon->gappih, | 1627 | netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); |
| 1517 | // selmon->gappiv + arg->i); | 1628 | netatom[NetSystemTrayOP] = |
| 1518 | // } | 1629 | XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); |
| 1519 | 1630 | netatom[NetSystemTrayOrientation] = | |
| 1520 | void setlayout(const Arg *arg) { | 1631 | XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); |
| 1521 | if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) | 1632 | netatom[NetSystemTrayOrientationHorz] = |
| 1522 | selmon->sellt ^= 1; | 1633 | XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); |
| 1523 | if (arg && arg->v) | 1634 | netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
| 1524 | selmon->lt[selmon->sellt] = (Layout *)arg->v; | 1635 | netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); |
| 1525 | strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, | 1636 | netatom[NetWMCheck] = |
| 1526 | sizeof selmon->ltsymbol); | 1637 | XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); |
| 1527 | if (selmon->sel) | 1638 | netatom[NetWMFullscreen] = |
| 1528 | arrange(selmon); | 1639 | XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); |
| 1529 | else | 1640 | netatom[NetWMWindowType] = |
| 1530 | drawbar(selmon); | 1641 | XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); |
| 1531 | } | 1642 | netatom[NetWMWindowTypeDialog] = |
| 1532 | 1643 | XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); | |
| 1533 | // /* arg > 1.0 will set mfact absolutely */ | 1644 | netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); |
| 1534 | // void setmfact(const Arg *arg) { | 1645 | xatom[Manager] = XInternAtom(dpy, "MANAGER", False); |
| 1535 | // float f; | 1646 | xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); |
| 1536 | // | 1647 | xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); |
| 1537 | // if (!arg || !selmon->lt[selmon->sellt]->arrange) | 1648 | /* init cursors */ |
| 1538 | // return; | 1649 | cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); |
| 1539 | // f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; | 1650 | cursor[CurResize] = drw_cur_create(drw, XC_sizing); |
| 1540 | // if (f < 0.05 || f > 0.95) | 1651 | cursor[CurMove] = drw_cur_create(drw, XC_fleur); |
| 1541 | // return; | 1652 | /* init appearance */ |
| 1542 | // selmon->mfact = f; | 1653 | scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); |
| 1543 | // arrange(selmon); | 1654 | for (i = 0; i < LENGTH(colors); i++) |
| 1544 | // } | 1655 | scheme[i] = drw_scm_create(drw, colors[i], 3); |
| 1545 | 1656 | /* init system tray */ | |
| 1546 | void setup(void) { | 1657 | updatesystray(); |
| 1547 | int i; | 1658 | /* init bars */ |
| 1548 | XSetWindowAttributes wa; | 1659 | updatebars(); |
| 1549 | Atom utf8string; | 1660 | updatestatus(); |
| 1550 | struct sigaction sa; | 1661 | /* supporting window for NetWMCheck */ |
| 1551 | 1662 | wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); | |
| 1552 | /* do not transform children into zombies when they terminate */ | 1663 | XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, |
| 1553 | sigemptyset(&sa.sa_mask); | 1664 | PropModeReplace, (unsigned char *)&wmcheckwin, 1); |
| 1554 | sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; | 1665 | XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, |
| 1555 | sa.sa_handler = SIG_IGN; | 1666 | PropModeReplace, (unsigned char *)"dwm", 3); |
| 1556 | sigaction(SIGCHLD, &sa, NULL); | 1667 | XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, |
| 1557 | 1668 | PropModeReplace, (unsigned char *)&wmcheckwin, 1); | |
| 1558 | /* clean up any zombies (inherited from .xinitrc etc) immediately */ | 1669 | /* EWMH support per view */ |
| 1559 | while (waitpid(-1, NULL, WNOHANG) > 0) | 1670 | XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
| 1560 | ; | 1671 | PropModeReplace, (unsigned char *)netatom, NetLast); |
| 1561 | 1672 | XDeleteProperty(dpy, root, netatom[NetClientList]); | |
| 1562 | /* init screen */ | 1673 | /* select events */ |
| 1563 | screen = DefaultScreen(dpy); | 1674 | wa.cursor = cursor[CurNormal]->cursor; |
| 1564 | sw = DisplayWidth(dpy, screen); | 1675 | wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | |
| 1565 | sh = DisplayHeight(dpy, screen); | 1676 | ButtonPressMask | PointerMotionMask | EnterWindowMask | |
| 1566 | root = RootWindow(dpy, screen); | 1677 | LeaveWindowMask | StructureNotifyMask | |
| 1567 | drw = drw_create(dpy, screen, root, sw, sh); | 1678 | PropertyChangeMask; |
| 1568 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) | 1679 | XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); |
| 1569 | die("no fonts could be loaded."); | 1680 | XSelectInput(dpy, root, wa.event_mask); |
| 1570 | lrpad = drw->fonts->h; | 1681 | grabkeys(); |
| 1571 | bh = drw->fonts->h + 2; | 1682 | focus(NULL); |
| 1572 | updategeom(); | 1683 | } |
| 1573 | /* init atoms */ | 1684 | |
| 1574 | utf8string = XInternAtom(dpy, "UTF8_STRING", False); | 1685 | void seturgent(Client *c, int urg) |
| 1575 | wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); | 1686 | { |
| 1576 | wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); | 1687 | XWMHints *wmh; |
| 1577 | wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); | 1688 | |
| 1578 | wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); | 1689 | c->isurgent = urg; |
| 1579 | netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); | 1690 | if (!(wmh = XGetWMHints(dpy, c->win))) |
| 1580 | netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); | 1691 | return; |
| 1581 | netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); | 1692 | wmh->flags = |
| 1582 | netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); | 1693 | urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); |
| 1583 | netatom[NetSystemTrayOrientation] = | 1694 | XSetWMHints(dpy, c->win, wmh); |
| 1584 | XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); | 1695 | XFree(wmh); |
| 1585 | netatom[NetSystemTrayOrientationHorz] = | 1696 | } |
| 1586 | XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); | 1697 | |
| 1587 | netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); | 1698 | void showhide(Client *c) |
| 1588 | netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); | 1699 | { |
| 1589 | netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); | 1700 | if (!c) |
| 1590 | netatom[NetWMFullscreen] = | 1701 | return; |
| 1591 | XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); | 1702 | if (ISVISIBLE(c)) { |
| 1592 | netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); | 1703 | /* show clients top down */ |
| 1593 | netatom[NetWMWindowTypeDialog] = | 1704 | XMoveWindow(dpy, c->win, c->x, c->y); |
| 1594 | XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); | 1705 | if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && |
| 1595 | netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); | 1706 | !c->isfullscreen) |
| 1596 | xatom[Manager] = XInternAtom(dpy, "MANAGER", False); | 1707 | resize(c, c->x, c->y, c->w, c->h, 0); |
| 1597 | xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); | 1708 | showhide(c->snext); |
| 1598 | xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); | 1709 | } else { |
| 1599 | /* init cursors */ | 1710 | /* hide clients bottom up */ |
| 1600 | cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); | 1711 | showhide(c->snext); |
| 1601 | cursor[CurResize] = drw_cur_create(drw, XC_sizing); | 1712 | XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); |
| 1602 | cursor[CurMove] = drw_cur_create(drw, XC_fleur); | 1713 | } |
| 1603 | /* init appearance */ | 1714 | } |
| 1604 | scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); | 1715 | |
| 1605 | for (i = 0; i < LENGTH(colors); i++) | 1716 | void spawn(const Arg *arg) |
| 1606 | scheme[i] = drw_scm_create(drw, colors[i], 3); | 1717 | { |
| 1607 | /* init system tray */ | 1718 | struct sigaction sa; |
| 1608 | updatesystray(); | 1719 | |
| 1609 | /* init bars */ | 1720 | if (arg->v == dmenucmd) |
| 1610 | updatebars(); | 1721 | dmenumon[0] = '0' + selmon->num; |
| 1611 | updatestatus(); | 1722 | if (fork() == 0) { |
| 1612 | /* supporting window for NetWMCheck */ | 1723 | if (dpy) |
| 1613 | wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); | 1724 | close(ConnectionNumber(dpy)); |
| 1614 | XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, | 1725 | setsid(); |
| 1615 | PropModeReplace, (unsigned char *)&wmcheckwin, 1); | 1726 | |
| 1616 | XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, | 1727 | sigemptyset(&sa.sa_mask); |
| 1617 | PropModeReplace, (unsigned char *)"dwm", 3); | 1728 | sa.sa_flags = 0; |
| 1618 | XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, | 1729 | sa.sa_handler = SIG_DFL; |
| 1619 | PropModeReplace, (unsigned char *)&wmcheckwin, 1); | 1730 | sigaction(SIGCHLD, &sa, NULL); |
| 1620 | /* EWMH support per view */ | 1731 | |
| 1621 | XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, | 1732 | execvp(((char **)arg->v)[0], (char **)arg->v); |
| 1622 | PropModeReplace, (unsigned char *)netatom, NetLast); | 1733 | die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]); |
| 1623 | XDeleteProperty(dpy, root, netatom[NetClientList]); | 1734 | } |
| 1624 | /* select events */ | 1735 | } |
| 1625 | wa.cursor = cursor[CurNormal]->cursor; | 1736 | |
| 1626 | wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | | 1737 | void tag(const Arg *arg) |
| 1627 | ButtonPressMask | PointerMotionMask | EnterWindowMask | | 1738 | { |
| 1628 | LeaveWindowMask | StructureNotifyMask | PropertyChangeMask; | 1739 | if (selmon->sel && arg->ui & TAGMASK) { |
| 1629 | XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); | 1740 | selmon->sel->tags = arg->ui & TAGMASK; |
| 1630 | XSelectInput(dpy, root, wa.event_mask); | 1741 | focus(NULL); |
| 1631 | grabkeys(); | 1742 | arrange(selmon); |
| 1632 | focus(NULL); | 1743 | } |
| 1633 | } | 1744 | } |
| 1634 | 1745 | ||
| 1635 | void seturgent(Client *c, int urg) { | 1746 | void tile(Monitor *m) |
| 1636 | XWMHints *wmh; | 1747 | { |
| 1637 | 1748 | unsigned int i, n, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty; | |
| 1638 | c->isurgent = urg; | 1749 | Client *c; |
| 1639 | if (!(wmh = XGetWMHints(dpy, c->win))) | 1750 | |
| 1640 | return; | 1751 | for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) |
| 1641 | wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); | 1752 | ; |
| 1642 | XSetWMHints(dpy, c->win, wmh); | 1753 | if (n == 0) |
| 1643 | XFree(wmh); | 1754 | return; |
| 1644 | } | 1755 | if (smartgaps == n) { |
| 1645 | 1756 | oe = 0; // outer gaps disabled | |
| 1646 | void showhide(Client *c) { | 1757 | } |
| 1647 | if (!c) | 1758 | |
| 1648 | return; | 1759 | if (n > m->nmaster) |
| 1649 | if (ISVISIBLE(c)) { | 1760 | mw = m->nmaster ? (m->ww + m->gappiv * ie) * m->mfact : 0; |
| 1650 | /* show clients top down */ | 1761 | else |
| 1651 | XMoveWindow(dpy, c->win, c->x, c->y); | 1762 | mw = m->ww - 2 * m->gappov * oe + m->gappiv * ie; |
| 1652 | if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && | 1763 | for (i = 0, my = ty = m->gappoh * oe, c = nexttiled(m->clients); c; |
| 1653 | !c->isfullscreen) | 1764 | c = nexttiled(c->next), i++) |
| 1654 | resize(c, c->x, c->y, c->w, c->h, 0); | 1765 | if (i < m->nmaster) { |
| 1655 | showhide(c->snext); | 1766 | r = MIN(n, m->nmaster) - i; |
| 1656 | } else { | 1767 | h = (m->wh - my - m->gappoh * oe - |
| 1657 | /* hide clients bottom up */ | 1768 | m->gappih * ie * (r - 1)) / |
| 1658 | showhide(c->snext); | 1769 | r; |
| 1659 | XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); | 1770 | resize(c, m->wx + m->gappov * oe, m->wy + my, |
| 1660 | } | 1771 | mw - (2 * c->bw) - m->gappiv * ie, |
| 1661 | } | 1772 | h - (2 * c->bw), 0); |
| 1662 | 1773 | my += HEIGHT(c) + m->gappih * ie; | |
| 1663 | void spawn(const Arg *arg) { | 1774 | |
| 1664 | struct sigaction sa; | 1775 | if (my + HEIGHT(c) < m->wh) |
| 1665 | 1776 | my += HEIGHT(c); | |
| 1666 | if (arg->v == dmenucmd) | 1777 | } else { |
| 1667 | dmenumon[0] = '0' + selmon->num; | 1778 | r = n - i; |
| 1668 | if (fork() == 0) { | 1779 | h = (m->wh - ty - m->gappoh * oe - |
| 1669 | if (dpy) | 1780 | m->gappih * ie * (r - 1)) / |
| 1670 | close(ConnectionNumber(dpy)); | 1781 | r; |
| 1671 | setsid(); | 1782 | resize(c, m->wx + mw + m->gappov * oe, m->wy + ty, |
| 1672 | 1783 | m->ww - mw - (2 * c->bw) - 2 * m->gappov * oe, | |
| 1673 | sigemptyset(&sa.sa_mask); | 1784 | h - (2 * c->bw), 0); |
| 1674 | sa.sa_flags = 0; | 1785 | ty += HEIGHT(c) + m->gappih * ie; |
| 1675 | sa.sa_handler = SIG_DFL; | 1786 | } |
| 1676 | sigaction(SIGCHLD, &sa, NULL); | 1787 | } |
| 1677 | 1788 | ||
| 1678 | execvp(((char **)arg->v)[0], (char **)arg->v); | 1789 | void togglebar(const Arg *arg) |
| 1679 | die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]); | 1790 | { |
| 1680 | } | 1791 | selmon->showbar = !selmon->showbar; |
| 1681 | } | 1792 | updatebarpos(selmon); |
| 1682 | 1793 | resizebarwin(selmon); | |
| 1683 | void tag(const Arg *arg) { | 1794 | if (showsystray) { |
| 1684 | if (selmon->sel && arg->ui & TAGMASK) { | 1795 | XWindowChanges wc; |
| 1685 | selmon->sel->tags = arg->ui & TAGMASK; | 1796 | if (!selmon->showbar) |
| 1686 | focus(NULL); | 1797 | wc.y = -bh; |
| 1687 | arrange(selmon); | 1798 | else if (selmon->showbar) { |
| 1688 | } | 1799 | wc.y = 0; |
| 1689 | } | 1800 | if (!selmon->topbar) |
| 1690 | 1801 | wc.y = selmon->mh - bh; | |
| 1691 | // void tagmon(const Arg *arg) { | 1802 | } |
| 1692 | // if (!selmon->sel || !mons->next) | 1803 | XConfigureWindow(dpy, systray->win, CWY, &wc); |
| 1693 | // return; | 1804 | } |
| 1694 | // sendmon(selmon->sel, dirtomon(arg->i)); | 1805 | arrange(selmon); |
| 1695 | // } | 1806 | } |
| 1696 | 1807 | ||
| 1697 | void tile(Monitor *m) { | 1808 | void togglefloating(const Arg *arg) |
| 1698 | unsigned int i, n, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty; | 1809 | { |
| 1699 | Client *c; | 1810 | if (!selmon->sel) |
| 1700 | 1811 | return; | |
| 1701 | for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) | 1812 | if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ |
| 1702 | ; | 1813 | return; |
| 1703 | if (n == 0) | 1814 | selmon->sel->isfloating = |
| 1704 | return; | 1815 | !selmon->sel->isfloating || selmon->sel->isfixed; |
| 1705 | if (smartgaps == n) { | 1816 | if (selmon->sel->isfloating) |
| 1706 | oe = 0; // outer gaps disabled | 1817 | resize(selmon->sel, selmon->sel->x, selmon->sel->y, |
| 1707 | } | 1818 | selmon->sel->w, selmon->sel->h, 0); |
| 1708 | 1819 | arrange(selmon); | |
| 1709 | if (n > m->nmaster) | 1820 | } |
| 1710 | mw = m->nmaster ? (m->ww + m->gappiv * ie) * m->mfact : 0; | 1821 | |
| 1711 | else | 1822 | void togglefullscr(const Arg *arg) |
| 1712 | mw = m->ww - 2 * m->gappov * oe + m->gappiv * ie; | 1823 | { |
| 1713 | for (i = 0, my = ty = m->gappoh * oe, c = nexttiled(m->clients); c; | 1824 | if (selmon->sel) |
| 1714 | c = nexttiled(c->next), i++) | 1825 | setfullscreen(selmon->sel, !selmon->sel->isfullscreen); |
| 1715 | if (i < m->nmaster) { | 1826 | } |
| 1716 | r = MIN(n, m->nmaster) - i; | 1827 | |
| 1717 | h = (m->wh - my - m->gappoh * oe - m->gappih * ie * (r - 1)) / r; | 1828 | void toggletag(const Arg *arg) |
| 1718 | resize(c, m->wx + m->gappov * oe, m->wy + my, | 1829 | { |
| 1719 | mw - (2 * c->bw) - m->gappiv * ie, h - (2 * c->bw), 0); | 1830 | unsigned int newtags; |
| 1720 | my += HEIGHT(c) + m->gappih * ie; | 1831 | |
| 1721 | 1832 | if (!selmon->sel) | |
| 1722 | if (my + HEIGHT(c) < m->wh) | 1833 | return; |
| 1723 | my += HEIGHT(c); | 1834 | newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); |
| 1724 | } else { | 1835 | if (newtags) { |
| 1725 | r = n - i; | 1836 | selmon->sel->tags = newtags; |
| 1726 | h = (m->wh - ty - m->gappoh * oe - m->gappih * ie * (r - 1)) / r; | 1837 | focus(NULL); |
| 1727 | resize(c, m->wx + mw + m->gappov * oe, m->wy + ty, | 1838 | arrange(selmon); |
| 1728 | m->ww - mw - (2 * c->bw) - 2 * m->gappov * oe, h - (2 * c->bw), 0); | 1839 | } |
| 1729 | ty += HEIGHT(c) + m->gappih * ie; | 1840 | } |
| 1730 | } | 1841 | |
| 1731 | } | 1842 | void toggleview(const Arg *arg) |
| 1732 | 1843 | { | |
| 1733 | void togglebar(const Arg *arg) { | 1844 | unsigned int newtagset = |
| 1734 | selmon->showbar = !selmon->showbar; | 1845 | selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); |
| 1735 | updatebarpos(selmon); | 1846 | |
| 1736 | resizebarwin(selmon); | 1847 | if (newtagset) { |
| 1737 | if (showsystray) { | 1848 | selmon->tagset[selmon->seltags] = newtagset; |
| 1738 | XWindowChanges wc; | 1849 | focus(NULL); |
| 1739 | if (!selmon->showbar) | 1850 | arrange(selmon); |
| 1740 | wc.y = -bh; | 1851 | } |
| 1741 | else if (selmon->showbar) { | 1852 | } |
| 1742 | wc.y = 0; | 1853 | |
| 1743 | if (!selmon->topbar) | 1854 | void unfocus(Client *c, int setfocus) |
| 1744 | wc.y = selmon->mh - bh; | 1855 | { |
| 1745 | } | 1856 | if (!c) |
| 1746 | XConfigureWindow(dpy, systray->win, CWY, &wc); | 1857 | return; |
| 1747 | } | 1858 | grabbuttons(c, 0); |
| 1748 | arrange(selmon); | 1859 | XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); |
| 1749 | } | 1860 | if (setfocus) { |
| 1750 | 1861 | XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); | |
| 1751 | void togglefloating(const Arg *arg) { | 1862 | XDeleteProperty(dpy, root, netatom[NetActiveWindow]); |
| 1752 | if (!selmon->sel) | 1863 | } |
| 1753 | return; | 1864 | } |
| 1754 | if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ | 1865 | |
| 1755 | return; | 1866 | void unmanage(Client *c, int destroyed) |
| 1756 | selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; | 1867 | { |
| 1757 | if (selmon->sel->isfloating) | 1868 | Monitor *m = c->mon; |
| 1758 | resize(selmon->sel, selmon->sel->x, selmon->sel->y, selmon->sel->w, | 1869 | XWindowChanges wc; |
| 1759 | selmon->sel->h, 0); | 1870 | |
| 1760 | arrange(selmon); | 1871 | if (c->swallowing) { |
| 1761 | } | 1872 | unswallow(c); |
| 1762 | 1873 | return; | |
| 1763 | void togglefullscr(const Arg *arg) { | 1874 | } |
| 1764 | if (selmon->sel) | 1875 | |
| 1765 | setfullscreen(selmon->sel, !selmon->sel->isfullscreen); | 1876 | Client *s = swallowingclient(c->win); |
| 1766 | } | 1877 | if (s) { |
| 1767 | 1878 | free(s->swallowing); | |
| 1768 | void toggletag(const Arg *arg) { | 1879 | s->swallowing = NULL; |
| 1769 | unsigned int newtags; | 1880 | arrange(m); |
| 1770 | 1881 | focus(NULL); | |
| 1771 | if (!selmon->sel) | 1882 | return; |
| 1772 | return; | 1883 | } |
| 1773 | newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); | 1884 | |
| 1774 | if (newtags) { | 1885 | detach(c); |
| 1775 | selmon->sel->tags = newtags; | 1886 | detachstack(c); |
| 1776 | focus(NULL); | 1887 | if (!destroyed) { |
| 1777 | arrange(selmon); | 1888 | wc.border_width = c->oldbw; |
| 1778 | } | 1889 | XGrabServer(dpy); /* avoid race conditions */ |
| 1779 | } | 1890 | XSetErrorHandler(xerrordummy); |
| 1780 | 1891 | XSelectInput(dpy, c->win, NoEventMask); | |
| 1781 | void toggleview(const Arg *arg) { | 1892 | XConfigureWindow(dpy, c->win, CWBorderWidth, |
| 1782 | unsigned int newtagset = | 1893 | &wc); /* restore border */ |
| 1783 | selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); | 1894 | XUngrabButton(dpy, AnyButton, AnyModifier, c->win); |
| 1784 | 1895 | setclientstate(c, WithdrawnState); | |
| 1785 | if (newtagset) { | 1896 | XSync(dpy, False); |
| 1786 | selmon->tagset[selmon->seltags] = newtagset; | 1897 | XSetErrorHandler(xerror); |
| 1787 | focus(NULL); | 1898 | XUngrabServer(dpy); |
| 1788 | arrange(selmon); | 1899 | } |
| 1789 | } | 1900 | free(c); |
| 1790 | } | 1901 | |
| 1791 | 1902 | if (!s) { | |
| 1792 | void unfocus(Client *c, int setfocus) { | 1903 | arrange(m); |
| 1793 | if (!c) | 1904 | focus(NULL); |
| 1794 | return; | 1905 | updateclientlist(); |
| 1795 | grabbuttons(c, 0); | 1906 | } |
| 1796 | XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); | 1907 | } |
| 1797 | if (setfocus) { | 1908 | |
| 1798 | XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); | 1909 | void unmapnotify(XEvent *e) |
| 1799 | XDeleteProperty(dpy, root, netatom[NetActiveWindow]); | 1910 | { |
| 1800 | } | 1911 | Client *c; |
| 1801 | } | 1912 | XUnmapEvent *ev = &e->xunmap; |
| 1802 | 1913 | ||
| 1803 | void unmanage(Client *c, int destroyed) { | 1914 | if ((c = wintoclient(ev->window))) { |
| 1804 | Monitor *m = c->mon; | 1915 | if (ev->send_event) |
| 1805 | XWindowChanges wc; | 1916 | setclientstate(c, WithdrawnState); |
| 1806 | 1917 | else | |
| 1807 | if (c->swallowing) { | 1918 | unmanage(c, 0); |
| 1808 | unswallow(c); | 1919 | } else if ((c = wintosystrayicon(ev->window))) { |
| 1809 | return; | 1920 | /* KLUDGE! sometimes icons occasionally unmap their windows, but |
| 1810 | } | 1921 | * do _not_ destroy them. We map those windows back */ |
| 1811 | 1922 | XMapRaised(dpy, c->win); | |
| 1812 | Client *s = swallowingclient(c->win); | 1923 | updatesystray(); |
| 1813 | if (s) { | 1924 | } |
| 1814 | free(s->swallowing); | 1925 | } |
| 1815 | s->swallowing = NULL; | 1926 | |
| 1816 | arrange(m); | 1927 | void updatebars(void) |
| 1817 | focus(NULL); | 1928 | { |
| 1818 | return; | 1929 | unsigned int w; |
| 1819 | } | 1930 | Monitor *m; |
| 1820 | 1931 | XSetWindowAttributes wa = {.override_redirect = True, | |
| 1821 | detach(c); | 1932 | .background_pixmap = ParentRelative, |
| 1822 | detachstack(c); | 1933 | .event_mask = |
| 1823 | if (!destroyed) { | 1934 | ButtonPressMask | ExposureMask}; |
| 1824 | wc.border_width = c->oldbw; | 1935 | XClassHint ch = {"dwm", "dwm"}; |
| 1825 | XGrabServer(dpy); /* avoid race conditions */ | 1936 | for (m = mons; m; m = m->next) { |
| 1826 | XSetErrorHandler(xerrordummy); | 1937 | if (m->barwin) |
| 1827 | XSelectInput(dpy, c->win, NoEventMask); | 1938 | continue; |
| 1828 | XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ | 1939 | w = m->ww; |
| 1829 | XUngrabButton(dpy, AnyButton, AnyModifier, c->win); | 1940 | if (showsystray && m == systraytomon(m)) |
| 1830 | setclientstate(c, WithdrawnState); | 1941 | w -= getsystraywidth(); |
| 1831 | XSync(dpy, False); | 1942 | m->barwin = XCreateWindow( |
| 1832 | XSetErrorHandler(xerror); | 1943 | dpy, root, m->wx, m->by, w, bh, 0, |
| 1833 | XUngrabServer(dpy); | 1944 | DefaultDepth(dpy, screen), CopyFromParent, |
| 1834 | } | 1945 | DefaultVisual(dpy, screen), |
| 1835 | free(c); | 1946 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
| 1836 | 1947 | XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); | |
| 1837 | if (!s) { | 1948 | if (showsystray && m == systraytomon(m)) |
| 1838 | arrange(m); | 1949 | XMapRaised(dpy, systray->win); |
| 1839 | focus(NULL); | 1950 | XMapRaised(dpy, m->barwin); |
| 1840 | updateclientlist(); | 1951 | XSetClassHint(dpy, m->barwin, &ch); |
| 1841 | } | 1952 | } |
| 1842 | } | 1953 | } |
| 1843 | 1954 | ||
| 1844 | void unmapnotify(XEvent *e) { | 1955 | void updatebarpos(Monitor *m) |
| 1845 | Client *c; | 1956 | { |
| 1846 | XUnmapEvent *ev = &e->xunmap; | 1957 | m->wy = m->my; |
| 1847 | 1958 | m->wh = m->mh; | |
| 1848 | if ((c = wintoclient(ev->window))) { | 1959 | if (m->showbar) { |
| 1849 | if (ev->send_event) | 1960 | m->wh -= bh; |
| 1850 | setclientstate(c, WithdrawnState); | 1961 | m->by = m->topbar ? m->wy : m->wy + m->wh; |
| 1851 | else | 1962 | m->wy = m->topbar ? m->wy + bh : m->wy; |
| 1852 | unmanage(c, 0); | 1963 | } else |
| 1853 | } else if ((c = wintosystrayicon(ev->window))) { | 1964 | m->by = -bh; |
| 1854 | /* KLUDGE! sometimes icons occasionally unmap their windows, but do | 1965 | } |
| 1855 | * _not_ destroy them. We map those windows back */ | 1966 | |
| 1856 | XMapRaised(dpy, c->win); | 1967 | void updateclientlist() |
| 1857 | updatesystray(); | 1968 | { |
| 1858 | } | 1969 | Client *c; |
| 1859 | } | 1970 | Monitor *m; |
| 1860 | 1971 | ||
| 1861 | void updatebars(void) { | 1972 | XDeleteProperty(dpy, root, netatom[NetClientList]); |
| 1862 | unsigned int w; | 1973 | for (m = mons; m; m = m->next) |
| 1863 | Monitor *m; | 1974 | for (c = m->clients; c; c = c->next) |
| 1864 | XSetWindowAttributes wa = {.override_redirect = True, | 1975 | XChangeProperty(dpy, root, netatom[NetClientList], |
| 1865 | .background_pixmap = ParentRelative, | 1976 | XA_WINDOW, 32, PropModeAppend, |
| 1866 | .event_mask = ButtonPressMask | ExposureMask}; | 1977 | (unsigned char *)&(c->win), 1); |
| 1867 | XClassHint ch = {"dwm", "dwm"}; | 1978 | } |
| 1868 | for (m = mons; m; m = m->next) { | 1979 | |
| 1869 | if (m->barwin) | 1980 | int updategeom(void) |
| 1870 | continue; | 1981 | { |
| 1871 | w = m->ww; | 1982 | int dirty = 0; |
| 1872 | if (showsystray && m == systraytomon(m)) | ||
| 1873 | w -= getsystraywidth(); | ||
| 1874 | m->barwin = XCreateWindow( | ||
| 1875 | dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), | ||
| 1876 | CopyFromParent, DefaultVisual(dpy, screen), | ||
| 1877 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | ||
| 1878 | XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); | ||
| 1879 | if (showsystray && m == systraytomon(m)) | ||
| 1880 | XMapRaised(dpy, systray->win); | ||
| 1881 | XMapRaised(dpy, m->barwin); | ||
| 1882 | XSetClassHint(dpy, m->barwin, &ch); | ||
| 1883 | } | ||
| 1884 | } | ||
| 1885 | |||
| 1886 | void updatebarpos(Monitor *m) { | ||
| 1887 | m->wy = m->my; | ||
| 1888 | m->wh = m->mh; | ||
| 1889 | if (m->showbar) { | ||
| 1890 | m->wh -= bh; | ||
| 1891 | m->by = m->topbar ? m->wy : m->wy + m->wh; | ||
| 1892 | m->wy = m->topbar ? m->wy + bh : m->wy; | ||
| 1893 | } else | ||
| 1894 | m->by = -bh; | ||
| 1895 | } | ||
| 1896 | |||
| 1897 | void updateclientlist() { | ||
| 1898 | Client *c; | ||
| 1899 | Monitor *m; | ||
| 1900 | |||
| 1901 | XDeleteProperty(dpy, root, netatom[NetClientList]); | ||
| 1902 | for (m = mons; m; m = m->next) | ||
| 1903 | for (c = m->clients; c; c = c->next) | ||
| 1904 | XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, | ||
| 1905 | PropModeAppend, (unsigned char *)&(c->win), 1); | ||
| 1906 | } | ||
| 1907 | |||
| 1908 | int updategeom(void) { | ||
| 1909 | int dirty = 0; | ||
| 1910 | 1983 | ||
| 1911 | #ifdef XINERAMA | 1984 | #ifdef XINERAMA |
| 1912 | if (XineramaIsActive(dpy)) { | 1985 | if (XineramaIsActive(dpy)) { |
| 1913 | int i, j, n, nn; | 1986 | int i, j, n, nn; |
| 1914 | Client *c; | 1987 | Client *c; |
| 1915 | Monitor *m; | 1988 | Monitor *m; |
| 1916 | XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); | 1989 | XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); |
| 1917 | XineramaScreenInfo *unique = NULL; | 1990 | XineramaScreenInfo *unique = NULL; |
| 1918 | 1991 | ||
| 1919 | for (n = 0, m = mons; m; m = m->next, n++) | 1992 | for (n = 0, m = mons; m; m = m->next, n++) |
| 1920 | ; | 1993 | ; |
| 1921 | /* only consider unique geometries as separate screens */ | 1994 | /* only consider unique geometries as separate screens */ |
| 1922 | unique = ecalloc(nn, sizeof(XineramaScreenInfo)); | 1995 | unique = ecalloc(nn, sizeof(XineramaScreenInfo)); |
| 1923 | for (i = 0, j = 0; i < nn; i++) | 1996 | for (i = 0, j = 0; i < nn; i++) |
| 1924 | if (isuniquegeom(unique, j, &info[i])) | 1997 | if (isuniquegeom(unique, j, &info[i])) |
| 1925 | memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); | 1998 | memcpy(&unique[j++], &info[i], |
| 1926 | XFree(info); | 1999 | sizeof(XineramaScreenInfo)); |
| 1927 | nn = j; | 2000 | XFree(info); |
| 1928 | 2001 | nn = j; | |
| 1929 | /* new monitors if nn > n */ | 2002 | |
| 1930 | for (i = n; i < nn; i++) { | 2003 | /* new monitors if nn > n */ |
| 1931 | for (m = mons; m && m->next; m = m->next) | 2004 | for (i = n; i < nn; i++) { |
| 1932 | ; | 2005 | for (m = mons; m && m->next; m = m->next) |
| 1933 | if (m) | 2006 | ; |
| 1934 | m->next = createmon(); | 2007 | if (m) |
| 1935 | else | 2008 | m->next = createmon(); |
| 1936 | mons = createmon(); | 2009 | else |
| 1937 | } | 2010 | mons = createmon(); |
| 1938 | for (i = 0, m = mons; i < nn && m; m = m->next, i++) | 2011 | } |
| 1939 | if (i >= n || unique[i].x_org != m->mx || unique[i].y_org != m->my || | 2012 | for (i = 0, m = mons; i < nn && m; m = m->next, i++) |
| 1940 | unique[i].width != m->mw || unique[i].height != m->mh) { | 2013 | if (i >= n || unique[i].x_org != m->mx || |
| 1941 | dirty = 1; | 2014 | unique[i].y_org != m->my || |
| 1942 | m->num = i; | 2015 | unique[i].width != m->mw || |
| 1943 | m->mx = m->wx = unique[i].x_org; | 2016 | unique[i].height != m->mh) { |
| 1944 | m->my = m->wy = unique[i].y_org; | 2017 | dirty = 1; |
| 1945 | m->mw = m->ww = unique[i].width; | 2018 | m->num = i; |
| 1946 | m->mh = m->wh = unique[i].height; | 2019 | m->mx = m->wx = unique[i].x_org; |
| 1947 | updatebarpos(m); | 2020 | m->my = m->wy = unique[i].y_org; |
| 1948 | } | 2021 | m->mw = m->ww = unique[i].width; |
| 1949 | /* removed monitors if n > nn */ | 2022 | m->mh = m->wh = unique[i].height; |
| 1950 | for (i = nn; i < n; i++) { | 2023 | updatebarpos(m); |
| 1951 | for (m = mons; m && m->next; m = m->next) | 2024 | } |
| 1952 | ; | 2025 | /* removed monitors if n > nn */ |
| 1953 | while ((c = m->clients)) { | 2026 | for (i = nn; i < n; i++) { |
| 1954 | dirty = 1; | 2027 | for (m = mons; m && m->next; m = m->next) |
| 1955 | m->clients = c->next; | 2028 | ; |
| 1956 | detachstack(c); | 2029 | while ((c = m->clients)) { |
| 1957 | c->mon = mons; | 2030 | dirty = 1; |
| 1958 | attach(c); | 2031 | m->clients = c->next; |
| 1959 | attachstack(c); | 2032 | detachstack(c); |
| 1960 | } | 2033 | c->mon = mons; |
| 1961 | if (m == selmon) | 2034 | attach(c); |
| 1962 | selmon = mons; | 2035 | attachstack(c); |
| 1963 | cleanupmon(m); | 2036 | } |
| 1964 | } | 2037 | if (m == selmon) |
| 1965 | free(unique); | 2038 | selmon = mons; |
| 1966 | } else | 2039 | cleanupmon(m); |
| 1967 | #endif /* XINERAMA */ | 2040 | } |
| 1968 | { /* default monitor setup */ | 2041 | free(unique); |
| 1969 | if (!mons) | 2042 | } else |
| 1970 | mons = createmon(); | 2043 | #endif /* XINERAMA */ |
| 1971 | if (mons->mw != sw || mons->mh != sh) { | 2044 | { /* default monitor setup */ |
| 1972 | dirty = 1; | 2045 | if (!mons) |
| 1973 | mons->mw = mons->ww = sw; | 2046 | mons = createmon(); |
| 1974 | mons->mh = mons->wh = sh; | 2047 | if (mons->mw != sw || mons->mh != sh) { |
| 1975 | updatebarpos(mons); | 2048 | dirty = 1; |
| 1976 | } | 2049 | mons->mw = mons->ww = sw; |
| 1977 | } | 2050 | mons->mh = mons->wh = sh; |
| 1978 | if (dirty) { | 2051 | updatebarpos(mons); |
| 1979 | selmon = mons; | 2052 | } |
| 1980 | selmon = wintomon(root); | 2053 | } |
| 1981 | } | 2054 | if (dirty) { |
| 1982 | return dirty; | 2055 | selmon = mons; |
| 1983 | } | 2056 | selmon = wintomon(root); |
| 1984 | 2057 | } | |
| 1985 | void updatenumlockmask(void) { | 2058 | return dirty; |
| 1986 | unsigned int i, j; | 2059 | } |
| 1987 | XModifierKeymap *modmap; | 2060 | |
| 1988 | 2061 | void updatenumlockmask(void) | |
| 1989 | numlockmask = 0; | 2062 | { |
| 1990 | modmap = XGetModifierMapping(dpy); | 2063 | unsigned int i, j; |
| 1991 | for (i = 0; i < 8; i++) | 2064 | XModifierKeymap *modmap; |
| 1992 | for (j = 0; j < modmap->max_keypermod; j++) | 2065 | |
| 1993 | if (modmap->modifiermap[i * modmap->max_keypermod + j] == | 2066 | numlockmask = 0; |
| 1994 | XKeysymToKeycode(dpy, XK_Num_Lock)) | 2067 | modmap = XGetModifierMapping(dpy); |
| 1995 | numlockmask = (1 << i); | 2068 | for (i = 0; i < 8; i++) |
| 1996 | XFreeModifiermap(modmap); | 2069 | for (j = 0; j < modmap->max_keypermod; j++) |
| 1997 | } | 2070 | if (modmap |
| 1998 | 2071 | ->modifiermap[i * modmap->max_keypermod + j] == | |
| 1999 | void updatesizehints(Client *c) { | 2072 | XKeysymToKeycode(dpy, XK_Num_Lock)) |
| 2000 | long msize; | 2073 | numlockmask = (1 << i); |
| 2001 | XSizeHints size; | 2074 | XFreeModifiermap(modmap); |
| 2002 | 2075 | } | |
| 2003 | if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) | 2076 | |
| 2004 | /* size is uninitialized, ensure that size.flags aren't used */ | 2077 | void updatesizehints(Client *c) |
| 2005 | size.flags = PSize; | 2078 | { |
| 2006 | if (size.flags & PBaseSize) { | 2079 | long msize; |
| 2007 | c->basew = size.base_width; | 2080 | XSizeHints size; |
| 2008 | c->baseh = size.base_height; | 2081 | |
| 2009 | } else if (size.flags & PMinSize) { | 2082 | if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) |
| 2010 | c->basew = size.min_width; | 2083 | /* size is uninitialized, ensure that size.flags aren't used */ |
| 2011 | c->baseh = size.min_height; | 2084 | size.flags = PSize; |
| 2012 | } else | 2085 | if (size.flags & PBaseSize) { |
| 2013 | c->basew = c->baseh = 0; | 2086 | c->basew = size.base_width; |
| 2014 | if (size.flags & PResizeInc) { | 2087 | c->baseh = size.base_height; |
| 2015 | c->incw = size.width_inc; | 2088 | } else if (size.flags & PMinSize) { |
| 2016 | c->inch = size.height_inc; | 2089 | c->basew = size.min_width; |
| 2017 | } else | 2090 | c->baseh = size.min_height; |
| 2018 | c->incw = c->inch = 0; | 2091 | } else |
| 2019 | if (size.flags & PMaxSize) { | 2092 | c->basew = c->baseh = 0; |
| 2020 | c->maxw = size.max_width; | 2093 | if (size.flags & PResizeInc) { |
| 2021 | c->maxh = size.max_height; | 2094 | c->incw = size.width_inc; |
| 2022 | } else | 2095 | c->inch = size.height_inc; |
| 2023 | c->maxw = c->maxh = 0; | 2096 | } else |
| 2024 | if (size.flags & PMinSize) { | 2097 | c->incw = c->inch = 0; |
| 2025 | c->minw = size.min_width; | 2098 | if (size.flags & PMaxSize) { |
| 2026 | c->minh = size.min_height; | 2099 | c->maxw = size.max_width; |
| 2027 | } else if (size.flags & PBaseSize) { | 2100 | c->maxh = size.max_height; |
| 2028 | c->minw = size.base_width; | 2101 | } else |
| 2029 | c->minh = size.base_height; | 2102 | c->maxw = c->maxh = 0; |
| 2030 | } else | 2103 | if (size.flags & PMinSize) { |
| 2031 | c->minw = c->minh = 0; | 2104 | c->minw = size.min_width; |
| 2032 | if (size.flags & PAspect) { | 2105 | c->minh = size.min_height; |
| 2033 | c->mina = (float)size.min_aspect.y / size.min_aspect.x; | 2106 | } else if (size.flags & PBaseSize) { |
| 2034 | c->maxa = (float)size.max_aspect.x / size.max_aspect.y; | 2107 | c->minw = size.base_width; |
| 2035 | } else | 2108 | c->minh = size.base_height; |
| 2036 | c->maxa = c->mina = 0.0; | 2109 | } else |
| 2037 | c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); | 2110 | c->minw = c->minh = 0; |
| 2038 | c->hintsvalid = 1; | 2111 | if (size.flags & PAspect) { |
| 2039 | } | 2112 | c->mina = (float)size.min_aspect.y / size.min_aspect.x; |
| 2040 | 2113 | c->maxa = (float)size.max_aspect.x / size.max_aspect.y; | |
| 2041 | void updatestatus(void) { | 2114 | } else |
| 2042 | if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) | 2115 | c->maxa = c->mina = 0.0; |
| 2043 | strcpy(stext, "dwm-" VERSION); | 2116 | c->isfixed = |
| 2044 | drawbar(selmon); | 2117 | (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); |
| 2045 | updatesystray(); | 2118 | c->hintsvalid = 1; |
| 2046 | } | 2119 | } |
| 2047 | 2120 | ||
| 2048 | void updatesystrayicongeom(Client *i, int w, int h) { | 2121 | void updatestatus(void) |
| 2049 | if (i) { | 2122 | { |
| 2050 | i->h = bh; | 2123 | if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) |
| 2051 | if (w == h) | 2124 | strcpy(stext, "dwm-" VERSION); |
| 2052 | i->w = bh; | 2125 | drawbar(selmon); |
| 2053 | else if (h == bh) | 2126 | updatesystray(); |
| 2054 | i->w = w; | 2127 | } |
| 2055 | else | 2128 | |
| 2056 | i->w = (int)((float)bh * ((float)w / (float)h)); | 2129 | void updatesystrayicongeom(Client *i, int w, int h) |
| 2057 | applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); | 2130 | { |
| 2058 | /* force icons into the systray dimensions if they don't want to */ | 2131 | if (i) { |
| 2059 | if (i->h > bh) { | 2132 | i->h = bh; |
| 2060 | if (i->w == i->h) | 2133 | if (w == h) |
| 2061 | i->w = bh; | 2134 | i->w = bh; |
| 2062 | else | 2135 | else if (h == bh) |
| 2063 | i->w = (int)((float)bh * ((float)i->w / (float)i->h)); | 2136 | i->w = w; |
| 2064 | i->h = bh; | 2137 | else |
| 2065 | } | 2138 | i->w = (int)((float)bh * ((float)w / (float)h)); |
| 2066 | } | 2139 | applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); |
| 2067 | } | 2140 | /* force icons into the systray dimensions if they don't want to |
| 2068 | 2141 | */ | |
| 2069 | void updatesystrayiconstate(Client *i, XPropertyEvent *ev) { | 2142 | if (i->h > bh) { |
| 2070 | long flags; | 2143 | if (i->w == i->h) |
| 2071 | int code = 0; | 2144 | i->w = bh; |
| 2072 | 2145 | else | |
| 2073 | if (!showsystray || !i || ev->atom != xatom[XembedInfo] || | 2146 | i->w = (int)((float)bh * |
| 2074 | !(flags = getatomprop(i, xatom[XembedInfo]))) | 2147 | ((float)i->w / (float)i->h)); |
| 2075 | return; | 2148 | i->h = bh; |
| 2076 | 2149 | } | |
| 2077 | if (flags & XEMBED_MAPPED && !i->tags) { | 2150 | } |
| 2078 | i->tags = 1; | 2151 | } |
| 2079 | code = XEMBED_WINDOW_ACTIVATE; | 2152 | |
| 2080 | XMapRaised(dpy, i->win); | 2153 | void updatesystrayiconstate(Client *i, XPropertyEvent *ev) |
| 2081 | setclientstate(i, NormalState); | 2154 | { |
| 2082 | } else if (!(flags & XEMBED_MAPPED) && i->tags) { | 2155 | long flags; |
| 2083 | i->tags = 0; | 2156 | int code = 0; |
| 2084 | code = XEMBED_WINDOW_DEACTIVATE; | 2157 | |
| 2085 | XUnmapWindow(dpy, i->win); | 2158 | if (!showsystray || !i || ev->atom != xatom[XembedInfo] || |
| 2086 | setclientstate(i, WithdrawnState); | 2159 | !(flags = getatomprop(i, xatom[XembedInfo]))) |
| 2087 | } else | 2160 | return; |
| 2088 | return; | 2161 | |
| 2089 | sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, | 2162 | if (flags & XEMBED_MAPPED && !i->tags) { |
| 2090 | systray->win, XEMBED_EMBEDDED_VERSION); | 2163 | i->tags = 1; |
| 2091 | } | 2164 | code = XEMBED_WINDOW_ACTIVATE; |
| 2092 | 2165 | XMapRaised(dpy, i->win); | |
| 2093 | void updatesystray(void) { | 2166 | setclientstate(i, NormalState); |
| 2094 | XSetWindowAttributes wa; | 2167 | } else if (!(flags & XEMBED_MAPPED) && i->tags) { |
| 2095 | XWindowChanges wc; | 2168 | i->tags = 0; |
| 2096 | Client *i; | 2169 | code = XEMBED_WINDOW_DEACTIVATE; |
| 2097 | Monitor *m = systraytomon(NULL); | 2170 | XUnmapWindow(dpy, i->win); |
| 2098 | unsigned int x = m->mx + m->mw; | 2171 | setclientstate(i, WithdrawnState); |
| 2099 | unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; | 2172 | } else |
| 2100 | unsigned int w = 1; | 2173 | return; |
| 2101 | 2174 | sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, | |
| 2102 | if (!showsystray) | 2175 | 0, systray->win, XEMBED_EMBEDDED_VERSION); |
| 2103 | return; | 2176 | } |
| 2104 | if (systrayonleft) | 2177 | |
| 2105 | x -= sw + lrpad / 2; | 2178 | void updatesystray(void) |
| 2106 | if (!systray) { | 2179 | { |
| 2107 | /* init systray */ | 2180 | XSetWindowAttributes wa; |
| 2108 | if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) | 2181 | XWindowChanges wc; |
| 2109 | die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); | 2182 | Client *i; |
| 2110 | systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, | 2183 | Monitor *m = systraytomon(NULL); |
| 2111 | scheme[SchemeSel][ColBg].pixel); | 2184 | unsigned int x = m->mx + m->mw; |
| 2112 | wa.event_mask = ButtonPressMask | ExposureMask; | 2185 | unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; |
| 2113 | wa.override_redirect = True; | 2186 | unsigned int w = 1; |
| 2114 | wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; | 2187 | |
| 2115 | XSelectInput(dpy, systray->win, SubstructureNotifyMask); | 2188 | if (!showsystray) |
| 2116 | XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], | 2189 | return; |
| 2117 | XA_CARDINAL, 32, PropModeReplace, | 2190 | if (systrayonleft) |
| 2118 | (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); | 2191 | x -= sw + lrpad / 2; |
| 2119 | XChangeWindowAttributes( | 2192 | if (!systray) { |
| 2120 | dpy, systray->win, CWEventMask | CWOverrideRedirect | CWBackPixel, &wa); | 2193 | /* init systray */ |
| 2121 | XMapRaised(dpy, systray->win); | 2194 | if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) |
| 2122 | XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); | 2195 | die("fatal: could not malloc() %u bytes\n", |
| 2123 | if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { | 2196 | sizeof(Systray)); |
| 2124 | sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, | 2197 | systray->win = |
| 2125 | netatom[NetSystemTray], systray->win, 0, 0); | 2198 | XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, |
| 2126 | XSync(dpy, False); | 2199 | scheme[SchemeSel][ColBg].pixel); |
| 2127 | } else { | 2200 | wa.event_mask = ButtonPressMask | ExposureMask; |
| 2128 | fprintf(stderr, "dwm: unable to obtain system tray.\n"); | 2201 | wa.override_redirect = True; |
| 2129 | free(systray); | 2202 | wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
| 2130 | systray = NULL; | 2203 | XSelectInput(dpy, systray->win, SubstructureNotifyMask); |
| 2131 | return; | 2204 | XChangeProperty( |
| 2132 | } | 2205 | dpy, systray->win, netatom[NetSystemTrayOrientation], |
| 2133 | } | 2206 | XA_CARDINAL, 32, PropModeReplace, |
| 2134 | for (w = 0, i = systray->icons; i; i = i->next) { | 2207 | (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); |
| 2135 | /* make sure the background color stays the same */ | 2208 | XChangeWindowAttributes( |
| 2136 | wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; | 2209 | dpy, systray->win, |
| 2137 | XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); | 2210 | CWEventMask | CWOverrideRedirect | CWBackPixel, &wa); |
| 2138 | XMapRaised(dpy, i->win); | 2211 | XMapRaised(dpy, systray->win); |
| 2139 | w += systrayspacing; | 2212 | XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, |
| 2140 | i->x = w; | 2213 | CurrentTime); |
| 2141 | XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); | 2214 | if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == |
| 2142 | w += i->w; | 2215 | systray->win) { |
| 2143 | if (i->mon != m) | 2216 | sendevent(root, xatom[Manager], StructureNotifyMask, |
| 2144 | i->mon = m; | 2217 | CurrentTime, netatom[NetSystemTray], |
| 2145 | } | 2218 | systray->win, 0, 0); |
| 2146 | w = w ? w + systrayspacing : 1; | 2219 | XSync(dpy, False); |
| 2147 | x -= w; | 2220 | } else { |
| 2148 | XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); | 2221 | fprintf(stderr, "dwm: unable to obtain system tray.\n"); |
| 2149 | wc.x = x; | 2222 | free(systray); |
| 2150 | wc.y = m->by; | 2223 | systray = NULL; |
| 2151 | wc.width = w; | 2224 | return; |
| 2152 | wc.height = bh; | 2225 | } |
| 2153 | wc.stack_mode = Above; | 2226 | } |
| 2154 | wc.sibling = m->barwin; | 2227 | for (w = 0, i = systray->icons; i; i = i->next) { |
| 2155 | XConfigureWindow(dpy, systray->win, | 2228 | /* make sure the background color stays the same */ |
| 2156 | CWX | CWY | CWWidth | CWHeight | CWSibling | CWStackMode, | 2229 | wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
| 2157 | &wc); | 2230 | XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); |
| 2158 | XMapWindow(dpy, systray->win); | 2231 | XMapRaised(dpy, i->win); |
| 2159 | XMapSubwindows(dpy, systray->win); | 2232 | w += systrayspacing; |
| 2160 | /* redraw background */ | 2233 | i->x = w; |
| 2161 | XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); | 2234 | XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); |
| 2162 | XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); | 2235 | w += i->w; |
| 2163 | XSync(dpy, False); | 2236 | if (i->mon != m) |
| 2164 | } | 2237 | i->mon = m; |
| 2165 | 2238 | } | |
| 2166 | void updatetitle(Client *c) { | 2239 | w = w ? w + systrayspacing : 1; |
| 2167 | if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) | 2240 | x -= w; |
| 2168 | gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); | 2241 | XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); |
| 2169 | if (c->name[0] == '\0') /* hack to mark broken clients */ | 2242 | wc.x = x; |
| 2170 | strcpy(c->name, broken); | 2243 | wc.y = m->by; |
| 2171 | } | 2244 | wc.width = w; |
| 2172 | 2245 | wc.height = bh; | |
| 2173 | void updatewindowtype(Client *c) { | 2246 | wc.stack_mode = Above; |
| 2174 | Atom state = getatomprop(c, netatom[NetWMState]); | 2247 | wc.sibling = m->barwin; |
| 2175 | Atom wtype = getatomprop(c, netatom[NetWMWindowType]); | 2248 | XConfigureWindow( |
| 2176 | 2249 | dpy, systray->win, | |
| 2177 | if (state == netatom[NetWMFullscreen]) | 2250 | CWX | CWY | CWWidth | CWHeight | CWSibling | CWStackMode, &wc); |
| 2178 | setfullscreen(c, 1); | 2251 | XMapWindow(dpy, systray->win); |
| 2179 | if (wtype == netatom[NetWMWindowTypeDialog]) | 2252 | XMapSubwindows(dpy, systray->win); |
| 2180 | c->isfloating = 1; | 2253 | /* redraw background */ |
| 2181 | } | 2254 | XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); |
| 2182 | 2255 | XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); | |
| 2183 | void updatewmhints(Client *c) { | 2256 | XSync(dpy, False); |
| 2184 | XWMHints *wmh; | 2257 | } |
| 2185 | 2258 | ||
| 2186 | if ((wmh = XGetWMHints(dpy, c->win))) { | 2259 | void updatetitle(Client *c) |
| 2187 | if (c == selmon->sel && wmh->flags & XUrgencyHint) { | 2260 | { |
| 2188 | wmh->flags &= ~XUrgencyHint; | 2261 | if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) |
| 2189 | XSetWMHints(dpy, c->win, wmh); | 2262 | gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); |
| 2190 | } else | 2263 | if (c->name[0] == '\0') /* hack to mark broken clients */ |
| 2191 | c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; | 2264 | strcpy(c->name, broken); |
| 2192 | if (wmh->flags & InputHint) | 2265 | } |
| 2193 | c->neverfocus = !wmh->input; | 2266 | |
| 2194 | else | 2267 | void updatewindowtype(Client *c) |
| 2195 | c->neverfocus = 0; | 2268 | { |
| 2196 | XFree(wmh); | 2269 | Atom state = getatomprop(c, netatom[NetWMState]); |
| 2197 | } | 2270 | Atom wtype = getatomprop(c, netatom[NetWMWindowType]); |
| 2198 | } | 2271 | |
| 2199 | 2272 | if (state == netatom[NetWMFullscreen]) | |
| 2200 | void view(const Arg *arg) { | 2273 | setfullscreen(c, 1); |
| 2201 | if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) | 2274 | if (wtype == netatom[NetWMWindowTypeDialog]) |
| 2202 | return; | 2275 | c->isfloating = 1; |
| 2203 | selmon->seltags ^= 1; /* toggle sel tagset */ | 2276 | } |
| 2204 | if (arg->ui & TAGMASK) | 2277 | |
| 2205 | selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; | 2278 | void updatewmhints(Client *c) |
| 2206 | focus(NULL); | 2279 | { |
| 2207 | arrange(selmon); | 2280 | XWMHints *wmh; |
| 2208 | } | 2281 | |
| 2209 | 2282 | if ((wmh = XGetWMHints(dpy, c->win))) { | |
| 2210 | pid_t winpid(Window w) { | 2283 | if (c == selmon->sel && wmh->flags & XUrgencyHint) { |
| 2211 | 2284 | wmh->flags &= ~XUrgencyHint; | |
| 2212 | pid_t result = 0; | 2285 | XSetWMHints(dpy, c->win, wmh); |
| 2286 | } else | ||
| 2287 | c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; | ||
| 2288 | if (wmh->flags & InputHint) | ||
| 2289 | c->neverfocus = !wmh->input; | ||
| 2290 | else | ||
| 2291 | c->neverfocus = 0; | ||
| 2292 | XFree(wmh); | ||
| 2293 | } | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | void view(const Arg *arg) | ||
| 2297 | { | ||
| 2298 | if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) | ||
| 2299 | return; | ||
| 2300 | selmon->seltags ^= 1; /* toggle sel tagset */ | ||
| 2301 | if (arg->ui & TAGMASK) | ||
| 2302 | selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; | ||
| 2303 | focus(NULL); | ||
| 2304 | arrange(selmon); | ||
| 2305 | } | ||
| 2306 | |||
| 2307 | pid_t winpid(Window w) | ||
| 2308 | { | ||
| 2309 | |||
| 2310 | pid_t result = 0; | ||
| 2213 | 2311 | ||
| 2214 | #ifdef __linux__ | 2312 | #ifdef __linux__ |
| 2215 | xcb_res_client_id_spec_t spec = {0}; | 2313 | xcb_res_client_id_spec_t spec = {0}; |
| 2216 | spec.client = w; | 2314 | spec.client = w; |
| 2217 | spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; | 2315 | spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; |
| 2218 | 2316 | ||
| 2219 | xcb_generic_error_t *e = NULL; | 2317 | xcb_generic_error_t *e = NULL; |
| 2220 | xcb_res_query_client_ids_cookie_t c = | 2318 | xcb_res_query_client_ids_cookie_t c = |
| 2221 | xcb_res_query_client_ids(xcon, 1, &spec); | 2319 | xcb_res_query_client_ids(xcon, 1, &spec); |
| 2222 | xcb_res_query_client_ids_reply_t *r = | 2320 | xcb_res_query_client_ids_reply_t *r = |
| 2223 | xcb_res_query_client_ids_reply(xcon, c, &e); | 2321 | xcb_res_query_client_ids_reply(xcon, c, &e); |
| 2224 | 2322 | ||
| 2225 | if (!r) | 2323 | if (!r) |
| 2226 | return (pid_t)0; | 2324 | return (pid_t)0; |
| 2227 | 2325 | ||
| 2228 | xcb_res_client_id_value_iterator_t i = | 2326 | xcb_res_client_id_value_iterator_t i = |
| 2229 | xcb_res_query_client_ids_ids_iterator(r); | 2327 | xcb_res_query_client_ids_ids_iterator(r); |
| 2230 | for (; i.rem; xcb_res_client_id_value_next(&i)) { | 2328 | for (; i.rem; xcb_res_client_id_value_next(&i)) { |
| 2231 | spec = i.data->spec; | 2329 | spec = i.data->spec; |
| 2232 | if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { | 2330 | if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { |
| 2233 | uint32_t *t = xcb_res_client_id_value_value(i.data); | 2331 | uint32_t *t = xcb_res_client_id_value_value(i.data); |
| 2234 | result = *t; | 2332 | result = *t; |
| 2235 | break; | 2333 | break; |
| 2236 | } | 2334 | } |
| 2237 | } | 2335 | } |
| 2238 | 2336 | ||
| 2239 | free(r); | 2337 | free(r); |
| 2240 | 2338 | ||
| 2241 | if (result == (pid_t)-1) | 2339 | if (result == (pid_t)-1) |
| 2242 | result = 0; | 2340 | result = 0; |
| 2243 | 2341 | ||
| 2244 | #endif /* __linux__ */ | 2342 | #endif /* __linux__ */ |
| 2245 | 2343 | ||
| 2246 | #ifdef __OpenBSD__ | 2344 | #ifdef __OpenBSD__ |
| 2247 | Atom type; | 2345 | Atom type; |
| 2248 | int format; | 2346 | int format; |
| 2249 | unsigned long len, bytes; | 2347 | unsigned long len, bytes; |
| 2250 | unsigned char *prop; | 2348 | unsigned char *prop; |
| 2251 | pid_t ret; | 2349 | pid_t ret; |
| 2252 | 2350 | ||
| 2253 | if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, | 2351 | if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, |
| 2254 | False, AnyPropertyType, &type, &format, &len, &bytes, | 2352 | False, AnyPropertyType, &type, &format, &len, |
| 2255 | &prop) != Success || | 2353 | &bytes, &prop) != Success || |
| 2256 | !prop) | 2354 | !prop) |
| 2257 | return 0; | 2355 | return 0; |
| 2258 | 2356 | ||
| 2259 | ret = *(pid_t *)prop; | 2357 | ret = *(pid_t *)prop; |
| 2260 | XFree(prop); | 2358 | XFree(prop); |
| 2261 | result = ret; | 2359 | result = ret; |
| 2262 | 2360 | ||
| 2263 | #endif /* __OpenBSD__ */ | 2361 | #endif /* __OpenBSD__ */ |
| 2264 | return result; | 2362 | return result; |
| 2265 | } | 2363 | } |
| 2266 | 2364 | ||
| 2267 | pid_t getparentprocess(pid_t p) { | 2365 | pid_t getparentprocess(pid_t p) |
| 2268 | unsigned int v = 0; | 2366 | { |
| 2367 | unsigned int v = 0; | ||
| 2269 | 2368 | ||
| 2270 | #ifdef __linux__ | 2369 | #ifdef __linux__ |
| 2271 | FILE *f; | 2370 | FILE *f; |
| 2272 | char buf[256]; | 2371 | char buf[256]; |
| 2273 | snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); | 2372 | snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); |
| 2274 | 2373 | ||
| 2275 | if (!(f = fopen(buf, "r"))) | 2374 | if (!(f = fopen(buf, "r"))) |
| 2276 | return 0; | 2375 | return 0; |
| 2277 | 2376 | ||
| 2278 | fscanf(f, "%*u %*s %*c %u", &v); | 2377 | fscanf(f, "%*u %*s %*c %u", &v); |
| 2279 | fclose(f); | 2378 | fclose(f); |
| 2280 | #endif /* __linux__ */ | 2379 | #endif /* __linux__ */ |
| 2281 | 2380 | ||
| 2282 | #ifdef __OpenBSD__ | 2381 | #ifdef __OpenBSD__ |
| 2283 | int n; | 2382 | int n; |
| 2284 | kvm_t *kd; | 2383 | kvm_t *kd; |
| 2285 | struct kinfo_proc *kp; | 2384 | struct kinfo_proc *kp; |
| 2286 | 2385 | ||
| 2287 | kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); | 2386 | kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); |
| 2288 | if (!kd) | 2387 | if (!kd) |
| 2289 | return 0; | 2388 | return 0; |
| 2290 | 2389 | ||
| 2291 | kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); | 2390 | kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); |
| 2292 | v = kp->p_ppid; | 2391 | v = kp->p_ppid; |
| 2293 | #endif /* __OpenBSD__ */ | 2392 | #endif /* __OpenBSD__ */ |
| 2294 | 2393 | ||
| 2295 | return (pid_t)v; | 2394 | return (pid_t)v; |
| 2296 | } | 2395 | } |
| 2297 | 2396 | ||
| 2298 | int isdescprocess(pid_t p, pid_t c) { | 2397 | int isdescprocess(pid_t p, pid_t c) |
| 2299 | while (p != c && c != 0) | 2398 | { |
| 2300 | c = getparentprocess(c); | 2399 | while (p != c && c != 0) |
| 2400 | c = getparentprocess(c); | ||
| 2301 | 2401 | ||
| 2302 | return (int)c; | 2402 | return (int)c; |
| 2303 | } | 2403 | } |
| 2304 | 2404 | ||
| 2305 | Client *termforwin(const Client *w) { | 2405 | Client *termforwin(const Client *w) |
| 2306 | Client *c; | 2406 | { |
| 2307 | Monitor *m; | 2407 | Client *c; |
| 2408 | Monitor *m; | ||
| 2308 | 2409 | ||
| 2309 | if (!w->pid || w->isterminal) | 2410 | if (!w->pid || w->isterminal) |
| 2310 | return NULL; | 2411 | return NULL; |
| 2311 | 2412 | ||
| 2312 | for (m = mons; m; m = m->next) { | 2413 | for (m = mons; m; m = m->next) { |
| 2313 | for (c = m->clients; c; c = c->next) { | 2414 | for (c = m->clients; c; c = c->next) { |
| 2314 | if (c->isterminal && !c->swallowing && c->pid && | 2415 | if (c->isterminal && !c->swallowing && c->pid && |
| 2315 | isdescprocess(c->pid, w->pid)) | 2416 | isdescprocess(c->pid, w->pid)) |
| 2316 | return c; | 2417 | return c; |
| 2317 | } | 2418 | } |
| 2318 | } | 2419 | } |
| 2319 | 2420 | ||
| 2320 | return NULL; | 2421 | return NULL; |
| 2321 | } | 2422 | } |
| 2322 | 2423 | ||
| 2323 | Client *swallowingclient(Window w) { | 2424 | Client *swallowingclient(Window w) |
| 2324 | Client *c; | 2425 | { |
| 2325 | Monitor *m; | 2426 | Client *c; |
| 2427 | Monitor *m; | ||
| 2326 | 2428 | ||
| 2327 | for (m = mons; m; m = m->next) { | 2429 | for (m = mons; m; m = m->next) { |
| 2328 | for (c = m->clients; c; c = c->next) { | 2430 | for (c = m->clients; c; c = c->next) { |
| 2329 | if (c->swallowing && c->swallowing->win == w) | 2431 | if (c->swallowing && c->swallowing->win == w) |
| 2330 | return c; | 2432 | return c; |
| 2331 | } | 2433 | } |
| 2332 | } | 2434 | } |
| 2333 | 2435 | ||
| 2334 | return NULL; | 2436 | return NULL; |
| 2335 | } | 2437 | } |
| 2336 | 2438 | ||
| 2337 | Client *wintoclient(Window w) { | 2439 | Client *wintoclient(Window w) |
| 2338 | Client *c; | 2440 | { |
| 2339 | Monitor *m; | 2441 | Client *c; |
| 2442 | Monitor *m; | ||
| 2340 | 2443 | ||
| 2341 | for (m = mons; m; m = m->next) | 2444 | for (m = mons; m; m = m->next) |
| 2342 | for (c = m->clients; c; c = c->next) | 2445 | for (c = m->clients; c; c = c->next) |
| 2343 | if (c->win == w) | 2446 | if (c->win == w) |
| 2344 | return c; | 2447 | return c; |
| 2345 | return NULL; | 2448 | return NULL; |
| 2346 | } | 2449 | } |
| 2347 | 2450 | ||
| 2348 | Client *wintosystrayicon(Window w) { | 2451 | Client *wintosystrayicon(Window w) |
| 2349 | Client *i = NULL; | 2452 | { |
| 2453 | Client *i = NULL; | ||
| 2350 | 2454 | ||
| 2351 | if (!showsystray || !w) | 2455 | if (!showsystray || !w) |
| 2352 | return i; | 2456 | return i; |
| 2353 | for (i = systray->icons; i && i->win != w; i = i->next) | 2457 | for (i = systray->icons; i && i->win != w; i = i->next) |
| 2354 | ; | 2458 | ; |
| 2355 | return i; | 2459 | return i; |
| 2356 | } | 2460 | } |
| 2357 | 2461 | ||
| 2358 | Monitor *wintomon(Window w) { | 2462 | Monitor *wintomon(Window w) |
| 2359 | int x, y; | 2463 | { |
| 2360 | Client *c; | 2464 | int x, y; |
| 2361 | Monitor *m; | 2465 | Client *c; |
| 2466 | Monitor *m; | ||
| 2362 | 2467 | ||
| 2363 | if (w == root && getrootptr(&x, &y)) | 2468 | if (w == root && getrootptr(&x, &y)) |
| 2364 | return recttomon(x, y, 1, 1); | 2469 | return recttomon(x, y, 1, 1); |
| 2365 | for (m = mons; m; m = m->next) | 2470 | for (m = mons; m; m = m->next) |
| 2366 | if (w == m->barwin) | 2471 | if (w == m->barwin) |
| 2367 | return m; | 2472 | return m; |
| 2368 | if ((c = wintoclient(w))) | 2473 | if ((c = wintoclient(w))) |
| 2369 | return c->mon; | 2474 | return c->mon; |
| 2370 | return selmon; | 2475 | return selmon; |
| 2371 | } | 2476 | } |
| 2372 | 2477 | ||
| 2373 | /* There's no way to check accesses to destroyed windows, thus those cases are | 2478 | /* There's no way to check accesses to destroyed windows, thus those cases are |
| 2374 | * ignored (especially on UnmapNotify's). Other types of errors call Xlibs | 2479 | * ignored (especially on UnmapNotify's). Other types of errors call Xlibs |
| 2375 | * default error handler, which may call exit. */ | 2480 | * default error handler, which may call exit. */ |
| 2376 | int xerror(Display *dpy, XErrorEvent *ee) { | 2481 | int xerror(Display *dpy, XErrorEvent *ee) |
| 2377 | if (ee->error_code == BadWindow || | 2482 | { |
| 2378 | (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) || | 2483 | if (ee->error_code == BadWindow || |
| 2379 | (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) || | 2484 | (ee->request_code == X_SetInputFocus && |
| 2380 | (ee->request_code == X_PolyFillRectangle && | 2485 | ee->error_code == BadMatch) || |
| 2381 | ee->error_code == BadDrawable) || | 2486 | (ee->request_code == X_PolyText8 && |
| 2382 | (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) || | 2487 | ee->error_code == BadDrawable) || |
| 2383 | (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) || | 2488 | (ee->request_code == X_PolyFillRectangle && |
| 2384 | (ee->request_code == X_GrabButton && ee->error_code == BadAccess) || | 2489 | ee->error_code == BadDrawable) || |
| 2385 | (ee->request_code == X_GrabKey && ee->error_code == BadAccess) || | 2490 | (ee->request_code == X_PolySegment && |
| 2386 | (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) | 2491 | ee->error_code == BadDrawable) || |
| 2387 | return 0; | 2492 | (ee->request_code == X_ConfigureWindow && |
| 2388 | fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", | 2493 | ee->error_code == BadMatch) || |
| 2389 | ee->request_code, ee->error_code); | 2494 | (ee->request_code == X_GrabButton && ee->error_code == BadAccess) || |
| 2390 | return xerrorxlib(dpy, ee); /* may call exit */ | 2495 | (ee->request_code == X_GrabKey && ee->error_code == BadAccess) || |
| 2496 | (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) | ||
| 2497 | return 0; | ||
| 2498 | fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", | ||
| 2499 | ee->request_code, ee->error_code); | ||
| 2500 | return xerrorxlib(dpy, ee); /* may call exit */ | ||
| 2391 | } | 2501 | } |
| 2392 | 2502 | ||
| 2393 | int xerrordummy(Display *dpy, XErrorEvent *ee) { return 0; } | 2503 | int xerrordummy(Display *dpy, XErrorEvent *ee) { return 0; } |
| 2394 | 2504 | ||
| 2395 | /* Startup Error handler to check if another window manager | 2505 | /* Startup Error handler to check if another window manager |
| 2396 | * is already running. */ | 2506 | * is already running. */ |
| 2397 | int xerrorstart(Display *dpy, XErrorEvent *ee) { | 2507 | int xerrorstart(Display *dpy, XErrorEvent *ee) |
| 2398 | die("dwm: another window manager is already running"); | 2508 | { |
| 2399 | return -1; | 2509 | die("dwm: another window manager is already running"); |
| 2400 | } | 2510 | return -1; |
| 2401 | 2511 | } | |
| 2402 | Monitor *systraytomon(Monitor *m) { | 2512 | |
| 2403 | Monitor *t; | 2513 | Monitor *systraytomon(Monitor *m) |
| 2404 | int i, n; | 2514 | { |
| 2405 | if (!systraypinning) { | 2515 | Monitor *t; |
| 2406 | if (!m) | 2516 | int i, n; |
| 2407 | return selmon; | 2517 | if (!systraypinning) { |
| 2408 | return m == selmon ? m : NULL; | 2518 | if (!m) |
| 2409 | } | 2519 | return selmon; |
| 2410 | for (n = 1, t = mons; t && t->next; n++, t = t->next) | 2520 | return m == selmon ? m : NULL; |
| 2411 | ; | 2521 | } |
| 2412 | for (i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) | 2522 | for (n = 1, t = mons; t && t->next; n++, t = t->next) |
| 2413 | ; | 2523 | ; |
| 2414 | if (systraypinningfailfirst && n < systraypinning) | 2524 | for (i = 1, t = mons; t && t->next && i < systraypinning; |
| 2415 | return mons; | 2525 | i++, t = t->next) |
| 2416 | return t; | 2526 | ; |
| 2417 | } | 2527 | if (systraypinningfailfirst && n < systraypinning) |
| 2418 | 2528 | return mons; | |
| 2419 | void zoom(const Arg *arg) { | 2529 | return t; |
| 2420 | Client *c = selmon->sel; | 2530 | } |
| 2421 | 2531 | ||
| 2422 | if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating) | 2532 | void zoom(const Arg *arg) |
| 2423 | return; | 2533 | { |
| 2424 | if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next))) | 2534 | Client *c = selmon->sel; |
| 2425 | return; | 2535 | |
| 2426 | pop(c); | 2536 | if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating) |
| 2427 | } | 2537 | return; |
| 2428 | 2538 | if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next))) | |
| 2429 | int main(int argc, char *argv[]) { | 2539 | return; |
| 2430 | if (argc == 2 && !strcmp("-v", argv[1])) | 2540 | pop(c); |
| 2431 | die("dwm-" VERSION); | 2541 | } |
| 2432 | else if (argc != 1) | 2542 | |
| 2433 | die("usage: dwm [-v]"); | 2543 | int main(int argc, char *argv[]) |
| 2434 | if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) | 2544 | { |
| 2435 | fputs("warning: no locale support\n", stderr); | 2545 | if (argc == 2 && !strcmp("-v", argv[1])) |
| 2436 | if (!(dpy = XOpenDisplay(NULL))) | 2546 | die("dwm-" VERSION); |
| 2437 | die("dwm: cannot open display"); | 2547 | else if (argc != 1) |
| 2438 | if (!(xcon = XGetXCBConnection(dpy))) | 2548 | die("usage: dwm [-v]"); |
| 2439 | die("dwm: cannot get xcb connection\n"); | 2549 | if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
| 2440 | checkotherwm(); | 2550 | fputs("warning: no locale support\n", stderr); |
| 2441 | setup(); | 2551 | if (!(dpy = XOpenDisplay(NULL))) |
| 2552 | die("dwm: cannot open display"); | ||
| 2553 | if (!(xcon = XGetXCBConnection(dpy))) | ||
| 2554 | die("dwm: cannot get xcb connection\n"); | ||
| 2555 | checkotherwm(); | ||
| 2556 | setup(); | ||
| 2442 | #ifdef __OpenBSD__ | 2557 | #ifdef __OpenBSD__ |
| 2443 | if (pledge("stdio rpath proc exec ps", NULL) == -1) | 2558 | if (pledge("stdio rpath proc exec ps", NULL) == -1) |
| 2444 | die("pledge"); | 2559 | die("pledge"); |
| 2445 | #endif /* __OpenBSD__ */ | 2560 | #endif /* __OpenBSD__ */ |
| 2446 | scan(); | 2561 | scan(); |
| 2447 | run(); | 2562 | run(); |
| 2448 | cleanup(); | 2563 | cleanup(); |
| 2449 | XCloseDisplay(dpy); | 2564 | XCloseDisplay(dpy); |
| 2450 | return EXIT_SUCCESS; | 2565 | return EXIT_SUCCESS; |
| 2451 | } | 2566 | } |
diff --git a/src/core/dwm.h b/src/core/dwm.h index 68eaf93..090448a 100644 --- a/src/core/dwm.h +++ b/src/core/dwm.h | |||
| @@ -2,126 +2,126 @@ | |||
| 2 | enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | 2 | enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ |
| 3 | enum { SchemeNorm, SchemeSel }; /* color schemes */ | 3 | enum { SchemeNorm, SchemeSel }; /* color schemes */ |
| 4 | enum { | 4 | enum { |
| 5 | NetSupported, | 5 | NetSupported, |
| 6 | NetWMName, | 6 | NetWMName, |
| 7 | NetWMState, | 7 | NetWMState, |
| 8 | NetWMCheck, | 8 | NetWMCheck, |
| 9 | NetSystemTray, | 9 | NetSystemTray, |
| 10 | NetSystemTrayOP, | 10 | NetSystemTrayOP, |
| 11 | NetSystemTrayOrientation, | 11 | NetSystemTrayOrientation, |
| 12 | NetSystemTrayOrientationHorz, | 12 | NetSystemTrayOrientationHorz, |
| 13 | NetWMFullscreen, | 13 | NetWMFullscreen, |
| 14 | NetActiveWindow, | 14 | NetActiveWindow, |
| 15 | NetWMWindowType, | 15 | NetWMWindowType, |
| 16 | NetWMWindowTypeDialog, | 16 | NetWMWindowTypeDialog, |
| 17 | NetClientList, | 17 | NetClientList, |
| 18 | NetLast | 18 | NetLast |
| 19 | }; /* EWMH atoms */ | 19 | }; /* EWMH atoms */ |
| 20 | enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ | 20 | enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ |
| 21 | enum { | 21 | enum { |
| 22 | WMProtocols, | 22 | WMProtocols, |
| 23 | WMDelete, | 23 | WMDelete, |
| 24 | WMState, | 24 | WMState, |
| 25 | WMTakeFocus, | 25 | WMTakeFocus, |
| 26 | WMLast | 26 | WMLast |
| 27 | }; /* default atoms */ | 27 | }; /* default atoms */ |
| 28 | enum { | 28 | enum { |
| 29 | ClkTagBar, | 29 | ClkTagBar, |
| 30 | ClkLtSymbol, | 30 | ClkLtSymbol, |
| 31 | ClkStatusText, | 31 | ClkStatusText, |
| 32 | ClkWinTitle, | 32 | ClkWinTitle, |
| 33 | ClkClientWin, | 33 | ClkClientWin, |
| 34 | ClkRootWin, | 34 | ClkRootWin, |
| 35 | ClkLast | 35 | ClkLast |
| 36 | }; /* clicks */ | 36 | }; /* clicks */ |
| 37 | 37 | ||
| 38 | typedef union { | 38 | typedef union { |
| 39 | int i; | 39 | int i; |
| 40 | unsigned int ui; | 40 | unsigned int ui; |
| 41 | float f; | 41 | float f; |
| 42 | const void *v; | 42 | const void *v; |
| 43 | } Arg; | 43 | } Arg; |
| 44 | 44 | ||
| 45 | typedef struct { | 45 | typedef struct { |
| 46 | unsigned int click; | 46 | unsigned int click; |
| 47 | unsigned int mask; | 47 | unsigned int mask; |
| 48 | unsigned int button; | 48 | unsigned int button; |
| 49 | void (*func)(const Arg *arg); | 49 | void (*func)(const Arg *arg); |
| 50 | const Arg arg; | 50 | const Arg arg; |
| 51 | } Button; | 51 | } Button; |
| 52 | 52 | ||
| 53 | typedef struct Monitor Monitor; | 53 | typedef struct Monitor Monitor; |
| 54 | typedef struct Client Client; | 54 | typedef struct Client Client; |
| 55 | struct Client { | 55 | struct Client { |
| 56 | char name[256]; | 56 | char name[256]; |
| 57 | float mina, maxa; | 57 | float mina, maxa; |
| 58 | int x, y, w, h; | 58 | int x, y, w, h; |
| 59 | int oldx, oldy, oldw, oldh; | 59 | int oldx, oldy, oldw, oldh; |
| 60 | int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; | 60 | int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; |
| 61 | int bw, oldbw; | 61 | int bw, oldbw; |
| 62 | unsigned int tags; | 62 | unsigned int tags; |
| 63 | int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, | 63 | int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, |
| 64 | isterminal, noswallow; | 64 | isterminal, noswallow; |
| 65 | pid_t pid; | 65 | pid_t pid; |
| 66 | Client *next; | 66 | Client *next; |
| 67 | Client *snext; | 67 | Client *snext; |
| 68 | Client *swallowing; | 68 | Client *swallowing; |
| 69 | Monitor *mon; | 69 | Monitor *mon; |
| 70 | Window win; | 70 | Window win; |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | typedef struct { | 73 | typedef struct { |
| 74 | unsigned int mod; | 74 | unsigned int mod; |
| 75 | KeySym keysym; | 75 | KeySym keysym; |
| 76 | void (*func)(const Arg *); | 76 | void (*func)(const Arg *); |
| 77 | const Arg arg; | 77 | const Arg arg; |
| 78 | } Key; | 78 | } Key; |
| 79 | 79 | ||
| 80 | typedef struct { | 80 | typedef struct { |
| 81 | const char *symbol; | 81 | const char *symbol; |
| 82 | void (*arrange)(Monitor *); | 82 | void (*arrange)(Monitor *); |
| 83 | } Layout; | 83 | } Layout; |
| 84 | 84 | ||
| 85 | struct Monitor { | 85 | struct Monitor { |
| 86 | char ltsymbol[16]; | 86 | char ltsymbol[16]; |
| 87 | float mfact; | 87 | float mfact; |
| 88 | int nmaster; | 88 | int nmaster; |
| 89 | int num; | 89 | int num; |
| 90 | int by; /* bar geometry */ | 90 | int by; /* bar geometry */ |
| 91 | int mx, my, mw, mh; /* screen size */ | 91 | int mx, my, mw, mh; /* screen size */ |
| 92 | int wx, wy, ww, wh; /* window area */ | 92 | int wx, wy, ww, wh; /* window area */ |
| 93 | int gappih; /* horizontal gap between windows */ | 93 | int gappih; /* horizontal gap between windows */ |
| 94 | int gappiv; /* vertical gap between windows */ | 94 | int gappiv; /* vertical gap between windows */ |
| 95 | int gappoh; /* horizontal outer gaps */ | 95 | int gappoh; /* horizontal outer gaps */ |
| 96 | int gappov; /* vertical outer gaps */ | 96 | int gappov; /* vertical outer gaps */ |
| 97 | unsigned int seltags; | 97 | unsigned int seltags; |
| 98 | unsigned int sellt; | 98 | unsigned int sellt; |
| 99 | unsigned int tagset[2]; | 99 | unsigned int tagset[2]; |
| 100 | int showbar; | 100 | int showbar; |
| 101 | int topbar; | 101 | int topbar; |
| 102 | Client *clients; | 102 | Client *clients; |
| 103 | Client *sel; | 103 | Client *sel; |
| 104 | Client *stack; | 104 | Client *stack; |
| 105 | Monitor *next; | 105 | Monitor *next; |
| 106 | Window barwin; | 106 | Window barwin; |
| 107 | const Layout *lt[2]; | 107 | const Layout *lt[2]; |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | typedef struct { | 110 | typedef struct { |
| 111 | const char *class; | 111 | const char *class; |
| 112 | const char *instance; | 112 | const char *instance; |
| 113 | const char *title; | 113 | const char *title; |
| 114 | unsigned int tags; | 114 | unsigned int tags; |
| 115 | int isfloating; | 115 | int isfloating; |
| 116 | int isterminal; | 116 | int isterminal; |
| 117 | int noswallow; | 117 | int noswallow; |
| 118 | int monitor; | 118 | int monitor; |
| 119 | } Rule; | 119 | } Rule; |
| 120 | 120 | ||
| 121 | typedef struct Systray Systray; | 121 | typedef struct Systray Systray; |
| 122 | struct Systray { | 122 | struct Systray { |
| 123 | Window win; | 123 | Window win; |
| 124 | Client *icons; | 124 | Client *icons; |
| 125 | }; | 125 | }; |
| 126 | 126 | ||
| 127 | /* function declarations */ | 127 | /* function declarations */ |
diff --git a/src/drw/drw.c b/src/drw/drw.c index 8f53beb..05420c0 100644 --- a/src/drw/drw.c +++ b/src/drw/drw.c | |||
| @@ -18,408 +18,460 @@ static const long utfmin[UTF_SIZ + 1] = {0, 0, 0x80, 0x800, 0x10000}; | |||
| 18 | static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, | 18 | static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, |
| 19 | 0x10FFFF}; | 19 | 0x10FFFF}; |
| 20 | 20 | ||
| 21 | static long utf8decodebyte(const char c, size_t *i) { | 21 | static long utf8decodebyte(const char c, size_t *i) |
| 22 | for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) | 22 | { |
| 23 | if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) | 23 | for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) |
| 24 | return (unsigned char)c & ~utfmask[*i]; | 24 | if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) |
| 25 | return 0; | 25 | return (unsigned char)c & ~utfmask[*i]; |
| 26 | return 0; | ||
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | static size_t utf8validate(long *u, size_t i) { | 29 | static size_t utf8validate(long *u, size_t i) |
| 29 | if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) | 30 | { |
| 30 | *u = UTF_INVALID; | 31 | if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) |
| 31 | for (i = 1; *u > utfmax[i]; ++i) | 32 | *u = UTF_INVALID; |
| 32 | ; | 33 | for (i = 1; *u > utfmax[i]; ++i) |
| 33 | return i; | 34 | ; |
| 35 | return i; | ||
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | static size_t utf8decode(const char *c, long *u, size_t clen) { | 38 | static size_t utf8decode(const char *c, long *u, size_t clen) |
| 37 | size_t i, j, len, type; | 39 | { |
| 38 | long udecoded; | 40 | size_t i, j, len, type; |
| 39 | 41 | long udecoded; | |
| 40 | *u = UTF_INVALID; | 42 | |
| 41 | if (!clen) | 43 | *u = UTF_INVALID; |
| 42 | return 0; | 44 | if (!clen) |
| 43 | udecoded = utf8decodebyte(c[0], &len); | 45 | return 0; |
| 44 | if (!BETWEEN(len, 1, UTF_SIZ)) | 46 | udecoded = utf8decodebyte(c[0], &len); |
| 45 | return 1; | 47 | if (!BETWEEN(len, 1, UTF_SIZ)) |
| 46 | for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { | 48 | return 1; |
| 47 | udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); | 49 | for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { |
| 48 | if (type) | 50 | udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); |
| 49 | return j; | 51 | if (type) |
| 50 | } | 52 | return j; |
| 51 | if (j < len) | 53 | } |
| 52 | return 0; | 54 | if (j < len) |
| 53 | *u = udecoded; | 55 | return 0; |
| 54 | utf8validate(u, len); | 56 | *u = udecoded; |
| 55 | 57 | utf8validate(u, len); | |
| 56 | return len; | 58 | |
| 59 | return len; | ||
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, | 62 | Drw *drw_create(Display *dpy, int screen, Window root, unsigned int w, |
| 60 | unsigned int h) { | 63 | unsigned int h) |
| 61 | Drw *drw = ecalloc(1, sizeof(Drw)); | 64 | { |
| 62 | 65 | Drw *drw = ecalloc(1, sizeof(Drw)); | |
| 63 | drw->dpy = dpy; | 66 | |
| 64 | drw->screen = screen; | 67 | drw->dpy = dpy; |
| 65 | drw->root = root; | 68 | drw->screen = screen; |
| 66 | drw->w = w; | 69 | drw->root = root; |
| 67 | drw->h = h; | 70 | drw->w = w; |
| 68 | drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); | 71 | drw->h = h; |
| 69 | drw->gc = XCreateGC(dpy, root, 0, NULL); | 72 | drw->drawable = |
| 70 | XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); | 73 | XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); |
| 71 | 74 | drw->gc = XCreateGC(dpy, root, 0, NULL); | |
| 72 | return drw; | 75 | XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); |
| 76 | |||
| 77 | return drw; | ||
| 73 | } | 78 | } |
| 74 | 79 | ||
| 75 | void drw_resize(Drw *drw, unsigned int w, unsigned int h) { | 80 | void drw_resize(Drw *drw, unsigned int w, unsigned int h) |
| 76 | if (!drw) | 81 | { |
| 77 | return; | 82 | if (!drw) |
| 78 | 83 | return; | |
| 79 | drw->w = w; | 84 | |
| 80 | drw->h = h; | 85 | drw->w = w; |
| 81 | if (drw->drawable) | 86 | drw->h = h; |
| 82 | XFreePixmap(drw->dpy, drw->drawable); | 87 | if (drw->drawable) |
| 83 | drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, | 88 | XFreePixmap(drw->dpy, drw->drawable); |
| 84 | DefaultDepth(drw->dpy, drw->screen)); | 89 | drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, |
| 90 | DefaultDepth(drw->dpy, drw->screen)); | ||
| 85 | } | 91 | } |
| 86 | 92 | ||
| 87 | void drw_free(Drw *drw) { | 93 | void drw_free(Drw *drw) |
| 88 | XFreePixmap(drw->dpy, drw->drawable); | 94 | { |
| 89 | XFreeGC(drw->dpy, drw->gc); | 95 | XFreePixmap(drw->dpy, drw->drawable); |
| 90 | drw_fontset_free(drw->fonts); | 96 | XFreeGC(drw->dpy, drw->gc); |
| 91 | free(drw); | 97 | drw_fontset_free(drw->fonts); |
| 98 | free(drw); | ||
| 92 | } | 99 | } |
| 93 | 100 | ||
| 94 | /* This function is an implementation detail. Library users should use | 101 | /* This function is an implementation detail. Library users should use |
| 95 | * drw_fontset_create instead. | 102 | * drw_fontset_create instead. |
| 96 | */ | 103 | */ |
| 97 | static Fnt *xfont_create(Drw *drw, const char *fontname, | 104 | static Fnt *xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) |
| 98 | FcPattern *fontpattern) { | 105 | { |
| 99 | Fnt *font; | 106 | Fnt *font; |
| 100 | XftFont *xfont = NULL; | 107 | XftFont *xfont = NULL; |
| 101 | FcPattern *pattern = NULL; | 108 | FcPattern *pattern = NULL; |
| 102 | 109 | ||
| 103 | if (fontname) { | 110 | if (fontname) { |
| 104 | /* Using the pattern found at font->xfont->pattern does not yield the | 111 | /* Using the pattern found at font->xfont->pattern does not |
| 105 | * same substitution results as using the pattern returned by | 112 | * yield the same substitution results as using the pattern |
| 106 | * FcNameParse; using the latter results in the desired fallback | 113 | * returned by FcNameParse; using the latter results in the |
| 107 | * behaviour whereas the former just results in missing-character | 114 | * desired fallback behaviour whereas the former just results in |
| 108 | * rectangles being drawn, at least with some fonts. */ | 115 | * missing-character rectangles being drawn, at least with some |
| 109 | if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { | 116 | * fonts. */ |
| 110 | fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); | 117 | if (!(xfont = |
| 111 | return NULL; | 118 | XftFontOpenName(drw->dpy, drw->screen, fontname))) { |
| 112 | } | 119 | fprintf(stderr, |
| 113 | if (!(pattern = FcNameParse((FcChar8 *)fontname))) { | 120 | "error, cannot load font from name: '%s'\n", |
| 114 | fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", | 121 | fontname); |
| 115 | fontname); | 122 | return NULL; |
| 116 | XftFontClose(drw->dpy, xfont); | 123 | } |
| 117 | return NULL; | 124 | if (!(pattern = FcNameParse((FcChar8 *)fontname))) { |
| 118 | } | 125 | fprintf( |
| 119 | } else if (fontpattern) { | 126 | stderr, |
| 120 | if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { | 127 | "error, cannot parse font name to pattern: '%s'\n", |
| 121 | fprintf(stderr, "error, cannot load font from pattern.\n"); | 128 | fontname); |
| 122 | return NULL; | 129 | XftFontClose(drw->dpy, xfont); |
| 123 | } | 130 | return NULL; |
| 124 | } else { | 131 | } |
| 125 | die("no font specified."); | 132 | } else if (fontpattern) { |
| 126 | } | 133 | if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { |
| 127 | 134 | fprintf(stderr, | |
| 128 | font = ecalloc(1, sizeof(Fnt)); | 135 | "error, cannot load font from pattern.\n"); |
| 129 | font->xfont = xfont; | 136 | return NULL; |
| 130 | font->pattern = pattern; | 137 | } |
| 131 | font->h = xfont->ascent + xfont->descent; | 138 | } else { |
| 132 | font->dpy = drw->dpy; | 139 | die("no font specified."); |
| 133 | 140 | } | |
| 134 | return font; | 141 | |
| 142 | font = ecalloc(1, sizeof(Fnt)); | ||
| 143 | font->xfont = xfont; | ||
| 144 | font->pattern = pattern; | ||
| 145 | font->h = xfont->ascent + xfont->descent; | ||
| 146 | font->dpy = drw->dpy; | ||
| 147 | |||
| 148 | return font; | ||
| 135 | } | 149 | } |
| 136 | 150 | ||
| 137 | static void xfont_free(Fnt *font) { | 151 | static void xfont_free(Fnt *font) |
| 138 | if (!font) | 152 | { |
| 139 | return; | 153 | if (!font) |
| 140 | if (font->pattern) | 154 | return; |
| 141 | FcPatternDestroy(font->pattern); | 155 | if (font->pattern) |
| 142 | XftFontClose(font->dpy, font->xfont); | 156 | FcPatternDestroy(font->pattern); |
| 143 | free(font); | 157 | XftFontClose(font->dpy, font->xfont); |
| 158 | free(font); | ||
| 144 | } | 159 | } |
| 145 | 160 | ||
| 146 | Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount) { | 161 | Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount) |
| 147 | Fnt *cur, *ret = NULL; | 162 | { |
| 148 | size_t i; | 163 | Fnt *cur, *ret = NULL; |
| 149 | 164 | size_t i; | |
| 150 | if (!drw || !fonts) | 165 | |
| 151 | return NULL; | 166 | if (!drw || !fonts) |
| 152 | 167 | return NULL; | |
| 153 | for (i = 1; i <= fontcount; i++) { | 168 | |
| 154 | if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { | 169 | for (i = 1; i <= fontcount; i++) { |
| 155 | cur->next = ret; | 170 | if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { |
| 156 | ret = cur; | 171 | cur->next = ret; |
| 157 | } | 172 | ret = cur; |
| 158 | } | 173 | } |
| 159 | return (drw->fonts = ret); | 174 | } |
| 175 | return (drw->fonts = ret); | ||
| 160 | } | 176 | } |
| 161 | 177 | ||
| 162 | void drw_fontset_free(Fnt *font) { | 178 | void drw_fontset_free(Fnt *font) |
| 163 | if (font) { | 179 | { |
| 164 | drw_fontset_free(font->next); | 180 | if (font) { |
| 165 | xfont_free(font); | 181 | drw_fontset_free(font->next); |
| 166 | } | 182 | xfont_free(font); |
| 183 | } | ||
| 167 | } | 184 | } |
| 168 | 185 | ||
| 169 | void drw_clr_create(Drw *drw, Clr *dest, const char *clrname) { | 186 | void drw_clr_create(Drw *drw, Clr *dest, const char *clrname) |
| 170 | if (!drw || !dest || !clrname) | 187 | { |
| 171 | return; | 188 | if (!drw || !dest || !clrname) |
| 189 | return; | ||
| 172 | 190 | ||
| 173 | if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), | 191 | if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), |
| 174 | DefaultColormap(drw->dpy, drw->screen), clrname, dest)) | 192 | DefaultColormap(drw->dpy, drw->screen), clrname, |
| 175 | die("error, cannot allocate color '%s'", clrname); | 193 | dest)) |
| 194 | die("error, cannot allocate color '%s'", clrname); | ||
| 176 | } | 195 | } |
| 177 | 196 | ||
| 178 | /* Wrapper to create color schemes. The caller has to call free(3) on the | 197 | /* Wrapper to create color schemes. The caller has to call free(3) on the |
| 179 | * returned color scheme when done using it. */ | 198 | * returned color scheme when done using it. */ |
| 180 | Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) { | 199 | Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) |
| 181 | size_t i; | 200 | { |
| 182 | Clr *ret; | 201 | size_t i; |
| 183 | 202 | Clr *ret; | |
| 184 | /* need at least two colors for a scheme */ | 203 | |
| 185 | if (!drw || !clrnames || clrcount < 2 || | 204 | /* need at least two colors for a scheme */ |
| 186 | !(ret = ecalloc(clrcount, sizeof(XftColor)))) | 205 | if (!drw || !clrnames || clrcount < 2 || |
| 187 | return NULL; | 206 | !(ret = ecalloc(clrcount, sizeof(XftColor)))) |
| 188 | 207 | return NULL; | |
| 189 | for (i = 0; i < clrcount; i++) | 208 | |
| 190 | drw_clr_create(drw, &ret[i], clrnames[i]); | 209 | for (i = 0; i < clrcount; i++) |
| 191 | return ret; | 210 | drw_clr_create(drw, &ret[i], clrnames[i]); |
| 211 | return ret; | ||
| 192 | } | 212 | } |
| 193 | 213 | ||
| 194 | void drw_setfontset(Drw *drw, Fnt *set) { | 214 | void drw_setfontset(Drw *drw, Fnt *set) |
| 195 | if (drw) | 215 | { |
| 196 | drw->fonts = set; | 216 | if (drw) |
| 217 | drw->fonts = set; | ||
| 197 | } | 218 | } |
| 198 | 219 | ||
| 199 | void drw_setscheme(Drw *drw, Clr *scm) { | 220 | void drw_setscheme(Drw *drw, Clr *scm) |
| 200 | if (drw) | 221 | { |
| 201 | drw->scheme = scm; | 222 | if (drw) |
| 223 | drw->scheme = scm; | ||
| 202 | } | 224 | } |
| 203 | 225 | ||
| 204 | void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, | 226 | void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, |
| 205 | int filled, int invert) { | 227 | int filled, int invert) |
| 206 | if (!drw || !drw->scheme) | 228 | { |
| 207 | return; | 229 | if (!drw || !drw->scheme) |
| 208 | XSetForeground(drw->dpy, drw->gc, | 230 | return; |
| 209 | invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); | 231 | XSetForeground(drw->dpy, drw->gc, |
| 210 | if (filled) | 232 | invert ? drw->scheme[ColBg].pixel |
| 211 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | 233 | : drw->scheme[ColFg].pixel); |
| 212 | else | 234 | if (filled) |
| 213 | XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); | 235 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
| 236 | else | ||
| 237 | XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, | ||
| 238 | h - 1); | ||
| 214 | } | 239 | } |
| 215 | 240 | ||
| 216 | int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, | 241 | int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, |
| 217 | unsigned int lpad, const char *text, int invert) { | 242 | unsigned int lpad, const char *text, int invert) |
| 218 | int i, ty, ellipsis_x = 0; | 243 | { |
| 219 | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; | 244 | int i, ty, ellipsis_x = 0; |
| 220 | XftDraw *d = NULL; | 245 | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; |
| 221 | Fnt *usedfont, *curfont, *nextfont; | 246 | XftDraw *d = NULL; |
| 222 | int utf8strlen, utf8charlen, render = x || y || w || h; | 247 | Fnt *usedfont, *curfont, *nextfont; |
| 223 | long utf8codepoint = 0; | 248 | int utf8strlen, utf8charlen, render = x || y || w || h; |
| 224 | const char *utf8str; | 249 | long utf8codepoint = 0; |
| 225 | FcCharSet *fccharset; | 250 | const char *utf8str; |
| 226 | FcPattern *fcpattern; | 251 | FcCharSet *fccharset; |
| 227 | FcPattern *match; | 252 | FcPattern *fcpattern; |
| 228 | XftResult result; | 253 | FcPattern *match; |
| 229 | int charexists = 0, overflow = 0; | 254 | XftResult result; |
| 230 | /* keep track of a couple codepoints for which we have no match. */ | 255 | int charexists = 0, overflow = 0; |
| 231 | enum { nomatches_len = 64 }; | 256 | /* keep track of a couple codepoints for which we have no match. */ |
| 232 | static struct { | 257 | enum { nomatches_len = 64 }; |
| 233 | long codepoint[nomatches_len]; | 258 | static struct { |
| 234 | unsigned int idx; | 259 | long codepoint[nomatches_len]; |
| 235 | } nomatches; | 260 | unsigned int idx; |
| 236 | static unsigned int ellipsis_width = 0; | 261 | } nomatches; |
| 237 | 262 | static unsigned int ellipsis_width = 0; | |
| 238 | if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) | 263 | |
| 239 | return 0; | 264 | if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) |
| 240 | 265 | return 0; | |
| 241 | if (!render) { | 266 | |
| 242 | w = invert ? invert : ~invert; | 267 | if (!render) { |
| 243 | } else { | 268 | w = invert ? invert : ~invert; |
| 244 | XSetForeground(drw->dpy, drw->gc, | 269 | } else { |
| 245 | drw->scheme[invert ? ColFg : ColBg].pixel); | 270 | XSetForeground(drw->dpy, drw->gc, |
| 246 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | 271 | drw->scheme[invert ? ColFg : ColBg].pixel); |
| 247 | d = XftDrawCreate(drw->dpy, drw->drawable, | 272 | XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
| 248 | DefaultVisual(drw->dpy, drw->screen), | 273 | d = XftDrawCreate(drw->dpy, drw->drawable, |
| 249 | DefaultColormap(drw->dpy, drw->screen)); | 274 | DefaultVisual(drw->dpy, drw->screen), |
| 250 | x += lpad; | 275 | DefaultColormap(drw->dpy, drw->screen)); |
| 251 | w -= lpad; | 276 | x += lpad; |
| 252 | } | 277 | w -= lpad; |
| 253 | 278 | } | |
| 254 | usedfont = drw->fonts; | 279 | |
| 255 | if (!ellipsis_width && render) | 280 | usedfont = drw->fonts; |
| 256 | ellipsis_width = drw_fontset_getwidth(drw, "..."); | 281 | if (!ellipsis_width && render) |
| 257 | while (1) { | 282 | ellipsis_width = drw_fontset_getwidth(drw, "..."); |
| 258 | ew = ellipsis_len = utf8strlen = 0; | 283 | while (1) { |
| 259 | utf8str = text; | 284 | ew = ellipsis_len = utf8strlen = 0; |
| 260 | nextfont = NULL; | 285 | utf8str = text; |
| 261 | while (*text) { | 286 | nextfont = NULL; |
| 262 | utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); | 287 | while (*text) { |
| 263 | for (curfont = drw->fonts; curfont; curfont = curfont->next) { | 288 | utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); |
| 264 | charexists = charexists || | 289 | for (curfont = drw->fonts; curfont; |
| 265 | XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); | 290 | curfont = curfont->next) { |
| 266 | if (charexists) { | 291 | charexists = |
| 267 | drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); | 292 | charexists || |
| 268 | if (ew + ellipsis_width <= w) { | 293 | XftCharExists(drw->dpy, curfont->xfont, |
| 269 | /* keep track where the ellipsis still fits */ | 294 | utf8codepoint); |
| 270 | ellipsis_x = x + ew; | 295 | if (charexists) { |
| 271 | ellipsis_w = w - ew; | 296 | drw_font_getexts(curfont, text, |
| 272 | ellipsis_len = utf8strlen; | 297 | utf8charlen, &tmpw, |
| 273 | } | 298 | NULL); |
| 274 | 299 | if (ew + ellipsis_width <= w) { | |
| 275 | if (ew + tmpw > w) { | 300 | /* keep track where the ellipsis |
| 276 | overflow = 1; | 301 | * still fits */ |
| 277 | /* called from drw_fontset_getwidth_clamp(): | 302 | ellipsis_x = x + ew; |
| 278 | * it wants the width AFTER the overflow | 303 | ellipsis_w = w - ew; |
| 279 | */ | 304 | ellipsis_len = utf8strlen; |
| 280 | if (!render) | 305 | } |
| 281 | x += tmpw; | 306 | |
| 282 | else | 307 | if (ew + tmpw > w) { |
| 283 | utf8strlen = ellipsis_len; | 308 | overflow = 1; |
| 284 | } else if (curfont == usedfont) { | 309 | /* called from |
| 285 | utf8strlen += utf8charlen; | 310 | * drw_fontset_getwidth_clamp(): |
| 286 | text += utf8charlen; | 311 | * it wants the width AFTER the |
| 287 | ew += tmpw; | 312 | * overflow |
| 288 | } else { | 313 | */ |
| 289 | nextfont = curfont; | 314 | if (!render) |
| 290 | } | 315 | x += tmpw; |
| 291 | break; | 316 | else |
| 292 | } | 317 | utf8strlen = |
| 293 | } | 318 | ellipsis_len; |
| 294 | 319 | } else if (curfont == usedfont) { | |
| 295 | if (overflow || !charexists || nextfont) | 320 | utf8strlen += utf8charlen; |
| 296 | break; | 321 | text += utf8charlen; |
| 297 | else | 322 | ew += tmpw; |
| 298 | charexists = 0; | 323 | } else { |
| 299 | } | 324 | nextfont = curfont; |
| 300 | 325 | } | |
| 301 | if (utf8strlen) { | 326 | break; |
| 302 | if (render) { | 327 | } |
| 303 | ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; | 328 | } |
| 304 | XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], | 329 | |
| 305 | usedfont->xfont, x, ty, (XftChar8 *)utf8str, | 330 | if (overflow || !charexists || nextfont) |
| 306 | utf8strlen); | 331 | break; |
| 307 | } | 332 | else |
| 308 | x += ew; | 333 | charexists = 0; |
| 309 | w -= ew; | 334 | } |
| 310 | } | 335 | |
| 311 | if (render && overflow) | 336 | if (utf8strlen) { |
| 312 | drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); | 337 | if (render) { |
| 313 | 338 | ty = y + (h - usedfont->h) / 2 + | |
| 314 | if (!*text || overflow) { | 339 | usedfont->xfont->ascent; |
| 315 | break; | 340 | XftDrawStringUtf8( |
| 316 | } else if (nextfont) { | 341 | d, &drw->scheme[invert ? ColBg : ColFg], |
| 317 | charexists = 0; | 342 | usedfont->xfont, x, ty, (XftChar8 *)utf8str, |
| 318 | usedfont = nextfont; | 343 | utf8strlen); |
| 319 | } else { | 344 | } |
| 320 | /* Regardless of whether or not a fallback font is found, the | 345 | x += ew; |
| 321 | * character must be drawn. */ | 346 | w -= ew; |
| 322 | charexists = 1; | 347 | } |
| 323 | 348 | if (render && overflow) | |
| 324 | for (i = 0; i < nomatches_len; ++i) { | 349 | drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", |
| 325 | /* avoid calling XftFontMatch if we know we won't find a match */ | 350 | invert); |
| 326 | if (utf8codepoint == nomatches.codepoint[i]) | 351 | |
| 327 | goto no_match; | 352 | if (!*text || overflow) { |
| 328 | } | 353 | break; |
| 329 | 354 | } else if (nextfont) { | |
| 330 | fccharset = FcCharSetCreate(); | 355 | charexists = 0; |
| 331 | FcCharSetAddChar(fccharset, utf8codepoint); | 356 | usedfont = nextfont; |
| 332 | 357 | } else { | |
| 333 | if (!drw->fonts->pattern) { | 358 | /* Regardless of whether or not a fallback font is |
| 334 | /* Refer to the comment in xfont_create for more information. */ | 359 | * found, the character must be drawn. */ |
| 335 | die("the first font in the cache must be loaded from a font string."); | 360 | charexists = 1; |
| 336 | } | 361 | |
| 337 | 362 | for (i = 0; i < nomatches_len; ++i) { | |
| 338 | fcpattern = FcPatternDuplicate(drw->fonts->pattern); | 363 | /* avoid calling XftFontMatch if we know we |
| 339 | FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); | 364 | * won't find a match */ |
| 340 | FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); | 365 | if (utf8codepoint == nomatches.codepoint[i]) |
| 341 | 366 | goto no_match; | |
| 342 | FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); | 367 | } |
| 343 | FcDefaultSubstitute(fcpattern); | 368 | |
| 344 | match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); | 369 | fccharset = FcCharSetCreate(); |
| 345 | 370 | FcCharSetAddChar(fccharset, utf8codepoint); | |
| 346 | FcCharSetDestroy(fccharset); | 371 | |
| 347 | FcPatternDestroy(fcpattern); | 372 | if (!drw->fonts->pattern) { |
| 348 | 373 | /* Refer to the comment in xfont_create for more | |
| 349 | if (match) { | 374 | * information. */ |
| 350 | usedfont = xfont_create(drw, NULL, match); | 375 | die("the first font in the cache must be " |
| 351 | if (usedfont && | 376 | "loaded from a font string."); |
| 352 | XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { | 377 | } |
| 353 | for (curfont = drw->fonts; curfont->next; curfont = curfont->next) | 378 | |
| 354 | ; /* NOP */ | 379 | fcpattern = FcPatternDuplicate(drw->fonts->pattern); |
| 355 | curfont->next = usedfont; | 380 | FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); |
| 356 | } else { | 381 | FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); |
| 357 | xfont_free(usedfont); | 382 | |
| 358 | nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; | 383 | FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); |
| 359 | no_match: | 384 | FcDefaultSubstitute(fcpattern); |
| 360 | usedfont = drw->fonts; | 385 | match = XftFontMatch(drw->dpy, drw->screen, fcpattern, |
| 361 | } | 386 | &result); |
| 362 | } | 387 | |
| 363 | } | 388 | FcCharSetDestroy(fccharset); |
| 364 | } | 389 | FcPatternDestroy(fcpattern); |
| 365 | if (d) | 390 | |
| 366 | XftDrawDestroy(d); | 391 | if (match) { |
| 367 | 392 | usedfont = xfont_create(drw, NULL, match); | |
| 368 | return x + (render ? w : 0); | 393 | if (usedfont && |
| 394 | XftCharExists(drw->dpy, usedfont->xfont, | ||
| 395 | utf8codepoint)) { | ||
| 396 | for (curfont = drw->fonts; | ||
| 397 | curfont->next; | ||
| 398 | curfont = curfont->next) | ||
| 399 | ; /* NOP */ | ||
| 400 | curfont->next = usedfont; | ||
| 401 | } else { | ||
| 402 | xfont_free(usedfont); | ||
| 403 | nomatches.codepoint[++nomatches.idx % | ||
| 404 | nomatches_len] = | ||
| 405 | utf8codepoint; | ||
| 406 | no_match: | ||
| 407 | usedfont = drw->fonts; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | } | ||
| 411 | } | ||
| 412 | if (d) | ||
| 413 | XftDrawDestroy(d); | ||
| 414 | |||
| 415 | return x + (render ? w : 0); | ||
| 369 | } | 416 | } |
| 370 | 417 | ||
| 371 | void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, | 418 | void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) |
| 372 | unsigned int h) { | 419 | { |
| 373 | if (!drw) | 420 | if (!drw) |
| 374 | return; | 421 | return; |
| 375 | 422 | ||
| 376 | XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); | 423 | XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); |
| 377 | XSync(drw->dpy, False); | 424 | XSync(drw->dpy, False); |
| 378 | } | 425 | } |
| 379 | 426 | ||
| 380 | unsigned int drw_fontset_getwidth(Drw *drw, const char *text) { | 427 | unsigned int drw_fontset_getwidth(Drw *drw, const char *text) |
| 381 | if (!drw || !drw->fonts || !text) | 428 | { |
| 382 | return 0; | 429 | if (!drw || !drw->fonts || !text) |
| 383 | return drw_text(drw, 0, 0, 0, 0, 0, text, 0); | 430 | return 0; |
| 431 | return drw_text(drw, 0, 0, 0, 0, 0, text, 0); | ||
| 384 | } | 432 | } |
| 385 | 433 | ||
| 386 | unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, | 434 | unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, |
| 387 | unsigned int n) { | 435 | unsigned int n) |
| 388 | unsigned int tmp = 0; | 436 | { |
| 389 | if (drw && drw->fonts && text && n) | 437 | unsigned int tmp = 0; |
| 390 | tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); | 438 | if (drw && drw->fonts && text && n) |
| 391 | return MIN(n, tmp); | 439 | tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); |
| 440 | return MIN(n, tmp); | ||
| 392 | } | 441 | } |
| 393 | 442 | ||
| 394 | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, | 443 | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, |
| 395 | unsigned int *w, unsigned int *h) { | 444 | unsigned int *w, unsigned int *h) |
| 396 | XGlyphInfo ext; | 445 | { |
| 397 | 446 | XGlyphInfo ext; | |
| 398 | if (!font || !text) | 447 | |
| 399 | return; | 448 | if (!font || !text) |
| 400 | 449 | return; | |
| 401 | XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); | 450 | |
| 402 | if (w) | 451 | XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); |
| 403 | *w = ext.xOff; | 452 | if (w) |
| 404 | if (h) | 453 | *w = ext.xOff; |
| 405 | *h = font->h; | 454 | if (h) |
| 455 | *h = font->h; | ||
| 406 | } | 456 | } |
| 407 | 457 | ||
| 408 | Cur *drw_cur_create(Drw *drw, int shape) { | 458 | Cur *drw_cur_create(Drw *drw, int shape) |
| 409 | Cur *cur; | 459 | { |
| 460 | Cur *cur; | ||
| 410 | 461 | ||
| 411 | if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) | 462 | if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) |
| 412 | return NULL; | 463 | return NULL; |
| 413 | 464 | ||
| 414 | cur->cursor = XCreateFontCursor(drw->dpy, shape); | 465 | cur->cursor = XCreateFontCursor(drw->dpy, shape); |
| 415 | 466 | ||
| 416 | return cur; | 467 | return cur; |
| 417 | } | 468 | } |
| 418 | 469 | ||
| 419 | void drw_cur_free(Drw *drw, Cur *cursor) { | 470 | void drw_cur_free(Drw *drw, Cur *cursor) |
| 420 | if (!cursor) | 471 | { |
| 421 | return; | 472 | if (!cursor) |
| 473 | return; | ||
| 422 | 474 | ||
| 423 | XFreeCursor(drw->dpy, cursor->cursor); | 475 | XFreeCursor(drw->dpy, cursor->cursor); |
| 424 | free(cursor); | 476 | free(cursor); |
| 425 | } | 477 | } |
diff --git a/src/drw/drw.h b/src/drw/drw.h index e645d43..88308ab 100644 --- a/src/drw/drw.h +++ b/src/drw/drw.h | |||
| @@ -1,29 +1,29 @@ | |||
| 1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
| 2 | 2 | ||
| 3 | typedef struct { | 3 | typedef struct { |
| 4 | Cursor cursor; | 4 | Cursor cursor; |
| 5 | } Cur; | 5 | } Cur; |
| 6 | 6 | ||
| 7 | typedef struct Fnt { | 7 | typedef struct Fnt { |
| 8 | Display *dpy; | 8 | Display *dpy; |
| 9 | unsigned int h; | 9 | unsigned int h; |
| 10 | XftFont *xfont; | 10 | XftFont *xfont; |
| 11 | FcPattern *pattern; | 11 | FcPattern *pattern; |
| 12 | struct Fnt *next; | 12 | struct Fnt *next; |
| 13 | } Fnt; | 13 | } Fnt; |
| 14 | 14 | ||
| 15 | enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ | 15 | enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ |
| 16 | typedef XftColor Clr; | 16 | typedef XftColor Clr; |
| 17 | 17 | ||
| 18 | typedef struct { | 18 | typedef struct { |
| 19 | unsigned int w, h; | 19 | unsigned int w, h; |
| 20 | Display *dpy; | 20 | Display *dpy; |
| 21 | int screen; | 21 | int screen; |
| 22 | Window root; | 22 | Window root; |
| 23 | Drawable drawable; | 23 | Drawable drawable; |
| 24 | GC gc; | 24 | GC gc; |
| 25 | Clr *scheme; | 25 | Clr *scheme; |
| 26 | Fnt *fonts; | 26 | Fnt *fonts; |
| 27 | } Drw; | 27 | } Drw; |
| 28 | 28 | ||
| 29 | /* Drawable abstraction */ | 29 | /* Drawable abstraction */ |
diff --git a/src/transient/transient.c b/src/transient/transient.c index ed6539f..fed0f77 100644 --- a/src/transient/transient.c +++ b/src/transient/transient.c | |||
| @@ -39,49 +39,52 @@ | |||
| 39 | * | 39 | * |
| 40 | * @return int Exit status (always 0). | 40 | * @return int Exit status (always 0). |
| 41 | */ | 41 | */ |
| 42 | int main(void) { | 42 | int main(void) |
| 43 | Display *display; | 43 | { |
| 44 | Window rootWindow, floatingWindow, transientWindow = None; | 44 | Display *display; |
| 45 | XSizeHints sizeHints; | 45 | Window rootWindow, floatingWindow, transientWindow = None; |
| 46 | XEvent event; | 46 | XSizeHints sizeHints; |
| 47 | XEvent event; | ||
| 47 | 48 | ||
| 48 | display = XOpenDisplay(NULL); | 49 | display = XOpenDisplay(NULL); |
| 49 | if (!display) | 50 | if (!display) |
| 50 | exit(1); | 51 | exit(1); |
| 51 | 52 | ||
| 52 | rootWindow = DefaultRootWindow(display); | 53 | rootWindow = DefaultRootWindow(display); |
| 53 | 54 | ||
| 54 | floatingWindow = XCreateSimpleWindow( | 55 | floatingWindow = XCreateSimpleWindow( |
| 55 | display, rootWindow, FLOATING_WINDOW_X_POS, FLOATING_WINDOW_Y_POS, | 56 | display, rootWindow, FLOATING_WINDOW_X_POS, FLOATING_WINDOW_Y_POS, |
| 56 | FLOATING_WINDOW_WIDTH, FLOATING_WINDOW_HEIGHT, WINDOW_BORDER_WIDTH, | 57 | FLOATING_WINDOW_WIDTH, FLOATING_WINDOW_HEIGHT, WINDOW_BORDER_WIDTH, |
| 57 | WINDOW_BORDER_COLOR, WINDOW_BACKGROUND_COLOR); | 58 | WINDOW_BORDER_COLOR, WINDOW_BACKGROUND_COLOR); |
| 58 | 59 | ||
| 59 | sizeHints.min_width = sizeHints.max_width = sizeHints.min_height = | 60 | sizeHints.min_width = sizeHints.max_width = sizeHints.min_height = |
| 60 | sizeHints.max_height = FLOATING_WINDOW_WIDTH; | 61 | sizeHints.max_height = FLOATING_WINDOW_WIDTH; |
| 61 | sizeHints.flags = PMinSize | PMaxSize; | 62 | sizeHints.flags = PMinSize | PMaxSize; |
| 62 | XSetWMNormalHints(display, floatingWindow, &sizeHints); | 63 | XSetWMNormalHints(display, floatingWindow, &sizeHints); |
| 63 | XStoreName(display, floatingWindow, "floating"); | 64 | XStoreName(display, floatingWindow, "floating"); |
| 64 | XMapWindow(display, floatingWindow); | 65 | XMapWindow(display, floatingWindow); |
| 65 | XSelectInput(display, floatingWindow, ExposureMask); | 66 | XSelectInput(display, floatingWindow, ExposureMask); |
| 66 | 67 | ||
| 67 | while (1) { | 68 | while (1) { |
| 68 | XNextEvent(display, &event); | 69 | XNextEvent(display, &event); |
| 69 | 70 | ||
| 70 | if (transientWindow == None) { | 71 | if (transientWindow == None) { |
| 71 | sleep(SLEEP_TIME); | 72 | sleep(SLEEP_TIME); |
| 72 | 73 | ||
| 73 | transientWindow = XCreateSimpleWindow( | 74 | transientWindow = XCreateSimpleWindow( |
| 74 | display, rootWindow, TRANSIENT_WINDOW_X_POS, TRANSIENT_WINDOW_Y_POS, | 75 | display, rootWindow, TRANSIENT_WINDOW_X_POS, |
| 75 | TRANSIENT_WINDOW_WIDTH, TRANSIENT_WINDOW_HEIGHT, WINDOW_BORDER_WIDTH, | 76 | TRANSIENT_WINDOW_Y_POS, TRANSIENT_WINDOW_WIDTH, |
| 76 | WINDOW_BORDER_COLOR, WINDOW_BACKGROUND_COLOR); | 77 | TRANSIENT_WINDOW_HEIGHT, WINDOW_BORDER_WIDTH, |
| 78 | WINDOW_BORDER_COLOR, WINDOW_BACKGROUND_COLOR); | ||
| 77 | 79 | ||
| 78 | XSetTransientForHint(display, transientWindow, floatingWindow); | 80 | XSetTransientForHint(display, transientWindow, |
| 79 | XStoreName(display, transientWindow, "transient"); | 81 | floatingWindow); |
| 80 | XMapWindow(display, transientWindow); | 82 | XStoreName(display, transientWindow, "transient"); |
| 81 | XSelectInput(display, transientWindow, ExposureMask); | 83 | XMapWindow(display, transientWindow); |
| 82 | } | 84 | XSelectInput(display, transientWindow, ExposureMask); |
| 83 | } | 85 | } |
| 86 | } | ||
| 84 | 87 | ||
| 85 | XCloseDisplay(display); | 88 | XCloseDisplay(display); |
| 86 | exit(0); | 89 | exit(0); |
| 87 | } | 90 | } |
diff --git a/src/util/util.c b/src/util/util.c index 7419d0c..61c864c 100644 --- a/src/util/util.c +++ b/src/util/util.c | |||
| @@ -18,19 +18,21 @@ | |||
| 18 | * Usage: | 18 | * Usage: |
| 19 | * die("Error occurred in function %s", __func__); | 19 | * die("Error occurred in function %s", __func__); |
| 20 | */ | 20 | */ |
| 21 | void die(const char *format_string, ...) { | 21 | void die(const char *format_string, ...) |
| 22 | va_list argument_list; | 22 | { |
| 23 | va_start(argument_list, format_string); | 23 | va_list argument_list; |
| 24 | vfprintf(stderr, format_string, argument_list); | 24 | va_start(argument_list, format_string); |
| 25 | va_end(argument_list); | 25 | vfprintf(stderr, format_string, argument_list); |
| 26 | 26 | va_end(argument_list); | |
| 27 | if (format_string[0] && format_string[strlen(format_string) - 1] == ':') { | 27 | |
| 28 | fputc(' ', stderr); | 28 | if (format_string[0] && |
| 29 | perror(NULL); | 29 | format_string[strlen(format_string) - 1] == ':') { |
| 30 | } else | 30 | fputc(' ', stderr); |
| 31 | fputc('\n', stderr); | 31 | perror(NULL); |
| 32 | 32 | } else | |
| 33 | exit(1); | 33 | fputc('\n', stderr); |
| 34 | |||
| 35 | exit(1); | ||
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | /* | 38 | /* |
| @@ -52,11 +54,12 @@ void die(const char *format_string, ...) { | |||
| 52 | * int *array = ecalloc(10, sizeof(int)); // Allocate memory for an array of | 54 | * int *array = ecalloc(10, sizeof(int)); // Allocate memory for an array of |
| 53 | * 10 integers. | 55 | * 10 integers. |
| 54 | */ | 56 | */ |
| 55 | void *ecalloc(size_t num_elements, size_t element_size) { | 57 | void *ecalloc(size_t num_elements, size_t element_size) |
| 56 | void *allocated_memory; | 58 | { |
| 59 | void *allocated_memory; | ||
| 57 | 60 | ||
| 58 | if (!(allocated_memory = calloc(num_elements, element_size))) | 61 | if (!(allocated_memory = calloc(num_elements, element_size))) |
| 59 | die("calloc:"); | 62 | die("calloc:"); |
| 60 | 63 | ||
| 61 | return allocated_memory; | 64 | return allocated_memory; |
| 62 | } | 65 | } |
