From 11498264d51331a6269aa306b55dda75ec60fba9 Mon Sep 17 00:00:00 2001 From: exkc Date: Wed, 20 Jul 2022 15:48:25 +0800 Subject: [PATCH] djjd\# Please enter the commit message for your changes. Lines starting --- LICENSE | 21 ++ Makefile | 55 +++++ bar.c | 46 ++++ bar.o | Bin 0 -> 3344 bytes client.c | 616 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ client.o | Bin 0 -> 16376 bytes config.mk | 31 +++ dev.c | 151 +++++++++++++ dev.o | Bin 0 -> 6968 bytes draw.c | 158 ++++++++++++++ draw.o | Bin 0 -> 7192 bytes dumbwm | Bin 0 -> 49728 bytes dumbwm.h | 155 ++++++++++++++ event.c | 216 +++++++++++++++++++ event.o | Bin 0 -> 6072 bytes main.c | 327 +++++++++++++++++++++++++++++ main.o | Bin 0 -> 12168 bytes util.c | 59 ++++++ util.o | Bin 0 -> 2872 bytes 19 files changed, 1835 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 bar.c create mode 100644 bar.o create mode 100644 client.c create mode 100644 client.o create mode 100644 config.mk create mode 100644 dev.c create mode 100644 dev.o create mode 100644 draw.c create mode 100644 draw.o create mode 100755 dumbwm create mode 100644 dumbwm.h create mode 100644 event.c create mode 100644 event.o create mode 100644 main.c create mode 100644 main.o create mode 100644 util.c create mode 100644 util.o diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..aa0a3ab --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +(C)opyright MMVI Anselm R. Garbe + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c75f6f3 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# dumbwm - dynamic window manager +# (C)opyright MMVI Anselm R. Garbe + +include config.mk + +SRC = bar.c client.c dev.c draw.c event.c main.c util.c +OBJ = ${SRC:.c=.o} +MAN1 = dumbwm.1 +BIN = dumbwm + +all: config dumbwm + @echo finished + +config: + @echo dumbwm build options: + @echo "LIBS = ${LIBS}" + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: dumbwm.h + +dumbwm: ${OBJ} + @echo LD $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f dumbwm *.o core + +dist: clean + mkdir -p dumbwm-${VERSION} + cp -R Makefile README LICENSE config.mk *.h *.c ${MAN1} dumbwm-${VERSION} + tar -cf dumbwm-${VERSION}.tar dumbwm-${VERSION} + gzip dumbwm-${VERSION}.tar + rm -rf dumbwm-${VERSION} + +install: all + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f ${BIN} ${DESTDIR}${PREFIX}/bin + @echo installed executable files to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${MANPREFIX}/man1 + @cp -f ${MAN1} ${DESTDIR}${MANPREFIX}/man1 + @echo installed manual pages to ${DESTDIR}${MANPREFIX}/man1 + +uninstall: + for i in ${BIN}; do \ + rm -f ${DESTDIR}${PREFIX}/bin/`basename $$i`; \ + done + for i in ${MAN1}; do \ + rm -f ${DESTDIR}${MANPREFIX}/man1/`basename $$i`; \ + done diff --git a/bar.c b/bar.c new file mode 100644 index 0000000..03e0786 --- /dev/null +++ b/bar.c @@ -0,0 +1,46 @@ +/* + * (C)opyright MMVI Anselm R. Garbe + * See LICENSE file for license details. + */ + +#include "dumbwm.h" + +void +barclick(XButtonPressedEvent *e) +{ + int x = 0; + Arg a; + for(a.i = 0; a.i < TLast; a.i++) { + x += textw(tags[a.i]) + dc.font.height; + if(e->x < x) { + view(&a); + return; + } + } +} + +void +draw_bar() +{ + int i; + dc.x = dc.y = 0; + dc.w = bw; + drawtext(NULL, False, False); + + dc.w = 0; + for(i = 0; i < TLast; i++) { + dc.x += dc.w; + dc.w = textw(tags[i]) + dc.font.height; + drawtext(tags[i], i == tsel, True); + } + if(sel) { + dc.x += dc.w; + dc.w = textw(sel->name) + dc.font.height; + drawtext(sel->name, True, True); + } + dc.w = textw(stext) + dc.font.height; + dc.x = bx + bw - dc.w; + drawtext(stext, False, False); + XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, bw, bh, 0, 0); + XFlush(dpy); +} diff --git a/bar.o b/bar.o new file mode 100644 index 0000000000000000000000000000000000000000..5527d63615c551cd90185125a923621680196ff5 GIT binary patch literal 3344 zcmbuBTWDNG7{_NXY1W#auC-#IRu-Dd2HWEvtJoB)yG@f!LkPh(THD6;>?Pf8HWzkJ zx{0V&7OTq|^+AfDZ+$N!eW-nqV1iH(l)m^-#0MX|)Cct;6soNA&G|m^G46TMfyvDL z=Ko#hvU74_Xlytf3JEG9@r>9U5f$Rwdp7%N-A#*aqDN#-jIHd2@uY12ecZVv8^6U1 zvK8H%R7^IH_QjmlX0)$yCvu@*esrw$^!m@Bj&#A_(AvOM`n9dH`ICmXyIaw|_Ui3# zWJ}o<`5%SiKo5e#DABp(JCd ze-@l8d@(#?^)@1-RwDeXl^n8CFIor3t@MPp$yhOzcWl5#RQ%EIG#Tk|v%8gW2je+Gbm9*O@I3(>_5<>vJoKI@1{bfB|8xL97QjaX_;>(65x`#v;HLuk zO98wXz~=+F$hlQJ4}bHOa(+g5?%A5~ic4Ny6!PMHxmXw3Y|V4?GueD;COhqxE22se(Xa!RE7AQxV(SP?bd%`J&sNfZ{A!EL=fCr%E|FDz%OMOU00t}NC{Di{6xQ*BsP z_+9+f_R9g)hXM>V#0LPX0{Shg!ns0`exvnp_eej@I9zbzuOm0(zRmbnrhkudh}(nX zO9tPGU6jv{$j$tJ zXL@)e$`9Fvp^xXe$#=$?WYmdPx|0MIz_x~}bw^;s9F+IO; zhnb$=2gx|kXPoiv%>VO@^ZhwvaN3_da&!O7Ob_oC?SGx|`xt+dafnO$cNpKn`1_3W z^QtVo|weJF75P^nB{hd908!mcgPdTvg&Ue#|) z)T@!7dWd!ahNP^@~(!qy&& zrR;RoorRb5|CfYv0ZWIy<0XxQ&v0L8&KL^#4#FO%Nq}t*AM%O_HH?1;7YuJ5oRMh{ gVa&5rNPLR-<~$5oG4~IC!=3D3#{4VH7P_YWKTtu-7XSbN literal 0 HcmV?d00001 diff --git a/client.c b/client.c new file mode 100644 index 0000000..6dc2f70 --- /dev/null +++ b/client.c @@ -0,0 +1,616 @@ +/* + * (C)opyright MMVI Anselm R. Garbe + * See LICENSE file for license details. + */ + +#include +#include +#include +#include +#include + +#include "dumbwm.h" + +void (*arrange)(Arg *) = tiling; + +static Rule rule[] = { + /* class instance tags floating */ + { "Firefox-bin", "Gecko", { [Twww] = "www" }, False }, +}; + +static Client * +next(Client *c) +{ + for(; c && !c->tags[tsel]; c = c->next); + return c; +} + +void +zoom(Arg *arg) +{ + Client **l, *c; + + if(!sel) + return; + + if(sel == next(clients) && sel->next) { + if((c = next(sel->next))) + sel = c; + } + + for(l = &clients; *l && *l != sel; l = &(*l)->next); + *l = sel->next; + + sel->next = clients; /* pop */ + clients = sel; + arrange(NULL); + focus(sel); +} + +void +max(Arg *arg) +{ + if(!sel) + return; + sel->x = sx; + sel->y = sy + bh; + sel->w = sw - 2 * sel->border; + sel->h = sh - 2 * sel->border - bh; + craise(sel); + resize(sel, False); +} + +void +view(Arg *arg) +{ + Client *c; + + tsel = arg->i; + arrange(NULL); + + for(c = clients; c; c = next(c->next)) + draw_client(c); + draw_bar(); +} + +void +tappend(Arg *arg) +{ + if(!sel) + return; + + sel->tags[arg->i] = tags[arg->i]; + arrange(NULL); +} + +void +ttrunc(Arg *arg) +{ + int i; + if(!sel) + return; + + for(i = 0; i < TLast; i++) + sel->tags[i] = NULL; + tappend(arg); +} + +static void +ban_client(Client *c) +{ + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty); +} + +void +floating(Arg *arg) +{ + Client *c; + + arrange = floating; + for(c = clients; c; c = c->next) { + if(c->tags[tsel]) + resize(c, True); + else + ban_client(c); + } + if(sel && !sel->tags[tsel]) { + if((sel = next(clients))) { + craise(sel); + focus(sel); + } + } +} + +void +tiling(Arg *arg) +{ + Client *c; + int n, i, w, h; + + w = sw - mw; + arrange = tiling; + for(n = 0, c = clients; c; c = c->next) + if(c->tags[tsel] && !c->floating) + n++; + + if(n > 1) + h = (sh - bh) / (n - 1); + else + h = sh - bh; + + for(i = 0, c = clients; c; c = c->next) { + if(c->tags[tsel]) { + if(c->floating) { + craise(c); + resize(c, True); + continue; + } + if(n == 1) { + c->x = sx; + c->y = sy + bh; + c->w = sw - 2 * c->border; + c->h = sh - 2 * c->border - bh; + } + else if(i == 0) { + c->x = sx; + c->y = sy + bh; + c->w = mw - 2 * c->border; + c->h = sh - 2 * c->border - bh; + } + else { + c->x = sx + mw; + c->y = sy + (i - 1) * h + bh; + c->w = w - 2 * c->border; + c->h = h - 2 * c->border; + } + resize(c, False); + i++; + } + else + ban_client(c); + } + if(!sel || (sel && !sel->tags[tsel])) { + if((sel = next(clients))) { + craise(sel); + focus(sel); + } + } +} + +void +prevc(Arg *arg) +{ + Client *c; + + if(!sel) + return; + + if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) { + craise(c); + focus(c); + } +} + +void +nextc(Arg *arg) +{ + Client *c; + + if(!sel) + return; + + if(!(c = next(sel->next))) + c = next(clients); + if(c) { + craise(c); + c->revert = sel; + focus(c); + } +} + +void +ckill(Arg *arg) +{ + if(!sel) + return; + if(sel->proto & WM_PROTOCOL_DELWIN) + send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]); + else + XKillClient(dpy, sel->win); +} + +static void +resize_title(Client *c) +{ + int i; + + c->tw = 0; + for(i = 0; i < TLast; i++) + if(c->tags[i]) + c->tw += textw(c->tags[i]) + dc.font.height; + c->tw += textw(c->name) + dc.font.height; + if(c->tw > c->w) + c->tw = c->w + 2; + c->tx = c->x + c->w - c->tw + 2; + c->ty = c->y; + XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th); +} + +void +update_name(Client *c) +{ + XTextProperty name; + int n; + char **list = NULL; + + name.nitems = 0; + c->name[0] = 0; + XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]); + if(!name.nitems) + XGetWMName(dpy, c->win, &name); + if(!name.nitems) + return; + if(name.encoding == XA_STRING) + strncpy(c->name, (char *)name.value, sizeof(c->name)); + else { + if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success + && n > 0 && *list) + { + strncpy(c->name, *list, sizeof(c->name)); + XFreeStringList(list); + } + } + XFree(name.value); + resize_title(c); +} + +void +update_size(Client *c) +{ + XSizeHints size; + long msize; + if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) + size.flags = PSize; + c->flags = size.flags; + if(c->flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } + else + c->basew = c->baseh = 0; + if(c->flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } + else + c->incw = c->inch = 0; + if(c->flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } + else + c->maxw = c->maxh = 0; + if(c->flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } + else + c->minw = c->minh = 0; + if(c->flags & PWinGravity) + c->grav = size.win_gravity; + else + c->grav = NorthWestGravity; +} + +void +craise(Client *c) +{ + XRaiseWindow(dpy, c->win); + XRaiseWindow(dpy, c->title); +} + +void +lower(Client *c) +{ + XLowerWindow(dpy, c->title); + XLowerWindow(dpy, c->win); +} + +void +focus(Client *c) +{ + Client *old = sel; + XEvent ev; + + XFlush(dpy); + sel = c; + if(old && old != c) + draw_client(old); + draw_client(c); + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XFlush(dpy); + while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +static void +init_tags(Client *c) +{ + XClassHint ch; + static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0; + unsigned int i, j; + Bool matched = False; + + if(!len) { + c->tags[tsel] = tags[tsel]; + return; + } + + if(XGetClassHint(dpy, c->win, &ch)) { + if(ch.res_class && ch.res_name) { + for(i = 0; i < len; i++) + if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class)) + && !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance))) + { + for(j = 0; j < TLast; j++) + c->tags[j] = rule[i].tags[j]; + c->floating = rule[i].floating; + matched = True; + break; + } + } + if(ch.res_class) + XFree(ch.res_class); + if(ch.res_name) + XFree(ch.res_name); + } + + if(!matched) + c->tags[tsel] = tags[tsel]; +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, **l; + XSetWindowAttributes twa; + Window trans; + + c = emallocz(sizeof(Client)); + c->win = w; + c->tx = c->x = wa->x; + c->ty = c->y = wa->y; + if(c->y < bh) + c->ty = c->y += bh; + c->tw = c->w = wa->width; + c->h = wa->height; + c->th = bh; + c->border = 1; + c->proto = win_proto(c->win); + update_size(c); + XSelectInput(dpy, c->win, + StructureNotifyMask | PropertyChangeMask | EnterWindowMask); + XGetTransientForHint(dpy, c->win, &trans); + twa.override_redirect = 1; + twa.background_pixmap = ParentRelative; + twa.event_mask = ExposureMask; + + c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th, + 0, DefaultDepth(dpy, screen), CopyFromParent, + DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa); + + update_name(c); + init_tags(c); + + for(l = &clients; *l; l = &(*l)->next); + c->next = *l; /* *l == nil */ + *l = c; + + XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask, + GrabModeAsync, GrabModeSync, None, None); + + if(!c->floating) + c->floating = trans + || ((c->maxw == c->minw) && (c->maxh == c->minh)); + + arrange(NULL); + /* mapping the window now prevents flicker */ + if(c->tags[tsel]) { + XMapRaised(dpy, c->win); + XMapRaised(dpy, c->title); + focus(c); + } + else { + ban_client(c); + XMapRaised(dpy, c->win); + XMapRaised(dpy, c->title); + } +} + +void +gravitate(Client *c, Bool invert) +{ + int dx = 0, dy = 0; + + switch(c->grav) { + case StaticGravity: + case NorthWestGravity: + case NorthGravity: + case NorthEastGravity: + dy = c->border; + break; + case EastGravity: + case CenterGravity: + case WestGravity: + dy = -(c->h / 2) + c->border; + break; + case SouthEastGravity: + case SouthGravity: + case SouthWestGravity: + dy = -c->h; + break; + default: + break; + } + + switch (c->grav) { + case StaticGravity: + case NorthWestGravity: + case WestGravity: + case SouthWestGravity: + dx = c->border; + break; + case NorthGravity: + case CenterGravity: + case SouthGravity: + dx = -(c->w / 2) + c->border; + break; + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: + dx = -(c->w + c->border); + break; + default: + break; + } + + if(invert) { + dx = -dx; + dy = -dy; + } + c->x += dx; + c->y += dy; +} + + +void +resize(Client *c, Bool inc) +{ + XConfigureEvent e; + + if(inc) { + if(c->incw) + c->w -= (c->w - c->basew) % c->incw; + if(c->inch) + c->h -= (c->h - c->baseh) % c->inch; + } + if(c->x > sw) /* might happen on restart */ + c->x = sw - c->w; + if(c->y > sh) + c->ty = c->y = sh - c->h; + if(c->minw && c->w < c->minw) + c->w = c->minw; + if(c->minh && c->h < c->minh) + c->h = c->minh; + if(c->maxw && c->w > c->maxw) + c->w = c->maxw; + if(c->maxh && c->h > c->maxh) + c->h = c->maxh; + resize_title(c); + XSetWindowBorderWidth(dpy, c->win, 1); + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + e.type = ConfigureNotify; + e.event = c->win; + e.window = c->win; + e.x = c->x; + e.y = c->y; + e.width = c->w; + e.height = c->h; + e.border_width = c->border; + e.above = None; + e.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e); + XFlush(dpy); +} + +static int +dummy_error_handler(Display *dsply, XErrorEvent *err) +{ + return 0; +} + +void +unmanage(Client *c) +{ + Client **l; + + XGrabServer(dpy); + XSetErrorHandler(dummy_error_handler); + + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + XDestroyWindow(dpy, c->title); + + for(l = &clients; *l && *l != c; l = &(*l)->next); + *l = c->next; + for(l = &clients; *l; l = &(*l)->next) + if((*l)->revert == c) + (*l)->revert = NULL; + if(sel == c) + sel = sel->revert ? sel->revert : clients; + + free(c); + + XFlush(dpy); + XSetErrorHandler(error_handler); + XUngrabServer(dpy); + arrange(NULL); + if(sel) + focus(sel); +} + +Client * +gettitle(Window w) +{ + Client *c; + for(c = clients; c; c = c->next) + if(c->title == w) + return c; + return NULL; +} + +Client * +getclient(Window w) +{ + Client *c; + for(c = clients; c; c = c->next) + if(c->win == w) + return c; + return NULL; +} + +void +draw_client(Client *c) +{ + int i; + if(c == sel) { + draw_bar(); + XUnmapWindow(dpy, c->title); + XSetWindowBorder(dpy, c->win, dc.fg); + return; + } + + XSetWindowBorder(dpy, c->win, dc.bg); + XMapWindow(dpy, c->title); + + dc.x = dc.y = 0; + + dc.w = 0; + for(i = 0; i < TLast; i++) { + if(c->tags[i]) { + dc.x += dc.w; + dc.w = textw(c->tags[i]) + dc.font.height; + drawtext(c->tags[i], False, True); + } + } + dc.x += dc.w; + dc.w = textw(c->name) + dc.font.height; + drawtext(c->name, False, True); + XCopyArea(dpy, dc.drawable, c->title, dc.gc, + 0, 0, c->tw, c->th, 0, 0); + XFlush(dpy); +} diff --git a/client.o b/client.o new file mode 100644 index 0000000000000000000000000000000000000000..75185d81e6549ce7798c0a72eac5aa69fa38f3a4 GIT binary patch literal 16376 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 + * See LICENSE file for license details. + */ + +#include "dumbwm.h" + +#include +#include +#include +#include + +/********** CUSTOMIZE **********/ + +const char *term[] = { + "urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-fn", + "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*",NULL +}; +const char *browse[] = { "firefox", NULL }; +const char *xlock[] = { "xlock", NULL }; + +static Key key[] = { + /* modifier key function arguments */ + { Mod1Mask, XK_Return, zoom, { 0 } }, + { Mod1Mask, XK_k, prevc, { 0 } }, + { Mod1Mask, XK_j, nextc, { 0 } }, + { Mod1Mask, XK_m, max, { 0 } }, + { Mod1Mask, XK_0, view, { .i = Tscratch } }, + { Mod1Mask, XK_1, view, { .i = Tdev } }, + { Mod1Mask, XK_2, view, { .i = Twww } }, + { Mod1Mask, XK_3, view, { .i = Twork } }, + { Mod1Mask, XK_space, tiling, { 0 } }, + { Mod1Mask|ShiftMask, XK_space, floating, { 0 } }, + { Mod1Mask|ShiftMask, XK_0, ttrunc, { .i = Tscratch } }, + { Mod1Mask|ShiftMask, XK_1, ttrunc, { .i = Tdev } }, + { Mod1Mask|ShiftMask, XK_2, ttrunc, { .i = Twww } }, + { Mod1Mask|ShiftMask, XK_3, ttrunc, { .i = Twork } }, + { Mod1Mask|ShiftMask, XK_c, ckill, { 0 } }, + { Mod1Mask|ShiftMask, XK_q, quit, { 0 } }, + { Mod1Mask|ShiftMask, XK_Return, spawn, { .argv = term } }, + { Mod1Mask|ShiftMask, XK_w, spawn, { .argv = browse } }, + { Mod1Mask|ShiftMask, XK_l, spawn, { .argv = xlock } }, + { ControlMask, XK_0, tappend, { .i = Tscratch } }, + { ControlMask, XK_1, tappend, { .i = Tdev } }, + { ControlMask, XK_2, tappend, { .i = Twww } }, + { ControlMask, XK_3, tappend, { .i = Twork } }, +}; + +/********** CUSTOMIZE **********/ + +void +update_keys(void) +{ + static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0; + unsigned int i; + KeyCode code; + + for(i = 0; i < len; i++) { + code = XKeysymToKeycode(dpy, key[i].keysym); + XUngrabKey(dpy, code, key[i].mod, root); + XGrabKey(dpy, code, key[i].mod, root, True, GrabModeAsync, GrabModeAsync); + } +} + +void +keypress(XEvent *e) +{ + XKeyEvent *ev = &e->xkey; + static unsigned int len = key ? sizeof(key) / sizeof(key[0]) : 0; + unsigned int i; + KeySym keysym; + + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for(i = 0; i < len; i++) + if((keysym == key[i].keysym) && (key[i].mod == ev->state)) { + if(key[i].func) + key[i].func(&key[i].arg); + return; + } +} + +#define ButtonMask (ButtonPressMask | ButtonReleaseMask) +#define MouseMask (ButtonMask | PointerMotionMask) + +void +mresize(Client *c) +{ + XEvent ev; + int ocx, ocy; + + ocx = c->x; + ocy = c->y; + if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize], CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h); + for(;;) { + XMaskEvent(dpy, MouseMask | ExposureMask, &ev); + switch(ev.type) { + default: break; + case Expose: + handler[Expose](&ev); + break; + case MotionNotify: + XFlush(dpy); + c->w = abs(ocx - ev.xmotion.x); + c->h = abs(ocy - ev.xmotion.y); + c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w; + c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h; + resize(c, True); + break; + case ButtonRelease: + XUngrabPointer(dpy, CurrentTime); + return; + } + } +} + +void +mmove(Client *c) +{ + XEvent ev; + int x1, y1, ocx, ocy, di; + unsigned int dui; + Window dummy; + + ocx = c->x; + ocy = c->y; + if(XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove], CurrentTime) != GrabSuccess) + return; + XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui); + for(;;) { + XMaskEvent(dpy, MouseMask | ExposureMask, &ev); + switch (ev.type) { + default: break; + case Expose: + handler[Expose](&ev); + break; + case MotionNotify: + XFlush(dpy); + c->x = ocx + (ev.xmotion.x - x1); + c->y = ocy + (ev.xmotion.y - y1); + resize(c, False); + break; + case ButtonRelease: + XUngrabPointer(dpy, CurrentTime); + return; + } + } +} diff --git a/dev.o b/dev.o new file mode 100644 index 0000000000000000000000000000000000000000..348247ca3d4a49b237535f515959269c08ce2502 GIT binary patch literal 6968 zcmd6rZ){W76~M2Zq+}Fc%-?z|rEY6RAjFDki^#N1F*xC^Gt6Cr$Ob4l_Df>oe>^|u z4{bG=3*yPO7Kv>_+J{c7v`za$CQXcfL4i~%{je!i+r+jHb31LLV`}L>K(tQE&Ux=1 zbGi5~mG))FdOqj=&bjB_ci#1T_xW4Bu|BWI!$>^r%j|xOC}Wp5-nV-kvxlu^YglC9 zV832{0!gg;M$OBZUMaTfl`kRD%kzO-XjJ-ZdSx|QZI^Cwr~RSh;@tj_<2b}d-oz)qX@ zjr!I1Tl7kFqfb9GXRXt#FK_f8UaBo!)5})_<$pa^x^Z|ua!?#I{BC66%@_<0=VpJR zpZ-S;?8?O;%qLp;Njs>NUTNOa4pg^a4K9EV&mD&|e;zEhKPneIB{-Zo?QM@t)ERCfD{Sgp#-LEXMpv4XLv{ob}k``W!fwCM}m zKDMvlyJ?@t3AE`~?GJ2ccHJMn;@x(`t~dp--;Z|x724PA^H_;1a6lFQ40P;nv7%ah&?;w{8N)OBgx2T*dD|WK>=98n{1Y$$tra{(AU>b@%`Gx<_?I-J`+5@Li}^)N`w&IcS%$ zrf?aLL_M{RXt3EXV^Q5}cLpnoC2LSgjNp|7OD(P3wR)*>4Ee_!yBYb9FXPWHVlhi@dENS0i7eGY;r7Z8DQmD=k`v^Fth1gso0q{Qt46_2!6uPaswOb zVm{op>$zQ>+v#NgAN0Pxd%qB9-*@2Pwm^7iC>-L2$2tYzXn_Nq%*#A;$mn^A!c^+T2qICv>p98kZ@i1ng-lO?m^F}oP*`|mVC^vf#Xzed*U42?RH2XAv zMDy*@;75ji26(@I)Zi$4y?a+`t$QAgX{|>9Ir%`FI4Q_m^~N>-YfXJx;B0e5YcIFF zpq=v$Yct;c+6C`dv>(E83PR3#2Z8MawudwCubkmwR*=ORo?-sqz=86DI{yW45_0U< zehRr~;h2H*x!^qntPfZOSU)iD>ks93Ge7)|Lp8IH8{S=;>eavBZv~hh=PJ1jcT6Nr z0w;#LiD9n?B%UjvTy>E_qlS);(NE8>5r;D1!` z_Z0kZ3VvI`?wR>A$i*T60y0OO;?UB#Z@oW>@N+bN7EA-)|r z+2nI{%9scx*|;&yN`+LyGKRn`vQ%N34Sp4@>FhurbTXeZn3>O8Z17-i)JzNmV}tv+ z0bL5FQ7k%LFx2S-eOVT8`lP{U9K+`$8#eQkMT5D|SSwK| z7`YTL9^H{}IpcHY->~sV`7HM%#~9*IbB?iib%^8r2LHZI4Tp4Tsg zJotJ_=d}_~2n5d;|8gL{Rp9uHBmQm9QHks4oWQZptKdNSj=;tFe4lf<&KHGvG5;lj zi+O%4^~&*@Jy?&x7K36~o^ca%mVgF9RMgkB|E%%qfR| z+Wxq|YBYY0C#;E!3St9rh=S|0(fRk_LkxuO19<-UJC)DB2N;eo|L-%$FUSb^M4|I1 zJpfL$<@4{sha5=3RrT*c-Exhufoe4WS$uecwDN&){y2Ae{wZJ>LiY5 znm1|uzm#k-Zl3oS8QOB}E5I;Rx=idk?=R1b=8w5hz6S^9l>0AIe`!Fu{|xkPRKLso zMtThVC|Ez-FH?V7|Bc4R_;&t><4t~HeZX)@$o(-)zV?9J!9eYl<}Wqj9kFqLKW=(J LUUyafTkiiKT$r4$ literal 0 HcmV?d00001 diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..c237b93 --- /dev/null +++ b/draw.c @@ -0,0 +1,158 @@ +/* + * (C)opyright MMIV-MMVI Anselm R. Garbe + * See LICENSE file for license details. + */ + +#include +#include + +#include + +#include "dumbwm.h" + +static void +drawborder(void) +{ + XPoint points[5]; + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); + XSetForeground(dpy, dc.gc, dc.border); + points[0].x = dc.x; + points[0].y = dc.y; + points[1].x = dc.w - 1; + points[1].y = 0; + points[2].x = 0; + points[2].y = dc.h - 1; + points[3].x = -(dc.w - 1); + points[3].y = 0; + points[4].x = 0; + points[4].y = -(dc.h - 1); + XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious); +} + +void +drawtext(const char *text, Bool invert, Bool border) +{ + int x, y, w, h; + unsigned int len; + static char buf[256]; + XGCValues gcv; + XRectangle r = { dc.x, dc.y, dc.w, dc.h }; + + XSetForeground(dpy, dc.gc, invert ? dc.fg : dc.bg); + XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); + + w = 0; + if(border) + drawborder(); + + if(!text) + return; + + len = strlen(text); + if(len >= sizeof(buf)) + len = sizeof(buf) - 1; + memcpy(buf, text, len); + buf[len] = 0; + + h = dc.font.ascent + dc.font.descent; + y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; + x = dc.x + (h / 2); + + /* shorten text if necessary */ + while(len && (w = textnw(buf, len)) > dc.w - h) + buf[--len] = 0; + + if(w > dc.w) + return; /* too long */ + + gcv.foreground = invert ? dc.bg : dc.fg; + gcv.background = invert ? dc.fg : dc.bg; + if(dc.font.set) { + XChangeGC(dpy, dc.gc, GCForeground | GCBackground, &gcv); + XmbDrawImageString(dpy, dc.drawable, dc.font.set, dc.gc, + x, y, buf, len); + } + else { + gcv.font = dc.font.xfont->fid; + XChangeGC(dpy, dc.gc, GCForeground | GCBackground | GCFont, &gcv); + XDrawImageString(dpy, dc.drawable, dc.gc, x, y, buf, len); + } +} + +unsigned long +initcolor(const char *colstr) +{ + XColor color; + Colormap cmap = DefaultColormap(dpy, screen); + + XAllocNamedColor(dpy, cmap, colstr, &color, &color); + return color.pixel; +} + +unsigned int +textnw(char *text, unsigned int len) +{ + XRectangle r; + if(dc.font.set) { + XmbTextExtents(dc.font.set, text, len, NULL, &r); + return r.width; + } + return XTextWidth(dc.font.xfont, text, len); +} + +unsigned int +textw(char *text) +{ + return textnw(text, strlen(text)); +} + +void +initfont(const char *fontstr) +{ + char **missing, *def; + int i, n; + + missing = NULL; + setlocale(LC_ALL, ""); + if(dc.font.set) + XFreeFontSet(dpy, dc.font.set); + dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); + if(missing) { + while(n--) + fprintf(stderr, "missing fontset: %s\n", missing[n]); + XFreeStringList(missing); + if(dc.font.set) { + XFreeFontSet(dpy, dc.font.set); + dc.font.set = NULL; + } + } + if(dc.font.set) { + XFontSetExtents *font_extents; + XFontStruct **xfonts; + char **font_names; + + dc.font.ascent = dc.font.descent = 0; + font_extents = XExtentsOfFontSet(dc.font.set); + n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); + for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { + if(dc.font.ascent < (*xfonts)->ascent) + dc.font.ascent = (*xfonts)->ascent; + if(dc.font.descent < (*xfonts)->descent) + dc.font.descent = (*xfonts)->descent; + xfonts++; + } + } + else { + if(dc.font.xfont) + XFreeFont(dpy, dc.font.xfont); + dc.font.xfont = NULL; + dc.font.xfont = XLoadQueryFont(dpy, fontstr); + if (!dc.font.xfont) + dc.font.xfont = XLoadQueryFont(dpy, "fixed"); + if (!dc.font.xfont) + error("error, cannot init 'fixed' font\n"); + dc.font.ascent = dc.font.xfont->ascent; + dc.font.descent = dc.font.xfont->descent; + } + dc.font.height = dc.font.ascent + dc.font.descent; +} diff --git a/draw.o b/draw.o new file mode 100644 index 0000000000000000000000000000000000000000..8ef32e7c35a849b57149adbfb8fb0cbef01b0324 GIT binary patch literal 7192 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

LrP}ei<2s+JD_1h&b^;6fn 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 + * See LICENSE file for license details. + */ + +#include + +/********** CUSTOMIZE **********/ + +#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*" +#define BGCOLOR "#666699" +#define FGCOLOR "#eeeeee" +#define BORDERCOLOR "#9999CC" +#define MASTERW 52 /* percent */ +#define WM_PROTOCOL_DELWIN 1 + +/* tags */ +enum { Tscratch, Tdev, Twww, Twork, TLast }; + +/********** CUSTOMIZE **********/ + +typedef union Arg Arg; +typedef struct DC DC; +typedef struct Client Client; +typedef struct Fnt Fnt; +typedef struct Key Key; +typedef struct Rule Rule; + +union Arg { + const char **argv; + int i; +}; + +/* atoms */ +enum { WMProtocols, WMDelete, WMLast }; +enum { NetSupported, NetWMName, NetLast }; + +/* cursor */ +enum { CurNormal, CurResize, CurMove, CurInput, CurLast }; + +struct Fnt { + XFontStruct *xfont; + XFontSet set; + int ascent; + int descent; + int height; +}; + +struct DC { /* draw context */ + GC gc; + Drawable drawable; + int x, y, w, h; + Fnt font; + unsigned long bg; + unsigned long fg; + unsigned long border; +}; + +struct Client { + char name[256]; + char *tags[TLast]; + int proto; + int x, y, w, h; + int tx, ty, tw, th; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int grav; + unsigned int border; + long flags; + Bool floating; + Window win; + Window title; + Client *next; + Client *revert; +}; + +struct Rule { + const char *class; + const char *instance; + char *tags[TLast]; + Bool floating; +}; + +struct Key { + unsigned long mod; + KeySym keysym; + void (*func)(Arg *arg); + Arg arg; +}; + +extern Display *dpy; +extern Window root, barwin; +extern Atom wm_atom[WMLast], net_atom[NetLast]; +extern Cursor cursor[CurLast]; +extern Bool running, issel; +extern void (*handler[LASTEvent])(XEvent *); +extern void (*arrange)(Arg *); + +extern int tsel, screen, sx, sy, sw, sh, bx, by, bw, bh, mw; +extern char *tags[TLast], stext[1024]; + +extern DC dc; +extern Client *clients, *sel; + +/* bar.c */ +extern void draw_bar(); +extern void barclick(XButtonPressedEvent *e); + +/* client.c */ +extern void manage(Window w, XWindowAttributes *wa); +extern void unmanage(Client *c); +extern Client *getclient(Window w); +extern void focus(Client *c); +extern void update_name(Client *c); +extern void draw_client(Client *c); +extern void resize(Client *c, Bool inc); +extern void update_size(Client *c); +extern Client *gettitle(Window w); +extern void craise(Client *c); +extern void lower(Client *c); +extern void ckill(Arg *arg); +extern void nextc(Arg *arg); +extern void prevc(Arg *arg); +extern void max(Arg *arg); +extern void floating(Arg *arg); +extern void tiling(Arg *arg); +extern void ttrunc(Arg *arg); +extern void tappend(Arg *arg); +extern void view(Arg *arg); +extern void zoom(Arg *arg); +extern void gravitate(Client *c, Bool invert); + +/* draw.c */ +extern void drawtext(const char *text, Bool invert, Bool border); +extern unsigned long initcolor(const char *colstr); +extern void initfont(const char *fontstr); +extern unsigned int textnw(char *text, unsigned int len); +extern unsigned int textw(char *text); +extern unsigned int texth(void); + +/* dev.c */ +extern void update_keys(void); +extern void keypress(XEvent *e); +extern void mresize(Client *c); +extern void mmove(Client *c); + +/* main.c */ +extern int error_handler(Display *dsply, XErrorEvent *e); +extern void send_message(Window w, Atom a, long value); +extern int win_proto(Window w); +extern void quit(Arg *arg); + +/* util.c */ +extern void error(const char *errstr, ...); +extern void *emallocz(unsigned int size); +extern void spawn(Arg *arg); diff --git a/event.c b/event.c new file mode 100644 index 0000000..b4ca5c4 --- /dev/null +++ b/event.c @@ -0,0 +1,216 @@ +/* + * (C)opyright MMVI Anselm R. Garbe + * See LICENSE file for license details. + */ + +#include +#include +#include +#include +#include +#include + +#include "dumbwm.h" + +/* local functions */ +static void buttonpress(XEvent *e); +static void configurerequest(XEvent *e); +static void destroynotify(XEvent *e); +static void enternotify(XEvent *e); +static void leavenotify(XEvent *e); +static void expose(XEvent *e); +static void keymapnotify(XEvent *e); +static void maprequest(XEvent *e); +static void propertynotify(XEvent *e); +static void unmapnotify(XEvent *e); + +void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ConfigureRequest] = configurerequest, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [LeaveNotify] = leavenotify, + [Expose] = expose, + [KeyPress] = keypress, + [KeymapNotify] = keymapnotify, + [MapRequest] = maprequest, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify +}; + +static void +buttonpress(XEvent *e) +{ + XButtonPressedEvent *ev = &e->xbutton; + Client *c; + + if(barwin == ev->window) + barclick(ev); + else if((c = getclient(ev->window))) { + craise(c); + switch(ev->button) { + default: + break; + case Button1: + mmove(c); + break; + case Button2: + lower(c); + break; + case Button3: + mresize(c); + break; + } + } +} + +static void +configurerequest(XEvent *e) +{ + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + Client *c; + + ev->value_mask &= ~CWSibling; + if((c = getclient(ev->window))) { + gravitate(c, True); + if(ev->value_mask & CWX) + c->x = ev->x; + if(ev->value_mask & CWY) + c->y = ev->y; + if(ev->value_mask & CWWidth) + c->w = ev->width; + if(ev->value_mask & CWHeight) + c->h = ev->height; + if(ev->value_mask & CWBorderWidth) + c->border = 1; + gravitate(c, False); + resize(c, True); + } + + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = 1; + wc.sibling = None; + wc.stack_mode = Above; + ev->value_mask &= ~CWStackMode; + ev->value_mask |= CWBorderWidth; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + XFlush(dpy); +} + +static void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if((c = getclient(ev->window))) + unmanage(c); +} + +static void +enternotify(XEvent *e) +{ + XCrossingEvent *ev = &e->xcrossing; + Client *c; + + if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) + return; + + if((c = getclient(ev->window))) + focus(c); + else if(ev->window == root) + issel = True; +} + +static void +leavenotify(XEvent *e) +{ + XCrossingEvent *ev = &e->xcrossing; + + if((ev->window == root) && !ev->same_screen) + issel = True; +} + +static void +expose(XEvent *e) +{ + XExposeEvent *ev = &e->xexpose; + Client *c; + + if(ev->count == 0) { + if((c = gettitle(ev->window))) + draw_client(c); + } +} + +static void +keymapnotify(XEvent *e) +{ + update_keys(); +} + +static void +maprequest(XEvent *e) +{ + XMapRequestEvent *ev = &e->xmaprequest; + static XWindowAttributes wa; + + if(!XGetWindowAttributes(dpy, ev->window, &wa)) + return; + + if(wa.override_redirect) { + XSelectInput(dpy, ev->window, + (StructureNotifyMask | PropertyChangeMask)); + return; + } + + if(!getclient(ev->window)) + manage(ev->window, &wa); +} + +static void +propertynotify(XEvent *e) +{ + XPropertyEvent *ev = &e->xproperty; + Window trans; + Client *c; + + if(ev->state == PropertyDelete) + return; /* ignore */ + + if((c = getclient(ev->window))) { + if(ev->atom == wm_atom[WMProtocols]) { + c->proto = win_proto(c->win); + return; + } + switch (ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + XGetTransientForHint(dpy, c->win, &trans); + if(!c->floating && (c->floating = (trans != 0))) + arrange(NULL); + break; + case XA_WM_NORMAL_HINTS: + update_size(c); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == net_atom[NetWMName]) { + update_name(c); + draw_client(c); + } + } +} + +static void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if((c = getclient(ev->window))) + unmanage(c); +} diff --git a/event.o b/event.o new file mode 100644 index 0000000000000000000000000000000000000000..cf0e3d11e2360e90faf03a821d846c73ed6edab1 GIT binary patch literal 6072 zcmeH~Uu+!38NlbxPB`0ez7X0Te@Zs=0!IiZ9|B}T0>0ik9;BuU*r7)ZIyQG}`{cXZ z%kFH>1|&x;sj|9OLPC}*BoGfsAi)D_g;X_CbE<=ks=gFe>PuS!52YAgD;d)LtJ z`77QRhPrXdONBu(?GP>Fed_?T( z{O0DjQ1!zE4c-ms#`*k>TiB4CHMP~Xr2@X!=xt#nY)3fGznGqVYz@K;K7~lfFN-vb zGtZabg$T2u_Sqh5(qR49=ok&&5>pq;ug2I=cX}*X%|OqqactZftY)z>h>h`J^#C>! z*fZMG!PbS786AxY%><|Qd;_qOWl)t2hD~JrH za68a@`DETz)W3-9Fv~Tyqz*>pm2Go)e@8B#8w)KBLSevz+XXsF zoWy#_q{KuUcM{4qVL@U~JVatkso3>bUXgefIy1m;5PctDSxBaS94{o({y-@?7XM2! z4WN)rpk7Jn4WrR*y{Y7}`2VCH+G+^B>#zj9hlZ1h$q_IDP3->(a*%%gDd4a3-Y_<- zPQcTH2gSu7u<6IAlE#C>$y5n#pMnb5pByQDvBG-@+8q?hxDjoD9D*k;n1z7HL@{W~}I!)P#;vKYS?$4^}zs{x1~0ZydZc% z@Gg|N2Xt8l(2u_m!C#5sc$esBrx(HBj^KZY;D3(b_>u27?|&lrPFUA|`ep>jL%E;+ z-UyCYhJO0_2!1$%mm>Jl2tE_RPeky?BRF1X`uX3C;BEvz7s2;O@YM+ZVg!E~_%8nS zhlK_)ppEi+gg&uOTP>EWlD1>FEr%_)Y*wFJCRMvNSD*JB%dt**mdl9OYMO1)Sp(qM zQgzW<-tIc-F=n^gj^(#O%MmK`7OOVuKuD)qF`3;Y zoqDSReleTW+RLOoWw9B@Y`Lg&#CB*MR80rSyhXfr&16=^tv_Lrmc_#H0=CSiMQV=O zsR;X(ip$LEVx_vUSeY~H4KnYTr|S$1kaAH5{-b)UW_L*WNW*g%c=#=Idm;$hB_~Y> zT*LwlR~JduG3yXivuU5UNW<<}4rxLr&?m>X8L7Lj)!=c2#tV!&b;y|IlJd0Gu&V5V zR@-9)GQsMsVUanz>bYdWY}FcI3+4T#a{! z;y>O|r2l&&_{|F6qv%tG?^XDU!oR2RK;apMKd1103ja*ucz2V2rj=x;f zO@e0wesd#E*vF8!)zC{?6gy z2J-K);QMD7>T + * See LICENSE file for license details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dumbwm.h" + +/********** CUSTOMIZE **********/ + +char *tags[TLast] = { + [Tscratch] = "scratch", + [Tdev] = "dev", + [Twww] = "www", + [Twork] = "work", +}; + +/********** CUSTOMIZE **********/ + +/* X structs */ +Display *dpy; +Window root, barwin; +Atom wm_atom[WMLast], net_atom[NetLast]; +Cursor cursor[CurLast]; +Bool running = True; +Bool issel; + +int tsel = Tdev; /* default tag */ +int screen, sx, sy, sw, sh, bx, by, bw, bh, mw; +char stext[1024]; + +DC dc = {0}; +Client *clients = NULL; +Client *sel = NULL; + +static Bool other_wm_running; +static const char version[] = + "dumbwm-" VERSION ", (C)opyright MMVI Anselm R. Garbe\n"; +static int (*x_error_handler) (Display *, XErrorEvent *); + +static void +usage() { error("usage: dumbwm [-v]\n"); } + +static void +scan_wins() +{ + unsigned int i, num; + Window *wins; + XWindowAttributes wa; + Window d1, d2; + + if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for(i = 0; i < num; i++) { + if(!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if(wa.map_state == IsViewable) + manage(wins[i], &wa); + } + } + if(wins) + XFree(wins); +} + +static int +win_property(Window w, Atom a, Atom t, long l, unsigned char **prop) +{ + Atom real; + int format; + unsigned long res, extra; + int status; + + status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format, + &res, &extra, prop); + + if(status != Success || *prop == 0) { + return 0; + } + if(res == 0) { + free((void *) *prop); + } + return res; +} + +int +win_proto(Window w) +{ + unsigned char *protocols; + long res; + int protos = 0; + int i; + + res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols); + if(res <= 0) { + return protos; + } + for(i = 0; i < res; i++) { + if(protocols[i] == wm_atom[WMDelete]) + protos |= WM_PROTOCOL_DELWIN; + } + free((char *) protocols); + return protos; +} + +void +send_message(Window w, Atom a, long value) +{ + XEvent e; + + e.type = ClientMessage; + e.xclient.window = w; + e.xclient.message_type = a; + e.xclient.format = 32; + e.xclient.data.l[0] = value; + e.xclient.data.l[1] = CurrentTime; + XSendEvent(dpy, w, False, NoEventMask, &e); + XFlush(dpy); +} + +/* + * There's no way to check accesses to destroyed windows, thus + * those cases are ignored (especially on UnmapNotify's). + * Other types of errors call Xlib's default error handler, which + * calls exit(). + */ +int +error_handler(Display *dpy, XErrorEvent *error) +{ + if(error->error_code == BadWindow + || (error->request_code == X_SetInputFocus + && error->error_code == BadMatch) + || (error->request_code == X_PolyText8 + && error->error_code == BadDrawable) + || (error->request_code == X_PolyFillRectangle + && error->error_code == BadDrawable) + || (error->request_code == X_PolySegment + && error->error_code == BadDrawable) + || (error->request_code == X_ConfigureWindow + && error->error_code == BadMatch) + || (error->request_code == X_GrabKey + && error->error_code == BadAccess)) + return 0; + fprintf(stderr, "dumbwm: fatal error: request code=%d, error code=%d\n", + error->request_code, error->error_code); + return x_error_handler(dpy, error); /* may call exit() */ +} + +/* + * Startup Error handler to check if another window manager + * is already running. + */ +static int +startup_error_handler(Display *dpy, XErrorEvent *error) +{ + other_wm_running = True; + return -1; +} + +static void +cleanup() +{ + while(sel) { + resize(sel, True); + unmanage(sel); + } + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +} + +void +quit(Arg *arg) +{ + running = False; +} + +int +main(int argc, char *argv[]) +{ + int i, n; + fd_set rd; + XSetWindowAttributes wa; + unsigned int mask; + Bool readstdin = True; + Window w; + XEvent ev; + + for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stdout, "%s", version); + exit(0); + break; + default: + usage(); + break; + } + } + + dpy = XOpenDisplay(0); + if(!dpy) + error("dumbwm: cannot connect X server\n"); + + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + + /* check if another WM is already running */ + other_wm_running = False; + XSetErrorHandler(startup_error_handler); + /* this causes an error if some other WM is running */ + XSelectInput(dpy, root, SubstructureRedirectMask); + XFlush(dpy); + + if(other_wm_running) + error("dumbwm: another window manager is already running\n"); + + XSetErrorHandler(0); + x_error_handler = XSetErrorHandler(error_handler); + + /* init atoms */ + wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) net_atom, NetLast); + + /* init cursors */ + cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); + cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); + cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); + + update_keys(); + + /* style */ + dc.bg = initcolor(BGCOLOR); + dc.fg = initcolor(FGCOLOR); + dc.border = initcolor(BORDERCOLOR); + initfont(FONT); + + sx = sy = 0; + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + mw = (sw * MASTERW) / 100; + + wa.override_redirect = 1; + wa.background_pixmap = ParentRelative; + wa.event_mask = ButtonPressMask | ExposureMask; + + bx = by = 0; + bw = sw; + dc.h = bh = dc.font.height + 4; + barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + XDefineCursor(dpy, barwin, cursor[CurNormal]); + XMapRaised(dpy, barwin); + + dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, 0); + draw_bar(); + + issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); + + wa.event_mask = SubstructureRedirectMask | EnterWindowMask \ + | LeaveWindowMask; + wa.cursor = cursor[CurNormal]; + + XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); + + strcpy(stext, "dumbwm-"VERSION); + scan_wins(); + + /* main event loop, reads status text from stdin as well */ +Mainloop: + while(running) { + FD_ZERO(&rd); + if(readstdin) + FD_SET(STDIN_FILENO, &rd); + FD_SET(ConnectionNumber(dpy), &rd); + + i = select(ConnectionNumber(dpy) + 1, &rd, 0, 0, 0); + if(i == -1 && errno == EINTR) + continue; + if(i < 0) + error("select failed\n"); + else if(i > 0) { + if(FD_ISSET(ConnectionNumber(dpy), &rd)) { + while(XPending(dpy)) { + XNextEvent(dpy, &ev); + if(handler[ev.type]) + (handler[ev.type])(&ev); /* call handler */ + } + } + if(readstdin && FD_ISSET(STDIN_FILENO, &rd)) { + i = n = 0; + for(;;) { + if((i = getchar()) == EOF) { + /* broken pipe/end of producer */ + readstdin = False; + strcpy(stext, "broken pipe"); + goto Mainloop; + } + if(i == '\n' || n >= sizeof(stext) - 1) + break; + stext[n++] = i; + } + stext[n] = 0; + draw_bar(); + } + } + } + + cleanup(); + XCloseDisplay(dpy); + + return 0; +} diff --git a/main.o b/main.o new file mode 100644 index 0000000000000000000000000000000000000000..c26a27856d5fa3e6973675515b0c320468f6f1dc GIT binary patch literal 12168 zcmb`N4RjROb;qBimH9AT2~29maNHrRT^Z1##e@hF>|K2^vIWRUfD*vVYIlUzNW1dx zERtMWg9ViBT8UfJhNP|=pSZ1$ecD4#Qy2VoWQ$;E(>lh*dfE#!^X51Ici(*<^JeC)?r&;sE-fh$+DgQ2V&Y6wAxRvtLj&Q}H6EiLmn59!Q z7a$d$ekr$n&wu`!H1+mkGk>Mx>GlO?VKqF5M$M7WB5@A8FPizEnE79B*;c#>r(X(< zZrL^#8Xcq3t~P~EMUKuT8aibT|Dx6`d!JvXwU~E`Mgrn7Q{CXDDmv6bpJ^ z;3Uwfnct1@TM@pQw*$3QaaBb#-w_ChPQOf77Lb;Xbp{<#VN(?77=}=uh@rA{)=d?0AnzSi8i) zz|33(u+xrZWOex&vnMeCoz(!c8Q- zH7a5JfwKrfjvMpEv(wD72jJH%ge#RVHT2{S@{ACb`tDSGBDP_f6t-U#5gL_}P*Jso zlYv!6&lacEY%#e&=`HmCdF`H3Io%kjpQ`bQQ*me7Ip&i!mo-(fwaK7gXvBq)t%0z@ zyzVayPWYR|m%F)B<|muMX_85`|Lu^PZBLu=-=VTZUQV7bBv9^)KclYv3d(Y5Vh6!WPy}U1Qm=1FM$u@}W99?b_JxJ8IM~L>X^_0vM;_}tvz2SR=8ZPP(`XF>V zFPq8PtAXm&uOQtuj+nkeq%L%-F)w3lgAbWfZ6ssWv*7UYu$ezGsRh*7cdDrJ$RT0I zWdQ~0Og%5;!2M&WR49#wa2?MSIz=N%x#Zp8q}52p1no0NIs%nSx>?1yHvgiTe-#g& z%C-poQ=XlHlK-JnIlfG%{?7=Lf>Etpi@PSjFK`qA4j(t1{LUkiZsgXH-hg8Ij&BWA zx8{GY9Jh|N24*3+Dw&b)?b�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 + * See LICENSE file for license details. + */ + +#include +#include +#include +#include +#include +#include + +#include "dumbwm.h" + +void +error(const char *errstr, ...) { + va_list ap; + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +static void +bad_malloc(unsigned int size) +{ + fprintf(stderr, "fatal: could not malloc() %d bytes\n", + (int) size); + exit(1); +} + +void * +emallocz(unsigned int size) +{ + void *res = calloc(1, size); + if(!res) + bad_malloc(size); + return res; +} + +void +spawn(Arg *arg) +{ + char **argv = (char **)arg->argv; + if(!argv || !argv[0]) + return; + if(fork() == 0) { + if(fork() == 0) { + if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(argv[0], argv); + fprintf(stderr, "dumbwm: execvp %s", argv[0]); + perror(" failed"); + } + exit (0); + } + wait(0); +} diff --git a/util.o b/util.o new file mode 100644 index 0000000000000000000000000000000000000000..ec19c34f2c5eceff537460d7415d575047b50ae7 GIT binary patch literal 2872 zcmbuB-)kI29KgSqUd`Dbcd;#4shEA3XbyGB1+^iqzhhRS&wpYqbMmwH)6M>XT(_!nKyy zgct1sx7%7?ZOvL<&#PbPSQ8Og4X5dQF2KUv+^jXZ@Y1Vgt1@j@Y+9B)HVYfg7(Flo zxdAc#&2y@MKQfX7iGtkvE0F7ri@rRY~3(^b48&u;Uwx_6%@(ewW7soD+ zh++Xv3)?AdBb+11oD`wRhAHt8SI=`VNk?V{4 zIc!;V7KZQ_hwzt&@H0dB*&)0!ghN*}eY*~JZElJl6?#lVBwQ~H;X3mMf6Rnv>+!X&DmImhyRHIgkD8+Mw0;4d+BW0< z%7PiOuOp*#X6|9Cb5rG~=cU)5Vo2V?Mxp6^OMwmr8IsQT(UkN&RW5yhI+r@1 z{vVKJjZJ)0jj#6)-3?SSoliB>-yRWsp!VMibqq-_E8S^X`7^YrC~qg~-ZP#55B?XP Ab^rhX literal 0 HcmV?d00001