diff --git a/client.c b/client.c new file mode 100644 index 0000000..f34752f --- /dev/null +++ b/client.c @@ -0,0 +1,2438 @@ +#include /* fabsf() */ + +#include "client.h" + +#include "dwm.h" +#include "keybinds.h" +#include "util.h" + +extern WM _wm; +extern XCBAtom netatom[]; +extern XCBAtom wmatom[]; +extern XCBAtom motifatom; + +/* Client struct flags */ +#define _FSTATE_FLOATING ((1 << 0)) +#define _FSTATE_WASFLOATING ((1 << 1)) +#define _FSTATE_SHOW_DECOR ((1 << 2)) +#define _FSTATE_OVERRIDE_REDIRECT ((1 << 3)) +#define _FSTATE_KEEP_FOCUS ((1 << 4)) +#define _FSTATE_DISABLE_BORDER ((1 << 5)) +/* EWMH window types */ +#define _TYPE_DESKTOP ((1 << 0)) +#define _TYPE_DOCK ((1 << 1)) +#define _TYPE_TOOLBAR ((1 << 2)) +#define _TYPE_MENU ((1 << 3)) +#define _TYPE_UTILITY ((1 << 4)) +#define _TYPE_SPLASH ((1 << 5)) +#define _TYPE_DIALOG ((1 << 6)) +#define _TYPE_DROPDOWN_MENU ((1 << 7)) +#define _TYPE_POPUP_MENU ((1 << 8)) +#define _TYPE_TOOLTIP ((1 << 9)) +#define _TYPE_NOTIFICATION ((1 << 10)) +#define _TYPE_COMBO ((1 << 11)) +#define _TYPE_DND ((1 << 12)) +#define _TYPE_NORMAL ((1 << 13)) + +/* custom types (using spare bits )*/ +#define _TYPE_NEVERFOCUS ((1 << 14)) +/* Window map states, Widthdrawn, Iconic, Normal. */ +#define _TYPE_MAP_ICONIC ((1 << 15)) + +/* EWMH Window states */ +#define _STATE_MODAL ((1 << 0)) +#define _STATE_STICKY ((1 << 1)) +#define _STATE_MAXIMIZED_VERT ((1 << 2)) +#define _STATE_MAXIMIZED_HORZ ((1 << 3)) +#define _STATE_SHADED ((1 << 4)) +#define _STATE_SKIP_TASKBAR ((1 << 5)) +#define _STATE_SKIP_PAGER ((1 << 6)) +#define _STATE_HIDDEN ((1 << 7)) +#define _STATE_FULLSCREEN ((1 << 8)) +#define _STATE_ABOVE ((1 << 9)) +#define _STATE_BELOW ((1 << 10)) +#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)) + +/* Macro definitions */ + +u16 OLDWIDTH(Client *c) { return (c->oldw + (c->bw * 2)); } +u16 OLDHEIGHT(Client *c) { return (c->oldw + (c->bw * 2)); } +u16 WIDTH(Client *c) { return (c->w + (c->bw * 2)); } +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) { return c->flags & _FSTATE_WASFLOATING; } +int ISFLOATING(Client *c) { return c->flags & _FSTATE_FLOATING; } +int ISOVERRIDEREDIRECT(Client *c) { return c->flags & _FSTATE_OVERRIDE_REDIRECT; } +int KEEPFOCUS(Client *c) { return c->flags & _FSTATE_KEEP_FOCUS; } +int DISABLEBORDER(Client *c) { return c->flags & _FSTATE_DISABLE_BORDER; } +int ISFAKEFLOATING(Client *c) { return c->flags & _FSTATE_FLOATING || c->desktop->layout == Floating; } + +int WASDOCKEDVERT(Client *c) { const i16 wy = c->desktop->mon->wy; + const u16 wh = c->desktop->mon->wh; + const i16 y = c->oldy; + const u16 h = OLDHEIGHT(c); + return (wy == y) && (wh == h); + } +int WASDOCKEDHORZ(Client *c) { const i16 wx = c->desktop->mon->wx; + const u16 ww = c->desktop->mon->ww; + const i16 x = c->oldx; + const u16 w = OLDWIDTH(c); + return (wx == x) && (ww == w); + } + +int WASDOCKED(Client *c) { return WASDOCKEDVERT(c) & WASDOCKEDHORZ(c); } + +int DOCKEDVERT(Client *c) { const i16 wy = c->desktop->mon->wy; + const u16 wh = c->desktop->mon->wh; + const i16 y = c->y; + const u16 h = HEIGHT(c); + return (wy == y) && (wh == h); + } + +int DOCKEDHORZ(Client *c) { const i16 wx = c->desktop->mon->wx; + const u16 ww = c->desktop->mon->ww; + const i16 x = c->x; + const u16 w = WIDTH(c); + return (wx == x) && (ww == w); + } +int DOCKED(Client *c) { return DOCKEDVERT(c) & DOCKEDHORZ(c); } + + +/* used in manage */ +int DOCKEDINITIAL(Client *c) { Monitor *m = c->desktop->mon; + const i16 wx = m->wx; + const i16 wy = m->my; + const i16 mx = m->mx; + const i16 my = m->my; + + const u16 ww = m->ww; + const u16 wh = m->wh; + const u16 mw = m->mw; + const u16 mh = m->mh; + + const i16 x = c->x; + const i16 y = c->y; + const u16 w = c->w; + const u16 h = c->h; + const u16 w1 = WIDTH(c); + const u16 h1 = HEIGHT(c); + + return + ((wx == x) && (wy == y) && (ww == w) && (wh == h)) + || + ((wx == x) && (wy == y) && (ww == w1) && (wh == h1)) + || + ((mx == x) && (my == y) && (mh == h) && (mw == w)) + || + ((mx == x) && (my == y) && (mh == h1) && (mw == w1)) + ; + } + +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->ww; } +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 SHOWDECOR(Client *c) { return c->flags & _FSTATE_SHOW_DECOR; } +int ISSELECTED(Client *c) { return c->desktop->sel == c; } + +int COULDBEBAR(Client *c, uint8_t strut) + { + const u8 sticky = !!ISSTICKY(c); + const u8 isdock = !!(ISDOCK(c)); + const u8 above = !!ISABOVE(c); + return (sticky && strut && (above || isdock)); + } +/* EWMH Window types */ +int ISDESKTOP(Client *c) { return c->wtypeflags & _TYPE_DESKTOP; } +int ISDOCK(Client *c) { return c->wtypeflags & _TYPE_DOCK; } +int ISTOOLBAR(Client *c) { return c->wtypeflags & _TYPE_TOOLBAR; } +int ISMENU(Client *c) { return c->wtypeflags & _TYPE_MENU; } +int ISUTILITY(Client *c) { return c->wtypeflags & _TYPE_UTILITY; } +int ISSPLASH(Client *c) { return c->wtypeflags & _TYPE_SPLASH; } +int ISDIALOG(Client *c) { return c->wtypeflags & _TYPE_DIALOG; } +int ISDROPDOWNMENU(Client *c) { return c->wtypeflags & _TYPE_DROPDOWN_MENU; } +int ISPOPUPMENU(Client *c) { return c->wtypeflags & _TYPE_POPUP_MENU; } +int ISTOOLTIP(Client *c) { return c->wtypeflags & _TYPE_TOOLTIP; } +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_MAP_ICONIC; } +int ISMAPNORMAL(Client *c) { return !ISMAPICONIC(c); } +int WTYPENONE(Client *c) { return c->wtypeflags == 0; } +/* EWMH Window states */ +int ISMODAL(Client *c) { return c->wstateflags & _STATE_MODAL; } +int ISSTICKY(Client *c) { return c->wstateflags & _STATE_STICKY; } +/* DONT USE */ +int ISMAXIMIZEDVERT(Client *c) { return c->wstateflags & _STATE_MAXIMIZED_VERT; } +/* DONT USE */ +int ISMAXIMIZEDHORZ(Client *c) { return c->wstateflags & _STATE_MAXIMIZED_HORZ; } +int ISSHADED(Client *c) { return c->wstateflags & _STATE_SHADED; } +int SKIPTASKBAR(Client *c) { return c->wstateflags & _STATE_SKIP_TASKBAR; } +int SKIPPAGER(Client *c) { return c->wstateflags & _STATE_SKIP_PAGER; } +int ISHIDDEN(Client *c) { return c->wstateflags & _STATE_HIDDEN; } +int ISFULLSCREEN(Client *c) { return c->wstateflags & _STATE_FULLSCREEN; } +int ISABOVE(Client *c) { return c->wstateflags & _STATE_ABOVE; } +int ISBELOW(Client *c) { return c->wstateflags & _STATE_BELOW; } +int DEMANDSATTENTION(Client *c) { return c->wstateflags & _STATE_DEMANDS_ATTENTION; } +int ISFOCUSED(Client *c) { return c->wstateflags & _STATE_FOCUSED; } +int WSTATENONE(Client *c) { return c->wstateflags == 0; } +/* WM Protocol */ +int HASWMTAKEFOCUS(Client *c) { return c->wstateflags & _STATE_SUPPORTED_WM_TAKE_FOCUS; } +int HASWMSAVEYOURSELF(Client *c){ return c->wstateflags & _STATE_SUPPORTED_WM_SAVE_YOURSELF; } +int HASWMDELETEWINDOW(Client *c){ return c->wstateflags & _STATE_SUPPORTED_WM_DELETE_WINDOW; } + + + +void +applygravity(const u32 gravity, i16 *x, i16 *y, const u16 w, const u16 h, const u16 bw) +{ + if(!gravity || !x || !y) + { return; + } + /* This is bullshit just reference relative to this point */ + if(gravity & XCB_GRAVITY_STATIC) + { /* default do nothing */ + } + else if(gravity & XCB_GRAVITY_NORTH_WEST) + { + *x -= bw; + *y -= bw; + } + else if(gravity & XCB_GRAVITY_NORTH) + { + *x += w >> 1; + *y -= bw; + } + else if(gravity & XCB_GRAVITY_NORTH_EAST) + { + *x += w + bw; + *y -= bw; + } + else if(gravity & XCB_GRAVITY_EAST) + { + *x += w + bw; + *y += h >> 1; + } + else if(gravity & XCB_GRAVITY_SOUTH_EAST) + { + *x += w + bw; + *y += h + bw; + } + else if(gravity & XCB_GRAVITY_SOUTH) + { + *x += w >> 1; + *y += h + bw; + } + else if(gravity & XCB_GRAVITY_SOUTH_WEST) + { + *x -= bw; + *y += h + bw; + } + else if(gravity & XCB_GRAVITY_WEST) + { + *x -= bw; + *y += h >> 1; + } + else if(gravity & XCB_GRAVITY_CENTER) + { + *x += w >> 1; + *y += h >> 1; + } + +} + +uint8_t +applysizehints(Client *c, i32 *x, i32 *y, i32 *width, i32 *height, uint8_t interact) +{ + u8 baseismin; + const Monitor *m = c->desktop->mon; + + if (interact) + { + if (*x > _wm.sw) + { *x = _wm.sw - WIDTH(c); + } + if (*y > _wm.sh) + { *y = _wm.sh - HEIGHT(c); + } + if (*x + *width + (WIDTH(c) - c->w) < 0) + { *x = 0; + } + if (*y + *height + (HEIGHT(c) - c->h) < 0) + { *y = 0; + } + } + else + { + if (*x >= m->wx + m->ww) + { *x = m->wx + m->ww - WIDTH(c); + } + if (*y >= m->wy + m->wh) + { *y = m->wy + m->wh - HEIGHT(c); + } + if (*x + *width + (WIDTH(c) - c->w) <= m->wx) + { *x = m->wx; + } + if (*y + *height + (HEIGHT(c) - c->h) <= m->wy) + { *y = m->wy; + } + } + + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + /* temporarily remove base dimensions */ + if (!baseismin) + { + *width -= c->basew; + *height -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) + { + if (c->maxa < (float)*width / *height) + { *width = *height * c->maxa + 0.5; + } + else if (c->mina < (float)*height / *width) + { *height = *width * c->mina + 0.5; + } + } + /* increment calculation requires this */ + if (baseismin) + { + *width -= c->basew; + *height -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + { *width -= *width % c->incw; + } + if (c->inch) + { *height -= *height % c->inch; + } + /* restore base dimensions */ + *width = MAX(*width + c->basew, c->minw); + *height = MAX(*height + c->baseh, c->minh); + if (c->maxw) + { *width = MIN(*width, c->maxw); + } + if (c->maxh) + { *height = MIN(*height, c->maxh); + } + return *x != c->x || *y != c->y || *width != c->w || *height != c->h; +} + +void +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 +clientinitgeom(Client *c, XCBWindowGeometry *wg) +{ + /* Give initial values. */ + c->x = c->oldx = 0; + c->y = c->oldy = 0; + c->w = c->oldw = _wm.selmon->ww; + c->h = c->oldh = _wm.selmon->wh; + c->bw = 0; /* TODO */ + + /* If we got attributes apply them. */ + if(wg) + { + /* init geometry */ + c->x = c->oldx = wg->x; + c->y = c->oldy = wg->y; + c->w = c->oldw = wg->width; + c->h = c->oldh = wg->height; + c->oldbw = wg->border_width; + /* if no specified border width default to our own. */ + if(wg->border_width) + { c->bw = wg->border_width; + } + } +} +void +clientinitwtype(Client *c, XCBWindowProperty *windowtypereply) +{ + if(windowtypereply) + { + XCBAtom *data = XCBGetPropertyValue(windowtypereply); + const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(windowtypereply, sizeof(XCBAtom)); + updatewindowtypes(c, data, ATOM_LENGTH); + } +} + +void +clientinitwstate(Client *c, XCBWindowProperty *windowstatereply) +{ + if(windowstatereply) + { + const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(windowstatereply, sizeof(XCBAtom)); + XCBAtom *data = XCBGetPropertyValue(windowstatereply); + updatewindowstates(c, data, ATOM_LENGTH); + } +} + +void +clientinittrans(Client *c, XCBWindow trans) +{ + Client *t; + if(trans && (t = wintoclient(trans))) + { c->desktop = t->desktop; + } + else + { c->desktop = _wm.selmon->desksel; + } +} + +void +configure(Client *c) +{ + const XCBConfigureNotifyEvent ce = + { + .response_type = XCB_CONFIGURE_NOTIFY, + .event = c->win, + .window = c->win, + .x = c->x, + .y = c->y, + .width = c->w, + .height = c->h, + .border_width = c->bw, + .above_sibling = XCB_NONE, + .override_redirect = False, + /* valgrind complains about "uninitialized bytes" */ + .pad0 = 0, + .pad1 = 0, + .sequence = 0 + }; + /* valgrind says that this generates some stack allocation error in writev(vector[1]) but it seems to be a xcb issue */ + XCBSendEvent(_wm.dpy, c->win, False, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *)&ce); +} + +Client * +createclient(void) +{ + /* This uses calloc as we are currently testing stuff, but we will juse malloc and zero it out later in production*/ + Client *c = calloc(1, sizeof(Client )); + Decoration *decor = createdecoration(); + if(!c || !decor) + { + DEBUG0("Could not allocate memory for client (OutOfMemory)."); + DEBUG("Client: %p", (void *)c); + DEBUG("Decoration: %p", (void *)decor); + free(c); + free(decor); + return NULL; + } + c->decor = decor; + c->x = c->y = 0; + c->w = c->h = 0; + c->oldx = c->oldy = 0; + c->oldw = c->oldh = 0; + c->wtypeflags = 0; + c->wstateflags = 0; + c->bw = c->oldbw = 0; + c->bcol = 0; + c->win = 0; + c->mina = c->maxa = 0; + c->basew = c->baseh = 0; + c->incw = c->inch = 0; + c->maxw = c->maxh = 0; + c->pid = 0; + c->desktop = NULL; + c->wmname = NULL; + c->netwmname = NULL; + c->classname = NULL; + c->instancename = NULL; + return c; +} + +void +focus(Client *c) +{ + Monitor *selmon = _wm.selmon; + Desktop *desk = selmon->desksel; + if(!c || !ISVISIBLE(c)) + { for(c = desk->focus; c && !ISVISIBLE(c) && !KEEPFOCUS(c); c = nextfocus(c)); + } + if(desk->sel && desk->sel != c) + { unfocus(desk->sel, 0); + } + if(c) + { + if(c->desktop->mon != _wm.selmon) + { _wm.selmon = c->desktop->mon; + } + if(c->desktop != _wm.selmon->desksel) + { setdesktopsel(_wm.selmon, c->desktop); + } + + if(ISURGENT(c)) + { seturgent(c, 0); + } + + detachfocus(c); + attachfocus(c); + + grabbuttons(c, 1); + XCBSetWindowBorder(_wm.dpy, c->win, c->bcol); + setfocus(c); + } + else + { + XCBSetInputFocus(_wm.dpy, _wm.root, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); + XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow]); + } + desk->sel = c; + DEBUG("Focused: [%d]", c ? c->win : 0); +} + +void +grabbuttons(Client *c, uint8_t focused) +{ + /* make sure no other client steals our grab */ + xcb_grab_server(_wm.dpy); + u16 i, j; + /* numlock is int */ + int modifiers[4] = { 0, XCB_MOD_MASK_LOCK, _wm.numlockmask, _wm.numlockmask|XCB_MOD_MASK_LOCK}; + /* Always grab these to allow for replay pointer when focusing by mouse click */ + u8 gbuttons[3] = { LMB, MMB, RMB }; + + /* ungrab any previously grabbed buttons that are ours */ + for(i = 0; i < LENGTH(modifiers); ++i) + { + for(j = 0; j < LENGTH(gbuttons); ++j) + { XCBUngrabButton(_wm.dpy, gbuttons[j], modifiers[i], c->win); + } + for(j = 0; j < LENGTH(buttons); ++j) + { XCBUngrabButton(_wm.dpy, buttons[j].button, modifiers[i], c->win); + } + } + if (!focused) + { + /* grab focus buttons */ + for (i = 0; i < LENGTH(gbuttons); ++i) + { + for (j = 0; j < LENGTH(modifiers); ++j) + { XCBGrabButton(_wm.dpy, gbuttons[i], modifiers[j], c->win, False, BUTTONMASK, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE); + } + } + } + for (i = 0; i < LENGTH(buttons); ++i) + { + for (j = 0; j < LENGTH(modifiers); ++j) + { + XCBGrabButton(_wm.dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, + XCB_NONE, XCB_NONE); + } + } + xcb_ungrab_server(_wm.dpy); +} + +void +grabkeys(void) +{ + u32 i, j, k; + u32 modifiers[4] = { 0, XCB_MOD_MASK_LOCK, _wm.numlockmask, _wm.numlockmask|XCB_MOD_MASK_LOCK }; + XCBKeyCode *keycodes[LENGTH(keys)]; + XCBUngrabKey(_wm.dpy, XCB_GRAB_ANY, XCB_MOD_MASK_ANY, _wm.root); + + /* This grabs all the keys */ + for(i = 0; i < LENGTH(keys); ++i) + { keycodes[i] = XCBKeySymbolsGetKeyCode(_wm.syms, keys[i].keysym); + } + for(i = 0; i < LENGTH(keys); ++i) + { + for(j = 0; keycodes[i][j] != XCB_NO_SYMBOL; ++j) + { + if(keys[i].keysym == XCBKeySymbolsGetKeySym(_wm.syms, keycodes[i][j], 0)) + { + for(k = 0; k < LENGTH(modifiers); ++k) + { + XCBGrabKey(_wm.dpy, + keycodes[i][j], keys[i].mod | modifiers[k], + _wm.root, True, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + } + } + } + } + + for(i = 0; i < LENGTH(keys); ++i) + { free(keycodes[i]); + } +} + +void +killclient(Client *c, enum KillType type) +{ + if(!c) + { return; + } + if(HASWMSAVEYOURSELF(c)) + { sendprotocolevent(c, wmatom[WMSaveYourself]); + } + if(HASWMDELETEWINDOW(c)) + { sendprotocolevent(c, wmatom[WMDeleteWindow]); + } + else + { + Monitor *m = c->desktop->mon; + XCBWindow win = c->win; + XCBUnmapNotifyEvent ev; + XCBCookie seq; + switch(type) + { + case Graceful: + seq = XCBKillClient(_wm.dpy, win); + break; + case Safedestroy: + /* TODO */ + seq = XCBKillClient(_wm.dpy, win); + break; + case Destroy: + seq = XCBDestroyWindow(_wm.dpy, win); + break; + default: + seq = XCBKillClient(_wm.dpy, win); + break; + } + /* let event handler handle this */ + ev.from_configure = 0; + ev.response_type = XCB_UNMAP_NOTIFY; + ev.event = _wm.root; + ev.window = win; + ev.sequence = seq.sequence + 1; + ev.pad0 = 0; + ev.pad1[0] = 0; + ev.pad1[1] = 0; + ev.pad1[2] = 0; + XCBSendEvent(_wm.dpy, _wm.root, 0, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)&ev); + } +} + +void +managerequest(XCBWindow win, XCBCookie requests[ManageCookieLAST]) +{ + 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; + const u8 MOTIF_WM_HINT_LENGTH = 5; + + /* Window Attributes */ + requests[ManageCookieAttributes] = + XCBGetWindowAttributesCookie(_wm.dpy, win); + /* Window Geometry */ + requests[ManageCookieGeometry] = + XCBGetWindowGeometryCookie(_wm.dpy, win); + /* Window Transient */ + requests[ManageCookieTransient] = + XCBGetTransientForHintCookie(_wm.dpy, win); + /* Window Type(s) */ + requests[ManageCookieWType] = + XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMWindowType], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); + /* Window State(s) */ + requests[ManageCookieWState] = + XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMState], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); + /* Window Size Hints */ + requests[ManageCookieSizeHint] = + XCBGetWMNormalHintsCookie(_wm.dpy, win); + /* Window WM Hints */ + requests[ManageCookieWMHints] = + XCBGetWMHintsCookie(_wm.dpy, win); + /* Window Class/Instance */ + requests[ManageCookieClass] = + XCBGetWMClassCookie(_wm.dpy, win); + /* Window WM Protocol(s) */ + requests[ManageCookieWMProtocol] = + XCBGetWMProtocolsCookie(_wm.dpy, win, wmatom[WMProtocols]); + /* Window Strut */ + requests[ManageCookieStrut] = + XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMStrut], NO_BYTE_OFFSET, STRUT_LENGTH, False, XCB_ATOM_CARDINAL); + /* Window StrutP */ + requests[ManageCookieStrutP] = + XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMStrutPartial], NO_BYTE_OFFSET, STRUT_P_LENGTH, False, XCB_ATOM_CARDINAL); + /* Window NetWMName */ + requests[ManageCookieNetWMName] = + XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMName], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, netatom[NetUtf8String]); + /* Window WMName */ + requests[ManageCookieWMName] = + XCBGetWindowPropertyCookie(_wm.dpy, win, XCB_ATOM_WM_NAME, NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_STRING); + /* Window Pid */ + requests[ManageCookiePid] = + XCBGetPidCookie(_wm.dpy, win, netatom[NetWMPid]); + /* Window Icon */ + requests[ManageCookieIcon] = + XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMIcon], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_CARDINAL); + /* Window Motif */ + requests[ManageCookieMotif] = + XCBGetWindowPropertyCookie(_wm.dpy, win, motifatom, NO_BYTE_OFFSET, MOTIF_WM_HINT_LENGTH, False, motifatom); +} + +Client * +managereply(XCBWindow win, XCBCookie requests[ManageCookieLAST]) +{ + /* checks */ + if(win == _wm.root) + { DEBUG("%s", "Cannot manage() root window."); + return NULL; + } + else if(wintoclient(win)) + { DEBUG("Window already managed????: [%u]", win); + return NULL; + } + + const u16 bw = 0; + const u32 bcol = 0; + const u8 showdecor = 1; + + Monitor *m = NULL; + Client *c = NULL; + XCBWindow trans = 0; + u8 transstatus = 0; + const u32 inputmask = XCB_EVENT_MASK_ENTER_WINDOW|XCB_EVENT_MASK_FOCUS_CHANGE|XCB_EVENT_MASK_PROPERTY_CHANGE|XCB_EVENT_MASK_STRUCTURE_NOTIFY; + XCBWindowGeometry *wg = NULL; + + XCBGetWindowAttributes *waattributes = NULL; + XCBWindowProperty *wtypeunused = NULL; + XCBWindowProperty *stateunused = NULL; + XCBSizeHints hints; + u8 hintstatus = 0; + XCBWMHints *wmh = NULL; + XCBWMClass cls = { ._reply = NULL }; + u8 clsstatus = 0; + XCBWMProtocols wmprotocols = { ._reply = NULL, .atoms_len = 0 }; + u8 wmprotocolsstatus = 0; + XCBWindowProperty *strutpreply = NULL; + XCBWindowProperty *strutreply = NULL; + u32 *strutp = NULL; + u32 *strut = NULL; + XCBWindowProperty *netwmnamereply = NULL; + XCBWindowProperty *wmnamereply = NULL; + char *netwmname = NULL; + char *wmname = NULL; + XCBWindowProperty *iconreply = NULL; + pid_t pid = 0; + XCBWindowProperty *motifreply = NULL; + + /* we do it here before, because we are waiting for replies and for more memory. */ + c = createclient(); + + /* wait for replies */ + waattributes = XCBGetWindowAttributesReply(_wm.dpy, requests[ManageCookieAttributes]); + wg = XCBGetWindowGeometryReply(_wm.dpy, requests[ManageCookieGeometry]); + transstatus = XCBGetTransientForHintReply(_wm.dpy, requests[ManageCookieTransient], &trans); trans *= !!transstatus; + wtypeunused = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieWType]); + stateunused = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieWState]); + hintstatus = XCBGetWMNormalHintsReply(_wm.dpy, requests[ManageCookieSizeHint], &hints); + wmh = XCBGetWMHintsReply(_wm.dpy, requests[ManageCookieWMHints]); + clsstatus = XCBGetWMClassReply(_wm.dpy, requests[ManageCookieClass], &cls); + wmprotocolsstatus = XCBGetWMProtocolsReply(_wm.dpy, requests[ManageCookieWMProtocol], &wmprotocols); + strutreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieStrut]); + strutpreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieStrutP]); + netwmnamereply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieNetWMName]); + wmnamereply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieWMName]); + iconreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieIcon]); + pid = XCBGetPidReply(_wm.dpy, requests[ManageCookiePid]); + motifreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieMotif]); + + strutp = strutpreply ? XCBGetWindowPropertyValue(strutpreply) : NULL; + strut = strutreply ? XCBGetWindowPropertyValue(strutpreply) : NULL; + + if(!c) + { goto FAILURE; + } + c->win = win; + + /* On Failure clear flag and ignore hints */ + hints.flags *= !!hintstatus; + + if(waattributes && waattributes->override_redirect) + { DEBUG("Override Redirect: [%d]", win); + /* theoredically we could manage these but they are a hastle to deal with */ + goto FAILURE; + } + + /* this sets up the desktop which is quite important for some operations */ + clientinittrans(c, trans); + + clientinitgeom(c, wg); + clientinitwtype(c, wtypeunused); + clientinitwstate(c, stateunused); + updatewindowprotocol(c, wmprotocolsstatus ? &wmprotocols : NULL); + getnamefromreply(netwmnamereply, &netwmname); + getnamefromreply(wmnamereply, &wmname); + setfloating(c, !!trans); + /* Custom stuff */ + setclientpid(c, pid); + setborderwidth(c, bw); + setbordercolor32(c, bcol); + setshowdecor(c, showdecor); + updatetitle(c, netwmname, wmname); + updatesizehints(c, &hints); + if(clsstatus) + { updateclass(c, &cls); + } + updatewmhints(c, wmh); + updatemotifhints(c, motifreply); + updateicon(c, iconreply); + XCBSelectInput(_wm.dpy, win, inputmask); + grabbuttons(c, 0); + + m = c->desktop->mon; + + attach(c); + attachstack(c); + attachfocus(c); + + updateclientlist(win, ClientListAdd); + setclientstate(c, XCB_WINDOW_NORMAL_STATE); + + HASH_ADD_INT(m->__hash, win, c); + + if(DOCKEDINITIAL(c)) + { + if(ISFLOATING(c)) + { setfloating(c, 0); + } + } + else + { + /* some windows (like st) dont mean to be "floating" but rather are a side effect of their own calculation(s), + * So we check if its in the corner, and assume its not meant to be floating. + */ + if((c->x == m->wx && c->y == m->wy) || (c->x == m->mx && c->y == m->my)) + { + if(ISFLOATING(c)) + { setfloating(c, 0); + } + } + /* else its some sort of popup and just leave floating */ + else + { + if(!ISFLOATING(c)) + { setfloating(c, 1); + } + } + } + /* inherit previous client state */ + if(c->desktop && c->desktop->sel) + { setfullscreen(c, ISFULLSCREEN(c->desktop->sel) || ISFULLSCREEN(c)); + } + + /* propagates border_width, if size doesn't change */ + configure(c); + + /* if its a new bar we dont want to return it as the monitor now manages it */ + if(!checknewbar(m, c, strut || strutp)) + { c = NULL; + } + goto CLEANUP; +FAILURE: + free(c); + c = NULL; + goto CLEANUP; +CLEANUP: + /* reply cleanup */ + free(waattributes); + free(wmh); + free(stateunused); + free(wtypeunused); + free(wg); + XCBWipeGetWMClass(&cls); + XCBWipeGetWMProtocols(&wmprotocols); + free(strutpreply); + free(strutreply); + free(netwmnamereply); + free(wmnamereply); + /* maybe no or just memcpy the first icon into a buffer and keep the thing just there. */ + free(iconreply); + return c; +} + +void +maximize(Client *c) +{ + maximizehorz(c); + maximizevert(c); + DEBUG("Maximized: %u", c->win); +} + +void +maximizehorz(Client *c) +{ + const Monitor *m = c->desktop->mon; + const i16 x = m->wx; + const i16 y = c->y; + const u16 w = m->ww - (WIDTH(c) - c->w); + const u16 h = c->h; + resize(c, x, y, w, h, 0); +} + +void +maximizevert(Client *c) +{ + const Monitor *m = c->desktop->mon; + const i16 x = c->x; + const i16 y = m->my; + const u16 w = c->w; + const u16 h = m->wh - (HEIGHT(c) - c->h); + resize(c, x, y, w, h, 0); +} + +Client * +nextclient(Client *c) +{ + return c ? c->next : c; +} + +Client * +nextstack(Client *c) +{ + return c ? c->snext : c; +} + +Client * +nextrstack(Client *c) +{ + return c ? c->rnext : c; +} + +Client * +nextfocus(Client *c) +{ + return c ? c->fnext : c; +} + +Client * +nexttiled(Client *c) +{ + for(; c && (ISFLOATING(c) || !ISVISIBLE(c)); c = nextstack(c)); + return c; +} + +Client * +nextvisible(Client *c) +{ + for(; c && !ISVISIBLE(c); c = c->next); + return c; +} + +Client * +prevclient(Client *c) +{ + return c ? c->prev : c; +} + +Client * +prevfocus(Client *c) +{ + return c ? c->fprev : c; +} + +Client * +prevstack(Client *c) +{ + return c ? c->sprev : c; +} + +Client * +prevrstack(Client *c) +{ + return c ? c->rprev : c; +} + +Client * +prevvisible(Client *c) +{ + while(c && !ISVISIBLE(c)) + { c = prevclient(c); + } + return c; +} + +void +resize(Client *c, i32 x, i32 y, i32 width, i32 height, uint8_t interact) +{ + if(applysizehints(c, &x, &y, &width, &height, interact)) + { resizeclient(c, x, y, width, height); + } +} + +void +resizeclient(Client *c, int16_t x, int16_t y, uint16_t width, uint16_t height) +{ + u32 mask = 0; + + if(c->x != x) + { + c->oldx = c->x; + c->x = x; + mask |= XCB_CONFIG_WINDOW_X; + } + if(c->y != y) + { + c->oldy = c->y; + c->y = y; + mask |= XCB_CONFIG_WINDOW_Y; + } + if(c->w != width) + { + c->oldw = c->w; + c->w = width; + mask |= XCB_CONFIG_WINDOW_WIDTH; + } + if(c->h != height) + { + c->oldh = c->h; + c->h = height; + mask |= XCB_CONFIG_WINDOW_HEIGHT; + } + + XCBWindowChanges changes = + { + .x = x, + .y = y, + .width = width, + .height = height, + }; + + /* Process resize requests only to visible clients as to. 1.) Save resources, no need to handle non visible windows. + * 2.) Incase that the window does get visible make it not appear to be movable (different desktop). + * 3.) Prevent the window from moving itself back into view, when it should be hidden. + * 4.) Incase a window does want focus, we switch to that desktop respectively and let showhide() do the work. + */ + if(ISVISIBLE(c)) + { + if(mask) + { XCBConfigureWindow(_wm.dpy, c->win, mask, &changes); + } + } + configure(c); +} + +void +sendprotocolevent(Client *c, XCBAtom proto) +{ + XCBClientMessageEvent ev; + ev.type = wmatom[WMProtocols]; + ev.response_type = XCB_CLIENT_MESSAGE; + ev.window = c->win; + ev.format = 32; + ev.data.data32[0] = proto; + ev.data.data32[1] = XCB_CURRENT_TIME; + XCBSendEvent(_wm.dpy, c->win, False, XCB_NONE, (const char *)&ev); +} + +void +setalwaysontop(Client *c, u8 state) +{ + SETFLAG(c->wstateflags, _STATE_ABOVE, !!state); +} + +void +setalwaysonbottom(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_BELOW, !!state); +} + +void +setborderalpha(Client *c, uint8_t alpha) +{ + /* remove previous alpha */ + const u32 ccol = c->bcol & ~(UINT8_MAX << 24); + const u32 col = ccol + (alpha << 24); + /* TODO */ + setbordercolor32(c, col); +} + +void +setbordercolor(Client *c, uint8_t red, uint8_t green, uint8_t blue) +{ + /* get alpha */ + const u32 alpha = c->bcol & (UINT8_MAX << 24); + + const u32 col = blue + (green << 8) + (red << 16) + alpha; + setbordercolor32(c, col); +} + +void +setbordercolor32(Client *c, uint32_t col) +{ + c->bcol = col; + XCBSetWindowBorder(_wm.dpy, c->win, c->bcol); +} + +void +setborderwidth(Client *c, uint16_t border_width) +{ + if(!DISABLEBORDER(c)) + { + c->oldbw = c->bw; + c->bw = border_width; + XCBSetWindowBorderWidth(_wm.dpy, c->win, c->bw); + configure(c); + } +} + +void +setclientdesktop(Client *c, Desktop *desk) +{ + detachcompletely(c); + c->desktop = desk; + attach(c); + attachstack(c); + attachfocus(c); +} + +void +setclientstate(Client *c, u8 state) +{ + /* Due to windows only having 1 map state we can set this without needing to replace other data */ + const i32 data[2] = { state, XCB_NONE }; + XCBChangeProperty(_wm.dpy, c->win, wmatom[WMState], wmatom[WMState], 32, XCB_PROP_MODE_REPLACE, (unsigned char *)data, 2); +} + +void +setclientwtype(Client *c, XCBAtom atom, u8 state) +{ + /* TODO manage race conditions without needing to lock the server */ + const u8 _delete = !state; + const XCBWindow win = c->win; + const u32 NO_BYTE_OFFSET = 0L; + const u32 REQUEST_MAX_NEEDED_ITEMS = UINT32_MAX; + + XCBCookie cookie = XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMWindowType], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); + XCBWindowProperty *prop = XCBGetWindowPropertyReply(_wm.dpy, cookie); + void *data = NULL; + u32 len = 0; + u32 propmode = XCB_PROP_MODE_REPLACE; + if(prop) + { + XCBAtom *atoms = XCBGetPropertyValue(prop); + const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(prop, sizeof(XCBAtom)); + + u32 i; + u32 offset = 0; + u8 set = 0; + for(i = 0; i < ATOM_LENGTH; ++i) + { + if(atoms[i] == atom) + { + offset = i; + set = 1; + break; + } + } + + if(set) + { + if(_delete) + { + for(i = offset; i < ATOM_LENGTH - 1; ++i) + { atoms[i] = atoms[i + 1]; + } + data = atoms; + len = ATOM_LENGTH - 1; + } + else /* atom already exists do nothing */ + { + free(prop); + return; + } + } + else + { + if(_delete) /* prop not found mark as already deleted */ + { + free(prop); + return; + } + else /* set propmode to append cause we didnt find it */ + { + propmode = XCB_PROP_MODE_APPEND; + len = 1; + data = &atom; + } + } + } + else + { + len = 1; + data = &atom; + } + XCBChangeProperty(_wm.dpy, win, netatom[NetWMWindowType], XCB_ATOM_ATOM, 32, propmode, (const char *)data, len); +} + +void +setclientnetstate(Client *c, XCBAtom atom, u8 state) +{ + /* TODO manage race conditions without needing to lock the server */ + const u8 _delete = !state; + const XCBWindow win = c->win; + const u32 NO_BYTE_OFFSET = 0L; + const u32 REQUEST_MAX_NEEDED_ITEMS = UINT32_MAX; + + XCBCookie cookie = XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMState], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); + XCBWindowProperty *prop = XCBGetWindowPropertyReply(_wm.dpy, cookie); + void *data = NULL; + u32 len = 0; + u32 propmode = XCB_PROP_MODE_REPLACE; + if(prop) + { + XCBAtom *atoms = XCBGetPropertyValue(prop); + const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(prop, sizeof(XCBAtom)); + + u32 i; + u32 offset = 0; + u8 set = 0; + for(i = 0; i < ATOM_LENGTH; ++i) + { + if(atoms[i] == atom) + { + offset = i; + set = 1; + break; + } + } + + if(set) + { + if(_delete) + { + /* this gets optimized to memmove, cool! + * GCC v14.1.1 -Ou + */ + for(i = offset; i < ATOM_LENGTH - 1; ++i) + { atoms[i] = atoms[i + 1]; + } + data = atoms; + len = ATOM_LENGTH - 1; + } + else /* atom already exists do nothing */ + { + free(prop); + return; + } + } + else + { + if(_delete) /* prop not found mark as already deleted */ + { + free(prop); + return; + } + else /* set propmode to append cause we didnt find it */ + { + propmode = XCB_PROP_MODE_APPEND; + len = 1; + data = &atom; + } + } + } + else + { + len = 1; + data = &atom; + } + XCBChangeProperty(_wm.dpy, win, netatom[NetWMState], XCB_ATOM_ATOM, 32, propmode, (const char *)data, len); +} + +void +setdisableborder(Client *c, uint8_t state) +{ + SETFLAG(c->flags, _FSTATE_DISABLE_BORDER, !!state); +} + +void +setclientpid(Client *c, pid_t pid) +{ + c->pid = pid; +} + +void +setwtypedesktop(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_DESKTOP, !!state); +} + +void +setwtypedialog(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_DIALOG, !!state); +} + +void +setwtypedock(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_DOCK, !!state); +} + +void +setwtypetoolbar(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_TOOLBAR, !!state); +} + +void +setwtypemenu(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_MENU, !!state); +} + +void +setwtypeneverfocus(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_NEVERFOCUS, !!state); +} + +void +setwtypeutility(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_UTILITY, !!state); +} + +void +setwtypesplash(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_SPLASH, !!state); +} + +void +setwtypedropdownmenu(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_DROPDOWN_MENU, !!state); +} + +void +setwtypepopupmenu(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_POPUP_MENU, !!state); +} + +void +setwtypetooltip(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_TOOLTIP, !!state); +} + +void +setwtypenotification(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_NOTIFICATION, !!state); +} + +void +setwtypecombo(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_COMBO, !!state); +} + +void +setwtypednd(Client *c, uint8_t state) +{ + SETFLAG(c->wtypeflags, _TYPE_DND, !!state); +} + +void +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) +{ + SETFLAG(c->wstateflags, _STATE_SUPPORTED_WM_TAKE_FOCUS, !!state); +} + +void +setwmsaveyourself(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_SUPPORTED_WM_SAVE_YOURSELF, !!state); +} + +void +setwmdeletewindow(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_SUPPORTED_WM_DELETE_WINDOW, !!state); +} + +void +setskippager(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_SKIP_PAGER, !!state); +} + +void +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) +{ + Monitor *m = c->desktop->mon; + if(state && !ISFULLSCREEN(c)) + { + setclientnetstate(c, netatom[NetWMStateFullscreen], 1); + setborderwidth(c, c->bw); + setborderwidth(c, 0); + resizeclient(c, m->mx, m->wy, m->mw, m->mh); + XCBRaiseWindow(_wm.dpy, c->win); + } + else if(!state && ISFULLSCREEN(c)) + { + setclientnetstate(c, netatom[NetWMStateFullscreen], 0); + setborderwidth(c, c->oldbw); + resizeclient(c, c->oldx, c->oldy, c->oldw, c->oldh); + } + 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) +{ + if(!NEVERFOCUS(c)) + { + XCBSetInputFocus(_wm.dpy, c->win, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); + XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow], XCB_ATOM_WINDOW, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&(c->win), 1); + SETFLAG(c->wstateflags, _STATE_FOCUSED, 1); + } + if(HASWMTAKEFOCUS(c)) + { sendprotocolevent(c, wmatom[WMTakeFocus]); + } +} + +void +sethidden(Client *c, uint8_t state) +{ + if(state) + { + setclientstate(c, XCB_WINDOW_ICONIC_STATE); + setwtypemapiconic(c, 1); + } + else + { + setclientstate(c, XCB_WINDOW_NORMAL_STATE); + setwtypemapnormal(c, 1); + } + SETFLAG(c->wstateflags, _STATE_HIDDEN, !!state); +} + +void +setkeepfocus(Client *c, uint8_t state) +{ + SETFLAG(c->flags, _FSTATE_KEEP_FOCUS, !!state); +} + +void +setmaximizedvert(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_MAXIMIZED_VERT, !!state); +} + +void +setmaximizedhorz(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_MAXIMIZED_HORZ, !!state); +} + +void +setshaded(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_SHADED, !!state); +} + +void +setmodal(Client *c, uint8_t state) +{ + SETFLAG(c->wstateflags, _STATE_MODAL, !!state); +} + +void +setoverrideredirect(Client *c, uint8_t state) +{ + SETFLAG(c->flags, _FSTATE_OVERRIDE_REDIRECT, !!state); +} + +void +setsticky(Client *c, u8 state) +{ + SETFLAG(c->wstateflags, _STATE_STICKY, !!state); +} + +void +seturgent(Client *c, uint8_t state) +{ + XCBCookie wmhcookie = XCBGetWMHintsCookie(_wm.dpy, c->win); + XCBWMHints *wmh = XCBGetWMHintsReply(_wm.dpy, wmhcookie); + SETFLAG(c->wstateflags, _STATE_DEMANDS_ATTENTION, !!state); + if(state) + { /* set window border */ + } + else + { /* set window border */ + } + + if(wmh) + { + wmh->flags = state ? (wmh->flags | XCB_WM_HINT_URGENCY) : (wmh->flags & ~XCB_WM_HINT_URGENCY); + XCBSetWMHintsCookie(_wm.dpy, c->win, wmh); + free(wmh); + } + /* drawbar */ +} + +void +showhide(Client *c, const int show) +{ + const Monitor *m = c->desktop->mon; + if(show) + { XCBMoveResizeWindow(_wm.dpy, c->win, c->x, c->y, c->w, c->h); + } + else + { + const i16 x = -c->w - m->mx; + XCBMoveResizeWindow(_wm.dpy, c->win, x, c->y, c->w, c->h); + } +} + +void +unfocus(Client *c, uint8_t setfocus) +{ + if(!c) + { return; + } + grabbuttons(c, 0); + XCBSetWindowBorder(_wm.dpy, c->win, c->bcol); + if(setfocus) + { + XCBSetInputFocus(_wm.dpy, _wm.root, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); + XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow]); + } + SETFLAG(c->wstateflags, _STATE_FOCUSED, 0); +} + +void +updateicon(Client *c, XCBWindowProperty *iconprop) +{ + free(c->icon); + c->icon = geticonprop(iconprop); +} + +void +unmanage(Client *c, uint8_t destroyed) +{ + if(!c) + { return; + } + Desktop *desk = c->desktop; + const XCBWindow win = c->win; + + if(desk->mon->bar == c) + { desk->mon->bar = NULL; + } + if(!destroyed) + { + /* TODO causes alot of errors for some reason even if its not "destroyed" */ + } + /* TODO + * Memory leak if a client is unmaped and maped again + * (cause we would get the same input focus twice) + */ + HASH_DEL(desk->mon->__hash, c); + detachcompletely(c); + updateclientlist(win, ClientListRemove); + /* no need to arrange fully cause client is not mapped anymore */ + arrange(desk); + cleanupclient(c); + DEBUG("Unmanaged: [%u]", win); +} + +void +unmaximize(Client *c) +{ + unmaximizevert(c); + unmaximizehorz(c); + DEBUG("Umaximized: [%u]", c->win); +} + +void +unmaximizehorz(Client *c) +{ + const i16 x = c->oldx; + const i16 y = c->y; + const u16 w = c->oldw; + const u16 h = c->h; + + if(DOCKEDHORZ(c)) + { + /* if never maximized */ + if(WASDOCKEDHORZ(c)) + { resize(c, x / 2, y, w / 2, h, 0); + } + else + { resize(c, x, y, w, h, 0); + } + } + else + { DEBUG("Client already unmaxed horz: [%u]", c->win); + } +} + +void +unmaximizevert(Client *c) +{ + const i16 x = c->x; + const i16 y = c->oldy; + const u16 w = c->w; + const u16 h = c->oldh; + if(DOCKEDVERT(c)) + { + if(WASDOCKEDVERT(c)) + { resize(c, x, y / 2, w, h / 2, 0); + } + else + { resize(c, x, y, w, h, 0); + } + } + else + { DEBUG("Client already unmaxed vert: [%u]", c->win); + } +} + +void +updateclass(Client *c, XCBWMClass *_class) +{ + const u32 MAX_LEN = 1024; + if(_class) + { + if(_class->class_name) + { + const u32 CLASS_NAME_LEN = strnlen(_class->class_name, MAX_LEN) + 1; + const size_t CLASS_NAME_SIZE = sizeof(char) * CLASS_NAME_LEN; + char *clsname = malloc(CLASS_NAME_SIZE); + if(clsname) + { + memcpy(clsname, _class->class_name, CLASS_NAME_SIZE - sizeof(char)); + clsname[CLASS_NAME_LEN - 1] = '\0'; + free(c->classname); + c->classname = clsname; + } + } + if(_class->instance_name) + { + const u32 INSTANCE_NAME_LEN = strnlen(_class->instance_name, MAX_LEN) + 1; + const size_t INSTANCE_NAME_SIZE = sizeof(char) * INSTANCE_NAME_LEN; + char *iname = malloc(INSTANCE_NAME_SIZE); + if(iname) + { + memcpy(iname, _class->instance_name, INSTANCE_NAME_SIZE - sizeof(char)); + iname[INSTANCE_NAME_LEN - 1] = '\0'; + free(c->instancename); + c->instancename = iname; + } + } + } +} + +static void +__update_motif_decor(Client *c, uint32_t hints) +{ + /* bit definitions for MwmHints.decorations */ + const u32 DECOR_ALL = 1 << 0; + const u32 DECOR_BORDER = 1 << 1; + const u32 DECOR_RESIZEH = 1 << 2; + const u32 DECOR_TITLE = 1 << 3; + const u32 DECOR_MENU = 1 << 4; + const u32 DECOR_MINIMIZE = 1 << 5; + const u32 DECOR_MAXIMIZE = 1 << 6; + if(hints & DECOR_ALL) + { hints |= (uint32_t)~0; + } + + if(hints & DECOR_BORDER) + { setborderwidth(c, c->oldbw); + } + else + { + setdisableborder(c, 0); + setborderwidth(c, 0); + setdisableborder(c, 1); + } + if(hints & DECOR_RESIZEH) + { + /* NOP */ + ASSUME(0); + } + if(hints & DECOR_TITLE) + { setshowdecor(c, 1); + } + else + { setshowdecor(c, 0); + } + if(hints & DECOR_MENU) + { + /* NOP */ + ASSUME(0); + } + if(hints & DECOR_MINIMIZE || hints & DECOR_MAXIMIZE) + { + /* NOP */ + ASSUME(0); + } +} + +static void __update_motif_func(Client *c, int32_t hints) +{ + /* bit definitions for MwmHints.functions */ + const u32 FUNCS_ALL = 1 << 0; + const u32 FUNCS_RESIZE = 1 << 1; + const u32 FUNCS_MOVE = 1 << 2; + const u32 FUNCS_MINIMIZE = 1 << 3; + const u32 FUNCS_MAXIMIZE = 1 << 4; + const u32 FUNCS_CLOSE = 1 << 5; + + if(hints & FUNCS_ALL) + { hints |= (int32_t)~0; + } + + if(hints & FUNCS_RESIZE) + { /* NOP */ + } + else + { /* IDK set fixed or something */ + } + if(hints & FUNCS_MOVE) + { /* IGNORE */ + } + if(hints & FUNCS_MINIMIZE) + { /* IGNORE */ + } + if(hints & FUNCS_MAXIMIZE) + { /* IGNORE */ + } + if(hints & FUNCS_CLOSE) + { /* IGNORE */ + } +} + +static void __update_motif_input(Client *c, int32_t hints) +{ + /* values for MwmHints.input_mode */ + enum ___input + { + INPUT_MODELESS = 0, + INPUT_PRIMARY_MODAL = 1, + INPUT_SYSTEM_MODAL = 2, + INPUT_FULL_MODAL = 3, + }; + + switch(hints) + { + case INPUT_PRIMARY_MODAL: + case INPUT_SYSTEM_MODAL: + case INPUT_FULL_MODAL: + /* FALLTHROUGH */ + /* TODO: Add a hash to client "class" name attribute and just make it so 1 primary window is allowed + * AKA just HASH the primary class name to be urgent/active window + */ + seturgent(c, 1); + break; + + case INPUT_MODELESS: + /* FALLTHROUGH */ + default: + break; + } +} + +static void __update_motif_status(Client *c, int32_t hints) +{ + /* bit definitions for MwmHints.status */ + const u32 STATUS_TEAROFF_WIDOW = 1 << 0; + if(hints & STATUS_TEAROFF_WIDOW) + { setmodal(c, 1); + } +} + + +void +updatemotifhints(Client *c, XCBWindowProperty *motifprop) +{ + /* bit definitions for MwmHints.flags */ + const u32 HINTS_FUNCTIONS = 1 << 0; + const u32 HINTS_DECORATION = 1 << 1; + const u32 HINTS_INPUT_MODE = 1 << 2; + const u32 HINTS_STATUS = 1 << 3; + + if(motifprop) + { + MotifWmHints *hints = XCBGetPropertyValue(motifprop); + uint32_t len = XCBGetPropertyValueLength(motifprop, sizeof(MotifWmHints)); + if(hints && len == 1) + { + if(hints->flags & HINTS_DECORATION) + { __update_motif_decor(c, hints->decorations); + } + if(hints->flags & HINTS_FUNCTIONS) + { __update_motif_func(c, hints->functions); + } + if(hints->flags & HINTS_INPUT_MODE) + { __update_motif_input(c, hints->input_mode); + } + if(hints->flags & HINTS_STATUS) + { __update_motif_status(c, hints->status); + } + } + } +} + +void +updatesizehints(Client *c, XCBSizeHints *size) +{ + const int UNINITIALIZED = 0; + i32 basew = UNINITIALIZED; + i32 baseh = UNINITIALIZED; + i32 minw = UNINITIALIZED; + i32 minh = UNINITIALIZED; + i32 maxw = UNINITIALIZED; + i32 maxh = UNINITIALIZED; + i32 incw = UNINITIALIZED; + i32 inch = UNINITIALIZED; + float mina = (float)UNINITIALIZED + 0.0f; /* make sure sign is positive */ + float maxa = (float)UNINITIALIZED + 0.0f; /* make sure sign is positive */ + + /* size is uninitialized, ensure that size.flags aren't used */ + if(!size->flags) + { size->flags = XCB_SIZE_HINT_P_SIZE; + } + if(size->flags & XCB_SIZE_HINT_P_MIN_SIZE) + { + minw = size->min_width; + minh = size->min_height; + } + else if(size->flags & XCB_SIZE_HINT_P_BASE_SIZE) + { + minw = size->base_width; + minh = size->base_height; + } + + if(size->flags & XCB_SIZE_HINT_P_BASE_SIZE) + { + basew = size->base_width; + baseh = size->base_height; + } + else if(size->flags & XCB_SIZE_HINT_P_MIN_SIZE) + { + minw = size->min_width; + minh = size->min_height; + } + + if(size->flags & XCB_SIZE_HINT_P_RESIZE_INC) + { + incw = size->width_inc; + inch = size->height_inc; + } + if(size->flags & XCB_SIZE_HINT_P_MAX_SIZE) + { + maxw = size->max_width; + maxh = size->max_height; + } + + if(size->flags & XCB_SIZE_HINT_P_ASPECT) + { + mina = (float)size->min_aspect_den / (size->min_aspect_num + !size->min_aspect_den); + maxa = (float)size->max_aspect_num / (size->max_aspect_den + !size->max_aspect_num); + mina = fabsf(mina); + maxa = fabsf(maxa); + } + /* clamp */ + minw = MIN(minw, UINT16_MAX); + minh = MIN(minh, UINT16_MAX); + maxw = MIN(maxw, UINT16_MAX); + maxh = MIN(maxh, UINT16_MAX); + basew = MIN(basew, UINT16_MAX); + baseh = MIN(baseh, UINT16_MAX); + (void)mina; + (void)maxa; + inch = MIN(inch, UINT16_MAX); + incw = MIN(incw, UINT16_MAX); + + c->minw = minw; + c->minh = minh; + c->maxw = maxw; + c->maxh = maxh; + c->basew = basew; + c->baseh = baseh; + c->mina = mina; + c->maxa = maxa; + c->inch = inch; + c->incw = incw; +} + +void +updatetitle(Client *c, char *netwmname, char *wmname) +{ + if(c->wmname != wmname) + { free(c->wmname); + c->wmname = NULL; + } + if(c->netwmname != netwmname) + { free(c->netwmname); + c->netwmname = NULL; + } + c->wmname = wmname; + c->netwmname = netwmname; +} + +void +updatewindowprotocol(Client *c, XCBWMProtocols *protocols) +{ + if(protocols && protocols->atoms_len) + { + uint32_t i; + XCBAtom atom; + for(i = 0; i < protocols->atoms_len; ++i) + { + atom = protocols->atoms[i]; + if(atom == wmatom[WMTakeFocus]) + { setwmtakefocus(c, 1); + } + else if(atom == wmatom[WMDeleteWindow]) + { setwmdeletewindow(c, 1); + } + else if(atom == wmatom[WMSaveYourself]) + { setwmsaveyourself(c, 1); + } + } + } +} + +void +updatewindowstate(Client *c, XCBAtom state, uint8_t add_remove_toggle) +{ + if(!c || !state) + { return; + } + const u8 toggle = add_remove_toggle == 2; + /* This is similiar to those Windows 10 dialog boxes that play the err sound and cant click anything else */ + if (state == netatom[NetWMStateModal]) + { + if(toggle) + { + setmodal(c, !ISMODAL(c)); + setwtypedialog(c, !ISDIALOG(c)); + } + else + { + setmodal(c, add_remove_toggle); + setwtypedialog(c, add_remove_toggle); + } + } /* This is just syntax sugar, really its just a alias to NetWMStateAbove */ + else if (state == netatom[NetWMStateAbove] || state == netatom[NetWMStateAlwaysOnTop]) + { + if(toggle) + { + setalwaysontop(c, !ISALWAYSONTOP(c)); + } + else + { + setalwaysontop(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateDemandAttention]) + { + if(toggle) + { + seturgent(c, !ISURGENT(c)); + } + else + { + seturgent(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateFullscreen]) + { + if(toggle) + { + setfullscreen(c, !ISFULLSCREEN(c)); + } + else + { + setfullscreen(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateMaximizedHorz]) + { + if(toggle) + { + if(DOCKEDHORZ(c)) + { + unmaximizehorz(c); + setmaximizedhorz(c, 0); + } + else + { + maximizehorz(c); + setmaximizedhorz(c, 1); + } + } + else + { + if(add_remove_toggle) + { maximizehorz(c); + } + else + { unmaximizehorz(c); + } + setmaximizedhorz(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateMaximizedVert]) + { + if(toggle) + { + if(DOCKEDVERT(c)) + { + unmaximizevert(c); + setmaximizedvert(c, 0); + } + else + { + maximizevert(c); + setmaximizedvert(c, 1); + } + } + else + { + if(add_remove_toggle) + { maximizevert(c); + } + else + { unmaximizevert(c); + } + setmaximizedvert(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateSticky]) + { + if(toggle) + { + setsticky(c, !ISSTICKY(c)); + } + else + { + setsticky(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateBelow]) + { + /* this is a wierd state to even configure so idk */ + if(toggle) + { + setalwaysonbottom(c, !ISALWAYSONBOTTOM(c)); + } + else + { + /* attach last */ + setalwaysonbottom(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateSkipTaskbar]) + { + if(toggle) + { + setskiptaskbar(c, !SKIPTASKBAR(c)); + } + else + { + setskiptaskbar(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateSkipPager]) + { + if(toggle) + { + setskippager(c, !SKIPPAGER(c)); + } + else + { + setskippager(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateHidden]) + { + if(toggle) + { + sethidden(c, !ISHIDDEN(c)); + } + else + { + sethidden(c, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateFocused]) + { + if(toggle) + { + SETFLAG(c->wstateflags, _STATE_FOCUSED, !ISFOCUSED(c)); + } + else + { + SETFLAG(c->wstateflags, _STATE_FOCUSED, add_remove_toggle); + } + } + else if (state == netatom[NetWMStateShaded]) + { + if(toggle) + { + setshaded(c, !ISSHADED(c)); + } + else + { + setshaded(c, add_remove_toggle); + } + } + else + { + DEBUG0("Could not find state."); + } +} + +void +updatewindowstates(Client *c, XCBAtom states[], uint32_t atomslength) +{ + if(!states || !c) + { return; + } + + /* bullshit client is trying to mess with us */ + u16 MAX_LIMIT = 1000; + atomslength = MIN(atomslength, MAX_LIMIT); + + + u32 i; + for(i = 0; i < atomslength; ++i) + { + /* Even though the wm-spec says that we should remove things that arent in the list + * The client will ussually tell us in clientmessage if its important. + * It also says however that if its in the list assume its a prop so... + */ + updatewindowstate(c, states[i], 1); + } +} + +void +updatewindowtype(Client *c, XCBAtom wtype, uint8_t add_remove_toggle) +{ + if(!c || !wtype) + { return; + } + + const u8 toggle = add_remove_toggle == 2; + + if (wtype == netatom[NetWMWindowTypeDesktop]) + { + if(toggle) + { + setwtypedesktop(c, !ISDESKTOP(c)); + } + else + { + setwtypedesktop(c, add_remove_toggle); + } + /* TODO */ + } + else if (wtype == netatom[NetWMWindowTypeDock]) + { + if(toggle) + { + setwtypedock(c, !ISDOCK(c)); + } + else + { + setwtypedock(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeToolbar]) + { + if(toggle) + { + setwtypetoolbar(c, !ISTOOLBAR(c)); + } + else + { + setwtypetoolbar(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeMenu]) + { + if(toggle) + { + setwtypemenu(c, !ISMENU(c)); + } + else + { + setwtypemenu(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeUtility]) + { + if(toggle) + { + setwtypeutility(c, !ISUTILITY(c)); + } + else + { + setwtypeutility(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeSplash]) + { + if(toggle) + { + setwtypesplash(c, !ISSPLASH(c)); + } + else + { + setwtypesplash(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeDialog]) + { + if(toggle) + { + setwtypedialog(c, !ISDIALOG(c)); + } + else + { + setwtypedialog(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeDropdownMenu]) + { + if(toggle) + { + setwtypedropdownmenu(c, !ISDROPDOWNMENU(c)); + } + else + { + setwtypedropdownmenu(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypePopupMenu]) + { + if(toggle) + { + setwtypepopupmenu(c, !ISPOPUPMENU(c)); + } + else + { + setwtypepopupmenu(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeTooltip]) + { + if(toggle) + { + setwtypetooltip(c, !ISTOOLTIP(c)); + } + else + { + setwtypetooltip(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeNotification]) + { + if(toggle) + { + setwtypenotification(c, !ISNOTIFICATION(c)); + } + else + { + setwtypenotification(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeCombo]) + { + if(toggle) + { + setwtypecombo(c, !ISCOMBO(c)); + } + else + { + setwtypecombo(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeDnd]) + { + if(toggle) + { + setwtypednd(c, !ISDND(c)); + } + else + { + setwtypednd(c, add_remove_toggle); + } + } + else if (wtype == netatom[NetWMWindowTypeNormal]) + { + if(toggle) + { + setwtypenormal(c, !ISNORMAL(c)); + } + else + { + setwtypenormal(c, add_remove_toggle); + } + } + else + { + DEBUG0("Could not find type."); + } +} + +void +updatewindowtypes(Client *c, XCBAtom wtypes[], uint32_t atomslength) +{ + if(!wtypes || !c) + { return; + } + /* bullshit client is trying to mess with us */ + u8 MAX_LIMIT = 255; + atomslength = MIN(atomslength, MAX_LIMIT); + + i32 i; + for(i = 0; i < atomslength; ++i) + { + /* wm-spec says that we should assume anythings in the list are props so we just pass into "add" */ + updatewindowtype(c, wtypes[i], 1); + } +} + +void +updatewmhints(Client *c, XCBWMHints *wmh) +{ + if(wmh) + { + if(c == c->desktop->sel && wmh->flags & XCB_WM_HINT_URGENCY) + { + wmh->flags &= ~XCB_WM_HINT_URGENCY; + XCBSetWMHintsCookie(_wm.dpy, c->win, wmh); + /* dont put seturgent() here cause that would just undo what we did and be recursive */ + } + else + { + /* dont put seturgent() here cause that would just undo what we did and be recursive */ + SETFLAG(c->wstateflags, _STATE_DEMANDS_ATTENTION, !!(wmh->flags & XCB_WM_HINT_URGENCY)); + } + if(wmh->flags & XCB_WM_HINT_INPUT) + { setwtypeneverfocus(c, !wmh->input); + } + else + { setwtypeneverfocus(c, 0); + } + if(wmh->flags & XCB_WM_HINT_STATE) + { + switch(wmh->initial_state) + { + case XCB_WINDOW_ICONIC_STATE: + sethidden(c, 1); + break; + case XCB_WINDOW_WITHDRAWN_STATE: + DEBUG("Window Specified is Widthdrawn? %d", c->win); + break; + case XCB_WINDOW_NORMAL_STATE: + break; + default: + break; + } + } + if(wmh->flags & XCB_WM_HINT_ICON_PIXMAP) + { /* update icon or something */ + } + if(wmh->flags & XCB_WM_HINT_ICON_MASK) + { /* use flagged bits to asign icon shape */ + } + } +} + +Client * +wintoclient(XCBWindow win) +{ + Client *c = NULL; + Monitor *m = NULL; + + /* check sel first */ + for(m = _wm.selmon; m; m = nextmonitor(m)) + { + HASH_FIND_INT(m->__hash, &win, c); + if(c) + { return c; + } + } + return NULL; +} diff --git a/client.h b/client.h new file mode 100644 index 0000000..03169ad --- /dev/null +++ b/client.h @@ -0,0 +1,489 @@ +#ifndef _WM_CLIENT_H +#define _WM_CLIENT_H + + +#include "XCB-TRL/xcb_trl.h" +#include "uthash.h" + +#include + +/* kill client type */ +enum KillType +{ + Graceful, + Safedestroy, + Destroy, +}; + +/* Manage cookies */ +enum ManageCookies +{ + ManageCookieAttributes, + ManageCookieGeometry, + ManageCookieTransient, + ManageCookieWType, + ManageCookieWState, + ManageCookieSizeHint, + ManageCookieWMHints, + ManageCookieClass, + ManageCookieWMProtocol, + ManageCookieStrutP, + ManageCookieStrut, + ManageCookieNetWMName, + ManageCookieWMName, + ManageCookiePid, + ManageCookieIcon, + ManageCookieMotif, + + + ManageCookieLAST +}; + +typedef struct Client Client; +typedef struct Monitor Monitor; +typedef struct Desktop Desktop; +typedef struct Decoration Decoration; + +struct Client +{ + int16_t x; /* X coordinate */ + int16_t y; /* Y coordinate */ + + uint16_t w; /* Width */ + uint16_t h; /* height */ + + + int16_t oldx; /* Previous X coordinate */ + int16_t oldy; /* Previous Y coordinate */ + + uint16_t oldw; /* Previous Width */ + uint16_t oldh; /* Previous Height */ + + + 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 */ + + uint32_t bcol; /* Border Colour */ + + + float mina; /* Minimum Aspect */ + float maxa; /* Maximum Aspect */ + + + uint16_t basew; /* Base Width */ + uint16_t baseh; /* Base Height */ + + uint16_t incw; /* Increment Width */ + uint16_t inch; /* Increment Height */ + + + uint16_t maxw; /* Max Width. */ + uint16_t maxh; /* Max Height. */ + + uint16_t minw; /* Minimum Width */ + uint16_t minh; /* Minimum Height */ + + + XCBWindow win; /* Client Window */ + pid_t pid; /* Client Pid */ + + + Client *next; /* The next client in list */ + Client *prev; /* The previous client */ + Client *sprev; /* The prev stack order clnt*/ + Client *snext; /* The next client in stack */ + Client *rnext; /* Restack Next */ + Client *rprev; /* Restack Prev */ + Client *fnext; /* The next focused client */ + Client *fprev; /* THe previous focused clnt*/ + Desktop *desktop; /* Client Associated Desktop*/ + Decoration *decor; /* Decoration AKA title bar.*/ + + char *netwmname; /* Client Name */ + 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 */ + uint16_t rstacknum; /* Used in calculating pos */ + uint8_t pad[6]; +}; + + +/* Applies the gravity shifts specified by the gravity onto the x and y coordinates. +*/ +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. +* RETURN: 1 if the specified x/y/w/h does not match after sizehints applied. (aka need to resize.) +* RETURN: 0 if the specified x/y/w/h does match after the sizehints applied. (No need to resize.) +*/ +uint8_t applysizehints(Client *c, int32_t *x, int32_t *y, int32_t *width, int32_t *height, uint8_t interact); +/* Frees Client and allocated client properties. +*/ +void cleanupclient(Client *c); +/* Initializes the Client geometry from the specified XCBWindowGeometry struct. + */ +void clientinitgeom(Client *c, XCBWindowGeometry *geometry); +/* Initializes the Client window type from the specified XCBWindowProperty. */ +void clientinitwtype(Client *c, XCBWindowProperty *windowtypereply); +/* Initializes the Client window state from the specified XCBWindowProperty. */ +void clientinitwstate(Client *c, XCBWindowProperty *windowstatereply); +/* Sets the correct client desktop if trans found, default to _wm.selmon->desksel if not.*/ +void clientinittrans(Client *c, XCBWindow trans); +/* Updates the XServers knowledge of the clients coordinates. + * NOTE: This is a sendevent to the c->win data type. + * NOTE: XCBFlush(); must be called to push the XCB internal buffer to send this request. + */ +void configure(Client *c); +/* Allocates a client and client properties with all data set to 0 or the adress of any newly allocated data. + * RETURN: Client * on Success. + * RETURN: NULL on Failure. +*/ +Client *createclient(void); +/* Sets focus to the specified client. + * NOTE: if NULL provided first visible client in stack is choosen as focus specifier. + */ +void focus(Client *c); +/* Grabs a win buttons. + * Basically this just allows us to receive button press/release events from windows. + */ +void grabbuttons(Client *c, uint8_t focused); +/* Grabs a windows keys. + * Basically this just allows us to receive/intercept key press/release events. + */ +void grabkeys(void); +/* Kills the specified window. + * type: Graceful Sends a message to the window to kill itself. + * Safedestroy Sends a message to the window to kill itself, on failure, forcefully kill the window. + * Destroy Destroys a window without sending any message for the window to response (Nuclear option.) + */ +void killclient(Client *c, enum KillType type); +/* requests for clients cookies. */ +void managerequest(XCBWindow win, XCBCookie requests[ManageCookieLAST]); +/* Part of main event loop "run()" + * Manages AKA adds the window to our current or windows specified desktop. + * Applies size checks, bounds, layout, etc... + * RETURN: Client * on Success. + * RETURN: NULL on Failure. + */ +Client *managereply(XCBWindow window, XCBCookie requests[ManageCookieLAST]); +/* Maximizes a client if unmaxed, Sets flag. + */ +void maximize(Client *c); +/* Maximizes horizontally a client if unmaxed horz, Sets flag. + */ +void maximizehorz(Client *c); +/* Maximizes vertically a client if unmaxed vert, Sets flag. + */ +void maximizevert(Client *c); +/* Returns the next client avaible. + * RETURN: Client * on Success. + * RETURN: NULL on Failure. + */ +Client *nextclient(Client *c); +/* Returns the next client in stack avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *nextstack(Client *c); +/* Returns the next client in restack avaible. + * RETURN: Client * on Success. + * RETURN: NULL on Failure. + */ +Client *nextrstack(Client *c); +/* Returns the next client in focus order avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *nextfocus(Client *c); +/* Returns next tiled client when tiling. + * RETURN: Client * on Success. + * RETURN: NULL on Failure. + */ +Client *nexttiled(Client *c); +/* Returns the next visible client avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *nextvisible(Client *c); +/* Returns the prev client avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *prevclient(Client *c); +/* Returns the prev focus client avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *prevfocus(Client *c); +/* Returns the prev stack client avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *prevstack(Client *c); +/* Returns the previous restack stack client avaible. + * RETURN: Client * on Success. + * RETURN: NULL on Failure. + */ +Client *prevrstack(Client *c); +/* Returns the prev visible client avaible. + * RETURN: Client* on Success. + * RETURN: NULL on Failure. + */ +Client *prevvisible(Client *c); +/* resize a client only if specified x/y/w/h is different + * interact + * {1, 0} + * 1 -> dont confide resize to monitor dimentions + * 0 -> confide resize within monitor dimentions + * */ +void resize(Client *c, int32_t x, int32_t y, int32_t width, int32_t height, uint8_t interact); +/* resize a client given parametors without sizehints */ +void resizeclient(Client *c, int16_t x, int16_t y, uint16_t width, uint16_t height); + +/* Sends a Protocol Event to specified client */ +void sendprotocolevent(Client *c, XCBAtom proto); +/* Sets the flag "alwaysontop" to the provided Client */ +void setalwaysontop(Client *c, uint8_t isalwaysontop); +/* Sets the flag "alwaysonbottom" to the provided Client */ +void setalwaysonbottom(Client *c, uint8_t state); +/* Sets the Clients border opacity, "alpha" 0-255 */ +void setborderalpha(Client *c, uint8_t alpha); +/* Sets the border color using red green and blue values */ +void setbordercolor(Client *c, uint8_t red, uint8_t green, uint8_t blue); +/* Sets the border color only using the 32bit value */ +void setbordercolor32(Client *c, uint32_t col); +/* Sets the border width to the provided Client */ +void setborderwidth(Client *c, uint16_t border_width); +/* Sets the clients desktop to the specified desktop, + * and cleanups any data that may have been left from the previous desktop. + */ +void setclientdesktop(Client *c, Desktop *desktop); +/* Sets the clients wmatom[WMState] property. */ +void setclientstate(Client *c, uint8_t state); +/* Sets the decor visibility. */ +void setdecorvisible(Client *c, uint8_t state); +/* Sets the desktop count rolling back any clients to previous desktops. */ +void setdesktopcount(Monitor *m, uint16_t desktops); +/* Sets the desktops layouts, (not automatic arrange must be called after to apply changes.) */ +void setdesktoplayout(Desktop *desk, uint8_t layout); +/* Sets the currently selected desktop */ +void setdesktopsel(Monitor *mon, Desktop *desksel); +/* Sets the flag to disable border >>CHANGES<< for a client. */ +void setdisableborder(Client *c, uint8_t state); +/* Sets the clients pid. */ +void setclientpid(Client *c, pid_t pid); +/* Sets the Clients IS Desktop Flag. */ +void setwtypedesktop(Client *c, uint8_t state); +/* Sets the Clients IS Dialog Flag. */ +void setwtypedialog(Client *c, uint8_t state); +/* Sets the Clients IS Dock Flag. */ +void setwtypedock(Client *c, uint8_t state); +/* Sets the Clients IS ToolBar Flag. */ +void setwtypetoolbar(Client *c, uint8_t state); +/* Sets the Clients IS Menu Flag. */ +void setwtypemenu(Client *c, uint8_t state); +/* Sets the Clients Never Focus Flag. */ +void setwtypeneverfocus(Client *c, uint8_t state); +/* Sets the Clients IS Utility Flag. */ +void setwtypeutility(Client *c, uint8_t state); +/* Sets the Clients IS Splash Flag. */ +void setwtypesplash(Client *c, uint8_t state); +/* Sets the Clients IS Dropdown Menu Flag. */ +void setwtypedropdownmenu(Client *c, uint8_t state); +/* Sets the Clients IS Popup Menu Flag. */ +void setwtypepopupmenu(Client *c, uint8_t state); +/* Sets the Clients IS Tool Tip Flag. */ +void setwtypetooltip(Client *c, uint8_t state); +/* Sets the Clients IS Notification Flag. */ +void setwtypenotification(Client *c, uint8_t state); +/* Sets the Clients IS Combo Flag. */ +void setwtypecombo(Client *c, uint8_t state); +/* Sets the Clients IS DND Flag. */ +void setwtypednd(Client *c, uint8_t state); +/* Sets the Clients IS Normal Flag. */ +void setwtypenormal(Client *c, uint8_t state); +/* Sets the Clients IS Map Iconic Flag. */ +void setwtypemapiconic(Client *c, uint8_t state); +/* Sets the Clients IS Map Normal Flag. */ +void setwtypemapnormal(Client *c, uint8_t state); +/* Sets the Clients IS Take Focus Flag. */ +void setwmtakefocus(Client *c, uint8_t state); +/* Sets the Clients IS Save Yourself Flag. */ +void setwmsaveyourself(Client *c, uint8_t state); +/* Sets the Clients IS Delete Window Flag. */ +void setwmdeletewindow(Client *c, uint8_t state); +/* Sets the Clients IS Skip Pager Flag. */ +void setskippager(Client *c, uint8_t state); +/* Sets the Clients IS Skip Taskbar Flag. */ +void setskiptaskbar(Client *c, uint8_t state); +/* Sets the Clients Show Decor Flag. */ +void setshowdecor(Client *c, uint8_t state); +/* Makes a client fullscreen and take up the entire monitor. (also sets the isfullscreen flag)*/ +void setfullscreen(Client *c, uint8_t isfullscreen); +/* Sets the Clients IS Floating Flag. */ +void setfloating(Client *c, uint8_t state); +/* Sets the current Window Focus. */ +void setfocus(Client *c); +/* Sets the Windows Map State (Iconic/Normal), and IS hidden Flag. */ +void sethidden(Client *c, uint8_t state); +/* Sets the keep focus state flag + * NOTE: Client must already be in focus to work. + */ +void setkeepfocus(Client *c, uint8_t state); +/* Sets the "Maximized Vert" Flag */ +void setmaximizedvert(Client *c, uint8_t state); +/* Sets the "Maximized Horz" Flag */ +void setmaximizedhorz(Client *c, uint8_t state); +/* Sets the Clients IS Shaded Flag. */ +void setshaded(Client *c, uint8_t state); +/* Sets the Clients IS Modal Flag. */ +void setmodal(Client *c, uint8_t state); +/* Sets override redirect flag, which disallows attaching to any linked list for a desktop + * But still allows a client to be found using wintoclient() + */ +void setoverrideredirect(Client *c, uint8_t state); +/* Replaces the Clients state with the sticky state, and sets IS sticky Flag. */ +void setsticky(Client *c, uint8_t state); +/* Updates a Clients state to Urgent, and sets the Urgent Flag. (Updates window border to urgen color.) */ +void seturgent(Client *c, uint8_t isurgent); +/* Moves Client offscreen if "show" is true + * Moves Client onscreen if "false" is false; + * Should be used when changing desktop ONLY. + */ +void showhide(Client *c, const int show); +/* Unfocuses specified client and sets to focus to root if setfocus is true */ +void unfocus(Client *c, uint8_t setfocus); +/* updates a clients classname from XCBWMClass *_class + * No side effects on non filled _class dataw; + */ +void updateclass(Client *c, XCBWMClass *_class); +void updatedecor(Client *c); +/* Updates the Client icon if we find one */ +void updateicon(Client *c, XCBWindowProperty *iconprop); +/* updates motif hints if they are set */ +void updatemotifhints(Client *c, XCBWindowProperty *motifprop); +/* Updates a Clients sizehints property using the provided hints pointer "size". + * Doesnt require any data from client, AKA modular. still requires "size" though. + */ +void updatesizehints(Client *c, XCBSizeHints *size); +/* Updates Client tile if we find one; + * if none found default to dwm.h BROKEN + */ +void updatetitle(Client *c, char *netwmname, char *wmname); +/* Updates Our own window protocol status (dont have to query every time) */ +void updatewindowprotocol(Client *c, XCBWMProtocols *protocols); +/* Updates Our own state based on Client state specified */ +void updatewindowstate(Client *c, XCBAtom state, uint8_t add_remove_toggle); +/* Updates Our own states based on Client state specified */ +void updatewindowstates(Client *c, XCBAtom state[], uint32_t atomslength); +/* Updates Our own state based on windowtype in Client */ +void updatewindowtype(Client *c, XCBAtom wtype, uint8_t add_remove_toggle); +/* Updates Our own states based on windowtype in Client */ +void updatewindowtypes(Client *c, XCBAtom wtype[], uint32_t atomslength); +/* Updates WM_HINTS for specified Client */ +void updatewmhints(Client *c, XCBWMHints *hints); +/* Returns the client if found from the specified window + * RETURN: Client * on Success. + * RETURN: NULL on Failure. + */ +Client *wintoclient(XCBWindow win); +/* Unmanages Client AKA we dont tell it what todo Nor does it use our resources; + * And perform checks based on specified "destroyed"; + * 1 -> widthdraw window; + * 0 -> skip checks (window already destroyed) + */ +void unmanage(Client *c, uint8_t destroyed); +/* unmaximizes a client if maxed, Sets flag. */ +void unmaximize(Client *c); +/* unmaximizes a client horizontally if maxed horz, Sets flag. */ +void unmaximizehorz(Client *c); +/* unmaximizes a client vertically if maxed vert, Sets flag. */ +void unmaximizevert(Client *c); + +/* MACROS */ + +int ISALWAYSONTOP(Client *c); +int ISALWAYSONBOTTOM(Client *c); +int WASFLOATING(Client *c); +int ISFLOATING(Client *c); +int ISOVERRIDEREDIRECT(Client *c); +int KEEPFOCUS(Client *c); +int DISABLEBORDER(Client *c); +int ISFAKEFLOATING(Client *c); +int DOCKEDVERT(Client *c); +int DOCKEDHORZ(Client *c); +int DOCKED(Client *c); +int WASDOCKEDVERT(Client *c); +int WASDOCKEDHORZ(Client *c); +int WASDOCKED(Client *c); +int ISFIXED(Client *c); +int ISURGENT(Client *c); +int NEVERFOCUS(Client *c); +int ISVISIBLE(Client *c); +int SHOWDECOR(Client *c); +int ISSELECTED(Client *c); + +/* EWMH Window types */ +int ISDESKTOP(Client *c); +int ISDOCK(Client *c); +int ISTOOLBAR(Client *c); +int ISMENU(Client *c); +int ISUTILITY(Client *c); +int ISSPLASH(Client *c); +int ISDIALOG(Client *c); +int ISDROPDOWNMENU(Client *c); +int ISPOPUPMENU(Client *c); +int ISTOOLTIP(Client *c); +int ISNOTIFICATION(Client *c); +int ISCOMBO(Client *c); +int ISDND(Client *c); +int ISNORMAL(Client *c); +int ISMAPICONIC(Client *c); +int ISMAPNORMAL(Client *c); +int WTYPENONE(Client *c); + +/* EWMH Window states */ +int ISMODAL(Client *c); +int ISSTICKY(Client *c); +int ISMAXIMIZEDVERT(Client *c); +int ISMAXIMIZEDHORZ(Client *c); +int ISSHADED(Client *c); +int SKIPTASKBAR(Client *c); +int SKIPPAGER(Client *c); +int ISHIDDEN(Client *c); +int ISFULLSCREEN(Client *c); +int ISABOVE(Client *c); +int ISBELOW(Client *c); +int DEMANDSATTENTION(Client *c); +int ISFOCUSED(Client *c); +int WSTATENONE(Client *c); + +/* WM Protocol */ +int HASWMTAKEFOCUS(Client *c); +int HASWMSAVEYOURSELF(Client *c); +int HASWMDELETEWINDOW(Client *c); + +uint16_t OLDWIDTH(Client *c); +uint16_t OLDHEIGHT(Client *c); +uint16_t WIDTH(Client *c); +uint16_t HEIGHT(Client *c); + + + + + + + + + +#endif diff --git a/dwm.c b/dwm.c index b2b6f39..d4ad9fc 100644 --- a/dwm.c +++ b/dwm.c @@ -41,135 +41,7 @@ XCBAtom gtkatom[GTKLAST]; XCBAtom motifatom; XCBCursor cursors[CurLast]; -/* Macro definitions */ -u16 OLDWIDTH(Client *c) { return (c->oldw + (c->bw * 2)); } -u16 OLDHEIGHT(Client *c) { return (c->oldw + (c->bw * 2)); } -u16 WIDTH(Client *c) { return (c->w + (c->bw * 2)); } -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) { return c->flags & _FSTATE_WASFLOATING; } -int ISFLOATING(Client *c) { return c->flags & _FSTATE_FLOATING; } -int ISOVERRIDEREDIRECT(Client *c) { return c->flags & _FSTATE_OVERRIDE_REDIRECT; } -int KEEPFOCUS(Client *c) { return c->flags & _FSTATE_KEEP_FOCUS; } -int DISABLEBORDER(Client *c) { return c->flags & _FSTATE_DISABLE_BORDER; } -int ISFAKEFLOATING(Client *c) { return c->flags & _FSTATE_FLOATING || c->desktop->layout == Floating; } - -int WASDOCKEDVERT(Client *c) { const i16 wy = c->desktop->mon->wy; - const u16 wh = c->desktop->mon->wh; - const i16 y = c->oldy; - const u16 h = OLDHEIGHT(c); - return (wy == y) && (wh == h); - } -int WASDOCKEDHORZ(Client *c) { const i16 wx = c->desktop->mon->wx; - const u16 ww = c->desktop->mon->ww; - const i16 x = c->oldx; - const u16 w = OLDWIDTH(c); - return (wx == x) && (ww == w); - } - -int WASDOCKED(Client *c) { return WASDOCKEDVERT(c) & WASDOCKEDHORZ(c); } - -int DOCKEDVERT(Client *c) { const i16 wy = c->desktop->mon->wy; - const u16 wh = c->desktop->mon->wh; - const i16 y = c->y; - const u16 h = HEIGHT(c); - return (wy == y) && (wh == h); - } -int DOCKEDHORZ(Client *c) { const i16 wx = c->desktop->mon->wx; - const u16 ww = c->desktop->mon->ww; - const i16 x = c->x; - const u16 w = WIDTH(c); - return (wx == x) && (ww == w); - } -int DOCKED(Client *c) { return DOCKEDVERT(c) & DOCKEDHORZ(c); } - -/* used in manage */ -int DOCKEDINITIAL(Client *c) { Monitor *m = c->desktop->mon; - const i16 wx = m->wx; - const i16 wy = m->my; - const i16 mx = m->mx; - const i16 my = m->my; - - const u16 ww = m->ww; - const u16 wh = m->wh; - const u16 mw = m->mw; - const u16 mh = m->mh; - - const i16 x = c->x; - const i16 y = c->y; - const u16 w = c->w; - const u16 h = c->h; - const u16 w1 = WIDTH(c); - const u16 h1 = HEIGHT(c); - - return - ((wx == x) && (wy == y) && (ww == w) && (wh == h)) - || - ((wx == x) && (wy == y) && (ww == w1) && (wh == h1)) - || - ((mx == x) && (my == y) && (mh == h) && (mw == w)) - || - ((mx == x) && (my == y) && (mh == h1) && (mw == w1)) - ; - } -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->ww; } -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 SHOWDECOR(Client *c) { return c->flags & _FSTATE_SHOW_DECOR; } -int ISSELECTED(Client *c) { return c->desktop->sel == c; } - -int COULDBEBAR(Client *c, uint8_t strut) - { - const u8 sticky = !!ISSTICKY(c); - const u8 isdock = !!(ISDOCK(c)); - const u8 above = !!ISABOVE(c); - return (sticky && strut && (above || isdock)); - } -/* EWMH Window types */ -int ISDESKTOP(Client *c) { return c->wtypeflags & _TYPE_DESKTOP; } -int ISDOCK(Client *c) { return c->wtypeflags & _TYPE_DOCK; } -int ISTOOLBAR(Client *c) { return c->wtypeflags & _TYPE_TOOLBAR; } -int ISMENU(Client *c) { return c->wtypeflags & _TYPE_MENU; } -int ISUTILITY(Client *c) { return c->wtypeflags & _TYPE_UTILITY; } -int ISSPLASH(Client *c) { return c->wtypeflags & _TYPE_SPLASH; } -int ISDIALOG(Client *c) { return c->wtypeflags & _TYPE_DIALOG; } -int ISDROPDOWNMENU(Client *c) { return c->wtypeflags & _TYPE_DROPDOWN_MENU; } -int ISPOPUPMENU(Client *c) { return c->wtypeflags & _TYPE_POPUP_MENU; } -int ISTOOLTIP(Client *c) { return c->wtypeflags & _TYPE_TOOLTIP; } -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_MAP_ICONIC; } -int ISMAPNORMAL(Client *c) { return !ISMAPICONIC(c); } -int WTYPENONE(Client *c) { return c->wtypeflags == 0; } -/* EWMH Window states */ -int ISMODAL(Client *c) { return c->wstateflags & _STATE_MODAL; } -int ISSTICKY(Client *c) { return c->wstateflags & _STATE_STICKY; } -/* DONT USE */ -int ISMAXIMIZEDVERT(Client *c) { return c->wstateflags & _STATE_MAXIMIZED_VERT; } -/* DONT USE */ -int ISMAXIMIZEDHORZ(Client *c) { return c->wstateflags & _STATE_MAXIMIZED_HORZ; } -int ISSHADED(Client *c) { return c->wstateflags & _STATE_SHADED; } -int SKIPTASKBAR(Client *c) { return c->wstateflags & _STATE_SKIP_TASKBAR; } -int SKIPPAGER(Client *c) { return c->wstateflags & _STATE_SKIP_PAGER; } -int ISHIDDEN(Client *c) { return c->wstateflags & _STATE_HIDDEN; } -int ISFULLSCREEN(Client *c) { return c->wstateflags & _STATE_FULLSCREEN; } -int ISABOVE(Client *c) { return c->wstateflags & _STATE_ABOVE; } -int ISBELOW(Client *c) { return c->wstateflags & _STATE_BELOW; } -int DEMANDSATTENTION(Client *c) { return c->wstateflags & _STATE_DEMANDS_ATTENTION; } -int ISFOCUSED(Client *c) { return c->wstateflags & _STATE_FOCUSED; } -int WSTATENONE(Client *c) { return c->wstateflags == 0; } -/* WM Protocol */ -int HASWMTAKEFOCUS(Client *c) { return c->wstateflags & _STATE_SUPPORTED_WM_TAKE_FOCUS; } -int HASWMSAVEYOURSELF(Client *c){ return c->wstateflags & _STATE_SUPPORTED_WM_SAVE_YOURSELF; } -int HASWMDELETEWINDOW(Client *c){ return c->wstateflags & _STATE_SUPPORTED_WM_DELETE_WINDOW; } static uint32_t __intersect_area( @@ -402,143 +274,6 @@ argcvhandler(int argc, char *argv[]) } } -void -applygravity(const u32 gravity, i16 *x, i16 *y, const u16 w, const u16 h, const u16 bw) -{ - if(!gravity || !x || !y) - { return; - } - /* This is bullshit just reference relative to this point */ - if(gravity & XCB_GRAVITY_STATIC) - { /* default do nothing */ - } - else if(gravity & XCB_GRAVITY_NORTH_WEST) - { - *x -= bw; - *y -= bw; - } - else if(gravity & XCB_GRAVITY_NORTH) - { - *x += w >> 1; - *y -= bw; - } - else if(gravity & XCB_GRAVITY_NORTH_EAST) - { - *x += w + bw; - *y -= bw; - } - else if(gravity & XCB_GRAVITY_EAST) - { - *x += w + bw; - *y += h >> 1; - } - else if(gravity & XCB_GRAVITY_SOUTH_EAST) - { - *x += w + bw; - *y += h + bw; - } - else if(gravity & XCB_GRAVITY_SOUTH) - { - *x += w >> 1; - *y += h + bw; - } - else if(gravity & XCB_GRAVITY_SOUTH_WEST) - { - *x -= bw; - *y += h + bw; - } - else if(gravity & XCB_GRAVITY_WEST) - { - *x -= bw; - *y += h >> 1; - } - else if(gravity & XCB_GRAVITY_CENTER) - { - *x += w >> 1; - *y += h >> 1; - } - -} - -uint8_t -applysizehints(Client *c, i32 *x, i32 *y, i32 *width, i32 *height, uint8_t interact) -{ - u8 baseismin; - const Monitor *m = c->desktop->mon; - - if (interact) - { - if (*x > _wm.sw) - { *x = _wm.sw - WIDTH(c); - } - if (*y > _wm.sh) - { *y = _wm.sh - HEIGHT(c); - } - if (*x + *width + (WIDTH(c) - c->w) < 0) - { *x = 0; - } - if (*y + *height + (HEIGHT(c) - c->h) < 0) - { *y = 0; - } - } - else - { - if (*x >= m->wx + m->ww) - { *x = m->wx + m->ww - WIDTH(c); - } - if (*y >= m->wy + m->wh) - { *y = m->wy + m->wh - HEIGHT(c); - } - if (*x + *width + (WIDTH(c) - c->w) <= m->wx) - { *x = m->wx; - } - if (*y + *height + (HEIGHT(c) - c->h) <= m->wy) - { *y = m->wy; - } - } - - /* see last two sentences in ICCCM 4.1.2.3 */ - baseismin = c->basew == c->minw && c->baseh == c->minh; - /* temporarily remove base dimensions */ - if (!baseismin) - { - *width -= c->basew; - *height -= c->baseh; - } - /* adjust for aspect limits */ - if (c->mina > 0 && c->maxa > 0) - { - if (c->maxa < (float)*width / *height) - { *width = *height * c->maxa + 0.5; - } - else if (c->mina < (float)*height / *width) - { *height = *width * c->mina + 0.5; - } - } - /* increment calculation requires this */ - if (baseismin) - { - *width -= c->basew; - *height -= c->baseh; - } - /* adjust for increment value */ - if (c->incw) - { *width -= *width % c->incw; - } - if (c->inch) - { *height -= *height % c->inch; - } - /* restore base dimensions */ - *width = MAX(*width + c->basew, c->minw); - *height = MAX(*height + c->baseh, c->minh); - if (c->maxw) - { *width = MIN(*width, c->maxw); - } - if (c->maxh) - { *height = MIN(*height, c->maxh); - } - return *x != c->x || *y != c->y || *width != c->w || *height != c->h; -} void arrangeq(Desktop *desk) @@ -1017,19 +752,6 @@ cleanupdesktop(Desktop *desk) desk = NULL; } -void -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) { @@ -1071,128 +793,6 @@ cleanupmons(void) } } -void -clientinitgeom(Client *c, XCBWindowGeometry *wg) -{ - /* Give initial values. */ - c->x = c->oldx = 0; - c->y = c->oldy = 0; - c->w = c->oldw = _wm.selmon->ww; - c->h = c->oldh = _wm.selmon->wh; - c->bw = 0; /* TODO */ - - /* If we got attributes apply them. */ - if(wg) - { - /* init geometry */ - c->x = c->oldx = wg->x; - c->y = c->oldy = wg->y; - c->w = c->oldw = wg->width; - c->h = c->oldh = wg->height; - c->oldbw = wg->border_width; - /* if no specified border width default to our own. */ - if(wg->border_width) - { c->bw = wg->border_width; - } - } -} -void -clientinitwtype(Client *c, XCBWindowProperty *windowtypereply) -{ - if(windowtypereply) - { - XCBAtom *data = XCBGetPropertyValue(windowtypereply); - const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(windowtypereply, sizeof(XCBAtom)); - updatewindowtypes(c, data, ATOM_LENGTH); - } -} - -void -clientinitwstate(Client *c, XCBWindowProperty *windowstatereply) -{ - if(windowstatereply) - { - const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(windowstatereply, sizeof(XCBAtom)); - XCBAtom *data = XCBGetPropertyValue(windowstatereply); - updatewindowstates(c, data, ATOM_LENGTH); - } -} - -void -clientinittrans(Client *c, XCBWindow trans) -{ - Client *t; - if(trans && (t = wintoclient(trans))) - { c->desktop = t->desktop; - } - else - { c->desktop = _wm.selmon->desksel; - } -} - - -void -configure(Client *c) -{ - const XCBConfigureNotifyEvent ce = - { - .response_type = XCB_CONFIGURE_NOTIFY, - .event = c->win, - .window = c->win, - .x = c->x, - .y = c->y, - .width = c->w, - .height = c->h, - .border_width = c->bw, - .above_sibling = XCB_NONE, - .override_redirect = False, - /* valgrind complains about "uninitialized bytes" */ - .pad0 = 0, - .pad1 = 0, - .sequence = 0 - }; - /* valgrind says that this generates some stack allocation error in writev(vector[1]) but it seems to be a xcb issue */ - XCBSendEvent(_wm.dpy, c->win, False, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *)&ce); -} - -Client * -createclient(void) -{ - /* This uses calloc as we are currently testing stuff, but we will juse malloc and zero it out later in production*/ - Client *c = calloc(1, sizeof(Client )); - Decoration *decor = createdecoration(); - if(!c || !decor) - { - DEBUG0("Could not allocate memory for client (OutOfMemory)."); - DEBUG("Client: %p", (void *)c); - DEBUG("Decoration: %p", (void *)decor); - free(c); - free(decor); - return NULL; - } - c->decor = decor; - c->x = c->y = 0; - c->w = c->h = 0; - c->oldx = c->oldy = 0; - c->oldw = c->oldh = 0; - c->wtypeflags = 0; - c->wstateflags = 0; - c->bw = c->oldbw = 0; - c->bcol = 0; - c->win = 0; - c->mina = c->maxa = 0; - c->basew = c->baseh = 0; - c->incw = c->inch = 0; - c->maxw = c->maxh = 0; - c->pid = 0; - c->desktop = NULL; - c->wmname = NULL; - c->netwmname = NULL; - c->classname = NULL; - c->instancename = NULL; - return c; -} - Desktop * createdesktop(void) { @@ -1298,46 +898,6 @@ floating(Desktop *desk) monocle(desk); } -void -focus(Client *c) -{ - Monitor *selmon = _wm.selmon; - Desktop *desk = selmon->desksel; - if(!c || !ISVISIBLE(c)) - { for(c = desk->focus; c && !ISVISIBLE(c) && !KEEPFOCUS(c); c = nextfocus(c)); - } - if(desk->sel && desk->sel != c) - { unfocus(desk->sel, 0); - } - if(c) - { - if(c->desktop->mon != _wm.selmon) - { _wm.selmon = c->desktop->mon; - } - if(c->desktop != _wm.selmon->desksel) - { setdesktopsel(_wm.selmon, c->desktop); - } - - if(ISURGENT(c)) - { seturgent(c, 0); - } - - detachfocus(c); - attachfocus(c); - - grabbuttons(c, 1); - XCBSetWindowBorder(_wm.dpy, c->win, c->bcol); - setfocus(c); - } - else - { - XCBSetInputFocus(_wm.dpy, _wm.root, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); - XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow]); - } - desk->sel = c; - DEBUG("Focused: [%d]", c ? c->win : 0); -} - void getnamefromreply(XCBWindowProperty *namerep, char **str_return) { @@ -1437,85 +997,6 @@ getrootptr(i16 *x, i16 *y) return samescr; } -void -grabbuttons(Client *c, uint8_t focused) -{ - /* make sure no other client steals our grab */ - xcb_grab_server(_wm.dpy); - u16 i, j; - /* numlock is int */ - int modifiers[4] = { 0, XCB_MOD_MASK_LOCK, _wm.numlockmask, _wm.numlockmask|XCB_MOD_MASK_LOCK}; - /* Always grab these to allow for replay pointer when focusing by mouse click */ - u8 gbuttons[3] = { LMB, MMB, RMB }; - - /* ungrab any previously grabbed buttons that are ours */ - for(i = 0; i < LENGTH(modifiers); ++i) - { - for(j = 0; j < LENGTH(gbuttons); ++j) - { XCBUngrabButton(_wm.dpy, gbuttons[j], modifiers[i], c->win); - } - for(j = 0; j < LENGTH(buttons); ++j) - { XCBUngrabButton(_wm.dpy, buttons[j].button, modifiers[i], c->win); - } - } - if (!focused) - { - /* grab focus buttons */ - for (i = 0; i < LENGTH(gbuttons); ++i) - { - for (j = 0; j < LENGTH(modifiers); ++j) - { XCBGrabButton(_wm.dpy, gbuttons[i], modifiers[j], c->win, False, BUTTONMASK, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC, XCB_NONE, XCB_NONE); - } - } - } - for (i = 0; i < LENGTH(buttons); ++i) - { - for (j = 0; j < LENGTH(modifiers); ++j) - { - XCBGrabButton(_wm.dpy, buttons[i].button, - buttons[i].mask | modifiers[j], - c->win, False, BUTTONMASK, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_SYNC, - XCB_NONE, XCB_NONE); - } - } - xcb_ungrab_server(_wm.dpy); -} - -void -grabkeys(void) -{ - u32 i, j, k; - u32 modifiers[4] = { 0, XCB_MOD_MASK_LOCK, _wm.numlockmask, _wm.numlockmask|XCB_MOD_MASK_LOCK }; - XCBKeyCode *keycodes[LENGTH(keys)]; - XCBUngrabKey(_wm.dpy, XCB_GRAB_ANY, XCB_MOD_MASK_ANY, _wm.root); - - /* This grabs all the keys */ - for(i = 0; i < LENGTH(keys); ++i) - { keycodes[i] = XCBKeySymbolsGetKeyCode(_wm.syms, keys[i].keysym); - } - for(i = 0; i < LENGTH(keys); ++i) - { - for(j = 0; keycodes[i][j] != XCB_NO_SYMBOL; ++j) - { - if(keys[i].keysym == XCBKeySymbolsGetKeySym(_wm.syms, keycodes[i][j], 0)) - { - for(k = 0; k < LENGTH(modifiers); ++k) - { - XCBGrabKey(_wm.dpy, - keycodes[i][j], keys[i].mod | modifiers[k], - _wm.root, True, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - } - } - } - } - - for(i = 0; i < LENGTH(keys); ++i) - { free(keycodes[i]); - } -} - void grid(Desktop *desk) { @@ -1580,325 +1061,6 @@ grid(Desktop *desk) } } -void -killclient(Client *c, enum KillType type) -{ - if(!c) - { return; - } - if(HASWMSAVEYOURSELF(c)) - { sendprotocolevent(c, wmatom[WMSaveYourself]); - } - if(HASWMDELETEWINDOW(c)) - { sendprotocolevent(c, wmatom[WMDeleteWindow]); - } - else - { - Monitor *m = c->desktop->mon; - XCBWindow win = c->win; - XCBUnmapNotifyEvent ev; - XCBCookie seq; - switch(type) - { - case Graceful: - seq = XCBKillClient(_wm.dpy, win); - break; - case Safedestroy: - /* TODO */ - seq = XCBKillClient(_wm.dpy, win); - break; - case Destroy: - seq = XCBDestroyWindow(_wm.dpy, win); - break; - default: - seq = XCBKillClient(_wm.dpy, win); - break; - } - /* let event handler handle this */ - ev.from_configure = 0; - ev.response_type = XCB_UNMAP_NOTIFY; - ev.event = _wm.root; - ev.window = win; - ev.sequence = seq.sequence + 1; - ev.pad0 = 0; - ev.pad1[0] = 0; - ev.pad1[1] = 0; - ev.pad1[2] = 0; - XCBSendEvent(_wm.dpy, _wm.root, 0, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)&ev); - } -} - -void -managerequest(XCBWindow win, XCBCookie requests[ManageCookieLAST]) -{ - 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; - const u8 MOTIF_WM_HINT_LENGTH = 5; - - /* Window Attributes */ - requests[ManageCookieAttributes] = - XCBGetWindowAttributesCookie(_wm.dpy, win); - /* Window Geometry */ - requests[ManageCookieGeometry] = - XCBGetWindowGeometryCookie(_wm.dpy, win); - /* Window Transient */ - requests[ManageCookieTransient] = - XCBGetTransientForHintCookie(_wm.dpy, win); - /* Window Type(s) */ - requests[ManageCookieWType] = - XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMWindowType], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); - /* Window State(s) */ - requests[ManageCookieWState] = - XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMState], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); - /* Window Size Hints */ - requests[ManageCookieSizeHint] = - XCBGetWMNormalHintsCookie(_wm.dpy, win); - /* Window WM Hints */ - requests[ManageCookieWMHints] = - XCBGetWMHintsCookie(_wm.dpy, win); - /* Window Class/Instance */ - requests[ManageCookieClass] = - XCBGetWMClassCookie(_wm.dpy, win); - /* Window WM Protocol(s) */ - requests[ManageCookieWMProtocol] = - XCBGetWMProtocolsCookie(_wm.dpy, win, wmatom[WMProtocols]); - /* Window Strut */ - requests[ManageCookieStrut] = - XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMStrut], NO_BYTE_OFFSET, STRUT_LENGTH, False, XCB_ATOM_CARDINAL); - /* Window StrutP */ - requests[ManageCookieStrutP] = - XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMStrutPartial], NO_BYTE_OFFSET, STRUT_P_LENGTH, False, XCB_ATOM_CARDINAL); - /* Window NetWMName */ - requests[ManageCookieNetWMName] = - XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMName], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, netatom[NetUtf8String]); - /* Window WMName */ - requests[ManageCookieWMName] = - XCBGetWindowPropertyCookie(_wm.dpy, win, XCB_ATOM_WM_NAME, NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_STRING); - /* Window Pid */ - requests[ManageCookiePid] = - XCBGetPidCookie(_wm.dpy, win, netatom[NetWMPid]); - /* Window Icon */ - requests[ManageCookieIcon] = - XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMIcon], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_CARDINAL); - /* Window Motif */ - requests[ManageCookieMotif] = - XCBGetWindowPropertyCookie(_wm.dpy, win, motifatom, NO_BYTE_OFFSET, MOTIF_WM_HINT_LENGTH, False, motifatom); -} - -Client * -managereply(XCBWindow win, XCBCookie requests[ManageCookieLAST]) -{ - /* checks */ - if(win == _wm.root) - { DEBUG("%s", "Cannot manage() root window."); - return NULL; - } - else if(wintoclient(win)) - { DEBUG("Window already managed????: [%u]", win); - return NULL; - } - - const u16 bw = 0; - const u32 bcol = 0; - const u8 showdecor = 1; - - Monitor *m = NULL; - Client *c = NULL; - XCBWindow trans = 0; - u8 transstatus = 0; - const u32 inputmask = XCB_EVENT_MASK_ENTER_WINDOW|XCB_EVENT_MASK_FOCUS_CHANGE|XCB_EVENT_MASK_PROPERTY_CHANGE|XCB_EVENT_MASK_STRUCTURE_NOTIFY; - XCBWindowGeometry *wg = NULL; - - XCBGetWindowAttributes *waattributes = NULL; - XCBWindowProperty *wtypeunused = NULL; - XCBWindowProperty *stateunused = NULL; - XCBSizeHints hints; - u8 hintstatus = 0; - XCBWMHints *wmh = NULL; - XCBWMClass cls = { ._reply = NULL }; - u8 clsstatus = 0; - XCBWMProtocols wmprotocols = { ._reply = NULL, .atoms_len = 0 }; - u8 wmprotocolsstatus = 0; - XCBWindowProperty *strutpreply = NULL; - XCBWindowProperty *strutreply = NULL; - u32 *strutp = NULL; - u32 *strut = NULL; - XCBWindowProperty *netwmnamereply = NULL; - XCBWindowProperty *wmnamereply = NULL; - char *netwmname = NULL; - char *wmname = NULL; - XCBWindowProperty *iconreply = NULL; - pid_t pid = 0; - XCBWindowProperty *motifreply = NULL; - - /* we do it here before, because we are waiting for replies and for more memory. */ - c = createclient(); - - /* wait for replies */ - waattributes = XCBGetWindowAttributesReply(_wm.dpy, requests[ManageCookieAttributes]); - wg = XCBGetWindowGeometryReply(_wm.dpy, requests[ManageCookieGeometry]); - transstatus = XCBGetTransientForHintReply(_wm.dpy, requests[ManageCookieTransient], &trans); trans *= !!transstatus; - wtypeunused = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieWType]); - stateunused = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieWState]); - hintstatus = XCBGetWMNormalHintsReply(_wm.dpy, requests[ManageCookieSizeHint], &hints); - wmh = XCBGetWMHintsReply(_wm.dpy, requests[ManageCookieWMHints]); - clsstatus = XCBGetWMClassReply(_wm.dpy, requests[ManageCookieClass], &cls); - wmprotocolsstatus = XCBGetWMProtocolsReply(_wm.dpy, requests[ManageCookieWMProtocol], &wmprotocols); - strutreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieStrut]); - strutpreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieStrutP]); - netwmnamereply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieNetWMName]); - wmnamereply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieWMName]); - iconreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieIcon]); - pid = XCBGetPidReply(_wm.dpy, requests[ManageCookiePid]); - motifreply = XCBGetWindowPropertyReply(_wm.dpy, requests[ManageCookieMotif]); - - strutp = strutpreply ? XCBGetWindowPropertyValue(strutpreply) : NULL; - strut = strutreply ? XCBGetWindowPropertyValue(strutpreply) : NULL; - - if(!c) - { goto FAILURE; - } - c->win = win; - - /* On Failure clear flag and ignore hints */ - hints.flags *= !!hintstatus; - - if(waattributes && waattributes->override_redirect) - { DEBUG("Override Redirect: [%d]", win); - /* theoredically we could manage these but they are a hastle to deal with */ - goto FAILURE; - } - - /* this sets up the desktop which is quite important for some operations */ - clientinittrans(c, trans); - - clientinitgeom(c, wg); - clientinitwtype(c, wtypeunused); - clientinitwstate(c, stateunused); - updatewindowprotocol(c, wmprotocolsstatus ? &wmprotocols : NULL); - getnamefromreply(netwmnamereply, &netwmname); - getnamefromreply(wmnamereply, &wmname); - setfloating(c, !!trans); - /* Custom stuff */ - setclientpid(c, pid); - setborderwidth(c, bw); - setbordercolor32(c, bcol); - setshowdecor(c, showdecor); - updatetitle(c, netwmname, wmname); - updatesizehints(c, &hints); - if(clsstatus) - { updateclass(c, &cls); - } - updatewmhints(c, wmh); - updatemotifhints(c, motifreply); - updateicon(c, iconreply); - XCBSelectInput(_wm.dpy, win, inputmask); - grabbuttons(c, 0); - - m = c->desktop->mon; - - attach(c); - attachstack(c); - attachfocus(c); - - updateclientlist(win, ClientListAdd); - setclientstate(c, XCB_WINDOW_NORMAL_STATE); - - HASH_ADD_INT(m->__hash, win, c); - - if(DOCKEDINITIAL(c)) - { - if(ISFLOATING(c)) - { setfloating(c, 0); - } - } - else - { - /* some windows (like st) dont mean to be "floating" but rather are a side effect of their own calculation(s), - * So we check if its in the corner, and assume its not meant to be floating. - */ - if((c->x == m->wx && c->y == m->wy) || (c->x == m->mx && c->y == m->my)) - { - if(ISFLOATING(c)) - { setfloating(c, 0); - } - } - /* else its some sort of popup and just leave floating */ - else - { - if(!ISFLOATING(c)) - { setfloating(c, 1); - } - } - } - /* inherit previous client state */ - if(c->desktop && c->desktop->sel) - { setfullscreen(c, ISFULLSCREEN(c->desktop->sel) || ISFULLSCREEN(c)); - } - - /* propagates border_width, if size doesn't change */ - configure(c); - - /* if its a new bar we dont want to return it as the monitor now manages it */ - if(!checknewbar(m, c, strut || strutp)) - { c = NULL; - } - goto CLEANUP; -FAILURE: - free(c); - c = NULL; - goto CLEANUP; -CLEANUP: - /* reply cleanup */ - free(waattributes); - free(wmh); - free(stateunused); - free(wtypeunused); - free(wg); - XCBWipeGetWMClass(&cls); - XCBWipeGetWMProtocols(&wmprotocols); - free(strutpreply); - free(strutreply); - free(netwmnamereply); - free(wmnamereply); - /* maybe no or just memcpy the first icon into a buffer and keep the thing just there. */ - free(iconreply); - return c; -} - -void -maximize(Client *c) -{ - maximizehorz(c); - maximizevert(c); - DEBUG("Maximized: %u", c->win); -} - -void -maximizehorz(Client *c) -{ - const Monitor *m = c->desktop->mon; - const i16 x = m->wx; - const i16 y = c->y; - const u16 w = m->ww - (WIDTH(c) - c->w); - const u16 h = c->h; - resize(c, x, y, w, h, 0); -} - -void -maximizevert(Client *c) -{ - const Monitor *m = c->desktop->mon; - const i16 x = c->x; - const i16 y = m->my; - const u16 w = c->w; - const u16 h = m->wh - (HEIGHT(c) - c->h); - resize(c, x, y, w, h, 0); -} - - void monocle(Desktop *desk) { @@ -1916,12 +1078,6 @@ monocle(Desktop *desk) } } -Client * -nextclient(Client *c) -{ - return c ? c->next : c; -} - Desktop * nextdesktop(Desktop *desk) { @@ -1934,86 +1090,21 @@ nextmonitor(Monitor *m) return m ? m->next : m; } -Client * -nextstack(Client *c) +Desktop * +prevdesktop(Desktop *desk) { - return c ? c->snext : c; + return desk ? desk->prev : desk; } -Client * -nextrstack(Client *c) +void +quit(void) { - return c ? c->rnext : c; + _wm.running = 0; + wakeupconnection(_wm.dpy, _wm.screen); } -Client * -nextfocus(Client *c) -{ - return c ? c->fnext : c; -} - -Client * -nexttiled(Client *c) -{ - for(; c && (ISFLOATING(c) || !ISVISIBLE(c)); c = nextstack(c)); - return c; -} - -Client * -nextvisible(Client *c) -{ - for(; c && !ISVISIBLE(c); c = c->next); - return c; -} - -Desktop * -prevdesktop(Desktop *desk) -{ - return desk ? desk->prev : desk; -} - -Client * -prevclient(Client *c) -{ - return c ? c->prev : c; -} - -Client * -prevfocus(Client *c) -{ - return c ? c->fprev : c; -} - -Client * -prevstack(Client *c) -{ - return c ? c->sprev : c; -} - -Client * -prevrstack(Client *c) -{ - return c ? c->rprev : c; -} - -Client * -prevvisible(Client *c) -{ - while(c && !ISVISIBLE(c)) - { c = prevclient(c); - } - return c; -} - -void -quit(void) -{ - _wm.running = 0; - wakeupconnection(_wm.dpy, _wm.screen); -} - -static u8 -_restore_parser(FILE *file, char *buffer, u16 bufflen) +static u8 +_restore_parser(FILE *file, char *buffer, u16 bufflen) { char *newline = NULL; const u8 success = 0; @@ -2428,67 +1519,6 @@ recttomon(i16 x, i16 y, u16 w, u16 h) return r; } -void -resize(Client *c, i32 x, i32 y, i32 width, i32 height, uint8_t interact) -{ - if(applysizehints(c, &x, &y, &width, &height, interact)) - { resizeclient(c, x, y, width, height); - } -} - -void -resizeclient(Client *c, int16_t x, int16_t y, uint16_t width, uint16_t height) -{ - u32 mask = 0; - - if(c->x != x) - { - c->oldx = c->x; - c->x = x; - mask |= XCB_CONFIG_WINDOW_X; - } - if(c->y != y) - { - c->oldy = c->y; - c->y = y; - mask |= XCB_CONFIG_WINDOW_Y; - } - if(c->w != width) - { - c->oldw = c->w; - c->w = width; - mask |= XCB_CONFIG_WINDOW_WIDTH; - } - if(c->h != height) - { - c->oldh = c->h; - c->h = height; - mask |= XCB_CONFIG_WINDOW_HEIGHT; - } - - XCBWindowChanges changes = - { - .x = x, - .y = y, - .width = width, - .height = height, - }; - - /* Process resize requests only to visible clients as to. 1.) Save resources, no need to handle non visible windows. - * 2.) Incase that the window does get visible make it not appear to be movable (different desktop). - * 3.) Prevent the window from moving itself back into view, when it should be hidden. - * 4.) Incase a window does want focus, we switch to that desktop respectively and let showhide() do the work. - */ - if(ISVISIBLE(c)) - { - if(mask) - { XCBConfigureWindow(_wm.dpy, c->win, mask, &changes); - } - } - configure(c); -} - - void restack(Desktop *desk) { @@ -2801,19 +1831,6 @@ scan(void) /* arrangemons(); */ } -void -sendprotocolevent(Client *c, XCBAtom proto) -{ - XCBClientMessageEvent ev; - ev.type = wmatom[WMProtocols]; - ev.response_type = XCB_CLIENT_MESSAGE; - ev.window = c->win; - ev.format = 32; - ev.data.data32[0] = proto; - ev.data.data32[1] = XCB_CURRENT_TIME; - XCBSendEvent(_wm.dpy, c->win, False, XCB_NONE, (const char *)&ev); -} - void sendmon(Client *c, Monitor *m) { @@ -2830,220 +1847,6 @@ sendmon(Client *c, Monitor *m) /* arrangeall() */ } -void -setalwaysontop(Client *c, u8 state) -{ - SETFLAG(c->wstateflags, _STATE_ABOVE, !!state); -} - -void -setalwaysonbottom(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_BELOW, !!state); -} - -void -setborderalpha(Client *c, uint8_t alpha) -{ - /* remove previous alpha */ - const u32 ccol = c->bcol & ~(UINT8_MAX << 24); - const u32 col = ccol + (alpha << 24); - /* TODO */ - setbordercolor32(c, col); -} - -void -setbordercolor(Client *c, uint8_t red, uint8_t green, uint8_t blue) -{ - /* get alpha */ - const u32 alpha = c->bcol & (UINT8_MAX << 24); - - const u32 col = blue + (green << 8) + (red << 16) + alpha; - setbordercolor32(c, col); -} - -void -setbordercolor32(Client *c, uint32_t col) -{ - c->bcol = col; - XCBSetWindowBorder(_wm.dpy, c->win, c->bcol); -} - -void -setborderwidth(Client *c, uint16_t border_width) -{ - if(!DISABLEBORDER(c)) - { - c->oldbw = c->bw; - c->bw = border_width; - XCBSetWindowBorderWidth(_wm.dpy, c->win, c->bw); - configure(c); - } -} - -void -setclientdesktop(Client *c, Desktop *desk) -{ - detachcompletely(c); - c->desktop = desk; - attach(c); - attachstack(c); - attachfocus(c); -} - -void -setclientstate(Client *c, u8 state) -{ - /* Due to windows only having 1 map state we can set this without needing to replace other data */ - const i32 data[2] = { state, XCB_NONE }; - XCBChangeProperty(_wm.dpy, c->win, wmatom[WMState], wmatom[WMState], 32, XCB_PROP_MODE_REPLACE, (unsigned char *)data, 2); -} - -void -setclientwtype(Client *c, XCBAtom atom, u8 state) -{ - /* TODO manage race conditions without needing to lock the server */ - const u8 _delete = !state; - const XCBWindow win = c->win; - const u32 NO_BYTE_OFFSET = 0L; - const u32 REQUEST_MAX_NEEDED_ITEMS = UINT32_MAX; - - XCBCookie cookie = XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMWindowType], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); - XCBWindowProperty *prop = XCBGetWindowPropertyReply(_wm.dpy, cookie); - void *data = NULL; - u32 len = 0; - u32 propmode = XCB_PROP_MODE_REPLACE; - if(prop) - { - XCBAtom *atoms = XCBGetPropertyValue(prop); - const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(prop, sizeof(XCBAtom)); - - u32 i; - u32 offset = 0; - u8 set = 0; - for(i = 0; i < ATOM_LENGTH; ++i) - { - if(atoms[i] == atom) - { - offset = i; - set = 1; - break; - } - } - - if(set) - { - if(_delete) - { - for(i = offset; i < ATOM_LENGTH - 1; ++i) - { atoms[i] = atoms[i + 1]; - } - data = atoms; - len = ATOM_LENGTH - 1; - } - else /* atom already exists do nothing */ - { - free(prop); - return; - } - } - else - { - if(_delete) /* prop not found mark as already deleted */ - { - free(prop); - return; - } - else /* set propmode to append cause we didnt find it */ - { - propmode = XCB_PROP_MODE_APPEND; - len = 1; - data = &atom; - } - } - } - else - { - len = 1; - data = &atom; - } - XCBChangeProperty(_wm.dpy, win, netatom[NetWMWindowType], XCB_ATOM_ATOM, 32, propmode, (const char *)data, len); -} - -void -setclientnetstate(Client *c, XCBAtom atom, u8 state) -{ - /* TODO manage race conditions without needing to lock the server */ - const u8 _delete = !state; - const XCBWindow win = c->win; - const u32 NO_BYTE_OFFSET = 0L; - const u32 REQUEST_MAX_NEEDED_ITEMS = UINT32_MAX; - - XCBCookie cookie = XCBGetWindowPropertyCookie(_wm.dpy, win, netatom[NetWMState], NO_BYTE_OFFSET, REQUEST_MAX_NEEDED_ITEMS, False, XCB_ATOM_ATOM); - XCBWindowProperty *prop = XCBGetWindowPropertyReply(_wm.dpy, cookie); - void *data = NULL; - u32 len = 0; - u32 propmode = XCB_PROP_MODE_REPLACE; - if(prop) - { - XCBAtom *atoms = XCBGetPropertyValue(prop); - const uint32_t ATOM_LENGTH = XCBGetPropertyValueLength(prop, sizeof(XCBAtom)); - - u32 i; - u32 offset = 0; - u8 set = 0; - for(i = 0; i < ATOM_LENGTH; ++i) - { - if(atoms[i] == atom) - { - offset = i; - set = 1; - break; - } - } - - if(set) - { - if(_delete) - { - /* this gets optimized to memmove, cool! - * GCC v14.1.1 -Ou - */ - for(i = offset; i < ATOM_LENGTH - 1; ++i) - { atoms[i] = atoms[i + 1]; - } - data = atoms; - len = ATOM_LENGTH - 1; - } - else /* atom already exists do nothing */ - { - free(prop); - return; - } - } - else - { - if(_delete) /* prop not found mark as already deleted */ - { - free(prop); - return; - } - else /* set propmode to append cause we didnt find it */ - { - propmode = XCB_PROP_MODE_APPEND; - len = 1; - data = &atom; - } - } - } - else - { - len = 1; - data = &atom; - } - XCBChangeProperty(_wm.dpy, win, netatom[NetWMState], XCB_ATOM_ATOM, 32, propmode, (const char *)data, len); -} - void setdesktopcount(Monitor *m, uint16_t desktops) { @@ -3135,341 +1938,77 @@ setdesktopsel(Monitor *mon, Desktop *desksel) } void -setdisableborder(Client *c, uint8_t state) +setup(void) { - SETFLAG(c->flags, _FSTATE_DISABLE_BORDER, !!state); -} + /* clean up any zombies immediately */ + sighandler(); -void -setclientpid(Client *c, pid_t pid) -{ - c->pid = pid; -} + /* startup wm */ + _wm.running = 1; + _wm.syms = XCBKeySymbolsAlloc(_wm.dpy); + _wm.sw = XCBDisplayWidth(_wm.dpy, _wm.screen); + _wm.sh = XCBDisplayHeight(_wm.dpy, _wm.screen); + _wm.root = XCBRootWindow(_wm.dpy, _wm.screen); + /* Most java apps require this see: + * https://wiki.archlinux.org/title/Java#Impersonate_another_window_manager + * https://wiki.archlinux.org/title/Java#Gray_window,_applications_not_resizing_with_WM,_menus_immediately_closing + * for more information. + * "Hard coded" window managers to ignore "Write Once, Debug Everywhere" + * This fixes java apps just having a blank white screen on some screen instances. + * One example is Ghidra, made by the CIA. + */ + _wm.wmname = "LG3D"; -void -setwtypedesktop(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_DESKTOP, !!state); -} + if(!_wm.syms) + { + cleanup(); + DIECAT("%s", "Could not establish connection with keyboard (OutOfMemory)"); + } + /* finds any monitor's */ + updategeom(); -void -setwtypedialog(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_DIALOG, !!state); -} + setupatoms(); + setupcursors(); + setupcfg(); + /* 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); + XCBChangeProperty(_wm.dpy, _wm.wmcheckwin, netatom[NetSupportingWMCheck], XCB_ATOM_WINDOW, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&_wm.wmcheckwin, 1); + XCBChangeProperty(_wm.dpy, _wm.wmcheckwin, netatom[NetWMName], netatom[NetUtf8String], 8, XCB_PROP_MODE_REPLACE, _wm.wmname, strlen(_wm.wmname) + 1); + XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupportingWMCheck], XCB_ATOM_WINDOW, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&_wm.wmcheckwin, 1); + /* EWMH support per view */ + XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&netatom, NetLast); + XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_APPEND, (unsigned char *)&wmatom, WMLast); + XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_APPEND, (unsigned char *)>katom, GTKLAST); + XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_APPEND, (unsigned char *)&motifatom, 1); -void -setwtypedock(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_DOCK, !!state); -} + XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetClientList]); + + updatedesktopnum(); + updatedesktop(); + updatedesktopnames(); + updateviewport(); -void -setwtypetoolbar(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_TOOLBAR, !!state); -} - -void -setwtypemenu(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_MENU, !!state); -} - -void -setwtypeneverfocus(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_NEVERFOCUS, !!state); -} - - -void -setwtypeutility(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_UTILITY, !!state); -} - -void -setwtypesplash(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_SPLASH, !!state); -} - -void -setwtypedropdownmenu(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_DROPDOWN_MENU, !!state); -} - -void -setwtypepopupmenu(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_POPUP_MENU, !!state); -} - -void -setwtypetooltip(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_TOOLTIP, !!state); -} - -void -setwtypenotification(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_NOTIFICATION, !!state); -} - -void -setwtypecombo(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_COMBO, !!state); -} - -void -setwtypednd(Client *c, uint8_t state) -{ - SETFLAG(c->wtypeflags, _TYPE_DND, !!state); -} - -void -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) -{ - SETFLAG(c->wstateflags, _STATE_SUPPORTED_WM_TAKE_FOCUS, !!state); -} - -void -setwmsaveyourself(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_SUPPORTED_WM_SAVE_YOURSELF, !!state); -} - -void -setwmdeletewindow(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_SUPPORTED_WM_DELETE_WINDOW, !!state); -} - -void -setskippager(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_SKIP_PAGER, !!state); -} - -void -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) -{ - Monitor *m = c->desktop->mon; - if(state && !ISFULLSCREEN(c)) - { - setclientnetstate(c, netatom[NetWMStateFullscreen], 1); - setborderwidth(c, c->bw); - setborderwidth(c, 0); - resizeclient(c, m->mx, m->wy, m->mw, m->mh); - XCBRaiseWindow(_wm.dpy, c->win); - } - else if(!state && ISFULLSCREEN(c)) - { - setclientnetstate(c, netatom[NetWMStateFullscreen], 0); - setborderwidth(c, c->oldbw); - resizeclient(c, c->oldx, c->oldy, c->oldw, c->oldh); - } - 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) -{ - if(!NEVERFOCUS(c)) - { - XCBSetInputFocus(_wm.dpy, c->win, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); - XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow], XCB_ATOM_WINDOW, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&(c->win), 1); - SETFLAG(c->wstateflags, _STATE_FOCUSED, 1); - } - if(HASWMTAKEFOCUS(c)) - { sendprotocolevent(c, wmatom[WMTakeFocus]); - } -} - -void -sethidden(Client *c, uint8_t state) -{ - if(state) - { - setclientstate(c, XCB_WINDOW_ICONIC_STATE); - setwtypemapiconic(c, 1); - } - else - { - setclientstate(c, XCB_WINDOW_NORMAL_STATE); - setwtypemapnormal(c, 1); - } - SETFLAG(c->wstateflags, _STATE_HIDDEN, !!state); -} - -void -setkeepfocus(Client *c, uint8_t state) -{ - SETFLAG(c->flags, _FSTATE_KEEP_FOCUS, !!state); -} -void -setmaximizedvert(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_MAXIMIZED_VERT, !!state); -} - -void -setmaximizedhorz(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_MAXIMIZED_HORZ, !!state); -} - -void -setshaded(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_SHADED, !!state); -} - -/* TODO: HERE */ - -void -setmodal(Client *c, uint8_t state) -{ - SETFLAG(c->wstateflags, _STATE_MODAL, !!state); -} - -void -setoverrideredirect(Client *c, uint8_t state) -{ - SETFLAG(c->flags, _FSTATE_OVERRIDE_REDIRECT, !!state); -} - -void -setsticky(Client *c, u8 state) -{ - SETFLAG(c->wstateflags, _STATE_STICKY, !!state); -} - -void -setup(void) -{ - /* clean up any zombies immediately */ - sighandler(); - - /* startup wm */ - _wm.running = 1; - _wm.syms = XCBKeySymbolsAlloc(_wm.dpy); - _wm.sw = XCBDisplayWidth(_wm.dpy, _wm.screen); - _wm.sh = XCBDisplayHeight(_wm.dpy, _wm.screen); - _wm.root = XCBRootWindow(_wm.dpy, _wm.screen); - /* Most java apps require this see: - * https://wiki.archlinux.org/title/Java#Impersonate_another_window_manager - * https://wiki.archlinux.org/title/Java#Gray_window,_applications_not_resizing_with_WM,_menus_immediately_closing - * for more information. - * "Hard coded" window managers to ignore "Write Once, Debug Everywhere" - * This fixes java apps just having a blank white screen on some screen instances. - * One example is Ghidra, made by the CIA. - */ - _wm.wmname = "LG3D"; - - if(!_wm.syms) - { - cleanup(); - DIECAT("%s", "Could not establish connection with keyboard (OutOfMemory)"); - } - /* finds any monitor's */ - updategeom(); - - setupatoms(); - setupcursors(); - setupcfg(); - /* 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); - XCBChangeProperty(_wm.dpy, _wm.wmcheckwin, netatom[NetSupportingWMCheck], XCB_ATOM_WINDOW, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&_wm.wmcheckwin, 1); - XCBChangeProperty(_wm.dpy, _wm.wmcheckwin, netatom[NetWMName], netatom[NetUtf8String], 8, XCB_PROP_MODE_REPLACE, _wm.wmname, strlen(_wm.wmname) + 1); - XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupportingWMCheck], XCB_ATOM_WINDOW, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&_wm.wmcheckwin, 1); - /* EWMH support per view */ - XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&netatom, NetLast); - XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_APPEND, (unsigned char *)&wmatom, WMLast); - XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_APPEND, (unsigned char *)>katom, GTKLAST); - XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetSupported], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_APPEND, (unsigned char *)&motifatom, 1); - - XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetClientList]); - - updatedesktopnum(); - updatedesktop(); - updatedesktopnames(); - updateviewport(); - - 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_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|XCB_CW_CURSOR, &wa); - XCBSelectInput(_wm.dpy, _wm.root, wa.event_mask); - /* init numlock */ - updatenumlockmask(); - grabkeys(); - focus(NULL); + 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_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|XCB_CW_CURSOR, &wa); + XCBSelectInput(_wm.dpy, _wm.root, wa.event_mask); + /* init numlock */ + updatenumlockmask(); + grabkeys(); + focus(NULL); } void @@ -3575,28 +2114,6 @@ setupcfgdefaults(void) bs->bottom.y = 1.0f - bs->bottom.h; } -void -seturgent(Client *c, uint8_t state) -{ - XCBCookie wmhcookie = XCBGetWMHintsCookie(_wm.dpy, c->win); - XCBWMHints *wmh = XCBGetWMHintsReply(_wm.dpy, wmhcookie); - SETFLAG(c->wstateflags, _STATE_DEMANDS_ATTENTION, !!state); - if(state) - { /* set window border */ - } - else - { /* set window border */ - } - - if(wmh) - { - wmh->flags = state ? (wmh->flags | XCB_WM_HINT_URGENCY) : (wmh->flags & ~XCB_WM_HINT_URGENCY); - XCBSetWMHintsCookie(_wm.dpy, c->win, wmh); - free(wmh); - } - /* drawbar */ -} - void updatedesktop(void) { @@ -3624,21 +2141,6 @@ updateviewport(void) XCBChangeProperty(_wm.dpy, _wm.root, netatom[NetDesktopViewport], XCB_ATOM_CARDINAL, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)data, 2); } - -inline void -showhide(Client *c, const int show) -{ - const Monitor *m = c->desktop->mon; - if(show) - { XCBMoveResizeWindow(_wm.dpy, c->win, c->x, c->y, c->w, c->h); - } - else - { - const i16 x = -c->w - m->mx; - XCBMoveResizeWindow(_wm.dpy, c->win, x, c->y, c->w, c->h); - } -} - void sigchld(int signo) /* signal */ { @@ -3955,23 +2457,6 @@ tile(Desktop *desk) } } - -void -unfocus(Client *c, uint8_t setfocus) -{ - if(!c) - { return; - } - grabbuttons(c, 0); - XCBSetWindowBorder(_wm.dpy, c->win, c->bcol); - if(setfocus) - { - XCBSetInputFocus(_wm.dpy, _wm.root, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); - XCBDeleteProperty(_wm.dpy, _wm.root, netatom[NetActiveWindow]); - } - SETFLAG(c->wstateflags, _STATE_FOCUSED, 0); -} - #ifdef XINERAMA static int isuniquegeom(XCBXineramaScreenInfo *unique, size_t n, XCBXineramaScreenInfo *info) @@ -4112,103 +2597,15 @@ updategeom(void) } void -updateicon(Client *c, XCBWindowProperty *iconprop) -{ - free(c->icon); - c->icon = geticonprop(iconprop); -} - -void -unmanage(Client *c, uint8_t destroyed) +updatebarpos(Monitor *m) { - if(!c) - { return; - } - Desktop *desk = c->desktop; - const XCBWindow win = c->win; - - if(desk->mon->bar == c) - { desk->mon->bar = NULL; - } - if(!destroyed) - { - /* TODO causes alot of errors for some reason even if its not "destroyed" */ - } - /* TODO - * Memory leak if a client is unmaped and maped again - * (cause we would get the same input focus twice) - */ - HASH_DEL(desk->mon->__hash, c); - detachcompletely(c); - updateclientlist(win, ClientListRemove); - /* no need to arrange fully cause client is not mapped anymore */ - arrange(desk); - cleanupclient(c); - DEBUG("Unmanaged: [%u]", win); -} - -void -unmaximize(Client *c) -{ - unmaximizevert(c); - unmaximizehorz(c); - DEBUG("Umaximized: [%u]", c->win); -} - -void -unmaximizehorz(Client *c) -{ - const i16 x = c->oldx; - const i16 y = c->y; - const u16 w = c->oldw; - const u16 h = c->h; - - if(DOCKEDHORZ(c)) - { - /* if never maximized */ - if(WASDOCKEDHORZ(c)) - { resize(c, x / 2, y, w / 2, h, 0); - } - else - { resize(c, x, y, w, h, 0); - } - } - else - { DEBUG("Client already unmaxed horz: [%u]", c->win); - } -} - -void -unmaximizevert(Client *c) -{ - const i16 x = c->x; - const i16 y = c->oldy; - const u16 w = c->w; - const u16 h = c->oldh; - if(DOCKEDVERT(c)) - { - if(WASDOCKEDVERT(c)) - { resize(c, x, y / 2, w, h / 2, 0); - } - else - { resize(c, x, y, w, h, 0); - } - } - else - { DEBUG("Client already unmaxed vert: [%u]", c->win); - } -} - -void -updatebarpos(Monitor *m) -{ - /* reset space */ - m->ww = m->mw; - m->wh = m->mh; - m->wx = m->mx; - m->wy = m->my; - Client *bar = m->bar; - if(!bar) + /* reset space */ + m->ww = m->mw; + m->wh = m->mh; + m->wx = m->mx; + m->wy = m->my; + Client *bar = m->bar; + if(!bar) { return; } enum BarSides side = GETBARSIDE(m, bar, 0); @@ -4385,41 +2782,6 @@ updatebargeom(Monitor *m) } } -void -updateclass(Client *c, XCBWMClass *_class) -{ - const u32 MAX_LEN = 1024; - if(_class) - { - if(_class->class_name) - { - const u32 CLASS_NAME_LEN = strnlen(_class->class_name, MAX_LEN) + 1; - const size_t CLASS_NAME_SIZE = sizeof(char) * CLASS_NAME_LEN; - char *clsname = malloc(CLASS_NAME_SIZE); - if(clsname) - { - memcpy(clsname, _class->class_name, CLASS_NAME_SIZE - sizeof(char)); - clsname[CLASS_NAME_LEN - 1] = '\0'; - free(c->classname); - c->classname = clsname; - } - } - if(_class->instance_name) - { - const u32 INSTANCE_NAME_LEN = strnlen(_class->instance_name, MAX_LEN) + 1; - const size_t INSTANCE_NAME_SIZE = sizeof(char) * INSTANCE_NAME_LEN; - char *iname = malloc(INSTANCE_NAME_SIZE); - if(iname) - { - memcpy(iname, _class->instance_name, INSTANCE_NAME_SIZE - sizeof(char)); - iname[INSTANCE_NAME_LEN - 1] = '\0'; - free(c->instancename); - c->instancename = iname; - } - } - } -} - void updateclientlist(XCBWindow win, uint8_t type) { @@ -4449,157 +2811,6 @@ updateclientlist(XCBWindow win, uint8_t type) } } - -static void -__update_motif_decor(Client *c, uint32_t hints) -{ - /* bit definitions for MwmHints.decorations */ - const u32 DECOR_ALL = 1 << 0; - const u32 DECOR_BORDER = 1 << 1; - const u32 DECOR_RESIZEH = 1 << 2; - const u32 DECOR_TITLE = 1 << 3; - const u32 DECOR_MENU = 1 << 4; - const u32 DECOR_MINIMIZE = 1 << 5; - const u32 DECOR_MAXIMIZE = 1 << 6; - if(hints & DECOR_ALL) - { hints |= (uint32_t)~0; - } - - if(hints & DECOR_BORDER) - { setborderwidth(c, c->oldbw); - } - else - { - setdisableborder(c, 0); - setborderwidth(c, 0); - setdisableborder(c, 1); - } - if(hints & DECOR_RESIZEH) - { - /* NOP */ - ASSUME(0); - } - if(hints & DECOR_TITLE) - { setshowdecor(c, 1); - } - else - { setshowdecor(c, 0); - } - if(hints & DECOR_MENU) - { - /* NOP */ - ASSUME(0); - } - if(hints & DECOR_MINIMIZE || hints & DECOR_MAXIMIZE) - { - /* NOP */ - ASSUME(0); - } -} - -static void __update_motif_func(Client *c, int32_t hints) -{ - /* bit definitions for MwmHints.functions */ - const u32 FUNCS_ALL = 1 << 0; - const u32 FUNCS_RESIZE = 1 << 1; - const u32 FUNCS_MOVE = 1 << 2; - const u32 FUNCS_MINIMIZE = 1 << 3; - const u32 FUNCS_MAXIMIZE = 1 << 4; - const u32 FUNCS_CLOSE = 1 << 5; - - if(hints & FUNCS_ALL) - { hints |= (int32_t)~0; - } - - if(hints & FUNCS_RESIZE) - { /* NOP */ - } - else - { /* IDK set fixed or something */ - } - if(hints & FUNCS_MOVE) - { /* IGNORE */ - } - if(hints & FUNCS_MINIMIZE) - { /* IGNORE */ - } - if(hints & FUNCS_MAXIMIZE) - { /* IGNORE */ - } - if(hints & FUNCS_CLOSE) - { /* IGNORE */ - } -} - -static void __update_motif_input(Client *c, int32_t hints) -{ - /* values for MwmHints.input_mode */ - enum ___input - { - INPUT_MODELESS = 0, - INPUT_PRIMARY_MODAL = 1, - INPUT_SYSTEM_MODAL = 2, - INPUT_FULL_MODAL = 3, - }; - - switch(hints) - { - case INPUT_PRIMARY_MODAL: - case INPUT_SYSTEM_MODAL: - case INPUT_FULL_MODAL: - /* FALLTHROUGH */ - /* TODO: Add a hash to client "class" name attribute and just make it so 1 primary window is allowed - * AKA just HASH the primary class name to be urgent/active window - */ - seturgent(c, 1); - break; - - case INPUT_MODELESS: - /* FALLTHROUGH */ - default: - break; - } -} - -static void __update_motif_status(Client *c, int32_t hints) -{ - /* bit definitions for MwmHints.status */ - const u32 STATUS_TEAROFF_WIDOW = 1 << 0; - if(hints & STATUS_TEAROFF_WIDOW) - { setmodal(c, 1); - } -} -void -updatemotifhints(Client *c, XCBWindowProperty *motifprop) -{ - /* bit definitions for MwmHints.flags */ - const u32 HINTS_FUNCTIONS = 1 << 0; - const u32 HINTS_DECORATION = 1 << 1; - const u32 HINTS_INPUT_MODE = 1 << 2; - const u32 HINTS_STATUS = 1 << 3; - - if(motifprop) - { - MotifWmHints *hints = XCBGetPropertyValue(motifprop); - uint32_t len = XCBGetPropertyValueLength(motifprop, sizeof(MotifWmHints)); - if(hints && len == 1) - { - if(hints->flags & HINTS_DECORATION) - { __update_motif_decor(c, hints->decorations); - } - if(hints->flags & HINTS_FUNCTIONS) - { __update_motif_func(c, hints->functions); - } - if(hints->flags & HINTS_INPUT_MODE) - { __update_motif_input(c, hints->input_mode); - } - if(hints->flags & HINTS_STATUS) - { __update_motif_status(c, hints->status); - } - } - } -} - /* this function is really slow, slower than malloc use only in startup or rare mapping changes */ void updatenumlockmask(void) @@ -4633,89 +2844,6 @@ updatenumlockmask(void) free(reply); } -void -updatesizehints(Client *c, XCBSizeHints *size) -{ - const int UNINITIALIZED = 0; - i32 basew = UNINITIALIZED; - i32 baseh = UNINITIALIZED; - i32 minw = UNINITIALIZED; - i32 minh = UNINITIALIZED; - i32 maxw = UNINITIALIZED; - i32 maxh = UNINITIALIZED; - i32 incw = UNINITIALIZED; - i32 inch = UNINITIALIZED; - float mina = (float)UNINITIALIZED + 0.0f; /* make sure sign is positive */ - float maxa = (float)UNINITIALIZED + 0.0f; /* make sure sign is positive */ - - /* size is uninitialized, ensure that size.flags aren't used */ - if(!size->flags) - { size->flags = XCB_SIZE_HINT_P_SIZE; - } - if(size->flags & XCB_SIZE_HINT_P_MIN_SIZE) - { - minw = size->min_width; - minh = size->min_height; - } - else if(size->flags & XCB_SIZE_HINT_P_BASE_SIZE) - { - minw = size->base_width; - minh = size->base_height; - } - - if(size->flags & XCB_SIZE_HINT_P_BASE_SIZE) - { - basew = size->base_width; - baseh = size->base_height; - } - else if(size->flags & XCB_SIZE_HINT_P_MIN_SIZE) - { - minw = size->min_width; - minh = size->min_height; - } - - if(size->flags & XCB_SIZE_HINT_P_RESIZE_INC) - { - incw = size->width_inc; - inch = size->height_inc; - } - if(size->flags & XCB_SIZE_HINT_P_MAX_SIZE) - { - maxw = size->max_width; - maxh = size->max_height; - } - - if(size->flags & XCB_SIZE_HINT_P_ASPECT) - { - mina = (float)size->min_aspect_den / (size->min_aspect_num + !size->min_aspect_den); - maxa = (float)size->max_aspect_num / (size->max_aspect_den + !size->max_aspect_num); - mina = fabsf(mina); - maxa = fabsf(maxa); - } - /* clamp */ - minw = MIN(minw, UINT16_MAX); - minh = MIN(minh, UINT16_MAX); - maxw = MIN(maxw, UINT16_MAX); - maxh = MIN(maxh, UINT16_MAX); - basew = MIN(basew, UINT16_MAX); - baseh = MIN(baseh, UINT16_MAX); - (void)mina; - (void)maxa; - inch = MIN(inch, UINT16_MAX); - incw = MIN(incw, UINT16_MAX); - - c->minw = minw; - c->minh = minh; - c->maxw = maxw; - c->maxh = maxh; - c->basew = basew; - c->baseh = baseh; - c->mina = mina; - c->maxa = maxa; - c->inch = inch; - c->incw = incw; -} - void updatestackpriorityfocus(Desktop *desk) { @@ -4730,493 +2858,6 @@ updatestackpriorityfocus(Desktop *desk) } } -void -updatetitle(Client *c, char *netwmname, char *wmname) -{ - if(c->wmname != wmname) - { free(c->wmname); - c->wmname = NULL; - } - if(c->netwmname != netwmname) - { free(c->netwmname); - c->netwmname = NULL; - } - c->wmname = wmname; - c->netwmname = netwmname; -} - -void -updatewindowprotocol(Client *c, XCBWMProtocols *protocols) -{ - if(protocols && protocols->atoms_len) - { - uint32_t i; - XCBAtom atom; - for(i = 0; i < protocols->atoms_len; ++i) - { - atom = protocols->atoms[i]; - if(atom == wmatom[WMTakeFocus]) - { setwmtakefocus(c, 1); - } - else if(atom == wmatom[WMDeleteWindow]) - { setwmdeletewindow(c, 1); - } - else if(atom == wmatom[WMSaveYourself]) - { setwmsaveyourself(c, 1); - } - } - } -} - -void -updatewindowstate(Client *c, XCBAtom state, uint8_t add_remove_toggle) -{ - if(!c || !state) - { return; - } - const u8 toggle = add_remove_toggle == 2; - /* This is similiar to those Windows 10 dialog boxes that play the err sound and cant click anything else */ - if (state == netatom[NetWMStateModal]) - { - if(toggle) - { - setmodal(c, !ISMODAL(c)); - setwtypedialog(c, !ISDIALOG(c)); - } - else - { - setmodal(c, add_remove_toggle); - setwtypedialog(c, add_remove_toggle); - } - } /* This is just syntax sugar, really its just a alias to NetWMStateAbove */ - else if (state == netatom[NetWMStateAbove] || state == netatom[NetWMStateAlwaysOnTop]) - { - if(toggle) - { - setalwaysontop(c, !ISALWAYSONTOP(c)); - } - else - { - setalwaysontop(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateDemandAttention]) - { - if(toggle) - { - seturgent(c, !ISURGENT(c)); - } - else - { - seturgent(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateFullscreen]) - { - if(toggle) - { - setfullscreen(c, !ISFULLSCREEN(c)); - } - else - { - setfullscreen(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateMaximizedHorz]) - { - if(toggle) - { - if(DOCKEDHORZ(c)) - { - unmaximizehorz(c); - setmaximizedhorz(c, 0); - } - else - { - maximizehorz(c); - setmaximizedhorz(c, 1); - } - } - else - { - if(add_remove_toggle) - { maximizehorz(c); - } - else - { unmaximizehorz(c); - } - setmaximizedhorz(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateMaximizedVert]) - { - if(toggle) - { - if(DOCKEDVERT(c)) - { - unmaximizevert(c); - setmaximizedvert(c, 0); - } - else - { - maximizevert(c); - setmaximizedvert(c, 1); - } - } - else - { - if(add_remove_toggle) - { maximizevert(c); - } - else - { unmaximizevert(c); - } - setmaximizedvert(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateSticky]) - { - if(toggle) - { - setsticky(c, !ISSTICKY(c)); - } - else - { - setsticky(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateBelow]) - { - /* this is a wierd state to even configure so idk */ - if(toggle) - { - setalwaysonbottom(c, !ISALWAYSONBOTTOM(c)); - } - else - { - /* attach last */ - setalwaysonbottom(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateSkipTaskbar]) - { - if(toggle) - { - setskiptaskbar(c, !SKIPTASKBAR(c)); - } - else - { - setskiptaskbar(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateSkipPager]) - { - if(toggle) - { - setskippager(c, !SKIPPAGER(c)); - } - else - { - setskippager(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateHidden]) - { - if(toggle) - { - sethidden(c, !ISHIDDEN(c)); - } - else - { - sethidden(c, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateFocused]) - { - if(toggle) - { - SETFLAG(c->wstateflags, _STATE_FOCUSED, !ISFOCUSED(c)); - } - else - { - SETFLAG(c->wstateflags, _STATE_FOCUSED, add_remove_toggle); - } - } - else if (state == netatom[NetWMStateShaded]) - { - if(toggle) - { - setshaded(c, !ISSHADED(c)); - } - else - { - setshaded(c, add_remove_toggle); - } - } - else - { - DEBUG0("Could not find state."); - } -} - -void -updatewindowstates(Client *c, XCBAtom states[], uint32_t atomslength) -{ - if(!states || !c) - { return; - } - - /* bullshit client is trying to mess with us */ - u16 MAX_LIMIT = 1000; - atomslength = MIN(atomslength, MAX_LIMIT); - - - u32 i; - for(i = 0; i < atomslength; ++i) - { - /* Even though the wm-spec says that we should remove things that arent in the list - * The client will ussually tell us in clientmessage if its important. - * It also says however that if its in the list assume its a prop so... - */ - updatewindowstate(c, states[i], 1); - } -} - -void -updatewindowtype(Client *c, XCBAtom wtype, uint8_t add_remove_toggle) -{ - if(!c || !wtype) - { return; - } - - const u8 toggle = add_remove_toggle == 2; - - if (wtype == netatom[NetWMWindowTypeDesktop]) - { - if(toggle) - { - setwtypedesktop(c, !ISDESKTOP(c)); - } - else - { - setwtypedesktop(c, add_remove_toggle); - } - /* TODO */ - } - else if (wtype == netatom[NetWMWindowTypeDock]) - { - if(toggle) - { - setwtypedock(c, !ISDOCK(c)); - } - else - { - setwtypedock(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeToolbar]) - { - if(toggle) - { - setwtypetoolbar(c, !ISTOOLBAR(c)); - } - else - { - setwtypetoolbar(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeMenu]) - { - if(toggle) - { - setwtypemenu(c, !ISMENU(c)); - } - else - { - setwtypemenu(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeUtility]) - { - if(toggle) - { - setwtypeutility(c, !ISUTILITY(c)); - } - else - { - setwtypeutility(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeSplash]) - { - if(toggle) - { - setwtypesplash(c, !ISSPLASH(c)); - } - else - { - setwtypesplash(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeDialog]) - { - if(toggle) - { - setwtypedialog(c, !ISDIALOG(c)); - } - else - { - setwtypedialog(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeDropdownMenu]) - { - if(toggle) - { - setwtypedropdownmenu(c, !ISDROPDOWNMENU(c)); - } - else - { - setwtypedropdownmenu(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypePopupMenu]) - { - if(toggle) - { - setwtypepopupmenu(c, !ISPOPUPMENU(c)); - } - else - { - setwtypepopupmenu(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeTooltip]) - { - if(toggle) - { - setwtypetooltip(c, !ISTOOLTIP(c)); - } - else - { - setwtypetooltip(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeNotification]) - { - if(toggle) - { - setwtypenotification(c, !ISNOTIFICATION(c)); - } - else - { - setwtypenotification(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeCombo]) - { - if(toggle) - { - setwtypecombo(c, !ISCOMBO(c)); - } - else - { - setwtypecombo(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeDnd]) - { - if(toggle) - { - setwtypednd(c, !ISDND(c)); - } - else - { - setwtypednd(c, add_remove_toggle); - } - } - else if (wtype == netatom[NetWMWindowTypeNormal]) - { - if(toggle) - { - setwtypenormal(c, !ISNORMAL(c)); - } - else - { - setwtypenormal(c, add_remove_toggle); - } - } - else - { - DEBUG0("Could not find type."); - } -} - -void -updatewindowtypes(Client *c, XCBAtom wtypes[], uint32_t atomslength) -{ - if(!wtypes || !c) - { return; - } - /* bullshit client is trying to mess with us */ - u8 MAX_LIMIT = 255; - atomslength = MIN(atomslength, MAX_LIMIT); - - i32 i; - for(i = 0; i < atomslength; ++i) - { - /* wm-spec says that we should assume anythings in the list are props so we just pass into "add" */ - updatewindowtype(c, wtypes[i], 1); - } -} - -void -updatewmhints(Client *c, XCBWMHints *wmh) -{ - if(wmh) - { - if(c == c->desktop->sel && wmh->flags & XCB_WM_HINT_URGENCY) - { - wmh->flags &= ~XCB_WM_HINT_URGENCY; - XCBSetWMHintsCookie(_wm.dpy, c->win, wmh); - /* dont put seturgent() here cause that would just undo what we did and be recursive */ - } - else - { - /* dont put seturgent() here cause that would just undo what we did and be recursive */ - SETFLAG(c->wstateflags, _STATE_DEMANDS_ATTENTION, !!(wmh->flags & XCB_WM_HINT_URGENCY)); - } - if(wmh->flags & XCB_WM_HINT_INPUT) - { setwtypeneverfocus(c, !wmh->input); - } - else - { setwtypeneverfocus(c, 0); - } - if(wmh->flags & XCB_WM_HINT_STATE) - { - switch(wmh->initial_state) - { - case XCB_WINDOW_ICONIC_STATE: - sethidden(c, 1); - break; - case XCB_WINDOW_WITHDRAWN_STATE: - DEBUG("Window Specified is Widthdrawn? %d", c->win); - break; - case XCB_WINDOW_NORMAL_STATE: - break; - default: - break; - } - } - if(wmh->flags & XCB_WM_HINT_ICON_PIXMAP) - { /* update icon or something */ - } - if(wmh->flags & XCB_WM_HINT_ICON_MASK) - { /* use flagged bits to asign icon shape */ - } - } -} - void wakeupconnection(XCBDisplay *display, int screen) { @@ -5238,42 +2879,6 @@ wakeupconnection(XCBDisplay *display, int screen) XCBFlush(_wm.dpy); } -void * -wintobar(XCBWindow win, uint8_t getmon) -{ - Monitor *m = NULL; - for(m = _wm.mons; m; m = nextmonitor(m)) - { - if(m->bar->win == win) - { - if(getmon) - { return m; - } - else - { return m->bar; - } - break; - } - } - return NULL; -} - -Client * -wintoclient(XCBWindow win) -{ - Client *c = NULL; - Monitor *m = NULL; - - /* check sel first */ - for(m = _wm.selmon; m; m = nextmonitor(m)) - { - HASH_FIND_INT(m->__hash, &win, c); - if(c) - { return c; - } - } - return NULL; -} Monitor * wintomon(XCBWindow win) @@ -5297,7 +2902,6 @@ wintomon(XCBWindow win) } - void xerror(XCBDisplay *display, XCBGenericError *err) { diff --git a/dwm.h b/dwm.h index 3948d30..7645103 100644 --- a/dwm.h +++ b/dwm.h @@ -8,6 +8,7 @@ #include "uthash.h" #include "settings.h" #include "pannel.h" +#include "client.h" #include "XCB-TRL/xcb_trl.h" #include "XCB-TRL/xcb_winutil.h" #include "XCB-TRL/xcb_gtk.h" @@ -35,53 +36,6 @@ #define SESSION_FILE "/tmp/dwm-session" #define CONFIG_FILE "/var/tmp/dwm-config" /* todo make dir .config/dwm/config or someting like that */ #define BORKED "NOT_SET" -/* Client struct flags */ -#define _FSTATE_FLOATING ((1 << 0)) -#define _FSTATE_WASFLOATING ((1 << 1)) -#define _FSTATE_SHOW_DECOR ((1 << 2)) -#define _FSTATE_OVERRIDE_REDIRECT ((1 << 3)) -#define _FSTATE_KEEP_FOCUS ((1 << 4)) -#define _FSTATE_DISABLE_BORDER ((1 << 5)) -/* EWMH window types */ -#define _TYPE_DESKTOP ((1 << 0)) -#define _TYPE_DOCK ((1 << 1)) -#define _TYPE_TOOLBAR ((1 << 2)) -#define _TYPE_MENU ((1 << 3)) -#define _TYPE_UTILITY ((1 << 4)) -#define _TYPE_SPLASH ((1 << 5)) -#define _TYPE_DIALOG ((1 << 6)) -#define _TYPE_DROPDOWN_MENU ((1 << 7)) -#define _TYPE_POPUP_MENU ((1 << 8)) -#define _TYPE_TOOLTIP ((1 << 9)) -#define _TYPE_NOTIFICATION ((1 << 10)) -#define _TYPE_COMBO ((1 << 11)) -#define _TYPE_DND ((1 << 12)) -#define _TYPE_NORMAL ((1 << 13)) - -/* custom types (using spare bits )*/ -#define _TYPE_NEVERFOCUS ((1 << 14)) -/* Window map states, Widthdrawn, Iconic, Normal. */ -#define _TYPE_MAP_ICONIC ((1 << 15)) - -/* EWMH Window states */ -#define _STATE_MODAL ((1 << 0)) -#define _STATE_STICKY ((1 << 1)) -#define _STATE_MAXIMIZED_VERT ((1 << 2)) -#define _STATE_MAXIMIZED_HORZ ((1 << 3)) -#define _STATE_SHADED ((1 << 4)) -#define _STATE_SKIP_TASKBAR ((1 << 5)) -#define _STATE_SKIP_PAGER ((1 << 6)) -#define _STATE_HIDDEN ((1 << 7)) -#define _STATE_FULLSCREEN ((1 << 8)) -#define _STATE_ABOVE ((1 << 9)) -#define _STATE_BELOW ((1 << 10)) -#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)) /* cursor */ enum CurType @@ -109,13 +63,6 @@ enum ClkType ClkRootWin, ClkLast }; -/* kill client type */ -enum KillType -{ - Graceful, - Safedestroy, - Destroy, -}; /* layout(s) */ enum LayoutType @@ -133,35 +80,11 @@ enum BarSides BarSideLeft, BarSideRight, BarSideTop, BarSideBottom }; -/* Manage cookies */ -enum ManageCookies -{ - ManageCookieAttributes, - ManageCookieGeometry, - ManageCookieTransient, - ManageCookieWType, - ManageCookieWState, - ManageCookieSizeHint, - ManageCookieWMHints, - ManageCookieClass, - ManageCookieWMProtocol, - ManageCookieStrutP, - ManageCookieStrut, - ManageCookieNetWMName, - ManageCookieWMName, - ManageCookiePid, - ManageCookieIcon, - ManageCookieMotif, - - - ManageCookieLAST -}; typedef union Arg Arg; typedef struct Key Key; typedef struct Button Button; typedef struct Monitor Monitor; -typedef struct Client Client; typedef struct Decoration Decoration; typedef struct Stack Stack; typedef struct Layout Layout; @@ -199,77 +122,6 @@ struct Button Arg arg; /* Argument */ }; -struct Client -{ - int16_t x; /* X coordinate */ - int16_t y; /* Y coordinate */ - - uint16_t w; /* Width */ - uint16_t h; /* height */ - - - int16_t oldx; /* Previous X coordinate */ - int16_t oldy; /* Previous Y coordinate */ - - uint16_t oldw; /* Previous Width */ - uint16_t oldh; /* Previous Height */ - - - 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 */ - - uint32_t bcol; /* Border Colour */ - - - float mina; /* Minimum Aspect */ - float maxa; /* Maximum Aspect */ - - - uint16_t basew; /* Base Width */ - uint16_t baseh; /* Base Height */ - - uint16_t incw; /* Increment Width */ - uint16_t inch; /* Increment Height */ - - - uint16_t maxw; /* Max Width. */ - uint16_t maxh; /* Max Height. */ - - uint16_t minw; /* Minimum Width */ - uint16_t minh; /* Minimum Height */ - - - XCBWindow win; /* Client Window */ - pid_t pid; /* Client Pid */ - - - Client *next; /* The next client in list */ - Client *prev; /* The previous client */ - Client *sprev; /* The prev stack order clnt*/ - Client *snext; /* The next client in stack */ - Client *rnext; /* Restack Next */ - Client *rprev; /* Restack Prev */ - Client *fnext; /* The next focused client */ - Client *fprev; /* THe previous focused clnt*/ - Desktop *desktop; /* Client Associated Desktop*/ - Decoration *decor; /* Decoration AKA title bar.*/ - - char *netwmname; /* Client Name */ - 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 */ - uint16_t rstacknum; /* Used in calculating pos */ - uint8_t pad[6]; -}; struct Decoration { @@ -365,16 +217,6 @@ struct MotifWmHints /* Handles the main(int argc, char **argv) arguments. */ void argcvhandler(int argc, char *argv[]); -/* Applies the gravity shifts specified by the gravity onto the x and y coordinates. -*/ -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. -* RETURN: 1 if the specified x/y/w/h does not match after sizehints applied. (aka need to resize.) -* RETURN: 0 if the specified x/y/w/h does match after the sizehints applied. (No need to resize.) -*/ -uint8_t applysizehints(Client *c, int32_t *x, int32_t *y, int32_t *width, int32_t *height, uint8_t interact); /* quickly calculate arrange stuff */ void arrangeq(Desktop *desk); /* Arranges and restacks the windows in the specified desktop. @@ -444,9 +286,6 @@ uint8_t checksticky(int64_t x); /* Cleanups and frees any data previously allocated. */ void cleanup(void); -/* Frees Client and allocated client properties. -*/ -void cleanupclient(Client *c); /* Frees allocated cursors. */ void cleanupcursors(void); @@ -459,25 +298,6 @@ void cleanupmon(Monitor *m); /* Frees all monitors and allocated Monitor properties. */ void cleanupmons(void); -/* Initializes the Client geometry from the specified XCBWindowGeometry struct. - */ -void clientinitgeom(Client *c, XCBWindowGeometry *geometry); -/* Initializes the Client window type from the specified XCBWindowProperty. */ -void clientinitwtype(Client *c, XCBWindowProperty *windowtypereply); -/* Initializes the Client window state from the specified XCBWindowProperty. */ -void clientinitwstate(Client *c, XCBWindowProperty *windowstatereply); -/* Sets the correct client desktop if trans found, default to _wm.selmon->desksel if not.*/ -void clientinittrans(Client *c, XCBWindow trans); -/* Updates the XServers knowledge of the clients coordinates. - * NOTE: This is a sendevent to the c->win data type. - * NOTE: XCBFlush(); must be called to push the XCB internal buffer to send this request. - */ -void configure(Client *c); -/* Allocates a client and client properties with all data set to 0 or the adress of any newly allocated data. - * RETURN: Client * on Success. - * RETURN: NULL on Failure. -*/ -Client *createclient(void); /* Allocates a desktop and desktop properties with all data set to 0 or to the adress of any newly allocated data. * RETURN: Desktop * on Success. * RETURN: NULL on Failure. @@ -498,8 +318,6 @@ Decoration *createdecoration(void); * RETURN: NULL on Failure. */ Monitor *dirtomon(uint8_t dir); -/* Deprecated !ISFLOATING(c) now has this behaviour. */ -uint8_t docked(Client *c); /* Jumps to the specified function handler for the provided event. */ void eventhandler(XCBGenericEvent *ev); @@ -510,64 +328,19 @@ void exithandler(void); * Floating -> Windows overlap each other AKA default win10 window behaviour. */ void floating(Desktop *desk); -/* Sets focus to the specified client. - * NOTE: if NULL provided first visible client in stack is choosen as focus specifier. - */ -void focus(Client *c); -/* UNUSED/TODO - */ -int32_t getstate(XCBWindow win, XCBGetWindowAttributes *state); /* Allocates memory and resturns the pointer in **str_return from the specified XCBWindowProperty. */ void getnamefromreply(XCBWindowProperty *namerep, char **str_return); /* Gets the icon property from the specified XCBWindowProperty. */ uint32_t *geticonprop(XCBWindowProperty *iconreply); -/* Grabs a win buttons. - * Basically this just allows us to receive button press/release events from windows. - */ -void grabbuttons(Client *c, uint8_t focused); -/* Grabs a windows keys. - * Basically this just allows us to receive/intercept key press/release events. - * - */ -void grabkeys(void); /* Sets the "grid" layout for the specified desktop. * grid -> windows are sorted in a grid like formation, like those ones in hacker movies. */ void grid(Desktop *desk); -/* Kills the specified window. - * type: Graceful Sends a message to the window to kill itself. - * Safedestroy Sends a message to the window to kill itself, on failure, forcefully kill the window. - * Destroy Destroys a window without sending any message for the window to response (Nuclear option.) - */ -void killclient(Client *c, enum KillType type); -/* requests for clients cookies. */ -void managerequest(XCBWindow win, XCBCookie requests[ManageCookieLAST]); -/* Part of main event loop "run()" - * Manages AKA adds the window to our current or windows specified desktop. - * Applies size checks, bounds, layout, etc... - * RETURN: Client * on Success. - * RETURN: NULL on Failure. - */ -Client *managereply(XCBWindow window, XCBCookie requests[ManageCookieLAST]); -/* Maximizes a client if unmaxed, Sets flag. - */ -void maximize(Client *c); -/* Maximizes horizontally a client if unmaxed horz, Sets flag. - */ -void maximizehorz(Client *c); -/* Maximizes vertically a client if unmaxed vert, Sets flag. - */ -void maximizevert(Client *c); /* Sets the "monocle" layout for the specified desktop. * monocle -> Windows are maximized to the screen avaible area, * while floating windows are always raised above all others. */ void monocle(Desktop *desk); -/* Returns the next client avaible. - * RETURN: Client * on Success. - * RETURN: NULL on Failure. - */ -Client *nextclient(Client *c); /* Returns the next Desktop avaible. * RETURN: Desktop* on Success. * RETURN: NULL on Failure. @@ -578,57 +351,11 @@ Desktop *nextdesktop(Desktop *desktop); * RETURN: NULL on Failure. */ Monitor *nextmonitor(Monitor *monitor); -/* Returns the next client in stack avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *nextstack(Client *c); -/* Returns the next client in restack avaible. - * RETURN: Client * on Success. - * RETURN: NULL on Failure. - */ -Client *nextrstack(Client *c); -/* Returns the next client in focus order avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *nextfocus(Client *c); -Client *nexttiled(Client *c); -/* Returns the next visible client avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *nextvisible(Client *c); /* Returns the previous desktop avaible. * RETURN: Desktop * on Success. * RETURN: NULL on Failure. */ Desktop *prevdesktop(Desktop *desk); -/* Returns the prev client avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *prevclient(Client *c); -/* Returns the prev focus client avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *prevfocus(Client *c); -/* Returns the prev stack client avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *prevstack(Client *c); -/* Returns the previous restack stack client avaible. - * RETURN: Client * on Success. - * RETURN: NULL on Failure. - */ -Client *prevrstack(Client *c); -/* Returns the prev visible client avaible. - * RETURN: Client* on Success. - * RETURN: NULL on Failure. - */ -Client *prevvisible(Client *c); /* Sends a event to the main event loop to stop running. */ void quit(void); @@ -642,15 +369,6 @@ Desktop *restoredesktopsession(Monitor *m, char *buff, uint16_t len); Monitor *restoremonsession(char *buff, uint16_t len); /* Searches through every monitor for a possible big enough size to fit rectangle parametors specified */ Monitor *recttomon(int16_t x, int16_t y, uint16_t width, uint16_t height); -/* resize a client only if specified x/y/w/h is different - * interact - * {1, 0} - * 1 -> dont confide resize to monitor dimentions - * 0 -> confide resize within monitor dimentions - * */ -void resize(Client *c, int32_t x, int32_t y, int32_t width, int32_t height, uint8_t interact); -/* resize a client given parametors without sizehints */ -void resizeclient(Client *c, int16_t x, int16_t y, uint16_t width, uint16_t height); /* Reorders(restacks) clients in current desk->stack */ void restack(Desktop *desk); /* "Restacks" clients on from linked list no effect unless restack called*/ @@ -673,112 +391,6 @@ void savedesktopsession(FILE *fw, Desktop *desktop); void savemonsession(FILE *fw, Monitor *m); /* Scans for new clients on startup */ void scan(void); -/* Sends a Protocol Event to specified client */ -void sendprotocolevent(Client *c, XCBAtom proto); -/* Sets the flag "alwaysontop" to the provided Client */ -void setalwaysontop(Client *c, uint8_t isalwaysontop); -/* Sets the flag "alwaysonbottom" to the provided Client */ -void setalwaysonbottom(Client *c, uint8_t state); -/* Sets the Clients border opacity, "alpha" 0-255 */ -void setborderalpha(Client *c, uint8_t alpha); -/* Sets the border color using red green and blue values */ -void setbordercolor(Client *c, uint8_t red, uint8_t green, uint8_t blue); -/* Sets the border color only using the 32bit value */ -void setbordercolor32(Client *c, uint32_t col); -/* Sets the border width to the provided Client */ -void setborderwidth(Client *c, uint16_t border_width); -/* Sets the clients desktop to the specified desktop, - * and cleanups any data that may have been left from the previous desktop. - */ -void setclientdesktop(Client *c, Desktop *desktop); -/* Sets the clients wmatom[WMState] property. */ -void setclientstate(Client *c, uint8_t state); -/* Sets the decor visibility. */ -void setdecorvisible(Client *c, uint8_t state); -/* Sets the desktop count rolling back any clients to previous desktops. */ -void setdesktopcount(Monitor *m, uint16_t desktops); -/* Sets the desktops layouts, (not automatic arrange must be called after to apply changes.) */ -void setdesktoplayout(Desktop *desk, uint8_t layout); -/* Sets the currently selected desktop */ -void setdesktopsel(Monitor *mon, Desktop *desksel); -/* Sets the flag to disable border >>CHANGES<< for a client. */ -void setdisableborder(Client *c, uint8_t state); -/* Sets the clients pid. */ -void setclientpid(Client *c, pid_t pid); -/* Sets the Clients IS Desktop Flag. */ -void setwtypedesktop(Client *c, uint8_t state); -/* Sets the Clients IS Dialog Flag. */ -void setwtypedialog(Client *c, uint8_t state); -/* Sets the Clients IS Dock Flag. */ -void setwtypedock(Client *c, uint8_t state); -/* Sets the Clients IS ToolBar Flag. */ -void setwtypetoolbar(Client *c, uint8_t state); -/* Sets the Clients IS Menu Flag. */ -void setwtypemenu(Client *c, uint8_t state); -/* Sets the Clients Never Focus Flag. */ -void setwtypeneverfocus(Client *c, uint8_t state); -/* Sets the Clients IS Utility Flag. */ -void setwtypeutility(Client *c, uint8_t state); -/* Sets the Clients IS Splash Flag. */ -void setwtypesplash(Client *c, uint8_t state); -/* Sets the Clients IS Dropdown Menu Flag. */ -void setwtypedropdownmenu(Client *c, uint8_t state); -/* Sets the Clients IS Popup Menu Flag. */ -void setwtypepopupmenu(Client *c, uint8_t state); -/* Sets the Clients IS Tool Tip Flag. */ -void setwtypetooltip(Client *c, uint8_t state); -/* Sets the Clients IS Notification Flag. */ -void setwtypenotification(Client *c, uint8_t state); -/* Sets the Clients IS Combo Flag. */ -void setwtypecombo(Client *c, uint8_t state); -/* Sets the Clients IS DND Flag. */ -void setwtypednd(Client *c, uint8_t state); -/* Sets the Clients IS Normal Flag. */ -void setwtypenormal(Client *c, uint8_t state); -/* Sets the Clients IS Map Iconic Flag. */ -void setwtypemapiconic(Client *c, uint8_t state); -/* Sets the Clients IS Map Normal Flag. */ -void setwtypemapnormal(Client *c, uint8_t state); -/* Sets the Clients IS Take Focus Flag. */ -void setwmtakefocus(Client *c, uint8_t state); -/* Sets the Clients IS Save Yourself Flag. */ -void setwmsaveyourself(Client *c, uint8_t state); -/* Sets the Clients IS Delete Window Flag. */ -void setwmdeletewindow(Client *c, uint8_t state); -/* Sets the Clients IS Skip Pager Flag. */ -void setskippager(Client *c, uint8_t state); -/* Sets the Clients IS Skip Taskbar Flag. */ -void setskiptaskbar(Client *c, uint8_t state); -/* Sets the Clients Show Decor Flag. */ -void setshowdecor(Client *c, uint8_t state); -/* Makes a client fullscreen and take up the entire monitor. (also sets the isfullscreen flag)*/ -void setfullscreen(Client *c, uint8_t isfullscreen); -/* Sets the Clients IS Floating Flag. */ -void setfloating(Client *c, uint8_t state); -/* Sets the current Window Focus. */ -void setfocus(Client *c); -/* Sets the Windows Map State (Iconic/Normal), and IS hidden Flag. */ -void sethidden(Client *c, uint8_t state); -/* Sets the keep focus state flag - * NOTE: Client must already be in focus to work. - */ -void setkeepfocus(Client *c, uint8_t state); -/* Sets the "Maximized Vert" Flag */ -void setmaximizedvert(Client *c, uint8_t state); -/* Sets the "Maximized Horz" Flag */ -void setmaximizedhorz(Client *c, uint8_t state); -/* Sets the Clients IS Shaded Flag. */ -void setshaded(Client *c, uint8_t state); -/* Sets the Clients IS Modal Flag. */ -void setmodal(Client *c, uint8_t state); -/* Sets the monitors currently selected desktop. */ -void setmondesktop(Monitor *m, Desktop *desk); -/* Sets override redirect flag, which disallows attaching to any linked list for a desktop - * But still allows a client to be found using wintoclient() - */ -void setoverrideredirect(Client *c, uint8_t state); -/* Replaces the Clients state with the sticky state, and sets IS sticky Flag. */ -void setsticky(Client *c, uint8_t state); /* Vital checks and data setup before any other action is performed. */ void startup(void); /* Sets up Variables, Checks, WM specific data, etc.. */ @@ -793,13 +405,6 @@ void setupcursors(void); void setupcfg(void); /* Loads default if CFG data failed to read. */ void setupcfgdefaults(void); -/* Updates a Clients state to Urgent, and sets the Urgent Flag. (Updates window border to urgen color.) */ -void seturgent(Client *c, uint8_t isurgent); -/* Moves Client offscreen if "show" is true - * Moves Client onscreen if "false" is false; - * Should be used when changing desktop ONLY. - */ -void showhide(Client *c, const int show); /* waits for childs (zombies) to die */ void sigchld(int signo); /* Handles Signals and how we use them */ @@ -827,23 +432,16 @@ void startup(void); * and "stacking" on top of each other smaller windows on the right. */ void tile(Desktop *desk); -/* Unfocuses specified client and sets to focus to root if setfocus is true */ -void unfocus(Client *c, uint8_t setfocus); /* updates the Status Bar Position from given monitor */ void updatebarpos(Monitor *m); /* updates the bar geometry from the given monitor */ void updatebargeom(Monitor *m); -/* updates a clients classname from XCBWMClass *_class - * No side effects on non filled _class dataw; - */ -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); /* Updates the XServer to the Current destop */ void updatedesktop(void); /* Updates the desktop names if they have changed */ @@ -852,139 +450,26 @@ void updatedesktopnames(void); 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, XCBWindowProperty *iconprop); -/* updates motif hints if they are set */ -void updatemotifhints(Client *c, XCBWindowProperty *motifprop); /* checks and updates mask if numlock is active */ void updatenumlockmask(void); -/* Updates a Clients sizehints property using the provided hints pointer "size". - * Doesnt require any data from client, AKA modular. still requires "size" though. - */ -void updatesizehints(Client *c, XCBSizeHints *size); void updatestackpriorityfocus(Desktop *desk); -/* Updates Client tile if we find one; - * if none found default to dwm.h BROKEN - */ -void updatetitle(Client *c, char *netwmname, char *wmname); /* updates the viewport property to the XServer */ void updateviewport(void); -/* Updates Our own window protocol status (dont have to query every time) */ -void updatewindowprotocol(Client *c, XCBWMProtocols *protocols); -/* Updates Our own state based on Client state specified */ -void updatewindowstate(Client *c, XCBAtom state, uint8_t add_remove_toggle); -/* Updates Our own states based on Client state specified */ -void updatewindowstates(Client *c, XCBAtom state[], uint32_t atomslength); -/* Updates Our own state based on windowtype in Client */ -void updatewindowtype(Client *c, XCBAtom wtype, uint8_t add_remove_toggle); -/* Updates Our own states based on windowtype in Client */ -void updatewindowtypes(Client *c, XCBAtom wtype[], uint32_t atomslength); -/* Updates WM_HINTS for specified Client */ -void updatewmhints(Client *c, XCBWMHints *hints); /* Wakups the current X connection by sending a event to it */ void wakeupconnection(XCBDisplay *display, int screen); -/* Returns the bar or the monitor depending on if is_return_mon is true. - * RETURN: Bar * on Success and is_return_mon is set to False. - * RETURN: Monitor * on Success and is_return_mon is set to True. - * RETURN: NULL on Failure. - */ -void *wintobar(XCBWindow win, uint8_t is_return_mon); -/* Returns the client if found from the specified window - * RETURN: Client * on Success. - * RETURN: NULL on Failure. - */ -Client *wintoclient(XCBWindow win); /* Returns the Monitor if found from the specified window * RETURN: Monitor* on Success. * RETURN: NULL on Failure. */ Monitor *wintomon(XCBWindow win); -/* Unmanages Client AKA we dont tell it what todo Nor does it use our resources; - * And perform checks based on specified "destroyed"; - * 1 -> widthdraw window; - * 0 -> skip checks (window already destroyed) - */ -void unmanage(Client *c, uint8_t destroyed); -/* unmaximizes a client if maxed, Sets flag. */ -void unmaximize(Client *c); -/* unmaximizes a client horizontally if maxed horz, Sets flag. */ -void unmaximizehorz(Client *c); -/* unmaximizes a client vertically if maxed vert, Sets flag. */ -void unmaximizevert(Client *c); /* Error handler */ void xerror(XCBDisplay *display, XCBGenericError *error); - -/* MACROS */ - -int ISALWAYSONTOP(Client *c); -int ISALWAYSONBOTTOM(Client *c); -int WASFLOATING(Client *c); -int ISFLOATING(Client *c); -int ISOVERRIDEREDIRECT(Client *c); -int KEEPFOCUS(Client *c); -int DISABLEBORDER(Client *c); -int ISFAKEFLOATING(Client *c); -int DOCKEDVERT(Client *c); -int DOCKEDHORZ(Client *c); -int DOCKED(Client *c); -int WASDOCKEDVERT(Client *c); -int WASDOCKEDHORZ(Client *c); -int WASDOCKED(Client *c); -int ISFIXED(Client *c); -int ISURGENT(Client *c); -int NEVERFOCUS(Client *c); -int ISVISIBLE(Client *c); -int SHOWDECOR(Client *c); -int ISSELECTED(Client *c); /* checks if a client could be a bar */ int COULDBEBAR(Client *c, uint8_t strut); -/* EWMH Window types */ -int ISDESKTOP(Client *c); -int ISDOCK(Client *c); -int ISTOOLBAR(Client *c); -int ISMENU(Client *c); -int ISUTILITY(Client *c); -int ISSPLASH(Client *c); -int ISDIALOG(Client *c); -int ISDROPDOWNMENU(Client *c); -int ISPOPUPMENU(Client *c); -int ISTOOLTIP(Client *c); -int ISNOTIFICATION(Client *c); -int ISCOMBO(Client *c); -int ISDND(Client *c); -int ISNORMAL(Client *c); -int ISMAPICONIC(Client *c); -int ISMAPNORMAL(Client *c); -int WTYPENONE(Client *c); -/* EWMH Window states */ -int ISMODAL(Client *c); -int ISSTICKY(Client *c); -int ISMAXIMIZEDVERT(Client *c); -int ISMAXIMIZEDHORZ(Client *c); -int ISSHADED(Client *c); -int SKIPTASKBAR(Client *c); -int SKIPPAGER(Client *c); -int ISHIDDEN(Client *c); -int ISFULLSCREEN(Client *c); -int ISABOVE(Client *c); -int ISBELOW(Client *c); -int DEMANDSATTENTION(Client *c); -int ISFOCUSED(Client *c); -int WSTATENONE(Client *c); -/* WM Protocol */ -int HASWMTAKEFOCUS(Client *c); -int HASWMSAVEYOURSELF(Client *c); -int HASWMDELETEWINDOW(Client *c); - enum BarSides GETBARSIDE(Monitor *m, Client *bar, uint8_t get_prev_side); -uint16_t OLDWIDTH(Client *c); -uint16_t OLDHEIGHT(Client *c); -uint16_t WIDTH(Client *c); -uint16_t HEIGHT(Client *c); - static const Layout layouts[LayoutTypeLAST] = {