Skip to content

Commit

Permalink
Added proper XServer change property handling, setclientwtype + setcl…
Browse files Browse the repository at this point in the history
…ientnetstate (#175)
  • Loading branch information
DerjenigeUberMensch authored Jun 18, 2024
1 parent d86e956 commit 312763d
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 18 deletions.
165 changes: 149 additions & 16 deletions dwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2851,10 +2851,153 @@ setclientdesktop(Client *c, Desktop *desk)
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[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)
{
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[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
setdesktopcount(Monitor *m, uint16_t desktops)
{
Expand Down Expand Up @@ -3086,15 +3229,15 @@ setfullscreen(Client *c, u8 state)
Monitor *m = c->desktop->mon;
if(state && !ISFULLSCREEN(c))
{
XCBChangeProperty(_wm.dpy, c->win, netatom[NetWMState], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)&netatom[NetWMStateFullscreen], 1);
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))
{
XCBChangeProperty(_wm.dpy, c->win, netatom[NetWMState], XCB_ATOM_ATOM, 32, XCB_PROP_MODE_REPLACE, (unsigned char *)0, 0);
setclientnetstate(c, netatom[NetWMStateFullscreen], 0);
setborderwidth(c, c->oldbw);
resizeclient(c, c->oldx, c->oldy, c->oldw, c->oldh);
}
Expand Down Expand Up @@ -3126,11 +3269,13 @@ void
sethidden(Client *c, uint8_t state)
{
if(state)
{ winsetstate(c->win, XCB_WINDOW_ICONIC_STATE);
{
setclientstate(c, XCB_WINDOW_ICONIC_STATE);
setwtypemapiconic(c, 1);
}
else
{ winsetstate(c->win, XCB_WINDOW_NORMAL_STATE);
{
setclientstate(c, XCB_WINDOW_NORMAL_STATE);
setwtypemapnormal(c, 1);
}
SETFLAG(c->wstateflags, _STATE_HIDDEN, !!state);
Expand Down Expand Up @@ -3181,11 +3326,6 @@ setoverrideredirect(Client *c, uint8_t state)
void
setsticky(Client *c, u8 state)
{
const XCBWindow win = c->win;
const XCBAtom replace = !!state * netatom[NetWMStateSticky];
const u8 length = !!state;
XCBChangeProperty(_wm.dpy, win, netatom[NetWMState], XCB_ATOM_ATOM, 32,
XCB_PROP_MODE_REPLACE, (unsigned char *)&replace, length);
SETFLAG(c->wstateflags, _STATE_STICKY, !!state);
}

Expand Down Expand Up @@ -5030,13 +5170,6 @@ wakeupconnection(XCBDisplay *display, int screen)
XCBFlush(_wm.dpy);
}

void
winsetstate(XCBWindow win, i32 state)
{
i32 data[2] = { state, XCB_NONE };
XCBChangeProperty(_wm.dpy, win, wmatom[WMState], wmatom[WMState], 32, XCB_PROP_MODE_REPLACE, (unsigned char *)data, 2);
}

void *
wintobar(XCBWindow win, uint8_t getmon)
{
Expand Down
2 changes: 0 additions & 2 deletions dwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -880,8 +880,6 @@ void updatewindowtypes(Client *c, XCBAtom wtype[], uint32_t atomslength);
void updatewmhints(Client *c, XCBWMHints *hints);
/* Wakups the current X connection by sending a event to it */
void wakeupconnection(XCBDisplay *display, int screen);
/* Sets the window _WM_STATE based on state specified */
void winsetstate(XCBWindow win, int32_t state);
/* 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.
Expand Down

0 comments on commit 312763d

Please sign in to comment.