diff --git a/Makefile b/Makefile index f37b5b7..4efbd49 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,14 @@ include config.mk +SRCDIR = XCB-TRL + BIN = binary SRC = $(wildcard *.c) -SRCH= $(wildcard *.h) +SRC += $(foreach dir, $(SRCDIR), $(wildcard $(dir)/*.c)) +SRCH= $(foreach dir, $(SRCDIR), $(wildcard $(dir)/*.h)) OBJ = $(patsubst %.c,${BIN}/%.o,$(SRC)) -VERSION = 1.0.0 +VERSION = 2.0.0 EXE = dwm EXEPATH = ${BIN}/${EXE} CMACROS += -DVERSION=\"${VERSION}\" -DNAME=\"${EXE}\" diff --git a/bar.c b/bar.c index 390e2f4..c4b1a3a 100644 --- a/bar.c +++ b/bar.c @@ -208,24 +208,6 @@ BarDrawBuff( } - - - - - - - - - - - - - - - - - - /* * id1 id2 id3 * 256 diff --git a/bar.h b/bar.h index 2c5225c..2381a8d 100644 --- a/bar.h +++ b/bar.h @@ -3,7 +3,7 @@ #include -#include "xcb_trl.h" +#include "XCB-TRL/xcb_trl.h" diff --git a/config.mk b/config.mk index b00b591..ff25a9d 100644 --- a/config.mk +++ b/config.mk @@ -64,7 +64,7 @@ BUILDSELF = ${RELEASEFLAGS} ${XNATIVE} -O3 # Set your options or presets (see above) ex: ${PRESETNAME} (Compiler used is on top) CFLAGS = ${DEBUG} -CMACROS = +CMACROS = -DXINERAMA @@ -80,7 +80,6 @@ endif ifeq ($(CFLAGS), $(DEBUG)) CMACROS += -DENABLE_DEBUG CMACROS += -DXCB_TRL_ENABLE_DEBUG - CMACROS += -DXINERAMA endif # Linker flags diff --git a/dwm.c b/dwm.c index 57f9b7e..f7ea33b 100644 --- a/dwm.c +++ b/dwm.c @@ -16,14 +16,14 @@ #include #include +#include /* cursors */ + #include /* error codes */ /* keycodes */ #include -#include "xcb_trl.h" -#include "xcb_winutil.h" #include "util.h" #include "dwm.h" #include "parser.h" @@ -42,6 +42,8 @@ UserSettings _cfg; XCBAtom netatom[NetLast]; XCBAtom wmatom[WMLast]; +XCBAtom motifatom; +XCBCursor cursors[CurLast]; /* Macro definitions */ u16 OLDWIDTH(Client *c) { return (c->oldw + (c->bw * 2)); } @@ -51,52 +53,50 @@ u16 HEIGHT(Client *c) { return (c->h + (c->bw * 2)); } /* Our custom states */ int ISALWAYSONTOP(Client *c) { return c->wstateflags & _STATE_ABOVE; } int ISALWAYSONBOTTOM(Client *c) { return c->wstateflags & _STATE_BELOW; } -int WASFLOATING(Client *c) { +int WASFLOATING(Client *c) { return c->flags & _FSTATE_WASFLOATING; } +int ISFLOATING(Client *c) { return c->flags & _FSTATE_FLOATING; } +int WASDOCKED(Client *c) { const i16 wx = c->desktop->mon->wx; const i16 wy = c->desktop->mon->wy; const u16 ww = c->desktop->mon->ww; const u16 wh = c->desktop->mon->wh; const i16 x = c->oldx; const i16 y = c->oldy; - const u16 w = c->oldw; - const u16 h = c->oldh; - return ((wx == x) & (wy == y) & (ww == w) & (wh == h)); + const u16 w = OLDWIDTH(c); + const u16 h = OLDHEIGHT(c); + return !((wx != x) + (wy != y) + (ww != w) + (wh != h)); } -int ISFLOATING(Client *c) { +int DOCKED(Client *c) { const i16 wx = c->desktop->mon->wx; const i16 wy = c->desktop->mon->wy; const u16 ww = c->desktop->mon->ww; const u16 wh = c->desktop->mon->wh; const i16 x = c->x; const i16 y = c->y; - const u16 w = c->w; - const u16 h = c->h; - i32 nx; - i32 ny; - i32 nw; - i32 nh; - return ((wx == x) & (wy == y) & (ww == w) & (wh == h)); + const u16 w = WIDTH(c); + const u16 h = HEIGHT(c); + return !((wx != x) + (wy != y) + (ww != w) + (wh != h)); } -int DOCKED(Client *c) { return !ISFLOATING(c); } -int WASDOCKED(Client *c) { return !WASFLOATING(c); } -int ISFIXED(Client *c) { return (c->minw != 0) & (c->minh != 0) & (c->minw == c->maxw) & (c->minh == c->maxh); } +int ISFIXED(Client *c) { return (c->minw != 0) && (c->minh != 0) && (c->minw == c->maxw) && (c->minh == c->maxh); } int ISURGENT(Client *c) { return c->wstateflags & _STATE_DEMANDS_ATTENTION; } int NEVERFOCUS(Client *c) { return c->wtypeflags & _TYPE_NEVERFOCUS; } int ISMAXHORZ(Client *c) { return WIDTH(c) == c->desktop->mon->wh; } int ISMAXVERT(Client *c) { return HEIGHT(c) == c->desktop->mon->wh; } -int ISVISIBLE(Client *c) { return (!!(c->desktop->mon->desksel == c->desktop) | (!!ISSTICKY(c))) & !ISHIDDEN(c); } +int ISVISIBLE(Client *c) { return (!!(c->desktop->mon->desksel == c->desktop) || (!!ISSTICKY(c))) && !ISHIDDEN(c); } +int SHOWDECOR(Client *c) { return c->flags & _FSTATE_SHOW_DECOR; } int ISSELECTED(Client *c) { return c->desktop->sel == c; } -int ISNORMALSTACK(Client *c) { return !( +int ISNORMALSTACK(Client *c) { return !( ISFLOATING(c) | ISALWAYSONTOP(c) | ISDIALOG(c) | ISMODAL(c) ); } + int COULDBEBAR(Client *c, uint8_t strut) { const u8 sticky = !!ISSTICKY(c); const u8 isdock = !!(ISDOCK(c) | ISTOOLBAR(c)); const u8 above = !!ISABOVE(c); - return (sticky && strut && (above || isdock)); + return (sticky && strut && (above || isdock)); } /* EWMH Window types */ int ISDESKTOP(Client *c) { return c->wtypeflags & _TYPE_DESKTOP; } @@ -113,8 +113,8 @@ int ISNOTIFICATION(Client *c) { return c->wtypeflags & _TYPE_NOTIFICATION; } int ISCOMBO(Client *c) { return c->wtypeflags & _TYPE_COMBO; } int ISDND(Client *c) { return c->wtypeflags & _TYPE_DND; } int ISNORMAL(Client *c) { return c->wtypeflags & _TYPE_NORMAL; } -int ISMAPICONIC(Client *c) { return c->wtypeflags & _TYPE_WINDOW_ICONIC; } -int ISMAPNORMAL(Client *c) { return !ISMAPICONIC(c);} +int ISMAPICONIC(Client *c) { return c->wtypeflags & _TYPE_MAP_ICONIC; } +int ISMAPNORMAL(Client *c) { return !ISMAPICONIC(c); } /* EWMH Window states */ int ISMODAL(Client *c) { return c->wstateflags & _STATE_MODAL; } int ISSTICKY(Client *c) { return c->wstateflags & _STATE_STICKY; } @@ -272,7 +272,7 @@ applysizechecks(Monitor *m, i32 *x, i32 *y, i32 *width, i32 *height, i32 *border } void -applygravity(u32 gravity, i16 *x, i16 *y, const u16 w, const u16 h, const u16 bw) +applygravity(const u32 gravity, i16 *x, i16 *y, const u16 w, const u16 h, const u16 bw) { if(!gravity || !x || !y) { return; @@ -432,6 +432,7 @@ arrangeq(Desktop *desk) } workingdesk = desk; } + reorder(desk); arrangedesktop(desk); } @@ -439,7 +440,6 @@ void arrange(Desktop *desk) { arrangeq(desk); - reorder(desk); switch(desk->layout) { case Monocle: case Floating: default: @@ -754,6 +754,7 @@ cleanup(void) return; } XCBCookie cookie = XCBDestroyWindow(_wm.dpy, _wm.wmcheckwin); + cleanupcursors(); XCBDiscardReply(_wm.dpy, cookie); XCBSetInputFocus(_wm.dpy, _wm.root, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow]); @@ -795,11 +796,23 @@ cleanupclient(Client *c) { free(c->wmname); free(c->netwmname); + free(c->classname); + free(c->instancename); free(c->decor); + free(c->icon); free(c); c = NULL; } +void +cleanupcursors(void) +{ + int i; + for(i = 0; i < CurLast; ++i) + { XCBFreeCursor(_wm.dpy, cursors[i]); + } +} + void cleanupmon(Monitor *m) { @@ -926,6 +939,7 @@ createclient(void) { DEBUG0("Could not allocated memory for decoration (OutOfMemory)."); return NULL; } + c->decor = decor; c->x = c->y = 0; c->w = c->h = 0; c->oldx = c->oldy = 0; @@ -943,6 +957,8 @@ createclient(void) c->desktop = NULL; c->wmname = NULL; c->netwmname = NULL; + c->classname = NULL; + c->instancename = NULL; return c; } @@ -1031,7 +1047,6 @@ createdecoration(void) decor->w = 0; decor->h = 0; decor->win = 0; - decor->flags = 0; } return decor; } @@ -1054,19 +1069,6 @@ dirtomon(u8 dir) return m; } -/* unused. */ -uint8_t -docked(Client *c) -{ - const Monitor *m = c->desktop->mon; - uint8_t dockd = 0; - if(m) - { - dockd = (m->wx == c->x) & (m->wy == c->y) & (WIDTH(c) == m->ww) & (HEIGHT(c) == m->wh); - } - return dockd; -} - void eventhandler(XCBGenericEvent *ev) { @@ -1150,6 +1152,33 @@ getnamefromreply(XCBWindowProperty *namerep, char **str_return) } } +u32 * +geticonprop(XCBWindowProperty *iconreply) +{ + const u8 WIDTH_INDEX = 0; + const u8 HEIGHT_INDEX = 1; + const u8 MIN_WIDTH = 1; + const u8 MIN_HEIGHT = 1; + const u8 MIN_ICON_DATA_SIZE = (MIN_WIDTH + MIN_HEIGHT) * 2; /* times 2 cause the first and second index are the size */ + + u32 *ret = NULL; + if(iconreply) + { + u32 *icon = XCBGetPropertyValue(iconreply); + size_t size = XCBGetPropertyValueSize(iconreply); + u32 length = XCBGetPropertyValueLength(iconreply, sizeof(u32)); + if(length >= MIN_ICON_DATA_SIZE) + { + size_t sz = sizeof(u32) * icon[WIDTH_INDEX] * icon[HEIGHT_INDEX] + sizeof(u32) * 2; + ret = malloc(MIN(sz, size)); + if(ret) + { memcpy(ret, icon, MIN(sz, size)); + } + } + } + return ret; +} + i8 getrootptr(i16 *x, i16 *y) { @@ -1241,7 +1270,11 @@ grid(Desktop *desk) Monitor *m = desk->mon; for(n = 0, c = desk->focus; c; c = nextfocus(c)) - { ++n; + { + if(ISFLOATING(c)) + { continue; + } + ++n; } if(!n) @@ -1262,6 +1295,9 @@ grid(Desktop *desk) cw = m->ww / (cols + !cols); for(i = 0, c = desk->focus; c; c = nextfocus(c)) { + if(ISFLOATING(c)) + { continue; + } nx = m->wx + (i / rows) * cw; ny = m->wy + (i % rows) * ch; /* adjust height/width of last row/column's windows */ @@ -1320,10 +1356,10 @@ killclient(Client *c, enum KillType type) void managerequest(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) { - const uint32_t REQUEST_MAX_NEEDED_ITEMS = UINT32_MAX; - const uint8_t STRUT_P_LENGTH = 12; - const uint8_t STRUT_LENGTH = 4; - const uint8_t NO_BYTE_OFFSET = 0; + const u32 REQUEST_MAX_NEEDED_ITEMS = UINT32_MAX; + const u8 STRUT_P_LENGTH = 12; + const u8 STRUT_LENGTH = 4; + const u8 NO_BYTE_OFFSET = 0; XCBCookie wacookie = XCBGetWindowAttributesCookie(_wm.dpy, win); XCBCookie wgcookie = XCBGetWindowGeometryCookie(_wm.dpy, win); XCBCookie transcookie = XCBGetTransientForHintCookie(_wm.dpy, win); @@ -1338,9 +1374,10 @@ managerequest(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) XCBCookie netwmnamecookie = XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMName], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, netatom[NetUtf8String]); XCBCookie wmnamecookie = XCBGetWindowPropertyCookie(_wm.dpy, win, XCB_ATOM_WM_NAME, NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_STRING); XCBCookie pidcookie = XCBGetPidCookie(_wm.dpy, win, netatom[NetWMPid]); + XCBCookie iconcookie = XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMIcon], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_CARDINAL); /* Mostly to prevent needing to rewrite the numbers over and over again if we mess up */ - int i = 0; + u8 i = 0; requests[i++] = wacookie; requests[i++] = wgcookie; requests[i++] = transcookie; @@ -1354,8 +1391,9 @@ managerequest(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) requests[i++] = strutcookie; requests[i++] = netwmnamecookie; requests[i++] = wmnamecookie; + requests[i++] = iconcookie; requests[i++] = pidcookie; - /* 16 elements in thing */ + /* 15 elements in thing */ } Client * @@ -1375,6 +1413,7 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) const u16 bw = 0; const u32 bcol = 0; + const u8 showdecor = 1; Client *c = NULL; XCBWindow trans = 0; @@ -1383,7 +1422,6 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) XCBWindowGeometry *wg = NULL; XCBGetWindowAttributes *waattributes = NULL; - u8 override_redirect = 0; XCBWindowProperty *wtypeunused = NULL; XCBWindowProperty *stateunused = NULL; XCBSizeHints hints; @@ -1401,7 +1439,6 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) char *netwmname = NULL; char *wmname = NULL; XCBWindowProperty *iconreply = NULL; - char *icon = NULL; pid_t pid = 0; /* we do it here before, because we are waiting for replies and for more memory. */ @@ -1421,7 +1458,7 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) strutreply = XCBGetWindowPropertyReply(_wm.dpy, requests[10]); netwmnamereply = XCBGetWindowPropertyReply(_wm.dpy, requests[11]); wmnamereply = XCBGetWindowPropertyReply(_wm.dpy, requests[12]); - iconreply = XCBGetWindowPropertyReply(_wm.dpy, requests[12]); + iconreply = XCBGetWindowPropertyReply(_wm.dpy, requests[13]); pid = XCBGetPidReply(_wm.dpy, requests[14]); strutp = strutpreply ? XCBGetWindowPropertyValue(strutpreply) : NULL; strut = strutreply ? XCBGetWindowPropertyValue(strutpreply) : NULL; @@ -1436,7 +1473,6 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) if(waattributes && waattributes->override_redirect) { DEBUG("Override Redirect: [%d]", win); - override_redirect = 1; /* theoredically we could manage these but they are a hastle to deal with */ goto FAILURE; } @@ -1466,10 +1502,13 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) setclientpid(c, pid); setborderwidth(c, bw); setbordercolor32(c, bcol); + setshowdecor(c, showdecor); configure(c); /* propagates border_width, if size doesn't change */ updatetitle(c, netwmname, wmname); updatesizehints(c, &hints); + updateclass(c, &cls); updatewmhints(c, wmh); + updateicon(c, iconreply); XCBSelectInput(_wm.dpy, win, inputmask); grabbuttons(win, 0); @@ -1492,7 +1531,6 @@ managereply(XCBWindow win, XCBCookie requests[MANAGE_CLIENT_COOKIE_COUNT]) if(c->desktop && c->desktop->sel) { setfullscreen(c, ISFULLSCREEN(c->desktop->sel) || ISFULLSCREEN(c)); } - XCBMapWindow(_wm.dpy, win); if(c->desktop) { HASH_ADD_INT(c->desktop->__hash, win, c); } @@ -1577,6 +1615,9 @@ monocle(Desktop *desk) for(c = desk->focus; c; c = nextfocus(c)) { + if(ISFLOATING(c)) + { continue; + } nw = m->ww - (c->bw * 2); nh = m->wh - (c->bw * 2); applysizechecks(m, &nx, &ny, &nw, &nh, &unused); @@ -1611,6 +1652,12 @@ nextstack(Client *c) return c ? c->snext : c; } +Client * +nextrstack(Client *c) +{ + return c ? c->rnext : c; +} + Client * nextfocus(Client *c) { @@ -1648,6 +1695,12 @@ prevstack(Client *c) return c ? c->sprev : c; } +Client * +prevrstack(Client *c) +{ + return c ? c->rprev : c; +} + Client * prevvisible(Client *c) { @@ -1771,7 +1824,7 @@ restoresession(void) } else { /* TODO: Technically we dont need isclientsend, but having that prevents a "fail" due to strcmp("Client.", buff); happening after/ */ - DEBUG0("Failed to pass checksum for client."); + DEBUG0("Failed to pass move checksum for client."); } } } @@ -1796,6 +1849,17 @@ restoresession(void) isclients += !strcmp(str, "Clients."); isclientsend += !strcmp(str, "ClientsEnd."); } + /* map all the windows again */ + Client *c; + for(m = _wm.mons; m; m = nextmonitor(m)) + { + for(desk = m->desktops; desk; desk = nextdesktop(desk)) + { + for(c = desk->clients; c; c = nextclient(c)) + { XCBMapWindow(_wm.dpy, c->win); + } + } + } arrangemons(); /* No need to flush run() syncs for us */ /* XCBFlush(_wm.dpy) */ @@ -1804,7 +1868,7 @@ restoresession(void) Client * restoreclientsession(Desktop *desk, char *buff, u16 len) { - const u8 SCANF_CHECK_SUM = 13; + const u8 SCANF_CHECK_SUM = 14; u8 check = 0; int x, y; @@ -1814,6 +1878,7 @@ restoreclientsession(Desktop *desk, char *buff, u16 len) XCBWindow WindowId; XCBWindow WindowIdFocus; XCBWindow WindowIdStack; + u32 Flags; u32 BorderWidth; u32 BorderColor; @@ -1827,6 +1892,7 @@ restoreclientsession(Desktop *desk, char *buff, u16 len) "WindowIdStack: %u" " " "BorderWidth: %u" " " "BorderColor: %u" " " + "Flags: %u" " " , &x, &y, &w, &h, &ox, &oy, &ow, &oh, @@ -1834,7 +1900,8 @@ restoreclientsession(Desktop *desk, char *buff, u16 len) &WindowIdFocus, &WindowIdStack, &BorderWidth, - &BorderColor + &BorderColor, + &Flags ); if(check == SCANF_CHECK_SUM) @@ -1848,6 +1915,7 @@ restoreclientsession(Desktop *desk, char *buff, u16 len) setbordercolor32(cclient, BorderColor); resize(cclient, ox, oy, ow, oh, 1); resize(cclient, x, y, w, h, 1); + cclient->flags = Flags; } if(fclient) { @@ -2076,9 +2144,11 @@ void restack(Desktop *desk) { Client *c; + Client *cr; XCBWindowChanges wc; wc.stack_mode = XCB_STACK_MODE_BELOW; + if(desk->mon->bar->win && SHOWBAR(desk->mon->bar)) { wc.sibling = desk->mon->bar->win; } @@ -2088,15 +2158,17 @@ restack(Desktop *desk) } /* FIXME restacking doesnt really work with the "stack" */ - for(c = desk->slast; c; c = prevstack(c)) + for(c = desk->stack; c; c = nextstack(c)) { XCBConfigureWindow(_wm.dpy, c->win, XCB_CONFIG_WINDOW_SIBLING|XCB_CONFIG_WINDOW_STACK_MODE, &wc); wc.sibling = c->win; } - for(c = desk->focus; c; c = nextfocus(c)) - { - XCBConfigureWindow(_wm.dpy, c->win, XCB_CONFIG_WINDOW_SIBLING|XCB_CONFIG_WINDOW_STACK_MODE, &wc); - wc.sibling = c->win; + /* arbitrary number */ + while(desk->rstack) + { detachrestack(desk->rstack); + } + for(c = desk->stack; c; c = nextstack(c)) + { attachrestack(c); } } @@ -2116,7 +2188,7 @@ restackq(Desktop *desk) Client *c; for(c = desk->stack; c; c = nextstack(c)) - { + { if(!ISNORMALSTACK(c)) { XCBConfigureWindow(_wm.dpy, c->win, XCB_CONFIG_WINDOW_SIBLING|XCB_CONFIG_WINDOW_STACK_MODE, &wc); wc.sibling = c->win; @@ -2127,9 +2199,9 @@ restackq(Desktop *desk) static i32 __cmp_helper(int32_t x1, int32_t x2) { - const u16 bigger = x1 > x2; - const u16 smaller = !bigger; - const i32 ret = bigger + (-smaller); + const u32 bigger = x1 > x2; + const u32 smaller = !bigger; + const i32 ret = -bigger + (smaller); return ret; } @@ -2141,31 +2213,24 @@ __cmp(Client *c1, Client *c2) * RETURN -1 on lesser priority * RETURN 0 on lesser priority. */ - /* XOR basically just skips if they both have it and only success if one of them has it AKA compare */ + /* != basically just skips if they both have it and only success if one of them has it AKA compare */ + + if(ISFLOATING(c1) && DOCKED(c1)) + { setfloating(c1, 0); + } + if(ISFLOATING(c2) && DOCKED(c2)) + { setfloating(c2, 0); + } + if(ISDOCK(c1) != ISDOCK(c2)) { return __cmp_helper(ISDOCK(c1), ISDOCK(c2)); } else if(ISALWAYSONTOP(c1) != ISALWAYSONTOP(c2)) { return __cmp_helper(ISALWAYSONTOP(c1), ISALWAYSONTOP(c2)); } - else if(ISMODAL(c1) != ISMODAL(c2)) - { return __cmp_helper(ISMODAL(c1), ISMODAL(c2)); - } - else if(ISNOTIFICATION(c1) != ISNOTIFICATION(c2)) - { return __cmp_helper(ISNOTIFICATION(c1), ISNOTIFICATION(c2)); - } - else if(ISDIALOG(c1) != ISDIALOG(c2)) - { return __cmp_helper(ISDIALOG(c1), ISDIALOG(c2)); - } - else if(ISUTILITY(c1) != ISUTILITY(c2)) - { return __cmp_helper(ISUTILITY(c1), ISUTILITY(c2)); - } else if(ISFLOATING(c1) != ISFLOATING(c2)) { return __cmp_helper(ISFLOATING(c1), ISFLOATING(c2)); } - else if(ISSELECTED(c1) != ISSELECTED(c2)) - { return __cmp_helper(ISSELECTED(c1), ISSELECTED(c2)); - } else if(ISNORMALSTACK(c1) != ISNORMALSTACK(c2)) { return __cmp_helper(ISNORMALSTACK(c1), ISNORMALSTACK(c2)); } @@ -2176,8 +2241,10 @@ __cmp(Client *c1, Client *c2) { return __cmp_helper(ISHIDDEN(c1), ISHIDDEN(c2)); } else - { /* UNRECHEABLE (hopefully) */ - return 0; + { + Client *c; + for(c = c1; c && c != c2; c = c->fprev); + return c == c2; } } @@ -2367,6 +2434,7 @@ saveclientsession(FILE *fw, Client *c, unsigned int iteration) "WindowIdStack: %u" " " "BorderWidth: %u" " " "BorderColor: %u" " " + "Flags: %u" " " "\n" , IDENTIFIER, @@ -2376,7 +2444,8 @@ saveclientsession(FILE *fw, Client *c, unsigned int iteration) focus, stack, c->bw, - c->bcol + c->bcol, + c->flags ); } @@ -2649,28 +2718,10 @@ setclientstate(Client *c, u8 state) XCBChangeProperty(_wm.dpy, c->win, wmatom[WMState], wmatom[WMState], 32, XCB_PROP_MODE_REPLACE, (unsigned char *)data, 2); } -void -setdecorvisible(Client *c, uint8_t state) -{ - if(state) - { - if(c->decor->win) - { XCBMapWindow(_wm.dpy, c->decor->win); - } - } - else - { - if(c->decor->win) - { XCBUnmapWindow(_wm.dpy, c->decor->win); - } - } - SETFLAG(c->decor->flags, _DECOR_VISIBLE, !!state); -} - void setdesktopcount(Monitor *m, uint16_t desktops) { - const int MIN_DESKTOPS = 1; + const u8 MIN_DESKTOPS = 1; if(desktops <= MIN_DESKTOPS) { DEBUG0("Cannot make desktop count less than possible."); return; @@ -2825,6 +2876,18 @@ setwtypenormal(Client *c, uint8_t state) SETFLAG(c->wtypeflags, _TYPE_NORMAL, !!state); } +void +setwtypemapiconic(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_MAP_ICONIC, !!state); +} + +void +setwtypemapnormal(Client *c, uint8_t state) +{ + setwtypemapiconic(c, !state); +} + void setwmtakefocus(Client *c, uint8_t state) { @@ -2855,6 +2918,24 @@ setskiptaskbar(Client *c, uint8_t state) SETFLAG(c->wstateflags, _STATE_SKIP_TASKBAR, !!state); } +void +setshowdecor(Client *c, uint8_t state) +{ + if(state) + { + if(c->decor->win) + { XCBMapWindow(_wm.dpy, c->decor->win); + } + } + else + { + if(c->decor->win) + { XCBUnmapWindow(_wm.dpy, c->decor->win); + } + } + SETFLAG(c->flags, _FSTATE_SHOW_DECOR, !!state); +} + void setfullscreen(Client *c, u8 state) { @@ -2878,6 +2959,13 @@ setfullscreen(Client *c, u8 state) SETFLAG(c->wstateflags, _STATE_FULLSCREEN, !!state); } +void +setfloating(Client *c, uint8_t state) +{ + SETFLAG(c->flags, _FSTATE_WASFLOATING, !!(c->flags & _FSTATE_FLOATING)); + SETFLAG(c->flags, _FSTATE_FLOATING, !!state); +} + void setfocus(Client *c) { @@ -2897,9 +2985,11 @@ sethidden(Client *c, uint8_t state) { if(state) { winsetstate(c->win, XCB_WINDOW_ICONIC_STATE); + setwtypemapiconic(c, 1); } else { winsetstate(c->win, XCB_WINDOW_NORMAL_STATE); + setwtypemapnormal(c, 1); } SETFLAG(c->wstateflags, _STATE_HIDDEN, !!state); } @@ -3000,10 +3090,12 @@ setup(void) cleanup(); DIECAT("%s", "Could not establish connection with keyboard (OutOfMemory)"); } - + setupcursors(); setupcfg(); updategeom(); + XCBCookie motifcookie = XCBInternAtomCookie(_wm.dpy, "_MOTIF_WM_HINTS", False); XCBInitAtoms(_wm.dpy, wmatom, netatom); + motifatom = XCBInternAtomReply(_wm.dpy, motifcookie); /* supporting window for NetWMCheck */ _wm.wmcheckwin = XCBCreateSimpleWindow(_wm.dpy, _wm.root, 0, 0, 1, 1, 0, 0, 0); XCBSelectInput(_wm.dpy, _wm.wmcheckwin, XCB_NONE); @@ -3022,15 +3114,16 @@ setup(void) XCBWindowAttributes wa; /* xcb_event_mask_t */ /* ~0 causes event errors because some event masks override others, for some reason... */ + wa.cursor = cursors[CurNormal]; wa.event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT|XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |XCB_EVENT_MASK_BUTTON_PRESS|XCB_EVENT_MASK_BUTTON_RELEASE - |XCB_EVENT_MASK_POINTER_MOTION|XCB_EVENT_MASK_BUTTON_MOTION - |XCB_EVENT_MASK_ENTER_WINDOW|XCB_EVENT_MASK_LEAVE_WINDOW + |XCB_EVENT_MASK_POINTER_MOTION| + XCB_EVENT_MASK_ENTER_WINDOW|XCB_EVENT_MASK_LEAVE_WINDOW |XCB_EVENT_MASK_STRUCTURE_NOTIFY |XCB_EVENT_MASK_PROPERTY_CHANGE ; /* the ; is here just so its out of the way */ - XCBChangeWindowAttributes(_wm.dpy, _wm.root, XCB_CW_EVENT_MASK, &wa); + XCBChangeWindowAttributes(_wm.dpy, _wm.root, XCB_CW_EVENT_MASK|XCB_CW_CURSOR, &wa); XCBSelectInput(_wm.dpy, _wm.root, wa.event_mask); /* init numlock */ updatenumlockmask(); @@ -3038,6 +3131,15 @@ setup(void) focus(NULL); } +void +setupcursors(void) +{ + cursors[CurNormal] = XCBCreateFontCursor(_wm.dpy, XC_left_ptr); + cursors[CurResizeTopL] = XCBCreateFontCursor(_wm.dpy, XC_top_left_corner); + cursors[CurResizeTopR] = XCBCreateFontCursor(_wm.dpy, XC_top_right_corner); + cursors[CurMove] = XCBCreateFontCursor(_wm.dpy, XC_fleur); +} + void setupcfg(void) { @@ -3093,6 +3195,26 @@ seturgent(Client *c, uint8_t state) /* drawbar */ } +void +updatedecor(Client *c, XCBGetWindowAttributes *wa) +{ + XCBWindow win = c->decor->win; + return; + if(!win) + { + XCBCreateWindowValueList values = + { + .override_redirect = 1, + }; + win = XCBCreateWindow(_wm.dpy, _wm.root, c->x, c->y - 15, c->w, c->h + 15, 0, + XCB_COPY_FROM_PARENT, XCB_WINDOW_CLASS_INPUT_ONLY, XCBGetScreen(_wm.dpy)->root_visual, XCB_CW_OVERRIDE_REDIRECT, &values); + XCBReparentWindow(_wm.dpy, c->win, win, c->x, c->y); + DEBUG("%u %u", c->win ,win); + XCBMapWindow(_wm.dpy, win); + c->decor->win = win; + } +} + void updatedesktop(void) { @@ -3326,7 +3448,11 @@ tile(Desktop *desk) m = desk->mon; for(n = 0, c = desk->focus; c; c = nextfocus(c)) - { ++n; + { + if(ISFLOATING(c)) + { continue; + } + ++n; } if(!n) @@ -3342,6 +3468,10 @@ tile(Desktop *desk) for (i = my = ty = 0, c = desk->focus; c; c = nextfocus(c), ++i) { + if(ISFLOATING(c)) + { --i; + continue; + } if (i < nmaster) { h = (m->wh - my) / (MIN(n, nmaster) - i); @@ -3389,12 +3519,6 @@ tile(Desktop *desk) } } -void -tilecalc(Desktop *desk, Client *optional_start, uint16_t count, int32_t startx, int32_t starty, int32_t *x_ret, int32_t *y_ret, int32_t *width_ret, int32_t *height_ret) -{ - /* TODO */ -} - void unfocus(Client *c, uint8_t setfocus) { @@ -3550,6 +3674,13 @@ updategeom(void) return dirty; } +void +updateicon(Client *c, XCBWindowProperty *iconprop) +{ + free(c->icon); + c->icon = geticonprop(iconprop); +} + void unmanage(Client *c, uint8_t destroyed) { @@ -3654,6 +3785,36 @@ updatebargeom(Monitor *m) { } +void +updateclass(Client *c, XCBWMClass *_class) +{ + const u32 MAX_LEN = 1024; + if(_class) + { + free(c->classname); + free(c->instancename); + const u32 CLASS_NAME_LEN = strnlen(_class->class_name, MAX_LEN) + 1; + const u32 INSTANCE_NAME_LEN = strnlen(_class->instance_name, MAX_LEN) + 1; + const size_t CLASS_NAME_SIZE = sizeof(char) * CLASS_NAME_LEN; + const size_t INSTANCE_NAME_SIZE = sizeof(char) * INSTANCE_NAME_LEN; + char *clsname = malloc(CLASS_NAME_SIZE); + char *iname = malloc(INSTANCE_NAME_SIZE); + + if(clsname) + { + memcpy(clsname, _class->class_name, CLASS_NAME_SIZE - sizeof(char)); + clsname[CLASS_NAME_LEN - 1] = '\0'; + } + if(iname) + { + memcpy(iname, _class->instance_name, INSTANCE_NAME_SIZE - sizeof(char)); + iname[INSTANCE_NAME_LEN - 1] = '\0'; + } + c->classname = clsname; + c->instancename = iname; + } +} + void updateclientlist(XCBWindow win, uint8_t type) { @@ -3683,13 +3844,10 @@ updateclientlist(XCBWindow win, uint8_t type) } } - - -/* TODO xcb_key_symbols_get_keycode -> xcb_key_symbols_get_keysym is called a fuck ton and is slow as hell like 20% of manage() slow (callgrind) */ +/* this function is really slow, slower than malloc use only in startup or rare mapping changes */ void updatenumlockmask(void) { - /* taken from i3 */ XCBKeyboardModifier *reply; XCBGenericError *err; @@ -4198,7 +4356,11 @@ updatewmhints(Client *c, XCBWMHints *wmh) case XCB_WINDOW_ICONIC_STATE: sethidden(c, 1); break; - case XCB_WINDOW_WITHDRAWN_STATE: case XCB_WINDOW_NORMAL_STATE: + case XCB_WINDOW_WITHDRAWN_STATE: + DEBUG("Window Specified is Widthdrawn? %d", c->win); + break; + case XCB_WINDOW_NORMAL_STATE: + break; default: break; } diff --git a/dwm.h b/dwm.h index e7a9117..b2990b7 100644 --- a/dwm.h +++ b/dwm.h @@ -5,12 +5,11 @@ #include #include -#include "util.h" +#include "uthash.h" #include "bar.h" -#include "thread.h" #include "settings.h" -#include "xcb_trl.h" -#include "xcb_winutil.h" +#include "XCB-TRL/xcb_trl.h" +#include "XCB-TRL/xcb_winutil.h" #ifndef VERSION @@ -38,6 +37,9 @@ #define MANAGE_CLIENT_COOKIE_COUNT 16 + 1 /* Client struct flags */ +#define _FSTATE_FLOATING ((1 << 0)) +#define _FSTATE_WASFLOATING ((1 << 1)) +#define _FSTATE_SHOW_DECOR ((1 << 2)) /* EWMH window types */ #define _TYPE_DESKTOP ((1 << 0)) @@ -54,16 +56,11 @@ #define _TYPE_COMBO ((1 << 11)) #define _TYPE_DND ((1 << 12)) #define _TYPE_NORMAL ((1 << 13)) -/* not actual state but just lumped in cause assinging its own is stupid. */ + +/* custom types (using spare bits )*/ #define _TYPE_NEVERFOCUS ((1 << 14)) -/* We only need a bit for ICONIC because a window can only have 3 states. - * Those 3 states are as follows: - * WithdrawnState, (We dont handle WithdrawnState (unmapped) windows) - * So we only have 2. - * Iconic, - * Normal - */ -#define _TYPE_WINDOW_ICONIC ((1 << 15)) +/* Window map states, Widthdrawn, Iconic, Normal. */ +#define _TYPE_MAP_ICONIC ((1 << 15)) /* EWMH Window states */ #define _STATE_MODAL ((1 << 0)) @@ -80,18 +77,17 @@ #define _STATE_DEMANDS_ATTENTION ((1 << 11)) #define _STATE_FOCUSED ((1 << 12)) +/* extra states (using spare bits) */ #define _STATE_SUPPORTED_WM_TAKE_FOCUS ((1 << 13)) #define _STATE_SUPPORTED_WM_SAVE_YOURSELF ((1 << 14)) #define _STATE_SUPPORTED_WM_DELETE_WINDOW ((1 << 15)) -/* Decoration states */ -#define _DECOR_VISIBLE ((1 << 0)) - /* cursor */ enum CurType { CurNormal, - CurResize, + CurResizeTopL, + CurResizeTopR, CurMove, CurLast }; @@ -206,6 +202,7 @@ struct Client uint16_t wtypeflags;/* Window type flags */ uint16_t wstateflags;/* Window state flags */ + uint32_t flags; /* Misc States */ uint16_t bw; /* Border Width */ uint16_t oldbw; /* Old Border Width */ @@ -238,8 +235,10 @@ struct Client Decoration *decor; /* Decoration AKA title bar.*/ char *netwmname; /* Client Name */ - char *wmname; /* Client name backup */ - char *icon; /* Array of icon values */ + char *wmname; /* Client Name backup */ + char *classname; /* Class Name */ + char *instancename; /* Instance Name */ + uint32_t *icon; /* Array of icon values */ UT_hash_handle hh; /* hash handle */ }; @@ -248,8 +247,6 @@ struct Decoration /* TODO */ uint16_t w; uint16_t h; - uint8_t flags; - uint8_t pad[3]; XCBWindow win; }; @@ -333,7 +330,7 @@ void argcvhandler(int argc, char *argv[]); void applysizechecks(Monitor *m, int32_t *x, int32_t *y, int32_t *width, int32_t *height, int32_t *border_width); /* Applies the gravity shifts specified by the gravity onto the x and y coordinates. */ -void applygravity(uint32_t gravity, int16_t *x, int16_t *y, const uint16_t width, const uint16_t height, const uint16_t border_width); +void applygravity(const uint32_t gravity, int16_t *x, int16_t *y, const uint16_t width, const uint16_t height, const uint16_t border_width); /* Applies size hints to the specified values. * interact: 1/true/True Does not restrict bounds to window area. * 0/false/False Restricts bounds to window area. @@ -406,6 +403,7 @@ void cleanup(void); /* frees client and allocated client properties. */ void cleanupclient(Client *c); +void cleanupcursors(void); /* frees desktop and allocated desktop properties. */ void cleanupdesktop(Desktop *desk); @@ -476,7 +474,7 @@ void focus(Client *c); */ int32_t getstate(XCBWindow win, XCBGetWindowAttributes *state); void getnamefromreply(XCBWindowProperty *namerep, char **str_return); -char *geticonreply(XCBCookie cookie); +uint32_t *geticonprop(XCBWindowProperty *iconreply); /* Grabs a windows buttons. * Basically this just allows us to receive button press/release events from windows. */ @@ -543,6 +541,7 @@ Monitor *nextmonitor(Monitor *monitor); * RETURN: NULL on Failure. */ Client *nextstack(Client *c); +Client *nextrstacK(Client *c); /* Returns the next client in focus order avaible. * RETURN: Client* on Success. * RETURN: NULL on Failure. @@ -569,6 +568,7 @@ Client *prevfocus(Client *c); * RETURN: NULL on Failure. */ Client *prevstack(Client *c); +Client *prevrstack(Client *c); /* Returns the prev visible client avaible. * RETURN: Client* on Success. * RETURN: NULL on Failure. @@ -650,12 +650,16 @@ void setwtypenotification(Client *c, uint8_t state); void setwtypecombo(Client *c, uint8_t state); void setwtypednd(Client *c, uint8_t state); void setwtypenormal(Client *c, uint8_t state); +void setwtypemapiconic(Client *c, uint8_t state); +void setwtypemapnormal(Client *c, uint8_t state); void setwmtakefocus(Client *c, uint8_t state); void setwmsaveyourself(Client *c, uint8_t state); void setwmdeletewindow(Client *c, uint8_t state); void setskippager(Client *c, uint8_t state); void setskiptaskbar(Client *c, uint8_t state); +void setshowdecor(Client *c, uint8_t state); void setfullscreen(Client *c, uint8_t isfullscreen); +void setfloating(Client *c, uint8_t state); void setfocus(Client *c); void sethidden(Client *c, uint8_t state); void setmaximizedvert(Client *c, uint8_t state); @@ -668,6 +672,7 @@ void settopbar(Client *c, uint8_t state); void startup(void); /* Sets up Variables, Checks, WM specific data, etc.. */ void setup(void); +void setupcursors(void); void setupcfg(void); void setupcfgdefaults(void); void seturgent(Client *c, uint8_t isurgent); @@ -703,12 +708,14 @@ void unfocus(Client *c, uint8_t setfocus); void updatebarpos(Monitor *m); /* updates the bar geometry from the given monitor */ void updatebargeom(Monitor *m); +void updateclass(Client *c, XCBWMClass *_class); /* Updates * type: 0 Adds the client win . * 1 Removes the specified win. * 2 Reloads the entire list. * _NET_WM_CLIENT_LIST */ void updateclientlist(XCBWindow win, uint8_t type); +void updatedecor(Client *c, XCBGetWindowAttributes *wa); /* Updates the XServer to the Current destop */ void updatedesktop(void); /* Updates the desktop names if they have changed */ @@ -718,7 +725,9 @@ void updatedesktopnum(void); /* Updates Geometry for external monitors based on if they have different geometry */ int updategeom(void); /* Updates the Client icon if we find one */ -void updateicon(Client *c); +void updateicon(Client *c, XCBWindowProperty *iconprop); +/* TODO */ +void updatemotifhints(void); /* checks and updates mask if numlock is active */ void updatenumlockmask(void); /* Updates a Clients sizehints property using the provided hints pointer "size" */ @@ -786,6 +795,7 @@ int ISFIXED(Client *c); int ISURGENT(Client *c); int NEVERFOCUS(Client *c); int ISVISIBLE(Client *c); +int SHOWDECOR(Client *c); int ISSELECTED(Client *c); /* if the window doesnt have any stacking priority. */ int ISNORMALSTACK(Client *c); @@ -808,6 +818,7 @@ int ISCOMBO(Client *c); int ISDND(Client *c); int ISNORMAL(Client *c); int ISMAPICONIC(Client *c); +int ISMAPNORMAL(Client *c); /* EWMH Window states */ int ISMODAL(Client *c); int ISSTICKY(Client *c); diff --git a/events.c b/events.c index b702a61..0feded7 100644 --- a/events.c +++ b/events.c @@ -1,4 +1,3 @@ -#include "xcb_trl.h" #include "events.h" #include "util.h" #include "keybinds.h" @@ -331,6 +330,7 @@ motionnotify(XCBGenericEvent *event) { return; } + u8 sync = 0; static Monitor *mon = NULL; Monitor *m; @@ -466,8 +466,7 @@ focusin(XCBGenericEvent *event) Client *sel = _wm.selmon->desksel->sel; if(sel && eventwin != sel->win) { - unfocus(sel, 1); - focus(NULL); + setfocus(sel); sync = 1; } @@ -684,6 +683,11 @@ configurerequest(XCBGenericEvent *event) c->oldy = c->y; c->y = m->my + ((m->mh >> 1) - (HEIGHT(c) >> 1)); /* center in y direction */ } + /* these checks are so we maintain wasfloating correctly without messing everything up */ + if(!ISFLOATING(c) && !DOCKED(c)) + { setfloating(c, 1); + } + if(mask & (XCB_CONFIG_WINDOW_X|XCB_CONFIG_WINDOW_Y) && !(mask & (XCB_CONFIG_WINDOW_WIDTH|XCB_CONFIG_WINDOW_HEIGHT))) { configure(c); } @@ -730,6 +734,9 @@ maprequest(XCBGenericEvent *event) c = managereply(win, cookies); if(c) { + updatedecor(c, NULL); + /* map window before input focus is set cause we just get errors other wise. */ + XCBMapWindow(_wm.dpy, c->win); focus(c); arrange(c->desktop); } @@ -750,13 +757,16 @@ resizerequest(XCBGenericEvent *event) const u16 w = ev->width; const u16 h = ev->height; - Client *c; u8 sync = 0; - if((c = wintoclient(win))) + Client *c = wintoclient(win); + if(c) { resize(c, c->x, c->y, w, h, 0); + if(!DOCKED(c)) + { setfloating(c, 1); + } sync = 1; } else diff --git a/events.h b/events.h index d1d1bf8..4ea75d9 100644 --- a/events.h +++ b/events.h @@ -1,7 +1,7 @@ #ifndef EVENTS_H_ #define EVENTS_H_ -#include "xcb_trl.h" +#include "XCB-TRL/xcb_trl.h" void keypress(XCBGenericEvent *event); void keyrelease(XCBGenericEvent *event); diff --git a/keybinds.h b/keybinds.h index 67447e7..0efc15c 100644 --- a/keybinds.h +++ b/keybinds.h @@ -121,7 +121,8 @@ static const Key keys[] = static const Button buttons[] = { /* Type Button Mask function arg */ - { XCB_BUTTON_PRESS, RMB, SUPER, ResizeWindow, {.i = RMB} }, + { XCB_BUTTON_PRESS, RMB, SUPER, ResizeWindow, {0} }, + { XCB_BUTTON_PRESS, LMB, SUPER, DragWindow, {0} }, }; diff --git a/toggle.c b/toggle.c index 0aa7009..eeac224 100644 --- a/toggle.c +++ b/toggle.c @@ -10,9 +10,7 @@ #include "util.h" #include "dwm.h" -#include "xcb_trl.h" #include "toggle.h" -#include "queue.h" /* * For people wanting to make new functions: @@ -20,23 +18,26 @@ */ /* TODO: Make these functions seperate threads */ -extern void (*handler[]) (XCBGenericEvent *); +extern void (*handler[XCBLASTEvent]) (XCBGenericEvent *); extern WM _wm; +extern XCBCursor cursors[CurLast]; void UserStats(const Arg *arg) { - char *str = XCBDebugGetCallStack(); - int i = 0; - while(str[i]) - { - fprintf(stderr, "%c", str[i]); - if(str[i] == '\0') - { break; - } - ++i; + Client *c = _wm.selmon->desksel->sel; + + if(c) + { DEBUG("(x: %d, y: %d, w: %u, h: %u)", c->x, c->y, c->w, c->h); + DEBUG("(ox: %d, oy: %d, ow: %u, oh: %u)", c->oldx, c->oldy, c->oldw, c->oldh); + DEBUG("NETNAME: %s", c->netwmname); + DEBUG("WMNAME: %s", c->wmname); + DEBUG("CLASSNAME: %s", c->classname); + DEBUG("INSTANCENAME:%s", c->instancename); + } + else + { DEBUG0("NULL"); } - free(str); } void @@ -95,10 +96,89 @@ TerminateWindow(const Arg *arg) void DragWindow( - XCBDisplay *display, - XCBWindow win, - const XCBKeyCode key_or_button) + const Arg *arg + ) { + + if(!_wm.selmon->desksel->sel) + { return; + } + Client *c = _wm.selmon->desksel->sel; + XCBWindow win = c->win; + i16 nx, ny; + i16 x, y; + i16 oldx, oldy; + const XCBCursor cur = XCB_NONE; + + /* init data */ + x = y = 0; + oldx = c->x; + oldy = c->y; + + XCBCookie QueryPointerCookie = XCBQueryPointerCookie(_wm.dpy, win); + XCBQueryPointer *pointer = XCBQueryPointerReply(_wm.dpy, QueryPointerCookie); + + if(pointer) + { + x = pointer->root_x; + y = pointer->root_y; + free(pointer); + } + XCBCookie GrabPointerCookie = XCBGrabPointerCookie(_wm.dpy, _wm.root, False, MOUSEMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, None, cur, XCB_CURRENT_TIME); + XCBGrabPointer *GrabPointer = XCBGrabPointerReply(_wm.dpy, GrabPointerCookie); + + if(!GrabPointer || GrabPointer->status != XCB_GRAB_STATUS_SUCCESS) + { free(GrabPointer); + return; + } + /* prevent DOCKED from computing non floating */ + setfloating(c, 1); c->x += 1; + arrange(c->desktop); + XCBRaiseWindow(_wm.dpy, win); + XCBFlush(_wm.dpy); + XCBGenericEvent *ev = NULL; + do + { + if(ev) + { + eventhandler(ev); + if(XCB_EVENT_RESPONSE_TYPE(ev) == XCB_MOTION_NOTIFY) + { + XCBMotionNotifyEvent *mev = (XCBMotionNotifyEvent *)ev; + nx = oldx + (mev->event_x - x); + ny = oldy + (mev->event_y - y); + resize(c, nx, ny, c->w, c->h, 1); + XCBFlush(_wm.dpy); + DEBUG("(x: %d, y: %d)", nx, ny); + } + /* this accounts for users killing the window (cause they can) */ + else if(XCB_EVENT_RESPONSE_TYPE(ev) == XCB_UNMAP_NOTIFY) + { XCBUnMapNotifyEvent *uev = (XCBUnMapNotifyEvent *)ev; + if(uev->window == win) + { free(ev); + win = 0; + break; + } + } + free(ev); + } + } while(_wm.running && !XCBNextEvent(_wm.dpy, &ev) && XCB_EVENT_RESPONSE_TYPE(ev) != XCB_BUTTON_RELEASE); + XCBUngrabPointer(_wm.dpy, XCB_CURRENT_TIME); + Monitor *m; + if(win) + { + if ((m = recttomon(c->x, c->y, c->w, c->h)) != _wm.selmon) + { + setclientdesktop(c, m->desksel); + _wm.selmon = m; + focus(NULL); + } + if(DOCKED(c)) + { setfloating(c, 0); + } + } + arrange(_wm.selmon->desksel); + XCBFlush(_wm.dpy); } void @@ -108,23 +188,12 @@ Restart(const Arg *arg) quit(); } -void -Restartf(const Arg *arg) -{ - restart(); -} - void Quit(const Arg *arg) { quit(); } -void -MoveWindow(const Arg *arg) -{ -} - void ResizeWindow(const Arg *arg) { @@ -144,13 +213,11 @@ ResizeWindow(const Arg *arg) i16 oldx, oldy; i8 horz, vert; u16 basew, baseh; + XCBCursor cur; /* init data */ curx = cury = oldw = oldh = nx = ny = nw = nh = oldx = oldy = horz = vert = basew = baseh = 0; - basew = c->minw; - baseh = c->minh; - XCBCookie QueryPointerCookie = XCBQueryPointerCookie(display, win); XCBQueryPointer *pointer = XCBQueryPointerReply(display, QueryPointerCookie); @@ -162,49 +229,98 @@ ResizeWindow(const Arg *arg) ny = pointer->win_y; free(pointer); } - - if(!pointer) + else { return; } horz = nx < c->w / 2 ? -1 : 1; vert = ny < c->h / 2 ? -1 : 1; + if(horz == -1) + { + if(vert == -1) + { cur = cursors[CurResizeTopR]; + } + else + { cur = cursors[CurResizeTopL]; + } + } + else + { + if(vert == -1) + { cur = cursors[CurResizeTopR]; + } + else + { cur = cursors[CurResizeTopL]; + } + } + + XCBCookie GrabPointerCookie = XCBGrabPointerCookie(_wm.dpy, _wm.root, False, MOUSEMASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, None, cur, XCB_CURRENT_TIME); + XCBGrabPointer *GrabPointer = XCBGrabPointerReply(_wm.dpy, GrabPointerCookie); + if(!GrabPointer || GrabPointer->status != XCB_GRAB_STATUS_SUCCESS) + { free(GrabPointer); + return; + } oldw = c->w; oldh = c->h; oldx = c->x; oldy = c->y; - + basew = c->minw; + baseh = c->minh; + /* Prevent it from being detected as non floating */ + setfloating(c, 1); c->x += 1; + arrange(c->desktop); + XCBRaiseWindow(_wm.dpy, win); + XCBFlush(_wm.dpy); XCBGenericEvent *ev = NULL; - while(_wm.running && !XCBNextEvent(_wm.dpy, &ev)) + do { - eventhandler(ev); - if(XCB_EVENT_RESPONSE_TYPE(ev) == XCB_MOTION_NOTIFY) + if(ev) { - nw = oldw + horz * ((XCBMotionNotifyEvent *)ev)->event_x - curx; - nh = oldh + vert * ((XCBMotionNotifyEvent *)ev)->event_y - cury; - - nw = MAX(nw, basew); - nh = MAX(nh, baseh); - - nx = oldx + !~horz * (oldw - nw); - ny = oldy + !~vert * (oldh - nh); - resize(c, nx, ny, nw, nh, 0); - DEBUG0("SEARCHED"); - /* XCBMoveResizeWindow(display, win, nx, ny, nw, nh); */ - } - else if(XCB_EVENT_RESPONSE_TYPE(ev) == XCB_BUTTON_RELEASE) - { - DEBUG0("RELEASED"); + eventhandler(ev); + if(XCB_EVENT_RESPONSE_TYPE(ev) == XCB_MOTION_NOTIFY) + { + nw = oldw + horz * (((XCBMotionNotifyEvent *)ev)->root_x - curx); + nh = oldh + vert * (((XCBMotionNotifyEvent *)ev)->root_y - cury); + + nw = MAX(nw, basew); + nh = MAX(nh, baseh); + + nx = oldx + !~horz * (oldw - nw); + ny = oldy + !~vert * (oldh - nh); + resize(c, nx, ny, nw, nh, 1); + XCBFlush(_wm.dpy); + DEBUG("(x: %d, y: %d, w: %u, h: %u)", nx, ny, nw, nh); + } + /* this accounts for users killing the window (cause they can) */ + else if(XCB_EVENT_RESPONSE_TYPE(ev) == XCB_UNMAP_NOTIFY) + { XCBUnMapNotifyEvent *uev = (XCBUnMapNotifyEvent *)ev; + if(uev->window == win) + { free(ev); + win = 0; + break; + } + } free(ev); - break; } - free(ev); - ev = NULL; + } while(_wm.running && !XCBNextEvent(_wm.dpy, &ev) && XCB_EVENT_RESPONSE_TYPE(ev) != XCB_BUTTON_RELEASE); + XCBUngrabPointer(_wm.dpy, XCB_CURRENT_TIME); + Monitor *m; + if(win) + { + if ((m = recttomon(c->x, c->y, c->w, c->h)) != _wm.selmon) + { + setclientdesktop(c, m->desksel); + _wm.selmon = m; + focus(NULL); + } + if(DOCKED(c)) + { setfloating(c, 0); + } } - - DEBUG0(""); + arrange(_wm.selmon->desksel); + XCBFlush(_wm.dpy); } void @@ -265,14 +381,14 @@ MaximizeWindow(const Arg *arg) { const Monitor *m = _wm.selmon; Client *c = m->desksel->sel; - if(!c || !m) + if(!c) { return; } const u16 snap = 0; /* floating are auto handled to be any window that isnt maxed */ - if(ISFLOATING(c)) + if(!DOCKED(c)) { if(ISFIXED(c)) { /* snap to grid instead. */ @@ -281,6 +397,7 @@ MaximizeWindow(const Arg *arg) else { maximize(c); } + DEBUG("Maximized: %u", c->win); } else /* else its maximized */ { @@ -288,7 +405,7 @@ MaximizeWindow(const Arg *arg) const uint8_t samey = c->y == c->oldy; const uint8_t samew = c->w == c->oldw; const uint8_t sameh = c->h == c->oldh; - const uint8_t sameall = samex & samey & samew & sameh; + const uint8_t sameall = samex && samey && samew && sameh; if(sameall) { @@ -298,7 +415,7 @@ MaximizeWindow(const Arg *arg) } else { /* make half the size */ - resize(c, c->x + c->w / 2, c->y + c->h / 2, c->w / 2, c->h / 2, 0); + resize(c, c->x + WIDTH(c) / 2, c->y + HEIGHT(c) / 2, WIDTH(c) / 2, HEIGHT(c) / 2, 0); } } else @@ -312,7 +429,10 @@ MaximizeWindow(const Arg *arg) resize(c, c->oldx, c->oldy, c->oldw, c->oldh, 0); } } + DEBUG("UnMaximized: %u", c->win); } + arrange(c->desktop); + XCBFlush(_wm.dpy); } void diff --git a/toggle.h b/toggle.h index 2a7554a..5e93221 100644 --- a/toggle.h +++ b/toggle.h @@ -1,5 +1,6 @@ #ifndef TOGGLE_H_ #define TOGGLE_H_ + #include "dwm.h" @@ -18,7 +19,7 @@ void KillWindow(const Arg *arg); /* Attempts to kill the current window directly instead of just sending a signal and waiting for the window to respond */ void TerminateWindow(const Arg *arg); /* keybind to move the current window where the mouse cursor is */ -void DragWindow(XCBDisplay *display, XCBWindow win, const XCBKeyCode key_or_button); +void DragWindow(const Arg *arg); /* restarts dwm */ void Restart(const Arg *arg); /* quits dwm */ diff --git a/util.h b/util.h index 3789b7e..bdd2e07 100644 --- a/util.h +++ b/util.h @@ -18,7 +18,6 @@ typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; - typedef union Generic Generic; typedef union ARGB ARGB; @@ -100,8 +99,6 @@ union ARGB #define DEBUG0(X) ((void)0) #endif - - /* gcc */ #ifdef __GNUC__ #define ASM(X) (__asm__(X)) @@ -147,7 +144,6 @@ double functime(void (*_timefunction)(void)); #define Nill ((void *)0) #endif - #define ASSUME(cond) do { if (!(cond)) __builtin_unreachable(); } while (0) /* Original implementation: Simon Tatham