diff --git a/config.def.h.orig b/config.def.h.orig index d749030..96e3ebc 100644 --- a/config.def.h.orig +++ b/config.def.h.orig @@ -15,8 +15,6 @@ static const unsigned int gappov = 30; /* vert outer gap between window static int smartgaps = 0; /* 1 means no outer gap when there is only one window */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ -static int iconsize = 16; /* icon size */ -static int iconspacing = 5; /* space between icon and title */ static const char *fonts[] = { "monospace:size=10" }; static const char dmenufont[] = "monospace:size=10"; static const char col_gray1[] = "#222222"; diff --git a/config.def.h.rej b/config.def.h.rej index ee73f24..36b8c7c 100644 --- a/config.def.h.rej +++ b/config.def.h.rej @@ -1,33 +1,15 @@ --- config.def.h +++ config.def.h -@@ -67,8 +68,10 @@ static const Key keys[] = { - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, - { MODKEY, XK_b, togglebar, {0} }, -- { MODKEY, XK_j, focusstack, {.i = +1 } }, -- { MODKEY, XK_k, focusstack, {.i = -1 } }, -+ { MODKEY, XK_j, focusstackvis, {.i = +1 } }, -+ { MODKEY, XK_k, focusstackvis, {.i = -1 } }, -+ { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, -+ { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, - { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_d, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, -@@ -87,6 +90,9 @@ static const Key keys[] = { - { MODKEY, XK_period, focusmon, {.i = +1 } }, - { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, - { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, -+ { MODKEY, XK_s, show, {0} }, -+ { MODKEY|ShiftMask, XK_s, showall, {0} }, -+ { MODKEY, XK_h, hide, {0} }, - TAGKEYS( XK_1, 0) - TAGKEYS( XK_2, 1) - TAGKEYS( XK_3, 2) -@@ -105,6 +111,7 @@ static const Button buttons[] = { - /* click event mask button function argument */ - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, -+ { ClkWinTitle, 0, Button1, togglewin, {0} }, - { ClkWinTitle, 0, Button2, zoom, {0} }, - { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, - { ClkClientWin, MODKEY, Button1, movemouse, {0} }, +@@ -26,9 +26,11 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ ++ /* class instance title tags mask isfloating monitor isgame */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ { "Steam", NULL, NULL, 0, 0, -1, 1 }, ++ { "steam_app",NULL, NULL, 0, 0, -1, 1 }, + }; + + /* layout(s) */ diff --git a/config.h b/config.h index 99f12f7..286db91 100644 --- a/config.h +++ b/config.h @@ -49,20 +49,23 @@ static char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; static const Rule rules[] = { /* xprop(1): - * WM_CLASS(STRING) = instance, class - * WM_NAME(STRING) = title + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title */ - /* class instance title tags mask isfloating isterminal monitor */ - { "Playground", NULL, NULL, 0, 1, -1 }, + /* class instance title tags mask isfloating monitor isgame */ + { "Playground", NULL, NULL, 0, 1, -1, 0 }, - { "steam", NULL, NULL, 1 << 1, 0, -1 }, - { "Firefox", NULL, NULL, 1 << 2, 0, -1 }, - { "brave-browser", NULL, NULL, 1 << 3, 0, -1 }, - { "discord", NULL, NULL, 1 << 4, 0, -1 }, - { "feishin", NULL, NULL, 1 << 5, 0, -1 }, - { NULL, "spterm", NULL, SPTAG(0), 1, 0 }, - { NULL, "spfm", NULL, SPTAG(1), 1, 0 }, - { NULL, "keepassxc", NULL, SPTAG(2), 0, 0 }, + { "Steam", NULL, NULL, 1 << 1, 0, -1, 1 }, + { "steam_app", NULL, NULL, 0, 0, -1, 1 }, + + { "Firefox", NULL, NULL, 1 << 2, 0, -1, 0 }, + { "brave-browser", NULL, NULL, 1 << 3, 0, -1, 0 }, + { "discord", NULL, NULL, 1 << 4, 0, -1, 0 }, + { "feishin", NULL, NULL, 1 << 5, 0, -1, 0 }, + + { NULL, "spterm", NULL, SPTAG(0), 1, -1, 0 }, + { NULL, "spfm", NULL, SPTAG(1), 1, -1, 0 }, + { NULL, "keepassxc", NULL, SPTAG(2), 0, -1, 0 }, }; /* layout(s) */ @@ -164,9 +167,9 @@ static const Key keys[] = { /* cycle layouts */ { MODKEY, XK_n, cyclelayout, {.i = +1 } }, - { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, - { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, - { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, + { MODKEY|Mod1Mask, XK_h, setcfact, {.f = +0.25} }, + { MODKEY|Mod1Mask, XK_l, setcfact, {.f = -0.25} }, + { MODKEY|Mod1Mask, XK_o, setcfact, {.f = 0.00} }, { MODKEY|Mod1Mask, XK_u, incrgaps, {.i = +1 } }, { MODKEY|Mod1Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, { MODKEY|Mod1Mask, XK_i, incrigaps, {.i = +1 } }, @@ -194,7 +197,7 @@ static const Key keys[] = { { MODKEY, XK_s, show, {0} }, { MODKEY|ShiftMask, XK_s, showall, {0} }, - { MODKEY|ShiftMask, XK_h, hide, {0} }, + { MODKEY|ShiftMask, XK_v, hide, {0} }, { MODKEY, XK_space, setlayout, {0} }, { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, diff --git a/dwm b/dwm index a3ccd6c..cf4538b 100755 Binary files a/dwm and b/dwm differ diff --git a/dwm.c b/dwm.c index ca16a6a..1a1b86b 100644 --- a/dwm.c +++ b/dwm.c @@ -51,6 +51,7 @@ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLEONTAG(C, T) ((C->tags & T)) #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +#define MINIMIZED(C) ((getstate(C->win) == IconicState)) #define HIDDEN(C) ((getstate(C->win) == IconicState)) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -114,7 +115,7 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; - int issteam; + int isgame; int fakefullscreen; Client *next; Client *snext; @@ -169,6 +170,7 @@ typedef struct { unsigned int tags; int isfloating; int monitor; + int isgame; } Rule; typedef struct Systray Systray; @@ -226,6 +228,7 @@ static void losefullscreen(Client *next); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); +static void minimize(Client *c); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); @@ -282,6 +285,7 @@ static void togglewin(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); +static void unminimize(Client *c); static void updatecurrentdesktop(void); static void updatebarpos(Monitor *m); static void updatebars(void); @@ -408,9 +412,6 @@ applyrules(Client *c) class = ch.res_class ? ch.res_class : broken; instance = ch.res_name ? ch.res_name : broken; - if (strstr(class, "Steam") || strstr(class, "steam_app_")) - c->issteam = 1; - for (i = 0; i < LENGTH(rules); i++) { r = &rules[i]; if ((!r->title || strstr(c->name, r->title)) @@ -419,6 +420,7 @@ applyrules(Client *c) { c->isfloating = r->isfloating; c->tags |= r->tags; + c->isgame = r->isgame; if ((r->tags & SPTAGMASK) && r->isfloating) { c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); @@ -800,15 +802,13 @@ configurerequest(XEvent *e) c->bw = ev->border_width; else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { m = c->mon; - if (!c->issteam) { - if (ev->value_mask & CWX) { - c->oldx = c->x; - c->x = m->mx + ev->x; - } - if (ev->value_mask & CWY) { - c->oldy = c->y; - c->y = m->my + ev->y; - } + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; } if (ev->value_mask & CWWidth) { c->oldw = c->w; @@ -1566,6 +1566,29 @@ maprequest(XEvent *e) manage(ev->window, &wa); } +void +minimize(Client *c) +{ + if (!c || MINIMIZED(c)) + return; + + Window w = c->win; + static XWindowAttributes ra, ca; + + // more or less taken directly from blackbox's hide() function + XGrabServer(dpy); + XGetWindowAttributes(dpy, root, &ra); + XGetWindowAttributes(dpy, w, &ca); + // prevent UnmapNotify events + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, w); + setclientstate(c, IconicState); + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, w, ca.your_event_mask); + XUngrabServer(dpy); +} + void monocle(Monitor *m) { @@ -1832,17 +1855,19 @@ propertynotify(XEvent *e) void quit(const Arg *arg) { - // fix: reloading dwm keeps all the hidden clients hidden - Monitor *m; - Client *c; - for (m = mons; m; m = m->next) { - if (m) { - for (c = m->stack; c; c = c->next) - if (c && HIDDEN(c)) showwin(c); + if(arg->i) restart = 1; + if (!restart) { + // fix: reloading dwm keeps all the hidden clients hidden + Monitor *m; + Client *c; + for (m = mons; m; m = m->next) { + if (m) { + for (c = m->stack; c; c = c->next) + if (c && HIDDEN(c)) showwin(c); + } } } - if(arg->i) restart = 1; running = 0; } @@ -2134,8 +2159,9 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } - if (c->issteam) - setclientstate(c, NormalState); + + if (c->isgame && c->isfullscreen) + unminimize(c); sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); } @@ -2662,6 +2688,10 @@ unfocus(Client *c, int setfocus) { if (!c) return; + + if (c->isgame && c->isfullscreen) + minimize(c); + grabbuttons(c, 0); XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); if (setfocus) { @@ -2716,6 +2746,16 @@ unmapnotify(XEvent *e) } } +void +unminimize(Client *c) +{ + if (!c || !MINIMIZED(c)) + return; + + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); +} + void updatebars(void) { diff --git a/dwm.c.orig b/dwm.c.orig index a24e352..4fbf4c0 100644 --- a/dwm.c.orig +++ b/dwm.c.orig @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -52,6 +51,7 @@ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLEONTAG(C, T) ((C->tags & T)) #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +#define MINIMIZED(C) ((getstate(C->win) == IconicState)) #define HIDDEN(C) ((getstate(C->win) == IconicState)) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -79,7 +79,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */ -enum { NetSupported, NetWMName, NetWMIcon, NetWMState, NetWMCheck, +enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetClientInfo, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ @@ -115,9 +115,8 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; - unsigned int icw, ich; - Picture icon; int issteam; + int isgame; int fakefullscreen; Client *next; Client *snext; @@ -172,6 +171,7 @@ typedef struct { unsigned int tags; int isfloating; int monitor; + int isgame; } Rule; typedef struct Systray Systray; @@ -188,7 +188,6 @@ static void arrangemon(Monitor *m); static void attach(Client *c); static void attachaside(Client *c); static void attachstack(Client *c); -static uint32_t *bilinear_scale(const uint32_t *src, int sw, int sh, uint32_t dw, uint32_t dh); static void buttonpress(XEvent *e); static void checkotherwm(void); static void cleanup(void); @@ -214,11 +213,9 @@ static void focusmon(const Arg *arg); static void focusstackvis(const Arg *arg); static void focusstackhid(const Arg *arg); static void focusstack(int inc, int vis); -static void freeicon(Client *c); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); -static Picture geticonprop(Display *dpy, Window w, int iconsize, unsigned int *icw, unsigned int *ich); static unsigned int getsystraywidth(); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); @@ -232,6 +229,7 @@ static void losefullscreen(Client *next); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); +static void minimize(Client *c); static void monocle(Monitor *m); static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); @@ -239,7 +237,6 @@ static Client *nexttagged(Client *c); static Client *nexttiled(Client *c); static void placedir(const Arg *arg); static void pop(Client *c); -static uint32_t prealpha(uint32_t p); static void propertynotify(XEvent *e); static void quit(const Arg *arg); static Monitor *recttomon(int x, int y, int w, int h); @@ -289,12 +286,12 @@ static void togglewin(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); +static void unminimize(Client *c); static void updatecurrentdesktop(void); static void updatebarpos(Monitor *m); static void updatebars(void); static void updateclientlist(void); static int updategeom(void); -static void updateicon(Client *c); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); @@ -427,6 +424,7 @@ applyrules(Client *c) { c->isfloating = r->isfloating; c->tags |= r->tags; + c->isgame = r->isgame; if ((r->tags & SPTAGMASK) && r->isfloating) { c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); @@ -559,57 +557,6 @@ attachstack(Client *c) c->mon->stack = c; } -uint32_t * -bilinear_scale(const uint32_t *src, int sw, int sh, unsigned int dw, unsigned int dh) -{ - uint32_t *dst = calloc(dw * dh, sizeof(uint32_t)); - if (!dst) return NULL; - - for (int y = 0; y < dh; y++) { - /* Source position (in fixed-point) */ - float sy = (y + 0.5f) * sh / (float)dh - 0.5f; - int y0 = (sy < 0) ? (int)(sy - 1) : (int)(sy);; - int y1 = y0 + 1; - float fy = sy - y0; - if (y0 < 0) { y0 = 0; y1 = 0; fy = 0; } - if (y1 >= sh) { y1 = sh-1; y0 = y1; fy = 0; } - - for (int x = 0; x < dw; x++) { - float sx = (x + 0.5f) * sw / (float)dw - 0.5f; - int x0 = (sx < 0) ? (int)(sx - 1) : (int)(sx); - int x1 = x0 + 1; - float fx = sx - x0; - if (x0 < 0) { x0 = 0; x1 = 0; fx = 0; } - if (x1 >= sw) { x1 = sw-1; x0 = x1; fx = 0; } - - uint32_t p00 = prealpha(src[y0*sw + x0]); - uint32_t p10 = prealpha(src[y0*sw + x1]); - uint32_t p01 = prealpha(src[y1*sw + x0]); - uint32_t p11 = prealpha(src[y1*sw + x1]); - - /* Extract premultiplied channels */ - int a00 = p00 >> 24, r00 = (p00 >> 16) & 0xFF, g00 = (p00 >> 8) & 0xFF, b00 = p00 & 0xFF; - int a10 = p10 >> 24, r10 = (p10 >> 16) & 0xFF, g10 = (p10 >> 8) & 0xFF, b10 = p10 & 0xFF; - int a01 = p01 >> 24, r01 = (p01 >> 16) & 0xFF, g01 = (p01 >> 8) & 0xFF, b01 = p01 & 0xFF; - int a11 = p11 >> 24, r11 = (p11 >> 16) & 0xFF, g11 = (p11 >> 8) & 0xFF, b11 = p11 & 0xFF; - - /* Bilinear weights */ - float w00 = (1.0f - fx) * (1.0f - fy); - float w10 = fx * (1.0f - fy); - float w01 = (1.0f - fx) * fy; - float w11 = fx * fy; - - int a = (int)(a00*w00 + a10*w10 + a01*w01 + a11*w11 + 0.5f); - int r = (int)(r00*w00 + r10*w10 + r01*w01 + r11*w11 + 0.5f); - int g = (int)(g00*w00 + g10*w10 + g01*w01 + g11*w11 + 0.5f); - int b = (int)(b00*w00 + b10*w10 + b01*w01 + b11*w11 + 0.5f); - - dst[y*dw + x] = (a << 24) | (r << 16) | (g << 8) | b; - } - } - return dst; -} - void buttonpress(XEvent *e) { @@ -1057,12 +1004,7 @@ drawbar(Monitor *m) } remainder--; } - if (c->icon) { - drw_text(drw, x, 0, w > m->ww - tw - stw - x ? m->ww - tw - stw - x : w, bh, lrpad / 2 + c->ich + iconspacing, c->name, 0); - drw_pic(drw, x + lrpad / 2, (bh - c->ich) / 2, c->icw, c->ich, c->icon); - } else { - drw_text(drw, x, 0, tabw > m->ww - tw - stw - x ? m->ww - tw - stw - x : tabw, bh, lrpad / 2, c->name, 0); - } + drw_text(drw, x, 0, tabw > m->ww - tw - stw - x ? m->ww - tw - stw - x : tabw, bh, lrpad / 2, c->name, 0); x += tabw; } } else { @@ -1290,15 +1232,6 @@ focusstack(int inc, int hid) } } -void -freeicon(Client *c) -{ - if (c->icon) { - XRenderFreePicture(dpy, c->icon); - c->icon = None; - } -} - Atom getatomprop(Client *c, Atom prop) { @@ -1361,104 +1294,6 @@ getstate(Window w) return result; } -/* geticonprop: read, scale, and return an XRender Picture */ -Picture -geticonprop(Display *dpy, Window win, int iconsize, unsigned int *icw, unsigned int *ich) { - Atom net_wm_icon = XInternAtom(dpy, "_NET_WM_ICON", False); - Atom actual_type; - int actual_format; - unsigned long nitems, bytes_after; - unsigned char *data = NULL; - Picture pict = None; - - if (XGetWindowProperty(dpy, win, net_wm_icon, 0, LONG_MAX, False, AnyPropertyType, - &actual_type, &actual_format, &nitems, &bytes_after, &data) != Success || !data) { - return None; - } - - unsigned long *p = (unsigned long *)data; - unsigned long *end = p + nitems; - - /* Pick icon closest to desired size */ - unsigned long *best = NULL; - unsigned long best_w = 0, best_h = 0; - unsigned long best_diff = ~0UL; - - while (p + 2 < end) { - unsigned long w0 = *p++; - unsigned long h0 = *p++; - if (w0 == 0 || h0 == 0 || p + w0*h0 > end) break; - - unsigned long diff = (w0 > (unsigned long)iconsize ? w0 - iconsize : iconsize - w0) - + (h0 > (unsigned long)iconsize ? h0 - iconsize : iconsize - h0); - - if (diff < best_diff) { - best_diff = diff; - best_w = w0; - best_h = h0; - best = p; - } - p += w0 * h0; - } - - if (!best) { - XFree(data); - return None; - } - - /* Copy into fixed 32-bit array */ - uint32_t *src = malloc(best_w * best_h * sizeof(uint32_t)); - for (size_t i = 0; i < best_w * best_h; i++) - src[i] = (uint32_t)best[i]; - - /* Scale */ - int dst_w, dst_h; - if (best_w > best_h) { - dst_w = iconsize; - dst_h = best_h * iconsize / best_w; - } else { - dst_h = iconsize; - dst_w = best_w * iconsize / best_h; - } - - uint32_t *scaled = bilinear_scale(src, best_w, best_h, dst_w, dst_h); - free(src); - XFree(data); - if (!scaled) return None; - - /* Create pixmap and upload pixels */ - Pixmap pm = XCreatePixmap(dpy, root, dst_w, dst_h, 32); - - XImage img; - memset(&img, 0, sizeof img); - img.width = dst_w; - img.height = dst_h; - img.format = ZPixmap; - img.data = (char*)scaled; - img.byte_order = LSBFirst; - img.bitmap_unit = 32; - img.bitmap_bit_order = LSBFirst; - img.bitmap_pad = 32; - img.depth = 32; - img.bits_per_pixel = 32; - img.bytes_per_line = dst_w * 4; - - XInitImage(&img); - GC gc = XCreateGC(dpy, pm, 0, NULL); - XPutImage(dpy, pm, gc, &img, 0, 0, 0, 0, dst_w, dst_h); - XFreeGC(dpy, gc); - - XRenderPictFormat *fmt = XRenderFindStandardFormat(dpy, PictStandardARGB32); - pict = XRenderCreatePicture(dpy, pm, fmt, 0, NULL); - XFreePixmap(dpy, pm); - - free(scaled); - - *icw = dst_w; - *ich = dst_h; - return pict; -} - int gettextprop(Window w, Atom atom, char *text, unsigned int size) { @@ -1640,7 +1475,6 @@ manage(Window w, XWindowAttributes *wa) c->oldbw = wa->border_width; c->cfact = 1.0; - updateicon(c); updatetitle(c); if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { c->mon = t->mon; @@ -1738,6 +1572,29 @@ maprequest(XEvent *e) manage(ev->window, &wa); } +void +minimize(Client *c) +{ + if (!c || MINIMIZED(c)) + return; + + Window w = c->win; + static XWindowAttributes ra, ca; + + // more or less taken directly from blackbox's hide() function + XGrabServer(dpy); + XGetWindowAttributes(dpy, root, &ra); + XGetWindowAttributes(dpy, w, &ca); + // prevent UnmapNotify events + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, w); + setclientstate(c, IconicState); + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, w, ca.your_event_mask); + XUngrabServer(dpy); +} + void monocle(Monitor *m) { @@ -1953,14 +1810,6 @@ pop(Client *c) arrange(c->mon); } -uint32_t -prealpha(uint32_t p) { - uint8_t a = p >> 24u; - uint32_t rb = (a * (p & 0xFF00FFu)) >> 8u; - uint32_t g = (a * (p & 0x00FF00u)) >> 8u; - return (rb & 0xFF00FFu) | (g & 0x00FF00u) | (a << 24u); -} - void propertynotify(XEvent *e) { @@ -2004,11 +1853,6 @@ propertynotify(XEvent *e) if (c == c->mon->sel) drawbar(c->mon); } - if (ev->atom == netatom[NetWMIcon]) { - updateicon(c); - if (c == c->mon->sel) - drawbar(c->mon); - } if (ev->atom == netatom[NetWMWindowType]) updatewindowtype(c); } @@ -2017,17 +1861,19 @@ propertynotify(XEvent *e) void quit(const Arg *arg) { - // fix: reloading dwm keeps all the hidden clients hidden - Monitor *m; - Client *c; - for (m = mons; m; m = m->next) { - if (m) { - for (c = m->stack; c; c = c->next) - if (c && HIDDEN(c)) showwin(c); + if(arg->i) restart = 1; + if (!restart) { + // fix: reloading dwm keeps all the hidden clients hidden + Monitor *m; + Client *c; + for (m = mons; m; m = m->next) { + if (m) { + for (c = m->stack; c; c = c->next) + if (c && HIDDEN(c)) showwin(c); + } } } - if(arg->i) restart = 1; running = 0; } @@ -2319,6 +2165,10 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } + + if (c->isgame && c->isfullscreen) + unminimize(c); + if (c->issteam) setclientstate(c, NormalState); @@ -2494,7 +2344,6 @@ setup(void) netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); - netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); @@ -2848,6 +2697,10 @@ unfocus(Client *c, int setfocus) { if (!c) return; + + if (c->isgame && c->isfullscreen) + minimize(c); + grabbuttons(c, 0); XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); if (setfocus) { @@ -2864,7 +2717,6 @@ unmanage(Client *c, int destroyed) detach(c); detachstack(c); - freeicon(c); if (!destroyed) { wc.border_width = c->oldbw; XGrabServer(dpy); /* avoid race conditions */ @@ -2903,6 +2755,16 @@ unmapnotify(XEvent *e) } } +void +unminimize(Client *c) +{ + if (!c || !MINIMIZED(c)) + return; + + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); +} + void updatebars(void) { @@ -2967,13 +2829,6 @@ void updatecurrentdesktop(void){ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); } -void -updateicon(Client *c) -{ - freeicon(c); - c->icon = geticonprop(dpy, c->win, iconsize, &c->icw, &c->ich); -} - int updategeom(void) { diff --git a/dwm.c.rej b/dwm.c.rej index e8b02c3..660493a 100644 --- a/dwm.c.rej +++ b/dwm.c.rej @@ -1,46 +1,19 @@ --- dwm.c +++ dwm.c -@@ -59,7 +58,7 @@ - /* enums */ - enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ - enum { SchemeNorm, SchemeSel }; /* color schemes */ --enum { NetSupported, NetWMName, NetWMIcon, NetWMState, NetWMCheck, -+enum { NetSupported, NetWMName, NetWMState, NetWMCheck, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ - enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -@@ -92,8 +91,6 @@ struct Client { +@@ -92,7 +92,6 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; -- unsigned int icw, ich; -- Picture icon; +- int issteam; Client *next; Client *snext; Monitor *mon; -@@ -170,11 +166,9 @@ static void focus(Client *c); - static void focusin(XEvent *e); - static void focusmon(const Arg *arg); - static void focusstack(const Arg *arg); --static void freeicon(Client *c); - static Atom getatomprop(Client *c, Atom prop); - static int getrootptr(int *x, int *y); - static long getstate(Window w); --static Picture geticonprop(Display *dpy, Window w, int iconsize, unsigned int *icw, unsigned int *ich); - static int gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, int focused); - static void grabkeys(void); -@@ -740,12 +681,7 @@ drawbar(Monitor *m) - if ((w = m->ww - tw - x) > bh) { - if (m->sel) { - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); -- if (m->sel->icon) { -- drw_text(drw, x, 0, w, bh, lrpad / 2 + m->sel->icw + iconspacing, m->sel->name, 0); -- drw_pic(drw, x + lrpad / 2, (bh - m->sel->ich) / 2, m->sel->icw, m->sel->ich, m->sel->icon); -- } else { -- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); -- } -+ drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); - if (m->sel->isfloating) - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); - } else { +@@ -1476,8 +1470,6 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } +- if (c->issteam) +- setclientstate(c, NormalState); + sendevent(c, wmatom[WMTakeFocus]); + } + diff --git a/dwm.o b/dwm.o index 9ec1f01..f4392cd 100644 Binary files a/dwm.o and b/dwm.o differ diff --git a/patches/dwm-games-6.6.diff b/patches/dwm-games-6.6.diff new file mode 100644 index 0000000..ce4bbdb --- /dev/null +++ b/patches/dwm-games-6.6.diff @@ -0,0 +1,173 @@ +From d06cefd6e1f8b5cd9bdfe694b7dc16da1f00d83e Mon Sep 17 00:00:00 2001 +From: Bakkeby +Date: Mon, 1 Jul 2024 22:19:15 +0200 +Subject: [PATCH] Game rule patch + +This patch adds a rule identifying clients as a "game" such that +if the client is in fullscreen and it loses focus (e.g. by moving +to another tag) then it will automatically be minimized (set to +IconicState and unmapped). + +When the client receives focus again (e.g. by going back to its +tag) then it will automaticaly be unminimized (set to NormalState +and mapped). This should address many of the black screen or window +is tiny after having moved to another tag and back again. + +This may conflict with the awesomebar patch which skips hidden +(iconic) windows when selecting which client to focus on, i.e. it +would be there but minimized and will not automatically unminimize. + +The function names are minimize and unminimize compared to the same +functions hide and show in the awesomebar patch. The name change is +due to two reasons; 1) because hide and show do something very +different compared to the showhide function and 2) because when +minimizing and unminimizing we do not want to trigger arrange or +a change in focus (which would affect the stacking order and thus +prevent the window receiving focus when we move back to the previous +tag). +--- + config.def.h | 4 +++- + dwm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 9efa774..9df3c97 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -26,9 +26,11 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ ++ /* class instance title tags mask isfloating monitor isgame */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ { "Steam", NULL, NULL, 0, 0, -1, 1 }, ++ { "steam_app",NULL, NULL, 0, 0, -1, 1 }, + }; + + /* layout(s) */ +diff --git a/dwm.c b/dwm.c +index 1443802..29de39a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -50,6 +50,7 @@ + #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) ++#define MINIMIZED(C) ((getstate(C->win) == IconicState)) + #define MOUSEMASK (BUTTONMASK|PointerMotionMask) + #define WIDTH(X) ((X)->w + 2 * (X)->bw) + #define HEIGHT(X) ((X)->h + 2 * (X)->bw) +@@ -92,6 +93,7 @@ struct Client { + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isgame; + Client *next; + Client *snext; + Monitor *mon; +@@ -138,6 +140,7 @@ typedef struct { + unsigned int tags; + int isfloating; + int monitor; ++ int isgame; + } Rule; + + /* function declarations */ +@@ -180,6 +183,7 @@ static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); + static void mappingnotify(XEvent *e); + static void maprequest(XEvent *e); ++static void minimize(Client *c); + static void monocle(Monitor *m); + static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); +@@ -215,6 +219,7 @@ static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); ++static void unminimize(Client *c); + static void updatebarpos(Monitor *m); + static void updatebars(void); + static void updateclientlist(void); +@@ -298,6 +303,7 @@ applyrules(Client *c) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; ++ c->isgame = r->isgame; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; +@@ -1109,6 +1115,29 @@ maprequest(XEvent *e) + manage(ev->window, &wa); + } + ++void ++minimize(Client *c) ++{ ++ if (!c || MINIMIZED(c)) ++ return; ++ ++ Window w = c->win; ++ static XWindowAttributes ra, ca; ++ ++ // more or less taken directly from blackbox's hide() function ++ XGrabServer(dpy); ++ XGetWindowAttributes(dpy, root, &ra); ++ XGetWindowAttributes(dpy, w, &ca); ++ // prevent UnmapNotify events ++ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); ++ XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); ++ XUnmapWindow(dpy, w); ++ setclientstate(c, IconicState); ++ XSelectInput(dpy, root, ra.your_event_mask); ++ XSelectInput(dpy, w, ca.your_event_mask); ++ XUngrabServer(dpy); ++} ++ + void + monocle(Monitor *m) + { +@@ -1475,6 +1504,10 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } ++ ++ if (c->isgame && c->isfullscreen) ++ unminimize(c); ++ + sendevent(c, wmatom[WMTakeFocus]); + } + +@@ -1766,6 +1799,10 @@ unfocus(Client *c, int setfocus) + { + if (!c) + return; ++ ++ if (c->isgame && c->isfullscreen) ++ minimize(c); ++ + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { +@@ -1814,6 +1851,16 @@ unmapnotify(XEvent *e) + } + } + ++void ++unminimize(Client *c) ++{ ++ if (!c || !MINIMIZED(c)) ++ return; ++ ++ XMapWindow(dpy, c->win); ++ setclientstate(c, NormalState); ++} ++ + void + updatebars(void) + { +-- +2.50.1 + diff --git a/patches/dwm-steam-6.6.diff b/patches/dwm-steam-6.6.diff deleted file mode 100644 index c6f5fd7..0000000 --- a/patches/dwm-steam-6.6.diff +++ /dev/null @@ -1,72 +0,0 @@ -From df7d9a685f38b64b8087faa3c72f05acf0190383 Mon Sep 17 00:00:00 2001 -From: Bakkeby -Date: Wed, 26 Jun 2024 23:06:37 +0200 -Subject: [PATCH] Steam patch - -Steam, and steam windows (games), trigger a ConfigureNotify request every time the window -gets focus. More so, the configure event passed along from Steam tends to have the wrong -x and y co-ordinates which can make the window, if floating, jump around the screen. - -This patch works around this age-old issue by ignoring the x and y co-ordinates for -ConfigureNotify requests relating to Steam windows. ---- - dwm.c | 22 +++++++++++++++------- - 1 file changed, 15 insertions(+), 7 deletions(-) - -diff --git a/dwm.c b/dwm.c -index 1443802..d99a6fb 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -92,6 +92,7 @@ struct Client { - int bw, oldbw; - unsigned int tags; - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; -+ int issteam; - Client *next; - Client *snext; - Monitor *mon; -@@ -290,6 +291,9 @@ applyrules(Client *c) - class = ch.res_class ? ch.res_class : broken; - instance = ch.res_name ? ch.res_name : broken; - -+ if (strstr(class, "Steam") || strstr(class, "steam_app_")) -+ c->issteam = 1; -+ - for (i = 0; i < LENGTH(rules); i++) { - r = &rules[i]; - if ((!r->title || strstr(c->name, r->title)) -@@ -590,13 +594,15 @@ configurerequest(XEvent *e) - c->bw = ev->border_width; - else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { - m = c->mon; -- if (ev->value_mask & CWX) { -- c->oldx = c->x; -- c->x = m->mx + ev->x; -- } -- if (ev->value_mask & CWY) { -- c->oldy = c->y; -- c->y = m->my + ev->y; -+ if (!c->issteam) { -+ if (ev->value_mask & CWX) { -+ c->oldx = c->x; -+ c->x = m->mx + ev->x; -+ } -+ if (ev->value_mask & CWY) { -+ c->oldy = c->y; -+ c->y = m->my + ev->y; -+ } - } - if (ev->value_mask & CWWidth) { - c->oldw = c->w; -@@ -1475,6 +1481,8 @@ setfocus(Client *c) - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); - } -+ if (c->issteam) -+ setclientstate(c, NormalState); - sendevent(c, wmatom[WMTakeFocus]); - } - --- -2.50.1 -