mirror of https://github.com/bakkeby/patches
Porting patches to 6.3
parent
f43513063d
commit
7cb6ef4f7d
@ -0,0 +1,297 @@
|
||||
From 29ce86e6162c47ee5cd830df5781a572e3fed43e Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 10:55:28 +0100
|
||||
Subject: [PATCH] Alpha, adds transparency for the status bar.
|
||||
|
||||
Allow dwm to have translucent bars, while keeping all the text on it opaque, just like the alpha-patch for st.
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/alpha/
|
||||
|
||||
Authors:
|
||||
|
||||
Eon S. Jeon - esjeon@hyunmu.am
|
||||
Laslo Hunhold - dev@frign.de (6.1 port)
|
||||
Thomas Oltmann - thomas.oltmann.hhg@gmail.com (20180613-b69c870 port)
|
||||
---
|
||||
config.def.h | 7 ++++++
|
||||
config.mk | 2 +-
|
||||
drw.c | 26 ++++++++++++-----------
|
||||
drw.h | 9 +++++---
|
||||
dwm.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++------
|
||||
5 files changed, 82 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..ca7a9ba 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -12,11 +12,18 @@ static const char col_gray2[] = "#444444";
|
||||
static const char col_gray3[] = "#bbbbbb";
|
||||
static const char col_gray4[] = "#eeeeee";
|
||||
static const char col_cyan[] = "#005577";
|
||||
+static const unsigned int baralpha = 0xd0;
|
||||
+static const unsigned int borderalpha = OPAQUE;
|
||||
static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
};
|
||||
+static const unsigned int alphas[][3] = {
|
||||
+ /* fg bg border */
|
||||
+ [SchemeNorm] = { OPAQUE, baralpha, borderalpha },
|
||||
+ [SchemeSel] = { OPAQUE, baralpha, borderalpha },
|
||||
+};
|
||||
|
||||
/* tagging */
|
||||
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
diff --git a/config.mk b/config.mk
|
||||
index b6eb7e0..848aef9 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
diff --git a/drw.c b/drw.c
|
||||
index 4cdbcbe..fe3aadd 100644
|
||||
--- a/drw.c
|
||||
+++ b/drw.c
|
||||
@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen)
|
||||
}
|
||||
|
||||
Drw *
|
||||
-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||
{
|
||||
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||
|
||||
@@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
|
||||
drw->root = root;
|
||||
drw->w = w;
|
||||
drw->h = h;
|
||||
- drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
||||
- drw->gc = XCreateGC(dpy, root, 0, NULL);
|
||||
+ drw->visual = visual;
|
||||
+ drw->depth = depth;
|
||||
+ drw->cmap = cmap;
|
||||
+ drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||
+ drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||
|
||||
return drw;
|
||||
@@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||
drw->h = h;
|
||||
if (drw->drawable)
|
||||
XFreePixmap(drw->dpy, drw->drawable);
|
||||
- drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
|
||||
+ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -194,21 +197,22 @@ drw_fontset_free(Fnt *font)
|
||||
}
|
||||
|
||||
void
|
||||
-drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
|
||||
{
|
||||
if (!drw || !dest || !clrname)
|
||||
return;
|
||||
|
||||
- if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||
- DefaultColormap(drw->dpy, drw->screen),
|
||||
+ if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||
clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
+
|
||||
+ dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||
}
|
||||
|
||||
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||
* returned color scheme when done using it. */
|
||||
Clr *
|
||||
-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||
+drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||
{
|
||||
size_t i;
|
||||
Clr *ret;
|
||||
@@ -218,7 +222,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < clrcount; i++)
|
||||
- drw_clr_create(drw, &ret[i], clrnames[i]);
|
||||
+ drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -274,9 +278,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
} else {
|
||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||
- d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||
- DefaultVisual(drw->dpy, drw->screen),
|
||||
- DefaultColormap(drw->dpy, drw->screen));
|
||||
+ d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||
x += lpad;
|
||||
w -= lpad;
|
||||
}
|
||||
diff --git a/drw.h b/drw.h
|
||||
index 4bcd5ad..a56f523 100644
|
||||
--- a/drw.h
|
||||
+++ b/drw.h
|
||||
@@ -20,6 +20,9 @@ typedef struct {
|
||||
Display *dpy;
|
||||
int screen;
|
||||
Window root;
|
||||
+ Visual *visual;
|
||||
+ unsigned int depth;
|
||||
+ Colormap cmap;
|
||||
Drawable drawable;
|
||||
GC gc;
|
||||
Clr *scheme;
|
||||
@@ -27,7 +30,7 @@ typedef struct {
|
||||
} Drw;
|
||||
|
||||
/* Drawable abstraction */
|
||||
-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
|
||||
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
|
||||
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||
void drw_free(Drw *drw);
|
||||
|
||||
@@ -38,8 +41,8 @@ unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
||||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||
|
||||
/* Colorscheme abstraction */
|
||||
-void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
|
||||
-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
|
||||
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||
|
||||
/* Cursor abstraction */
|
||||
Cur *drw_cur_create(Drw *drw, int shape);
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..34b9a32 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -57,6 +57,8 @@
|
||||
#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
|
||||
+#define OPAQUE 0xffU
|
||||
+
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
@@ -233,6 +235,7 @@ static Monitor *wintomon(Window w);
|
||||
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
+static void xinitvisual();
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
/* variables */
|
||||
@@ -269,6 +272,11 @@ static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
|
||||
+static int useargb = 0;
|
||||
+static Visual *visual;
|
||||
+static int depth;
|
||||
+static Colormap cmap;
|
||||
+
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
@@ -1545,7 +1553,8 @@ setup(void)
|
||||
sw = DisplayWidth(dpy, screen);
|
||||
sh = DisplayHeight(dpy, screen);
|
||||
root = RootWindow(dpy, screen);
|
||||
- drw = drw_create(dpy, screen, root, sw, sh);
|
||||
+ xinitvisual();
|
||||
+ drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
|
||||
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||
die("no fonts could be loaded.");
|
||||
lrpad = drw->fonts->h;
|
||||
@@ -1573,7 +1582,7 @@ setup(void)
|
||||
/* init appearance */
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
- scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||
+ scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
|
||||
/* init bars */
|
||||
updatebars();
|
||||
updatestatus();
|
||||
@@ -1810,16 +1819,18 @@ updatebars(void)
|
||||
Monitor *m;
|
||||
XSetWindowAttributes wa = {
|
||||
.override_redirect = True,
|
||||
- .background_pixmap = ParentRelative,
|
||||
+ .background_pixel = 0,
|
||||
+ .border_pixel = 0,
|
||||
+ .colormap = cmap,
|
||||
.event_mask = ButtonPressMask|ExposureMask
|
||||
};
|
||||
XClassHint ch = {"dwm", "dwm"};
|
||||
for (m = mons; m; m = m->next) {
|
||||
if (m->barwin)
|
||||
continue;
|
||||
- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
|
||||
- CopyFromParent, DefaultVisual(dpy, screen),
|
||||
- CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
||||
+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, depth,
|
||||
+ InputOutput, visual,
|
||||
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
||||
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
||||
XMapRaised(dpy, m->barwin);
|
||||
XSetClassHint(dpy, m->barwin, &ch);
|
||||
@@ -2116,6 +2127,43 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
|
||||
return -1;
|
||||
}
|
||||
|
||||
+void
|
||||
+xinitvisual()
|
||||
+{
|
||||
+ XVisualInfo *infos;
|
||||
+ XRenderPictFormat *fmt;
|
||||
+ int nitems;
|
||||
+ int i;
|
||||
+
|
||||
+ XVisualInfo tpl = {
|
||||
+ .screen = screen,
|
||||
+ .depth = 32,
|
||||
+ .class = TrueColor
|
||||
+ };
|
||||
+ long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||
+
|
||||
+ infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||
+ visual = NULL;
|
||||
+ for(i = 0; i < nitems; i ++) {
|
||||
+ fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||
+ visual = infos[i].visual;
|
||||
+ depth = infos[i].depth;
|
||||
+ cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||
+ useargb = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ XFree(infos);
|
||||
+
|
||||
+ if (! visual) {
|
||||
+ visual = DefaultVisual(dpy, screen);
|
||||
+ depth = DefaultDepth(dpy, screen);
|
||||
+ cmap = DefaultColormap(dpy, screen);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
zoom(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,721 @@
|
||||
From 14803952902c1cbde814bc1233a6c0d766a0febf Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:45:19 +0100
|
||||
Subject: [PATCH 2/2] Adding systray patch
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/systray/
|
||||
---
|
||||
config.def.h | 4 +
|
||||
dwm.c | 410 ++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 390 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index ca7a9ba..0b82307 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,10 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
|
||||
+static const unsigned int systrayspacing = 2; /* systray spacing */
|
||||
+static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
|
||||
+static const int showsystray = 1; /* 0 means no systray */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 34b9a32..2ae3e2b 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -59,12 +59,30 @@
|
||||
|
||||
#define OPAQUE 0xffU
|
||||
|
||||
+#define SYSTEM_TRAY_REQUEST_DOCK 0
|
||||
+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
|
||||
+
|
||||
+/* XEMBED messages */
|
||||
+#define XEMBED_EMBEDDED_NOTIFY 0
|
||||
+#define XEMBED_WINDOW_ACTIVATE 1
|
||||
+#define XEMBED_FOCUS_IN 4
|
||||
+#define XEMBED_MODALITY_ON 10
|
||||
+
|
||||
+#define XEMBED_MAPPED (1 << 0)
|
||||
+#define XEMBED_WINDOW_ACTIVATE 1
|
||||
+#define XEMBED_WINDOW_DEACTIVATE 2
|
||||
+
|
||||
+#define VERSION_MAJOR 0
|
||||
+#define VERSION_MINOR 0
|
||||
+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
|
||||
+
|
||||
/* enums */
|
||||
+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
-enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
+enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayVisual,
|
||||
+ NetWMName, NetWMState, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDock,
|
||||
+ NetSystemTrayOrientationHorz, NetWMWindowTypeDialog, NetClientList, NetWMCheck, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
@@ -143,6 +161,12 @@ typedef struct {
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
+typedef struct Systray Systray;
|
||||
+struct Systray {
|
||||
+ Window win;
|
||||
+ Client *icons;
|
||||
+};
|
||||
+
|
||||
/* function declarations */
|
||||
static void applyrules(Client *c);
|
||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||
@@ -175,6 +199,7 @@ static Atom getatomprop(Client *c, Atom prop);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
+static unsigned int getsystraywidth();
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
@@ -194,10 +219,12 @@ static Monitor *recttomon(int x, int y, int w, int h);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
+static void removesystrayicon(Client *i);
|
||||
+static void resizerequest(XEvent *e);
|
||||
static void restack(Monitor *m);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
-static int sendevent(Client *c, Atom proto);
|
||||
+static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
|
||||
static void sendmon(Client *c, Monitor *m);
|
||||
static void setclientstate(Client *c, long state);
|
||||
static void setfocus(Client *c);
|
||||
@@ -209,6 +236,7 @@ static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static Monitor *systraytomon(Monitor *m);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
@@ -226,12 +254,16 @@ static int updategeom(void);
|
||||
static void updatenumlockmask(void);
|
||||
static void updatesizehints(Client *c);
|
||||
static void updatestatus(void);
|
||||
+static void updatesystray(int updatebar);
|
||||
+static void updatesystrayicongeom(Client *i, int w, int h);
|
||||
+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
|
||||
static void updatetitle(Client *c);
|
||||
static void updatewindowtype(Client *c);
|
||||
static void updatewmhints(Client *c);
|
||||
static void view(const Arg *arg);
|
||||
static Client *wintoclient(Window w);
|
||||
static Monitor *wintomon(Window w);
|
||||
+static Client *wintosystrayicon(Window w);
|
||||
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
@@ -261,9 +293,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[MapRequest] = maprequest,
|
||||
[MotionNotify] = motionnotify,
|
||||
[PropertyNotify] = propertynotify,
|
||||
+ [ResizeRequest] = resizerequest,
|
||||
[UnmapNotify] = unmapnotify
|
||||
};
|
||||
-static Atom wmatom[WMLast], netatom[NetLast];
|
||||
+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
|
||||
static int running = 1;
|
||||
static Cur *cursor[CurLast];
|
||||
static Clr **scheme;
|
||||
@@ -272,6 +305,9 @@ static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
|
||||
+static Systray *systray = NULL;
|
||||
+static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
||||
+
|
||||
static int useargb = 0;
|
||||
static Visual *visual;
|
||||
static int depth;
|
||||
@@ -448,7 +484,7 @@ buttonpress(XEvent *e)
|
||||
arg.ui = 1 << i;
|
||||
} else if (ev->x < x + blw)
|
||||
click = ClkLtSymbol;
|
||||
- else if (ev->x > selmon->ww - (int)TEXTW(stext))
|
||||
+ else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth())
|
||||
click = ClkStatusText;
|
||||
else
|
||||
click = ClkWinTitle;
|
||||
@@ -491,6 +527,13 @@ cleanup(void)
|
||||
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||
while (mons)
|
||||
cleanupmon(mons);
|
||||
+ if (showsystray) {
|
||||
+ while (systray->icons)
|
||||
+ removesystrayicon(systray->icons);
|
||||
+ XUnmapWindow(dpy, systray->win);
|
||||
+ XDestroyWindow(dpy, systray->win);
|
||||
+ free(systray);
|
||||
+ }
|
||||
for (i = 0; i < CurLast; i++)
|
||||
drw_cur_free(drw, cursor[i]);
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
@@ -521,9 +564,49 @@ cleanupmon(Monitor *mon)
|
||||
void
|
||||
clientmessage(XEvent *e)
|
||||
{
|
||||
+ XWindowAttributes wa;
|
||||
+ XSetWindowAttributes swa;
|
||||
XClientMessageEvent *cme = &e->xclient;
|
||||
Client *c = wintoclient(cme->window);
|
||||
|
||||
+ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
|
||||
+ /* add systray icons */
|
||||
+ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
|
||||
+ if (!(c = (Client *)calloc(1, sizeof(Client))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Client));
|
||||
+ if (!(c->win = cme->data.l[2])) {
|
||||
+ free(c);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ c->mon = selmon;
|
||||
+ c->next = systray->icons;
|
||||
+ systray->icons = c;
|
||||
+ XGetWindowAttributes(dpy, c->win, &wa);
|
||||
+ c->x = c->oldx = c->y = c->oldy = 0;
|
||||
+ c->w = c->oldw = wa.width;
|
||||
+ c->h = c->oldh = wa.height;
|
||||
+ c->oldbw = wa.border_width;
|
||||
+ c->bw = 0;
|
||||
+ c->isfloating = True;
|
||||
+ /* reuse tags field as mapped status */
|
||||
+ c->tags = 1;
|
||||
+ updatesizehints(c);
|
||||
+ updatesystrayicongeom(c, wa.width, wa.height);
|
||||
+ XAddToSaveSet(dpy, c->win);
|
||||
+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
|
||||
+ XReparentWindow(dpy, c->win, systray->win, 0, 0);
|
||||
+ /* use parents background color */
|
||||
+ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
+ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
|
||||
+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
|
||||
+ XSync(dpy, False);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ updatesystray(1);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!c)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
@@ -661,6 +744,10 @@ destroynotify(XEvent *e)
|
||||
|
||||
if ((c = wintoclient(ev->window)))
|
||||
unmanage(c, 1);
|
||||
+ else if (showsystray && (c = wintosystrayicon(ev->window))) {
|
||||
+ removesystrayicon(c);
|
||||
+ updatesystray(1);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -704,7 +791,7 @@ dirtomon(int dir)
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
- int x, w, tw = 0;
|
||||
+ int x, w, tw = 0, stw = 0;
|
||||
int boxs = drw->fonts->h / 9;
|
||||
int boxw = drw->fonts->h / 6 + 2;
|
||||
unsigned int i, occ = 0, urg = 0;
|
||||
@@ -713,11 +800,17 @@ drawbar(Monitor *m)
|
||||
if (!m->showbar)
|
||||
return;
|
||||
|
||||
+ if (showsystray && m == systraytomon(m)) {
|
||||
+ stw = getsystraywidth();
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ drw_rect(drw, m->ww - stw, 0, stw, bh, 1, 1);
|
||||
+ }
|
||||
+
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
+ drw_text(drw, m->ww - tw - stw, 0, tw, bh, 0, stext, 0);
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
@@ -740,7 +833,7 @@ drawbar(Monitor *m)
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
||||
|
||||
- if ((w = m->ww - tw - x) > bh) {
|
||||
+ if ((w = m->ww - tw - stw - x) > bh) {
|
||||
if (m->sel) {
|
||||
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
|
||||
@@ -761,6 +854,9 @@ drawbars(void)
|
||||
|
||||
for (m = mons; m; m = m->next)
|
||||
drawbar(m);
|
||||
+
|
||||
+ if (showsystray && !systraypinning)
|
||||
+ updatesystray(0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -788,8 +884,12 @@ expose(XEvent *e)
|
||||
Monitor *m;
|
||||
XExposeEvent *ev = &e->xexpose;
|
||||
|
||||
- if (ev->count == 0 && (m = wintomon(ev->window)))
|
||||
+ if (ev->count == 0 && (m = wintomon(ev->window))) {
|
||||
drawbar(m);
|
||||
+
|
||||
+ if (showsystray && m == systraytomon(m))
|
||||
+ updatesystray(0);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -875,9 +975,17 @@ getatomprop(Client *c, Atom prop)
|
||||
unsigned char *p = NULL;
|
||||
Atom da, atom = None;
|
||||
|
||||
- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
||||
+ /* FIXME getatomprop should return the number of items and a pointer to
|
||||
+ * the stored data instead of this workaround */
|
||||
+ Atom req = XA_ATOM;
|
||||
+ if (prop == xatom[XembedInfo])
|
||||
+ req = xatom[XembedInfo];
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
|
||||
&da, &di, &dl, &dl, &p) == Success && p) {
|
||||
atom = *(Atom *)p;
|
||||
+ if (da == xatom[XembedInfo] && dl == 2)
|
||||
+ atom = ((Atom *)p)[1];
|
||||
XFree(p);
|
||||
}
|
||||
return atom;
|
||||
@@ -911,6 +1019,16 @@ getstate(Window w)
|
||||
return result;
|
||||
}
|
||||
|
||||
+unsigned int
|
||||
+getsystraywidth()
|
||||
+{
|
||||
+ unsigned int w = 0;
|
||||
+ Client *i;
|
||||
+ if (showsystray)
|
||||
+ for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
|
||||
+ return w ? w + systrayspacing : 0;
|
||||
+}
|
||||
+
|
||||
int
|
||||
gettextprop(Window w, Atom atom, char *text, unsigned int size)
|
||||
{
|
||||
@@ -1015,7 +1133,7 @@ killclient(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
- if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
||||
+ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) {
|
||||
XGrabServer(dpy);
|
||||
XSetErrorHandler(xerrordummy);
|
||||
XSetCloseDownMode(dpy, DestroyAll);
|
||||
@@ -1104,6 +1222,12 @@ maprequest(XEvent *e)
|
||||
static XWindowAttributes wa;
|
||||
XMapRequestEvent *ev = &e->xmaprequest;
|
||||
|
||||
+ Client *i;
|
||||
+ if (showsystray && (i = wintosystrayicon(ev->window))) {
|
||||
+ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
|
||||
+ updatesystray(1);
|
||||
+ }
|
||||
+
|
||||
if (!XGetWindowAttributes(dpy, ev->window, &wa))
|
||||
return;
|
||||
if (wa.override_redirect)
|
||||
@@ -1227,6 +1351,16 @@ propertynotify(XEvent *e)
|
||||
Window trans;
|
||||
XPropertyEvent *ev = &e->xproperty;
|
||||
|
||||
+ if (showsystray && (c = wintosystrayicon(ev->window))) {
|
||||
+ if (ev->atom == XA_WM_NORMAL_HINTS) {
|
||||
+ updatesizehints(c);
|
||||
+ updatesystrayicongeom(c, c->w, c->h);
|
||||
+ }
|
||||
+ else
|
||||
+ updatesystrayiconstate(c, ev);
|
||||
+ updatesystray(1);
|
||||
+ }
|
||||
+
|
||||
if ((ev->window == root) && (ev->atom == XA_WM_NAME))
|
||||
updatestatus();
|
||||
else if (ev->state == PropertyDelete)
|
||||
@@ -1277,6 +1411,19 @@ recttomon(int x, int y, int w, int h)
|
||||
return r;
|
||||
}
|
||||
|
||||
+void
|
||||
+removesystrayicon(Client *i)
|
||||
+{
|
||||
+ Client **ii;
|
||||
+
|
||||
+ if (!showsystray || !i)
|
||||
+ return;
|
||||
+ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
|
||||
+ if (ii)
|
||||
+ *ii = i->next;
|
||||
+ free(i);
|
||||
+}
|
||||
+
|
||||
void
|
||||
resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
{
|
||||
@@ -1356,6 +1503,18 @@ resizemouse(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+resizerequest(XEvent *e)
|
||||
+{
|
||||
+ XResizeRequestEvent *ev = &e->xresizerequest;
|
||||
+ Client *i;
|
||||
+
|
||||
+ if ((i = wintosystrayicon(ev->window))) {
|
||||
+ updatesystrayicongeom(i, ev->width, ev->height);
|
||||
+ updatesystray(1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
restack(Monitor *m)
|
||||
{
|
||||
@@ -1445,26 +1604,35 @@ setclientstate(Client *c, long state)
|
||||
}
|
||||
|
||||
int
|
||||
-sendevent(Client *c, Atom proto)
|
||||
+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
|
||||
{
|
||||
int n;
|
||||
- Atom *protocols;
|
||||
+ Atom *protocols, mt;
|
||||
int exists = 0;
|
||||
XEvent ev;
|
||||
|
||||
- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
||||
- while (!exists && n--)
|
||||
- exists = protocols[n] == proto;
|
||||
- XFree(protocols);
|
||||
+ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
|
||||
+ mt = wmatom[WMProtocols];
|
||||
+ if (XGetWMProtocols(dpy, w, &protocols, &n)) {
|
||||
+ while (!exists && n--)
|
||||
+ exists = protocols[n] == proto;
|
||||
+ XFree(protocols);
|
||||
+ }
|
||||
+ } else {
|
||||
+ exists = True;
|
||||
+ mt = proto;
|
||||
}
|
||||
if (exists) {
|
||||
ev.type = ClientMessage;
|
||||
- ev.xclient.window = c->win;
|
||||
- ev.xclient.message_type = wmatom[WMProtocols];
|
||||
+ ev.xclient.window = w;
|
||||
+ ev.xclient.message_type = mt;
|
||||
ev.xclient.format = 32;
|
||||
- ev.xclient.data.l[0] = proto;
|
||||
- ev.xclient.data.l[1] = CurrentTime;
|
||||
- XSendEvent(dpy, c->win, False, NoEventMask, &ev);
|
||||
+ ev.xclient.data.l[0] = d0;
|
||||
+ ev.xclient.data.l[1] = d1;
|
||||
+ ev.xclient.data.l[2] = d2;
|
||||
+ ev.xclient.data.l[3] = d3;
|
||||
+ ev.xclient.data.l[4] = d4;
|
||||
+ XSendEvent(dpy, w, False, mask, &ev);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
@@ -1478,7 +1646,7 @@ setfocus(Client *c)
|
||||
XA_WINDOW, 32, PropModeReplace,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
}
|
||||
- sendevent(c, wmatom[WMTakeFocus]);
|
||||
+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1568,13 +1736,22 @@ setup(void)
|
||||
wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
|
||||
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
|
||||
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
|
||||
+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
|
||||
+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
|
||||
+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
|
||||
+ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
|
||||
+ netatom[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False);
|
||||
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", 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);
|
||||
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
||||
+ netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
|
||||
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
||||
+ xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
|
||||
+ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
|
||||
+ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
@@ -1583,6 +1760,9 @@ setup(void)
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
|
||||
+ /* init system tray */
|
||||
+ if (showsystray)
|
||||
+ updatesystray(0);
|
||||
/* init bars */
|
||||
updatebars();
|
||||
updatestatus();
|
||||
@@ -1665,6 +1845,23 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+Monitor *
|
||||
+systraytomon(Monitor *m)
|
||||
+{
|
||||
+ Monitor *t;
|
||||
+ int i, n;
|
||||
+ if (!systraypinning) {
|
||||
+ if (!m)
|
||||
+ return selmon;
|
||||
+ return m == selmon ? m : NULL;
|
||||
+ }
|
||||
+ for (n = 1, t = mons; t && t->next; n++, t = t->next);
|
||||
+ for (i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next);
|
||||
+ if (systraypinningfailfirst && n < systraypinning)
|
||||
+ return mons;
|
||||
+ return t;
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@@ -1717,6 +1914,23 @@ togglebar(const Arg *arg)
|
||||
selmon->showbar = !selmon->showbar;
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
+ if (showsystray) {
|
||||
+ XWindowChanges wc;
|
||||
+ if (!selmon->showbar)
|
||||
+ wc.y = -bh;
|
||||
+ else if (selmon->showbar) {
|
||||
+ #if BARPADDING_PATCH
|
||||
+ wc.y = vp;
|
||||
+ if (!selmon->topbar)
|
||||
+ wc.y = selmon->mh - bh + vp;
|
||||
+ #else
|
||||
+ wc.y = 0;
|
||||
+ if (!selmon->topbar)
|
||||
+ wc.y = selmon->mh - bh;
|
||||
+ #endif // BARPADDING_PATCH
|
||||
+ }
|
||||
+ XConfigureWindow(dpy, systray->win, CWY, &wc);
|
||||
+ }
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1810,6 +2024,11 @@ unmapnotify(XEvent *e)
|
||||
setclientstate(c, WithdrawnState);
|
||||
else
|
||||
unmanage(c, 0);
|
||||
+ } else if (showsystray && (c = wintosystrayicon(ev->window))) {
|
||||
+ /* KLUDGE! sometimes icons occasionally unmap their windows, but do
|
||||
+ * _not_ destroy them. We map those windows back */
|
||||
+ XMapRaised(dpy, c->win);
|
||||
+ updatesystray(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1832,6 +2051,8 @@ updatebars(void)
|
||||
InputOutput, visual,
|
||||
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
||||
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
||||
+ if (showsystray && m == systraytomon(m))
|
||||
+ XMapRaised(dpy, systray->win);
|
||||
XMapRaised(dpy, m->barwin);
|
||||
XSetClassHint(dpy, m->barwin, &ch);
|
||||
}
|
||||
@@ -2009,6 +2230,137 @@ updatestatus(void)
|
||||
drawbar(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+updatesystray(int updatebar)
|
||||
+{
|
||||
+ XSetWindowAttributes wa;
|
||||
+ XWindowChanges wc;
|
||||
+ Client *i;
|
||||
+ Monitor *m = systraytomon(NULL);
|
||||
+ unsigned int x = m->mx + m->mw;
|
||||
+ unsigned int w = 1, xpad = 0, ypad = 0;
|
||||
+ #if BARPADDING_PATCH
|
||||
+ xpad = sp;
|
||||
+ ypad = vp;
|
||||
+ #endif // BARPADDING_PATCH
|
||||
+
|
||||
+ if (!showsystray)
|
||||
+ return;
|
||||
+ if (!systray) {
|
||||
+ /* init systray */
|
||||
+ if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
|
||||
+
|
||||
+ wa.override_redirect = True;
|
||||
+ wa.event_mask = ButtonPressMask|ExposureMask;
|
||||
+ wa.background_pixel = 0;
|
||||
+ wa.border_pixel = 0;
|
||||
+ wa.colormap = cmap;
|
||||
+ systray->win = XCreateWindow(dpy, root, x - xpad, m->by + ypad, w, bh, 0, depth,
|
||||
+ InputOutput, visual,
|
||||
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
||||
+ XSelectInput(dpy, systray->win, SubstructureNotifyMask);
|
||||
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
|
||||
+ PropModeReplace, (unsigned char *)&systrayorientation, 1);
|
||||
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
|
||||
+ PropModeReplace, (unsigned char *)&visual->visualid, 1);
|
||||
+ XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1);
|
||||
+ XMapRaised(dpy, systray->win);
|
||||
+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
|
||||
+ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
|
||||
+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
|
||||
+ XSync(dpy, False);
|
||||
+ }
|
||||
+ else {
|
||||
+ fprintf(stderr, "dwm: unable to obtain system tray.\n");
|
||||
+ free(systray);
|
||||
+ systray = NULL;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (w = 0, i = systray->icons; i; i = i->next) {
|
||||
+ wa.background_pixel = 0;
|
||||
+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
|
||||
+ XMapRaised(dpy, i->win);
|
||||
+ w += systrayspacing;
|
||||
+ i->x = w;
|
||||
+ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
|
||||
+ w += i->w;
|
||||
+ if (i->mon != m)
|
||||
+ i->mon = m;
|
||||
+ }
|
||||
+ w = w ? w + systrayspacing : 1;
|
||||
+ x -= w;
|
||||
+ XMoveResizeWindow(dpy, systray->win, x - xpad, m->by + ypad, w, bh);
|
||||
+ wc.x = x - xpad;
|
||||
+ wc.y = m->by + ypad;
|
||||
+ wc.width = w;
|
||||
+ wc.height = bh;
|
||||
+ wc.stack_mode = Above; wc.sibling = m->barwin;
|
||||
+ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
|
||||
+ XMapWindow(dpy, systray->win);
|
||||
+ XMapSubwindows(dpy, systray->win);
|
||||
+ XSync(dpy, False);
|
||||
+
|
||||
+ if (updatebar)
|
||||
+ drawbar(m);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+updatesystrayicongeom(Client *i, int w, int h)
|
||||
+{
|
||||
+ if (i) {
|
||||
+ i->h = bh;
|
||||
+ if (w == h)
|
||||
+ i->w = bh;
|
||||
+ else if (h == bh)
|
||||
+ i->w = w;
|
||||
+ else
|
||||
+ i->w = (int) ((float)bh * ((float)w / (float)h));
|
||||
+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
|
||||
+ /* force icons into the systray dimensions if they don't want to */
|
||||
+ if (i->h > bh) {
|
||||
+ if (i->w == i->h)
|
||||
+ i->w = bh;
|
||||
+ else
|
||||
+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
|
||||
+ i->h = bh;
|
||||
+ }
|
||||
+ if (i->w > 2*bh)
|
||||
+ i->w = bh;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
|
||||
+{
|
||||
+ long flags;
|
||||
+ int code = 0;
|
||||
+
|
||||
+ if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
|
||||
+ !(flags = getatomprop(i, xatom[XembedInfo])))
|
||||
+ return;
|
||||
+
|
||||
+ if (flags & XEMBED_MAPPED && !i->tags) {
|
||||
+ i->tags = 1;
|
||||
+ code = XEMBED_WINDOW_ACTIVATE;
|
||||
+ XMapRaised(dpy, i->win);
|
||||
+ setclientstate(i, NormalState);
|
||||
+ }
|
||||
+ else if (!(flags & XEMBED_MAPPED) && i->tags) {
|
||||
+ i->tags = 0;
|
||||
+ code = XEMBED_WINDOW_DEACTIVATE;
|
||||
+ XUnmapWindow(dpy, i->win);
|
||||
+ setclientstate(i, WithdrawnState);
|
||||
+ }
|
||||
+ else
|
||||
+ return;
|
||||
+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
|
||||
+ systray->win, XEMBED_EMBEDDED_VERSION);
|
||||
+}
|
||||
+
|
||||
void
|
||||
updatetitle(Client *c)
|
||||
{
|
||||
@@ -2091,6 +2443,16 @@ wintomon(Window w)
|
||||
return selmon;
|
||||
}
|
||||
|
||||
+Client *
|
||||
+wintosystrayicon(Window w) {
|
||||
+ Client *i = NULL;
|
||||
+
|
||||
+ if (!showsystray || !w)
|
||||
+ return i;
|
||||
+ for (i = systray->icons; i && i->win != w; i = i->next);
|
||||
+ return i;
|
||||
+}
|
||||
+
|
||||
/* There's no way to check accesses to destroyed windows, thus those cases are
|
||||
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
|
||||
* default error handler, which may call exit. */
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,99 @@
|
||||
From d59d1fcbaacacc8fffa8cbf6212e1013f95d4e0e Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:09:11 +0100
|
||||
Subject: [PATCH] alpha deck layout: only show the currently focused window
|
||||
(rather than all windows stacked on top of each other)
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 40 ++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..a52bbfa 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -42,6 +42,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile }, /* first entry is default */
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "[D]", deck },
|
||||
};
|
||||
|
||||
/* key definitions */
|
||||
@@ -77,6 +78,7 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { MODKEY, XK_c, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..4d79804 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -157,6 +157,7 @@ static void configure(Client *c);
|
||||
static void configurenotify(XEvent *e);
|
||||
static void configurerequest(XEvent *e);
|
||||
static Monitor *createmon(void);
|
||||
+static void deck(Monitor *m);
|
||||
static void destroynotify(XEvent *e);
|
||||
static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
@@ -645,6 +646,43 @@ createmon(void)
|
||||
return m;
|
||||
}
|
||||
|
||||
+void
|
||||
+deck(Monitor *m) {
|
||||
+ unsigned int i, n, h, mw, my;
|
||||
+ Client *c, *s;
|
||||
+
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ if (n > m->nmaster) {
|
||||
+ mw = m->nmaster ? m->ww * m->mfact : 0;
|
||||
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster);
|
||||
+ }
|
||||
+ else
|
||||
+ mw = m->ww;
|
||||
+ for (i = my = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < m->nmaster) {
|
||||
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i);
|
||||
+ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
|
||||
+ my += HEIGHT(c);
|
||||
+ }
|
||||
+ else
|
||||
+ XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
|
||||
+
|
||||
+ for (s = m->stack; s; s = s->snext) {
|
||||
+ if (!ISVISIBLE(s) || s->isfloating)
|
||||
+ continue;
|
||||
+
|
||||
+ for (i = my = 0, c = nexttiled(m->clients); c && c != s; c = nexttiled(c->next), i++);
|
||||
+ if (i < m->nmaster)
|
||||
+ continue;
|
||||
+ XMoveWindow(dpy, s->win, c->x, c->y);
|
||||
+ resize(s, m->wx + mw, m->wy, m->ww - mw - (2*s->bw), m->wh - (2*s->bw), False);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
destroynotify(XEvent *e)
|
||||
{
|
||||
@@ -806,6 +844,8 @@ focus(Client *c)
|
||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||
}
|
||||
selmon->sel = c;
|
||||
+ if (selmon->lt[selmon->sellt]->arrange == deck)
|
||||
+ arrangemon(selmon);
|
||||
drawbars();
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,43 @@
|
||||
From 945f4d84a9617c26769d2ee9c36d96dc39a5856f Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:08:27 +0100
|
||||
Subject: [PATCH] alpha monocle layout: only show the currently focused window
|
||||
(rather than all windows stacked on top of each other)
|
||||
|
||||
---
|
||||
dwm.c | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..05f9edb 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -806,6 +806,8 @@ focus(Client *c)
|
||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||
}
|
||||
selmon->sel = c;
|
||||
+ if (selmon->lt[selmon->sellt]->arrange == monocle)
|
||||
+ arrangemon(selmon);
|
||||
drawbars();
|
||||
}
|
||||
|
||||
@@ -1115,8 +1117,15 @@ monocle(Monitor *m)
|
||||
n++;
|
||||
if (n > 0) /* override layout symbol */
|
||||
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
|
||||
- for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
|
||||
+ for (c = m->stack; c && (!ISVISIBLE(c) || c->isfloating); c = c->snext);
|
||||
+ if (c && !c->isfloating) {
|
||||
+ XMoveWindow(dpy, c->win, m->wx, m->wy);
|
||||
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
|
||||
+ c = c->snext;
|
||||
+ }
|
||||
+ for (; c; c = c->snext)
|
||||
+ if (!c->isfloating && ISVISIBLE(c))
|
||||
+ XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,71 @@
|
||||
From 2b0aa06acb2ce04d8761cfd993adf069e9abb9ab Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:11:00 +0100
|
||||
Subject: [PATCH] attachbottom patch
|
||||
|
||||
New clients attach at the bottom of the stack instead of the top.
|
||||
---
|
||||
dwm.c | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..15b0138 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -147,6 +147,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac
|
||||
static void arrange(Monitor *m);
|
||||
static void arrangemon(Monitor *m);
|
||||
static void attach(Client *c);
|
||||
+static void attachbottom(Client *c);
|
||||
static void attachstack(Client *c);
|
||||
static void buttonpress(XEvent *e);
|
||||
static void checkotherwm(void);
|
||||
@@ -407,6 +408,18 @@ attach(Client *c)
|
||||
c->mon->clients = c;
|
||||
}
|
||||
|
||||
+void
|
||||
+attachbottom(Client *c)
|
||||
+{
|
||||
+ Client *below = c->mon->clients;
|
||||
+ for (; below && below->next; below = below->next);
|
||||
+ c->next = NULL;
|
||||
+ if (below)
|
||||
+ below->next = c;
|
||||
+ else
|
||||
+ c->mon->clients = c;
|
||||
+}
|
||||
+
|
||||
void
|
||||
attachstack(Client *c)
|
||||
{
|
||||
@@ -1066,7 +1079,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- attach(c);
|
||||
+ attachbottom(c);
|
||||
attachstack(c);
|
||||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
@@ -1421,7 +1434,7 @@ sendmon(Client *c, Monitor *m)
|
||||
detachstack(c);
|
||||
c->mon = m;
|
||||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
- attach(c);
|
||||
+ attachbottom(c);
|
||||
attachstack(c);
|
||||
focus(NULL);
|
||||
arrange(NULL);
|
||||
@@ -1903,7 +1916,7 @@ updategeom(void)
|
||||
m->clients = c->next;
|
||||
detachstack(c);
|
||||
c->mon = mons;
|
||||
- attach(c);
|
||||
+ attachbottom(c);
|
||||
attachstack(c);
|
||||
}
|
||||
if (m == selmon)
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,137 @@
|
||||
From 8481cf0e5f3879a19c69385917f4775f529f1ff4 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:12:29 +0100
|
||||
Subject: [PATCH] Adding attachx patch (combined attach
|
||||
above/below/bottom/aside/master patch)
|
||||
|
||||
This includes the following attach modes:
|
||||
|
||||
0 - master (default behaviour): new windows become the new master
|
||||
1 - attachabove: new window is placed above selected client
|
||||
2 - attachaside: new window is placed on top of the stack
|
||||
3 - attachbelow: new window is placed below selected client
|
||||
4 - attachbottom: new window is placed at the bottom of the stack
|
||||
|
||||
Refer to:
|
||||
https://dwm.suckless.org/patches/attachabove/
|
||||
https://dwm.suckless.org/patches/attachaside/
|
||||
https://dwm.suckless.org/patches/attachbelow/
|
||||
https://dwm.suckless.org/patches/attachbottom/
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwm.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 57 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..774c5f0 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const int attachmode = 0; /* 0 master (default), 1 = above, 2 = aside, 3 = below, 4 = bottom */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..10fbeef 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -49,7 +49,8 @@
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#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 ISVISIBLEONTAG(C, T) ((C->tags & T))
|
||||
+#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags])
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
|
||||
@@ -148,6 +149,7 @@ static void arrange(Monitor *m);
|
||||
static void arrangemon(Monitor *m);
|
||||
static void attach(Client *c);
|
||||
static void attachstack(Client *c);
|
||||
+static void attachx(Client *c);
|
||||
static void buttonpress(XEvent *e);
|
||||
static void checkotherwm(void);
|
||||
static void cleanup(void);
|
||||
@@ -400,6 +402,57 @@ arrangemon(Monitor *m)
|
||||
m->lt[m->sellt]->arrange(m);
|
||||
}
|
||||
|
||||
+void
|
||||
+attachx(Client *c)
|
||||
+{
|
||||
+ Client *at;
|
||||
+ unsigned int n;
|
||||
+
|
||||
+ switch (attachmode) {
|
||||
+ case 1: // above
|
||||
+ if (c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating)
|
||||
+ break;
|
||||
+
|
||||
+ for (at = c->mon->clients; at->next != c->mon->sel; at = at->next);
|
||||
+ c->next = at->next;
|
||||
+ at->next = c;
|
||||
+ return;
|
||||
+
|
||||
+ case 2: // aside
|
||||
+ for (at = c->mon->clients, n = 0; at; at = at->next)
|
||||
+ if (!at->isfloating && ISVISIBLEONTAG(at, c->tags))
|
||||
+ if (++n >= c->mon->nmaster)
|
||||
+ break;
|
||||
+
|
||||
+ if (!at || !c->mon->nmaster)
|
||||
+ break;
|
||||
+
|
||||
+ c->next = at->next;
|
||||
+ at->next = c;
|
||||
+ return;
|
||||
+
|
||||
+ case 3: // below
|
||||
+ if (c->mon->sel == NULL || c->mon->sel->isfloating)
|
||||
+ break;
|
||||
+
|
||||
+ c->next = c->mon->sel->next;
|
||||
+ c->mon->sel->next = c;
|
||||
+ return;
|
||||
+
|
||||
+ case 4: // bottom
|
||||
+ for (at = c->mon->clients; at && at->next; at = at->next);
|
||||
+ if (!at)
|
||||
+ break;
|
||||
+
|
||||
+ at->next = c;
|
||||
+ c->next = NULL;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* master (default) */
|
||||
+ attach(c);
|
||||
+}
|
||||
+
|
||||
void
|
||||
attach(Client *c)
|
||||
{
|
||||
@@ -1066,7 +1119,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- attach(c);
|
||||
+ attachx(c);
|
||||
attachstack(c);
|
||||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
@@ -1421,7 +1474,7 @@ sendmon(Client *c, Monitor *m)
|
||||
detachstack(c);
|
||||
c->mon = m;
|
||||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
- attach(c);
|
||||
+ attachx(c);
|
||||
attachstack(c);
|
||||
focus(NULL);
|
||||
arrange(NULL);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,51 @@
|
||||
From b27822d126334b6fd5bf5265fff201e54f4d8ede Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:13:09 +0100
|
||||
Subject: [PATCH] Adding autostart patch
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/autostart/
|
||||
---
|
||||
dwm.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..0fad144 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -194,6 +194,7 @@ static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
static void run(void);
|
||||
+static void runAutostart(void);
|
||||
static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
static void sendmon(Client *c, Monitor *m);
|
||||
@@ -1384,6 +1385,17 @@ run(void)
|
||||
handler[ev.type](&ev); /* call handler */
|
||||
}
|
||||
|
||||
+void
|
||||
+runAutostart(void) {
|
||||
+
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = system("cd ~/.config/dwm; ./autostart_blocking.sh");
|
||||
+ ret = system("cd ~/.config/dwm; ./autostart.sh &");
|
||||
+
|
||||
+ if (ret); // ignore, hide compilation warnings
|
||||
+}
|
||||
+
|
||||
void
|
||||
scan(void)
|
||||
{
|
||||
@@ -2148,6 +2160,7 @@ main(int argc, char *argv[])
|
||||
die("pledge");
|
||||
#endif /* __OpenBSD__ */
|
||||
scan();
|
||||
+ runAutostart();
|
||||
run();
|
||||
cleanup();
|
||||
XCloseDisplay(dpy);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,897 @@
|
||||
From 2433e0499e4607d39a3f511449f9466886055914 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:06:10 +0100
|
||||
Subject: [PATCH] Bar Modules - splits the bar functionality into individual
|
||||
segments that can be re-arranged
|
||||
|
||||
---
|
||||
config.def.h | 20 +++
|
||||
dwm.c | 393 ++++++++++++++++++++++++++++++++-----------
|
||||
patch/bar_ltsymbol.c | 17 ++
|
||||
patch/bar_ltsymbol.h | 3 +
|
||||
patch/bar_status.c | 19 +++
|
||||
patch/bar_status.h | 3 +
|
||||
patch/bar_tags.c | 55 ++++++
|
||||
patch/bar_tags.h | 3 +
|
||||
patch/bar_wintitle.c | 31 ++++
|
||||
patch/bar_wintitle.h | 3 +
|
||||
patch/include.c | 5 +
|
||||
patch/include.h | 5 +
|
||||
12 files changed, 458 insertions(+), 99 deletions(-)
|
||||
create mode 100644 patch/bar_ltsymbol.c
|
||||
create mode 100644 patch/bar_ltsymbol.h
|
||||
create mode 100644 patch/bar_status.c
|
||||
create mode 100644 patch/bar_status.h
|
||||
create mode 100644 patch/bar_tags.c
|
||||
create mode 100644 patch/bar_tags.h
|
||||
create mode 100644 patch/bar_wintitle.c
|
||||
create mode 100644 patch/bar_wintitle.h
|
||||
create mode 100644 patch/include.c
|
||||
create mode 100644 patch/include.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..f870c41 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -31,6 +31,26 @@ static const Rule rules[] = {
|
||||
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
};
|
||||
|
||||
+/* Bar rules allow you to configure what is shown where on the bar, as well as
|
||||
+ * introducing your own bar modules.
|
||||
+ *
|
||||
+ * monitor:
|
||||
+ * -1 show on all monitors
|
||||
+ * 0 show on monitor 0
|
||||
+ * 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?)
|
||||
+ * bar - bar index, 0 is default, 1 is extrabar
|
||||
+ * alignment - how the module is aligned compared to other modules
|
||||
+ * widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions
|
||||
+ * name - does nothing, intended for visual clue and for logging / debugging
|
||||
+ */
|
||||
+static const BarRule barrules[] = {
|
||||
+ /* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
+ { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
+ { -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
+ { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
+ { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
+};
|
||||
+
|
||||
/* layout(s) */
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..86763d8 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "util.h"
|
||||
|
||||
/* macros */
|
||||
+#define BARRULES 20
|
||||
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
|
||||
@@ -66,6 +67,19 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
+enum {
|
||||
+ BAR_ALIGN_LEFT,
|
||||
+ BAR_ALIGN_CENTER,
|
||||
+ BAR_ALIGN_RIGHT,
|
||||
+ BAR_ALIGN_LEFT_LEFT,
|
||||
+ BAR_ALIGN_LEFT_RIGHT,
|
||||
+ BAR_ALIGN_LEFT_CENTER,
|
||||
+ BAR_ALIGN_NONE,
|
||||
+ BAR_ALIGN_RIGHT_LEFT,
|
||||
+ BAR_ALIGN_RIGHT_RIGHT,
|
||||
+ BAR_ALIGN_RIGHT_CENTER,
|
||||
+ BAR_ALIGN_LAST
|
||||
+}; /* bar alignment */
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
@@ -74,6 +88,46 @@ typedef union {
|
||||
const void *v;
|
||||
} Arg;
|
||||
|
||||
+typedef struct Monitor Monitor;
|
||||
+typedef struct Bar Bar;
|
||||
+struct Bar {
|
||||
+ Window win;
|
||||
+ Monitor *mon;
|
||||
+ Bar *next;
|
||||
+ int idx;
|
||||
+ int topbar;
|
||||
+ int bx, by, bw, bh; /* bar geometry */
|
||||
+ int w[BARRULES]; // module width
|
||||
+ int x[BARRULES]; // module position
|
||||
+};
|
||||
+
|
||||
+typedef struct {
|
||||
+ int max_width;
|
||||
+} BarWidthArg;
|
||||
+
|
||||
+typedef struct {
|
||||
+ int x;
|
||||
+ int w;
|
||||
+} BarDrawArg;
|
||||
+
|
||||
+typedef struct {
|
||||
+ int rel_x;
|
||||
+ int rel_y;
|
||||
+ int rel_w;
|
||||
+ int rel_h;
|
||||
+} BarClickArg;
|
||||
+
|
||||
+typedef struct {
|
||||
+ int monitor;
|
||||
+ int bar;
|
||||
+ int alignment; // see bar alignment enum
|
||||
+ int (*widthfunc)(Bar *bar, BarWidthArg *a);
|
||||
+ int (*drawfunc)(Bar *bar, BarDrawArg *a);
|
||||
+ int (*clickfunc)(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+ char *name; // for debugging
|
||||
+ int x, w; // position, width for internal use
|
||||
+} BarRule;
|
||||
+
|
||||
typedef struct {
|
||||
unsigned int click;
|
||||
unsigned int mask;
|
||||
@@ -82,7 +136,6 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Button;
|
||||
|
||||
-typedef struct Monitor Monitor;
|
||||
typedef struct Client Client;
|
||||
struct Client {
|
||||
char name[256];
|
||||
@@ -116,19 +169,17 @@ struct Monitor {
|
||||
float mfact;
|
||||
int nmaster;
|
||||
int num;
|
||||
- int by; /* bar geometry */
|
||||
int mx, my, mw, mh; /* screen size */
|
||||
int wx, wy, ww, wh; /* window area */
|
||||
unsigned int seltags;
|
||||
unsigned int sellt;
|
||||
unsigned int tagset[2];
|
||||
int showbar;
|
||||
- int topbar;
|
||||
Client *clients;
|
||||
Client *sel;
|
||||
Client *stack;
|
||||
Monitor *next;
|
||||
- Window barwin;
|
||||
+ Bar *bar;
|
||||
const Layout *lt[2];
|
||||
};
|
||||
|
||||
@@ -163,6 +214,7 @@ static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
+static void drawbarwin(Bar *bar);
|
||||
static void enternotify(XEvent *e);
|
||||
static void expose(XEvent *e);
|
||||
static void focus(Client *c);
|
||||
@@ -235,12 +287,13 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
+#include "patch/include.h"
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
-static int bh, blw = 0; /* bar geometry */
|
||||
+static int bh; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
@@ -272,6 +325,8 @@ static Window root, wmcheckwin;
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
+#include "patch/include.c"
|
||||
+
|
||||
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||
|
||||
@@ -417,43 +472,61 @@ attachstack(Client *c)
|
||||
void
|
||||
buttonpress(XEvent *e)
|
||||
{
|
||||
- unsigned int i, x, click;
|
||||
+ int click, i, r, mi;
|
||||
Arg arg = {0};
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
+ Bar *bar;
|
||||
XButtonPressedEvent *ev = &e->xbutton;
|
||||
+ const BarRule *br;
|
||||
+ BarClickArg carg = { 0, 0, 0, 0 };
|
||||
|
||||
click = ClkRootWin;
|
||||
/* focus monitor if necessary */
|
||||
- if ((m = wintomon(ev->window)) && m != selmon) {
|
||||
+ if ((m = wintomon(ev->window)) && m != selmon
|
||||
+ ) {
|
||||
unfocus(selmon->sel, 1);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
- if (ev->window == selmon->barwin) {
|
||||
- i = x = 0;
|
||||
- do
|
||||
- x += TEXTW(tags[i]);
|
||||
- while (ev->x >= x && ++i < LENGTH(tags));
|
||||
- if (i < LENGTH(tags)) {
|
||||
- click = ClkTagBar;
|
||||
- arg.ui = 1 << i;
|
||||
- } else if (ev->x < x + blw)
|
||||
- click = ClkLtSymbol;
|
||||
- else if (ev->x > selmon->ww - (int)TEXTW(stext))
|
||||
- click = ClkStatusText;
|
||||
- else
|
||||
- click = ClkWinTitle;
|
||||
- } else if ((c = wintoclient(ev->window))) {
|
||||
+
|
||||
+ for (mi = 0, m = mons; m && m != selmon; m = m->next, mi++); // get the monitor index
|
||||
+ for (bar = selmon->bar; bar; bar = bar->next) {
|
||||
+ if (ev->window == bar->win) {
|
||||
+ for (r = 0; r < LENGTH(barrules); r++) {
|
||||
+ br = &barrules[r];
|
||||
+ if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL)
|
||||
+ continue;
|
||||
+ if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi)
|
||||
+ continue;
|
||||
+ if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) {
|
||||
+ carg.rel_x = ev->x - bar->x[r];
|
||||
+ carg.rel_y = ev->y;
|
||||
+ carg.rel_w = bar->w[r];
|
||||
+ carg.rel_h = bar->bh;
|
||||
+ click = br->clickfunc(bar, &arg, &carg);
|
||||
+ if (click < 0)
|
||||
+ return;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (click == ClkRootWin && (c = wintoclient(ev->window))) {
|
||||
focus(c);
|
||||
restack(selmon);
|
||||
XAllowEvents(dpy, ReplayPointer, CurrentTime);
|
||||
click = ClkClientWin;
|
||||
}
|
||||
- for (i = 0; i < LENGTH(buttons); i++)
|
||||
+
|
||||
+ for (i = 0; i < LENGTH(buttons); i++) {
|
||||
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
|
||||
- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
|
||||
+ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
|
||||
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -498,6 +571,7 @@ void
|
||||
cleanupmon(Monitor *mon)
|
||||
{
|
||||
Monitor *m;
|
||||
+ Bar *bar;
|
||||
|
||||
if (mon == mons)
|
||||
mons = mons->next;
|
||||
@@ -505,8 +579,12 @@ cleanupmon(Monitor *mon)
|
||||
for (m = mons; m && m->next != mon; m = m->next);
|
||||
m->next = mon->next;
|
||||
}
|
||||
- XUnmapWindow(dpy, mon->barwin);
|
||||
- XDestroyWindow(dpy, mon->barwin);
|
||||
+ for (bar = mon->bar; bar; bar = mon->bar) {
|
||||
+ XUnmapWindow(dpy, bar->win);
|
||||
+ XDestroyWindow(dpy, bar->win);
|
||||
+ mon->bar = bar->next;
|
||||
+ free(bar);
|
||||
+ }
|
||||
free(mon);
|
||||
}
|
||||
|
||||
@@ -552,6 +630,7 @@ void
|
||||
configurenotify(XEvent *e)
|
||||
{
|
||||
Monitor *m;
|
||||
+ Bar *bar;
|
||||
Client *c;
|
||||
XConfigureEvent *ev = &e->xconfigure;
|
||||
int dirty;
|
||||
@@ -568,7 +647,8 @@ configurenotify(XEvent *e)
|
||||
for (c = m->clients; c; c = c->next)
|
||||
if (c->isfullscreen)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
+ for (bar = m->bar; bar; bar = bar->next)
|
||||
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
||||
}
|
||||
focus(NULL);
|
||||
arrange(NULL);
|
||||
@@ -631,17 +711,40 @@ configurerequest(XEvent *e)
|
||||
Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
- Monitor *m;
|
||||
+ Monitor *m, *mon;
|
||||
+ int i, n, mi, max_bars = 2, istopbar = topbar;
|
||||
+
|
||||
+ const BarRule *br;
|
||||
+ Bar *bar;
|
||||
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
m->mfact = mfact;
|
||||
m->nmaster = nmaster;
|
||||
m->showbar = showbar;
|
||||
- m->topbar = topbar;
|
||||
+
|
||||
+ for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ /* Derive the number of bars for this monitor based on bar rules */
|
||||
+ for (n = -1, i = 0; i < LENGTH(barrules); i++) {
|
||||
+ br = &barrules[i];
|
||||
+ if (br->monitor == 'A' || br->monitor == -1 || br->monitor == mi)
|
||||
+ n = MAX(br->bar, n);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i <= n && i < max_bars; i++) {
|
||||
+ bar = ecalloc(1, sizeof(Bar));
|
||||
+ bar->mon = m;
|
||||
+ bar->idx = i;
|
||||
+ bar->next = m->bar;
|
||||
+ bar->topbar = istopbar;
|
||||
+ m->bar = bar;
|
||||
+ istopbar = !istopbar;
|
||||
+ }
|
||||
+
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -696,65 +799,117 @@ dirtomon(int dir)
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
- int x, w, tw = 0;
|
||||
- int boxs = drw->fonts->h / 9;
|
||||
- int boxw = drw->fonts->h / 6 + 2;
|
||||
- unsigned int i, occ = 0, urg = 0;
|
||||
- Client *c;
|
||||
-
|
||||
- if (!m->showbar)
|
||||
- return;
|
||||
-
|
||||
- /* draw status first so it can be overdrawn by tags later */
|
||||
- if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
- }
|
||||
-
|
||||
- for (c = m->clients; c; c = c->next) {
|
||||
- occ |= c->tags;
|
||||
- if (c->isurgent)
|
||||
- urg |= c->tags;
|
||||
- }
|
||||
- x = 0;
|
||||
- for (i = 0; i < LENGTH(tags); i++) {
|
||||
- w = TEXTW(tags[i]);
|
||||
- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
|
||||
- if (occ & 1 << i)
|
||||
- drw_rect(drw, x + boxs, boxs, boxw, boxw,
|
||||
- m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
|
||||
- urg & 1 << i);
|
||||
- x += w;
|
||||
- }
|
||||
- w = blw = TEXTW(m->ltsymbol);
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
||||
-
|
||||
- if ((w = m->ww - tw - x) > bh) {
|
||||
- if (m->sel) {
|
||||
- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
- 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 {
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- drw_rect(drw, x, 0, w, bh, 1, 1);
|
||||
- }
|
||||
- }
|
||||
- drw_map(drw, m->barwin, 0, 0, m->ww, bh);
|
||||
+ Bar *bar;
|
||||
+ for (bar = m->bar; bar; bar = bar->next)
|
||||
+ drawbarwin(bar);
|
||||
}
|
||||
|
||||
void
|
||||
drawbars(void)
|
||||
{
|
||||
Monitor *m;
|
||||
-
|
||||
for (m = mons; m; m = m->next)
|
||||
drawbar(m);
|
||||
}
|
||||
|
||||
+void
|
||||
+drawbarwin(Bar *bar)
|
||||
+{
|
||||
+ if (!bar->win)
|
||||
+ return;
|
||||
+ Monitor *mon;
|
||||
+ int r, w, mi;
|
||||
+ int rx, lx, rw, lw; // bar size, split between left and right if a center module is added
|
||||
+ const BarRule *br;
|
||||
+ BarWidthArg warg = { 0 };
|
||||
+ BarDrawArg darg = { 0, 0 };
|
||||
+
|
||||
+ for (mi = 0, mon = mons; mon && mon != bar->mon; mon = mon->next, mi++); // get the monitor index
|
||||
+ rw = lw = bar->bw;
|
||||
+ rx = lx = 0;
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ drw_rect(drw, lx, 0, lw, bh, 1, 1);
|
||||
+ for (r = 0; r < LENGTH(barrules); r++) {
|
||||
+ br = &barrules[r];
|
||||
+ if (br->bar != bar->idx || br->drawfunc == NULL || (br->monitor == 'A' && bar->mon != selmon))
|
||||
+ continue;
|
||||
+ if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi)
|
||||
+ continue;
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ warg.max_width = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw);
|
||||
+ w = br->widthfunc(bar, &warg);
|
||||
+ w = MIN(warg.max_width, w);
|
||||
+
|
||||
+ if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa
|
||||
+ lw = rw;
|
||||
+ lx = rx;
|
||||
+ } else if (rw <= 0) {
|
||||
+ rw = lw;
|
||||
+ rx = lx;
|
||||
+ }
|
||||
+
|
||||
+ switch(br->alignment) {
|
||||
+ default:
|
||||
+ case BAR_ALIGN_NONE:
|
||||
+ case BAR_ALIGN_LEFT_LEFT:
|
||||
+ case BAR_ALIGN_LEFT:
|
||||
+ bar->x[r] = lx;
|
||||
+ if (lx == rx) {
|
||||
+ rx += w;
|
||||
+ rw -= w;
|
||||
+ }
|
||||
+ lx += w;
|
||||
+ lw -= w;
|
||||
+ break;
|
||||
+ case BAR_ALIGN_LEFT_RIGHT:
|
||||
+ case BAR_ALIGN_RIGHT:
|
||||
+ bar->x[r] = lx + lw - w;
|
||||
+ if (lx == rx)
|
||||
+ rw -= w;
|
||||
+ lw -= w;
|
||||
+ break;
|
||||
+ case BAR_ALIGN_LEFT_CENTER:
|
||||
+ case BAR_ALIGN_CENTER:
|
||||
+ bar->x[r] = lx + lw / 2 - w / 2;
|
||||
+ if (lx == rx) {
|
||||
+ rw = rx + rw - bar->x[r] - w;
|
||||
+ rx = bar->x[r] + w;
|
||||
+ }
|
||||
+ lw = bar->x[r] - lx;
|
||||
+ break;
|
||||
+ case BAR_ALIGN_RIGHT_LEFT:
|
||||
+ bar->x[r] = rx;
|
||||
+ if (lx == rx) {
|
||||
+ lx += w;
|
||||
+ lw -= w;
|
||||
+ }
|
||||
+ rx += w;
|
||||
+ rw -= w;
|
||||
+ break;
|
||||
+ case BAR_ALIGN_RIGHT_RIGHT:
|
||||
+ bar->x[r] = rx + rw - w;
|
||||
+ if (lx == rx)
|
||||
+ lw -= w;
|
||||
+ rw -= w;
|
||||
+ break;
|
||||
+ case BAR_ALIGN_RIGHT_CENTER:
|
||||
+ bar->x[r] = rx + rw / 2 - w / 2;
|
||||
+ if (lx == rx) {
|
||||
+ lw = lx + lw - bar->x[r] + w;
|
||||
+ lx = bar->x[r] + w;
|
||||
+ }
|
||||
+ rw = bar->x[r] - rx;
|
||||
+ break;
|
||||
+ }
|
||||
+ bar->w[r] = w;
|
||||
+ darg.x = bar->x[r];
|
||||
+ darg.w = bar->w[r];
|
||||
+ br->drawfunc(bar, &darg);
|
||||
+ }
|
||||
+ drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
|
||||
+}
|
||||
+
|
||||
void
|
||||
enternotify(XEvent *e)
|
||||
{
|
||||
@@ -1049,7 +1204,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->y = c->mon->my + c->mon->mh - HEIGHT(c);
|
||||
c->x = MAX(c->x, c->mon->mx);
|
||||
/* only fix client y-offset, if the client center might cover the bar */
|
||||
- c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
|
||||
+ c->y = MAX(c->y, ((c->mon->bar->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
|
||||
&& (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
|
||||
c->bw = borderpx;
|
||||
|
||||
@@ -1236,7 +1391,8 @@ propertynotify(XEvent *e)
|
||||
break;
|
||||
case XA_WM_HINTS:
|
||||
updatewmhints(c);
|
||||
- drawbars();
|
||||
+ if (c->isurgent)
|
||||
+ drawbars();
|
||||
break;
|
||||
}
|
||||
if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
|
||||
@@ -1362,7 +1518,7 @@ restack(Monitor *m)
|
||||
XRaiseWindow(dpy, m->sel->win);
|
||||
if (m->lt[m->sellt]->arrange) {
|
||||
wc.stack_mode = Below;
|
||||
- wc.sibling = m->barwin;
|
||||
+ wc.sibling = m->bar->win;
|
||||
for (c = m->stack; c; c = c->snext)
|
||||
if (!c->isfloating && ISVISIBLE(c)) {
|
||||
XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
|
||||
@@ -1705,9 +1861,11 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
+ Bar *bar;
|
||||
selmon->showbar = !selmon->showbar;
|
||||
updatebarpos(selmon);
|
||||
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
+ for (bar = selmon->bar; bar; bar = bar->next)
|
||||
+ XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1807,22 +1965,37 @@ unmapnotify(XEvent *e)
|
||||
void
|
||||
updatebars(void)
|
||||
{
|
||||
+ Bar *bar;
|
||||
Monitor *m;
|
||||
XSetWindowAttributes wa = {
|
||||
.override_redirect = True,
|
||||
+ #if BAR_ALPHA_PATCH
|
||||
+ .background_pixel = 0,
|
||||
+ .border_pixel = 0,
|
||||
+ .colormap = cmap,
|
||||
+ #else
|
||||
.background_pixmap = ParentRelative,
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
.event_mask = ButtonPressMask|ExposureMask
|
||||
};
|
||||
XClassHint ch = {"dwm", "dwm"};
|
||||
for (m = mons; m; m = m->next) {
|
||||
- if (m->barwin)
|
||||
- continue;
|
||||
- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
|
||||
- CopyFromParent, DefaultVisual(dpy, screen),
|
||||
- CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
||||
- XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
||||
- XMapRaised(dpy, m->barwin);
|
||||
- XSetClassHint(dpy, m->barwin, &ch);
|
||||
+ for (bar = m->bar; bar; bar = bar->next) {
|
||||
+ if (!bar->win) {
|
||||
+ #if BAR_ALPHA_PATCH
|
||||
+ bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth,
|
||||
+ InputOutput, visual,
|
||||
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
||||
+ #else
|
||||
+ bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen),
|
||||
+ CopyFromParent, DefaultVisual(dpy, screen),
|
||||
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor);
|
||||
+ XMapRaised(dpy, bar->win);
|
||||
+ XSetClassHint(dpy, bar->win, &ch);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1831,12 +2004,30 @@ updatebarpos(Monitor *m)
|
||||
{
|
||||
m->wy = m->my;
|
||||
m->wh = m->mh;
|
||||
- if (m->showbar) {
|
||||
- m->wh -= bh;
|
||||
- m->by = m->topbar ? m->wy : m->wy + m->wh;
|
||||
- m->wy = m->topbar ? m->wy + bh : m->wy;
|
||||
- } else
|
||||
- m->by = -bh;
|
||||
+ int num_bars;
|
||||
+ Bar *bar;
|
||||
+ int y_pad = 0;
|
||||
+ int x_pad = 0;
|
||||
+
|
||||
+ for (bar = m->bar; bar; bar = bar->next) {
|
||||
+ bar->bx = m->mx + x_pad;
|
||||
+ bar->bw = m->ww - 2 * x_pad;
|
||||
+ bar->bh = bh;
|
||||
+ }
|
||||
+
|
||||
+ if (!m->showbar) {
|
||||
+ for (bar = m->bar; bar; bar = bar->next)
|
||||
+ bar->by = -bh - y_pad;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (num_bars = 0, bar = m->bar; bar; bar = bar->next, num_bars++)
|
||||
+ if (bar->topbar)
|
||||
+ m->wy = m->my + bh + y_pad;
|
||||
+ m->wh = m->wh - y_pad * num_bars - bh * num_bars;
|
||||
+
|
||||
+ for (bar = m->bar; bar; bar = bar->next)
|
||||
+ bar->by = (bar->topbar ? m->wy - bh : m->wy + m->wh);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1993,9 +2184,11 @@ updatesizehints(Client *c)
|
||||
void
|
||||
updatestatus(void)
|
||||
{
|
||||
+ Monitor *m;
|
||||
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
||||
strcpy(stext, "dwm-"VERSION);
|
||||
- drawbar(selmon);
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ drawbar(m);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2069,12 +2262,14 @@ wintomon(Window w)
|
||||
int x, y;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
+ Bar *bar;
|
||||
|
||||
if (w == root && getrootptr(&x, &y))
|
||||
return recttomon(x, y, 1, 1);
|
||||
for (m = mons; m; m = m->next)
|
||||
- if (w == m->barwin)
|
||||
- return m;
|
||||
+ for (bar = m->bar; bar; bar = bar->next)
|
||||
+ if (w == bar->win)
|
||||
+ return m;
|
||||
if ((c = wintoclient(w)))
|
||||
return c->mon;
|
||||
return selmon;
|
||||
diff --git a/patch/bar_ltsymbol.c b/patch/bar_ltsymbol.c
|
||||
new file mode 100644
|
||||
index 0000000..6676a2a
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_ltsymbol.c
|
||||
@@ -0,0 +1,17 @@
|
||||
+int
|
||||
+width_ltsymbol(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return TEXTW(bar->mon->ltsymbol);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_ltsymbol(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, bar->mon->ltsymbol, 0);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_ltsymbol(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkLtSymbol;
|
||||
+}
|
||||
diff --git a/patch/bar_ltsymbol.h b/patch/bar_ltsymbol.h
|
||||
new file mode 100644
|
||||
index 0000000..d9c79bf
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_ltsymbol.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_ltsymbol(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_ltsymbol(Bar *bar, BarDrawArg *a);
|
||||
+static int click_ltsymbol(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
diff --git a/patch/bar_status.c b/patch/bar_status.c
|
||||
new file mode 100644
|
||||
index 0000000..7d27282
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_status.c
|
||||
@@ -0,0 +1,19 @@
|
||||
+int
|
||||
+width_status(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return TEXTW(stext);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int
|
||||
+draw_status(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, stext, 0);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int
|
||||
+click_status(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkStatusText;
|
||||
+}
|
||||
diff --git a/patch/bar_status.h b/patch/bar_status.h
|
||||
new file mode 100644
|
||||
index 0000000..b02a4b8
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_status.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_status(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_status(Bar *bar, BarDrawArg *a);
|
||||
+static int click_status(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
diff --git a/patch/bar_tags.c b/patch/bar_tags.c
|
||||
new file mode 100644
|
||||
index 0000000..680e1fe
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_tags.c
|
||||
@@ -0,0 +1,55 @@
|
||||
+int
|
||||
+width_tags(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ int w, i;
|
||||
+
|
||||
+ for (w = 0, i = 0; i < LENGTH(tags); i++) {
|
||||
+ w += TEXTW(tags[i]);
|
||||
+ }
|
||||
+ return w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_tags(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ int invert;
|
||||
+ int w, x = a->x;
|
||||
+ int boxs = drw->fonts->h / 9;
|
||||
+ int boxw = drw->fonts->h / 6 + 2;
|
||||
+ unsigned int i, occ = 0, urg = 0;
|
||||
+ Client *c;
|
||||
+ Monitor *m = bar->mon;
|
||||
+
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ occ |= c->tags;
|
||||
+ if (c->isurgent)
|
||||
+ urg |= c->tags;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < LENGTH(tags); i++) {
|
||||
+ invert = urg & 1 << i;
|
||||
+ w = TEXTW(tags[i]);
|
||||
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], invert);
|
||||
+ if (occ & 1 << i)
|
||||
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
|
||||
+ m == selmon && selmon->sel && selmon->sel->tags & 1 << i, invert);
|
||||
+ x += w;
|
||||
+ }
|
||||
+
|
||||
+ return x;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_tags(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ int i = 0, x = lrpad / 2;
|
||||
+
|
||||
+ do {
|
||||
+ x += TEXTW(tags[i]);
|
||||
+ } while (a->rel_x >= x && ++i < LENGTH(tags));
|
||||
+ if (i < LENGTH(tags)) {
|
||||
+ arg->ui = 1 << i;
|
||||
+ }
|
||||
+ return ClkTagBar;
|
||||
+}
|
||||
diff --git a/patch/bar_tags.h b/patch/bar_tags.h
|
||||
new file mode 100644
|
||||
index 0000000..7ac04d8
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_tags.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_tags(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_tags(Bar *bar, BarDrawArg *a);
|
||||
+static int click_tags(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
diff --git a/patch/bar_wintitle.c b/patch/bar_wintitle.c
|
||||
new file mode 100644
|
||||
index 0000000..3c11b75
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_wintitle.c
|
||||
@@ -0,0 +1,31 @@
|
||||
+int
|
||||
+width_wintitle(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return a->max_width;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_wintitle(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ int boxs = drw->fonts->h / 9;
|
||||
+ int boxw = drw->fonts->h / 6 + 2;
|
||||
+ int x = a->x, w = a->w;
|
||||
+ Monitor *m = bar->mon;
|
||||
+
|
||||
+ if (m->sel) {
|
||||
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
+ 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 {
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ drw_rect(drw, x, 0, w, bh, 1, 1);
|
||||
+ }
|
||||
+ return x + w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_wintitle(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkWinTitle;
|
||||
+}
|
||||
diff --git a/patch/bar_wintitle.h b/patch/bar_wintitle.h
|
||||
new file mode 100644
|
||||
index 0000000..266404c
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_wintitle.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_wintitle(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_wintitle(Bar *bar, BarDrawArg *a);
|
||||
+static int click_wintitle(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
new file mode 100644
|
||||
index 0000000..d422f56
|
||||
--- /dev/null
|
||||
+++ b/patch/include.c
|
||||
@@ -0,0 +1,5 @@
|
||||
+/* Bar functionality */
|
||||
+#include "bar_ltsymbol.c"
|
||||
+#include "bar_status.c"
|
||||
+#include "bar_tags.c"
|
||||
+#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
new file mode 100644
|
||||
index 0000000..5f9a3fe
|
||||
--- /dev/null
|
||||
+++ b/patch/include.h
|
||||
@@ -0,0 +1,5 @@
|
||||
+/* Bar functionality */
|
||||
+#include "bar_ltsymbol.h"
|
||||
+#include "bar_status.h"
|
||||
+#include "bar_tags.h"
|
||||
+#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,180 @@
|
||||
From bef83ecfe66bb83a8420239f8c068cf60d2c3e0c Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:07:02 +0100
|
||||
Subject: [PATCH 2/2] Adding awesomebar barmodules patch.
|
||||
|
||||
Note that this patch does not come with bound ClkWinTitle button click
|
||||
actions for extra behaviour when clicking on the window name in the bar.
|
||||
|
||||
The original bartabgroups patch included hardcoded focus on click which
|
||||
has been replaced with a generic click for barmodules.
|
||||
|
||||
The intention here is that this is combined with the wintitleactions
|
||||
patch that allow clients to be focused, zoomed and hidden - functionality
|
||||
that has been separated from the original awesomebar patch.
|
||||
|
||||
In other words, all this patch does is showing all window titles in the
|
||||
title bar with an even split between them.
|
||||
---
|
||||
config.def.h | 2 +-
|
||||
patch/bar_awesomebar.c | 94 ++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_awesomebar.h | 3 ++
|
||||
patch/include.c | 3 +-
|
||||
patch/include.h | 3 +-
|
||||
5 files changed, 102 insertions(+), 3 deletions(-)
|
||||
create mode 100644 patch/bar_awesomebar.c
|
||||
create mode 100644 patch/bar_awesomebar.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..74ad870 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -48,7 +48,7 @@ static const BarRule barrules[] = {
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
- { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
+ { -1, 0, BAR_ALIGN_NONE, width_awesomebar, draw_awesomebar, click_awesomebar, "awesomebar" },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/patch/bar_awesomebar.c b/patch/bar_awesomebar.c
|
||||
new file mode 100644
|
||||
index 0000000..aa2e2e5
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_awesomebar.c
|
||||
@@ -0,0 +1,94 @@
|
||||
+int
|
||||
+width_awesomebar(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return a->max_width;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_awesomebar(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ int n = 0, scm, remainder = 0, tabw, pad;
|
||||
+ unsigned int i;
|
||||
+ #if BAR_TITLE_LEFT_PAD && BAR_TITLE_RIGHT_PAD
|
||||
+ int x = a->x + lrpad / 2, w = a->w - lrpad;
|
||||
+ #elif BAR_TITLE_LEFT_PAD
|
||||
+ int x = a->x + lrpad / 2, w = a->w - lrpad / 2;
|
||||
+ #elif BAR_TITLE_RIGHT_PAD
|
||||
+ int x = a->x, w = a->w - lrpad / 2;
|
||||
+ #else
|
||||
+ int x = a->x, w = a->w;
|
||||
+ #endif // BAR_TITLE_LEFT_PAD | BAR_TITLE_RIGHT_PAD
|
||||
+
|
||||
+ Client *c;
|
||||
+ for (c = bar->mon->clients; c; c = c->next)
|
||||
+ if (ISVISIBLE(c))
|
||||
+ n++;
|
||||
+
|
||||
+ if (n > 0) {
|
||||
+ remainder = w % n;
|
||||
+ tabw = w / n;
|
||||
+ for (i = 0, c = bar->mon->clients; c; c = c->next, i++) {
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ if (bar->mon->sel == c)
|
||||
+ #if BAR_VTCOLORS_PATCH
|
||||
+ scm = SchemeTitleSel;
|
||||
+ #elif BAR_TITLECOLOR_PATCH
|
||||
+ scm = SchemeTitle;
|
||||
+ #else
|
||||
+ scm = SchemeSel;
|
||||
+ #endif // BAR_VTCOLORS_PATCH / BAR_TITLECOLOR_PATCH
|
||||
+ #ifdef HIDDEN
|
||||
+ else if (HIDDEN(c))
|
||||
+ scm = SchemeHid;
|
||||
+ #endif
|
||||
+ else
|
||||
+ #if BAR_VTCOLORS_PATCH
|
||||
+ scm = SchemeTitleNorm;
|
||||
+ #else
|
||||
+ scm = SchemeNorm;
|
||||
+ #endif // BAR_VTCOLORS_PATCH
|
||||
+
|
||||
+ pad = lrpad / 2;
|
||||
+ #if BAR_CENTEREDWINDOWNAME_PATCH
|
||||
+ if (TEXTW(c->name) < tabw)
|
||||
+ pad = (tabw - TEXTW(c->name) + lrpad) / 2;
|
||||
+ #endif // BAR_CENTEREDWINDOWNAME_PATCH
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[scm]);
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ drw_text(drw, x, 0, tabw + (i < remainder ? 1 : 0), bh, pad, c->name, 0, False);
|
||||
+ #else
|
||||
+ drw_text(drw, x, 0, tabw + (i < remainder ? 1 : 0), bh, pad, c->name, 0);
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+ x += tabw + (i < remainder ? 1 : 0);
|
||||
+ }
|
||||
+ }
|
||||
+ return a->x + a->w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_awesomebar(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ int x = 0, n = 0;
|
||||
+ Client *c;
|
||||
+
|
||||
+ for (c = bar->mon->clients; c; c = c->next)
|
||||
+ if (ISVISIBLE(c))
|
||||
+ n++;
|
||||
+
|
||||
+ c = bar->mon->clients;
|
||||
+
|
||||
+ do {
|
||||
+ if (!c || !ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ else
|
||||
+ x += (1.0 / (double)n) * a->rel_w;
|
||||
+ } while (c && a->rel_x > x && (c = c->next));
|
||||
+
|
||||
+ if (c) {
|
||||
+ arg->v = c;
|
||||
+ return ClkWinTitle;
|
||||
+ }
|
||||
+ return -1;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_awesomebar.h b/patch/bar_awesomebar.h
|
||||
new file mode 100644
|
||||
index 0000000..3269954
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_awesomebar.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_awesomebar(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_awesomebar(Bar *bar, BarDrawArg *a);
|
||||
+static int click_awesomebar(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..6ae83ed 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+//#include "bar_wintitle.c"
|
||||
+#include "bar_awesomebar.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..de77a11 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+//#include "bar_wintitle.h"
|
||||
+#include "bar_awesomebar.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,351 @@
|
||||
From d8f276471e66eb7a4d9f5bcf23964f0e37be1db9 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:07:45 +0100
|
||||
Subject: [PATCH 2/2] Adding bartabgroups barmodules patch.
|
||||
|
||||
Note that this patch does not come with bound ClkWinTitle button click
|
||||
actions for extra behaviour when clicking on the window name in the bar.
|
||||
|
||||
The original bartabgroups patch included hardcoded focus on click which
|
||||
has been replaced with a generic click for barmodules.
|
||||
|
||||
The intention here is that this is combined with the wintitleactions
|
||||
patch that adds options such as allowing clients to be focused and
|
||||
hidden - functionality that has been separated from the awesomebar patch.
|
||||
---
|
||||
config.def.h | 5 +-
|
||||
dwm.c | 2 +-
|
||||
patch/bar_tabgroups.c | 233 ++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_tabgroups.h | 7 ++
|
||||
patch/include.c | 3 +-
|
||||
patch/include.h | 3 +-
|
||||
6 files changed, 249 insertions(+), 4 deletions(-)
|
||||
create mode 100644 patch/bar_tabgroups.c
|
||||
create mode 100644 patch/bar_tabgroups.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..1324c30 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -7,6 +7,7 @@ static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
+static void (*bartabmonfns[])(Monitor *) = { monocle /* , customlayoutfn */ };
|
||||
static const char col_gray1[] = "#222222";
|
||||
static const char col_gray2[] = "#444444";
|
||||
static const char col_gray3[] = "#bbbbbb";
|
||||
@@ -16,6 +17,8 @@ static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeTabActive] = { col_gray2, col_gray3, col_gray2 },
|
||||
+ [SchemeTabInactive] = { col_gray1, col_gray3, col_gray1 },
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
@@ -48,7 +51,7 @@ static const BarRule barrules[] = {
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
- { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
+ { -1, 0, BAR_ALIGN_NONE, width_bartabgroups, draw_bartabgroups, click_bartabgroups, "bartabgroups" },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..ba80bc9 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
-enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeTabActive, SchemeTabInactive }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
diff --git a/patch/bar_tabgroups.c b/patch/bar_tabgroups.c
|
||||
new file mode 100644
|
||||
index 0000000..116ddc7
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_tabgroups.c
|
||||
@@ -0,0 +1,233 @@
|
||||
+/* Bartabgroups properties, you can override these in your config.h if you want. */
|
||||
+#ifndef BARTAB_BORDERS
|
||||
+#define BARTAB_BORDERS 1 // 0 = off, 1 = on
|
||||
+#endif
|
||||
+#ifndef BARTAB_TAGSINDICATOR
|
||||
+#define BARTAB_TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on
|
||||
+#endif
|
||||
+#ifndef BARTAB_TAGSPX
|
||||
+#define BARTAB_TAGSPX 5 // # pixels for tag grid boxes
|
||||
+#endif
|
||||
+#ifndef BARTAB_TAGSROWS
|
||||
+#define BARTAB_TAGSROWS 3 // # rows in tag grid (9 tags, e.g. 3x3)
|
||||
+#endif
|
||||
+#ifndef BARTAB_SHOWFLOATING
|
||||
+#define BARTAB_SHOWFLOATING 0 // whether to show titles for floating windows, hidden clients are always shown
|
||||
+#endif
|
||||
+#ifndef BARTAB_STACKWEIGHT
|
||||
+#define BARTAB_STACKWEIGHT 1 // stack weight compared to hidden and floating window titles
|
||||
+#endif
|
||||
+#ifndef BARTAB_HIDDENWEIGHT
|
||||
+#define BARTAB_HIDDENWEIGHT 1 // hidden window title weight
|
||||
+#endif
|
||||
+#ifndef BARTAB_FLOATWEIGHT
|
||||
+#define BARTAB_FLOATWEIGHT 1 // floating window title weight, set to 0 to not show floating windows
|
||||
+#endif
|
||||
+
|
||||
+int
|
||||
+width_bartabgroups(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return a->max_width;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_bartabgroups(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ drw_rect(drw, a->x, 0, a->w, bh, 1, 1);
|
||||
+ bartabcalculate(bar->mon, a->x, a->w, -1, bartabdraw, NULL);
|
||||
+ return a->x + a->w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_bartabgroups(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ bartabcalculate(bar->mon, 0, a->rel_w, a->rel_x, bartabclick, arg);
|
||||
+ return ClkWinTitle;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg)
|
||||
+{
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ int i, nclienttags = 0, nviewtags = 0;
|
||||
+ drw_setscheme(drw, scheme[
|
||||
+ m->sel == c
|
||||
+ ? SchemeSel
|
||||
+ #ifdef HIDDEN
|
||||
+ : HIDDEN(c)
|
||||
+ ? SchemeHid
|
||||
+ #endif
|
||||
+ : groupactive
|
||||
+ ? SchemeTabActive
|
||||
+ : SchemeTabInactive
|
||||
+ ]);
|
||||
+ drw_text(drw, x, 0, w, bh, lrpad / 2, c->name, 0);
|
||||
+ if (c->isfloating)
|
||||
+ drw_rect(drw, x + 2, 2, 5, 5, 0, 0);
|
||||
+
|
||||
+ if (BARTAB_BORDERS) {
|
||||
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeSel][ColBorder].pixel);
|
||||
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, 0, 1, bh);
|
||||
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x + w, 0, 1, bh);
|
||||
+ }
|
||||
+ /* Optional tags icons */
|
||||
+ for (i = 0; i < LENGTH(tags); i++) {
|
||||
+ if ((m->tagset[m->seltags] >> i) & 1)
|
||||
+ nviewtags++;
|
||||
+ if ((c->tags >> i) & 1)
|
||||
+ nclienttags++;
|
||||
+ }
|
||||
+
|
||||
+ if (BARTAB_TAGSINDICATOR == 2 || nclienttags > 1 || nviewtags > 1) {
|
||||
+ for (i = 0; i < LENGTH(tags); i++) {
|
||||
+ drw_rect(drw,
|
||||
+ ( x + w - 2 - ((LENGTH(tags) / BARTAB_TAGSROWS) * BARTAB_TAGSPX)
|
||||
+ - (i % (LENGTH(tags)/BARTAB_TAGSROWS)) + ((i % (LENGTH(tags) / BARTAB_TAGSROWS)) * BARTAB_TAGSPX)
|
||||
+ ),
|
||||
+ ( 2 + ((i / (LENGTH(tags)/BARTAB_TAGSROWS)) * BARTAB_TAGSPX)
|
||||
+ - ((i / (LENGTH(tags)/BARTAB_TAGSROWS)))
|
||||
+ ),
|
||||
+ BARTAB_TAGSPX, BARTAB_TAGSPX, (c->tags >> i) & 1, 0
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#ifndef HIDDEN
|
||||
+#define HIDDEN(C) 0
|
||||
+#endif
|
||||
+
|
||||
+void
|
||||
+bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg)
|
||||
+{
|
||||
+ if (passx >= x && passx <= x + w)
|
||||
+ arg->v = c;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+bartabcalculate(
|
||||
+ Monitor *m, int offx, int tabw, int passx,
|
||||
+ void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg), Arg *arg
|
||||
+) {
|
||||
+ Client *c;
|
||||
+ int
|
||||
+ i, clientsnmaster = 0, clientsnstack = 0, clientsnfloating = 0, clientsnhidden = 0,
|
||||
+ masteractive = 0, fulllayout = 0,
|
||||
+ x = offx, w, r, num = 0, den, tgactive;
|
||||
+
|
||||
+ for (i = 0; i < LENGTH(bartabmonfns); i++)
|
||||
+ if (m ->lt[m->sellt]->arrange == bartabmonfns[i]) {
|
||||
+ fulllayout = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0, c = m->clients; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ if (HIDDEN(c)) {
|
||||
+ clientsnhidden++;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (c->isfloating) {
|
||||
+ clientsnfloating++;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (m->sel == c)
|
||||
+ masteractive = i < m->nmaster;
|
||||
+ if (i < m->nmaster)
|
||||
+ clientsnmaster++;
|
||||
+ else
|
||||
+ clientsnstack++;
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ if (clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden == 0)
|
||||
+ return;
|
||||
+
|
||||
+ tgactive = 1;
|
||||
+ num = tabw;
|
||||
+ /* floating mode */
|
||||
+ if ((fulllayout && BARTAB_FLOATWEIGHT) || clientsnmaster + clientsnstack == 0 || !m->lt[m->sellt]->arrange) {
|
||||
+ den = clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden;
|
||||
+ r = num % den;
|
||||
+ w = num / den;
|
||||
+ for (c = m->clients, i = 0; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg);
|
||||
+ x += w + (i < r ? 1 : 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+ /* no master and stack mode, e.g. monocole, grid layouts, fibonacci */
|
||||
+ } else if (fulllayout) {
|
||||
+ den = clientsnmaster + clientsnstack + clientsnhidden;
|
||||
+ r = num % den;
|
||||
+ w = num / den;
|
||||
+ for (c = m->clients, i = 0; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c) || (c->isfloating && !HIDDEN(c)))
|
||||
+ continue;
|
||||
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg);
|
||||
+ x += w + (i < r ? 1 : 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+ /* tiled mode */
|
||||
+ } else {
|
||||
+ den = clientsnmaster;
|
||||
+ c = m->clients;
|
||||
+ i = 0;
|
||||
+ if (den) {
|
||||
+ if (clientsnstack + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden) {
|
||||
+ tgactive = masteractive;
|
||||
+ num = tabw * m->mfact;
|
||||
+ }
|
||||
+ r = num % den;
|
||||
+ w = num / den;
|
||||
+ for (; c && i < m->nmaster; c = c->next) { // tiled master
|
||||
+ if (!ISVISIBLE(c) || c->isfloating || HIDDEN(c))
|
||||
+ continue;
|
||||
+ tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg);
|
||||
+ x += w + (i < r ? 1 : 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+ tgactive = !tgactive;
|
||||
+ num = tabw - num;
|
||||
+ }
|
||||
+
|
||||
+ den = clientsnstack * BARTAB_STACKWEIGHT + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden * BARTAB_HIDDENWEIGHT;
|
||||
+ if (!den)
|
||||
+ return;
|
||||
+
|
||||
+ r = num % den;
|
||||
+ w = num / den;
|
||||
+ #if BARTAB_STACKWEIGHT
|
||||
+ for (; c; c = c->next) { // tiled stack
|
||||
+ if (!ISVISIBLE(c) || HIDDEN(c) || c->isfloating)
|
||||
+ continue;
|
||||
+ tabfn(m, c, passx, x, w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg);
|
||||
+ x += w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+ #endif // BARTAB_STACKWEIGHT
|
||||
+
|
||||
+ #if BARTAB_HIDDENWEIGHT
|
||||
+ for (c = m->clients; c; c = c->next) { // hidden windows
|
||||
+ if (!ISVISIBLE(c) || !HIDDEN(c))
|
||||
+ continue;
|
||||
+ tabfn(m, c, passx, x, w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg);
|
||||
+ x += w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+ #endif // BARTAB_HIDDENWEIGHT
|
||||
+
|
||||
+ #if BARTAB_FLOATWEIGHT
|
||||
+ for (c = m->clients; c; c = c->next) { // floating windows
|
||||
+ if (!ISVISIBLE(c) || HIDDEN(c) || !c->isfloating)
|
||||
+ continue;
|
||||
+ tabfn(m, c, passx, x, w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg);
|
||||
+ x += w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0);
|
||||
+ i++;
|
||||
+ }
|
||||
+ #endif // BARTAB_FLOATWEIGHT
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_tabgroups.h b/patch/bar_tabgroups.h
|
||||
new file mode 100644
|
||||
index 0000000..15f6876
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_tabgroups.h
|
||||
@@ -0,0 +1,7 @@
|
||||
+static int width_bartabgroups(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_bartabgroups(Bar *bar, BarDrawArg *a);
|
||||
+static int click_bartabgroups(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+
|
||||
+static void bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg);
|
||||
+static void bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg);
|
||||
+static void bartabcalculate(Monitor *m, int offx, int w, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg), Arg *arg);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..a1885ed 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+// #include "bar_wintitle.c"
|
||||
+#include "bar_tabgroups.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..a024a16 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+// #include "bar_wintitle.h"
|
||||
+#include "bar_tabgroups.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,157 @@
|
||||
From 01bd1d40399c4ee4b73216ab894d65bf29c01d93 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:08:23 +0100
|
||||
Subject: [PATCH 2/2] Adding fancybar module
|
||||
|
||||
---
|
||||
config.def.h | 2 +-
|
||||
patch/bar_fancybar.c | 84 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_fancybar.h | 3 ++
|
||||
patch/include.c | 3 +-
|
||||
patch/include.h | 3 +-
|
||||
5 files changed, 92 insertions(+), 3 deletions(-)
|
||||
create mode 100644 patch/bar_fancybar.c
|
||||
create mode 100644 patch/bar_fancybar.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..59c1b42 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -48,7 +48,7 @@ static const BarRule barrules[] = {
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
- { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
+ { -1, 0, BAR_ALIGN_NONE, width_fancybar, draw_fancybar, click_fancybar, "fancybar" },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/patch/bar_fancybar.c b/patch/bar_fancybar.c
|
||||
new file mode 100644
|
||||
index 0000000..810026d
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_fancybar.c
|
||||
@@ -0,0 +1,84 @@
|
||||
+int
|
||||
+width_fancybar(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return a->max_width;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_fancybar(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ int ftw, mw, ew = 0, n = 0;
|
||||
+ unsigned int i;
|
||||
+ Client *c;
|
||||
+ Monitor *m = bar->mon;
|
||||
+
|
||||
+ int boxs = drw->fonts->h / 9;
|
||||
+ int boxw = drw->fonts->h / 6 + 2;
|
||||
+ #if BAR_TITLE_LEFT_PAD && BAR_TITLE_RIGHT_PAD
|
||||
+ int x = a->x + lrpad / 2, w = a->w - lrpad;
|
||||
+ #elif BAR_TITLE_LEFT_PAD
|
||||
+ int x = a->x + lrpad / 2, w = a->w - lrpad / 2;
|
||||
+ #elif BAR_TITLE_RIGHT_PAD
|
||||
+ int x = a->x, w = a->w - lrpad / 2;
|
||||
+ #else
|
||||
+ int x = a->x, w = a->w;
|
||||
+ #endif // BAR_TITLE_LEFT_PAD | BAR_TITLE_RIGHT_PAD
|
||||
+
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (ISVISIBLE(c))
|
||||
+ n++;
|
||||
+ }
|
||||
+
|
||||
+ if (n > 0) {
|
||||
+ ftw = TEXTW(m->sel->name);
|
||||
+ mw = (ftw >= w || n == 1) ? 0 : (w - ftw) / (n - 1);
|
||||
+
|
||||
+ i = 0;
|
||||
+
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c) || c == m->sel)
|
||||
+ continue;
|
||||
+ ftw = TEXTW(c->name);
|
||||
+ if (ftw < mw)
|
||||
+ ew += (mw - ftw);
|
||||
+ else
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ if (i > 0)
|
||||
+ mw += ew / i;
|
||||
+
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ ftw = MIN(m->sel == c ? w : mw, TEXTW(c->name));
|
||||
+
|
||||
+ #if BAR_VTCOLORS_PATCH
|
||||
+ drw_setscheme(drw, scheme[m->sel == c ? SchemeTitleSel : SchemeTitleNorm]);
|
||||
+ #elif BAR_TITLECOLOR_PATCH
|
||||
+ drw_setscheme(drw, scheme[m->sel == c ? SchemeTitle : SchemeNorm]);
|
||||
+ #else
|
||||
+ drw_setscheme(drw, scheme[m->sel == c ? SchemeSel : SchemeNorm]);
|
||||
+ #endif // BAR_VTCOLORS_PATCH / BAR_TITLECOLOR_PATCH
|
||||
+ if (ftw > 0) /* trap special handling of 0 in drw_text */
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ drw_text(drw, x, 0, ftw, bh, lrpad / 2, c->name, 0, False);
|
||||
+ #else
|
||||
+ drw_text(drw, x, 0, ftw, bh, lrpad / 2, c->name, 0);
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+ if (c->isfloating)
|
||||
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, c->isfixed, 0);
|
||||
+ x += ftw;
|
||||
+ w -= ftw;
|
||||
+ }
|
||||
+ }
|
||||
+ return x + w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_fancybar(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkWinTitle;
|
||||
+}
|
||||
+
|
||||
+
|
||||
diff --git a/patch/bar_fancybar.h b/patch/bar_fancybar.h
|
||||
new file mode 100644
|
||||
index 0000000..c90d189
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_fancybar.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_fancybar(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_fancybar(Bar *bar, BarDrawArg *a);
|
||||
+static int click_fancybar(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..2ab4594 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+//#include "bar_wintitle.c"
|
||||
+#include "bar_fancybar.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..4eab55d 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+//#include "bar_wintitle.h"
|
||||
+#include "bar_fancybar.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,479 @@
|
||||
From 97343b7b17a3bdc111768f026e8532b93143d409 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:08:58 +0100
|
||||
Subject: [PATCH 2/2] Adding powerline module
|
||||
|
||||
---
|
||||
config.def.h | 10 ++-
|
||||
drw.c | 41 +++++++++++
|
||||
drw.h | 2 +
|
||||
dwm.c | 7 ++
|
||||
patch/bar_powerline_status.c | 121 +++++++++++++++++++++++++++++++++
|
||||
patch/bar_powerline_status.h | 11 +++
|
||||
patch/bar_powerline_tags.c | 127 +++++++++++++++++++++++++++++++++++
|
||||
patch/bar_powerline_tags.h | 3 +
|
||||
patch/include.c | 8 ++-
|
||||
patch/include.h | 8 ++-
|
||||
10 files changed, 330 insertions(+), 8 deletions(-)
|
||||
create mode 100644 patch/bar_powerline_status.c
|
||||
create mode 100644 patch/bar_powerline_status.h
|
||||
create mode 100644 patch/bar_powerline_tags.c
|
||||
create mode 100644 patch/bar_powerline_tags.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..1187340 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -18,6 +18,12 @@ static const char *colors[][3] = {
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
};
|
||||
|
||||
+static const char *statuscolors[][3] = {
|
||||
+ /* fg bg border */
|
||||
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+};
|
||||
+
|
||||
/* tagging */
|
||||
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
|
||||
@@ -45,9 +51,9 @@ static const Rule rules[] = {
|
||||
*/
|
||||
static const BarRule barrules[] = {
|
||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
- { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
+ { -1, 0, BAR_ALIGN_LEFT, width_pwrl_tags, draw_pwrl_tags, click_pwrl_tags, "powerline_tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
- { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
+ { 'A', 0, BAR_ALIGN_RIGHT, width_pwrl_status, draw_pwrl_status, click_pwrl_status, "powerline_status" },
|
||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
};
|
||||
|
||||
diff --git a/drw.c b/drw.c
|
||||
index 4cdbcbe..522fc79 100644
|
||||
--- a/drw.c
|
||||
+++ b/drw.c
|
||||
@@ -15,6 +15,7 @@ static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}
|
||||
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||
+Clr transcheme[3];
|
||||
|
||||
static long
|
||||
utf8decodebyte(const char c, size_t *i)
|
||||
@@ -236,6 +237,15 @@ drw_setscheme(Drw *drw, Clr *scm)
|
||||
drw->scheme = scm;
|
||||
}
|
||||
|
||||
+void
|
||||
+drw_settrans(Drw *drw, Clr *psc, Clr *nsc)
|
||||
+{
|
||||
+ if (drw) {
|
||||
+ transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder];
|
||||
+ drw->scheme = transcheme;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
|
||||
{
|
||||
@@ -379,6 +389,37 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
return x + (render ? w : 0);
|
||||
}
|
||||
|
||||
+void
|
||||
+drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash)
|
||||
+{
|
||||
+ if (!drw || !drw->scheme)
|
||||
+ return;
|
||||
+
|
||||
+ /* direction=1 draws right arrow */
|
||||
+ x = direction ? x : x + w;
|
||||
+ w = direction ? w : -w;
|
||||
+ /* slash=1 draws slash instead of arrow */
|
||||
+ unsigned int hh = slash ? (direction ? 0 : h) : h/2;
|
||||
+
|
||||
+ XPoint points[] = {
|
||||
+ {x , y },
|
||||
+ {x + w, y + hh },
|
||||
+ {x , y + h },
|
||||
+ };
|
||||
+
|
||||
+ XPoint bg[] = {
|
||||
+ {x , y },
|
||||
+ {x + w, y },
|
||||
+ {x + w, y + h},
|
||||
+ {x , y + h},
|
||||
+ };
|
||||
+
|
||||
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
|
||||
+ XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin);
|
||||
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
|
||||
+ XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin);
|
||||
+}
|
||||
+
|
||||
void
|
||||
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||
{
|
||||
diff --git a/drw.h b/drw.h
|
||||
index 4bcd5ad..4a42557 100644
|
||||
--- a/drw.h
|
||||
+++ b/drw.h
|
||||
@@ -48,10 +48,12 @@ void drw_cur_free(Drw *drw, Cur *cursor);
|
||||
/* Drawing context manipulation */
|
||||
void drw_setfontset(Drw *drw, Fnt *set);
|
||||
void drw_setscheme(Drw *drw, Clr *scm);
|
||||
+void drw_settrans(Drw *drw, Clr *psc, Clr *nsc);
|
||||
|
||||
/* Drawing functions */
|
||||
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
|
||||
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
|
||||
+void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash);
|
||||
|
||||
/* Map functions */
|
||||
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..48905e3 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1730,6 +1730,13 @@ setup(void)
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||
+ statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *));
|
||||
+ for (i = 0; i < LENGTH(statuscolors); i++)
|
||||
+ #if BAR_ALPHA_PATCH
|
||||
+ statusscheme[i] = drw_scm_create(drw, statuscolors[i], alphas[0], ColCount);
|
||||
+ #else
|
||||
+ statusscheme[i] = drw_scm_create(drw, statuscolors[i], 3);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
/* init bars */
|
||||
updatebars();
|
||||
updatestatus();
|
||||
diff --git a/patch/bar_powerline_status.c b/patch/bar_powerline_status.c
|
||||
new file mode 100644
|
||||
index 0000000..3e2ee6a
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_powerline_status.c
|
||||
@@ -0,0 +1,121 @@
|
||||
+static Clr **statusscheme;
|
||||
+
|
||||
+int
|
||||
+width_pwrl_status(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return widthpowerlinestatus(rawstext);
|
||||
+ #else
|
||||
+ return widthpowerlinestatus(stext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+int
|
||||
+width_pwrl_status_es(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return widthpowerlinestatus(rawestext);
|
||||
+ #else
|
||||
+ return widthpowerlinestatus(estext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+
|
||||
+int
|
||||
+draw_pwrl_status(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return drawpowerlinestatus(a->x + a->w, rawstext);
|
||||
+ #else
|
||||
+ return drawpowerlinestatus(a->x + a->w, stext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+int
|
||||
+draw_pwrl_status_es(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return drawpowerlinestatus(a->x + a->w, rawestext);
|
||||
+ #else
|
||||
+ return drawpowerlinestatus(a->x + a->w, estext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+
|
||||
+int
|
||||
+click_pwrl_status(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkStatusText;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+widthpowerlinestatus(char *stext)
|
||||
+{
|
||||
+ char status[512];
|
||||
+ int w = 0, i, n = strlen(stext);
|
||||
+ int plw = drw->fonts->h / 2 + 1;
|
||||
+ char *bs, bp = '|';
|
||||
+ strcpy(status, stext);
|
||||
+
|
||||
+ for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) {
|
||||
+ if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */
|
||||
+ if (bp != '|')
|
||||
+ w += plw;
|
||||
+ w += TEXTW(bs+2);
|
||||
+ bp = *bs;
|
||||
+ *bs = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (bp != '|')
|
||||
+ w += plw * 2;
|
||||
+
|
||||
+ return w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+drawpowerlinestatus(int xpos, char *stext)
|
||||
+{
|
||||
+ char status[512];
|
||||
+ int i, n = strlen(stext), cn = 0;
|
||||
+ int x = xpos, w = 0;
|
||||
+ int plw = drw->fonts->h / 2 + 1;
|
||||
+ char *bs, bp = '|';
|
||||
+ Clr *prevscheme = statusscheme[0], *nxtscheme;
|
||||
+ strcpy(status, stext);
|
||||
+
|
||||
+ for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) {
|
||||
+ if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */
|
||||
+ cn = ((int) *(bs+1)) - 1;
|
||||
+
|
||||
+ if (cn < LENGTH(statuscolors)) {
|
||||
+ drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[cn]));
|
||||
+ } else {
|
||||
+ drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[0]));
|
||||
+ }
|
||||
+
|
||||
+ if (bp != '|') {
|
||||
+ drw_arrow(drw, x - plw, 0, plw, bh, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1);
|
||||
+ x -= plw;
|
||||
+ }
|
||||
+
|
||||
+ drw_setscheme(drw, nxtscheme);
|
||||
+ w = TEXTW(bs+2);
|
||||
+ drw_text(drw, x - w, 0, w, bh, lrpad / 2, bs+2, 0);
|
||||
+ x -= w;
|
||||
+
|
||||
+ bp = *bs;
|
||||
+ *bs = 0;
|
||||
+ prevscheme = nxtscheme;
|
||||
+ }
|
||||
+ }
|
||||
+ if (bp != '|') {
|
||||
+ drw_settrans(drw, prevscheme, scheme[SchemeNorm]);
|
||||
+ drw_arrow(drw, x - plw, 0, plw, bh, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1);
|
||||
+ drw_rect(drw, x - 2 * plw, 0, plw, bh, 1, 1);
|
||||
+ x -= plw * 2;
|
||||
+ }
|
||||
+
|
||||
+ return xpos - x;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_powerline_status.h b/patch/bar_powerline_status.h
|
||||
new file mode 100644
|
||||
index 0000000..2ff5ad2
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_powerline_status.h
|
||||
@@ -0,0 +1,11 @@
|
||||
+static int width_pwrl_status(Bar *bar, BarWidthArg *a);
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+static int width_pwrl_status_es(Bar *bar, BarWidthArg *a);
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+static int draw_pwrl_status(Bar *bar, BarDrawArg *a);
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+static int draw_pwrl_status_es(Bar *bar, BarDrawArg *a);
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+static int click_pwrl_status(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+static int drawpowerlinestatus(int x, char *stext);
|
||||
+static int widthpowerlinestatus(char *stext);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_powerline_tags.c b/patch/bar_powerline_tags.c
|
||||
new file mode 100644
|
||||
index 0000000..a85559b
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_powerline_tags.c
|
||||
@@ -0,0 +1,127 @@
|
||||
+int
|
||||
+width_pwrl_tags(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ int w, i;
|
||||
+ int plw = drw->fonts->h / 2 + 1;
|
||||
+ #if BAR_HIDEVACANTTAGS_PATCH
|
||||
+ Client *c;
|
||||
+ unsigned int occ = 0;
|
||||
+ for (c = bar->mon->clients; c; c = c->next)
|
||||
+ occ |= c->tags == 255 ? 0 : c->tags;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+
|
||||
+ for (w = 0, i = 0; i < LENGTH(tags); i++) {
|
||||
+ #if BAR_HIDEVACANTTAGS_PATCH
|
||||
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
|
||||
+ continue;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+ #if BAR_ALTERNATIVE_TAGS_PATCH
|
||||
+ w += selmon->alttag ? TEXTW(tagsalt[i]) : TEXTW(tags[i]) + plw;
|
||||
+ #else
|
||||
+ w += TEXTW(tags[i]) + plw;
|
||||
+ #endif // BAR_ALTERNATIVE_TAGS_PATCH
|
||||
+ }
|
||||
+ return w + lrpad;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_pwrl_tags(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ int x, w;
|
||||
+ int invert;
|
||||
+ int plw = drw->fonts->h / 2 + 1;
|
||||
+ unsigned int i, occ = 0, urg = 0;
|
||||
+ Client *c;
|
||||
+ Clr *prevscheme, *nxtscheme;
|
||||
+ #if !BAR_HIDEVACANTTAGS_PATCH
|
||||
+ #if !BAR_ACTIVETAGINDICATORBAR_PATCH && !BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH
|
||||
+ int boxs = drw->fonts->h / 9;
|
||||
+ #endif // BAR_ACTIVETAGINDICATORBAR_PATCH | BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH
|
||||
+ int boxw = drw->fonts->h / 6 + 2;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+
|
||||
+ for (c = bar->mon->clients; c; c = c->next) {
|
||||
+ #if BAR_HIDEVACANTTAGS_PATCH
|
||||
+ occ |= c->tags == 255 ? 0 : c->tags;
|
||||
+ #else
|
||||
+ occ |= c->tags;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+ if (c->isurgent)
|
||||
+ urg |= c->tags;
|
||||
+ }
|
||||
+ x = a->x;
|
||||
+ prevscheme = scheme[SchemeNorm];
|
||||
+ for (i = 0; i < LENGTH(tags); i++) {
|
||||
+ #if BAR_HIDEVACANTTAGS_PATCH
|
||||
+ /* do not draw vacant tags */
|
||||
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
|
||||
+ continue;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+ #if URGENTBORDER_PATCH
|
||||
+ invert = 0;
|
||||
+ #else
|
||||
+ invert = urg & 1 << i;
|
||||
+ #endif // URGENTBORDER_PATCH
|
||||
+ w = TEXTW(tags[i]);
|
||||
+ drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeNorm]));
|
||||
+ #if BAR_POWERLINE_TAGS_SLASH_PATCH
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 1, 1);
|
||||
+ #else
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 1, 1);
|
||||
+ #endif // BAR_POWERLINE_TAGS_SLASH_PATCH
|
||||
+ x += plw;
|
||||
+ drw_setscheme(drw, nxtscheme);
|
||||
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], invert);
|
||||
+ #if !BAR_HIDEVACANTTAGS_PATCH
|
||||
+ if (occ & 1 << i)
|
||||
+ #if BAR_ACTIVETAGINDICATORBAR_PATCH
|
||||
+ drw_rect(drw, x + boxw, 0, w - ( 2 * boxw + 1), boxw,
|
||||
+ #elif BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH
|
||||
+ drw_rect(drw, x + boxw, bh - boxw/2, w - ( 2 * boxw + 1), boxw/2,
|
||||
+ #else
|
||||
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
|
||||
+ #endif // BAR_ACTIVETAGINDICATORBAR_PATCH
|
||||
+ bar->mon == selmon && selmon->sel && selmon->sel->tags & 1 << i, invert);
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+ x += w;
|
||||
+ prevscheme = nxtscheme;
|
||||
+ }
|
||||
+ nxtscheme = scheme[SchemeNorm];
|
||||
+
|
||||
+ drw_settrans(drw, prevscheme, nxtscheme);
|
||||
+ #if BAR_POWERLINE_TAGS_SLASH_PATCH
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 1, 1);
|
||||
+ #else
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 1, 0);
|
||||
+ #endif // BAR_POWERLINE_TAGS_SLASH_PATCH
|
||||
+ return a->x + a->w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_pwrl_tags(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ int i = 0, x = lrpad / 2;
|
||||
+ int plw = drw->fonts->h / 2 + 1;
|
||||
+ #if BAR_HIDEVACANTTAGS_PATCH
|
||||
+ Client *c;
|
||||
+ unsigned int occ = 0;
|
||||
+ for (c = bar->mon->clients; c; c = c->next)
|
||||
+ occ |= c->tags == 255 ? 0 : c->tags;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+
|
||||
+ do {
|
||||
+ #if BAR_HIDEVACANTTAGS_PATCH
|
||||
+ if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i))
|
||||
+ continue;
|
||||
+ #endif // BAR_HIDEVACANTTAGS_PATCH
|
||||
+ #if BAR_ALTERNATIVE_TAGS_PATCH
|
||||
+ x += selmon->alttag ? TEXTW(tagsalt[i]) : TEXTW(tags[i]) + plw;
|
||||
+ #else
|
||||
+ x += TEXTW(tags[i]) + plw;
|
||||
+ #endif
|
||||
+ } while (a->rel_x >= x && ++i < LENGTH(tags));
|
||||
+ if (i < LENGTH(tags)) {
|
||||
+ arg->ui = 1 << i;
|
||||
+ }
|
||||
+ return ClkTagBar;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_powerline_tags.h b/patch/bar_powerline_tags.h
|
||||
new file mode 100644
|
||||
index 0000000..b1e0389
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_powerline_tags.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_pwrl_tags(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_pwrl_tags(Bar *bar, BarDrawArg *a);
|
||||
+static int click_pwrl_tags(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..48ce1cb 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -1,5 +1,7 @@
|
||||
/* Bar functionality */
|
||||
#include "bar_ltsymbol.c"
|
||||
-#include "bar_status.c"
|
||||
-#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+//#include "bar_status.c"
|
||||
+//#include "bar_tags.c"
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_powerline_tags.c"
|
||||
+#include "bar_powerline_status.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..b313ca4 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -1,5 +1,7 @@
|
||||
/* Bar functionality */
|
||||
#include "bar_ltsymbol.h"
|
||||
-#include "bar_status.h"
|
||||
-#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+//#include "bar_status.h"
|
||||
+//#include "bar_tags.h"
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_powerline_tags.h"
|
||||
+#include "bar_powerline_status.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,346 @@
|
||||
From 8592c59216ccdbaf3bfbc028130e116057517d0d Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:09:50 +0100
|
||||
Subject: [PATCH 2/2] Adding status2d module
|
||||
|
||||
---
|
||||
config.def.h | 2 +-
|
||||
dwm.c | 7 +-
|
||||
patch/bar_status2d.c | 225 +++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_status2d.h | 13 +++
|
||||
patch/include.c | 5 +-
|
||||
patch/include.h | 5 +-
|
||||
6 files changed, 249 insertions(+), 8 deletions(-)
|
||||
create mode 100644 patch/bar_status2d.c
|
||||
create mode 100644 patch/bar_status2d.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..299974a 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -47,7 +47,7 @@ static const BarRule barrules[] = {
|
||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
- { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
+ { 'A', 0, BAR_ALIGN_RIGHT, width_status2d, draw_status2d, click_status2d, "status2d" },
|
||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
};
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..10f9220 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -290,7 +290,7 @@ static void zoom(const Arg *arg);
|
||||
#include "patch/include.h"
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
-static char stext[256];
|
||||
+static char stext[1024];
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
static int bh; /* bar geometry */
|
||||
@@ -558,7 +558,7 @@ cleanup(void)
|
||||
cleanupmon(mons);
|
||||
for (i = 0; i < CurLast; i++)
|
||||
drw_cur_free(drw, cursor[i]);
|
||||
- for (i = 0; i < LENGTH(colors); i++)
|
||||
+ for (i = 0; i < LENGTH(colors) + 1; i++)
|
||||
free(scheme[i]);
|
||||
XDestroyWindow(dpy, wmcheckwin);
|
||||
drw_free(drw);
|
||||
@@ -1727,7 +1727,8 @@ setup(void)
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
||||
/* init appearance */
|
||||
- scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
+ scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
|
||||
+ scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||
/* init bars */
|
||||
diff --git a/patch/bar_status2d.c b/patch/bar_status2d.c
|
||||
new file mode 100644
|
||||
index 0000000..5863d44
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_status2d.c
|
||||
@@ -0,0 +1,225 @@
|
||||
+int
|
||||
+width_status2d(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return status2dtextlength(rawstext) + lrpad;
|
||||
+ #else
|
||||
+ return status2dtextlength(stext) + lrpad;
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+int
|
||||
+width_status2d_es(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return status2dtextlength(rawestext);
|
||||
+ #else
|
||||
+ return status2dtextlength(estext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+
|
||||
+int
|
||||
+draw_status2d(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return drawstatusbar(a->x, rawstext);
|
||||
+ #else
|
||||
+ return drawstatusbar(a->x, stext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+int
|
||||
+draw_status2d_es(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ return drawstatusbar(a->x, rawestext);
|
||||
+ #else
|
||||
+ return drawstatusbar(a->x, estext);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+}
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+
|
||||
+#if !BAR_STATUSCMD_PATCH
|
||||
+int
|
||||
+click_status2d(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkStatusText;
|
||||
+}
|
||||
+#endif // BAR_STATUSCMD_PATCH
|
||||
+
|
||||
+int
|
||||
+drawstatusbar(int x, char* stext)
|
||||
+{
|
||||
+ int i, w, len;
|
||||
+ short isCode = 0;
|
||||
+ char *text;
|
||||
+ char *p;
|
||||
+
|
||||
+ len = strlen(stext);
|
||||
+ if (!(text = (char*) malloc(sizeof(char)*(len + 1))))
|
||||
+ die("malloc");
|
||||
+ p = text;
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ copyvalidchars(text, stext);
|
||||
+ #else
|
||||
+ memcpy(text, stext, len);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+ text[len] = '\0';
|
||||
+
|
||||
+ x += lrpad / 2;
|
||||
+ drw_setscheme(drw, scheme[LENGTH(colors)]);
|
||||
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
|
||||
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
|
||||
+
|
||||
+ /* process status text */
|
||||
+ i = -1;
|
||||
+ while (text[++i]) {
|
||||
+ if (text[i] == '^' && !isCode) {
|
||||
+ isCode = 1;
|
||||
+
|
||||
+ text[i] = '\0';
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ w = TEXTWM(text) - lrpad;
|
||||
+ drw_text(drw, x, 0, w, bh, 0, text, 0, True);
|
||||
+ #else
|
||||
+ w = TEXTW(text) - lrpad;
|
||||
+ drw_text(drw, x, 0, w, bh, 0, text, 0);
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+
|
||||
+ x += w;
|
||||
+
|
||||
+ /* process code */
|
||||
+ while (text[++i] != '^') {
|
||||
+ if (text[i] == 'c') {
|
||||
+ char buf[8];
|
||||
+ if (i + 7 > len - 1) {
|
||||
+ i += 7;
|
||||
+ len = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ memcpy(buf, (char*)text+i+1, 7);
|
||||
+ buf[7] = '\0';
|
||||
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColFg], buf, 0xff);
|
||||
+ #elif BAR_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColFg], buf, alphas[SchemeNorm][ColFg]);
|
||||
+ #else
|
||||
+ drw_clr_create(drw, &drw->scheme[ColFg], buf);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ i += 7;
|
||||
+ } else if (text[i] == 'b') {
|
||||
+ char buf[8];
|
||||
+ if (i + 7 > len - 1) {
|
||||
+ i += 7;
|
||||
+ len = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ memcpy(buf, (char*)text+i+1, 7);
|
||||
+ buf[7] = '\0';
|
||||
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColBg], buf, 0xff);
|
||||
+ #elif BAR_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColBg], buf, alphas[SchemeNorm][ColBg]);
|
||||
+ #else
|
||||
+ drw_clr_create(drw, &drw->scheme[ColBg], buf);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ i += 7;
|
||||
+ } else if (text[i] == 'd') {
|
||||
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
|
||||
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
|
||||
+ } else if (text[i] == 'r') {
|
||||
+ int rx = atoi(text + ++i);
|
||||
+ while (text[++i] != ',');
|
||||
+ int ry = atoi(text + ++i);
|
||||
+ while (text[++i] != ',');
|
||||
+ int rw = atoi(text + ++i);
|
||||
+ while (text[++i] != ',');
|
||||
+ int rh = atoi(text + ++i);
|
||||
+
|
||||
+ if (ry < 0)
|
||||
+ ry = 0;
|
||||
+ if (rx < 0)
|
||||
+ rx = 0;
|
||||
+
|
||||
+ drw_rect(drw, rx + x, ry, rw, rh, 1, 0);
|
||||
+ } else if (text[i] == 'f') {
|
||||
+ x += atoi(text + ++i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ text = text + i + 1;
|
||||
+ len -= i + 1;
|
||||
+ i=-1;
|
||||
+ isCode = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!isCode && len) {
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ w = TEXTWM(text) - lrpad;
|
||||
+ drw_text(drw, x, 0, w, bh, 0, text, 0, True);
|
||||
+ #else
|
||||
+ w = TEXTW(text) - lrpad;
|
||||
+ drw_text(drw, x, 0, w, bh, 0, text, 0);
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+ x += w;
|
||||
+ }
|
||||
+ free(p);
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+
|
||||
+ return x;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+status2dtextlength(char* stext)
|
||||
+{
|
||||
+ int i, w, len;
|
||||
+ short isCode = 0;
|
||||
+ char *text;
|
||||
+ char *p;
|
||||
+
|
||||
+ len = strlen(stext) + 1;
|
||||
+ if (!(text = (char*) malloc(sizeof(char)*len)))
|
||||
+ die("malloc");
|
||||
+ p = text;
|
||||
+ #if BAR_STATUSCMD_PATCH
|
||||
+ copyvalidchars(text, stext);
|
||||
+ #else
|
||||
+ memcpy(text, stext, len);
|
||||
+ #endif // BAR_STATUSCMD_PATCH
|
||||
+
|
||||
+ /* compute width of the status text */
|
||||
+ w = 0;
|
||||
+ i = -1;
|
||||
+ while (text[++i]) {
|
||||
+ if (text[i] == '^') {
|
||||
+ if (!isCode) {
|
||||
+ isCode = 1;
|
||||
+ text[i] = '\0';
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ w += TEXTWM(text) - lrpad;
|
||||
+ #else
|
||||
+ w += TEXTW(text) - lrpad;
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+ text[i] = '^';
|
||||
+ if (text[++i] == 'f')
|
||||
+ w += atoi(text + ++i);
|
||||
+ } else {
|
||||
+ isCode = 0;
|
||||
+ text = text + i + 1;
|
||||
+ i = -1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (!isCode)
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ w += TEXTWM(text) - lrpad;
|
||||
+ #else
|
||||
+ w += TEXTW(text) - lrpad;
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+ free(p);
|
||||
+ return w;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_status2d.h b/patch/bar_status2d.h
|
||||
new file mode 100644
|
||||
index 0000000..ea48dd3
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_status2d.h
|
||||
@@ -0,0 +1,13 @@
|
||||
+static int width_status2d(Bar *bar, BarWidthArg *a);
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+static int width_status2d_es(Bar *bar, BarWidthArg *a);
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+static int draw_status2d(Bar *bar, BarDrawArg *a);
|
||||
+#if BAR_EXTRASTATUS_PATCH
|
||||
+static int draw_status2d_es(Bar *bar, BarDrawArg *a);
|
||||
+#endif // BAR_EXTRASTATUS_PATCH
|
||||
+#if !BAR_STATUSCMD_PATCH
|
||||
+static int click_status2d(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+#endif // BAR_STATUSCMD_PATCH
|
||||
+static int drawstatusbar(int x, char *text);
|
||||
+static int status2dtextlength(char *stext);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..77eafa3 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -1,5 +1,6 @@
|
||||
/* Bar functionality */
|
||||
#include "bar_ltsymbol.c"
|
||||
-#include "bar_status.c"
|
||||
+//#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_status2d.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..2927238 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -1,5 +1,6 @@
|
||||
/* Bar functionality */
|
||||
#include "bar_ltsymbol.h"
|
||||
-#include "bar_status.h"
|
||||
+//#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_status2d.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,459 @@
|
||||
From 69ba99292c4eac2ffa2eb1f1962f55ce463b35db Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:10:28 +0100
|
||||
Subject: [PATCH 2/2] Adding status2d + statuscmd + dwmblocks + extrastatus
|
||||
module
|
||||
|
||||
---
|
||||
config.def.h | 11 ++-
|
||||
dwm.c | 23 +++++-
|
||||
patch/bar_dwmblocks.c | 31 ++++++++
|
||||
patch/bar_dwmblocks.h | 2 +
|
||||
patch/bar_status2d.c | 171 ++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_status2d.h | 6 ++
|
||||
patch/bar_statuscmd.c | 49 ++++++++++++
|
||||
patch/bar_statuscmd.h | 4 +
|
||||
patch/include.c | 7 +-
|
||||
patch/include.h | 7 +-
|
||||
10 files changed, 301 insertions(+), 10 deletions(-)
|
||||
create mode 100644 patch/bar_dwmblocks.c
|
||||
create mode 100644 patch/bar_dwmblocks.h
|
||||
create mode 100644 patch/bar_status2d.c
|
||||
create mode 100644 patch/bar_status2d.h
|
||||
create mode 100644 patch/bar_statuscmd.c
|
||||
create mode 100644 patch/bar_statuscmd.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..af2aa90 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char statussep = ';'; /* separator between status bars */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -47,8 +48,10 @@ static const BarRule barrules[] = {
|
||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
- { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
+ { 'A', 0, BAR_ALIGN_RIGHT, width_status2d, draw_status2d, click_statuscmd, "status2d" },
|
||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
+ { 0, 1, BAR_ALIGN_CENTER, width_status2d_es, draw_status2d_es, click_statuscmd_es, "status2d_es" },
|
||||
+
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -124,7 +127,11 @@ static Button buttons[] = {
|
||||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
+ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1 } },
|
||||
+ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2 } },
|
||||
+ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3 } },
|
||||
+ { ClkStatusText, 0, Button4, sigdwmblocks, {.i = 4 } },
|
||||
+ { ClkStatusText, 0, Button5, sigdwmblocks, {.i = 5 } },
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..9fd8b67 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -290,7 +290,10 @@ static void zoom(const Arg *arg);
|
||||
#include "patch/include.h"
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
-static char stext[256];
|
||||
+static char stext[1024];
|
||||
+static char rawstext[1024];
|
||||
+static char estext[1024];
|
||||
+static char rawestext[1024];
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
static int bh; /* bar geometry */
|
||||
@@ -558,7 +561,7 @@ cleanup(void)
|
||||
cleanupmon(mons);
|
||||
for (i = 0; i < CurLast; i++)
|
||||
drw_cur_free(drw, cursor[i]);
|
||||
- for (i = 0; i < LENGTH(colors); i++)
|
||||
+ for (i = 0; i < LENGTH(colors) + 1; i++)
|
||||
free(scheme[i]);
|
||||
XDestroyWindow(dpy, wmcheckwin);
|
||||
drw_free(drw);
|
||||
@@ -1727,7 +1730,8 @@ setup(void)
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
||||
/* init appearance */
|
||||
- scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
+ scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
|
||||
+ scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||
/* init bars */
|
||||
@@ -2185,8 +2189,19 @@ void
|
||||
updatestatus(void)
|
||||
{
|
||||
Monitor *m;
|
||||
- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
||||
+ if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) {
|
||||
strcpy(stext, "dwm-"VERSION);
|
||||
+ estext[0] = '\0';
|
||||
+ } else {
|
||||
+ char *e = strchr(rawstext, statussep);
|
||||
+ if (e) {
|
||||
+ *e = '\0'; e++;
|
||||
+ strncpy(rawestext, e, sizeof(estext) - 1);
|
||||
+ copyvalidchars(estext, rawestext);
|
||||
+ } else
|
||||
+ estext[0] = '\0';
|
||||
+ copyvalidchars(stext, rawstext);
|
||||
+ }
|
||||
for (m = mons; m; m = m->next)
|
||||
drawbar(m);
|
||||
}
|
||||
diff --git a/patch/bar_dwmblocks.c b/patch/bar_dwmblocks.c
|
||||
new file mode 100644
|
||||
index 0000000..442b0bc
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_dwmblocks.c
|
||||
@@ -0,0 +1,31 @@
|
||||
+static int dwmblockssig;
|
||||
+pid_t dwmblockspid = 0;
|
||||
+
|
||||
+int
|
||||
+getdwmblockspid()
|
||||
+{
|
||||
+ char buf[16];
|
||||
+ FILE *fp = popen("pidof -s dwmblocks", "r");
|
||||
+ if (fgets(buf, sizeof(buf), fp));
|
||||
+ pid_t pid = strtoul(buf, NULL, 10);
|
||||
+ pclose(fp);
|
||||
+ dwmblockspid = pid;
|
||||
+ return pid != 0 ? 0 : -1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+sigdwmblocks(const Arg *arg)
|
||||
+{
|
||||
+ union sigval sv;
|
||||
+ sv.sival_int = (dwmblockssig << 8) | arg->i;
|
||||
+ if (!dwmblockspid)
|
||||
+ if (getdwmblockspid() == -1)
|
||||
+ return;
|
||||
+
|
||||
+ if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) {
|
||||
+ if (errno == ESRCH) {
|
||||
+ if (!getdwmblockspid())
|
||||
+ sigqueue(dwmblockspid, SIGUSR1, sv);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_dwmblocks.h b/patch/bar_dwmblocks.h
|
||||
new file mode 100644
|
||||
index 0000000..f08f1d5
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_dwmblocks.h
|
||||
@@ -0,0 +1,2 @@
|
||||
+static int getdwmblockspid();
|
||||
+static void sigdwmblocks(const Arg *arg);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_status2d.c b/patch/bar_status2d.c
|
||||
new file mode 100644
|
||||
index 0000000..6111a51
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_status2d.c
|
||||
@@ -0,0 +1,171 @@
|
||||
+int
|
||||
+width_status2d(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return status2dtextlength(rawstext) + lrpad;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+width_status2d_es(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return status2dtextlength(rawestext);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_status2d(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ return drawstatusbar(a->x, rawstext);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_status2d_es(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ return drawstatusbar(a->x, rawestext);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+drawstatusbar(int x, char* stext)
|
||||
+{
|
||||
+ int i, w, len;
|
||||
+ short isCode = 0;
|
||||
+ char *text;
|
||||
+ char *p;
|
||||
+
|
||||
+ len = strlen(stext);
|
||||
+ if (!(text = (char*) malloc(sizeof(char)*(len + 1))))
|
||||
+ die("malloc");
|
||||
+ p = text;
|
||||
+ copyvalidchars(text, stext);
|
||||
+ text[len] = '\0';
|
||||
+
|
||||
+ x += lrpad / 2;
|
||||
+ drw_setscheme(drw, scheme[LENGTH(colors)]);
|
||||
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
|
||||
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
|
||||
+
|
||||
+ /* process status text */
|
||||
+ i = -1;
|
||||
+ while (text[++i]) {
|
||||
+ if (text[i] == '^' && !isCode) {
|
||||
+ isCode = 1;
|
||||
+
|
||||
+ text[i] = '\0';
|
||||
+ w = TEXTW(text) - lrpad;
|
||||
+ drw_text(drw, x, 0, w, bh, 0, text, 0);
|
||||
+
|
||||
+ x += w;
|
||||
+
|
||||
+ /* process code */
|
||||
+ while (text[++i] != '^') {
|
||||
+ if (text[i] == 'c') {
|
||||
+ char buf[8];
|
||||
+ if (i + 7 > len - 1) {
|
||||
+ i += 7;
|
||||
+ len = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ memcpy(buf, (char*)text+i+1, 7);
|
||||
+ buf[7] = '\0';
|
||||
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColFg], buf, 0xff);
|
||||
+ #elif BAR_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColFg], buf, alphas[SchemeNorm][ColFg]);
|
||||
+ #else
|
||||
+ drw_clr_create(drw, &drw->scheme[ColFg], buf);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ i += 7;
|
||||
+ } else if (text[i] == 'b') {
|
||||
+ char buf[8];
|
||||
+ if (i + 7 > len - 1) {
|
||||
+ i += 7;
|
||||
+ len = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ memcpy(buf, (char*)text+i+1, 7);
|
||||
+ buf[7] = '\0';
|
||||
+ #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColBg], buf, 0xff);
|
||||
+ #elif BAR_ALPHA_PATCH
|
||||
+ drw_clr_create(drw, &drw->scheme[ColBg], buf, alphas[SchemeNorm][ColBg]);
|
||||
+ #else
|
||||
+ drw_clr_create(drw, &drw->scheme[ColBg], buf);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ i += 7;
|
||||
+ } else if (text[i] == 'd') {
|
||||
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
|
||||
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
|
||||
+ } else if (text[i] == 'r') {
|
||||
+ int rx = atoi(text + ++i);
|
||||
+ while (text[++i] != ',');
|
||||
+ int ry = atoi(text + ++i);
|
||||
+ while (text[++i] != ',');
|
||||
+ int rw = atoi(text + ++i);
|
||||
+ while (text[++i] != ',');
|
||||
+ int rh = atoi(text + ++i);
|
||||
+
|
||||
+ if (ry < 0)
|
||||
+ ry = 0;
|
||||
+ if (rx < 0)
|
||||
+ rx = 0;
|
||||
+
|
||||
+ drw_rect(drw, rx + x, ry, rw, rh, 1, 0);
|
||||
+ } else if (text[i] == 'f') {
|
||||
+ x += atoi(text + ++i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ text = text + i + 1;
|
||||
+ len -= i + 1;
|
||||
+ i=-1;
|
||||
+ isCode = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!isCode && len) {
|
||||
+ w = TEXTW(text) - lrpad;
|
||||
+ drw_text(drw, x, 0, w, bh, 0, text, 0);
|
||||
+ x += w;
|
||||
+ }
|
||||
+ free(p);
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+
|
||||
+ return x;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+status2dtextlength(char* stext)
|
||||
+{
|
||||
+ int i, w, len;
|
||||
+ short isCode = 0;
|
||||
+ char *text;
|
||||
+ char *p;
|
||||
+
|
||||
+ len = strlen(stext) + 1;
|
||||
+ if (!(text = (char*) malloc(sizeof(char)*len)))
|
||||
+ die("malloc");
|
||||
+ p = text;
|
||||
+ copyvalidchars(text, stext);
|
||||
+
|
||||
+ /* compute width of the status text */
|
||||
+ w = 0;
|
||||
+ i = -1;
|
||||
+ while (text[++i]) {
|
||||
+ if (text[i] == '^') {
|
||||
+ if (!isCode) {
|
||||
+ isCode = 1;
|
||||
+ text[i] = '\0';
|
||||
+ w += TEXTW(text) - lrpad;
|
||||
+ text[i] = '^';
|
||||
+ if (text[++i] == 'f')
|
||||
+ w += atoi(text + ++i);
|
||||
+ } else {
|
||||
+ isCode = 0;
|
||||
+ text = text + i + 1;
|
||||
+ i = -1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (!isCode)
|
||||
+ w += TEXTW(text) - lrpad;
|
||||
+ free(p);
|
||||
+ return w;
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_status2d.h b/patch/bar_status2d.h
|
||||
new file mode 100644
|
||||
index 0000000..0830025
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_status2d.h
|
||||
@@ -0,0 +1,6 @@
|
||||
+static int width_status2d(Bar *bar, BarWidthArg *a);
|
||||
+static int width_status2d_es(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_status2d(Bar *bar, BarDrawArg *a);
|
||||
+static int draw_status2d_es(Bar *bar, BarDrawArg *a);
|
||||
+static int drawstatusbar(int x, char *text);
|
||||
+static int status2dtextlength(char *stext);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_statuscmd.c b/patch/bar_statuscmd.c
|
||||
new file mode 100644
|
||||
index 0000000..28ce120
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_statuscmd.c
|
||||
@@ -0,0 +1,49 @@
|
||||
+int
|
||||
+click_statuscmd(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return click_statuscmd_text(arg, a->rel_x, rawstext);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_statuscmd_es(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return click_statuscmd_text(arg, a->rel_x, rawestext);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_statuscmd_text(Arg *arg, int rel_x, char *text)
|
||||
+{
|
||||
+ int i = -1;
|
||||
+ int x = 0;
|
||||
+ char ch;
|
||||
+ dwmblockssig = -1;
|
||||
+ while (text[++i]) {
|
||||
+ if ((unsigned char)text[i] < ' ') {
|
||||
+ ch = text[i];
|
||||
+ text[i] = '\0';
|
||||
+ x += status2dtextlength(text);
|
||||
+ text[i] = ch;
|
||||
+ text += i+1;
|
||||
+ i = -1;
|
||||
+ if (x >= rel_x && dwmblockssig != -1)
|
||||
+ break;
|
||||
+ dwmblockssig = ch;
|
||||
+ }
|
||||
+ }
|
||||
+ if (dwmblockssig == -1)
|
||||
+ dwmblockssig = 0;
|
||||
+ return ClkStatusText;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+copyvalidchars(char *text, char *rawtext)
|
||||
+{
|
||||
+ int i = -1, j = 0;
|
||||
+
|
||||
+ while (rawtext[++i]) {
|
||||
+ if ((unsigned char)rawtext[i] >= ' ') {
|
||||
+ text[j++] = rawtext[i];
|
||||
+ }
|
||||
+ }
|
||||
+ text[j] = '\0';
|
||||
+}
|
||||
diff --git a/patch/bar_statuscmd.h b/patch/bar_statuscmd.h
|
||||
new file mode 100644
|
||||
index 0000000..d6d428e
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_statuscmd.h
|
||||
@@ -0,0 +1,4 @@
|
||||
+static int click_statuscmd(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+static int click_statuscmd_es(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+static int click_statuscmd_text(Arg *arg, int rel_x, char *text);
|
||||
+static void copyvalidchars(char *text, char *rawtext);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..84bbd19 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -1,5 +1,8 @@
|
||||
/* Bar functionality */
|
||||
#include "bar_ltsymbol.c"
|
||||
-#include "bar_status.c"
|
||||
+//#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_status2d.c"
|
||||
+#include "bar_dwmblocks.c"
|
||||
+#include "bar_statuscmd.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..78f7520 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -1,5 +1,8 @@
|
||||
/* Bar functionality */
|
||||
#include "bar_ltsymbol.h"
|
||||
-#include "bar_status.h"
|
||||
+//#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_status2d.h"
|
||||
+#include "bar_dwmblocks.h"
|
||||
+#include "bar_statuscmd.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,127 @@
|
||||
From 941d14787a5f49e5fe1be516a2b30858110ec35d Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:11:09 +0100
|
||||
Subject: [PATCH 2/2] Adding statusbutton module
|
||||
|
||||
---
|
||||
config.def.h | 5 ++++-
|
||||
dwm.c | 2 +-
|
||||
patch/bar_statusbutton.c | 21 +++++++++++++++++++++
|
||||
patch/bar_statusbutton.h | 3 +++
|
||||
patch/include.c | 3 ++-
|
||||
patch/include.h | 3 ++-
|
||||
6 files changed, 33 insertions(+), 4 deletions(-)
|
||||
create mode 100644 patch/bar_statusbutton.c
|
||||
create mode 100644 patch/bar_statusbutton.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..14d47ad 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char buttonbar[] = "<O>";
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -45,6 +46,7 @@ static const Rule rules[] = {
|
||||
*/
|
||||
static const BarRule barrules[] = {
|
||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
+ { -1, 0, BAR_ALIGN_LEFT, width_stbutton, draw_stbutton, click_stbutton, "statusbutton" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
@@ -118,9 +120,10 @@ static Key keys[] = {
|
||||
};
|
||||
|
||||
/* button definitions */
|
||||
-/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
||||
+/* click can be ClkButton, ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
||||
static Button buttons[] = {
|
||||
/* click event mask button function argument */
|
||||
+ { ClkButton, 0, Button1, spawn, {.v = dmenucmd } },
|
||||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..de465bc 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -65,7 +65,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
+enum { ClkButton, ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
enum {
|
||||
BAR_ALIGN_LEFT,
|
||||
diff --git a/patch/bar_statusbutton.c b/patch/bar_statusbutton.c
|
||||
new file mode 100644
|
||||
index 0000000..f5c9c9d
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_statusbutton.c
|
||||
@@ -0,0 +1,21 @@
|
||||
+int
|
||||
+width_stbutton(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return TEXTW(buttonbar);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_stbutton(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ #if BAR_PANGO_PATCH
|
||||
+ return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, buttonbar, 0, False);
|
||||
+ #else
|
||||
+ return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, buttonbar, 0);
|
||||
+ #endif // BAR_PANGO_PATCH
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_stbutton(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return ClkButton;
|
||||
+}
|
||||
diff --git a/patch/bar_statusbutton.h b/patch/bar_statusbutton.h
|
||||
new file mode 100644
|
||||
index 0000000..8e9d6fe
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_statusbutton.h
|
||||
@@ -0,0 +1,3 @@
|
||||
+static int width_stbutton(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_stbutton(Bar *bar, BarDrawArg *a);
|
||||
+static int click_stbutton(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..b731f2e 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_statusbutton.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..c2a1127 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_statusbutton.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,561 @@
|
||||
From a44a11168d6823a5b725242dfb5480b5be2f4b91 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:11:51 +0100
|
||||
Subject: [PATCH 2/2] Adding systray module
|
||||
|
||||
---
|
||||
config.def.h | 3 +
|
||||
dwm.c | 131 ++++++++++++++++++++++++++----
|
||||
patch/bar_systray.c | 190 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_systray.h | 40 ++++++++++
|
||||
patch/include.c | 3 +-
|
||||
patch/include.h | 3 +-
|
||||
6 files changed, 353 insertions(+), 17 deletions(-)
|
||||
create mode 100644 patch/bar_systray.c
|
||||
create mode 100644 patch/bar_systray.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..a22f507 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const unsigned int systrayspacing = 2; /* systray spacing */
|
||||
+static const int showsystray = 1; /* 0 means no systray */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -47,6 +49,7 @@ static const BarRule barrules[] = {
|
||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
+ { 'A', 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" },
|
||||
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
};
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..6875b06 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -63,6 +63,8 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
+ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
|
||||
+ NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
@@ -247,7 +249,7 @@ static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
-static int sendevent(Client *c, Atom proto);
|
||||
+static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
|
||||
static void sendmon(Client *c, Monitor *m);
|
||||
static void setclientstate(Client *c, long state);
|
||||
static void setfocus(Client *c);
|
||||
@@ -311,9 +313,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[MapRequest] = maprequest,
|
||||
[MotionNotify] = motionnotify,
|
||||
[PropertyNotify] = propertynotify,
|
||||
+ [ResizeRequest] = resizerequest,
|
||||
[UnmapNotify] = unmapnotify
|
||||
};
|
||||
-static Atom wmatom[WMLast], netatom[NetLast];
|
||||
+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
|
||||
static int running = 1;
|
||||
static Cur *cursor[CurLast];
|
||||
static Clr **scheme;
|
||||
@@ -556,6 +559,15 @@ cleanup(void)
|
||||
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||
while (mons)
|
||||
cleanupmon(mons);
|
||||
+ if (showsystray && systray) {
|
||||
+ while (systray->icons)
|
||||
+ removesystrayicon(systray->icons);
|
||||
+ if (systray->win) {
|
||||
+ XUnmapWindow(dpy, systray->win);
|
||||
+ XDestroyWindow(dpy, systray->win);
|
||||
+ }
|
||||
+ free(systray);
|
||||
+ }
|
||||
for (i = 0; i < CurLast; i++)
|
||||
drw_cur_free(drw, cursor[i]);
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
@@ -591,9 +603,48 @@ cleanupmon(Monitor *mon)
|
||||
void
|
||||
clientmessage(XEvent *e)
|
||||
{
|
||||
+ XWindowAttributes wa;
|
||||
+ XSetWindowAttributes swa;
|
||||
XClientMessageEvent *cme = &e->xclient;
|
||||
Client *c = wintoclient(cme->window);
|
||||
|
||||
+ if (showsystray && systray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
|
||||
+ /* add systray icons */
|
||||
+ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
|
||||
+ if (!(c = (Client *)calloc(1, sizeof(Client))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Client));
|
||||
+ if (!(c->win = cme->data.l[2])) {
|
||||
+ free(c);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ c->mon = selmon;
|
||||
+ c->next = systray->icons;
|
||||
+ systray->icons = c;
|
||||
+ XGetWindowAttributes(dpy, c->win, &wa);
|
||||
+ c->x = c->oldx = c->y = c->oldy = 0;
|
||||
+ c->w = c->oldw = wa.width;
|
||||
+ c->h = c->oldh = wa.height;
|
||||
+ c->oldbw = wa.border_width;
|
||||
+ c->bw = 0;
|
||||
+ c->isfloating = True;
|
||||
+ /* reuse tags field as mapped status */
|
||||
+ c->tags = 1;
|
||||
+ updatesizehints(c);
|
||||
+ updatesystrayicongeom(c, wa.width, wa.height);
|
||||
+ XAddToSaveSet(dpy, c->win);
|
||||
+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
|
||||
+ XReparentWindow(dpy, c->win, systray->win, 0, 0);
|
||||
+ /* use parents background color */
|
||||
+ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
+ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
|
||||
+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
|
||||
+ XSync(dpy, False);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!c)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
@@ -756,6 +807,10 @@ destroynotify(XEvent *e)
|
||||
|
||||
if ((c = wintoclient(ev->window)))
|
||||
unmanage(c, 1);
|
||||
+ else if (showsystray && (c = wintosystrayicon(ev->window))) {
|
||||
+ removesystrayicon(c);
|
||||
+ drawbarwin(systray->bar);
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1022,9 +1077,15 @@ getatomprop(Client *c, Atom prop)
|
||||
unsigned char *p = NULL;
|
||||
Atom da, atom = None;
|
||||
|
||||
- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
||||
+ Atom req = XA_ATOM;
|
||||
+ if (prop == xatom[XembedInfo])
|
||||
+ req = xatom[XembedInfo];
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
|
||||
&da, &di, &dl, &dl, &p) == Success && p) {
|
||||
atom = *(Atom *)p;
|
||||
+ if (da == xatom[XembedInfo] && dl == 2)
|
||||
+ atom = ((Atom *)p)[1];
|
||||
XFree(p);
|
||||
}
|
||||
return atom;
|
||||
@@ -1162,7 +1223,7 @@ killclient(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
- if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
||||
+ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) {
|
||||
XGrabServer(dpy);
|
||||
XSetErrorHandler(xerrordummy);
|
||||
XSetCloseDownMode(dpy, DestroyAll);
|
||||
@@ -1248,9 +1309,15 @@ mappingnotify(XEvent *e)
|
||||
void
|
||||
maprequest(XEvent *e)
|
||||
{
|
||||
+ Client *i;
|
||||
static XWindowAttributes wa;
|
||||
XMapRequestEvent *ev = &e->xmaprequest;
|
||||
|
||||
+ if (showsystray && systray && (i = wintosystrayicon(ev->window))) {
|
||||
+ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
|
||||
+ drawbarwin(systray->bar);
|
||||
+ }
|
||||
+
|
||||
if (!XGetWindowAttributes(dpy, ev->window, &wa))
|
||||
return;
|
||||
if (wa.override_redirect)
|
||||
@@ -1374,6 +1441,16 @@ propertynotify(XEvent *e)
|
||||
Window trans;
|
||||
XPropertyEvent *ev = &e->xproperty;
|
||||
|
||||
+ if (showsystray && (c = wintosystrayicon(ev->window))) {
|
||||
+ if (ev->atom == XA_WM_NORMAL_HINTS) {
|
||||
+ updatesizehints(c);
|
||||
+ updatesystrayicongeom(c, c->w, c->h);
|
||||
+ }
|
||||
+ else
|
||||
+ updatesystrayiconstate(c, ev);
|
||||
+ drawbarwin(systray->bar);
|
||||
+ }
|
||||
+
|
||||
if ((ev->window == root) && (ev->atom == XA_WM_NAME))
|
||||
updatestatus();
|
||||
else if (ev->state == PropertyDelete)
|
||||
@@ -1593,26 +1670,36 @@ setclientstate(Client *c, long state)
|
||||
}
|
||||
|
||||
int
|
||||
-sendevent(Client *c, Atom proto)
|
||||
+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
|
||||
{
|
||||
int n;
|
||||
Atom *protocols;
|
||||
+ Atom mt;
|
||||
int exists = 0;
|
||||
XEvent ev;
|
||||
|
||||
- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
||||
- while (!exists && n--)
|
||||
- exists = protocols[n] == proto;
|
||||
- XFree(protocols);
|
||||
+ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
|
||||
+ mt = wmatom[WMProtocols];
|
||||
+ if (XGetWMProtocols(dpy, w, &protocols, &n)) {
|
||||
+ while (!exists && n--)
|
||||
+ exists = protocols[n] == proto;
|
||||
+ XFree(protocols);
|
||||
+ }
|
||||
+ } else {
|
||||
+ exists = True;
|
||||
+ mt = proto;
|
||||
}
|
||||
if (exists) {
|
||||
ev.type = ClientMessage;
|
||||
- ev.xclient.window = c->win;
|
||||
- ev.xclient.message_type = wmatom[WMProtocols];
|
||||
+ ev.xclient.window = w;
|
||||
+ ev.xclient.message_type = mt;
|
||||
ev.xclient.format = 32;
|
||||
- ev.xclient.data.l[0] = proto;
|
||||
- ev.xclient.data.l[1] = CurrentTime;
|
||||
- XSendEvent(dpy, c->win, False, NoEventMask, &ev);
|
||||
+ ev.xclient.data.l[0] = d0;
|
||||
+ ev.xclient.data.l[1] = d1;
|
||||
+ ev.xclient.data.l[2] = d2;
|
||||
+ ev.xclient.data.l[3] = d3;
|
||||
+ ev.xclient.data.l[4] = d4;
|
||||
+ XSendEvent(dpy, w, False, mask, &ev);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
@@ -1626,7 +1713,7 @@ setfocus(Client *c)
|
||||
XA_WINDOW, 32, PropModeReplace,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
}
|
||||
- sendevent(c, wmatom[WMTakeFocus]);
|
||||
+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1715,6 +1802,15 @@ setup(void)
|
||||
wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
|
||||
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
|
||||
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
|
||||
+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
|
||||
+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
|
||||
+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
|
||||
+ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
|
||||
+ netatom[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False);
|
||||
+ netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
|
||||
+ xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
|
||||
+ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
|
||||
+ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
|
||||
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
|
||||
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
|
||||
netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
|
||||
@@ -1959,6 +2055,11 @@ unmapnotify(XEvent *e)
|
||||
setclientstate(c, WithdrawnState);
|
||||
else
|
||||
unmanage(c, 0);
|
||||
+ } else if (showsystray && (c = wintosystrayicon(ev->window))) {
|
||||
+ /* KLUDGE! sometimes icons occasionally unmap their windows, but do
|
||||
+ * _not_ destroy them. We map those windows back */
|
||||
+ XMapRaised(dpy, c->win);
|
||||
+ drawbarwin(systray->bar);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/patch/bar_systray.c b/patch/bar_systray.c
|
||||
new file mode 100644
|
||||
index 0000000..3ae2e56
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_systray.c
|
||||
@@ -0,0 +1,190 @@
|
||||
+static Systray *systray = NULL;
|
||||
+static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
|
||||
+
|
||||
+int
|
||||
+width_systray(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ unsigned int w = 0;
|
||||
+ Client *i;
|
||||
+ if (!systray)
|
||||
+ return 1;
|
||||
+ if (showsystray)
|
||||
+ for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next);
|
||||
+ return w ? w + lrpad - systrayspacing : 0;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_systray(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ if (!showsystray) {
|
||||
+ if (systray)
|
||||
+ XMoveWindow(dpy, systray->win, -500, bar->by);
|
||||
+ return a->x;
|
||||
+ }
|
||||
+
|
||||
+ XSetWindowAttributes wa;
|
||||
+ Client *i;
|
||||
+ unsigned int w;
|
||||
+
|
||||
+ if (!systray) {
|
||||
+ /* init systray */
|
||||
+ if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
|
||||
+
|
||||
+ wa.override_redirect = True;
|
||||
+ wa.event_mask = ButtonPressMask|ExposureMask;
|
||||
+ wa.border_pixel = 0;
|
||||
+ #if BAR_ALPHA_PATCH
|
||||
+ wa.background_pixel = 0;
|
||||
+ wa.colormap = cmap;
|
||||
+ systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by, MAX(a->w + 40, 1), bar->bh, 0, depth,
|
||||
+ InputOutput, visual,
|
||||
+ CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap
|
||||
+ #else
|
||||
+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
+ systray->win = XCreateSimpleWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by, MIN(a->w, 1), bar->bh, 0, 0, scheme[SchemeNorm][ColBg].pixel);
|
||||
+ XChangeWindowAttributes(dpy, systray->win, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &wa);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+
|
||||
+ XSelectInput(dpy, systray->win, SubstructureNotifyMask);
|
||||
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
|
||||
+ PropModeReplace, (unsigned char *)&systrayorientation, 1);
|
||||
+ #if BAR_ALPHA_PATCH
|
||||
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32,
|
||||
+ PropModeReplace, (unsigned char *)&visual->visualid, 1);
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1);
|
||||
+ XMapRaised(dpy, systray->win);
|
||||
+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
|
||||
+ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
|
||||
+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
|
||||
+ XSync(dpy, False);
|
||||
+ } else {
|
||||
+ fprintf(stderr, "dwm: unable to obtain system tray.\n");
|
||||
+ free(systray);
|
||||
+ systray = NULL;
|
||||
+ return a->x;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ systray->bar = bar;
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ for (w = 0, i = systray->icons; i; i = i->next) {
|
||||
+ #if BAR_ALPHA_PATCH
|
||||
+ wa.background_pixel = 0;
|
||||
+ #else
|
||||
+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||
+ #endif // BAR_ALPHA_PATCH
|
||||
+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
|
||||
+ XMapRaised(dpy, i->win);
|
||||
+ i->x = w;
|
||||
+ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
|
||||
+ w += i->w;
|
||||
+ if (i->next)
|
||||
+ w += systrayspacing;
|
||||
+ if (i->mon != bar->mon)
|
||||
+ i->mon = bar->mon;
|
||||
+ }
|
||||
+
|
||||
+ XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by : -bar->by), MAX(w, 1), bar->bh);
|
||||
+ return a->x + a->w;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_systray(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+removesystrayicon(Client *i)
|
||||
+{
|
||||
+ Client **ii;
|
||||
+
|
||||
+ if (!showsystray || !i)
|
||||
+ return;
|
||||
+ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
|
||||
+ if (ii)
|
||||
+ *ii = i->next;
|
||||
+ free(i);
|
||||
+ drawbarwin(systray->bar);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+resizerequest(XEvent *e)
|
||||
+{
|
||||
+ XResizeRequestEvent *ev = &e->xresizerequest;
|
||||
+ Client *i;
|
||||
+
|
||||
+ if ((i = wintosystrayicon(ev->window))) {
|
||||
+ updatesystrayicongeom(i, ev->width, ev->height);
|
||||
+ drawbarwin(systray->bar);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+updatesystrayicongeom(Client *i, int w, int h)
|
||||
+{
|
||||
+ if (i) {
|
||||
+ i->h = bh;
|
||||
+ if (w == h)
|
||||
+ i->w = bh;
|
||||
+ else if (h == bh)
|
||||
+ i->w = w;
|
||||
+ else
|
||||
+ i->w = (int) ((float)bh * ((float)w / (float)h));
|
||||
+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
|
||||
+ /* force icons into the systray dimensions if they don't want to */
|
||||
+ if (i->h > bh) {
|
||||
+ if (i->w == i->h)
|
||||
+ i->w = bh;
|
||||
+ else
|
||||
+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
|
||||
+ i->h = bh;
|
||||
+ }
|
||||
+ if (i->w > 2*bh)
|
||||
+ i->w = bh;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
|
||||
+{
|
||||
+ long flags;
|
||||
+ int code = 0;
|
||||
+
|
||||
+ if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] ||
|
||||
+ !(flags = getatomprop(i, xatom[XembedInfo])))
|
||||
+ return;
|
||||
+
|
||||
+ if (flags & XEMBED_MAPPED && !i->tags) {
|
||||
+ i->tags = 1;
|
||||
+ code = XEMBED_WINDOW_ACTIVATE;
|
||||
+ XMapRaised(dpy, i->win);
|
||||
+ setclientstate(i, NormalState);
|
||||
+ }
|
||||
+ else if (!(flags & XEMBED_MAPPED) && i->tags) {
|
||||
+ i->tags = 0;
|
||||
+ code = XEMBED_WINDOW_DEACTIVATE;
|
||||
+ XUnmapWindow(dpy, i->win);
|
||||
+ setclientstate(i, WithdrawnState);
|
||||
+ }
|
||||
+ else
|
||||
+ return;
|
||||
+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
|
||||
+ systray->win, XEMBED_EMBEDDED_VERSION);
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+wintosystrayicon(Window w)
|
||||
+{
|
||||
+ if (!systray)
|
||||
+ return NULL;
|
||||
+ Client *i = NULL;
|
||||
+ if (!showsystray || !w)
|
||||
+ return i;
|
||||
+ for (i = systray->icons; i && i->win != w; i = i->next);
|
||||
+ return i;
|
||||
+}
|
||||
diff --git a/patch/bar_systray.h b/patch/bar_systray.h
|
||||
new file mode 100644
|
||||
index 0000000..5123a73
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_systray.h
|
||||
@@ -0,0 +1,40 @@
|
||||
+#define SYSTEM_TRAY_REQUEST_DOCK 0
|
||||
+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
|
||||
+
|
||||
+/* XEMBED messages */
|
||||
+#define XEMBED_EMBEDDED_NOTIFY 0
|
||||
+#define XEMBED_WINDOW_ACTIVATE 1
|
||||
+#define XEMBED_FOCUS_IN 4
|
||||
+#define XEMBED_MODALITY_ON 10
|
||||
+
|
||||
+#define XEMBED_MAPPED (1 << 0)
|
||||
+#define XEMBED_WINDOW_ACTIVATE 1
|
||||
+#define XEMBED_WINDOW_DEACTIVATE 2
|
||||
+
|
||||
+#define VERSION_MAJOR 0
|
||||
+#define VERSION_MINOR 0
|
||||
+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
|
||||
+
|
||||
+/* enums */
|
||||
+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
|
||||
+
|
||||
+typedef struct Systray Systray;
|
||||
+struct Systray {
|
||||
+ Window win;
|
||||
+ Client *icons;
|
||||
+ Bar *bar;
|
||||
+};
|
||||
+
|
||||
+/* bar integration */
|
||||
+static int width_systray(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_systray(Bar *bar, BarDrawArg *a);
|
||||
+static int click_systray(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+
|
||||
+/* function declarations */
|
||||
+static Atom getatomprop(Client *c, Atom prop);
|
||||
+static void removesystrayicon(Client *i);
|
||||
+static void resizerequest(XEvent *e);
|
||||
+static void updatesystrayicongeom(Client *i, int w, int h);
|
||||
+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
|
||||
+static Client *wintosystrayicon(Window w);
|
||||
+
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..c82b392 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_systray.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..c01916a 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_systray.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,260 @@
|
||||
From 3b3064354ad90f18beb933b3d2b5ecf892201633 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:12:28 +0100
|
||||
Subject: [PATCH 2/2] Adding taggrid module
|
||||
|
||||
---
|
||||
config.def.h | 25 ++++++++
|
||||
patch/bar_taggrid.c | 148 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_taggrid.h | 4 ++
|
||||
patch/include.c | 3 +-
|
||||
patch/include.h | 3 +-
|
||||
5 files changed, 181 insertions(+), 2 deletions(-)
|
||||
create mode 100644 patch/bar_taggrid.c
|
||||
create mode 100644 patch/bar_taggrid.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..6d5e172 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -21,6 +21,22 @@ static const char *colors[][3] = {
|
||||
/* tagging */
|
||||
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
|
||||
+/* grid of tags */
|
||||
+#define DRAWCLASSICTAGS 1 << 0
|
||||
+#define DRAWTAGGRID 1 << 1
|
||||
+
|
||||
+#define SWITCHTAG_UP 1 << 0
|
||||
+#define SWITCHTAG_DOWN 1 << 1
|
||||
+#define SWITCHTAG_LEFT 1 << 2
|
||||
+#define SWITCHTAG_RIGHT 1 << 3
|
||||
+#define SWITCHTAG_TOGGLETAG 1 << 4
|
||||
+#define SWITCHTAG_TAG 1 << 5
|
||||
+#define SWITCHTAG_VIEW 1 << 6
|
||||
+#define SWITCHTAG_TOGGLEVIEW 1 << 7
|
||||
+
|
||||
+static const unsigned int drawtagmask = DRAWTAGGRID; /* | DRAWCLASSICTAGS to show classic row of tags */
|
||||
+static const int tagrows = 2;
|
||||
+
|
||||
static const Rule rules[] = {
|
||||
/* xprop(1):
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
@@ -46,6 +62,7 @@ static const Rule rules[] = {
|
||||
static const BarRule barrules[] = {
|
||||
/* monitor bar alignment widthfunc drawfunc clickfunc name */
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
||||
+ { -1, 0, BAR_ALIGN_LEFT, width_taggrid, draw_taggrid, click_taggrid, "taggrid" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" },
|
||||
{ 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" },
|
||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" },
|
||||
@@ -101,6 +118,14 @@ static Key keys[] = {
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
+ { MODKEY|ControlMask, XK_Up, switchtag, { .ui = SWITCHTAG_UP | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|ControlMask, XK_Down, switchtag, { .ui = SWITCHTAG_DOWN | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|ControlMask, XK_Right, switchtag, { .ui = SWITCHTAG_RIGHT | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|ControlMask, XK_Left, switchtag, { .ui = SWITCHTAG_LEFT | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|Mod4Mask, XK_Up, switchtag, { .ui = SWITCHTAG_UP | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|Mod4Mask, XK_Down, switchtag, { .ui = SWITCHTAG_DOWN | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|Mod4Mask, XK_Right, switchtag, { .ui = SWITCHTAG_RIGHT | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
+ { MODKEY|Mod4Mask, XK_Left, switchtag, { .ui = SWITCHTAG_LEFT | SWITCHTAG_TAG | SWITCHTAG_VIEW } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
diff --git a/patch/bar_taggrid.c b/patch/bar_taggrid.c
|
||||
new file mode 100644
|
||||
index 0000000..53046fa
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_taggrid.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+int
|
||||
+width_taggrid(Bar *bar, BarWidthArg *a)
|
||||
+{
|
||||
+ return (bh / 2) * (LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0)) + lrpad;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+draw_taggrid(Bar *bar, BarDrawArg *a)
|
||||
+{
|
||||
+ unsigned int x, y, h, max_x = 0, columns, occ = 0;
|
||||
+ int invert, i,j, k;
|
||||
+ Client *c;
|
||||
+
|
||||
+ for (c = bar->mon->clients; c; c = c->next)
|
||||
+ occ |= c->tags;
|
||||
+
|
||||
+ max_x = x = a->x + lrpad / 2;
|
||||
+ h = bh / tagrows;
|
||||
+ y = 0;
|
||||
+ columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
|
||||
+
|
||||
+ /* Firstly we will fill the borders of squares */
|
||||
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
|
||||
+ XFillRectangle(dpy, drw->drawable, drw->gc, x, y, h*columns + 1, bh);
|
||||
+
|
||||
+ /* We will draw LENGTH(tags) squares in tagraws raws. */
|
||||
+ for (j = 0, i = 0; j < tagrows; j++) {
|
||||
+ x = a->x + lrpad / 2;
|
||||
+ for (k = 0; k < columns; k++, i++) {
|
||||
+ if (i < LENGTH(tags)) {
|
||||
+ invert = bar->mon->tagset[bar->mon->seltags] & 1 << i ? 0 : 1;
|
||||
+
|
||||
+ /* Select active color for current square */
|
||||
+ XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeSel][ColBg].pixel :
|
||||
+ scheme[SchemeNorm][ColFg].pixel);
|
||||
+ XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h-1);
|
||||
+
|
||||
+ /* Mark square if tag has client */
|
||||
+ if (occ & 1 << i) {
|
||||
+ XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeSel][ColFg].pixel :
|
||||
+ scheme[SchemeNorm][ColBg].pixel);
|
||||
+ XFillRectangle(dpy, drw->drawable, drw->gc, x + 1, y + 1,
|
||||
+ h / 2, h / 2);
|
||||
+ }
|
||||
+ } else {
|
||||
+ XSetForeground(drw->dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
|
||||
+ XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h);
|
||||
+ }
|
||||
+ x += h;
|
||||
+ if (x > max_x) {
|
||||
+ max_x = x;
|
||||
+ }
|
||||
+ }
|
||||
+ y += h;
|
||||
+ }
|
||||
+ return max_x;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+click_taggrid(Bar *bar, Arg *arg, BarClickArg *a)
|
||||
+{
|
||||
+ unsigned int i, columns;
|
||||
+
|
||||
+ columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
|
||||
+ i = (a->rel_x - lrpad / 2) / (bh / tagrows) + columns * (a->rel_y / (bh / tagrows));
|
||||
+ if (i >= LENGTH(tags)) {
|
||||
+ i = LENGTH(tags) - 1;
|
||||
+ }
|
||||
+ arg->ui = 1 << i;
|
||||
+ return ClkTagBar;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+switchtag(const Arg *arg)
|
||||
+{
|
||||
+ unsigned int columns;
|
||||
+ unsigned int new_tagset = 0;
|
||||
+ unsigned int pos, i;
|
||||
+ int col, row;
|
||||
+ Arg new_arg;
|
||||
+
|
||||
+ columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
|
||||
+
|
||||
+ for (i = 0; i < LENGTH(tags); ++i) {
|
||||
+ if (!(selmon->tagset[selmon->seltags] & 1 << i)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ pos = i;
|
||||
+ row = pos / columns;
|
||||
+ col = pos % columns;
|
||||
+ if (arg->ui & SWITCHTAG_UP) { /* UP */
|
||||
+ row --;
|
||||
+ if (row < 0) {
|
||||
+ row = tagrows - 1;
|
||||
+ }
|
||||
+ do {
|
||||
+ pos = row * columns + col;
|
||||
+ row --;
|
||||
+ } while (pos >= LENGTH(tags));
|
||||
+ }
|
||||
+ if (arg->ui & SWITCHTAG_DOWN) { /* DOWN */
|
||||
+ row ++;
|
||||
+ if (row >= tagrows) {
|
||||
+ row = 0;
|
||||
+ }
|
||||
+ pos = row * columns + col;
|
||||
+ if (pos >= LENGTH(tags)) {
|
||||
+ row = 0;
|
||||
+ }
|
||||
+ pos = row * columns + col;
|
||||
+ }
|
||||
+ if (arg->ui & SWITCHTAG_LEFT) { /* LEFT */
|
||||
+ col --;
|
||||
+ if (col < 0) {
|
||||
+ col = columns - 1;
|
||||
+ }
|
||||
+ do {
|
||||
+ pos = row * columns + col;
|
||||
+ col --;
|
||||
+ } while (pos >= LENGTH(tags));
|
||||
+ }
|
||||
+ if (arg->ui & SWITCHTAG_RIGHT) { /* RIGHT */
|
||||
+ col ++;
|
||||
+ if (col >= columns) {
|
||||
+ col = 0;
|
||||
+ }
|
||||
+ pos = row * columns + col;
|
||||
+ if (pos >= LENGTH(tags)) {
|
||||
+ col = 0;
|
||||
+ pos = row * columns + col;
|
||||
+ }
|
||||
+ }
|
||||
+ new_tagset |= 1 << pos;
|
||||
+ }
|
||||
+ new_arg.ui = new_tagset;
|
||||
+ if (arg->ui & SWITCHTAG_TOGGLETAG) {
|
||||
+ toggletag(&new_arg);
|
||||
+ }
|
||||
+ if (arg->ui & SWITCHTAG_TAG) {
|
||||
+ tag(&new_arg);
|
||||
+ }
|
||||
+ if (arg->ui & SWITCHTAG_VIEW) {
|
||||
+ view (&new_arg);
|
||||
+ }
|
||||
+ if (arg->ui & SWITCHTAG_TOGGLEVIEW) {
|
||||
+ toggleview (&new_arg);
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_taggrid.h b/patch/bar_taggrid.h
|
||||
new file mode 100644
|
||||
index 0000000..c35b337
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_taggrid.h
|
||||
@@ -0,0 +1,4 @@
|
||||
+static int width_taggrid(Bar *bar, BarWidthArg *a);
|
||||
+static int draw_taggrid(Bar *bar, BarDrawArg *a);
|
||||
+static int click_taggrid(Bar *bar, Arg *arg, BarClickArg *a);
|
||||
+static void switchtag(const Arg *arg);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..f6455d8 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_taggrid.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..98ac046 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_taggrid.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,266 @@
|
||||
From 54674a344665e893a72a81319b7caf9226a2180f Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:13:41 +0100
|
||||
Subject: [PATCH 2/2] Adding wintitleactions patch
|
||||
|
||||
---
|
||||
config.def.h | 4 ++
|
||||
dwm.c | 24 +++++-----
|
||||
patch/bar_wintitleactions.c | 90 +++++++++++++++++++++++++++++++++++++
|
||||
patch/bar_wintitleactions.h | 7 +++
|
||||
patch/include.c | 3 +-
|
||||
patch/include.h | 3 +-
|
||||
6 files changed, 119 insertions(+), 12 deletions(-)
|
||||
create mode 100644 patch/bar_wintitleactions.c
|
||||
create mode 100644 patch/bar_wintitleactions.h
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index f870c41..b8cbed0 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -16,6 +16,7 @@ static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeHid] = { col_cyan, col_gray1, col_cyan },
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
@@ -93,6 +94,7 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
{ MODKEY, XK_Return, zoom, {0} },
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
+ { MODKEY|ControlMask, XK_z, showhideclient, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
@@ -123,7 +125,9 @@ static 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} },
|
||||
+ { ClkWinTitle, 0, Button3, showhideclient, {0} },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 86763d8..5de793d 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
-enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
@@ -524,7 +524,7 @@ buttonpress(XEvent *e)
|
||||
for (i = 0; i < LENGTH(buttons); i++) {
|
||||
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
|
||||
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
|
||||
- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
|
||||
+ buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -996,16 +996,16 @@ focusstack(const Arg *arg)
|
||||
if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
+ for (c = selmon->sel->next; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next);
|
||||
if (!c)
|
||||
- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
|
||||
+ for (c = selmon->clients; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next);
|
||||
} else {
|
||||
for (i = selmon->clients; i != selmon->sel; i = i->next)
|
||||
- if (ISVISIBLE(i))
|
||||
+ if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i)))
|
||||
c = i;
|
||||
if (!c)
|
||||
for (; i; i = i->next)
|
||||
- if (ISVISIBLE(i))
|
||||
+ if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i)))
|
||||
c = i;
|
||||
}
|
||||
if (c) {
|
||||
@@ -1226,12 +1226,14 @@ manage(Window w, XWindowAttributes *wa)
|
||||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
- setclientstate(c, NormalState);
|
||||
+ if (!HIDDEN(c))
|
||||
+ setclientstate(c, NormalState);
|
||||
if (c->mon == selmon)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
- XMapWindow(dpy, c->win);
|
||||
+ if (!HIDDEN(c))
|
||||
+ XMapWindow(dpy, c->win);
|
||||
focus(NULL);
|
||||
}
|
||||
|
||||
@@ -1354,7 +1356,7 @@ movemouse(const Arg *arg)
|
||||
Client *
|
||||
nexttiled(Client *c)
|
||||
{
|
||||
- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
|
||||
+ for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -2314,7 +2316,9 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
|
||||
void
|
||||
zoom(const Arg *arg)
|
||||
{
|
||||
- Client *c = selmon->sel;
|
||||
+ Client *c = (Client*)arg->v;
|
||||
+ if (!c)
|
||||
+ c = selmon->sel;
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange
|
||||
|| (selmon->sel && selmon->sel->isfloating))
|
||||
diff --git a/patch/bar_wintitleactions.c b/patch/bar_wintitleactions.c
|
||||
new file mode 100644
|
||||
index 0000000..a9ae3e1
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_wintitleactions.c
|
||||
@@ -0,0 +1,90 @@
|
||||
+void
|
||||
+hide(Client *c) {
|
||||
+
|
||||
+ Client *n;
|
||||
+ if (!c || HIDDEN(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);
|
||||
+
|
||||
+ if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
|
||||
+ for (n = c->snext; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext);
|
||||
+ if (!n)
|
||||
+ for (n = c->mon->stack; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext);
|
||||
+ } else {
|
||||
+ n = nexttiled(c);
|
||||
+ if (!n)
|
||||
+ n = prevtiled(c);
|
||||
+ }
|
||||
+ focus(n);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+show(Client *c)
|
||||
+{
|
||||
+ if (!c || !HIDDEN(c))
|
||||
+ return;
|
||||
+
|
||||
+ XMapWindow(dpy, c->win);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglewin(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = (Client*)arg->v;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ if (c == selmon->sel)
|
||||
+ hide(c);
|
||||
+ else {
|
||||
+ if (HIDDEN(c))
|
||||
+ show(c);
|
||||
+ focus(c);
|
||||
+ restack(c->mon);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+prevtiled(Client *c)
|
||||
+{
|
||||
+ Client *p, *i;
|
||||
+ for (p = NULL, i = c->mon->clients; c && i != c; i = i->next)
|
||||
+ if (ISVISIBLE(i) && !HIDDEN(i))
|
||||
+ p = i;
|
||||
+ return p;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+showhideclient(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = (Client*)arg->v;
|
||||
+ if (!c)
|
||||
+ c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (HIDDEN(c)) {
|
||||
+ show(c);
|
||||
+ focus(c);
|
||||
+ restack(c->mon);
|
||||
+ } else {
|
||||
+ hide(c);
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/bar_wintitleactions.h b/patch/bar_wintitleactions.h
|
||||
new file mode 100644
|
||||
index 0000000..e37201e
|
||||
--- /dev/null
|
||||
+++ b/patch/bar_wintitleactions.h
|
||||
@@ -0,0 +1,7 @@
|
||||
+#define HIDDEN(C) ((getstate(C->win) == IconicState))
|
||||
+
|
||||
+static void hide(Client *c);
|
||||
+static void show(Client *c);
|
||||
+static void togglewin(const Arg *arg);
|
||||
+static Client * prevtiled(Client *c);
|
||||
+static void showhideclient(const Arg *arg);
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.c b/patch/include.c
|
||||
index d422f56..8008552 100644
|
||||
--- a/patch/include.c
|
||||
+++ b/patch/include.c
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_tags.c"
|
||||
-#include "bar_wintitle.c"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.c"
|
||||
+#include "bar_wintitleactions.c"
|
||||
\ No newline at end of file
|
||||
diff --git a/patch/include.h b/patch/include.h
|
||||
index 5f9a3fe..be075b5 100644
|
||||
--- a/patch/include.h
|
||||
+++ b/patch/include.h
|
||||
@@ -2,4 +2,5 @@
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_tags.h"
|
||||
-#include "bar_wintitle.h"
|
||||
\ No newline at end of file
|
||||
+#include "bar_wintitle.h"
|
||||
+#include "bar_wintitleactions.h"
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,117 @@
|
||||
From a3e3bd001c4b9b4d5bc6b26ed0cef6f2ec78a205 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 14:49:22 +0100
|
||||
Subject: [PATCH] barpadding: multi-monitor fix
|
||||
|
||||
Ref.
|
||||
https://www.reddit.com/r/suckless/comments/nfc3xn/gaps_problem_with_multiple_monitors/
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 24 ++++++++++++++----------
|
||||
2 files changed, 16 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..f0b739f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const int vertpad = 10; /* vertical padding of bar */
|
||||
+static const int sidepad = 10; /* horizontal padding of bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..5728f92 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -242,6 +242,8 @@ static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
static int bh, blw = 0; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
+static int vp; /* vertical padding for bar */
|
||||
+static int sp; /* side padding for bar */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
@@ -568,7 +570,7 @@ configurenotify(XEvent *e)
|
||||
for (c = m->clients; c; c = c->next)
|
||||
if (c->isfullscreen)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
+ XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
|
||||
}
|
||||
focus(NULL);
|
||||
arrange(NULL);
|
||||
@@ -709,7 +711,7 @@ drawbar(Monitor *m)
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
+ drw_text(drw, m->ww - tw - 2 * sp, 0, tw, bh, 0, stext, 0);
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
@@ -735,12 +737,12 @@ drawbar(Monitor *m)
|
||||
if ((w = m->ww - tw - x) > bh) {
|
||||
if (m->sel) {
|
||||
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
|
||||
+ drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0);
|
||||
if (m->sel->isfloating)
|
||||
drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
|
||||
} else {
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- drw_rect(drw, x, 0, w, bh, 1, 1);
|
||||
+ drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1);
|
||||
}
|
||||
}
|
||||
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
|
||||
@@ -1550,6 +1552,8 @@ setup(void)
|
||||
die("no fonts could be loaded.");
|
||||
lrpad = drw->fonts->h;
|
||||
bh = drw->fonts->h + 2;
|
||||
+ sp = sidepad;
|
||||
+ vp = (topbar == 1) ? vertpad : - vertpad;
|
||||
updategeom();
|
||||
/* init atoms */
|
||||
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
@@ -1707,7 +1711,7 @@ togglebar(const Arg *arg)
|
||||
{
|
||||
selmon->showbar = !selmon->showbar;
|
||||
updatebarpos(selmon);
|
||||
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1817,7 +1821,7 @@ updatebars(void)
|
||||
for (m = mons; m; m = m->next) {
|
||||
if (m->barwin)
|
||||
continue;
|
||||
- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
|
||||
+ m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen),
|
||||
CopyFromParent, DefaultVisual(dpy, screen),
|
||||
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
||||
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
||||
@@ -1832,11 +1836,11 @@ updatebarpos(Monitor *m)
|
||||
m->wy = m->my;
|
||||
m->wh = m->mh;
|
||||
if (m->showbar) {
|
||||
- m->wh -= bh;
|
||||
- m->by = m->topbar ? m->wy : m->wy + m->wh;
|
||||
- m->wy = m->topbar ? m->wy + bh : m->wy;
|
||||
+ m->wh = m->wh - vertpad - bh;
|
||||
+ m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
|
||||
+ m->wy = m->topbar ? m->wy + bh + vp : m->wy;
|
||||
} else
|
||||
- m->by = -bh;
|
||||
+ m->by = -bh - vp;
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,92 @@
|
||||
From 687f8c8ff590302462e629f8313b8fc6371e09ca Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:17:58 +0100
|
||||
Subject: [PATCH] Adding 6.3 center patch with multi-monitor fix and
|
||||
auto-centering of floating popup windows
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/center/
|
||||
---
|
||||
config.def.h | 6 +++---
|
||||
dwm.c | 13 +++++++++++--
|
||||
2 files changed, 14 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..dd91fa6 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -26,9 +26,9 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask iscentered isfloating monitor */
|
||||
+ { "Gimp", NULL, NULL, 0, 0, 1, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b7b97e3 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -92,7 +92,7 @@ struct Client {
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int isfixed, iscentered, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -137,6 +137,7 @@ typedef struct {
|
||||
const char *instance;
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
+ int iscentered;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
} Rule;
|
||||
@@ -286,6 +287,7 @@ applyrules(Client *c)
|
||||
XClassHint ch = { NULL, NULL };
|
||||
|
||||
/* rule matching */
|
||||
+ c->iscentered = 0;
|
||||
c->isfloating = 0;
|
||||
c->tags = 0;
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
@@ -298,6 +300,7 @@ applyrules(Client *c)
|
||||
&& (!r->class || strstr(class, r->class))
|
||||
&& (!r->instance || strstr(instance, r->instance)))
|
||||
{
|
||||
+ c->iscentered = r->iscentered;
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
@@ -1060,6 +1063,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
updatewindowtype(c);
|
||||
updatesizehints(c);
|
||||
updatewmhints(c);
|
||||
+ if (c->iscentered) {
|
||||
+ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
|
||||
+ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
|
||||
+ }
|
||||
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
||||
grabbuttons(c, 0);
|
||||
if (!c->isfloating)
|
||||
@@ -2015,8 +2022,10 @@ updatewindowtype(Client *c)
|
||||
|
||||
if (state == netatom[NetWMFullscreen])
|
||||
setfullscreen(c, 1);
|
||||
- if (wtype == netatom[NetWMWindowTypeDialog])
|
||||
+ if (wtype == netatom[NetWMWindowTypeDialog]) {
|
||||
+ c->iscentered = 1;
|
||||
c->isfloating = 1;
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,79 @@
|
||||
From b38b2f665b587add976cd9572ad0bfb748f1b143 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:19:17 +0100
|
||||
Subject: [PATCH] Center clients within their allocated tile based on size
|
||||
hints
|
||||
|
||||
---
|
||||
dwm.c | 30 ++++++++++++++++++++++++++----
|
||||
1 file changed, 26 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..bc7c7ef 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -191,6 +191,7 @@ static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
+static void resizeclientpad(Client *c, int x, int y, int w, int h, int xpad, int ypad);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
static void run(void);
|
||||
@@ -1233,6 +1234,7 @@ propertynotify(XEvent *e)
|
||||
break;
|
||||
case XA_WM_NORMAL_HINTS:
|
||||
updatesizehints(c);
|
||||
+ arrangemon(c->mon);
|
||||
break;
|
||||
case XA_WM_HINTS:
|
||||
updatewmhints(c);
|
||||
@@ -1270,21 +1272,41 @@ recttomon(int x, int y, int w, int h)
|
||||
}
|
||||
|
||||
void
|
||||
-resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
+resize(Client *c, int tx, int ty, int tw, int th, int interact)
|
||||
{
|
||||
- if (applysizehints(c, &x, &y, &w, &h, interact))
|
||||
- resizeclient(c, x, y, w, h);
|
||||
+ int wh = tw, hh = th;
|
||||
+ if (applysizehints(c, &tx, &ty, &wh, &hh, interact))
|
||||
+ resizeclientpad(c, tx, ty, wh, hh, tw, th);
|
||||
}
|
||||
|
||||
+/* This wrapper is just for compatibility with other patches that may call resizeclient */
|
||||
void
|
||||
resizeclient(Client *c, int x, int y, int w, int h)
|
||||
{
|
||||
- XWindowChanges wc;
|
||||
+ resizeclientpad(c, x, y, w, h, w, h);
|
||||
+}
|
||||
|
||||
+/* This is essentially the resizeclient function renamed with two
|
||||
+ * additional parameters, tw and th (for tile width and height). */
|
||||
+void
|
||||
+resizeclientpad(Client *c, int x, int y, int w, int h, int tw, int th)
|
||||
+{
|
||||
+ XWindowChanges wc;
|
||||
c->oldx = c->x; c->x = wc.x = x;
|
||||
c->oldy = c->y; c->y = wc.y = y;
|
||||
c->oldw = c->w; c->w = wc.width = w;
|
||||
c->oldh = c->h; c->h = wc.height = h;
|
||||
+ if (!c->isfloating) {
|
||||
+ if (w != tw) {
|
||||
+ wc.x += (tw - w) / 2;
|
||||
+ c->w = tw;
|
||||
+ }
|
||||
+ if (h != th) {
|
||||
+ wc.y += (th - h) / 2;
|
||||
+ c->h = th;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
wc.border_width = c->bw;
|
||||
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
|
||||
configure(c);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,119 @@
|
||||
From 112abfec73e12282e4b0288f2e7739000ad135b6 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:21:06 +0100
|
||||
Subject: [PATCH] Adding cfacts patch which provides the ability to assign
|
||||
different weights to clients in their respective stack in tiled layout.
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/cfacts/
|
||||
---
|
||||
config.def.h | 3 +++
|
||||
dwm.c | 35 ++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 35 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5b0cfde 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -71,6 +71,9 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
+ { 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, XK_Return, zoom, {0} },
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..bcb155d 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -87,6 +87,7 @@ typedef struct Client Client;
|
||||
struct Client {
|
||||
char name[256];
|
||||
float mina, maxa;
|
||||
+ float cfact;
|
||||
int x, y, w, h;
|
||||
int oldx, oldy, oldw, oldh;
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
@@ -201,6 +202,7 @@ static void setclientstate(Client *c, long state);
|
||||
static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
+static void setcfact(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
@@ -1033,6 +1035,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->w = c->oldw = wa->width;
|
||||
c->h = c->oldh = wa->height;
|
||||
c->oldbw = wa->border_width;
|
||||
+ c->cfact = 1.0;
|
||||
|
||||
updatetitle(c);
|
||||
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
||||
@@ -1515,6 +1518,24 @@ setlayout(const Arg *arg)
|
||||
drawbar(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+setcfact(const Arg *arg) {
|
||||
+ float f;
|
||||
+ Client *c;
|
||||
+
|
||||
+ c = selmon->sel;
|
||||
+
|
||||
+ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+ f = arg->f + c->cfact;
|
||||
+ if(arg->f == 0.0)
|
||||
+ f = 1.0;
|
||||
+ else if(f < 0.25 || f > 4.0)
|
||||
+ return;
|
||||
+ c->cfact = f;
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
/* arg > 1.0 will set mfact absolutely */
|
||||
void
|
||||
setmfact(const Arg *arg)
|
||||
@@ -1678,9 +1699,15 @@ void
|
||||
tile(Monitor *m)
|
||||
{
|
||||
unsigned int i, n, h, mw, my, ty;
|
||||
+ float mfacts = 0, sfacts = 0;
|
||||
Client *c;
|
||||
|
||||
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
|
||||
+ if (n < m->nmaster)
|
||||
+ mfacts += c->cfact;
|
||||
+ else
|
||||
+ sfacts += c->cfact;
|
||||
+ }
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
@@ -1690,15 +1717,17 @@ tile(Monitor *m)
|
||||
mw = m->ww;
|
||||
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
if (i < m->nmaster) {
|
||||
- h = (m->wh - my) / (MIN(n, m->nmaster) - i);
|
||||
+ h = (m->wh - my) * (c->cfact / mfacts);
|
||||
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
if (my + HEIGHT(c) < m->wh)
|
||||
my += HEIGHT(c);
|
||||
+ mfacts -= c->cfact;
|
||||
} else {
|
||||
- h = (m->wh - ty) / (n - i);
|
||||
+ h = (m->wh - ty) * (c->cfact / sfacts);
|
||||
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
if (ty + HEIGHT(c) < m->wh)
|
||||
ty += HEIGHT(c);
|
||||
+ sfacts -= c->cfact;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,152 @@
|
||||
From 39647ff8b155bdff072e32d04ca4e1c5e27873d5 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:22:21 +0100
|
||||
Subject: [PATCH 2/2] The dragcfact patch allow you resize clients' size (i.e.
|
||||
modify cfact) by holding modkey + shift + right-click and dragging the mouse.
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwm.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
2 files changed, 89 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5b0cfde..595cf43 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -111,6 +111,7 @@ static Button buttons[] = {
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
+ { ClkClientWin, MODKEY|ShiftMask, Button3, dragcfact, {0} },
|
||||
{ ClkTagBar, 0, Button1, view, {0} },
|
||||
{ ClkTagBar, 0, Button3, toggleview, {0} },
|
||||
{ ClkTagBar, MODKEY, Button1, tag, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index bcb155d..54f7320 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -162,6 +162,7 @@ static void destroynotify(XEvent *e);
|
||||
static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
+static void dragcfact(const Arg *arg);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
@@ -695,6 +696,81 @@ dirtomon(int dir)
|
||||
return m;
|
||||
}
|
||||
|
||||
+void
|
||||
+dragcfact(const Arg *arg)
|
||||
+{
|
||||
+ int prev_x, prev_y, dist_x, dist_y;
|
||||
+ float fact;
|
||||
+ Client *c;
|
||||
+ XEvent ev;
|
||||
+ Time lasttime = 0;
|
||||
+
|
||||
+ if (!(c = selmon->sel))
|
||||
+ return;
|
||||
+ if (c->isfloating) {
|
||||
+ resizemouse(arg);
|
||||
+ return;
|
||||
+ }
|
||||
+ #if !FAKEFULLSCREEN_PATCH
|
||||
+ #if FAKEFULLSCREEN_CLIENT_PATCH
|
||||
+ if (c->isfullscreen && !c->fakefullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ return;
|
||||
+ #else
|
||||
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ return;
|
||||
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
|
||||
+ #endif // !FAKEFULLSCREEN_PATCH
|
||||
+ restack(selmon);
|
||||
+
|
||||
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
||||
+ return;
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||
+
|
||||
+ prev_x = prev_y = -999999;
|
||||
+
|
||||
+ do {
|
||||
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
+ switch(ev.type) {
|
||||
+ case ConfigureRequest:
|
||||
+ case Expose:
|
||||
+ case MapRequest:
|
||||
+ handler[ev.type](&ev);
|
||||
+ break;
|
||||
+ case MotionNotify:
|
||||
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
|
||||
+ continue;
|
||||
+ lasttime = ev.xmotion.time;
|
||||
+ if (prev_x == -999999) {
|
||||
+ prev_x = ev.xmotion.x_root;
|
||||
+ prev_y = ev.xmotion.y_root;
|
||||
+ }
|
||||
+
|
||||
+ dist_x = ev.xmotion.x - prev_x;
|
||||
+ dist_y = ev.xmotion.y - prev_y;
|
||||
+
|
||||
+ if (abs(dist_x) > abs(dist_y)) {
|
||||
+ fact = (float) 4.0 * dist_x / c->mon->ww;
|
||||
+ } else {
|
||||
+ fact = (float) -4.0 * dist_y / c->mon->wh;
|
||||
+ }
|
||||
+
|
||||
+ if (fact)
|
||||
+ setcfact(&((Arg) { .f = fact }));
|
||||
+
|
||||
+ prev_x = ev.xmotion.x;
|
||||
+ prev_y = ev.xmotion.y;
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (ev.type != ButtonRelease);
|
||||
+
|
||||
+
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||
+
|
||||
+ XUngrabPointer(dpy, CurrentTime);
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
+}
|
||||
+
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
@@ -1519,19 +1595,25 @@ setlayout(const Arg *arg)
|
||||
}
|
||||
|
||||
void
|
||||
-setcfact(const Arg *arg) {
|
||||
+setcfact(const Arg *arg)
|
||||
+{
|
||||
float f;
|
||||
Client *c;
|
||||
|
||||
c = selmon->sel;
|
||||
|
||||
- if(!arg || !c || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ if (!arg || !c || !selmon->lt[selmon->sellt]->arrange)
|
||||
return;
|
||||
- f = arg->f + c->cfact;
|
||||
- if(arg->f == 0.0)
|
||||
+ if (!arg->f)
|
||||
f = 1.0;
|
||||
- else if(f < 0.25 || f > 4.0)
|
||||
- return;
|
||||
+ else if (arg->f > 4.0) // set fact absolutely
|
||||
+ f = arg->f - 4.0;
|
||||
+ else
|
||||
+ f = arg->f + c->cfact;
|
||||
+ if (f < 0.25)
|
||||
+ f = 0.25;
|
||||
+ else if (f > 4.0)
|
||||
+ f = 4.0;
|
||||
c->cfact = f;
|
||||
arrange(selmon);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,272 @@
|
||||
From 112abfec73e12282e4b0288f2e7739000ad135b6 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:21:06 +0100
|
||||
Subject: [PATCH 1/2] Adding cfacts patch which provides the ability to assign
|
||||
different weights to clients in their respective stack in tiled layout.
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/cfacts/
|
||||
---
|
||||
config.def.h | 3 +++
|
||||
dwm.c | 35 ++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 35 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5b0cfde 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -71,6 +71,9 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
+ { 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, XK_Return, zoom, {0} },
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..bcb155d 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -87,6 +87,7 @@ typedef struct Client Client;
|
||||
struct Client {
|
||||
char name[256];
|
||||
float mina, maxa;
|
||||
+ float cfact;
|
||||
int x, y, w, h;
|
||||
int oldx, oldy, oldw, oldh;
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
@@ -201,6 +202,7 @@ static void setclientstate(Client *c, long state);
|
||||
static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
+static void setcfact(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
@@ -1033,6 +1035,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->w = c->oldw = wa->width;
|
||||
c->h = c->oldh = wa->height;
|
||||
c->oldbw = wa->border_width;
|
||||
+ c->cfact = 1.0;
|
||||
|
||||
updatetitle(c);
|
||||
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
||||
@@ -1515,6 +1518,24 @@ setlayout(const Arg *arg)
|
||||
drawbar(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+setcfact(const Arg *arg) {
|
||||
+ float f;
|
||||
+ Client *c;
|
||||
+
|
||||
+ c = selmon->sel;
|
||||
+
|
||||
+ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ return;
|
||||
+ f = arg->f + c->cfact;
|
||||
+ if(arg->f == 0.0)
|
||||
+ f = 1.0;
|
||||
+ else if(f < 0.25 || f > 4.0)
|
||||
+ return;
|
||||
+ c->cfact = f;
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
/* arg > 1.0 will set mfact absolutely */
|
||||
void
|
||||
setmfact(const Arg *arg)
|
||||
@@ -1678,9 +1699,15 @@ void
|
||||
tile(Monitor *m)
|
||||
{
|
||||
unsigned int i, n, h, mw, my, ty;
|
||||
+ float mfacts = 0, sfacts = 0;
|
||||
Client *c;
|
||||
|
||||
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
|
||||
+ if (n < m->nmaster)
|
||||
+ mfacts += c->cfact;
|
||||
+ else
|
||||
+ sfacts += c->cfact;
|
||||
+ }
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
@@ -1690,15 +1717,17 @@ tile(Monitor *m)
|
||||
mw = m->ww;
|
||||
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
if (i < m->nmaster) {
|
||||
- h = (m->wh - my) / (MIN(n, m->nmaster) - i);
|
||||
+ h = (m->wh - my) * (c->cfact / mfacts);
|
||||
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
if (my + HEIGHT(c) < m->wh)
|
||||
my += HEIGHT(c);
|
||||
+ mfacts -= c->cfact;
|
||||
} else {
|
||||
- h = (m->wh - ty) / (n - i);
|
||||
+ h = (m->wh - ty) * (c->cfact / sfacts);
|
||||
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
if (ty + HEIGHT(c) < m->wh)
|
||||
ty += HEIGHT(c);
|
||||
+ sfacts -= c->cfact;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 39647ff8b155bdff072e32d04ca4e1c5e27873d5 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:22:21 +0100
|
||||
Subject: [PATCH 2/2] The dragcfact patch allow you resize clients' size (i.e.
|
||||
modify cfact) by holding modkey + shift + right-click and dragging the mouse.
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwm.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
2 files changed, 89 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5b0cfde..595cf43 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -111,6 +111,7 @@ static Button buttons[] = {
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
+ { ClkClientWin, MODKEY|ShiftMask, Button3, dragcfact, {0} },
|
||||
{ ClkTagBar, 0, Button1, view, {0} },
|
||||
{ ClkTagBar, 0, Button3, toggleview, {0} },
|
||||
{ ClkTagBar, MODKEY, Button1, tag, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index bcb155d..54f7320 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -162,6 +162,7 @@ static void destroynotify(XEvent *e);
|
||||
static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
+static void dragcfact(const Arg *arg);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
@@ -695,6 +696,81 @@ dirtomon(int dir)
|
||||
return m;
|
||||
}
|
||||
|
||||
+void
|
||||
+dragcfact(const Arg *arg)
|
||||
+{
|
||||
+ int prev_x, prev_y, dist_x, dist_y;
|
||||
+ float fact;
|
||||
+ Client *c;
|
||||
+ XEvent ev;
|
||||
+ Time lasttime = 0;
|
||||
+
|
||||
+ if (!(c = selmon->sel))
|
||||
+ return;
|
||||
+ if (c->isfloating) {
|
||||
+ resizemouse(arg);
|
||||
+ return;
|
||||
+ }
|
||||
+ #if !FAKEFULLSCREEN_PATCH
|
||||
+ #if FAKEFULLSCREEN_CLIENT_PATCH
|
||||
+ if (c->isfullscreen && !c->fakefullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ return;
|
||||
+ #else
|
||||
+ if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ return;
|
||||
+ #endif // FAKEFULLSCREEN_CLIENT_PATCH
|
||||
+ #endif // !FAKEFULLSCREEN_PATCH
|
||||
+ restack(selmon);
|
||||
+
|
||||
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
||||
+ return;
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||
+
|
||||
+ prev_x = prev_y = -999999;
|
||||
+
|
||||
+ do {
|
||||
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
+ switch(ev.type) {
|
||||
+ case ConfigureRequest:
|
||||
+ case Expose:
|
||||
+ case MapRequest:
|
||||
+ handler[ev.type](&ev);
|
||||
+ break;
|
||||
+ case MotionNotify:
|
||||
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
|
||||
+ continue;
|
||||
+ lasttime = ev.xmotion.time;
|
||||
+ if (prev_x == -999999) {
|
||||
+ prev_x = ev.xmotion.x_root;
|
||||
+ prev_y = ev.xmotion.y_root;
|
||||
+ }
|
||||
+
|
||||
+ dist_x = ev.xmotion.x - prev_x;
|
||||
+ dist_y = ev.xmotion.y - prev_y;
|
||||
+
|
||||
+ if (abs(dist_x) > abs(dist_y)) {
|
||||
+ fact = (float) 4.0 * dist_x / c->mon->ww;
|
||||
+ } else {
|
||||
+ fact = (float) -4.0 * dist_y / c->mon->wh;
|
||||
+ }
|
||||
+
|
||||
+ if (fact)
|
||||
+ setcfact(&((Arg) { .f = fact }));
|
||||
+
|
||||
+ prev_x = ev.xmotion.x;
|
||||
+ prev_y = ev.xmotion.y;
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (ev.type != ButtonRelease);
|
||||
+
|
||||
+
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||
+
|
||||
+ XUngrabPointer(dpy, CurrentTime);
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
+}
|
||||
+
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
@@ -1519,19 +1595,25 @@ setlayout(const Arg *arg)
|
||||
}
|
||||
|
||||
void
|
||||
-setcfact(const Arg *arg) {
|
||||
+setcfact(const Arg *arg)
|
||||
+{
|
||||
float f;
|
||||
Client *c;
|
||||
|
||||
c = selmon->sel;
|
||||
|
||||
- if(!arg || !c || !selmon->lt[selmon->sellt]->arrange)
|
||||
+ if (!arg || !c || !selmon->lt[selmon->sellt]->arrange)
|
||||
return;
|
||||
- f = arg->f + c->cfact;
|
||||
- if(arg->f == 0.0)
|
||||
+ if (!arg->f)
|
||||
f = 1.0;
|
||||
- else if(f < 0.25 || f > 4.0)
|
||||
- return;
|
||||
+ else if (arg->f > 4.0) // set fact absolutely
|
||||
+ f = arg->f - 4.0;
|
||||
+ else
|
||||
+ f = arg->f + c->cfact;
|
||||
+ if (f < 0.25)
|
||||
+ f = 0.25;
|
||||
+ else if (f > 4.0)
|
||||
+ f = 4.0;
|
||||
c->cfact = f;
|
||||
arrange(selmon);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,994 @@
|
||||
From 3786a63796c661a8a66b4a10aa45dcf77cdf68ac Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:26:11 +0100
|
||||
Subject: [PATCH 2/2] vanitygaps - adds gaps to layouts
|
||||
|
||||
This patch differentiates between inner and outer gaps as well as
|
||||
horizontal and vertical gaps.
|
||||
|
||||
The logic of these layouts also aims to be pixel perfect by ensuring
|
||||
an even split of the available space and re-distributing the remainder
|
||||
among the available clients.
|
||||
---
|
||||
config.def.h | 38 ++-
|
||||
dwm.c | 45 +--
|
||||
vanitygaps.c | 822 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 867 insertions(+), 38 deletions(-)
|
||||
create mode 100644 vanitygaps.c
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5b0cfde..b9c2e61 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -3,6 +3,11 @@
|
||||
/* appearance */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
+static const unsigned int gappih = 20; /* horiz inner gap between windows */
|
||||
+static const unsigned int gappiv = 10; /* vert inner gap between windows */
|
||||
+static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
|
||||
+static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */
|
||||
+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 const char *fonts[] = { "monospace:size=10" };
|
||||
@@ -37,11 +42,26 @@ static const int nmaster = 1; /* number of clients in master area */
|
||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
+#define FORCE_VSPLIT 1 /* nrowgrid layout: force two clients to always split vertically */
|
||||
+#include "vanitygaps.c"
|
||||
+
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
{ "[]=", tile }, /* first entry is default */
|
||||
- { "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { "[@]", spiral },
|
||||
+ { "[\\]", dwindle },
|
||||
+ { "D[]", deck },
|
||||
+ { "TTT", bstack },
|
||||
+ { "===", bstackhoriz },
|
||||
+ { "HHH", grid },
|
||||
+ { "###", nrowgrid },
|
||||
+ { "---", horizgrid },
|
||||
+ { ":::", gaplessgrid },
|
||||
+ { "|M|", centeredmaster },
|
||||
+ { ">M>", centeredfloatingmaster },
|
||||
+ { "><>", NULL }, /* no layout function means floating behavior */
|
||||
+ { NULL, NULL },
|
||||
};
|
||||
|
||||
/* key definitions */
|
||||
@@ -75,6 +95,22 @@ static Key keys[] = {
|
||||
{ MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} },
|
||||
{ MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} },
|
||||
{ MODKEY, XK_Return, zoom, {0} },
|
||||
+ { MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } },
|
||||
+ { MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index bcb155d..36582e1 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -120,6 +120,10 @@ struct Monitor {
|
||||
int by; /* bar geometry */
|
||||
int mx, my, mw, mh; /* screen size */
|
||||
int wx, wy, ww, wh; /* window area */
|
||||
+ int gappih; /* horizontal gap between windows */
|
||||
+ int gappiv; /* vertical gap between windows */
|
||||
+ int gappoh; /* horizontal outer gaps */
|
||||
+ int gappov; /* vertical outer gaps */
|
||||
unsigned int seltags;
|
||||
unsigned int sellt;
|
||||
unsigned int tagset[2];
|
||||
@@ -211,7 +215,6 @@ static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
-static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
@@ -641,6 +644,10 @@ createmon(void)
|
||||
m->nmaster = nmaster;
|
||||
m->showbar = showbar;
|
||||
m->topbar = topbar;
|
||||
+ m->gappih = gappih;
|
||||
+ m->gappiv = gappiv;
|
||||
+ m->gappoh = gappoh;
|
||||
+ m->gappov = gappov;
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
@@ -1695,42 +1702,6 @@ tagmon(const Arg *arg)
|
||||
sendmon(selmon->sel, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
-void
|
||||
-tile(Monitor *m)
|
||||
-{
|
||||
- unsigned int i, n, h, mw, my, ty;
|
||||
- float mfacts = 0, sfacts = 0;
|
||||
- Client *c;
|
||||
-
|
||||
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
|
||||
- if (n < m->nmaster)
|
||||
- mfacts += c->cfact;
|
||||
- else
|
||||
- sfacts += c->cfact;
|
||||
- }
|
||||
- if (n == 0)
|
||||
- return;
|
||||
-
|
||||
- if (n > m->nmaster)
|
||||
- mw = m->nmaster ? m->ww * m->mfact : 0;
|
||||
- else
|
||||
- mw = m->ww;
|
||||
- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
- if (i < m->nmaster) {
|
||||
- h = (m->wh - my) * (c->cfact / mfacts);
|
||||
- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
- if (my + HEIGHT(c) < m->wh)
|
||||
- my += HEIGHT(c);
|
||||
- mfacts -= c->cfact;
|
||||
- } else {
|
||||
- h = (m->wh - ty) * (c->cfact / sfacts);
|
||||
- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
- if (ty + HEIGHT(c) < m->wh)
|
||||
- ty += HEIGHT(c);
|
||||
- sfacts -= c->cfact;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
diff --git a/vanitygaps.c b/vanitygaps.c
|
||||
new file mode 100644
|
||||
index 0000000..1a816b6
|
||||
--- /dev/null
|
||||
+++ b/vanitygaps.c
|
||||
@@ -0,0 +1,822 @@
|
||||
+/* Key binding functions */
|
||||
+static void defaultgaps(const Arg *arg);
|
||||
+static void incrgaps(const Arg *arg);
|
||||
+static void incrigaps(const Arg *arg);
|
||||
+static void incrogaps(const Arg *arg);
|
||||
+static void incrohgaps(const Arg *arg);
|
||||
+static void incrovgaps(const Arg *arg);
|
||||
+static void incrihgaps(const Arg *arg);
|
||||
+static void incrivgaps(const Arg *arg);
|
||||
+static void togglegaps(const Arg *arg);
|
||||
+/* Layouts (delete the ones you do not need) */
|
||||
+static void bstack(Monitor *m);
|
||||
+static void bstackhoriz(Monitor *m);
|
||||
+static void centeredmaster(Monitor *m);
|
||||
+static void centeredfloatingmaster(Monitor *m);
|
||||
+static void deck(Monitor *m);
|
||||
+static void dwindle(Monitor *m);
|
||||
+static void fibonacci(Monitor *m, int s);
|
||||
+static void grid(Monitor *m);
|
||||
+static void nrowgrid(Monitor *m);
|
||||
+static void spiral(Monitor *m);
|
||||
+static void tile(Monitor *m);
|
||||
+/* Internals */
|
||||
+static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc);
|
||||
+static void getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr);
|
||||
+static void setgaps(int oh, int ov, int ih, int iv);
|
||||
+
|
||||
+/* Settings */
|
||||
+#if !PERTAG_PATCH
|
||||
+static int enablegaps = 1;
|
||||
+#endif // PERTAG_PATCH
|
||||
+
|
||||
+void
|
||||
+setgaps(int oh, int ov, int ih, int iv)
|
||||
+{
|
||||
+ if (oh < 0) oh = 0;
|
||||
+ if (ov < 0) ov = 0;
|
||||
+ if (ih < 0) ih = 0;
|
||||
+ if (iv < 0) iv = 0;
|
||||
+
|
||||
+ selmon->gappoh = oh;
|
||||
+ selmon->gappov = ov;
|
||||
+ selmon->gappih = ih;
|
||||
+ selmon->gappiv = iv;
|
||||
+ arrange(selmon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglegaps(const Arg *arg)
|
||||
+{
|
||||
+ #if PERTAG_PATCH
|
||||
+ selmon->pertag->enablegaps[selmon->pertag->curtag] = !selmon->pertag->enablegaps[selmon->pertag->curtag];
|
||||
+ #else
|
||||
+ enablegaps = !enablegaps;
|
||||
+ #endif // PERTAG_PATCH
|
||||
+ arrange(NULL);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+defaultgaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(gappoh, gappov, gappih, gappiv);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrgaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh + arg->i,
|
||||
+ selmon->gappov + arg->i,
|
||||
+ selmon->gappih + arg->i,
|
||||
+ selmon->gappiv + arg->i
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrigaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh,
|
||||
+ selmon->gappov,
|
||||
+ selmon->gappih + arg->i,
|
||||
+ selmon->gappiv + arg->i
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrogaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh + arg->i,
|
||||
+ selmon->gappov + arg->i,
|
||||
+ selmon->gappih,
|
||||
+ selmon->gappiv
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrohgaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh + arg->i,
|
||||
+ selmon->gappov,
|
||||
+ selmon->gappih,
|
||||
+ selmon->gappiv
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrovgaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh,
|
||||
+ selmon->gappov + arg->i,
|
||||
+ selmon->gappih,
|
||||
+ selmon->gappiv
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrihgaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh,
|
||||
+ selmon->gappov,
|
||||
+ selmon->gappih + arg->i,
|
||||
+ selmon->gappiv
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+incrivgaps(const Arg *arg)
|
||||
+{
|
||||
+ setgaps(
|
||||
+ selmon->gappoh,
|
||||
+ selmon->gappov,
|
||||
+ selmon->gappih,
|
||||
+ selmon->gappiv + arg->i
|
||||
+ );
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
|
||||
+{
|
||||
+ unsigned int n, oe, ie;
|
||||
+ #if PERTAG_PATCH
|
||||
+ oe = ie = selmon->pertag->enablegaps[selmon->pertag->curtag];
|
||||
+ #else
|
||||
+ oe = ie = enablegaps;
|
||||
+ #endif // PERTAG_PATCH
|
||||
+ Client *c;
|
||||
+
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
+ if (smartgaps && n == 1) {
|
||||
+ oe = 0; // outer gaps disabled when only one client
|
||||
+ }
|
||||
+
|
||||
+ *oh = m->gappoh*oe; // outer horizontal gap
|
||||
+ *ov = m->gappov*oe; // outer vertical gap
|
||||
+ *ih = m->gappih*ie; // inner horizontal gap
|
||||
+ *iv = m->gappiv*ie; // inner vertical gap
|
||||
+ *nc = n; // number of clients
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
|
||||
+{
|
||||
+ unsigned int n;
|
||||
+ float mfacts = 0, sfacts = 0;
|
||||
+ int mtotal = 0, stotal = 0;
|
||||
+ Client *c;
|
||||
+
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
|
||||
+ if (n < m->nmaster)
|
||||
+ mfacts += c->cfact;
|
||||
+ else
|
||||
+ sfacts += c->cfact;
|
||||
+
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
|
||||
+ if (n < m->nmaster)
|
||||
+ mtotal += msize * (c->cfact / mfacts);
|
||||
+ else
|
||||
+ stotal += ssize * (c->cfact / sfacts);
|
||||
+
|
||||
+ *mf = mfacts; // total factor of master area
|
||||
+ *sf = sfacts; // total factor of stack area
|
||||
+ *mr = msize - mtotal; // the remainder (rest) of pixels after a cfacts master split
|
||||
+ *sr = ssize - stotal; // the remainder (rest) of pixels after a cfacts stack split
|
||||
+}
|
||||
+
|
||||
+/***
|
||||
+ * Layouts
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * Bottomstack layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/bottomstack/
|
||||
+ */
|
||||
+static void
|
||||
+bstack(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int sx = 0, sy = 0, sh = 0, sw = 0;
|
||||
+ float mfacts, sfacts;
|
||||
+ int mrest, srest;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sx = mx = m->wx + ov;
|
||||
+ sy = my = m->wy + oh;
|
||||
+ sh = mh = m->wh - 2*oh;
|
||||
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
|
||||
+ sw = m->ww - 2*ov - iv * (n - m->nmaster - 1);
|
||||
+
|
||||
+ if (m->nmaster && n > m->nmaster) {
|
||||
+ sh = (mh - ih) * (1 - m->mfact);
|
||||
+ mh = mh - ih - sh;
|
||||
+ sx = mx;
|
||||
+ sy = my + mh + ih;
|
||||
+ }
|
||||
+
|
||||
+ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
|
||||
+ if (i < m->nmaster) {
|
||||
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
||||
+ mx += WIDTH(c) + iv;
|
||||
+ } else {
|
||||
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
|
||||
+ sx += WIDTH(c) + iv;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+bstackhoriz(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int sx = 0, sy = 0, sh = 0, sw = 0;
|
||||
+ float mfacts, sfacts;
|
||||
+ int mrest, srest;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sx = mx = m->wx + ov;
|
||||
+ sy = my = m->wy + oh;
|
||||
+ mh = m->wh - 2*oh;
|
||||
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
|
||||
+ mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
|
||||
+ sw = m->ww - 2*ov;
|
||||
+
|
||||
+ if (m->nmaster && n > m->nmaster) {
|
||||
+ sh = (mh - ih) * (1 - m->mfact);
|
||||
+ mh = mh - ih - sh;
|
||||
+ sy = my + mh + ih;
|
||||
+ sh = m->wh - mh - 2*oh - ih * (n - m->nmaster);
|
||||
+ }
|
||||
+
|
||||
+ getfacts(m, mw, sh, &mfacts, &sfacts, &mrest, &srest);
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
|
||||
+ if (i < m->nmaster) {
|
||||
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
||||
+ mx += WIDTH(c) + iv;
|
||||
+ } else {
|
||||
+ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ sy += HEIGHT(c) + ih;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Centred master layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/centeredmaster/
|
||||
+ */
|
||||
+void
|
||||
+centeredmaster(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int lx = 0, ly = 0, lw = 0, lh = 0;
|
||||
+ int rx = 0, ry = 0, rw = 0, rh = 0;
|
||||
+ float mfacts = 0, lfacts = 0, rfacts = 0;
|
||||
+ int mtotal = 0, ltotal = 0, rtotal = 0;
|
||||
+ int mrest = 0, lrest = 0, rrest = 0;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* initialize areas */
|
||||
+ mx = m->wx + ov;
|
||||
+ my = m->wy + oh;
|
||||
+ mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1);
|
||||
+ mw = m->ww - 2*ov;
|
||||
+ lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1);
|
||||
+ rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1));
|
||||
+
|
||||
+ if (m->nmaster && n > m->nmaster) {
|
||||
+ /* go mfact box in the center if more than nmaster clients */
|
||||
+ if (n - m->nmaster > 1) {
|
||||
+ /* ||<-S->|<---M--->|<-S->|| */
|
||||
+ mw = (m->ww - 2*ov - 2*iv) * m->mfact;
|
||||
+ lw = (m->ww - mw - 2*ov - 2*iv) / 2;
|
||||
+ rw = (m->ww - mw - 2*ov - 2*iv) - lw;
|
||||
+ mx += lw + iv;
|
||||
+ } else {
|
||||
+ /* ||<---M--->|<-S->|| */
|
||||
+ mw = (mw - iv) * m->mfact;
|
||||
+ lw = 0;
|
||||
+ rw = m->ww - mw - iv - 2*ov;
|
||||
+ }
|
||||
+ lx = m->wx + ov;
|
||||
+ ly = m->wy + oh;
|
||||
+ rx = mx + mw + iv;
|
||||
+ ry = m->wy + oh;
|
||||
+ }
|
||||
+
|
||||
+ /* calculate facts */
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
|
||||
+ if (!m->nmaster || n < m->nmaster)
|
||||
+ mfacts += c->cfact;
|
||||
+ else if ((n - m->nmaster) % 2)
|
||||
+ lfacts += c->cfact; // total factor of left hand stack area
|
||||
+ else
|
||||
+ rfacts += c->cfact; // total factor of right hand stack area
|
||||
+ }
|
||||
+
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
|
||||
+ if (!m->nmaster || n < m->nmaster)
|
||||
+ mtotal += mh * (c->cfact / mfacts);
|
||||
+ else if ((n - m->nmaster) % 2)
|
||||
+ ltotal += lh * (c->cfact / lfacts);
|
||||
+ else
|
||||
+ rtotal += rh * (c->cfact / rfacts);
|
||||
+
|
||||
+ mrest = mh - mtotal;
|
||||
+ lrest = lh - ltotal;
|
||||
+ rrest = rh - rtotal;
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
|
||||
+ if (!m->nmaster || i < m->nmaster) {
|
||||
+ /* nmaster clients are stacked vertically, in the center of the screen */
|
||||
+ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ my += HEIGHT(c) + ih;
|
||||
+ } else {
|
||||
+ /* stack clients are stacked vertically */
|
||||
+ if ((i - m->nmaster) % 2 ) {
|
||||
+ resize(c, lx, ly, lw - (2*c->bw), lh * (c->cfact / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ ly += HEIGHT(c) + ih;
|
||||
+ } else {
|
||||
+ resize(c, rx, ry, rw - (2*c->bw), rh * (c->cfact / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ ry += HEIGHT(c) + ih;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+centeredfloatingmaster(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ float mfacts, sfacts;
|
||||
+ float mivf = 1.0; // master inner vertical gap factor
|
||||
+ int oh, ov, ih, iv, mrest, srest;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int sx = 0, sy = 0, sh = 0, sw = 0;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sx = mx = m->wx + ov;
|
||||
+ sy = my = m->wy + oh;
|
||||
+ sh = mh = m->wh - 2*oh;
|
||||
+ mw = m->ww - 2*ov - iv*(n - 1);
|
||||
+ sw = m->ww - 2*ov - iv*(n - m->nmaster - 1);
|
||||
+
|
||||
+ if (m->nmaster && n > m->nmaster) {
|
||||
+ mivf = 0.8;
|
||||
+ /* go mfact box in the center if more than nmaster clients */
|
||||
+ if (m->ww > m->wh) {
|
||||
+ mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1);
|
||||
+ mh = m->wh * 0.9;
|
||||
+ } else {
|
||||
+ mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1);
|
||||
+ mh = m->wh * m->mfact;
|
||||
+ }
|
||||
+ mx = m->wx + (m->ww - mw) / 2;
|
||||
+ my = m->wy + (m->wh - mh - 2*oh) / 2;
|
||||
+
|
||||
+ sx = m->wx + ov;
|
||||
+ sy = m->wy + oh;
|
||||
+ sh = m->wh - 2*oh;
|
||||
+ }
|
||||
+
|
||||
+ getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < m->nmaster) {
|
||||
+ /* nmaster clients are stacked horizontally, in the center of the screen */
|
||||
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
||||
+ mx += WIDTH(c) + iv*mivf;
|
||||
+ } else {
|
||||
+ /* stack clients are stacked horizontally */
|
||||
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
|
||||
+ sx += WIDTH(c) + iv;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Deck layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/deck/
|
||||
+ */
|
||||
+void
|
||||
+deck(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int sx = 0, sy = 0, sh = 0, sw = 0;
|
||||
+ float mfacts, sfacts;
|
||||
+ int mrest, srest;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sx = mx = m->wx + ov;
|
||||
+ sy = my = m->wy + oh;
|
||||
+ sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
|
||||
+ sw = mw = m->ww - 2*ov;
|
||||
+
|
||||
+ if (m->nmaster && n > m->nmaster) {
|
||||
+ sw = (mw - iv) * (1 - m->mfact);
|
||||
+ mw = mw - iv - sw;
|
||||
+ sx = mx + mw + iv;
|
||||
+ sh = m->wh - 2*oh;
|
||||
+ }
|
||||
+
|
||||
+ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
|
||||
+
|
||||
+ if (n - m->nmaster > 0) /* override layout symbol */
|
||||
+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < m->nmaster) {
|
||||
+ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ my += HEIGHT(c) + ih;
|
||||
+ } else {
|
||||
+ resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Fibonacci layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/fibonacci/
|
||||
+ */
|
||||
+void
|
||||
+fibonacci(Monitor *m, int s)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int nx, ny, nw, nh;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int nv, hrest = 0, wrest = 0, r = 1;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ nx = m->wx + ov;
|
||||
+ ny = m->wy + oh;
|
||||
+ nw = m->ww - 2*ov;
|
||||
+ nh = m->wh - 2*oh;
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
|
||||
+ if (r) {
|
||||
+ if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw))
|
||||
+ || (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) {
|
||||
+ r = 0;
|
||||
+ }
|
||||
+ if (r && i < n - 1) {
|
||||
+ if (i % 2) {
|
||||
+ nv = (nh - ih) / 2;
|
||||
+ hrest = nh - 2*nv - ih;
|
||||
+ nh = nv;
|
||||
+ } else {
|
||||
+ nv = (nw - iv) / 2;
|
||||
+ wrest = nw - 2*nv - iv;
|
||||
+ nw = nv;
|
||||
+ }
|
||||
+
|
||||
+ if ((i % 4) == 2 && !s)
|
||||
+ nx += nw + iv;
|
||||
+ else if ((i % 4) == 3 && !s)
|
||||
+ ny += nh + ih;
|
||||
+ }
|
||||
+
|
||||
+ if ((i % 4) == 0) {
|
||||
+ if (s) {
|
||||
+ ny += nh + ih;
|
||||
+ nh += hrest;
|
||||
+ }
|
||||
+ else {
|
||||
+ nh -= hrest;
|
||||
+ ny -= nh + ih;
|
||||
+ }
|
||||
+ }
|
||||
+ else if ((i % 4) == 1) {
|
||||
+ nx += nw + iv;
|
||||
+ nw += wrest;
|
||||
+ }
|
||||
+ else if ((i % 4) == 2) {
|
||||
+ ny += nh + ih;
|
||||
+ nh += hrest;
|
||||
+ if (i < n - 1)
|
||||
+ nw += wrest;
|
||||
+ }
|
||||
+ else if ((i % 4) == 3) {
|
||||
+ if (s) {
|
||||
+ nx += nw + iv;
|
||||
+ nw -= wrest;
|
||||
+ } else {
|
||||
+ nw -= wrest;
|
||||
+ nx -= nw + iv;
|
||||
+ nh += hrest;
|
||||
+ }
|
||||
+ }
|
||||
+ if (i == 0) {
|
||||
+ if (n != 1) {
|
||||
+ nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact);
|
||||
+ wrest = 0;
|
||||
+ }
|
||||
+ ny = m->wy + oh;
|
||||
+ }
|
||||
+ else if (i == 1)
|
||||
+ nw = m->ww - nw - iv - 2*ov;
|
||||
+ i++;
|
||||
+ }
|
||||
+
|
||||
+ resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+dwindle(Monitor *m)
|
||||
+{
|
||||
+ fibonacci(m, 1);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+spiral(Monitor *m)
|
||||
+{
|
||||
+ fibonacci(m, 0);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Gappless grid layout + gaps (ironically)
|
||||
+ * https://dwm.suckless.org/patches/gaplessgrid/
|
||||
+ */
|
||||
+void
|
||||
+gaplessgrid(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
|
||||
+ int oh, ov, ih, iv;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* grid dimensions */
|
||||
+ for (cols = 0; cols <= n/2; cols++)
|
||||
+ if (cols*cols >= n)
|
||||
+ break;
|
||||
+ if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
|
||||
+ cols = 2;
|
||||
+ rows = n/cols;
|
||||
+ cn = rn = 0; // reset column no, row no, client count
|
||||
+
|
||||
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
|
||||
+ cw = (m->ww - 2*ov - iv * (cols - 1)) / cols;
|
||||
+ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
|
||||
+ crest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
|
||||
+ x = m->wx + ov;
|
||||
+ y = m->wy + oh;
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
|
||||
+ if (i/rows + 1 > cols - n%cols) {
|
||||
+ rows = n/cols + 1;
|
||||
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / rows;
|
||||
+ rrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
|
||||
+ }
|
||||
+ resize(c,
|
||||
+ x,
|
||||
+ y + rn*(ch + ih) + MIN(rn, rrest),
|
||||
+ cw + (cn < crest ? 1 : 0) - 2*c->bw,
|
||||
+ ch + (rn < rrest ? 1 : 0) - 2*c->bw,
|
||||
+ 0);
|
||||
+ rn++;
|
||||
+ if (rn >= rows) {
|
||||
+ rn = 0;
|
||||
+ x += cw + ih + (cn < crest ? 1 : 0);
|
||||
+ cn++;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Gridmode layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/gridmode/
|
||||
+ */
|
||||
+void
|
||||
+grid(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+
|
||||
+ /* grid dimensions */
|
||||
+ for (rows = 0; rows <= n/2; rows++)
|
||||
+ if (rows*rows >= n)
|
||||
+ break;
|
||||
+ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
|
||||
+
|
||||
+ /* window geoms (cell height/width) */
|
||||
+ ch = (m->wh - 2*oh - ih * (rows - 1)) / (rows ? rows : 1);
|
||||
+ cw = (m->ww - 2*ov - iv * (cols - 1)) / (cols ? cols : 1);
|
||||
+ chrest = (m->wh - 2*oh - ih * (rows - 1)) - ch * rows;
|
||||
+ cwrest = (m->ww - 2*ov - iv * (cols - 1)) - cw * cols;
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
|
||||
+ cc = i / rows;
|
||||
+ cr = i % rows;
|
||||
+ cx = m->wx + ov + cc * (cw + iv) + MIN(cc, cwrest);
|
||||
+ cy = m->wy + oh + cr * (ch + ih) + MIN(cr, chrest);
|
||||
+ resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Horizontal grid layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/horizgrid/
|
||||
+ */
|
||||
+void
|
||||
+horizgrid(Monitor *m) {
|
||||
+ Client *c;
|
||||
+ unsigned int n, i;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int sx = 0, sy = 0, sh = 0, sw = 0;
|
||||
+ int ntop, nbottom = 1;
|
||||
+ float mfacts = 0, sfacts = 0;
|
||||
+ int mrest, srest, mtotal = 0, stotal = 0;
|
||||
+
|
||||
+ /* Count windows */
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ if (n <= 2)
|
||||
+ ntop = n;
|
||||
+ else {
|
||||
+ ntop = n / 2;
|
||||
+ nbottom = n - ntop;
|
||||
+ }
|
||||
+ sx = mx = m->wx + ov;
|
||||
+ sy = my = m->wy + oh;
|
||||
+ sh = mh = m->wh - 2*oh;
|
||||
+ sw = mw = m->ww - 2*ov;
|
||||
+
|
||||
+ if (n > ntop) {
|
||||
+ sh = (mh - ih) / 2;
|
||||
+ mh = mh - ih - sh;
|
||||
+ sy = my + mh + ih;
|
||||
+ mw = m->ww - 2*ov - iv * (ntop - 1);
|
||||
+ sw = m->ww - 2*ov - iv * (nbottom - 1);
|
||||
+ }
|
||||
+
|
||||
+ /* calculate facts */
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < ntop)
|
||||
+ mfacts += c->cfact;
|
||||
+ else
|
||||
+ sfacts += c->cfact;
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < ntop)
|
||||
+ mtotal += mh * (c->cfact / mfacts);
|
||||
+ else
|
||||
+ stotal += sw * (c->cfact / sfacts);
|
||||
+
|
||||
+ mrest = mh - mtotal;
|
||||
+ srest = sw - stotal;
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < ntop) {
|
||||
+ resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
||||
+ mx += WIDTH(c) + iv;
|
||||
+ } else {
|
||||
+ resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
|
||||
+ sx += WIDTH(c) + iv;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * nrowgrid layout + gaps
|
||||
+ * https://dwm.suckless.org/patches/nrowgrid/
|
||||
+ */
|
||||
+void
|
||||
+nrowgrid(Monitor *m)
|
||||
+{
|
||||
+ unsigned int n;
|
||||
+ int ri = 0, ci = 0; /* counters */
|
||||
+ int oh, ov, ih, iv; /* vanitygap settings */
|
||||
+ unsigned int cx, cy, cw, ch; /* client geometry */
|
||||
+ unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */
|
||||
+ unsigned int cols, rows = m->nmaster + 1;
|
||||
+ Client *c;
|
||||
+
|
||||
+ /* count clients */
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+
|
||||
+ /* nothing to do here */
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ /* force 2 clients to always split vertically */
|
||||
+ if (FORCE_VSPLIT && n == 2)
|
||||
+ rows = 1;
|
||||
+
|
||||
+ /* never allow empty rows */
|
||||
+ if (n < rows)
|
||||
+ rows = n;
|
||||
+
|
||||
+ /* define first row */
|
||||
+ cols = n / rows;
|
||||
+ uc = cols;
|
||||
+ cy = m->wy + oh;
|
||||
+ ch = (m->wh - 2*oh - ih*(rows - 1)) / rows;
|
||||
+ uh = ch;
|
||||
+
|
||||
+ for (c = nexttiled(m->clients); c; c = nexttiled(c->next), ci++) {
|
||||
+ if (ci == cols) {
|
||||
+ uw = 0;
|
||||
+ ci = 0;
|
||||
+ ri++;
|
||||
+
|
||||
+ /* next row */
|
||||
+ cols = (n - uc) / (rows - ri);
|
||||
+ uc += cols;
|
||||
+ cy = m->wy + oh + uh + ih;
|
||||
+ uh += ch + ih;
|
||||
+ }
|
||||
+
|
||||
+ cx = m->wx + ov + uw;
|
||||
+ cw = (m->ww - 2*ov - uw) / (cols - ci);
|
||||
+ uw += cw + iv;
|
||||
+
|
||||
+ resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Default tile layout + gaps
|
||||
+ */
|
||||
+static void
|
||||
+tile(Monitor *m)
|
||||
+{
|
||||
+ unsigned int i, n;
|
||||
+ int oh, ov, ih, iv;
|
||||
+ int mx = 0, my = 0, mh = 0, mw = 0;
|
||||
+ int sx = 0, sy = 0, sh = 0, sw = 0;
|
||||
+ float mfacts, sfacts;
|
||||
+ int mrest, srest;
|
||||
+ Client *c;
|
||||
+
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ if (n == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sx = mx = m->wx + ov;
|
||||
+ sy = my = m->wy + oh;
|
||||
+ mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
|
||||
+ sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
|
||||
+ sw = mw = m->ww - 2*ov;
|
||||
+
|
||||
+ if (m->nmaster && n > m->nmaster) {
|
||||
+ sw = (mw - iv) * (1 - m->mfact);
|
||||
+ mw = mw - iv - sw;
|
||||
+ sx = mx + mw + iv;
|
||||
+ }
|
||||
+
|
||||
+ getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
|
||||
+
|
||||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ if (i < m->nmaster) {
|
||||
+ resize(c, mx, my, mw - (2*c->bw), mh * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ my += HEIGHT(c) + ih;
|
||||
+ } else {
|
||||
+ resize(c, sx, sy, sw - (2*c->bw), sh * (c->cfact / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
|
||||
+ sy += HEIGHT(c) + ih;
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,95 @@
|
||||
From 48d8560319e18a0325007a1f765f0589fb2dbfc8 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:26:41 +0100
|
||||
Subject: [PATCH] cyclelayout, function to cycle through available layouts.
|
||||
|
||||
MOD-CTRL-, and MOD-CTRL-.
|
||||
cycle backwards and forwards through available layouts.
|
||||
Probably only useful if you have a lot of additional layouts.
|
||||
The NULL, NULL layout should always be the last layout in your list,
|
||||
in order to guarantee consistent behavior.
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/cyclelayouts/
|
||||
---
|
||||
config.def.h | 3 +++
|
||||
dwm.1 | 6 ++++++
|
||||
dwm.c | 18 ++++++++++++++++++
|
||||
3 files changed, 27 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..938fd60 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -42,6 +42,7 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile }, /* first entry is default */
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
+ { NULL, NULL },
|
||||
};
|
||||
|
||||
/* key definitions */
|
||||
@@ -85,6 +86,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } },
|
||||
+ { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
diff --git a/dwm.1 b/dwm.1
|
||||
index ddc8321..829047b 100644
|
||||
--- a/dwm.1
|
||||
+++ b/dwm.1
|
||||
@@ -92,6 +92,12 @@ Sets monocle layout.
|
||||
.B Mod1\-space
|
||||
Toggles between current and previous layout.
|
||||
.TP
|
||||
+.B Mod1\-Control\-,
|
||||
+Cycles backwards in layout list.
|
||||
+.TP
|
||||
+.B Mod1\-Control\-.
|
||||
+Cycles forwards in layout list.
|
||||
+.TP
|
||||
.B Mod1\-j
|
||||
Focus next window.
|
||||
.TP
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..2d98c2b 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -157,6 +157,7 @@ static void configure(Client *c);
|
||||
static void configurenotify(XEvent *e);
|
||||
static void configurerequest(XEvent *e);
|
||||
static Monitor *createmon(void);
|
||||
+static void cyclelayout(const Arg *arg);
|
||||
static void destroynotify(XEvent *e);
|
||||
static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
@@ -645,6 +646,23 @@ createmon(void)
|
||||
return m;
|
||||
}
|
||||
|
||||
+void
|
||||
+cyclelayout(const Arg *arg) {
|
||||
+ Layout *l;
|
||||
+ for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++);
|
||||
+ if(arg->i > 0) {
|
||||
+ if(l->symbol && (l + 1)->symbol)
|
||||
+ setlayout(&((Arg) { .v = (l + 1) }));
|
||||
+ else
|
||||
+ setlayout(&((Arg) { .v = layouts }));
|
||||
+ } else {
|
||||
+ if(l != layouts && (l - 1)->symbol)
|
||||
+ setlayout(&((Arg) { .v = (l - 1) }));
|
||||
+ else
|
||||
+ setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] }));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
destroynotify(XEvent *e)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,53 @@
|
||||
From 4c76c1e41ce0f3d48bac61993e71adbc6239bba1 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:28:06 +0100
|
||||
Subject: [PATCH] Adding desktop patch
|
||||
|
||||
---
|
||||
dwm.c | 15 ++++++++++-----
|
||||
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..5c76f0b 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1743,12 +1743,14 @@ toggletag(const Arg *arg)
|
||||
void
|
||||
toggleview(const Arg *arg)
|
||||
{
|
||||
+ Monitor *m;
|
||||
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
||||
|
||||
if (newtagset) {
|
||||
- selmon->tagset[selmon->seltags] = newtagset;
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ m->tagset[m->seltags] = newtagset;
|
||||
focus(NULL);
|
||||
- arrange(selmon);
|
||||
+ arrange(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2041,13 +2043,16 @@ updatewmhints(Client *c)
|
||||
void
|
||||
view(const Arg *arg)
|
||||
{
|
||||
+ Monitor *m;
|
||||
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
- selmon->seltags ^= 1; /* toggle sel tagset */
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ m->seltags ^= 1; /* toggle sel tagset */
|
||||
if (arg->ui & TAGMASK)
|
||||
- selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ m->tagset[m->seltags] = arg->ui & TAGMASK;
|
||||
focus(NULL);
|
||||
- arrange(selmon);
|
||||
+ arrange(NULL);
|
||||
}
|
||||
|
||||
Client *
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,59 @@
|
||||
From 7014c3f566124fc3612cc2e720efbf8678a046eb Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:29:24 +0100
|
||||
Subject: [PATCH] desktop icons patch
|
||||
|
||||
New windows that has the _NET_WM_WINDOW_TYPE_DESKTOP window type
|
||||
will not be managed by dwm.
|
||||
|
||||
Example programs that this applies to:
|
||||
- pcmanfm --desktop
|
||||
- nautilus -n (legacy)
|
||||
- nemo-desktop
|
||||
- caja --force-desktop --no-default-window
|
||||
|
||||
Note that these applications have a tendency of managing the
|
||||
background wallpaper as well, the exception being nemo-desktop
|
||||
where it appears to just be transparent if a compositor is used.
|
||||
---
|
||||
dwm.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..efe966f 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -62,6 +62,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
+ NetWMWindowTypeDesktop,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
@@ -1027,6 +1028,14 @@ manage(Window w, XWindowAttributes *wa)
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
+
|
||||
+ if (getatomprop(c, netatom[NetWMWindowType]) == netatom[NetWMWindowTypeDesktop]) {
|
||||
+ XMapWindow(dpy, c->win);
|
||||
+ XLowerWindow(dpy, c->win);
|
||||
+ free(c);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
@@ -1565,6 +1574,7 @@ setup(void)
|
||||
netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
||||
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
+ netatom[NetWMWindowTypeDesktop] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
|
||||
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,286 @@
|
||||
From 8643834a556125bb8c68583c46d4cac6a82ebe87 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:29:56 +0100
|
||||
Subject: [PATCH] dragmfact patch with smooth sliding and support for multiple
|
||||
layouts
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwm.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 228 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..f20315f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -108,6 +108,7 @@ static Button buttons[] = {
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
+ { ClkClientWin, MODKEY|ShiftMask, Button1, dragmfact, {0} },
|
||||
{ ClkTagBar, 0, Button1, view, {0} },
|
||||
{ ClkTagBar, 0, Button3, toggleview, {0} },
|
||||
{ ClkTagBar, MODKEY, Button1, tag, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..02283e7 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -58,7 +58,7 @@
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
|
||||
/* enums */
|
||||
-enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
+enum { CurNormal, CurResize, CurMove, CurResizeHorzArrow, CurResizeVertArrow, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
@@ -161,6 +161,7 @@ static void destroynotify(XEvent *e);
|
||||
static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
+static void dragmfact(const Arg *arg);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
@@ -693,6 +694,229 @@ dirtomon(int dir)
|
||||
return m;
|
||||
}
|
||||
|
||||
+void
|
||||
+dragmfact(const Arg *arg)
|
||||
+{
|
||||
+ unsigned int n;
|
||||
+ int py, px; // pointer coordinates
|
||||
+ int ax, ay, aw, ah; // area position, width and height
|
||||
+ int center = 0, horizontal = 0, mirror = 0, fixed = 0; // layout configuration
|
||||
+ double fact;
|
||||
+ Monitor *m;
|
||||
+ XEvent ev;
|
||||
+ Time lasttime = 0;
|
||||
+
|
||||
+ m = selmon;
|
||||
+
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ int oh, ov, ih, iv;
|
||||
+ getgaps(m, &oh, &ov, &ih, &iv, &n);
|
||||
+ #else
|
||||
+ Client *c;
|
||||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+
|
||||
+ ax = m->wx;
|
||||
+ ay = m->wy;
|
||||
+ ah = m->wh;
|
||||
+ aw = m->ww;
|
||||
+
|
||||
+ if (!n)
|
||||
+ return;
|
||||
+ #if FLEXTILE_DELUXE_LAYOUT
|
||||
+ else if (m->lt[m->sellt]->arrange == &flextile) {
|
||||
+ int layout = m->ltaxis[LAYOUT];
|
||||
+ if (layout < 0) {
|
||||
+ mirror = 1;
|
||||
+ layout *= -1;
|
||||
+ }
|
||||
+ if (layout > FLOATING_MASTER) {
|
||||
+ layout -= FLOATING_MASTER;
|
||||
+ fixed = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (layout == SPLIT_HORIZONTAL || layout == SPLIT_HORIZONTAL_DUAL_STACK)
|
||||
+ horizontal = 1;
|
||||
+ else if (layout == SPLIT_CENTERED_VERTICAL && (fixed || n - m->nmaster > 1))
|
||||
+ center = 1;
|
||||
+ else if (layout == FLOATING_MASTER) {
|
||||
+ center = 1;
|
||||
+ if (aw < ah)
|
||||
+ horizontal = 1;
|
||||
+ }
|
||||
+ else if (layout == SPLIT_CENTERED_HORIZONTAL) {
|
||||
+ if (fixed || n - m->nmaster > 1)
|
||||
+ center = 1;
|
||||
+ horizontal = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ #endif // FLEXTILE_DELUXE_LAYOUT
|
||||
+ #if CENTEREDMASTER_LAYOUT
|
||||
+ else if (m->lt[m->sellt]->arrange == ¢eredmaster && (fixed || n - m->nmaster > 1))
|
||||
+ center = 1;
|
||||
+ #endif // CENTEREDMASTER_LAYOUT
|
||||
+ #if CENTEREDFLOATINGMASTER_LAYOUT
|
||||
+ else if (m->lt[m->sellt]->arrange == ¢eredfloatingmaster)
|
||||
+ center = 1;
|
||||
+ #endif // CENTEREDFLOATINGMASTER_LAYOUT
|
||||
+ #if BSTACK_LAYOUT
|
||||
+ else if (m->lt[m->sellt]->arrange == &bstack)
|
||||
+ horizontal = 1;
|
||||
+ #endif // BSTACK_LAYOUT
|
||||
+ #if BSTACKHORIZ_LAYOUT
|
||||
+ else if (m->lt[m->sellt]->arrange == &bstackhoriz)
|
||||
+ horizontal = 1;
|
||||
+ #endif // BSTACKHORIZ_LAYOUT
|
||||
+
|
||||
+ /* do not allow mfact to be modified under certain conditions */
|
||||
+ if (!m->lt[m->sellt]->arrange // floating layout
|
||||
+ || (!fixed && m->nmaster && n <= m->nmaster) // no master
|
||||
+ #if MONOCLE_LAYOUT
|
||||
+ || m->lt[m->sellt]->arrange == &monocle
|
||||
+ #endif // MONOCLE_LAYOUT
|
||||
+ #if GRIDMODE_LAYOUT
|
||||
+ || m->lt[m->sellt]->arrange == &grid
|
||||
+ #endif // GRIDMODE_LAYOUT
|
||||
+ #if HORIZGRID_LAYOUT
|
||||
+ || m->lt[m->sellt]->arrange == &horizgrid
|
||||
+ #endif // HORIZGRID_LAYOUT
|
||||
+ #if GAPPLESSGRID_LAYOUT
|
||||
+ || m->lt[m->sellt]->arrange == &gaplessgrid
|
||||
+ #endif // GAPPLESSGRID_LAYOUT
|
||||
+ #if NROWGRID_LAYOUT
|
||||
+ || m->lt[m->sellt]->arrange == &nrowgrid
|
||||
+ #endif // NROWGRID_LAYOUT
|
||||
+ #if FLEXTILE_DELUXE_LAYOUT
|
||||
+ || (m->lt[m->sellt]->arrange == &flextile && m->ltaxis[LAYOUT] == NO_SPLIT)
|
||||
+ #endif // FLEXTILE_DELUXE_LAYOUT
|
||||
+ )
|
||||
+ return;
|
||||
+
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ ay += oh;
|
||||
+ ax += ov;
|
||||
+ aw -= 2*ov;
|
||||
+ ah -= 2*oh;
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+
|
||||
+ if (center) {
|
||||
+ if (horizontal) {
|
||||
+ px = ax + aw / 2;
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ py = ay + ah / 2 + (ah - 2*ih) * (m->mfact / 2.0) + ih / 2;
|
||||
+ #else
|
||||
+ py = ay + ah / 2 + ah * m->mfact / 2.0;
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+ } else { // vertical split
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ px = ax + aw / 2 + (aw - 2*iv) * m->mfact / 2.0 + iv / 2;
|
||||
+ #else
|
||||
+ px = ax + aw / 2 + aw * m->mfact / 2.0;
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+ py = ay + ah / 2;
|
||||
+ }
|
||||
+ } else if (horizontal) {
|
||||
+ px = ax + aw / 2;
|
||||
+ if (mirror)
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ py = ay + (ah - ih) * (1.0 - m->mfact) + ih / 2;
|
||||
+ #else
|
||||
+ py = ay + (ah * (1.0 - m->mfact));
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+ else
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ py = ay + ((ah - ih) * m->mfact) + ih / 2;
|
||||
+ #else
|
||||
+ py = ay + (ah * m->mfact);
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+ } else { // vertical split
|
||||
+ if (mirror)
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ px = ax + (aw - iv) * (1.0 - m->mfact) + iv / 2;
|
||||
+ #else
|
||||
+ px = ax + (aw * m->mfact);
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+ else
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ px = ax + ((aw - iv) * m->mfact) + iv / 2;
|
||||
+ #else
|
||||
+ px = ax + (aw * m->mfact);
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+ py = ay + ah / 2;
|
||||
+ }
|
||||
+
|
||||
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
+ None, cursor[horizontal ? CurResizeVertArrow : CurResizeHorzArrow]->cursor, CurrentTime) != GrabSuccess)
|
||||
+ return;
|
||||
+ XWarpPointer(dpy, None, root, 0, 0, 0, 0, px, py);
|
||||
+
|
||||
+ do {
|
||||
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
+ switch(ev.type) {
|
||||
+ case ConfigureRequest:
|
||||
+ case Expose:
|
||||
+ case MapRequest:
|
||||
+ handler[ev.type](&ev);
|
||||
+ break;
|
||||
+ case MotionNotify:
|
||||
+ if ((ev.xmotion.time - lasttime) <= (1000 / 40))
|
||||
+ continue;
|
||||
+ if (lasttime != 0) {
|
||||
+ px = ev.xmotion.x;
|
||||
+ py = ev.xmotion.y;
|
||||
+ }
|
||||
+ lasttime = ev.xmotion.time;
|
||||
+
|
||||
+ #if VANITYGAPS_PATCH
|
||||
+ if (center)
|
||||
+ if (horizontal)
|
||||
+ if (py - ay > ah / 2)
|
||||
+ fact = (double) 1.0 - (ay + ah - py - ih / 2) * 2 / (double) (ah - 2*ih);
|
||||
+ else
|
||||
+ fact = (double) 1.0 - (py - ay - ih / 2) * 2 / (double) (ah - 2*ih);
|
||||
+ else
|
||||
+ if (px - ax > aw / 2)
|
||||
+ fact = (double) 1.0 - (ax + aw - px - iv / 2) * 2 / (double) (aw - 2*iv);
|
||||
+ else
|
||||
+ fact = (double) 1.0 - (px - ax - iv / 2) * 2 / (double) (aw - 2*iv);
|
||||
+ else
|
||||
+ if (horizontal)
|
||||
+ fact = (double) (py - ay - ih / 2) / (double) (ah - ih);
|
||||
+ else
|
||||
+ fact = (double) (px - ax - iv / 2) / (double) (aw - iv);
|
||||
+ #else
|
||||
+ if (center)
|
||||
+ if (horizontal)
|
||||
+ if (py - ay > ah / 2)
|
||||
+ fact = (double) 1.0 - (ay + ah - py) * 2 / (double) ah;
|
||||
+ else
|
||||
+ fact = (double) 1.0 - (py - ay) * 2 / (double) ah;
|
||||
+ else
|
||||
+ if (px - ax > aw / 2)
|
||||
+ fact = (double) 1.0 - (ax + aw - px) * 2 / (double) aw;
|
||||
+ else
|
||||
+ fact = (double) 1.0 - (px - ax) * 2 / (double) aw;
|
||||
+ else
|
||||
+ if (horizontal)
|
||||
+ fact = (double) (py - ay) / (double) ah;
|
||||
+ else
|
||||
+ fact = (double) (px - ax) / (double) aw;
|
||||
+ #endif // VANITYGAPS_PATCH
|
||||
+
|
||||
+ if (!center && mirror)
|
||||
+ fact = 1.0 - fact;
|
||||
+
|
||||
+ setmfact(&((Arg) { .f = 1.0 + fact }));
|
||||
+ px = ev.xmotion.x;
|
||||
+ py = ev.xmotion.y;
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (ev.type != ButtonRelease);
|
||||
+
|
||||
+ XUngrabPointer(dpy, CurrentTime);
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
+}
|
||||
+
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
@@ -1570,6 +1794,8 @@ setup(void)
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
||||
+ cursor[CurResizeHorzArrow] = drw_cur_create(drw, XC_sb_h_double_arrow);
|
||||
+ cursor[CurResizeVertArrow] = drw_cur_create(drw, XC_sb_v_double_arrow);
|
||||
/* init appearance */
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,161 @@
|
||||
From 7d6a517f890828b497fcfe28f8d10d5bced4bc3e Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:31:15 +0100
|
||||
Subject: [PATCH] fakefullscreenclient - enable fake fullscreen on a per client
|
||||
basis
|
||||
|
||||
---
|
||||
config.def.h | 1 +
|
||||
dwm.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 55 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..7e6b2ff 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -78,6 +78,7 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b95f50f 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int fakefullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -211,6 +212,7 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void togglefakefullscreen(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
@@ -566,7 +568,7 @@ configurenotify(XEvent *e)
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
for (c = m->clients; c; c = c->next)
|
||||
- if (c->isfullscreen)
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
}
|
||||
@@ -1147,7 +1149,7 @@ movemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1288,7 +1290,10 @@ resizeclient(Client *c, int x, int y, int w, int h)
|
||||
wc.border_width = c->bw;
|
||||
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
|
||||
configure(c);
|
||||
- XSync(dpy, False);
|
||||
+ if (c->fakefullscreen == 1)
|
||||
+ XSync(dpy, True);
|
||||
+ else
|
||||
+ XSync(dpy, False);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1302,7 +1307,7 @@ resizemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1480,8 +1485,10 @@ setfullscreen(Client *c, int fullscreen)
|
||||
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
c->isfullscreen = 1;
|
||||
- c->oldstate = c->isfloating;
|
||||
c->oldbw = c->bw;
|
||||
+ if (c->fakefullscreen == 1)
|
||||
+ return;
|
||||
+ c->oldstate = c->isfloating;
|
||||
c->bw = 0;
|
||||
c->isfloating = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
@@ -1490,8 +1497,12 @@ setfullscreen(Client *c, int fullscreen)
|
||||
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char*)0, 0);
|
||||
c->isfullscreen = 0;
|
||||
- c->isfloating = c->oldstate;
|
||||
c->bw = c->oldbw;
|
||||
+ if (c->fakefullscreen == 1)
|
||||
+ return;
|
||||
+ if (c->fakefullscreen == 2)
|
||||
+ c->fakefullscreen = 1;
|
||||
+ c->isfloating = c->oldstate;
|
||||
c->x = c->oldx;
|
||||
c->y = c->oldy;
|
||||
c->w = c->oldw;
|
||||
@@ -1711,12 +1722,48 @@ togglebar(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglefakefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen) {
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->isfloating && c->fakefullscreen == 1) {
|
||||
+ c->oldstate = c->isfloating;
|
||||
+ c->oldx = c->x;
|
||||
+ c->oldy = c->y;
|
||||
+ c->oldw = c->w;
|
||||
+ c->oldh = c->h;
|
||||
+ }
|
||||
+ c->fakefullscreen = 0;
|
||||
+ }
|
||||
+ else
|
||||
+ c->isfullscreen = 0;
|
||||
+ } else {
|
||||
+ c->fakefullscreen = 1;
|
||||
+ if (c->isfullscreen) {
|
||||
+ c->isfloating = c->oldstate;
|
||||
+ c->bw = c->oldbw;
|
||||
+ c->x = c->oldx;
|
||||
+ c->y = c->oldy;
|
||||
+ c->w = c->oldw;
|
||||
+ c->h = c->oldh;
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ }
|
||||
+ c->isfullscreen = 0;
|
||||
+ }
|
||||
+ setfullscreen(c, !c->isfullscreen);
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
||||
+ if (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1) /* no support for fullscreen windows */
|
||||
return;
|
||||
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,96 @@
|
||||
From 781cd03b7c3a0cf59701b9d6a928c1b81cd28cdd Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:36:07 +0100
|
||||
Subject: [PATCH] fancybar, shows the titles of all visible windows in the
|
||||
status bar
|
||||
|
||||
Inspired by the decorated tabbed layout of Xmonad this patch provides a status bar that shows
|
||||
the titles of all visible windows (as opposed to showing just the selected one). When the
|
||||
titles don't completely fit, they're cropped. The title of the selected window is inverted.
|
||||
|
||||
Authors:
|
||||
Mate Nagy
|
||||
Jochen Sprickerhof
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/fancybar/
|
||||
---
|
||||
dwm.c | 46 ++++++++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 36 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b8c6449 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -696,10 +696,10 @@ dirtomon(int dir)
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
- int x, w, tw = 0;
|
||||
+ int x, w, tw = 0, tabw, mw, ew = 0;
|
||||
int boxs = drw->fonts->h / 9;
|
||||
int boxw = drw->fonts->h / 6 + 2;
|
||||
- unsigned int i, occ = 0, urg = 0;
|
||||
+ unsigned int i, occ = 0, urg = 0, n = 0;
|
||||
Client *c;
|
||||
|
||||
if (!m->showbar)
|
||||
@@ -713,6 +713,8 @@ drawbar(Monitor *m)
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
+ if (ISVISIBLE(c))
|
||||
+ n++;
|
||||
occ |= c->tags;
|
||||
if (c->isurgent)
|
||||
urg |= c->tags;
|
||||
@@ -733,15 +735,39 @@ drawbar(Monitor *m)
|
||||
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
||||
|
||||
if ((w = m->ww - tw - x) > bh) {
|
||||
- if (m->sel) {
|
||||
- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
- 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 {
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- drw_rect(drw, x, 0, w, bh, 1, 1);
|
||||
+ if (n > 0) {
|
||||
+ tabw = TEXTW(m->sel->name) + lrpad;
|
||||
+ mw = (tabw >= w || n == 1) ? 0 : (w - tabw) / (n - 1);
|
||||
+
|
||||
+ i = 0;
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c) || c == m->sel)
|
||||
+ continue;
|
||||
+ tw = TEXTW(c->name);
|
||||
+ if (tabw < mw)
|
||||
+ ew += (mw - tabw);
|
||||
+ else
|
||||
+ i++;
|
||||
+ }
|
||||
+ if (i > 0)
|
||||
+ mw += ew / i;
|
||||
+
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ tabw = MIN(m->sel == c ? w : mw, TEXTW(c->name));
|
||||
+
|
||||
+ drw_setscheme(drw, scheme[m->sel == c ? SchemeSel : SchemeNorm]);
|
||||
+ if (tabw > 0) /* trap special handling of 0 in drw_text */
|
||||
+ drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0);
|
||||
+ if (c->isfloating)
|
||||
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, c->isfixed, 0);
|
||||
+ x += tabw;
|
||||
+ w -= tabw;
|
||||
+ }
|
||||
}
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ drw_rect(drw, x, 0, w, bh, 1, 1);
|
||||
}
|
||||
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,369 @@
|
||||
From 6639e81666ec1793956fa462282a85d3d046aa45 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:37:31 +0100
|
||||
Subject: [PATCH] floatpos: Control the size and position of floating windows
|
||||
|
||||
This patch offers a comprehensive and monitor size agnostic way
|
||||
of positioning new and existing floating windows.
|
||||
|
||||
Refer to:
|
||||
https://github.com/bakkeby/patches/wiki/floatpos/
|
||||
---
|
||||
config.def.h | 46 +++++++++++-
|
||||
dwm.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 233 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..91004b2 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static int floatposgrid_x = 5; /* float grid columns */
|
||||
+static int floatposgrid_y = 5; /* float grid rows */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -26,9 +28,9 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating floatpos monitor */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, NULL, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, NULL, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -85,6 +87,44 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ /* Client position is limited to monitor window area */
|
||||
+ { Mod4Mask, XK_u, floatpos, {.v = "-26x -26y" } }, // ↖
|
||||
+ { Mod4Mask, XK_i, floatpos, {.v = " 0x -26y" } }, // ↑
|
||||
+ { Mod4Mask, XK_o, floatpos, {.v = " 26x -26y" } }, // ↗
|
||||
+ { Mod4Mask, XK_j, floatpos, {.v = "-26x 0y" } }, // ←
|
||||
+ { Mod4Mask, XK_l, floatpos, {.v = " 26x 0y" } }, // →
|
||||
+ { Mod4Mask, XK_m, floatpos, {.v = "-26x 26y" } }, // ↙
|
||||
+ { Mod4Mask, XK_comma, floatpos, {.v = " 0x 26y" } }, // ↓
|
||||
+ { Mod4Mask, XK_period, floatpos, {.v = " 26x 26y" } }, // ↘
|
||||
+ /* Absolute positioning (allows moving windows between monitors) */
|
||||
+ { Mod4Mask|ControlMask, XK_u, floatpos, {.v = "-26a -26a" } }, // ↖
|
||||
+ { Mod4Mask|ControlMask, XK_i, floatpos, {.v = " 0a -26a" } }, // ↑
|
||||
+ { Mod4Mask|ControlMask, XK_o, floatpos, {.v = " 26a -26a" } }, // ↗
|
||||
+ { Mod4Mask|ControlMask, XK_j, floatpos, {.v = "-26a 0a" } }, // ←
|
||||
+ { Mod4Mask|ControlMask, XK_l, floatpos, {.v = " 26a 0a" } }, // →
|
||||
+ { Mod4Mask|ControlMask, XK_m, floatpos, {.v = "-26a 26a" } }, // ↙
|
||||
+ { Mod4Mask|ControlMask, XK_comma, floatpos, {.v = " 0a 26a" } }, // ↓
|
||||
+ { Mod4Mask|ControlMask, XK_period, floatpos, {.v = " 26a 26a" } }, // ↘
|
||||
+ /* Resize client, client center position is fixed which means that client expands in all directions */
|
||||
+ { Mod4Mask|ShiftMask, XK_u, floatpos, {.v = "-26w -26h" } }, // ↖
|
||||
+ { Mod4Mask|ShiftMask, XK_i, floatpos, {.v = " 0w -26h" } }, // ↑
|
||||
+ { Mod4Mask|ShiftMask, XK_o, floatpos, {.v = " 26w -26h" } }, // ↗
|
||||
+ { Mod4Mask|ShiftMask, XK_j, floatpos, {.v = "-26w 0h" } }, // ←
|
||||
+ { Mod4Mask|ShiftMask, XK_k, floatpos, {.v = "800W 800H" } }, // ·
|
||||
+ { Mod4Mask|ShiftMask, XK_l, floatpos, {.v = " 26w 0h" } }, // →
|
||||
+ { Mod4Mask|ShiftMask, XK_m, floatpos, {.v = "-26w 26h" } }, // ↙
|
||||
+ { Mod4Mask|ShiftMask, XK_comma, floatpos, {.v = " 0w 26h" } }, // ↓
|
||||
+ { Mod4Mask|ShiftMask, XK_period, floatpos, {.v = " 26w 26h" } }, // ↘
|
||||
+ /* Client is positioned in a floating grid, movement is relative to client's current position */
|
||||
+ { Mod4Mask|Mod1Mask, XK_u, floatpos, {.v = "-1p -1p" } }, // ↖
|
||||
+ { Mod4Mask|Mod1Mask, XK_i, floatpos, {.v = " 0p -1p" } }, // ↑
|
||||
+ { Mod4Mask|Mod1Mask, XK_o, floatpos, {.v = " 1p -1p" } }, // ↗
|
||||
+ { Mod4Mask|Mod1Mask, XK_j, floatpos, {.v = "-1p 0p" } }, // ←
|
||||
+ { Mod4Mask|Mod1Mask, XK_k, floatpos, {.v = " 0p 0p" } }, // ·
|
||||
+ { Mod4Mask|Mod1Mask, XK_l, floatpos, {.v = " 1p 0p" } }, // →
|
||||
+ { Mod4Mask|Mod1Mask, XK_m, floatpos, {.v = "-1p 1p" } }, // ↙
|
||||
+ { Mod4Mask|Mod1Mask, XK_comma, floatpos, {.v = " 0p 1p" } }, // ↓
|
||||
+ { Mod4Mask|Mod1Mask, XK_period, floatpos, {.v = " 1p 1p" } }, // ↘
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..bf9ba9a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int ignoresizehints;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -138,6 +139,7 @@ typedef struct {
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ const char *floatpos;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -165,11 +167,13 @@ static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
static void expose(XEvent *e);
|
||||
+static void floatpos(const Arg *arg);
|
||||
static void focus(Client *c);
|
||||
static void focusin(XEvent *e);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static Atom getatomprop(Client *c, Atom prop);
|
||||
+static void getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
@@ -198,6 +202,7 @@ static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
static void sendmon(Client *c, Monitor *m);
|
||||
static void setclientstate(Client *c, long state);
|
||||
+static void setfloatpos(Client *c, const char *floatpos);
|
||||
static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
@@ -303,6 +308,8 @@ applyrules(Client *c)
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
+ if (c->isfloating && r->floatpos)
|
||||
+ setfloatpos(c, r->floatpos);
|
||||
}
|
||||
}
|
||||
if (ch.res_class)
|
||||
@@ -344,7 +351,7 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
|
||||
*h = bh;
|
||||
if (*w < bh)
|
||||
*w = bh;
|
||||
- if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
|
||||
+ if (!c->ignoresizehints && (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange)) {
|
||||
/* see last two sentences in ICCCM 4.1.2.3 */
|
||||
baseismin = c->basew == c->minw && c->baseh == c->minh;
|
||||
if (!baseismin) { /* temporarily remove base dimensions */
|
||||
@@ -784,6 +791,21 @@ expose(XEvent *e)
|
||||
drawbar(m);
|
||||
}
|
||||
|
||||
+void
|
||||
+floatpos(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+
|
||||
+ if (!c || (selmon->lt[selmon->sellt]->arrange && !c->isfloating))
|
||||
+ return;
|
||||
+
|
||||
+ setfloatpos(c, (char *)arg->v);
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||
+}
|
||||
+
|
||||
void
|
||||
focus(Client *c)
|
||||
{
|
||||
@@ -875,6 +897,124 @@ getatomprop(Client *c, Atom prop)
|
||||
return atom;
|
||||
}
|
||||
|
||||
+void
|
||||
+getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s)
|
||||
+{
|
||||
+ int abs_p, abs_s, i, delta, rest;
|
||||
+
|
||||
+ abs_p = pCh == 'A' || pCh == 'a';
|
||||
+ abs_s = sCh == 'A' || sCh == 'a';
|
||||
+
|
||||
+ cs += 2*cbw;
|
||||
+
|
||||
+ switch(pCh) {
|
||||
+ case 'A': // absolute position
|
||||
+ cp = pos;
|
||||
+ break;
|
||||
+ case 'a': // absolute relative position
|
||||
+ cp += pos;
|
||||
+ break;
|
||||
+ case 'y':
|
||||
+ case 'x': // client relative position
|
||||
+ cp = MIN(cp + pos, min_p + max_s);
|
||||
+ break;
|
||||
+ case 'Y':
|
||||
+ case 'X': // client position relative to monitor
|
||||
+ cp = min_p + MIN(pos, max_s);
|
||||
+ break;
|
||||
+ case 'S': // fixed client position (sticky)
|
||||
+ case 'C': // fixed client position (center)
|
||||
+ case 'Z': // fixed client right-hand position (position + size)
|
||||
+ if (pos == -1)
|
||||
+ break;
|
||||
+ pos = MAX(MIN(pos, max_s), 0);
|
||||
+ if (pCh == 'Z')
|
||||
+ cs = abs((cp + cs) - (min_p + pos));
|
||||
+ else if (pCh == 'C')
|
||||
+ cs = abs((cp + cs / 2) - (min_p + pos));
|
||||
+ else
|
||||
+ cs = abs(cp - (min_p + pos));
|
||||
+ cp = min_p + pos;
|
||||
+ sCh = 0; // size determined by position, override defined size
|
||||
+ break;
|
||||
+ case 'G': // grid
|
||||
+ if (pos <= 0)
|
||||
+ pos = defgrid; // default configurable
|
||||
+ if (size == 0 || pos < 2 || (sCh != 'p' && sCh != 'P'))
|
||||
+ break;
|
||||
+ delta = (max_s - cs) / (pos - 1);
|
||||
+ rest = max_s - cs - delta * (pos - 1);
|
||||
+ if (sCh == 'P') {
|
||||
+ if (size < 1 || size > pos)
|
||||
+ break;
|
||||
+ cp = min_p + delta * (size - 1);
|
||||
+ } else {
|
||||
+ for (i = 0; i < pos && cp >= min_p + delta * i + (i > pos - rest ? i + rest - pos + 1 : 0); i++);
|
||||
+ cp = min_p + delta * (MAX(MIN(i + size, pos), 1) - 1) + (i > pos - rest ? i + rest - pos + 1 : 0);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ switch(sCh) {
|
||||
+ case 'A': // absolute size
|
||||
+ cs = size;
|
||||
+ break;
|
||||
+ case 'a': // absolute relative size
|
||||
+ cs = MAX(1, cs + size);
|
||||
+ break;
|
||||
+ case '%': // client size percentage in relation to monitor window area size
|
||||
+ if (size <= 0)
|
||||
+ break;
|
||||
+ size = max_s * MIN(size, 100) / 100;
|
||||
+ /* falls through */
|
||||
+ case 'h':
|
||||
+ case 'w': // size relative to client
|
||||
+ if (sCh == 'w' || sCh == 'h') {
|
||||
+ if (size == 0)
|
||||
+ break;
|
||||
+ size += cs;
|
||||
+ }
|
||||
+ /* falls through */
|
||||
+ case 'H':
|
||||
+ case 'W': // normal size, position takes precedence
|
||||
+ if (pCh == 'S' && cp + size > min_p + max_s)
|
||||
+ size = min_p + max_s - cp;
|
||||
+ else if (size > max_s)
|
||||
+ size = max_s;
|
||||
+
|
||||
+ if (pCh == 'C') { // fixed client center, expand or contract client
|
||||
+ delta = size - cs;
|
||||
+ if (delta < 0 || (cp - delta / 2 + size <= min_p + max_s))
|
||||
+ cp -= delta / 2;
|
||||
+ else if (cp - delta / 2 < min_p)
|
||||
+ cp = min_p;
|
||||
+ else if (delta)
|
||||
+ cp = min_p + max_s;
|
||||
+ } else if (pCh == 'Z')
|
||||
+ cp -= size - cs;
|
||||
+
|
||||
+ cs = size;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (pCh == '%') // client mid-point position in relation to monitor window area size
|
||||
+ cp = min_p + max_s * MAX(MIN(pos, 100), 0) / 100 - (cs) / 2;
|
||||
+ if (pCh == 'm' || pCh == 'M')
|
||||
+ cp = pos - cs / 2;
|
||||
+
|
||||
+ if (!abs_p && cp < min_p)
|
||||
+ cp = min_p;
|
||||
+ if (cp + cs > min_p + max_s && !(abs_p && abs_s)) {
|
||||
+ if (abs_p || cp == min_p)
|
||||
+ cs = min_p + max_s - cp;
|
||||
+ else
|
||||
+ cp = min_p + max_s - cs;
|
||||
+ }
|
||||
+
|
||||
+ *out_p = cp;
|
||||
+ *out_s = MAX(cs - 2*cbw, 1);
|
||||
+}
|
||||
+
|
||||
int
|
||||
getrootptr(int *x, int *y)
|
||||
{
|
||||
@@ -1033,8 +1173,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->w = c->oldw = wa->width;
|
||||
c->h = c->oldh = wa->height;
|
||||
c->oldbw = wa->border_width;
|
||||
+ c->ignoresizehints = 0;
|
||||
|
||||
updatetitle(c);
|
||||
+ c->bw = borderpx;
|
||||
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
||||
c->mon = t->mon;
|
||||
c->tags = t->tags;
|
||||
@@ -1051,7 +1193,6 @@ manage(Window w, XWindowAttributes *wa)
|
||||
/* only fix client y-offset, if the client center might cover the bar */
|
||||
c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
|
||||
&& (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
|
||||
- c->bw = borderpx;
|
||||
|
||||
wc.border_width = c->bw;
|
||||
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
|
||||
@@ -1461,6 +1602,53 @@ sendevent(Client *c, Atom proto)
|
||||
return exists;
|
||||
}
|
||||
|
||||
+void
|
||||
+setfloatpos(Client *c, const char *floatpos)
|
||||
+{
|
||||
+ char xCh, yCh, wCh, hCh;
|
||||
+ int x, y, w, h, wx, ww, wy, wh;
|
||||
+
|
||||
+ if (!c || !floatpos)
|
||||
+ return;
|
||||
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
|
||||
+ return;
|
||||
+ switch(sscanf(floatpos, "%d%c %d%c %d%c %d%c", &x, &xCh, &y, &yCh, &w, &wCh, &h, &hCh)) {
|
||||
+ case 4:
|
||||
+ if (xCh == 'w' || xCh == 'W') {
|
||||
+ w = x; wCh = xCh;
|
||||
+ h = y; hCh = yCh;
|
||||
+ x = -1; xCh = 'C';
|
||||
+ y = -1; yCh = 'C';
|
||||
+ } else if (xCh == 'p' || xCh == 'P') {
|
||||
+ w = x; wCh = xCh;
|
||||
+ h = y; hCh = yCh;
|
||||
+ x = 0; xCh = 'G';
|
||||
+ y = 0; yCh = 'G';
|
||||
+ } else if (xCh == 'm' || xCh == 'M') {
|
||||
+ getrootptr(&x, &y);
|
||||
+ } else {
|
||||
+ w = 0; wCh = 0;
|
||||
+ h = 0; hCh = 0;
|
||||
+ }
|
||||
+ break;
|
||||
+ case 8:
|
||||
+ if (xCh == 'm' || xCh == 'M')
|
||||
+ getrootptr(&x, &y);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ wx = c->mon->wx;
|
||||
+ wy = c->mon->wy;
|
||||
+ ww = c->mon->ww;
|
||||
+ wh = c->mon->wh;
|
||||
+ c->ignoresizehints = 1;
|
||||
+
|
||||
+ getfloatpos(x, xCh, w, wCh, wx, ww, c->x, c->w, c->bw, floatposgrid_x, &c->x, &c->w);
|
||||
+ getfloatpos(y, yCh, h, hCh, wy, wh, c->y, c->h, c->bw, floatposgrid_y, &c->y, &c->h);
|
||||
+}
|
||||
+
|
||||
void
|
||||
setfocus(Client *c)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,114 @@
|
||||
From 45957f20d45e99469e7f296231769966b016d11a Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:38:04 +0100
|
||||
Subject: [PATCH] focusdir: focus on the next client by direction (up, down,
|
||||
left, right)
|
||||
|
||||
---
|
||||
config.def.h | 4 ++++
|
||||
dwm.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 71 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..cd41574 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -67,6 +67,10 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
+ { MODKEY, XK_Left, focusdir, {.i = 0 } }, // left
|
||||
+ { MODKEY, XK_Right, focusdir, {.i = 1 } }, // right
|
||||
+ { MODKEY, XK_Up, focusdir, {.i = 2 } }, // up
|
||||
+ { MODKEY, XK_Down, focusdir, {.i = 3 } }, // down
|
||||
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..c3a868e 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -166,6 +166,7 @@ static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
static void expose(XEvent *e);
|
||||
static void focus(Client *c);
|
||||
+static void focusdir(const Arg *arg);
|
||||
static void focusin(XEvent *e);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
@@ -809,6 +810,72 @@ focus(Client *c)
|
||||
drawbars();
|
||||
}
|
||||
|
||||
+void
|
||||
+focusdir(const Arg *arg)
|
||||
+{
|
||||
+ Client *s = selmon->sel, *f = NULL, *c, *next;
|
||||
+
|
||||
+ if (!s)
|
||||
+ return;
|
||||
+
|
||||
+ unsigned int score = -1;
|
||||
+ unsigned int client_score;
|
||||
+ int dist;
|
||||
+ int dirweight = 20;
|
||||
+ int isfloating = s->isfloating;
|
||||
+
|
||||
+ next = s->next;
|
||||
+ if (!next)
|
||||
+ next = s->mon->clients;
|
||||
+ for (c = next; c != s; c = next) {
|
||||
+
|
||||
+ next = c->next;
|
||||
+ if (!next)
|
||||
+ next = s->mon->clients;
|
||||
+
|
||||
+ if (!ISVISIBLE(c) || c->isfloating != isfloating) // || HIDDEN(c)
|
||||
+ continue;
|
||||
+
|
||||
+ switch (arg->i) {
|
||||
+ case 0: // left
|
||||
+ dist = s->x - c->x - c->w;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
+ abs(s->y - c->y);
|
||||
+ break;
|
||||
+ case 1: // right
|
||||
+ dist = c->x - s->x - s->w;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
+ abs(c->y - s->y);
|
||||
+ break;
|
||||
+ case 2: // up
|
||||
+ dist = s->y - c->y - c->h;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
+ abs(s->x - c->x);
|
||||
+ break;
|
||||
+ default:
|
||||
+ case 3: // down
|
||||
+ dist = c->y - s->y - s->h;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
+ abs(c->x - s->x);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) {
|
||||
+ score = client_score;
|
||||
+ f = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (f && f != s) {
|
||||
+ focus(f);
|
||||
+ restack(f->mon);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* there are some broken focus acquiring clients needing extra handling */
|
||||
void
|
||||
focusin(XEvent *e)
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,301 @@
|
||||
From 96b77618391c9feb45e91291fad274ca9dfeed11 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:43:28 +0100
|
||||
Subject: [PATCH] focusedontop: allow the currently focused client to display
|
||||
on top of floating windows, but not on top of transient windows or dialog
|
||||
boxes
|
||||
|
||||
---
|
||||
config.def.h | 14 +++++++--
|
||||
dwm.c | 83 ++++++++++++++++++++++++++++++++++++++--------------
|
||||
2 files changed, 72 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..c964678 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const int focusedontop = 1; /* 1 means focused client is shown on top of floating windows */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -21,14 +22,21 @@ static const char *colors[][3] = {
|
||||
/* tagging */
|
||||
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
|
||||
+#define WTYPE "_NET_WM_WINDOW_TYPE_"
|
||||
static const Rule rules[] = {
|
||||
/* xprop(1):
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
+ * _NET_WM_WINDOW_TYPE(ATOM) = wintype
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class role instance title wintype, tags mask isfloating alwaysontop monitor */
|
||||
+ { NULL, NULL, NULL, NULL, WTYPE "DIALOG", 0, 1, 1, -1 },
|
||||
+ { NULL, NULL, NULL, NULL, WTYPE "UTILITY", 0, 1, 1, -1 },
|
||||
+ { NULL, NULL, NULL, NULL, WTYPE "TOOLBAR", 0, 1, 1, -1 },
|
||||
+ { NULL, NULL, NULL, NULL, WTYPE "SPLASH", 0, 1, 1, -1 },
|
||||
+ { "Gimp", NULL, NULL, NULL, NULL, 0, 1, 0, -1 },
|
||||
+ { "Firefox", NULL, NULL, NULL, NULL, 1 << 8, 0, 0, -1 },
|
||||
+ { NULL, "pop-up", NULL, NULL, NULL, 0, 1, 1, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..0f7b60e 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -60,10 +60,10 @@
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
-enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
+enum { NetSupported, NetWMName, NetWMState, NetWMStateAbove, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
-enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
+ NetClientList, NetLast }; /* EWMH atoms */
|
||||
+enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMWindowRole, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int alwaysontop;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -134,10 +135,13 @@ struct Monitor {
|
||||
|
||||
typedef struct {
|
||||
const char *class;
|
||||
+ const char *role;
|
||||
const char *instance;
|
||||
const char *title;
|
||||
+ const char *wintype;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ int alwaysontop;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -225,7 +229,6 @@ static void updatenumlockmask(void);
|
||||
static void updatesizehints(Client *c);
|
||||
static void updatestatus(void);
|
||||
static void updatetitle(Client *c);
|
||||
-static void updatewindowtype(Client *c);
|
||||
static void updatewmhints(Client *c);
|
||||
static void view(const Arg *arg);
|
||||
static Client *wintoclient(Window w);
|
||||
@@ -280,6 +283,8 @@ void
|
||||
applyrules(Client *c)
|
||||
{
|
||||
const char *class, *instance;
|
||||
+ char role[64];
|
||||
+ Atom wintype;
|
||||
unsigned int i;
|
||||
const Rule *r;
|
||||
Monitor *m;
|
||||
@@ -291,15 +296,20 @@ applyrules(Client *c)
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
class = ch.res_class ? ch.res_class : broken;
|
||||
instance = ch.res_name ? ch.res_name : broken;
|
||||
+ gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
|
||||
+ wintype = getatomprop(c, netatom[NetWMWindowType]);
|
||||
|
||||
for (i = 0; i < LENGTH(rules); i++) {
|
||||
r = &rules[i];
|
||||
if ((!r->title || strstr(c->name, r->title))
|
||||
&& (!r->class || strstr(class, r->class))
|
||||
- && (!r->instance || strstr(instance, r->instance)))
|
||||
+ && (!r->role || strstr(role, r->role))
|
||||
+ && (!r->instance || strstr(instance, r->instance))
|
||||
+ && (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False)))
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
+ c->alwaysontop = r->alwaysontop;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
@@ -523,6 +533,9 @@ clientmessage(XEvent *e)
|
||||
|| cme->data.l[2] == netatom[NetWMFullscreen])
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
+ else if (cme->data.l[1] == netatom[NetWMStateAbove]
|
||||
+ || cme->data.l[2] == netatom[NetWMStateAbove])
|
||||
+ c->alwaysontop = (cme->data.l[0] || cme->data.l[1]);
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
if (c != selmon->sel && !c->isurgent)
|
||||
seturgent(c, 1);
|
||||
@@ -760,6 +773,7 @@ enternotify(XEvent *e)
|
||||
{
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
+ XEvent xev;
|
||||
XCrossingEvent *ev = &e->xcrossing;
|
||||
|
||||
if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
|
||||
@@ -772,6 +786,7 @@ enternotify(XEvent *e)
|
||||
} else if (!c || c == selmon->sel)
|
||||
return;
|
||||
focus(c);
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &xev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -787,6 +802,8 @@ expose(XEvent *e)
|
||||
void
|
||||
focus(Client *c)
|
||||
{
|
||||
+ Client *f;
|
||||
+ XWindowChanges wc;
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
if (selmon->sel && selmon->sel != c)
|
||||
@@ -801,6 +818,31 @@ focus(Client *c)
|
||||
grabbuttons(c, 1);
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
setfocus(c);
|
||||
+ if (focusedontop && c->mon->lt[c->mon->sellt]->arrange) {
|
||||
+
|
||||
+ /* Move all visible tiled clients that are not marked as on top below the bar window */
|
||||
+ wc.stack_mode = Below;
|
||||
+ wc.sibling = c->mon->barwin;
|
||||
+ for (f = c->mon->stack; f; f = f->snext)
|
||||
+ if (f != c && !f->isfloating && ISVISIBLE(f) && !f->alwaysontop) {
|
||||
+ XConfigureWindow(dpy, f->win, CWSibling|CWStackMode, &wc);
|
||||
+ wc.sibling = f->win;
|
||||
+ }
|
||||
+
|
||||
+ /* Move the currently focused client above the bar window */
|
||||
+ wc.stack_mode = Above;
|
||||
+ wc.sibling = c->mon->barwin;
|
||||
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
|
||||
+
|
||||
+ /* Move all visible floating windows that are not marked as on top below the current window */
|
||||
+ wc.stack_mode = Below;
|
||||
+ wc.sibling = c->win;
|
||||
+ for (f = c->mon->stack; f; f = f->snext)
|
||||
+ if (f != c && f->isfloating && ISVISIBLE(f) && !f->alwaysontop) {
|
||||
+ XConfigureWindow(dpy, f->win, CWSibling|CWStackMode, &wc);
|
||||
+ wc.sibling = f->win;
|
||||
+ }
|
||||
+ }
|
||||
} else {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||
@@ -837,6 +879,7 @@ void
|
||||
focusstack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *i;
|
||||
+ XEvent xev;
|
||||
|
||||
if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
return;
|
||||
@@ -855,8 +898,10 @@ focusstack(const Arg *arg)
|
||||
}
|
||||
if (c) {
|
||||
focus(c);
|
||||
- restack(selmon);
|
||||
+ if (!focusedontop)
|
||||
+ restack(selmon);
|
||||
}
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &xev));
|
||||
}
|
||||
|
||||
Atom
|
||||
@@ -1024,6 +1069,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
Client *c, *t = NULL;
|
||||
Window trans = None;
|
||||
XWindowChanges wc;
|
||||
+ XEvent xev;
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
@@ -1038,6 +1084,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
||||
c->mon = t->mon;
|
||||
c->tags = t->tags;
|
||||
+ c->alwaysontop = 1;
|
||||
} else {
|
||||
c->mon = selmon;
|
||||
applyrules(c);
|
||||
@@ -1057,7 +1104,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
|
||||
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
|
||||
configure(c); /* propagates border_width, if size doesn't change */
|
||||
- updatewindowtype(c);
|
||||
+ if (getatomprop(c, netatom[NetWMState]) == netatom[NetWMStateAbove])
|
||||
+ c->alwaysontop = 1;
|
||||
+ if (getatomprop(c, netatom[NetWMState]) == netatom[NetWMFullscreen])
|
||||
+ setfullscreen(c, 1);
|
||||
updatesizehints(c);
|
||||
updatewmhints(c);
|
||||
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
||||
@@ -1077,7 +1127,9 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
+
|
||||
focus(NULL);
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &xev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1244,8 +1296,6 @@ propertynotify(XEvent *e)
|
||||
if (c == c->mon->sel)
|
||||
drawbar(c->mon);
|
||||
}
|
||||
- if (ev->atom == netatom[NetWMWindowType])
|
||||
- updatewindowtype(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1557,14 +1607,15 @@ setup(void)
|
||||
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
||||
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
|
||||
wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
|
||||
+ wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
|
||||
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
|
||||
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
|
||||
netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
|
||||
netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
|
||||
+ netatom[NetWMStateAbove] = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
|
||||
netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
|
||||
netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
||||
- netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
@@ -2007,18 +2058,6 @@ updatetitle(Client *c)
|
||||
strcpy(c->name, broken);
|
||||
}
|
||||
|
||||
-void
|
||||
-updatewindowtype(Client *c)
|
||||
-{
|
||||
- Atom state = getatomprop(c, netatom[NetWMState]);
|
||||
- Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
|
||||
-
|
||||
- if (state == netatom[NetWMFullscreen])
|
||||
- setfullscreen(c, 1);
|
||||
- if (wtype == netatom[NetWMWindowTypeDialog])
|
||||
- c->isfloating = 1;
|
||||
-}
|
||||
-
|
||||
void
|
||||
updatewmhints(Client *c)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,60 @@
|
||||
From 43b77da0e9125c66ac7585d79d2f0784cc38e86e Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:44:58 +0100
|
||||
Subject: [PATCH] Activate a window in response to _NET_ACTIVE_WINDOW
|
||||
|
||||
By default, dwm response to client requests to _NET_ACTIVE_WINDOW client
|
||||
messages by setting the urgency bit on the named window.
|
||||
|
||||
This patch activates the window instead.
|
||||
|
||||
Both behaviours are legitimate according to
|
||||
https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm140200472702304
|
||||
|
||||
One should decide which of these one should perform based on the message
|
||||
senders' untestable claims that it represents the end-user. Setting the
|
||||
urgency bit is the conservative decision. This patch implements the more
|
||||
trusting alternative.
|
||||
|
||||
It also allows dwm to work with `wmctrl -a` and other external window
|
||||
management utilities
|
||||
|
||||
Refer to:
|
||||
https://dwm.suckless.org/patches/focusonnetactive/
|
||||
---
|
||||
dwm.c | 12 ++++++++++--
|
||||
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..44d55b1 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -515,6 +515,7 @@ clientmessage(XEvent *e)
|
||||
{
|
||||
XClientMessageEvent *cme = &e->xclient;
|
||||
Client *c = wintoclient(cme->window);
|
||||
+ unsigned int i;
|
||||
|
||||
if (!c)
|
||||
return;
|
||||
@@ -524,8 +525,15 @@ clientmessage(XEvent *e)
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
- if (c != selmon->sel && !c->isurgent)
|
||||
- seturgent(c, 1);
|
||||
+ for (i = 0; i < LENGTH(tags) && !((1 << i) & c->tags); i++);
|
||||
+ if (i < LENGTH(tags)) {
|
||||
+ const Arg a = {.ui = 1 << i};
|
||||
+ unfocus(selmon->sel, 0);
|
||||
+ selmon = c->mon;
|
||||
+ view(&a);
|
||||
+ focus(c);
|
||||
+ restack(selmon);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,356 @@
|
||||
From 26143b40a079f2bded51a6e01dba8530bec8e486 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:47:56 +0100
|
||||
Subject: [PATCH] Compilation of fullscreen patches for dwm.
|
||||
|
||||
This aims to provide a comprehensive fullscreen solution with the following features:
|
||||
- toggle fullscreen for any window using a single keybinding rather than having
|
||||
to rely on per-application keybindings
|
||||
- the ability to have windows go fullscreen within the size and position the
|
||||
window is currently in (fake fullscreen)
|
||||
- allow a fullscreen window to be moved to an adjacent monitor while remaining
|
||||
fullscreen
|
||||
- make fullscreen windows lose fullscreen if another (e.g. new) window on the
|
||||
same monitor receives focus, while still allowing dialog boxes to show while
|
||||
in fullscreen
|
||||
- allow seamless transition between the two fullscreen modes
|
||||
|
||||
The default keybindings are:
|
||||
- MOD+f to make a window fullscreen
|
||||
- MOD+Shift+f to make a window fake fullscreen
|
||||
|
||||
This incorporates, and expands on, the following patches:
|
||||
- fakefullscreenclient
|
||||
- togglefullscreen (a.k.a. actualfullscreen)
|
||||
- tagmonfixfs
|
||||
- losefullscreen
|
||||
---
|
||||
config.def.h | 5 +-
|
||||
dwm.c | 174 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
2 files changed, 147 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5f28f2c 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -35,7 +35,6 @@ static const Rule rules[] = {
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -75,10 +74,12 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { MODKEY, XK_e, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { MODKEY, XK_f, togglefullscreen, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..dbea07a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int fakefullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -178,6 +179,7 @@ static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void losefullscreen(Client *next);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
@@ -211,7 +213,9 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void togglefakefullscreen(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -520,9 +524,12 @@ clientmessage(XEvent *e)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
if (cme->data.l[1] == netatom[NetWMFullscreen]
|
||||
- || cme->data.l[2] == netatom[NetWMFullscreen])
|
||||
+ || cme->data.l[2] == netatom[NetWMFullscreen]) {
|
||||
+ if (c->fakefullscreen == 2 && c->isfullscreen)
|
||||
+ c->fakefullscreen = 3;
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
+ }
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
if (c != selmon->sel && !c->isurgent)
|
||||
seturgent(c, 1);
|
||||
@@ -566,7 +573,7 @@ configurenotify(XEvent *e)
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
for (c = m->clients; c; c = c->next)
|
||||
- if (c->isfullscreen)
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
}
|
||||
@@ -789,8 +796,10 @@ focus(Client *c)
|
||||
{
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
- if (selmon->sel && selmon->sel != c)
|
||||
+ if (selmon->sel && selmon->sel != c) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
if (c) {
|
||||
if (c->mon != selmon)
|
||||
selmon = c->mon;
|
||||
@@ -838,7 +847,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *i;
|
||||
|
||||
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
+ if (!selmon->sel || (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
@@ -1018,6 +1027,16 @@ killclient(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+losefullscreen(Client *next)
|
||||
+{
|
||||
+ Client *sel = selmon->sel;
|
||||
+ if (!sel || !next)
|
||||
+ return;
|
||||
+ if (sel->isfullscreen && sel->fakefullscreen != 1 && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
|
||||
+ setfullscreen(sel, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
@@ -1072,8 +1091,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
+ if (c->mon == selmon) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
@@ -1147,7 +1168,7 @@ movemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1302,7 +1323,7 @@ resizemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1476,29 +1497,79 @@ setfocus(Client *c)
|
||||
void
|
||||
setfullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
- if (fullscreen && !c->isfullscreen) {
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ XEvent ev;
|
||||
+ int savestate = 0, restorestate = 0, restorefakefullscreen = 0;
|
||||
+
|
||||
+ if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
|
||||
+ || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
|
||||
+ savestate = 1; // go actual fullscreen
|
||||
+ else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
|
||||
+ || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
|
||||
+ restorestate = 1; // go back into tiled
|
||||
+
|
||||
+ /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
|
||||
+ * that while staying in fullscreen. The exception to this is if we are in said state, but
|
||||
+ * the client itself disables fullscreen (3) then we let the client go out of fullscreen
|
||||
+ * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
|
||||
+ * client and the window manager's perception of the client's fullscreen state). */
|
||||
+ if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
|
||||
+ restorefakefullscreen = 1;
|
||||
c->isfullscreen = 1;
|
||||
- c->oldstate = c->isfloating;
|
||||
+ fullscreen = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (fullscreen != c->isfullscreen) { // only send property change if necessary
|
||||
+ if (fullscreen)
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ else
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)0, 0);
|
||||
+ }
|
||||
+
|
||||
+ c->isfullscreen = fullscreen;
|
||||
+
|
||||
+ /* Some clients, e.g. firefox, will send a client message informing the window manager
|
||||
+ * that it is going into fullscreen after receiving the above signal. This has the side
|
||||
+ * effect of this function (setfullscreen) sometimes being called twice when toggling
|
||||
+ * fullscreen on and off via the window manager as opposed to the application itself.
|
||||
+ * To protect against obscure issues where the client settings are stored or restored
|
||||
+ * when they are not supposed to we add an additional bit-lock on the old state so that
|
||||
+ * settings can only be stored and restored in that precise order. */
|
||||
+ if (savestate && !(c->oldstate & (1 << 1))) {
|
||||
c->oldbw = c->bw;
|
||||
+ c->oldstate = c->isfloating | (1 << 1);
|
||||
c->bw = 0;
|
||||
c->isfloating = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- } else if (!fullscreen && c->isfullscreen){
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)0, 0);
|
||||
- c->isfullscreen = 0;
|
||||
- c->isfloating = c->oldstate;
|
||||
+ } else if (restorestate && (c->oldstate & (1 << 1))) {
|
||||
c->bw = c->oldbw;
|
||||
- c->x = c->oldx;
|
||||
- c->y = c->oldy;
|
||||
- c->w = c->oldw;
|
||||
- c->h = c->oldh;
|
||||
+ c->isfloating = c->oldstate = c->oldstate & 1;
|
||||
+ if (restorefakefullscreen || c->fakefullscreen == 3)
|
||||
+ c->fakefullscreen = 1;
|
||||
+ /* The client may have been moved to another monitor whilst in fullscreen which if tiled
|
||||
+ * we address by doing a full arrange of tiled clients. If the client is floating then the
|
||||
+ * height and width may be larger than the monitor's window area, so we cap that by
|
||||
+ * ensuring max / min values. */
|
||||
+ if (c->isfloating) {
|
||||
+ c->x = MAX(c->mon->wx, c->oldx);
|
||||
+ c->y = MAX(c->mon->wy, c->oldy);
|
||||
+ c->w = MIN(c->mon->ww - c->x - 2*c->bw, c->oldw);
|
||||
+ c->h = MIN(c->mon->wh - c->y - 2*c->bw, c->oldh);
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ restack(c->mon);
|
||||
+ } else
|
||||
+ arrange(c->mon);
|
||||
+ } else
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- arrange(c->mon);
|
||||
- }
|
||||
+
|
||||
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
|
||||
+ * mode, then the focus would sometimes drift to whichever window is under the mouse cursor
|
||||
+ * at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
|
||||
+ */
|
||||
+ if (!c->isfullscreen)
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1669,9 +1740,19 @@ tag(const Arg *arg)
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel || !mons->next)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c || !mons->next)
|
||||
return;
|
||||
- sendmon(selmon->sel, dirtomon(arg->i));
|
||||
+ if (c->isfullscreen) {
|
||||
+ c->isfullscreen = 0;
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
+ c->isfullscreen = 1;
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ } else
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1711,18 +1792,51 @@ togglebar(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglefakefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 0);
|
||||
+ } else if (c->fakefullscreen == 1) {
|
||||
+ setfullscreen(c, 0);
|
||||
+ c->fakefullscreen = 0;
|
||||
+ } else {
|
||||
+ c->fakefullscreen = 1;
|
||||
+ setfullscreen(c, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
return;
|
||||
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
|
||||
return;
|
||||
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
+ c->isfloating = !c->isfloating || c->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
||||
- selmon->sel->w, selmon->sel->h, 0);
|
||||
- arrange(selmon);
|
||||
+ resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 1);
|
||||
+ } else
|
||||
+ setfullscreen(c, !c->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,32 @@
|
||||
From 7c7f76b5981d64c8309c3c9d91a6de881076c137 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:50:15 +0100
|
||||
Subject: [PATCH 2/2] Adding fake fullscreen compatible noborder patch
|
||||
|
||||
---
|
||||
dwm.c | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..4990319 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1307,6 +1307,15 @@ resizeclient(Client *c, int x, int y, int w, int h)
|
||||
c->oldw = c->w; c->w = wc.width = w;
|
||||
c->oldh = c->h; c->h = wc.height = h;
|
||||
wc.border_width = c->bw;
|
||||
+ if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next))
|
||||
+ || &monocle == c->mon->lt[c->mon->sellt]->arrange)
|
||||
+ && (c->fakefullscreen == 1 || !c->isfullscreen)
|
||||
+ && !c->isfloating
|
||||
+ && c->mon->lt[c->mon->sellt]->arrange) {
|
||||
+ c->w = wc.width += c->bw * 2;
|
||||
+ c->h = wc.height += c->bw * 2;
|
||||
+ wc.border_width = 0;
|
||||
+ }
|
||||
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
|
||||
configure(c);
|
||||
XSync(dpy, False);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,389 @@
|
||||
From 26143b40a079f2bded51a6e01dba8530bec8e486 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:47:56 +0100
|
||||
Subject: [PATCH 1/2] Compilation of fullscreen patches for dwm.
|
||||
|
||||
This aims to provide a comprehensive fullscreen solution with the following features:
|
||||
- toggle fullscreen for any window using a single keybinding rather than having
|
||||
to rely on per-application keybindings
|
||||
- the ability to have windows go fullscreen within the size and position the
|
||||
window is currently in (fake fullscreen)
|
||||
- allow a fullscreen window to be moved to an adjacent monitor while remaining
|
||||
fullscreen
|
||||
- make fullscreen windows lose fullscreen if another (e.g. new) window on the
|
||||
same monitor receives focus, while still allowing dialog boxes to show while
|
||||
in fullscreen
|
||||
- allow seamless transition between the two fullscreen modes
|
||||
|
||||
The default keybindings are:
|
||||
- MOD+f to make a window fullscreen
|
||||
- MOD+Shift+f to make a window fake fullscreen
|
||||
|
||||
This incorporates, and expands on, the following patches:
|
||||
- fakefullscreenclient
|
||||
- togglefullscreen (a.k.a. actualfullscreen)
|
||||
- tagmonfixfs
|
||||
- losefullscreen
|
||||
---
|
||||
config.def.h | 5 +-
|
||||
dwm.c | 174 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
2 files changed, 147 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5f28f2c 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -35,7 +35,6 @@ static const Rule rules[] = {
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -75,10 +74,12 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { MODKEY, XK_e, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { MODKEY, XK_f, togglefullscreen, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..dbea07a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int fakefullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -178,6 +179,7 @@ static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void losefullscreen(Client *next);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
@@ -211,7 +213,9 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void togglefakefullscreen(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -520,9 +524,12 @@ clientmessage(XEvent *e)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
if (cme->data.l[1] == netatom[NetWMFullscreen]
|
||||
- || cme->data.l[2] == netatom[NetWMFullscreen])
|
||||
+ || cme->data.l[2] == netatom[NetWMFullscreen]) {
|
||||
+ if (c->fakefullscreen == 2 && c->isfullscreen)
|
||||
+ c->fakefullscreen = 3;
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
+ }
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
if (c != selmon->sel && !c->isurgent)
|
||||
seturgent(c, 1);
|
||||
@@ -566,7 +573,7 @@ configurenotify(XEvent *e)
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
for (c = m->clients; c; c = c->next)
|
||||
- if (c->isfullscreen)
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
}
|
||||
@@ -789,8 +796,10 @@ focus(Client *c)
|
||||
{
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
- if (selmon->sel && selmon->sel != c)
|
||||
+ if (selmon->sel && selmon->sel != c) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
if (c) {
|
||||
if (c->mon != selmon)
|
||||
selmon = c->mon;
|
||||
@@ -838,7 +847,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *i;
|
||||
|
||||
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
+ if (!selmon->sel || (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
@@ -1018,6 +1027,16 @@ killclient(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+losefullscreen(Client *next)
|
||||
+{
|
||||
+ Client *sel = selmon->sel;
|
||||
+ if (!sel || !next)
|
||||
+ return;
|
||||
+ if (sel->isfullscreen && sel->fakefullscreen != 1 && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
|
||||
+ setfullscreen(sel, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
@@ -1072,8 +1091,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
+ if (c->mon == selmon) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
@@ -1147,7 +1168,7 @@ movemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1302,7 +1323,7 @@ resizemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1476,29 +1497,79 @@ setfocus(Client *c)
|
||||
void
|
||||
setfullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
- if (fullscreen && !c->isfullscreen) {
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ XEvent ev;
|
||||
+ int savestate = 0, restorestate = 0, restorefakefullscreen = 0;
|
||||
+
|
||||
+ if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
|
||||
+ || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
|
||||
+ savestate = 1; // go actual fullscreen
|
||||
+ else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
|
||||
+ || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
|
||||
+ restorestate = 1; // go back into tiled
|
||||
+
|
||||
+ /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
|
||||
+ * that while staying in fullscreen. The exception to this is if we are in said state, but
|
||||
+ * the client itself disables fullscreen (3) then we let the client go out of fullscreen
|
||||
+ * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
|
||||
+ * client and the window manager's perception of the client's fullscreen state). */
|
||||
+ if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
|
||||
+ restorefakefullscreen = 1;
|
||||
c->isfullscreen = 1;
|
||||
- c->oldstate = c->isfloating;
|
||||
+ fullscreen = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (fullscreen != c->isfullscreen) { // only send property change if necessary
|
||||
+ if (fullscreen)
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ else
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)0, 0);
|
||||
+ }
|
||||
+
|
||||
+ c->isfullscreen = fullscreen;
|
||||
+
|
||||
+ /* Some clients, e.g. firefox, will send a client message informing the window manager
|
||||
+ * that it is going into fullscreen after receiving the above signal. This has the side
|
||||
+ * effect of this function (setfullscreen) sometimes being called twice when toggling
|
||||
+ * fullscreen on and off via the window manager as opposed to the application itself.
|
||||
+ * To protect against obscure issues where the client settings are stored or restored
|
||||
+ * when they are not supposed to we add an additional bit-lock on the old state so that
|
||||
+ * settings can only be stored and restored in that precise order. */
|
||||
+ if (savestate && !(c->oldstate & (1 << 1))) {
|
||||
c->oldbw = c->bw;
|
||||
+ c->oldstate = c->isfloating | (1 << 1);
|
||||
c->bw = 0;
|
||||
c->isfloating = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- } else if (!fullscreen && c->isfullscreen){
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)0, 0);
|
||||
- c->isfullscreen = 0;
|
||||
- c->isfloating = c->oldstate;
|
||||
+ } else if (restorestate && (c->oldstate & (1 << 1))) {
|
||||
c->bw = c->oldbw;
|
||||
- c->x = c->oldx;
|
||||
- c->y = c->oldy;
|
||||
- c->w = c->oldw;
|
||||
- c->h = c->oldh;
|
||||
+ c->isfloating = c->oldstate = c->oldstate & 1;
|
||||
+ if (restorefakefullscreen || c->fakefullscreen == 3)
|
||||
+ c->fakefullscreen = 1;
|
||||
+ /* The client may have been moved to another monitor whilst in fullscreen which if tiled
|
||||
+ * we address by doing a full arrange of tiled clients. If the client is floating then the
|
||||
+ * height and width may be larger than the monitor's window area, so we cap that by
|
||||
+ * ensuring max / min values. */
|
||||
+ if (c->isfloating) {
|
||||
+ c->x = MAX(c->mon->wx, c->oldx);
|
||||
+ c->y = MAX(c->mon->wy, c->oldy);
|
||||
+ c->w = MIN(c->mon->ww - c->x - 2*c->bw, c->oldw);
|
||||
+ c->h = MIN(c->mon->wh - c->y - 2*c->bw, c->oldh);
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ restack(c->mon);
|
||||
+ } else
|
||||
+ arrange(c->mon);
|
||||
+ } else
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- arrange(c->mon);
|
||||
- }
|
||||
+
|
||||
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
|
||||
+ * mode, then the focus would sometimes drift to whichever window is under the mouse cursor
|
||||
+ * at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
|
||||
+ */
|
||||
+ if (!c->isfullscreen)
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1669,9 +1740,19 @@ tag(const Arg *arg)
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel || !mons->next)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c || !mons->next)
|
||||
return;
|
||||
- sendmon(selmon->sel, dirtomon(arg->i));
|
||||
+ if (c->isfullscreen) {
|
||||
+ c->isfullscreen = 0;
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
+ c->isfullscreen = 1;
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ } else
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1711,18 +1792,51 @@ togglebar(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglefakefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 0);
|
||||
+ } else if (c->fakefullscreen == 1) {
|
||||
+ setfullscreen(c, 0);
|
||||
+ c->fakefullscreen = 0;
|
||||
+ } else {
|
||||
+ c->fakefullscreen = 1;
|
||||
+ setfullscreen(c, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
return;
|
||||
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
|
||||
return;
|
||||
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
+ c->isfloating = !c->isfloating || c->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
||||
- selmon->sel->w, selmon->sel->h, 0);
|
||||
- arrange(selmon);
|
||||
+ resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 1);
|
||||
+ } else
|
||||
+ setfullscreen(c, !c->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 7c7f76b5981d64c8309c3c9d91a6de881076c137 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:50:15 +0100
|
||||
Subject: [PATCH 2/2] Adding fake fullscreen compatible noborder patch
|
||||
|
||||
---
|
||||
dwm.c | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..4990319 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1307,6 +1307,15 @@ resizeclient(Client *c, int x, int y, int w, int h)
|
||||
c->oldw = c->w; c->w = wc.width = w;
|
||||
c->oldh = c->h; c->h = wc.height = h;
|
||||
wc.border_width = c->bw;
|
||||
+ if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next))
|
||||
+ || &monocle == c->mon->lt[c->mon->sellt]->arrange)
|
||||
+ && (c->fakefullscreen == 1 || !c->isfullscreen)
|
||||
+ && !c->isfloating
|
||||
+ && c->mon->lt[c->mon->sellt]->arrange) {
|
||||
+ c->w = wc.width += c->bw * 2;
|
||||
+ c->h = wc.height += c->bw * 2;
|
||||
+ wc.border_width = 0;
|
||||
+ }
|
||||
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
|
||||
configure(c);
|
||||
XSync(dpy, False);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,50 @@
|
||||
From a3575ad7318c5da7f83ce08afc1e84acf63cdc1b Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:50:49 +0100
|
||||
Subject: [PATCH 2/2] Adding fake fullscreen client rule
|
||||
|
||||
---
|
||||
config.def.h | 6 +++---
|
||||
dwm.c | 2 ++
|
||||
2 files changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5f28f2c..dd98367 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -26,9 +26,9 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating isfakefullscreen monitor */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, 0, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..b0251d6 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -139,6 +139,7 @@ typedef struct {
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ int isfakefullscreen;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -304,6 +305,7 @@ applyrules(Client *c)
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
+ c->fakefullscreen = r->isfakefullscreen;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,407 @@
|
||||
From 26143b40a079f2bded51a6e01dba8530bec8e486 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:47:56 +0100
|
||||
Subject: [PATCH 1/2] Compilation of fullscreen patches for dwm.
|
||||
|
||||
This aims to provide a comprehensive fullscreen solution with the following features:
|
||||
- toggle fullscreen for any window using a single keybinding rather than having
|
||||
to rely on per-application keybindings
|
||||
- the ability to have windows go fullscreen within the size and position the
|
||||
window is currently in (fake fullscreen)
|
||||
- allow a fullscreen window to be moved to an adjacent monitor while remaining
|
||||
fullscreen
|
||||
- make fullscreen windows lose fullscreen if another (e.g. new) window on the
|
||||
same monitor receives focus, while still allowing dialog boxes to show while
|
||||
in fullscreen
|
||||
- allow seamless transition between the two fullscreen modes
|
||||
|
||||
The default keybindings are:
|
||||
- MOD+f to make a window fullscreen
|
||||
- MOD+Shift+f to make a window fake fullscreen
|
||||
|
||||
This incorporates, and expands on, the following patches:
|
||||
- fakefullscreenclient
|
||||
- togglefullscreen (a.k.a. actualfullscreen)
|
||||
- tagmonfixfs
|
||||
- losefullscreen
|
||||
---
|
||||
config.def.h | 5 +-
|
||||
dwm.c | 174 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
2 files changed, 147 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5f28f2c 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -35,7 +35,6 @@ static const Rule rules[] = {
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -75,10 +74,12 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { MODKEY, XK_e, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { MODKEY, XK_f, togglefullscreen, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..dbea07a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int fakefullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -178,6 +179,7 @@ static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void losefullscreen(Client *next);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
@@ -211,7 +213,9 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void togglefakefullscreen(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -520,9 +524,12 @@ clientmessage(XEvent *e)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
if (cme->data.l[1] == netatom[NetWMFullscreen]
|
||||
- || cme->data.l[2] == netatom[NetWMFullscreen])
|
||||
+ || cme->data.l[2] == netatom[NetWMFullscreen]) {
|
||||
+ if (c->fakefullscreen == 2 && c->isfullscreen)
|
||||
+ c->fakefullscreen = 3;
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
+ }
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
if (c != selmon->sel && !c->isurgent)
|
||||
seturgent(c, 1);
|
||||
@@ -566,7 +573,7 @@ configurenotify(XEvent *e)
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
for (c = m->clients; c; c = c->next)
|
||||
- if (c->isfullscreen)
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
}
|
||||
@@ -789,8 +796,10 @@ focus(Client *c)
|
||||
{
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
- if (selmon->sel && selmon->sel != c)
|
||||
+ if (selmon->sel && selmon->sel != c) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
if (c) {
|
||||
if (c->mon != selmon)
|
||||
selmon = c->mon;
|
||||
@@ -838,7 +847,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *i;
|
||||
|
||||
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
+ if (!selmon->sel || (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
@@ -1018,6 +1027,16 @@ killclient(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+losefullscreen(Client *next)
|
||||
+{
|
||||
+ Client *sel = selmon->sel;
|
||||
+ if (!sel || !next)
|
||||
+ return;
|
||||
+ if (sel->isfullscreen && sel->fakefullscreen != 1 && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
|
||||
+ setfullscreen(sel, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
@@ -1072,8 +1091,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
+ if (c->mon == selmon) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
@@ -1147,7 +1168,7 @@ movemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1302,7 +1323,7 @@ resizemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1476,29 +1497,79 @@ setfocus(Client *c)
|
||||
void
|
||||
setfullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
- if (fullscreen && !c->isfullscreen) {
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ XEvent ev;
|
||||
+ int savestate = 0, restorestate = 0, restorefakefullscreen = 0;
|
||||
+
|
||||
+ if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
|
||||
+ || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
|
||||
+ savestate = 1; // go actual fullscreen
|
||||
+ else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
|
||||
+ || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
|
||||
+ restorestate = 1; // go back into tiled
|
||||
+
|
||||
+ /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
|
||||
+ * that while staying in fullscreen. The exception to this is if we are in said state, but
|
||||
+ * the client itself disables fullscreen (3) then we let the client go out of fullscreen
|
||||
+ * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
|
||||
+ * client and the window manager's perception of the client's fullscreen state). */
|
||||
+ if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
|
||||
+ restorefakefullscreen = 1;
|
||||
c->isfullscreen = 1;
|
||||
- c->oldstate = c->isfloating;
|
||||
+ fullscreen = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (fullscreen != c->isfullscreen) { // only send property change if necessary
|
||||
+ if (fullscreen)
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ else
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)0, 0);
|
||||
+ }
|
||||
+
|
||||
+ c->isfullscreen = fullscreen;
|
||||
+
|
||||
+ /* Some clients, e.g. firefox, will send a client message informing the window manager
|
||||
+ * that it is going into fullscreen after receiving the above signal. This has the side
|
||||
+ * effect of this function (setfullscreen) sometimes being called twice when toggling
|
||||
+ * fullscreen on and off via the window manager as opposed to the application itself.
|
||||
+ * To protect against obscure issues where the client settings are stored or restored
|
||||
+ * when they are not supposed to we add an additional bit-lock on the old state so that
|
||||
+ * settings can only be stored and restored in that precise order. */
|
||||
+ if (savestate && !(c->oldstate & (1 << 1))) {
|
||||
c->oldbw = c->bw;
|
||||
+ c->oldstate = c->isfloating | (1 << 1);
|
||||
c->bw = 0;
|
||||
c->isfloating = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- } else if (!fullscreen && c->isfullscreen){
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)0, 0);
|
||||
- c->isfullscreen = 0;
|
||||
- c->isfloating = c->oldstate;
|
||||
+ } else if (restorestate && (c->oldstate & (1 << 1))) {
|
||||
c->bw = c->oldbw;
|
||||
- c->x = c->oldx;
|
||||
- c->y = c->oldy;
|
||||
- c->w = c->oldw;
|
||||
- c->h = c->oldh;
|
||||
+ c->isfloating = c->oldstate = c->oldstate & 1;
|
||||
+ if (restorefakefullscreen || c->fakefullscreen == 3)
|
||||
+ c->fakefullscreen = 1;
|
||||
+ /* The client may have been moved to another monitor whilst in fullscreen which if tiled
|
||||
+ * we address by doing a full arrange of tiled clients. If the client is floating then the
|
||||
+ * height and width may be larger than the monitor's window area, so we cap that by
|
||||
+ * ensuring max / min values. */
|
||||
+ if (c->isfloating) {
|
||||
+ c->x = MAX(c->mon->wx, c->oldx);
|
||||
+ c->y = MAX(c->mon->wy, c->oldy);
|
||||
+ c->w = MIN(c->mon->ww - c->x - 2*c->bw, c->oldw);
|
||||
+ c->h = MIN(c->mon->wh - c->y - 2*c->bw, c->oldh);
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ restack(c->mon);
|
||||
+ } else
|
||||
+ arrange(c->mon);
|
||||
+ } else
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- arrange(c->mon);
|
||||
- }
|
||||
+
|
||||
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
|
||||
+ * mode, then the focus would sometimes drift to whichever window is under the mouse cursor
|
||||
+ * at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
|
||||
+ */
|
||||
+ if (!c->isfullscreen)
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1669,9 +1740,19 @@ tag(const Arg *arg)
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel || !mons->next)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c || !mons->next)
|
||||
return;
|
||||
- sendmon(selmon->sel, dirtomon(arg->i));
|
||||
+ if (c->isfullscreen) {
|
||||
+ c->isfullscreen = 0;
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
+ c->isfullscreen = 1;
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ } else
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1711,18 +1792,51 @@ togglebar(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglefakefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 0);
|
||||
+ } else if (c->fakefullscreen == 1) {
|
||||
+ setfullscreen(c, 0);
|
||||
+ c->fakefullscreen = 0;
|
||||
+ } else {
|
||||
+ c->fakefullscreen = 1;
|
||||
+ setfullscreen(c, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
return;
|
||||
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
|
||||
return;
|
||||
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
+ c->isfloating = !c->isfloating || c->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
||||
- selmon->sel->w, selmon->sel->h, 0);
|
||||
- arrange(selmon);
|
||||
+ resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 1);
|
||||
+ } else
|
||||
+ setfullscreen(c, !c->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From a3575ad7318c5da7f83ce08afc1e84acf63cdc1b Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:50:49 +0100
|
||||
Subject: [PATCH 2/2] Adding fake fullscreen client rule
|
||||
|
||||
---
|
||||
config.def.h | 6 +++---
|
||||
dwm.c | 2 ++
|
||||
2 files changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5f28f2c..dd98367 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -26,9 +26,9 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating isfakefullscreen monitor */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, 0, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..b0251d6 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -139,6 +139,7 @@ typedef struct {
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ int isfakefullscreen;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -304,6 +305,7 @@ applyrules(Client *c)
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
+ c->fakefullscreen = r->isfakefullscreen;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,89 @@
|
||||
From de057561771f4e849c67be952c644374271a9603 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:52:05 +0100
|
||||
Subject: [PATCH 2/2] Adding fullscreen-compilation compatible tagallmon patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 47 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5f28f2c..0d5456a 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -86,6 +86,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_comma, tagallmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_period, tagallmon, {.i = -1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..a703cad 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -210,6 +210,7 @@ static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
+static void tagallmon(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
@@ -1737,6 +1738,50 @@ tag(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+tagallmon(const Arg *arg)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ Client *c, *last, *slast, *next;
|
||||
+
|
||||
+ if (!mons->next)
|
||||
+ return;
|
||||
+
|
||||
+ m = dirtomon(arg->i);
|
||||
+ for (last = m->clients; last && last->next; last = last->next);
|
||||
+ for (slast = m->stack; slast && slast->snext; slast = slast->snext);
|
||||
+
|
||||
+ for (c = selmon->clients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ unfocus(c, 1, NULL);
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
+ c->next = NULL;
|
||||
+ c->snext = NULL;
|
||||
+ if (last)
|
||||
+ last = last->next = c;
|
||||
+ else
|
||||
+ m->clients = last = c;
|
||||
+ if (slast)
|
||||
+ slast = slast->snext = c;
|
||||
+ else
|
||||
+ m->stack = slast = c;
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ focus(NULL);
|
||||
+ arrange(NULL);
|
||||
+}
|
||||
+
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,446 @@
|
||||
From 26143b40a079f2bded51a6e01dba8530bec8e486 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:47:56 +0100
|
||||
Subject: [PATCH 1/2] Compilation of fullscreen patches for dwm.
|
||||
|
||||
This aims to provide a comprehensive fullscreen solution with the following features:
|
||||
- toggle fullscreen for any window using a single keybinding rather than having
|
||||
to rely on per-application keybindings
|
||||
- the ability to have windows go fullscreen within the size and position the
|
||||
window is currently in (fake fullscreen)
|
||||
- allow a fullscreen window to be moved to an adjacent monitor while remaining
|
||||
fullscreen
|
||||
- make fullscreen windows lose fullscreen if another (e.g. new) window on the
|
||||
same monitor receives focus, while still allowing dialog boxes to show while
|
||||
in fullscreen
|
||||
- allow seamless transition between the two fullscreen modes
|
||||
|
||||
The default keybindings are:
|
||||
- MOD+f to make a window fullscreen
|
||||
- MOD+Shift+f to make a window fake fullscreen
|
||||
|
||||
This incorporates, and expands on, the following patches:
|
||||
- fakefullscreenclient
|
||||
- togglefullscreen (a.k.a. actualfullscreen)
|
||||
- tagmonfixfs
|
||||
- losefullscreen
|
||||
---
|
||||
config.def.h | 5 +-
|
||||
dwm.c | 174 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
2 files changed, 147 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5f28f2c 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -35,7 +35,6 @@ static const Rule rules[] = {
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -75,10 +74,12 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { MODKEY, XK_e, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { MODKEY, XK_f, togglefullscreen, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..dbea07a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int fakefullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -178,6 +179,7 @@ static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void losefullscreen(Client *next);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
@@ -211,7 +213,9 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void togglefakefullscreen(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -520,9 +524,12 @@ clientmessage(XEvent *e)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
if (cme->data.l[1] == netatom[NetWMFullscreen]
|
||||
- || cme->data.l[2] == netatom[NetWMFullscreen])
|
||||
+ || cme->data.l[2] == netatom[NetWMFullscreen]) {
|
||||
+ if (c->fakefullscreen == 2 && c->isfullscreen)
|
||||
+ c->fakefullscreen = 3;
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
+ }
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
if (c != selmon->sel && !c->isurgent)
|
||||
seturgent(c, 1);
|
||||
@@ -566,7 +573,7 @@ configurenotify(XEvent *e)
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
for (c = m->clients; c; c = c->next)
|
||||
- if (c->isfullscreen)
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
}
|
||||
@@ -789,8 +796,10 @@ focus(Client *c)
|
||||
{
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
- if (selmon->sel && selmon->sel != c)
|
||||
+ if (selmon->sel && selmon->sel != c) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
if (c) {
|
||||
if (c->mon != selmon)
|
||||
selmon = c->mon;
|
||||
@@ -838,7 +847,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *i;
|
||||
|
||||
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
+ if (!selmon->sel || (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
@@ -1018,6 +1027,16 @@ killclient(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+losefullscreen(Client *next)
|
||||
+{
|
||||
+ Client *sel = selmon->sel;
|
||||
+ if (!sel || !next)
|
||||
+ return;
|
||||
+ if (sel->isfullscreen && sel->fakefullscreen != 1 && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
|
||||
+ setfullscreen(sel, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
@@ -1072,8 +1091,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
+ if (c->mon == selmon) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
@@ -1147,7 +1168,7 @@ movemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1302,7 +1323,7 @@ resizemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1476,29 +1497,79 @@ setfocus(Client *c)
|
||||
void
|
||||
setfullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
- if (fullscreen && !c->isfullscreen) {
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ XEvent ev;
|
||||
+ int savestate = 0, restorestate = 0, restorefakefullscreen = 0;
|
||||
+
|
||||
+ if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
|
||||
+ || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
|
||||
+ savestate = 1; // go actual fullscreen
|
||||
+ else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
|
||||
+ || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
|
||||
+ restorestate = 1; // go back into tiled
|
||||
+
|
||||
+ /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
|
||||
+ * that while staying in fullscreen. The exception to this is if we are in said state, but
|
||||
+ * the client itself disables fullscreen (3) then we let the client go out of fullscreen
|
||||
+ * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
|
||||
+ * client and the window manager's perception of the client's fullscreen state). */
|
||||
+ if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
|
||||
+ restorefakefullscreen = 1;
|
||||
c->isfullscreen = 1;
|
||||
- c->oldstate = c->isfloating;
|
||||
+ fullscreen = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (fullscreen != c->isfullscreen) { // only send property change if necessary
|
||||
+ if (fullscreen)
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ else
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)0, 0);
|
||||
+ }
|
||||
+
|
||||
+ c->isfullscreen = fullscreen;
|
||||
+
|
||||
+ /* Some clients, e.g. firefox, will send a client message informing the window manager
|
||||
+ * that it is going into fullscreen after receiving the above signal. This has the side
|
||||
+ * effect of this function (setfullscreen) sometimes being called twice when toggling
|
||||
+ * fullscreen on and off via the window manager as opposed to the application itself.
|
||||
+ * To protect against obscure issues where the client settings are stored or restored
|
||||
+ * when they are not supposed to we add an additional bit-lock on the old state so that
|
||||
+ * settings can only be stored and restored in that precise order. */
|
||||
+ if (savestate && !(c->oldstate & (1 << 1))) {
|
||||
c->oldbw = c->bw;
|
||||
+ c->oldstate = c->isfloating | (1 << 1);
|
||||
c->bw = 0;
|
||||
c->isfloating = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- } else if (!fullscreen && c->isfullscreen){
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)0, 0);
|
||||
- c->isfullscreen = 0;
|
||||
- c->isfloating = c->oldstate;
|
||||
+ } else if (restorestate && (c->oldstate & (1 << 1))) {
|
||||
c->bw = c->oldbw;
|
||||
- c->x = c->oldx;
|
||||
- c->y = c->oldy;
|
||||
- c->w = c->oldw;
|
||||
- c->h = c->oldh;
|
||||
+ c->isfloating = c->oldstate = c->oldstate & 1;
|
||||
+ if (restorefakefullscreen || c->fakefullscreen == 3)
|
||||
+ c->fakefullscreen = 1;
|
||||
+ /* The client may have been moved to another monitor whilst in fullscreen which if tiled
|
||||
+ * we address by doing a full arrange of tiled clients. If the client is floating then the
|
||||
+ * height and width may be larger than the monitor's window area, so we cap that by
|
||||
+ * ensuring max / min values. */
|
||||
+ if (c->isfloating) {
|
||||
+ c->x = MAX(c->mon->wx, c->oldx);
|
||||
+ c->y = MAX(c->mon->wy, c->oldy);
|
||||
+ c->w = MIN(c->mon->ww - c->x - 2*c->bw, c->oldw);
|
||||
+ c->h = MIN(c->mon->wh - c->y - 2*c->bw, c->oldh);
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ restack(c->mon);
|
||||
+ } else
|
||||
+ arrange(c->mon);
|
||||
+ } else
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- arrange(c->mon);
|
||||
- }
|
||||
+
|
||||
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
|
||||
+ * mode, then the focus would sometimes drift to whichever window is under the mouse cursor
|
||||
+ * at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
|
||||
+ */
|
||||
+ if (!c->isfullscreen)
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1669,9 +1740,19 @@ tag(const Arg *arg)
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel || !mons->next)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c || !mons->next)
|
||||
return;
|
||||
- sendmon(selmon->sel, dirtomon(arg->i));
|
||||
+ if (c->isfullscreen) {
|
||||
+ c->isfullscreen = 0;
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
+ c->isfullscreen = 1;
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ } else
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1711,18 +1792,51 @@ togglebar(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglefakefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 0);
|
||||
+ } else if (c->fakefullscreen == 1) {
|
||||
+ setfullscreen(c, 0);
|
||||
+ c->fakefullscreen = 0;
|
||||
+ } else {
|
||||
+ c->fakefullscreen = 1;
|
||||
+ setfullscreen(c, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
return;
|
||||
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
|
||||
return;
|
||||
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
+ c->isfloating = !c->isfloating || c->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
||||
- selmon->sel->w, selmon->sel->h, 0);
|
||||
- arrange(selmon);
|
||||
+ resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 1);
|
||||
+ } else
|
||||
+ setfullscreen(c, !c->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From de057561771f4e849c67be952c644374271a9603 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:52:05 +0100
|
||||
Subject: [PATCH 2/2] Adding fullscreen-compilation compatible tagallmon patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 47 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5f28f2c..0d5456a 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -86,6 +86,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_comma, tagallmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ShiftMask, XK_period, tagallmon, {.i = -1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..a703cad 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -210,6 +210,7 @@ static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
+static void tagallmon(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
@@ -1737,6 +1738,50 @@ tag(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+tagallmon(const Arg *arg)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ Client *c, *last, *slast, *next;
|
||||
+
|
||||
+ if (!mons->next)
|
||||
+ return;
|
||||
+
|
||||
+ m = dirtomon(arg->i);
|
||||
+ for (last = m->clients; last && last->next; last = last->next);
|
||||
+ for (slast = m->stack; slast && slast->snext; slast = slast->snext);
|
||||
+
|
||||
+ for (c = selmon->clients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ unfocus(c, 1, NULL);
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
+ c->next = NULL;
|
||||
+ c->snext = NULL;
|
||||
+ if (last)
|
||||
+ last = last->next = c;
|
||||
+ else
|
||||
+ m->clients = last = c;
|
||||
+ if (slast)
|
||||
+ slast = slast->snext = c;
|
||||
+ else
|
||||
+ m->stack = slast = c;
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ focus(NULL);
|
||||
+ arrange(NULL);
|
||||
+}
|
||||
+
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,110 @@
|
||||
From 3008b8f55b7ebd78b8433f213559068f08145e48 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:52:50 +0100
|
||||
Subject: [PATCH 2/2] Adding fullscreen-compilation compatible tagswapmon patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 68 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5f28f2c..c47cddb 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -86,6 +86,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ControlMask, XK_comma, tagswapmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ControlMask, XK_period, tagswapmon, {.i = -1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..fc9c208 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -211,6 +211,7 @@ static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
+static void tagswapmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefakefullscreen(const Arg *arg);
|
||||
@@ -1755,6 +1756,71 @@ tagmon(const Arg *arg)
|
||||
sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
+void
|
||||
+tagswapmon(const Arg *arg)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ Client *c, *sc = NULL, *mc = NULL, *next;
|
||||
+
|
||||
+ if (!mons->next)
|
||||
+ return;
|
||||
+
|
||||
+ m = dirtomon(arg->i);
|
||||
+
|
||||
+ for (c = selmon->clients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ unfocus(c, 1, NULL);
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = sc;
|
||||
+ sc = c;
|
||||
+ }
|
||||
+
|
||||
+ for (c = m->clients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ unfocus(c, 1, NULL);
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = mc;
|
||||
+ mc = c;
|
||||
+ }
|
||||
+
|
||||
+ for (c = sc; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (c = mc; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ c->mon = selmon;
|
||||
+ c->tags = selmon->tagset[selmon->seltags]; /* assign tags of target monitor */
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ focus(NULL);
|
||||
+ arrange(NULL);
|
||||
+}
|
||||
+
|
||||
void
|
||||
tile(Monitor *m)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,467 @@
|
||||
From 26143b40a079f2bded51a6e01dba8530bec8e486 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:47:56 +0100
|
||||
Subject: [PATCH 1/2] Compilation of fullscreen patches for dwm.
|
||||
|
||||
This aims to provide a comprehensive fullscreen solution with the following features:
|
||||
- toggle fullscreen for any window using a single keybinding rather than having
|
||||
to rely on per-application keybindings
|
||||
- the ability to have windows go fullscreen within the size and position the
|
||||
window is currently in (fake fullscreen)
|
||||
- allow a fullscreen window to be moved to an adjacent monitor while remaining
|
||||
fullscreen
|
||||
- make fullscreen windows lose fullscreen if another (e.g. new) window on the
|
||||
same monitor receives focus, while still allowing dialog boxes to show while
|
||||
in fullscreen
|
||||
- allow seamless transition between the two fullscreen modes
|
||||
|
||||
The default keybindings are:
|
||||
- MOD+f to make a window fullscreen
|
||||
- MOD+Shift+f to make a window fake fullscreen
|
||||
|
||||
This incorporates, and expands on, the following patches:
|
||||
- fakefullscreenclient
|
||||
- togglefullscreen (a.k.a. actualfullscreen)
|
||||
- tagmonfixfs
|
||||
- losefullscreen
|
||||
---
|
||||
config.def.h | 5 +-
|
||||
dwm.c | 174 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
2 files changed, 147 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..5f28f2c 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -35,7 +35,6 @@ static const Rule rules[] = {
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
@@ -75,10 +74,12 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { MODKEY, XK_e, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { MODKEY, XK_f, togglefullscreen, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..dbea07a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int fakefullscreen;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -178,6 +179,7 @@ static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void losefullscreen(Client *next);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
@@ -211,7 +213,9 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void togglefakefullscreen(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -520,9 +524,12 @@ clientmessage(XEvent *e)
|
||||
return;
|
||||
if (cme->message_type == netatom[NetWMState]) {
|
||||
if (cme->data.l[1] == netatom[NetWMFullscreen]
|
||||
- || cme->data.l[2] == netatom[NetWMFullscreen])
|
||||
+ || cme->data.l[2] == netatom[NetWMFullscreen]) {
|
||||
+ if (c->fakefullscreen == 2 && c->isfullscreen)
|
||||
+ c->fakefullscreen = 3;
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
+ }
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
if (c != selmon->sel && !c->isurgent)
|
||||
seturgent(c, 1);
|
||||
@@ -566,7 +573,7 @@ configurenotify(XEvent *e)
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
for (c = m->clients; c; c = c->next)
|
||||
- if (c->isfullscreen)
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
}
|
||||
@@ -789,8 +796,10 @@ focus(Client *c)
|
||||
{
|
||||
if (!c || !ISVISIBLE(c))
|
||||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
- if (selmon->sel && selmon->sel != c)
|
||||
+ if (selmon->sel && selmon->sel != c) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
if (c) {
|
||||
if (c->mon != selmon)
|
||||
selmon = c->mon;
|
||||
@@ -838,7 +847,7 @@ focusstack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *i;
|
||||
|
||||
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
+ if (!selmon->sel || (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
@@ -1018,6 +1027,16 @@ killclient(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+losefullscreen(Client *next)
|
||||
+{
|
||||
+ Client *sel = selmon->sel;
|
||||
+ if (!sel || !next)
|
||||
+ return;
|
||||
+ if (sel->isfullscreen && sel->fakefullscreen != 1 && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
|
||||
+ setfullscreen(sel, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
@@ -1072,8 +1091,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
+ if (c->mon == selmon) {
|
||||
+ losefullscreen(c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
@@ -1147,7 +1168,7 @@ movemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1302,7 +1323,7 @@ resizemouse(const Arg *arg)
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
||||
return;
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
@@ -1476,29 +1497,79 @@ setfocus(Client *c)
|
||||
void
|
||||
setfullscreen(Client *c, int fullscreen)
|
||||
{
|
||||
- if (fullscreen && !c->isfullscreen) {
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ XEvent ev;
|
||||
+ int savestate = 0, restorestate = 0, restorefakefullscreen = 0;
|
||||
+
|
||||
+ if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
|
||||
+ || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
|
||||
+ savestate = 1; // go actual fullscreen
|
||||
+ else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
|
||||
+ || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
|
||||
+ restorestate = 1; // go back into tiled
|
||||
+
|
||||
+ /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
|
||||
+ * that while staying in fullscreen. The exception to this is if we are in said state, but
|
||||
+ * the client itself disables fullscreen (3) then we let the client go out of fullscreen
|
||||
+ * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
|
||||
+ * client and the window manager's perception of the client's fullscreen state). */
|
||||
+ if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
|
||||
+ restorefakefullscreen = 1;
|
||||
c->isfullscreen = 1;
|
||||
- c->oldstate = c->isfloating;
|
||||
+ fullscreen = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (fullscreen != c->isfullscreen) { // only send property change if necessary
|
||||
+ if (fullscreen)
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
||||
+ else
|
||||
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
+ PropModeReplace, (unsigned char*)0, 0);
|
||||
+ }
|
||||
+
|
||||
+ c->isfullscreen = fullscreen;
|
||||
+
|
||||
+ /* Some clients, e.g. firefox, will send a client message informing the window manager
|
||||
+ * that it is going into fullscreen after receiving the above signal. This has the side
|
||||
+ * effect of this function (setfullscreen) sometimes being called twice when toggling
|
||||
+ * fullscreen on and off via the window manager as opposed to the application itself.
|
||||
+ * To protect against obscure issues where the client settings are stored or restored
|
||||
+ * when they are not supposed to we add an additional bit-lock on the old state so that
|
||||
+ * settings can only be stored and restored in that precise order. */
|
||||
+ if (savestate && !(c->oldstate & (1 << 1))) {
|
||||
c->oldbw = c->bw;
|
||||
+ c->oldstate = c->isfloating | (1 << 1);
|
||||
c->bw = 0;
|
||||
c->isfloating = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- } else if (!fullscreen && c->isfullscreen){
|
||||
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
||||
- PropModeReplace, (unsigned char*)0, 0);
|
||||
- c->isfullscreen = 0;
|
||||
- c->isfloating = c->oldstate;
|
||||
+ } else if (restorestate && (c->oldstate & (1 << 1))) {
|
||||
c->bw = c->oldbw;
|
||||
- c->x = c->oldx;
|
||||
- c->y = c->oldy;
|
||||
- c->w = c->oldw;
|
||||
- c->h = c->oldh;
|
||||
+ c->isfloating = c->oldstate = c->oldstate & 1;
|
||||
+ if (restorefakefullscreen || c->fakefullscreen == 3)
|
||||
+ c->fakefullscreen = 1;
|
||||
+ /* The client may have been moved to another monitor whilst in fullscreen which if tiled
|
||||
+ * we address by doing a full arrange of tiled clients. If the client is floating then the
|
||||
+ * height and width may be larger than the monitor's window area, so we cap that by
|
||||
+ * ensuring max / min values. */
|
||||
+ if (c->isfloating) {
|
||||
+ c->x = MAX(c->mon->wx, c->oldx);
|
||||
+ c->y = MAX(c->mon->wy, c->oldy);
|
||||
+ c->w = MIN(c->mon->ww - c->x - 2*c->bw, c->oldw);
|
||||
+ c->h = MIN(c->mon->wh - c->y - 2*c->bw, c->oldh);
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ restack(c->mon);
|
||||
+ } else
|
||||
+ arrange(c->mon);
|
||||
+ } else
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- arrange(c->mon);
|
||||
- }
|
||||
+
|
||||
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
|
||||
+ * mode, then the focus would sometimes drift to whichever window is under the mouse cursor
|
||||
+ * at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
|
||||
+ */
|
||||
+ if (!c->isfullscreen)
|
||||
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1669,9 +1740,19 @@ tag(const Arg *arg)
|
||||
void
|
||||
tagmon(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel || !mons->next)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c || !mons->next)
|
||||
return;
|
||||
- sendmon(selmon->sel, dirtomon(arg->i));
|
||||
+ if (c->isfullscreen) {
|
||||
+ c->isfullscreen = 0;
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
+ c->isfullscreen = 1;
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ } else
|
||||
+ sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1711,18 +1792,51 @@ togglebar(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglefakefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 0);
|
||||
+ } else if (c->fakefullscreen == 1) {
|
||||
+ setfullscreen(c, 0);
|
||||
+ c->fakefullscreen = 0;
|
||||
+ } else {
|
||||
+ c->fakefullscreen = 1;
|
||||
+ setfullscreen(c, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
togglefloating(const Arg *arg)
|
||||
{
|
||||
- if (!selmon->sel)
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
return;
|
||||
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
||||
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
|
||||
return;
|
||||
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
+ c->isfloating = !c->isfloating || c->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
||||
- selmon->sel->w, selmon->sel->h, 0);
|
||||
- arrange(selmon);
|
||||
+ resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
+ arrange(c->mon);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+togglefullscreen(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
|
||||
+ c->fakefullscreen = 2;
|
||||
+ setfullscreen(c, 1);
|
||||
+ } else
|
||||
+ setfullscreen(c, !c->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 3008b8f55b7ebd78b8433f213559068f08145e48 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:52:50 +0100
|
||||
Subject: [PATCH 2/2] Adding fullscreen-compilation compatible tagswapmon patch
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 68 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 5f28f2c..c47cddb 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -86,6 +86,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ControlMask, XK_comma, tagswapmon, {.i = +1 } },
|
||||
+ { MODKEY|Mod4Mask|ControlMask, XK_period, tagswapmon, {.i = -1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index dbea07a..fc9c208 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -211,6 +211,7 @@ static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
+static void tagswapmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefakefullscreen(const Arg *arg);
|
||||
@@ -1755,6 +1756,71 @@ tagmon(const Arg *arg)
|
||||
sendmon(c, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
+void
|
||||
+tagswapmon(const Arg *arg)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ Client *c, *sc = NULL, *mc = NULL, *next;
|
||||
+
|
||||
+ if (!mons->next)
|
||||
+ return;
|
||||
+
|
||||
+ m = dirtomon(arg->i);
|
||||
+
|
||||
+ for (c = selmon->clients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ unfocus(c, 1, NULL);
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = sc;
|
||||
+ sc = c;
|
||||
+ }
|
||||
+
|
||||
+ for (c = m->clients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ if (!ISVISIBLE(c))
|
||||
+ continue;
|
||||
+ unfocus(c, 1, NULL);
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = mc;
|
||||
+ mc = c;
|
||||
+ }
|
||||
+
|
||||
+ for (c = sc; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (c = mc; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ c->mon = selmon;
|
||||
+ c->tags = selmon->tagset[selmon->seltags]; /* assign tags of target monitor */
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ if (c->isfullscreen) {
|
||||
+ if (c->fakefullscreen != 1) {
|
||||
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ focus(NULL);
|
||||
+ arrange(NULL);
|
||||
+}
|
||||
+
|
||||
void
|
||||
tile(Monitor *m)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,146 @@
|
||||
From 4faf7404d72587f940024a63568ae3d4f00e3028 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:53:22 +0100
|
||||
Subject: [PATCH] holdbar: variant of the patch where holdbar is only active
|
||||
when the bar is toggled off
|
||||
|
||||
Additionally this allows the use of the primary MOD key to be used as the holdbar key while
|
||||
still allowing the bar to be toggled on and off using MOD+b. This gives a more intuitive and
|
||||
flexible feel when using this functionality.
|
||||
|
||||
Use xev to find the keysym for the key that you want to use and add/update the HOLDKEY
|
||||
definition in config.h.
|
||||
|
||||
E.g. using Alt_L as the HOLDKEY
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 52 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..94e02cf 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -51,6 +51,7 @@ static const Layout layouts[] = {
|
||||
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||
+#define HOLDKEY 0 // replace 0 with the keysym to activate holdbar
|
||||
|
||||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||
@@ -95,6 +96,7 @@ static Key keys[] = {
|
||||
TAGKEYS( XK_8, 7)
|
||||
TAGKEYS( XK_9, 8)
|
||||
{ MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
+ { 0, HOLDKEY, holdbar, {0} },
|
||||
};
|
||||
|
||||
/* button definitions */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..ec84ee8 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -177,6 +177,7 @@ static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
+static void keyrelease(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
@@ -211,6 +212,7 @@ static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
+static void holdbar(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
@@ -218,6 +220,7 @@ static void unfocus(Client *c, int setfocus);
|
||||
static void unmanage(Client *c, int destroyed);
|
||||
static void unmapnotify(XEvent *e);
|
||||
static void updatebarpos(Monitor *m);
|
||||
+static void updateholdbarpos(Monitor *m);
|
||||
static void updatebars(void);
|
||||
static void updateclientlist(void);
|
||||
static int updategeom(void);
|
||||
@@ -246,6 +249,7 @@ static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[ButtonPress] = buttonpress,
|
||||
+ [ButtonRelease] = keyrelease,
|
||||
[ClientMessage] = clientmessage,
|
||||
[ConfigureRequest] = configurerequest,
|
||||
[ConfigureNotify] = configurenotify,
|
||||
@@ -253,6 +257,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[EnterNotify] = enternotify,
|
||||
[Expose] = expose,
|
||||
[FocusIn] = focusin,
|
||||
+ [KeyRelease] = keyrelease,
|
||||
[KeyPress] = keypress,
|
||||
[MappingNotify] = mappingnotify,
|
||||
[MapRequest] = maprequest,
|
||||
@@ -276,6 +281,50 @@ static Window root, wmcheckwin;
|
||||
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||
|
||||
/* function implementations */
|
||||
+void
|
||||
+holdbar(const Arg *arg)
|
||||
+{
|
||||
+ if (selmon->showbar)
|
||||
+ return;
|
||||
+ selmon->showbar = 2;
|
||||
+ updateholdbarpos(selmon);
|
||||
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+keyrelease(XEvent *e)
|
||||
+{
|
||||
+ if (XEventsQueued(dpy, QueuedAfterReading)) {
|
||||
+ XEvent ne;
|
||||
+ XPeekEvent(dpy, &ne);
|
||||
+
|
||||
+ if (ne.type == KeyPress && ne.xkey.time == e->xkey.time &&
|
||||
+ ne.xkey.keycode == e->xkey.keycode) {
|
||||
+ XNextEvent(dpy, &ne);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ if (e->xkey.keycode == XKeysymToKeycode(dpy, HOLDKEY) && selmon->showbar == 2) {
|
||||
+ selmon->showbar = 0;
|
||||
+ updateholdbarpos(selmon);
|
||||
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
+ arrange(selmon);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+updateholdbarpos(Monitor *m)
|
||||
+{
|
||||
+ m->wy = m->my;
|
||||
+ m->wh = m->mh;
|
||||
+ if (m->showbar) {
|
||||
+ m->by = m->topbar ? m->wy : m->wy + m->wh - bh;
|
||||
+ m->wy = m->topbar ? m->wy - bh + bh : m->wy;
|
||||
+ } else {
|
||||
+ m->by = -bh;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
applyrules(Client *c)
|
||||
{
|
||||
@@ -1705,7 +1754,7 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
- selmon->showbar = !selmon->showbar;
|
||||
+ selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar);
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
arrange(selmon);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,124 @@
|
||||
From 9a855a7a11ec8982bae1b8d5e052c4ff8b572733 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:54:40 +0100
|
||||
Subject: [PATCH] keypressrelease patch
|
||||
|
||||
---
|
||||
config.def.h | 58 ++++++++++++++++++++++++++--------------------------
|
||||
dwm.c | 3 +++
|
||||
2 files changed, 32 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..fbced7e 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -47,10 +47,10 @@ static const Layout layouts[] = {
|
||||
/* key definitions */
|
||||
#define MODKEY Mod1Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
- { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
- { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||
- { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||
+ { KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
+ { KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
+ { KeyPress, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||
+ { KeyPress, MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||
|
||||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||
@@ -61,30 +61,30 @@ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont,
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
static Key keys[] = {
|
||||
- /* modifier key function argument */
|
||||
- { 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_i, incnmaster, {.i = +1 } },
|
||||
- { MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
- { MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
- { MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
- { MODKEY, XK_Return, zoom, {0} },
|
||||
- { MODKEY, XK_Tab, view, {0} },
|
||||
- { MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
- { MODKEY, XK_space, setlayout, {0} },
|
||||
- { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
- { MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
- { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
- { MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
- { MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
- { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
- { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ /* type modifier key function argument */
|
||||
+ { KeyPress, MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { KeyPress, MODKEY, XK_b, togglebar, {0} },
|
||||
+ { KeyPress, MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
+ { KeyPress, MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
+ { KeyPress, MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
+ { KeyPress, MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
+ { KeyPress, MODKEY, XK_Return, zoom, {0} },
|
||||
+ { KeyPress, MODKEY, XK_Tab, view, {0} },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
+ { KeyPress, MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
+ { KeyPress, MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { KeyPress, MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { KeyPress, MODKEY, XK_space, setlayout, {0} },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { KeyPress, MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
+ { KeyPress, MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
@@ -94,7 +94,7 @@ static Key keys[] = {
|
||||
TAGKEYS( XK_7, 6)
|
||||
TAGKEYS( XK_8, 7)
|
||||
TAGKEYS( XK_9, 8)
|
||||
- { MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
};
|
||||
|
||||
/* button definitions */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..5cf093a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -100,6 +100,7 @@ struct Client {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
+ int type;
|
||||
unsigned int mod;
|
||||
KeySym keysym;
|
||||
void (*func)(const Arg *);
|
||||
@@ -254,6 +255,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[Expose] = expose,
|
||||
[FocusIn] = focusin,
|
||||
[KeyPress] = keypress,
|
||||
+ [KeyRelease] = keypress,
|
||||
[MappingNotify] = mappingnotify,
|
||||
[MapRequest] = maprequest,
|
||||
[MotionNotify] = motionnotify,
|
||||
@@ -997,6 +999,7 @@ keypress(XEvent *e)
|
||||
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
|
||||
for (i = 0; i < LENGTH(keys); i++)
|
||||
if (keysym == keys[i].keysym
|
||||
+ && ev->type == keys[i].type
|
||||
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
|
||||
&& keys[i].func)
|
||||
keys[i].func(&(keys[i].arg));
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,113 @@
|
||||
From 0fd8c7aceab8886bf904f4a567e163040356c6aa Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:55:09 +0100
|
||||
Subject: [PATCH 2/2] Holdbar patch on top of keypressrelease
|
||||
|
||||
---
|
||||
config.def.h | 5 +++--
|
||||
dwm.c | 24 ++++++++++++++++++++++--
|
||||
2 files changed, 25 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index fbced7e..267f8e9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -3,7 +3,6 @@
|
||||
/* appearance */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
-static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
@@ -45,7 +44,7 @@ static const Layout layouts[] = {
|
||||
};
|
||||
|
||||
/* key definitions */
|
||||
-#define MODKEY Mod1Mask
|
||||
+#define MODKEY Mod4Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
{ KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
{ KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
@@ -62,6 +61,8 @@ static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
static Key keys[] = {
|
||||
/* type modifier key function argument */
|
||||
+ { KeyPress, 0, XK_Super_L,showbar, {0} },
|
||||
+ { KeyRelease, MODKEY, XK_Super_L,hidebar, {0} },
|
||||
{ KeyPress, MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ KeyPress, MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
{ KeyPress, MODKEY, XK_b, togglebar, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 5cf093a..f7c2050 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -176,6 +176,7 @@ static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
+static void hidebar(const Arg *arg);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
@@ -207,6 +208,7 @@ static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
+static void showbar(const Arg *arg);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
@@ -639,7 +641,7 @@ createmon(void)
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
m->mfact = mfact;
|
||||
m->nmaster = nmaster;
|
||||
- m->showbar = showbar;
|
||||
+ m->showbar = 0;
|
||||
m->topbar = topbar;
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
@@ -969,6 +971,15 @@ grabkeys(void)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+hidebar(const Arg *arg)
|
||||
+{
|
||||
+ if (selmon->showbar == 2) {
|
||||
+ selmon->showbar = 1;
|
||||
+ togglebar(arg);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
@@ -1643,6 +1654,15 @@ sigchld(int unused)
|
||||
while (0 < waitpid(-1, NULL, WNOHANG));
|
||||
}
|
||||
|
||||
+void
|
||||
+showbar(const Arg *arg)
|
||||
+{
|
||||
+ if (!selmon->showbar) {
|
||||
+ togglebar(arg);
|
||||
+ selmon->showbar = 2;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
@@ -1708,7 +1728,7 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
- selmon->showbar = !selmon->showbar;
|
||||
+ selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar);
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
arrange(selmon);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,238 @@
|
||||
From 9a855a7a11ec8982bae1b8d5e052c4ff8b572733 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:54:40 +0100
|
||||
Subject: [PATCH 1/2] keypressrelease patch
|
||||
|
||||
---
|
||||
config.def.h | 58 ++++++++++++++++++++++++++--------------------------
|
||||
dwm.c | 3 +++
|
||||
2 files changed, 32 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..fbced7e 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -47,10 +47,10 @@ static const Layout layouts[] = {
|
||||
/* key definitions */
|
||||
#define MODKEY Mod1Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
- { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
- { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||
- { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||
+ { KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
+ { KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
+ { KeyPress, MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||
+ { KeyPress, MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||
|
||||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||
@@ -61,30 +61,30 @@ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont,
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
static Key keys[] = {
|
||||
- /* modifier key function argument */
|
||||
- { 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_i, incnmaster, {.i = +1 } },
|
||||
- { MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
- { MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
- { MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
- { MODKEY, XK_Return, zoom, {0} },
|
||||
- { MODKEY, XK_Tab, view, {0} },
|
||||
- { MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
- { MODKEY, XK_space, setlayout, {0} },
|
||||
- { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
- { MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
- { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
- { MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
- { MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
- { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
- { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
+ /* type modifier key function argument */
|
||||
+ { KeyPress, MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { KeyPress, MODKEY, XK_b, togglebar, {0} },
|
||||
+ { KeyPress, MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
+ { KeyPress, MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
+ { KeyPress, MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
+ { KeyPress, MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
+ { KeyPress, MODKEY, XK_Return, zoom, {0} },
|
||||
+ { KeyPress, MODKEY, XK_Tab, view, {0} },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
+ { KeyPress, MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
+ { KeyPress, MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
+ { KeyPress, MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
+ { KeyPress, MODKEY, XK_space, setlayout, {0} },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { KeyPress, MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
+ { KeyPress, MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
@@ -94,7 +94,7 @@ static Key keys[] = {
|
||||
TAGKEYS( XK_7, 6)
|
||||
TAGKEYS( XK_8, 7)
|
||||
TAGKEYS( XK_9, 8)
|
||||
- { MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
+ { KeyPress, MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
};
|
||||
|
||||
/* button definitions */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..5cf093a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -100,6 +100,7 @@ struct Client {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
+ int type;
|
||||
unsigned int mod;
|
||||
KeySym keysym;
|
||||
void (*func)(const Arg *);
|
||||
@@ -254,6 +255,7 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[Expose] = expose,
|
||||
[FocusIn] = focusin,
|
||||
[KeyPress] = keypress,
|
||||
+ [KeyRelease] = keypress,
|
||||
[MappingNotify] = mappingnotify,
|
||||
[MapRequest] = maprequest,
|
||||
[MotionNotify] = motionnotify,
|
||||
@@ -997,6 +999,7 @@ keypress(XEvent *e)
|
||||
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
|
||||
for (i = 0; i < LENGTH(keys); i++)
|
||||
if (keysym == keys[i].keysym
|
||||
+ && ev->type == keys[i].type
|
||||
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
|
||||
&& keys[i].func)
|
||||
keys[i].func(&(keys[i].arg));
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 0fd8c7aceab8886bf904f4a567e163040356c6aa Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 11:55:09 +0100
|
||||
Subject: [PATCH 2/2] Holdbar patch on top of keypressrelease
|
||||
|
||||
---
|
||||
config.def.h | 5 +++--
|
||||
dwm.c | 24 ++++++++++++++++++++++--
|
||||
2 files changed, 25 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index fbced7e..267f8e9 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -3,7 +3,6 @@
|
||||
/* appearance */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
-static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
@@ -45,7 +44,7 @@ static const Layout layouts[] = {
|
||||
};
|
||||
|
||||
/* key definitions */
|
||||
-#define MODKEY Mod1Mask
|
||||
+#define MODKEY Mod4Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
{ KeyPress, MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
{ KeyPress, MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
@@ -62,6 +61,8 @@ static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
static Key keys[] = {
|
||||
/* type modifier key function argument */
|
||||
+ { KeyPress, 0, XK_Super_L,showbar, {0} },
|
||||
+ { KeyRelease, MODKEY, XK_Super_L,hidebar, {0} },
|
||||
{ KeyPress, MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ KeyPress, MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
{ KeyPress, MODKEY, XK_b, togglebar, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 5cf093a..f7c2050 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -176,6 +176,7 @@ static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
+static void hidebar(const Arg *arg);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
@@ -207,6 +208,7 @@ static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
+static void showbar(const Arg *arg);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
@@ -639,7 +641,7 @@ createmon(void)
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
m->mfact = mfact;
|
||||
m->nmaster = nmaster;
|
||||
- m->showbar = showbar;
|
||||
+ m->showbar = 0;
|
||||
m->topbar = topbar;
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
@@ -969,6 +971,15 @@ grabkeys(void)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+hidebar(const Arg *arg)
|
||||
+{
|
||||
+ if (selmon->showbar == 2) {
|
||||
+ selmon->showbar = 1;
|
||||
+ togglebar(arg);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
@@ -1643,6 +1654,15 @@ sigchld(int unused)
|
||||
while (0 < waitpid(-1, NULL, WNOHANG));
|
||||
}
|
||||
|
||||
+void
|
||||
+showbar(const Arg *arg)
|
||||
+{
|
||||
+ if (!selmon->showbar) {
|
||||
+ togglebar(arg);
|
||||
+ selmon->showbar = 2;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
@@ -1708,7 +1728,7 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
- selmon->showbar = !selmon->showbar;
|
||||
+ selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar);
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
arrange(selmon);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,61 @@
|
||||
From 0d1ef9f548011345e144b2b37565c2f9f964ea61 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 12:56:49 +0100
|
||||
Subject: [PATCH] Lose fullscreen on focus change
|
||||
|
||||
This implements a separate losefullscreen function proposed by jzbor.
|
||||
---
|
||||
dwm.c | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..2964adb 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -178,6 +178,7 @@ static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
+static void losefullscreen(Client *sel, Client *next);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
@@ -854,6 +855,7 @@ focusstack(const Arg *arg)
|
||||
c = i;
|
||||
}
|
||||
if (c) {
|
||||
+ losefullscreen(selmon->sel, c);
|
||||
focus(c);
|
||||
restack(selmon);
|
||||
}
|
||||
@@ -1018,6 +1020,15 @@ killclient(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+losefullscreen(Client *sel, Client *next)
|
||||
+{
|
||||
+ if (!sel || !next)
|
||||
+ return;
|
||||
+ if (sel->isfullscreen && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
|
||||
+ setfullscreen(sel, 0);
|
||||
+}
|
||||
+
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
@@ -1072,8 +1083,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
+ if (c->mon == selmon) {
|
||||
+ losefullscreen(selmon->sel, c);
|
||||
unfocus(selmon->sel, 0);
|
||||
+ }
|
||||
c->mon->sel = c;
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,95 @@
|
||||
From f2e1a6e15ba38b29d20f1fa8fa979f8f380e93ae Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 12:57:26 +0100
|
||||
Subject: [PATCH] Monitor rules patch
|
||||
|
||||
This patch allows the user to define layout, mfact, nmaster, showbar,
|
||||
and topbar settings on a per monitor basis. An example use case could
|
||||
be to have a layout with a horizontal split for a secondary vertical
|
||||
monitor.
|
||||
---
|
||||
config.def.h | 6 ++++++
|
||||
dwm.c | 36 ++++++++++++++++++++++++++++++++----
|
||||
2 files changed, 38 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..7718adc 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -31,6 +31,12 @@ static const Rule rules[] = {
|
||||
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
};
|
||||
|
||||
+static const MonitorRule monrules[] = {
|
||||
+ /* monitor layout mfact nmaster showbar topbar */
|
||||
+ { 1, 2, -1, -1, -1, -1 }, // use a different layout for the second monitor
|
||||
+ { -1, 0, -1, -1, -1, -1 }, // default
|
||||
+};
|
||||
+
|
||||
/* layout(s) */
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..31e5834 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -141,6 +141,15 @@ typedef struct {
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
+typedef struct {
|
||||
+ int monitor;
|
||||
+ int layout;
|
||||
+ float mfact;
|
||||
+ int nmaster;
|
||||
+ int showbar;
|
||||
+ int topbar;
|
||||
+} MonitorRule;
|
||||
+
|
||||
/* function declarations */
|
||||
static void applyrules(Client *c);
|
||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||
@@ -631,7 +640,9 @@ configurerequest(XEvent *e)
|
||||
Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
- Monitor *m;
|
||||
+ Monitor *m, *mon;
|
||||
+ unsigned int mi, j;
|
||||
+ const MonitorRule *mr;
|
||||
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
@@ -639,9 +650,26 @@ createmon(void)
|
||||
m->nmaster = nmaster;
|
||||
m->showbar = showbar;
|
||||
m->topbar = topbar;
|
||||
- m->lt[0] = &layouts[0];
|
||||
- m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
- strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ for (mi = 0, mon = mons; mon; mon = mon->next, mi++);
|
||||
+ for (j = 0; j < LENGTH(monrules); j++) {
|
||||
+ mr = &monrules[j];
|
||||
+ if ((mr->monitor == -1 || mr->monitor == mi)) {
|
||||
+ m->lt[0] = &layouts[mr->layout];
|
||||
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
+ strncpy(m->ltsymbol, layouts[mr->layout].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ if (mr->mfact > -1)
|
||||
+ m->mfact = mr->mfact;
|
||||
+ if (mr->nmaster > -1)
|
||||
+ m->nmaster = mr->nmaster;
|
||||
+ if (mr->showbar > -1)
|
||||
+ m->showbar = mr->showbar;
|
||||
+ if (mr->topbar > -1)
|
||||
+ m->topbar = mr->topbar;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
return m;
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,84 @@
|
||||
From a6b1b5e62da24750c057fbd8fcbea4b05bb2c152 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 12:58:43 +0100
|
||||
Subject: [PATCH] Monitor tags patch
|
||||
|
||||
This patch allows you to have different tags icons on a per-monitor
|
||||
basis. This patch will conflict with a series of other patches, but
|
||||
it should be more or less straightforward to sort out:
|
||||
- LENGTH(tags) is replaced with TAGLENGTH
|
||||
- tags[i] is replaced with tags[m->mon][i]
|
||||
---
|
||||
config.def.h | 6 +++++-
|
||||
dwm.c | 16 ++++++++--------
|
||||
2 files changed, 13 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..7845d7f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -19,7 +19,11 @@ static const char *colors[][3] = {
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
-static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
+#define TAGLENGTH 9
|
||||
+static const char *tags[][TAGLENGTH] = {
|
||||
+ { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
|
||||
+ { "A", "B", "C", "D", "E", "F", "G", "H", "I"},
|
||||
+};
|
||||
|
||||
static const Rule rules[] = {
|
||||
/* xprop(1):
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..1ac16f4 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -54,7 +54,7 @@
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
|
||||
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
|
||||
-#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
||||
+#define TAGMASK ((1 << TAGLENGTH) - 1)
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
|
||||
/* enums */
|
||||
@@ -273,7 +273,7 @@ static Window root, wmcheckwin;
|
||||
#include "config.h"
|
||||
|
||||
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||
-struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||
+struct NumTags { char limitexceeded[TAGLENGTH > 31 ? -1 : 1]; };
|
||||
|
||||
/* function implementations */
|
||||
void
|
||||
@@ -433,9 +433,9 @@ buttonpress(XEvent *e)
|
||||
if (ev->window == selmon->barwin) {
|
||||
i = x = 0;
|
||||
do
|
||||
- x += TEXTW(tags[i]);
|
||||
- while (ev->x >= x && ++i < LENGTH(tags));
|
||||
- if (i < LENGTH(tags)) {
|
||||
+ x += TEXTW(tags[selmon->num][i]);
|
||||
+ while (ev->x >= x && ++i < TAGLENGTH);
|
||||
+ if (i < TAGLENGTH) {
|
||||
click = ClkTagBar;
|
||||
arg.ui = 1 << i;
|
||||
} else if (ev->x < x + blw)
|
||||
@@ -718,10 +718,10 @@ drawbar(Monitor *m)
|
||||
urg |= c->tags;
|
||||
}
|
||||
x = 0;
|
||||
- for (i = 0; i < LENGTH(tags); i++) {
|
||||
- w = TEXTW(tags[i]);
|
||||
+ for (i = 0; i < TAGLENGTH; i++) {
|
||||
+ w = TEXTW(tags[m->num][i]);
|
||||
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
|
||||
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[m->num][i], urg & 1 << i);
|
||||
if (occ & 1 << i)
|
||||
drw_rect(drw, x + boxs, boxs, boxw, boxw,
|
||||
m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,129 @@
|
||||
From 3e6552b77de5c70f04cf96f6191d84efebfbb448 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 12:59:49 +0100
|
||||
Subject: [PATCH] The moveresize patch allows floating windows to be resized
|
||||
and moved using keyboard shortcuts.
|
||||
|
||||
This example keybinding reduces the y position with 25 pixels.
|
||||
|
||||
{ MODKEY, XK_Up, moveresize, {.v = "0x -25y 0w 0h" } },
|
||||
|
||||
Use capital letters to specify absolute size and position should you need it.
|
||||
|
||||
{ MODKEY, XK_Up, moveresize, {.v = "0x 0y 500W 300H" } },
|
||||
|
||||
The above example would set the size of the client to 300x500 pixels, but leave the position as-is.
|
||||
|
||||
Refer to:
|
||||
https://dwm.suckless.org/patches/moveresize/
|
||||
---
|
||||
config.def.h | 8 +++++++
|
||||
dwm.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 74 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..94783ca 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -79,6 +79,14 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
+ { MODKEY, XK_Down, moveresize, {.v = "0x 25y 0w 0h" } },
|
||||
+ { MODKEY, XK_Up, moveresize, {.v = "0x -25y 0w 0h" } },
|
||||
+ { MODKEY, XK_Right, moveresize, {.v = "25x 0y 0w 0h" } },
|
||||
+ { MODKEY, XK_Left, moveresize, {.v = "-25x 0y 0w 0h" } },
|
||||
+ { MODKEY|ShiftMask, XK_Down, moveresize, {.v = "0x 0y 0w 25h" } },
|
||||
+ { MODKEY|ShiftMask, XK_Up, moveresize, {.v = "0x 0y 0w -25h" } },
|
||||
+ { MODKEY|ShiftMask, XK_Right, moveresize, {.v = "0x 0y 25w 0h" } },
|
||||
+ { MODKEY|ShiftMask, XK_Left, moveresize, {.v = "0x 0y -25w 0h" } },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..a419c23 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -183,6 +183,7 @@ static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionnotify(XEvent *e);
|
||||
+static void moveresize(const Arg *arg);
|
||||
static void movemouse(const Arg *arg);
|
||||
static Client *nexttiled(Client *c);
|
||||
static void pop(Client *);
|
||||
@@ -1196,6 +1197,71 @@ movemouse(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void
|
||||
+moveresize(const Arg *arg) {
|
||||
+ /* only floating windows can be moved */
|
||||
+ Client *c;
|
||||
+ c = selmon->sel;
|
||||
+ int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh;
|
||||
+ char xAbs, yAbs, wAbs, hAbs;
|
||||
+ int msx, msy, dx, dy, nmx, nmy;
|
||||
+ unsigned int dui;
|
||||
+ Window dummy;
|
||||
+
|
||||
+ if (!c || !arg)
|
||||
+ return;
|
||||
+ if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
|
||||
+ return;
|
||||
+ if (sscanf((char *)arg->v, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8)
|
||||
+ return;
|
||||
+
|
||||
+ /* compute new window position; prevent window from be positioned outside the current monitor */
|
||||
+ nw = c->w + w;
|
||||
+ if (wAbs == 'W')
|
||||
+ nw = w < selmon->mw - 2 * c->bw ? w : selmon->mw - 2 * c->bw;
|
||||
+
|
||||
+ nh = c->h + h;
|
||||
+ if (hAbs == 'H')
|
||||
+ nh = h < selmon->mh - 2 * c->bw ? h : selmon->mh - 2 * c->bw;
|
||||
+
|
||||
+ nx = c->x + x;
|
||||
+ if (xAbs == 'X') {
|
||||
+ if (x < selmon->mx)
|
||||
+ nx = selmon->mx;
|
||||
+ else if (x > selmon->mx + selmon->mw)
|
||||
+ nx = selmon->mx + selmon->mw - nw - 2 * c->bw;
|
||||
+ else
|
||||
+ nx = x;
|
||||
+ }
|
||||
+
|
||||
+ ny = c->y + y;
|
||||
+ if (yAbs == 'Y') {
|
||||
+ if (y < selmon->my)
|
||||
+ ny = selmon->my;
|
||||
+ else if (y > selmon->my + selmon->mh)
|
||||
+ ny = selmon->my + selmon->mh - nh - 2 * c->bw;
|
||||
+ else
|
||||
+ ny = y;
|
||||
+ }
|
||||
+
|
||||
+ ox = c->x;
|
||||
+ oy = c->y;
|
||||
+ ow = c->w;
|
||||
+ oh = c->h;
|
||||
+
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &msx, &msy, &dx, &dy, &dui);
|
||||
+ resize(c, nx, ny, nw, nh, True);
|
||||
+
|
||||
+ /* move cursor along with the window to avoid problems caused by the sloppy focus */
|
||||
+ if (xqp && ox <= msx && (ox + ow) >= msx && oy <= msy && (oy + oh) >= msy)
|
||||
+ {
|
||||
+ nmx = c->x - ox + c->w - ow;
|
||||
+ nmy = c->y - oy + c->h - oh;
|
||||
+ XWarpPointer(dpy, None, None, 0, 0, 0, 0, nmx, nmy);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
Client *
|
||||
nexttiled(Client *c)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,217 @@
|
||||
From bbc5059faa2372e6d01ae4c5e5de9ec230a6c020 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:00:24 +0100
|
||||
Subject: [PATCH] This is an example patch extending the focusonnetactive patch
|
||||
to offer different behaviours on receipt of the net active event signal and
|
||||
a per client rule for what action to take.
|
||||
|
||||
An example use case is to ignore net active signals from Steam,
|
||||
which triggers every time the client get focus.
|
||||
|
||||
Being an example patch this has a lot of comments explaining why
|
||||
code is being added in the places where they are and what the code
|
||||
does. It is not the intention that the comments is kept. It is
|
||||
intended as a learning exercise for making changes like this from
|
||||
scratch.
|
||||
|
||||
This patch was created in relation to this reddit post:
|
||||
https://www.reddit.com/r/suckless/comments/gyrszt/dwm_and_steam_issue_with_steam_always_taking/
|
||||
---
|
||||
config.def.h | 16 ++++++--
|
||||
dwm.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 115 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..33b0b42 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,16 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+/* Default action to take when we receive a net active signal.
|
||||
+ * 0 - disable / does nothing
|
||||
+ * 1 - focus the client (as per the focusonnetactive patch)
|
||||
+ * 2 - focus the client tag in addition to the current tags
|
||||
+ * 3 - set the urgency bit (as per dwm default)
|
||||
+ * 4 - client is shown on current tag in addition to its existing tags
|
||||
+ * 5 - client is moved to current tag
|
||||
+ * 6 - client receives focus only if current tag is shown
|
||||
+ */
|
||||
+static const int defnetactiverule = 1;
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -26,9 +36,9 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating monitor netactiverule */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, -1, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, -1, -1 },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b1bc3f7 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -66,6 +66,18 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
+// Adding an enum here is not strictly necessary, but it
|
||||
+// can help avoid "magic" numbers in your code base. An
|
||||
+// example of this is when you read the code and you go
|
||||
+// "wtf is 58?". Here we have that DoNothing is 0, Focus
|
||||
+// is 1 and Urgent is 3. Other enums have a *Last value
|
||||
+// at the end - this is only used when one need to loop
|
||||
+// through all the values. Also note that you can use
|
||||
+// these rather than plain numbers in your configuration
|
||||
+// file, e.g. defnetactiverule = Focus;
|
||||
+// I left the configuration with plain numbers just for
|
||||
+// consistency.
|
||||
+enum { DoNothing, Focus, FocusPlus, Urgent, ShowClient, MoveClient, FocusIfShown }; /* net active rule options */
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
@@ -91,6 +103,11 @@ struct Client {
|
||||
int oldx, oldy, oldw, oldh;
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
int bw, oldbw;
|
||||
+ // We need to associate a specific behaviour on
|
||||
+ // a per-client basis. As such we need to set a
|
||||
+ // value for the client and therefore we also
|
||||
+ // need a variable to store this in.
|
||||
+ int onnetactive;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
Client *next;
|
||||
@@ -139,6 +156,12 @@ typedef struct {
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ // Adding our new rule option, making it an int.
|
||||
+ // Note that the order of the fields here are
|
||||
+ // important and the "columns" for the rules
|
||||
+ // array in your config needs to be in this
|
||||
+ // exact order.
|
||||
+ int netactiverule;
|
||||
} Rule;
|
||||
|
||||
/* function declarations */
|
||||
@@ -288,6 +311,11 @@ applyrules(Client *c)
|
||||
/* rule matching */
|
||||
c->isfloating = 0;
|
||||
c->tags = 0;
|
||||
+ // In case we have no rule set up for our client, or
|
||||
+ // the rule value is -1, then we'll want to set the
|
||||
+ // default action to take when we receive a net active
|
||||
+ // signal.
|
||||
+ c->onnetactive = defnetactiverule;
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
class = ch.res_class ? ch.res_class : broken;
|
||||
instance = ch.res_name ? ch.res_name : broken;
|
||||
@@ -303,6 +331,11 @@ applyrules(Client *c)
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
+ // If our net active rule is not -1, then associate
|
||||
+ // that action value with our client.
|
||||
+ if (r->netactiverule > -1)
|
||||
+ c->onnetactive = r->netactiverule;
|
||||
+
|
||||
}
|
||||
}
|
||||
if (ch.res_class)
|
||||
@@ -515,6 +548,7 @@ clientmessage(XEvent *e)
|
||||
{
|
||||
XClientMessageEvent *cme = &e->xclient;
|
||||
Client *c = wintoclient(cme->window);
|
||||
+ unsigned int i;
|
||||
|
||||
if (!c)
|
||||
return;
|
||||
@@ -524,8 +558,74 @@ clientmessage(XEvent *e)
|
||||
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
||||
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
|
||||
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
||||
- if (c != selmon->sel && !c->isurgent)
|
||||
- seturgent(c, 1);
|
||||
+ // OK, so we have received the net active window signal,
|
||||
+ // let's decide what to do about it.
|
||||
+ switch(c->onnetactive) {
|
||||
+ default:
|
||||
+ break;
|
||||
+ case DoNothing:
|
||||
+ // Yes let's just not do anything. This is
|
||||
+ // redudnant as we could have just left it
|
||||
+ // for the default, but at last this is
|
||||
+ // explicit and sort of readable.
|
||||
+ break;
|
||||
+ case Focus:
|
||||
+ // This is lifted straight from the original
|
||||
+ // focusonnetactive patch.
|
||||
+ for (i = 0; i < LENGTH(tags) && !((1 << i) & c->tags); i++);
|
||||
+ if (i < LENGTH(tags)) {
|
||||
+ const Arg a = {.ui = 1 << i};
|
||||
+ selmon = c->mon;
|
||||
+ view(&a);
|
||||
+ focus(c);
|
||||
+ restack(selmon);
|
||||
+ }
|
||||
+ break;
|
||||
+ case FocusPlus:
|
||||
+ // Similar to the original focusonnetactive
|
||||
+ // logic, but shows the client's tag in
|
||||
+ // addition to your current tags.
|
||||
+ for (i = 0; i < LENGTH(tags) && !((1 << i) & c->tags); i++);
|
||||
+ if (i < LENGTH(tags)) {
|
||||
+ selmon = c->mon;
|
||||
+ view(&((Arg) {.ui = c->mon->seltags | (1 << i)}));
|
||||
+ focus(c);
|
||||
+ restack(selmon);
|
||||
+ }
|
||||
+ break;
|
||||
+ case ShowClient:
|
||||
+ // If client is not already on any of the currently
|
||||
+ // viewed tags, then let the client be shown on the
|
||||
+ // currently viewed tag(s) in addition to the client's
|
||||
+ // existing tags.
|
||||
+ if (!(c->mon->tagset[c->mon->seltags] & c->tags))
|
||||
+ c->tags |= c->mon->tagset[c->mon->seltags];
|
||||
+ focus(c);
|
||||
+ arrange(c->mon);
|
||||
+ break;
|
||||
+ case MoveClient:
|
||||
+ // If client is not already on any of the currently
|
||||
+ // viewed tags, then move the client to the currently
|
||||
+ // viewed tag(s).
|
||||
+ if (!(c->mon->tagset[c->mon->seltags] & c->tags))
|
||||
+ c->tags = c->mon->tagset[c->mon->seltags];
|
||||
+ focus(c);
|
||||
+ arrange(c->mon);
|
||||
+ break;
|
||||
+ case FocusIfShown:
|
||||
+ // If client is already shown on the currently viewed
|
||||
+ // tag then focus it, otherwise do nothing.
|
||||
+ if ((c->mon->tagset[c->mon->seltags] & c->tags))
|
||||
+ focus(c);
|
||||
+ break;
|
||||
+ case Urgent:
|
||||
+ // This is simply the original code.
|
||||
+ if (c != selmon->sel && !c->isurgent)
|
||||
+ seturgent(c, 1);
|
||||
+ break;
|
||||
+ // You could easily extend this to add other behaviours
|
||||
+ // should you want it.
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 88398a44ab4dce31c48708d36d39d5ff2a21c8b2 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:01:24 +0100
|
||||
Subject: [PATCH] Adds the _NET_CLIENT_LIST_STACKING property which may be
|
||||
needed by some applications, e.g. zoom for window sharing.
|
||||
|
||||
---
|
||||
dwm.c | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..7e640dc 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -62,7 +62,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
+ NetWMWindowTypeDialog, NetClientList, NetClientListStacking, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
@@ -1070,6 +1070,8 @@ manage(Window w, XWindowAttributes *wa)
|
||||
attachstack(c);
|
||||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
+ XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend,
|
||||
+ (unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
if (c->mon == selmon)
|
||||
@@ -1566,6 +1568,7 @@ setup(void)
|
||||
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
||||
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
||||
+ netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
@@ -1589,6 +1592,7 @@ setup(void)
|
||||
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
|
||||
PropModeReplace, (unsigned char *) netatom, NetLast);
|
||||
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
||||
+ XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
|
||||
/* select events */
|
||||
wa.cursor = cursor[CurNormal]->cursor;
|
||||
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
|
||||
@@ -1851,6 +1855,13 @@ updateclientlist()
|
||||
XChangeProperty(dpy, root, netatom[NetClientList],
|
||||
XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
+
|
||||
+ XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ for (c = m->stack; c; c = c->snext)
|
||||
+ XChangeProperty(dpy, root, netatom[NetClientListStacking],
|
||||
+ XA_WINDOW, 32, PropModeAppend,
|
||||
+ (unsigned char *) &(c->win), 1);
|
||||
}
|
||||
|
||||
int
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,207 @@
|
||||
From 8323f1e2e1e71223aa516f66415611fe4dd1f2ed Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:02:01 +0100
|
||||
Subject: [PATCH] pertag patch, keeps layout, mwfact, barpos and nmaster per
|
||||
tag
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/pertag/
|
||||
---
|
||||
dwm.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 90 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b8ae4a5 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -111,6 +111,7 @@ typedef struct {
|
||||
void (*arrange)(Monitor *);
|
||||
} Layout;
|
||||
|
||||
+typedef struct Pertag Pertag;
|
||||
struct Monitor {
|
||||
char ltsymbol[16];
|
||||
float mfact;
|
||||
@@ -130,6 +131,7 @@ struct Monitor {
|
||||
Monitor *next;
|
||||
Window barwin;
|
||||
const Layout *lt[2];
|
||||
+ Pertag *pertag;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -272,6 +274,18 @@ static Window root, wmcheckwin;
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
+struct Pertag {
|
||||
+ unsigned int curtag, prevtag; /* current and previous tag */
|
||||
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
|
||||
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
|
||||
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
|
||||
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
|
||||
+ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
|
||||
+ #if ZOOMSWAP_PATCH
|
||||
+ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
|
||||
+ #endif // ZOOMSWAP_PATCH
|
||||
+};
|
||||
+
|
||||
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||
|
||||
@@ -507,6 +521,7 @@ cleanupmon(Monitor *mon)
|
||||
}
|
||||
XUnmapWindow(dpy, mon->barwin);
|
||||
XDestroyWindow(dpy, mon->barwin);
|
||||
+ free(mon->pertag);
|
||||
free(mon);
|
||||
}
|
||||
|
||||
@@ -632,6 +647,7 @@ Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
Monitor *m;
|
||||
+ int i;
|
||||
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
@@ -642,6 +658,28 @@ createmon(void)
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+ if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
|
||||
+ m->pertag->curtag = m->pertag->prevtag = 1;
|
||||
+ for (i = 0; i <= LENGTH(tags); i++) {
|
||||
+ /* init nmaster */
|
||||
+ m->pertag->nmasters[i] = m->nmaster;
|
||||
+
|
||||
+ /* init mfacts */
|
||||
+ m->pertag->mfacts[i] = m->mfact;
|
||||
+
|
||||
+ /* init layouts */
|
||||
+ m->pertag->ltidxs[i][0] = m->lt[0];
|
||||
+ m->pertag->ltidxs[i][1] = m->lt[1];
|
||||
+ m->pertag->sellts[i] = m->sellt;
|
||||
+
|
||||
+ /* init showbar */
|
||||
+ m->pertag->showbars[i] = m->showbar;
|
||||
+
|
||||
+ #if ZOOMSWAP_PATCH
|
||||
+ m->pertag->prevzooms[i] = NULL;
|
||||
+ #endif // ZOOMSWAP_PATCH
|
||||
+ }
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -970,7 +1008,7 @@ grabkeys(void)
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1504,10 +1542,13 @@ setfullscreen(Client *c, int fullscreen)
|
||||
void
|
||||
setlayout(const Arg *arg)
|
||||
{
|
||||
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
|
||||
- selmon->sellt ^= 1;
|
||||
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ }
|
||||
if (arg && arg->v)
|
||||
- selmon->lt[selmon->sellt] = (Layout *)arg->v;
|
||||
+ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
||||
if (selmon->sel)
|
||||
arrange(selmon);
|
||||
@@ -1526,7 +1567,7 @@ setmfact(const Arg *arg)
|
||||
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
|
||||
if (f < 0.05 || f > 0.95)
|
||||
return;
|
||||
- selmon->mfact = f;
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1705,7 +1746,7 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
- selmon->showbar = !selmon->showbar;
|
||||
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
arrange(selmon);
|
||||
@@ -1744,9 +1785,29 @@ void
|
||||
toggleview(const Arg *arg)
|
||||
{
|
||||
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
||||
+ int i;
|
||||
|
||||
if (newtagset) {
|
||||
+ if (newtagset == ~0) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ selmon->pertag->curtag = 0;
|
||||
+ }
|
||||
+ /* test if the user did not select the same tag */
|
||||
+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ for (i=0; !(newtagset & 1 << i); i++) ;
|
||||
+ selmon->pertag->curtag = i + 1;
|
||||
+ }
|
||||
selmon->tagset[selmon->seltags] = newtagset;
|
||||
+
|
||||
+ /* apply settings for this view */
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||
+ togglebar(NULL);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
@@ -2041,11 +2102,33 @@ updatewmhints(Client *c)
|
||||
void
|
||||
view(const Arg *arg)
|
||||
{
|
||||
+ int i;
|
||||
+ unsigned int tmptag;
|
||||
+
|
||||
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
selmon->seltags ^= 1; /* toggle sel tagset */
|
||||
- if (arg->ui & TAGMASK)
|
||||
+ if (arg->ui & TAGMASK) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
||||
+ if (arg->ui == ~0)
|
||||
+ selmon->pertag->curtag = 0;
|
||||
+ else {
|
||||
+ for (i=0; !(arg->ui & 1 << i); i++) ;
|
||||
+ selmon->pertag->curtag = i + 1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ tmptag = selmon->pertag->prevtag;
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ selmon->pertag->curtag = tmptag;
|
||||
+ }
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||
+ togglebar(NULL);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,139 @@
|
||||
From 2f39e89ed604854515f8c4be502af09b9a89d05f Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:11:18 +0100
|
||||
Subject: [PATCH 2/2] Monitor rules patch on top of pertag
|
||||
|
||||
This patch allows the user to define layout, mfact, nmaster, showbar,
|
||||
and topbar settings on a per monitor basis. An example use case could
|
||||
be to have a layout with a horizontal split for a secondary vertical
|
||||
monitor.
|
||||
|
||||
https://github.com/bakkeby/patches/wiki/monitorrules
|
||||
---
|
||||
config.def.h | 6 +++++
|
||||
dwm.c | 67 +++++++++++++++++++++++++++++++++++++++++-----------
|
||||
2 files changed, 59 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..cf8c7d1 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -44,6 +44,12 @@ static const Layout layouts[] = {
|
||||
{ "[M]", monocle },
|
||||
};
|
||||
|
||||
+static const MonitorRule monrules[] = {
|
||||
+ /* monitor tag layout mfact nmaster showbar topbar */
|
||||
+ { 1, -1, 2, -1, -1, -1, -1 }, // use a different layout for the second monitor
|
||||
+ { -1, -1, 0, -1, -1, -1, -1 }, // default
|
||||
+};
|
||||
+
|
||||
/* key definitions */
|
||||
#define MODKEY Mod1Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index b8ae4a5..d167d42 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -143,6 +143,16 @@ typedef struct {
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
+typedef struct {
|
||||
+ int monitor;
|
||||
+ int tag;
|
||||
+ int layout;
|
||||
+ float mfact;
|
||||
+ int nmaster;
|
||||
+ int showbar;
|
||||
+ int topbar;
|
||||
+} MonitorRule;
|
||||
+
|
||||
/* function declarations */
|
||||
static void applyrules(Client *c);
|
||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||
@@ -646,31 +656,46 @@ configurerequest(XEvent *e)
|
||||
Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
- Monitor *m;
|
||||
- int i;
|
||||
-
|
||||
+ Monitor *m, *mon;
|
||||
+ int i, mi, j, layout;
|
||||
+ const MonitorRule *mr;
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
m->mfact = mfact;
|
||||
m->nmaster = nmaster;
|
||||
m->showbar = showbar;
|
||||
m->topbar = topbar;
|
||||
- m->lt[0] = &layouts[0];
|
||||
- m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
- strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ for (mi = 0, mon = mons; mon; mon = mon->next, mi++);
|
||||
+ for (j = 0; j < LENGTH(monrules); j++) {
|
||||
+ mr = &monrules[j];
|
||||
+ if ((mr->monitor == -1 || mr->monitor == mi)
|
||||
+ && (mr->tag <= 0 || (m->tagset[0] & (1 << (mr->tag - 1))))
|
||||
+ ) {
|
||||
+ layout = MAX(mr->layout, 0);
|
||||
+ layout = MIN(layout, LENGTH(layouts) - 1);
|
||||
+ m->lt[0] = &layouts[layout];
|
||||
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
+ strncpy(m->ltsymbol, layouts[layout].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ if (mr->mfact > -1)
|
||||
+ m->mfact = mr->mfact;
|
||||
+ if (mr->nmaster > -1)
|
||||
+ m->nmaster = mr->nmaster;
|
||||
+ if (mr->showbar > -1)
|
||||
+ m->showbar = mr->showbar;
|
||||
+ if (mr->topbar > -1)
|
||||
+ m->topbar = mr->topbar;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
|
||||
die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
|
||||
m->pertag->curtag = m->pertag->prevtag = 1;
|
||||
- for (i = 0; i <= LENGTH(tags); i++) {
|
||||
- /* init nmaster */
|
||||
- m->pertag->nmasters[i] = m->nmaster;
|
||||
-
|
||||
- /* init mfacts */
|
||||
- m->pertag->mfacts[i] = m->mfact;
|
||||
|
||||
+ for (i = 0; i <= LENGTH(tags); i++) {
|
||||
/* init layouts */
|
||||
- m->pertag->ltidxs[i][0] = m->lt[0];
|
||||
- m->pertag->ltidxs[i][1] = m->lt[1];
|
||||
m->pertag->sellts[i] = m->sellt;
|
||||
|
||||
/* init showbar */
|
||||
@@ -679,6 +704,20 @@ createmon(void)
|
||||
#if ZOOMSWAP_PATCH
|
||||
m->pertag->prevzooms[i] = NULL;
|
||||
#endif // ZOOMSWAP_PATCH
|
||||
+
|
||||
+ for (j = 0; j < LENGTH(monrules); j++) {
|
||||
+ mr = &monrules[j];
|
||||
+ if ((mr->monitor == -1 || mr->monitor == mi) && (mr->tag == -1 || mr->tag == i)) {
|
||||
+ layout = MAX(mr->layout, 0);
|
||||
+ layout = MIN(layout, LENGTH(layouts) - 1);
|
||||
+ m->pertag->ltidxs[i][0] = &layouts[layout];
|
||||
+ m->pertag->ltidxs[i][1] = m->lt[0];
|
||||
+ m->pertag->nmasters[i] = (mr->nmaster > -1 ? mr->nmaster : m->nmaster);
|
||||
+ m->pertag->mfacts[i] = (mr->mfact > -1 ? mr->mfact : m->mfact);
|
||||
+ m->pertag->showbars[i] = (mr->showbar > -1 ? mr->showbar : m->showbar);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
return m;
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,347 @@
|
||||
From 8323f1e2e1e71223aa516f66415611fe4dd1f2ed Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:02:01 +0100
|
||||
Subject: [PATCH 1/2] pertag patch, keeps layout, mwfact, barpos and nmaster
|
||||
per tag
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/pertag/
|
||||
---
|
||||
dwm.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 90 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b8ae4a5 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -111,6 +111,7 @@ typedef struct {
|
||||
void (*arrange)(Monitor *);
|
||||
} Layout;
|
||||
|
||||
+typedef struct Pertag Pertag;
|
||||
struct Monitor {
|
||||
char ltsymbol[16];
|
||||
float mfact;
|
||||
@@ -130,6 +131,7 @@ struct Monitor {
|
||||
Monitor *next;
|
||||
Window barwin;
|
||||
const Layout *lt[2];
|
||||
+ Pertag *pertag;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -272,6 +274,18 @@ static Window root, wmcheckwin;
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
+struct Pertag {
|
||||
+ unsigned int curtag, prevtag; /* current and previous tag */
|
||||
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
|
||||
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
|
||||
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
|
||||
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
|
||||
+ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
|
||||
+ #if ZOOMSWAP_PATCH
|
||||
+ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
|
||||
+ #endif // ZOOMSWAP_PATCH
|
||||
+};
|
||||
+
|
||||
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||
|
||||
@@ -507,6 +521,7 @@ cleanupmon(Monitor *mon)
|
||||
}
|
||||
XUnmapWindow(dpy, mon->barwin);
|
||||
XDestroyWindow(dpy, mon->barwin);
|
||||
+ free(mon->pertag);
|
||||
free(mon);
|
||||
}
|
||||
|
||||
@@ -632,6 +647,7 @@ Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
Monitor *m;
|
||||
+ int i;
|
||||
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
@@ -642,6 +658,28 @@ createmon(void)
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+ if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
|
||||
+ m->pertag->curtag = m->pertag->prevtag = 1;
|
||||
+ for (i = 0; i <= LENGTH(tags); i++) {
|
||||
+ /* init nmaster */
|
||||
+ m->pertag->nmasters[i] = m->nmaster;
|
||||
+
|
||||
+ /* init mfacts */
|
||||
+ m->pertag->mfacts[i] = m->mfact;
|
||||
+
|
||||
+ /* init layouts */
|
||||
+ m->pertag->ltidxs[i][0] = m->lt[0];
|
||||
+ m->pertag->ltidxs[i][1] = m->lt[1];
|
||||
+ m->pertag->sellts[i] = m->sellt;
|
||||
+
|
||||
+ /* init showbar */
|
||||
+ m->pertag->showbars[i] = m->showbar;
|
||||
+
|
||||
+ #if ZOOMSWAP_PATCH
|
||||
+ m->pertag->prevzooms[i] = NULL;
|
||||
+ #endif // ZOOMSWAP_PATCH
|
||||
+ }
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -970,7 +1008,7 @@ grabkeys(void)
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1504,10 +1542,13 @@ setfullscreen(Client *c, int fullscreen)
|
||||
void
|
||||
setlayout(const Arg *arg)
|
||||
{
|
||||
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
|
||||
- selmon->sellt ^= 1;
|
||||
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ }
|
||||
if (arg && arg->v)
|
||||
- selmon->lt[selmon->sellt] = (Layout *)arg->v;
|
||||
+ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
||||
if (selmon->sel)
|
||||
arrange(selmon);
|
||||
@@ -1526,7 +1567,7 @@ setmfact(const Arg *arg)
|
||||
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
|
||||
if (f < 0.05 || f > 0.95)
|
||||
return;
|
||||
- selmon->mfact = f;
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1705,7 +1746,7 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
- selmon->showbar = !selmon->showbar;
|
||||
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
arrange(selmon);
|
||||
@@ -1744,9 +1785,29 @@ void
|
||||
toggleview(const Arg *arg)
|
||||
{
|
||||
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
||||
+ int i;
|
||||
|
||||
if (newtagset) {
|
||||
+ if (newtagset == ~0) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ selmon->pertag->curtag = 0;
|
||||
+ }
|
||||
+ /* test if the user did not select the same tag */
|
||||
+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ for (i=0; !(newtagset & 1 << i); i++) ;
|
||||
+ selmon->pertag->curtag = i + 1;
|
||||
+ }
|
||||
selmon->tagset[selmon->seltags] = newtagset;
|
||||
+
|
||||
+ /* apply settings for this view */
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||
+ togglebar(NULL);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
@@ -2041,11 +2102,33 @@ updatewmhints(Client *c)
|
||||
void
|
||||
view(const Arg *arg)
|
||||
{
|
||||
+ int i;
|
||||
+ unsigned int tmptag;
|
||||
+
|
||||
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
selmon->seltags ^= 1; /* toggle sel tagset */
|
||||
- if (arg->ui & TAGMASK)
|
||||
+ if (arg->ui & TAGMASK) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
||||
+ if (arg->ui == ~0)
|
||||
+ selmon->pertag->curtag = 0;
|
||||
+ else {
|
||||
+ for (i=0; !(arg->ui & 1 << i); i++) ;
|
||||
+ selmon->pertag->curtag = i + 1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ tmptag = selmon->pertag->prevtag;
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ selmon->pertag->curtag = tmptag;
|
||||
+ }
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||
+ togglebar(NULL);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 2f39e89ed604854515f8c4be502af09b9a89d05f Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:11:18 +0100
|
||||
Subject: [PATCH 2/2] Monitor rules patch on top of pertag
|
||||
|
||||
This patch allows the user to define layout, mfact, nmaster, showbar,
|
||||
and topbar settings on a per monitor basis. An example use case could
|
||||
be to have a layout with a horizontal split for a secondary vertical
|
||||
monitor.
|
||||
|
||||
https://github.com/bakkeby/patches/wiki/monitorrules
|
||||
---
|
||||
config.def.h | 6 +++++
|
||||
dwm.c | 67 +++++++++++++++++++++++++++++++++++++++++-----------
|
||||
2 files changed, 59 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..cf8c7d1 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -44,6 +44,12 @@ static const Layout layouts[] = {
|
||||
{ "[M]", monocle },
|
||||
};
|
||||
|
||||
+static const MonitorRule monrules[] = {
|
||||
+ /* monitor tag layout mfact nmaster showbar topbar */
|
||||
+ { 1, -1, 2, -1, -1, -1, -1 }, // use a different layout for the second monitor
|
||||
+ { -1, -1, 0, -1, -1, -1, -1 }, // default
|
||||
+};
|
||||
+
|
||||
/* key definitions */
|
||||
#define MODKEY Mod1Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index b8ae4a5..d167d42 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -143,6 +143,16 @@ typedef struct {
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
+typedef struct {
|
||||
+ int monitor;
|
||||
+ int tag;
|
||||
+ int layout;
|
||||
+ float mfact;
|
||||
+ int nmaster;
|
||||
+ int showbar;
|
||||
+ int topbar;
|
||||
+} MonitorRule;
|
||||
+
|
||||
/* function declarations */
|
||||
static void applyrules(Client *c);
|
||||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
|
||||
@@ -646,31 +656,46 @@ configurerequest(XEvent *e)
|
||||
Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
- Monitor *m;
|
||||
- int i;
|
||||
-
|
||||
+ Monitor *m, *mon;
|
||||
+ int i, mi, j, layout;
|
||||
+ const MonitorRule *mr;
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
m->mfact = mfact;
|
||||
m->nmaster = nmaster;
|
||||
m->showbar = showbar;
|
||||
m->topbar = topbar;
|
||||
- m->lt[0] = &layouts[0];
|
||||
- m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
- strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ for (mi = 0, mon = mons; mon; mon = mon->next, mi++);
|
||||
+ for (j = 0; j < LENGTH(monrules); j++) {
|
||||
+ mr = &monrules[j];
|
||||
+ if ((mr->monitor == -1 || mr->monitor == mi)
|
||||
+ && (mr->tag <= 0 || (m->tagset[0] & (1 << (mr->tag - 1))))
|
||||
+ ) {
|
||||
+ layout = MAX(mr->layout, 0);
|
||||
+ layout = MIN(layout, LENGTH(layouts) - 1);
|
||||
+ m->lt[0] = &layouts[layout];
|
||||
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
+ strncpy(m->ltsymbol, layouts[layout].symbol, sizeof m->ltsymbol);
|
||||
+
|
||||
+ if (mr->mfact > -1)
|
||||
+ m->mfact = mr->mfact;
|
||||
+ if (mr->nmaster > -1)
|
||||
+ m->nmaster = mr->nmaster;
|
||||
+ if (mr->showbar > -1)
|
||||
+ m->showbar = mr->showbar;
|
||||
+ if (mr->topbar > -1)
|
||||
+ m->topbar = mr->topbar;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
|
||||
die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
|
||||
m->pertag->curtag = m->pertag->prevtag = 1;
|
||||
- for (i = 0; i <= LENGTH(tags); i++) {
|
||||
- /* init nmaster */
|
||||
- m->pertag->nmasters[i] = m->nmaster;
|
||||
-
|
||||
- /* init mfacts */
|
||||
- m->pertag->mfacts[i] = m->mfact;
|
||||
|
||||
+ for (i = 0; i <= LENGTH(tags); i++) {
|
||||
/* init layouts */
|
||||
- m->pertag->ltidxs[i][0] = m->lt[0];
|
||||
- m->pertag->ltidxs[i][1] = m->lt[1];
|
||||
m->pertag->sellts[i] = m->sellt;
|
||||
|
||||
/* init showbar */
|
||||
@@ -679,6 +704,20 @@ createmon(void)
|
||||
#if ZOOMSWAP_PATCH
|
||||
m->pertag->prevzooms[i] = NULL;
|
||||
#endif // ZOOMSWAP_PATCH
|
||||
+
|
||||
+ for (j = 0; j < LENGTH(monrules); j++) {
|
||||
+ mr = &monrules[j];
|
||||
+ if ((mr->monitor == -1 || mr->monitor == mi) && (mr->tag == -1 || mr->tag == i)) {
|
||||
+ layout = MAX(mr->layout, 0);
|
||||
+ layout = MIN(layout, LENGTH(layouts) - 1);
|
||||
+ m->pertag->ltidxs[i][0] = &layouts[layout];
|
||||
+ m->pertag->ltidxs[i][1] = m->lt[0];
|
||||
+ m->pertag->nmasters[i] = (mr->nmaster > -1 ? mr->nmaster : m->nmaster);
|
||||
+ m->pertag->mfacts[i] = (mr->mfact > -1 ? mr->mfact : m->mfact);
|
||||
+ m->pertag->showbars[i] = (mr->showbar > -1 ? mr->showbar : m->showbar);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
return m;
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,32 @@
|
||||
From 31aef05d160eb20228919461a6e3a03670c09b0a Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:16:52 +0100
|
||||
Subject: [PATCH 2/2] togglelayout - keyboard shortcuts to set a given layout
|
||||
will toggle to the previous layout if the given layout is already active
|
||||
|
||||
---
|
||||
dwm.c | 8 +++-----
|
||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index b8ae4a5..c4b3166 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1542,11 +1542,9 @@ setfullscreen(Client *c, int fullscreen)
|
||||
void
|
||||
setlayout(const Arg *arg)
|
||||
{
|
||||
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
- selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
- selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
- }
|
||||
- if (arg && arg->v)
|
||||
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ if (arg && arg->v && arg->v != selmon->lt[selmon->sellt ^ 1])
|
||||
selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
||||
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,240 @@
|
||||
From 8323f1e2e1e71223aa516f66415611fe4dd1f2ed Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:02:01 +0100
|
||||
Subject: [PATCH 1/2] pertag patch, keeps layout, mwfact, barpos and nmaster
|
||||
per tag
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/pertag/
|
||||
---
|
||||
dwm.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 90 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..b8ae4a5 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -111,6 +111,7 @@ typedef struct {
|
||||
void (*arrange)(Monitor *);
|
||||
} Layout;
|
||||
|
||||
+typedef struct Pertag Pertag;
|
||||
struct Monitor {
|
||||
char ltsymbol[16];
|
||||
float mfact;
|
||||
@@ -130,6 +131,7 @@ struct Monitor {
|
||||
Monitor *next;
|
||||
Window barwin;
|
||||
const Layout *lt[2];
|
||||
+ Pertag *pertag;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -272,6 +274,18 @@ static Window root, wmcheckwin;
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
|
||||
+struct Pertag {
|
||||
+ unsigned int curtag, prevtag; /* current and previous tag */
|
||||
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
|
||||
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
|
||||
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
|
||||
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
|
||||
+ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
|
||||
+ #if ZOOMSWAP_PATCH
|
||||
+ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
|
||||
+ #endif // ZOOMSWAP_PATCH
|
||||
+};
|
||||
+
|
||||
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||
|
||||
@@ -507,6 +521,7 @@ cleanupmon(Monitor *mon)
|
||||
}
|
||||
XUnmapWindow(dpy, mon->barwin);
|
||||
XDestroyWindow(dpy, mon->barwin);
|
||||
+ free(mon->pertag);
|
||||
free(mon);
|
||||
}
|
||||
|
||||
@@ -632,6 +647,7 @@ Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
Monitor *m;
|
||||
+ int i;
|
||||
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
@@ -642,6 +658,28 @@ createmon(void)
|
||||
m->lt[0] = &layouts[0];
|
||||
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||
+ if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
|
||||
+ m->pertag->curtag = m->pertag->prevtag = 1;
|
||||
+ for (i = 0; i <= LENGTH(tags); i++) {
|
||||
+ /* init nmaster */
|
||||
+ m->pertag->nmasters[i] = m->nmaster;
|
||||
+
|
||||
+ /* init mfacts */
|
||||
+ m->pertag->mfacts[i] = m->mfact;
|
||||
+
|
||||
+ /* init layouts */
|
||||
+ m->pertag->ltidxs[i][0] = m->lt[0];
|
||||
+ m->pertag->ltidxs[i][1] = m->lt[1];
|
||||
+ m->pertag->sellts[i] = m->sellt;
|
||||
+
|
||||
+ /* init showbar */
|
||||
+ m->pertag->showbars[i] = m->showbar;
|
||||
+
|
||||
+ #if ZOOMSWAP_PATCH
|
||||
+ m->pertag->prevzooms[i] = NULL;
|
||||
+ #endif // ZOOMSWAP_PATCH
|
||||
+ }
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -970,7 +1008,7 @@ grabkeys(void)
|
||||
void
|
||||
incnmaster(const Arg *arg)
|
||||
{
|
||||
- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1504,10 +1542,13 @@ setfullscreen(Client *c, int fullscreen)
|
||||
void
|
||||
setlayout(const Arg *arg)
|
||||
{
|
||||
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
|
||||
- selmon->sellt ^= 1;
|
||||
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ }
|
||||
if (arg && arg->v)
|
||||
- selmon->lt[selmon->sellt] = (Layout *)arg->v;
|
||||
+ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
||||
if (selmon->sel)
|
||||
arrange(selmon);
|
||||
@@ -1526,7 +1567,7 @@ setmfact(const Arg *arg)
|
||||
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
|
||||
if (f < 0.05 || f > 0.95)
|
||||
return;
|
||||
- selmon->mfact = f;
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
@@ -1705,7 +1746,7 @@ tile(Monitor *m)
|
||||
void
|
||||
togglebar(const Arg *arg)
|
||||
{
|
||||
- selmon->showbar = !selmon->showbar;
|
||||
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
|
||||
updatebarpos(selmon);
|
||||
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||
arrange(selmon);
|
||||
@@ -1744,9 +1785,29 @@ void
|
||||
toggleview(const Arg *arg)
|
||||
{
|
||||
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
||||
+ int i;
|
||||
|
||||
if (newtagset) {
|
||||
+ if (newtagset == ~0) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ selmon->pertag->curtag = 0;
|
||||
+ }
|
||||
+ /* test if the user did not select the same tag */
|
||||
+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ for (i=0; !(newtagset & 1 << i); i++) ;
|
||||
+ selmon->pertag->curtag = i + 1;
|
||||
+ }
|
||||
selmon->tagset[selmon->seltags] = newtagset;
|
||||
+
|
||||
+ /* apply settings for this view */
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||
+ togglebar(NULL);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
@@ -2041,11 +2102,33 @@ updatewmhints(Client *c)
|
||||
void
|
||||
view(const Arg *arg)
|
||||
{
|
||||
+ int i;
|
||||
+ unsigned int tmptag;
|
||||
+
|
||||
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
selmon->seltags ^= 1; /* toggle sel tagset */
|
||||
- if (arg->ui & TAGMASK)
|
||||
+ if (arg->ui & TAGMASK) {
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
||||
+ if (arg->ui == ~0)
|
||||
+ selmon->pertag->curtag = 0;
|
||||
+ else {
|
||||
+ for (i=0; !(arg->ui & 1 << i); i++) ;
|
||||
+ selmon->pertag->curtag = i + 1;
|
||||
+ }
|
||||
+ } else {
|
||||
+ tmptag = selmon->pertag->prevtag;
|
||||
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||
+ selmon->pertag->curtag = tmptag;
|
||||
+ }
|
||||
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||
+ togglebar(NULL);
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 31aef05d160eb20228919461a6e3a03670c09b0a Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:16:52 +0100
|
||||
Subject: [PATCH 2/2] togglelayout - keyboard shortcuts to set a given layout
|
||||
will toggle to the previous layout if the given layout is already active
|
||||
|
||||
---
|
||||
dwm.c | 8 +++-----
|
||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index b8ae4a5..c4b3166 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1542,11 +1542,9 @@ setfullscreen(Client *c, int fullscreen)
|
||||
void
|
||||
setlayout(const Arg *arg)
|
||||
{
|
||||
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
- selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
- selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
- }
|
||||
- if (arg && arg->v)
|
||||
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||
+ if (arg && arg->v && arg->v != selmon->lt[selmon->sellt ^ 1])
|
||||
selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
||||
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,145 @@
|
||||
From 1d5bbf1fc8627507e62498a9335bd2bc9ed01896 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:17:56 +0100
|
||||
Subject: [PATCH] Adding placedir, moving clients around with behaviour similar
|
||||
to that of focusdir
|
||||
|
||||
---
|
||||
config.def.h | 4 +++
|
||||
dwm.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 102 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..e8719d3 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -67,6 +67,10 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
+ { MODKEY|ControlMask, XK_Left, placedir, {.i = 0 } }, // left
|
||||
+ { MODKEY|ControlMask, XK_Right, placedir, {.i = 1 } }, // right
|
||||
+ { MODKEY|ControlMask, XK_Up, placedir, {.i = 2 } }, // up
|
||||
+ { MODKEY|ControlMask, XK_Down, placedir, {.i = 3 } }, // down
|
||||
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..7a20672 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -185,6 +185,7 @@ static void monocle(Monitor *m);
|
||||
static void motionnotify(XEvent *e);
|
||||
static void movemouse(const Arg *arg);
|
||||
static Client *nexttiled(Client *c);
|
||||
+static void placedir(const Arg *arg);
|
||||
static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
@@ -1203,6 +1204,103 @@ nexttiled(Client *c)
|
||||
return c;
|
||||
}
|
||||
|
||||
+void
|
||||
+placedir(const Arg *arg)
|
||||
+{
|
||||
+ Client *s = selmon->sel, *f = NULL, *c, *next, *fprior, *sprior;
|
||||
+
|
||||
+ if (!s || s->isfloating)
|
||||
+ return;
|
||||
+
|
||||
+ unsigned int score = -1;
|
||||
+ unsigned int client_score;
|
||||
+ int dist;
|
||||
+ int dirweight = 20;
|
||||
+
|
||||
+ next = s->next;
|
||||
+ if (!next)
|
||||
+ next = s->mon->clients;
|
||||
+ for (c = next; c != s; c = next) {
|
||||
+
|
||||
+ next = c->next;
|
||||
+ if (!next)
|
||||
+ next = s->mon->clients;
|
||||
+
|
||||
+ if (!ISVISIBLE(c)) // || HIDDEN(c)
|
||||
+ continue;
|
||||
+
|
||||
+ switch (arg->i) {
|
||||
+ case 0: // left
|
||||
+ dist = s->x - c->x - c->w;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
+ abs(s->y - c->y);
|
||||
+ break;
|
||||
+ case 1: // right
|
||||
+ dist = c->x - s->x - s->w;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
+ abs(c->y - s->y);
|
||||
+ break;
|
||||
+ case 2: // up
|
||||
+ dist = s->y - c->y - c->h;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
+ abs(s->x - c->x);
|
||||
+ break;
|
||||
+ default:
|
||||
+ case 3: // down
|
||||
+ dist = c->y - s->y - s->h;
|
||||
+ client_score =
|
||||
+ dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
+ abs(c->x - s->x);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) {
|
||||
+ score = client_score;
|
||||
+ f = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (f && f != s) {
|
||||
+ for (fprior = f->mon->clients; fprior && fprior->next != f; fprior = fprior->next);
|
||||
+ for (sprior = s->mon->clients; sprior && sprior->next != s; sprior = sprior->next);
|
||||
+
|
||||
+ if (s == fprior) {
|
||||
+ next = f->next;
|
||||
+ if (sprior)
|
||||
+ sprior->next = f;
|
||||
+ else
|
||||
+ f->mon->clients = f;
|
||||
+ f->next = s;
|
||||
+ s->next = next;
|
||||
+ } else if (f == sprior) {
|
||||
+ next = s->next;
|
||||
+ if (fprior)
|
||||
+ fprior->next = s;
|
||||
+ else
|
||||
+ s->mon->clients = s;
|
||||
+ s->next = f;
|
||||
+ f->next = next;
|
||||
+ } else { // clients are not adjacent to each other
|
||||
+ next = f->next;
|
||||
+ f->next = s->next;
|
||||
+ s->next = next;
|
||||
+ if (fprior)
|
||||
+ fprior->next = s;
|
||||
+ else
|
||||
+ s->mon->clients = s;
|
||||
+ if (sprior)
|
||||
+ sprior->next = f;
|
||||
+ else
|
||||
+ f->mon->clients = f;
|
||||
+ }
|
||||
+
|
||||
+ arrange(f->mon);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
pop(Client *c)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,259 @@
|
||||
From 399cb51f86d259d0d15d2db767d31c9e030c0528 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:18:37 +0100
|
||||
Subject: [PATCH] Adding placemouse patch
|
||||
|
||||
---
|
||||
config.def.h | 12 +++-
|
||||
dwm.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 177 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..caaebf6 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -105,7 +105,17 @@ static Button buttons[] = {
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
- { ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
+ /* placemouse options, choose which feels more natural:
|
||||
+ * 0 - tiled position is relative to mouse cursor
|
||||
+ * 1 - tiled postiion is relative to window center
|
||||
+ * 2 - mouse pointer warps to window center
|
||||
+ *
|
||||
+ * The moveorplace uses movemouse or placemouse depending on the floating state
|
||||
+ * of the selected client. Set up individual keybindings for the two if you want
|
||||
+ * to control these separately (i.e. to retain the feature to move a tiled window
|
||||
+ * into a floating position).
|
||||
+ */
|
||||
+ { ClkClientWin, MODKEY, Button1, moveorplace, {.i = 1} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
{ ClkTagBar, 0, Button1, view, {0} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..5d57e18 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -49,6 +49,8 @@
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#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 INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \
|
||||
+ * MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y)))
|
||||
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
@@ -93,6 +95,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int beingmoved;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -184,10 +187,13 @@ static void maprequest(XEvent *e);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionnotify(XEvent *e);
|
||||
static void movemouse(const Arg *arg);
|
||||
+static void moveorplace(const Arg *arg);
|
||||
static Client *nexttiled(Client *c);
|
||||
+static void placemouse(const Arg *arg);
|
||||
static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
+static Client *recttoclient(int x, int y, int w, int h);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
@@ -1136,6 +1142,14 @@ motionnotify(XEvent *e)
|
||||
mon = m;
|
||||
}
|
||||
|
||||
+void
|
||||
+moveorplace(const Arg *arg) {
|
||||
+ if ((!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)))
|
||||
+ movemouse(arg);
|
||||
+ else
|
||||
+ placemouse(arg);
|
||||
+}
|
||||
+
|
||||
void
|
||||
movemouse(const Arg *arg)
|
||||
{
|
||||
@@ -1203,6 +1217,139 @@ nexttiled(Client *c)
|
||||
return c;
|
||||
}
|
||||
|
||||
+void
|
||||
+placemouse(const Arg *arg)
|
||||
+{
|
||||
+ int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0;
|
||||
+ Client *c, *r = NULL, *at, *prevr;
|
||||
+ Monitor *m;
|
||||
+ XEvent ev;
|
||||
+ XWindowAttributes wa;
|
||||
+ Time lasttime = 0;
|
||||
+ int attachmode, prevattachmode;
|
||||
+ attachmode = prevattachmode = -1;
|
||||
+
|
||||
+ if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */
|
||||
+ return;
|
||||
+ if (c->isfullscreen) /* no support placing fullscreen windows by mouse */
|
||||
+ return;
|
||||
+ restack(selmon);
|
||||
+ prevr = c;
|
||||
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
|
||||
+ return;
|
||||
+
|
||||
+ c->isfloating = 0;
|
||||
+ c->beingmoved = 1;
|
||||
+
|
||||
+ XGetWindowAttributes(dpy, c->win, &wa);
|
||||
+ ocx = wa.x;
|
||||
+ ocy = wa.y;
|
||||
+
|
||||
+ if (arg->i == 2) // warp cursor to client center
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2);
|
||||
+
|
||||
+ if (!getrootptr(&x, &y))
|
||||
+ return;
|
||||
+
|
||||
+ do {
|
||||
+ XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
+ switch (ev.type) {
|
||||
+ case ConfigureRequest:
|
||||
+ case Expose:
|
||||
+ case MapRequest:
|
||||
+ handler[ev.type](&ev);
|
||||
+ break;
|
||||
+ case MotionNotify:
|
||||
+ if ((ev.xmotion.time - lasttime) <= (1000 / 60))
|
||||
+ continue;
|
||||
+ lasttime = ev.xmotion.time;
|
||||
+
|
||||
+ nx = ocx + (ev.xmotion.x - x);
|
||||
+ ny = ocy + (ev.xmotion.y - y);
|
||||
+
|
||||
+ if (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap))
|
||||
+ freemove = 1;
|
||||
+
|
||||
+ if (freemove)
|
||||
+ XMoveWindow(dpy, c->win, nx, ny);
|
||||
+
|
||||
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon)
|
||||
+ selmon = m;
|
||||
+
|
||||
+ if (arg->i == 1) { // tiled position is relative to the client window center point
|
||||
+ px = nx + wa.width / 2;
|
||||
+ py = ny + wa.height / 2;
|
||||
+ } else { // tiled position is relative to the mouse cursor
|
||||
+ px = ev.xmotion.x;
|
||||
+ py = ev.xmotion.y;
|
||||
+ }
|
||||
+
|
||||
+ r = recttoclient(px, py, 1, 1);
|
||||
+
|
||||
+ if (!r || r == c)
|
||||
+ break;
|
||||
+
|
||||
+ attachmode = 0; // below
|
||||
+ if (((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w)) {
|
||||
+ if (abs(r->y - py) < r->h / 2)
|
||||
+ attachmode = 1; // above
|
||||
+ } else if (abs(r->x - px) < r->w / 2)
|
||||
+ attachmode = 1; // above
|
||||
+
|
||||
+ if ((r && r != prevr) || (attachmode != prevattachmode)) {
|
||||
+ detachstack(c);
|
||||
+ detach(c);
|
||||
+ if (c->mon != r->mon) {
|
||||
+ arrangemon(c->mon);
|
||||
+ c->tags = r->mon->tagset[r->mon->seltags];
|
||||
+ }
|
||||
+
|
||||
+ c->mon = r->mon;
|
||||
+ r->mon->sel = r;
|
||||
+
|
||||
+ if (attachmode) {
|
||||
+ if (r == r->mon->clients)
|
||||
+ attach(c);
|
||||
+ else {
|
||||
+ for (at = r->mon->clients; at->next != r; at = at->next);
|
||||
+ c->next = at->next;
|
||||
+ at->next = c;
|
||||
+ }
|
||||
+ } else {
|
||||
+ c->next = r->next;
|
||||
+ r->next = c;
|
||||
+ }
|
||||
+
|
||||
+ attachstack(c);
|
||||
+ arrangemon(r->mon);
|
||||
+ prevr = r;
|
||||
+ prevattachmode = attachmode;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (ev.type != ButtonRelease);
|
||||
+ XUngrabPointer(dpy, CurrentTime);
|
||||
+
|
||||
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ arrangemon(c->mon);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ selmon = m;
|
||||
+ }
|
||||
+
|
||||
+ focus(c);
|
||||
+ c->beingmoved = 0;
|
||||
+
|
||||
+ if (nx != -9999)
|
||||
+ resize(c, nx, ny, c->w, c->h, 0);
|
||||
+ arrangemon(c->mon);
|
||||
+}
|
||||
+
|
||||
void
|
||||
pop(Client *c)
|
||||
{
|
||||
@@ -1255,6 +1402,21 @@ quit(const Arg *arg)
|
||||
running = 0;
|
||||
}
|
||||
|
||||
+Client *
|
||||
+recttoclient(int x, int y, int w, int h)
|
||||
+{
|
||||
+ Client *c, *r = NULL;
|
||||
+ int a, area = 0;
|
||||
+
|
||||
+ for (c = nexttiled(selmon->clients); c; c = nexttiled(c->next)) {
|
||||
+ if ((a = INTERSECTC(x, y, w, h, c)) > area) {
|
||||
+ area = a;
|
||||
+ r = c;
|
||||
+ }
|
||||
+ }
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
Monitor *
|
||||
recttomon(int x, int y, int w, int h)
|
||||
{
|
||||
@@ -1285,6 +1447,10 @@ resizeclient(Client *c, int x, int y, int w, int h)
|
||||
c->oldy = c->y; c->y = wc.y = y;
|
||||
c->oldw = c->w; c->w = wc.width = w;
|
||||
c->oldh = c->h; c->h = wc.height = h;
|
||||
+
|
||||
+ if (c->beingmoved)
|
||||
+ return;
|
||||
+
|
||||
wc.border_width = c->bw;
|
||||
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
|
||||
configure(c);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,377 @@
|
||||
From 2240bee664499ab165a662d0c98a6dbd594de6af Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:22:32 +0100
|
||||
Subject: [PATCH] Powerline patch - adds arrows for tags and status
|
||||
|
||||
https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40
|
||||
---
|
||||
config.def.h | 16 +++++--
|
||||
drw.c | 51 +++++++++++++++++++--
|
||||
drw.h | 2 +
|
||||
dwm.c | 126 +++++++++++++++++++++++++++++++++++++++------------
|
||||
4 files changed, 159 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..d16d4b4 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -13,9 +13,19 @@ static const char col_gray3[] = "#bbbbbb";
|
||||
static const char col_gray4[] = "#eeeeee";
|
||||
static const char col_cyan[] = "#005577";
|
||||
static const char *colors[][3] = {
|
||||
- /* fg bg border */
|
||||
- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
- [SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ /* fg bg border */
|
||||
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeTitle] = { "#554433", "#FF4444", "#44FF44" },
|
||||
+ [SchemeTitleSel] = { "#4444FF", "#884400", "#440044" },
|
||||
+};
|
||||
+
|
||||
+static const char *statuscolors[][3] = {
|
||||
+ /* fg bg border */
|
||||
+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
+ [SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeTitle] = { "#554433", "#FF4444", "#44FF44" },
|
||||
+ [SchemeTitleSel] = { "#4444FF", "#884400", "#440044" },
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
diff --git a/drw.c b/drw.c
|
||||
index 4cdbcbe..6d676b1 100644
|
||||
--- a/drw.c
|
||||
+++ b/drw.c
|
||||
@@ -15,6 +15,7 @@ static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}
|
||||
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||
+Clr transcheme[3];
|
||||
|
||||
static long
|
||||
utf8decodebyte(const char c, size_t *i)
|
||||
@@ -200,8 +201,8 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||
return;
|
||||
|
||||
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||
- DefaultColormap(drw->dpy, drw->screen),
|
||||
- clrname, dest))
|
||||
+ DefaultColormap(drw->dpy, drw->screen),
|
||||
+ clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
}
|
||||
|
||||
@@ -236,6 +237,15 @@ drw_setscheme(Drw *drw, Clr *scm)
|
||||
drw->scheme = scm;
|
||||
}
|
||||
|
||||
+void
|
||||
+drw_settrans(Drw *drw, Clr *psc, Clr *nsc)
|
||||
+{
|
||||
+ if (drw) {
|
||||
+ transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder];
|
||||
+ drw->scheme = transcheme;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
|
||||
{
|
||||
@@ -275,8 +285,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||
d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||
- DefaultVisual(drw->dpy, drw->screen),
|
||||
- DefaultColormap(drw->dpy, drw->screen));
|
||||
+ DefaultVisual(drw->dpy, drw->screen),
|
||||
+ DefaultColormap(drw->dpy, drw->screen));
|
||||
x += lpad;
|
||||
w -= lpad;
|
||||
}
|
||||
@@ -323,7 +333,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
if (render) {
|
||||
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||
- usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
||||
+ usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
||||
}
|
||||
x += ew;
|
||||
w -= ew;
|
||||
@@ -379,6 +389,37 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
return x + (render ? w : 0);
|
||||
}
|
||||
|
||||
+void
|
||||
+drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash)
|
||||
+{
|
||||
+ if (!drw || !drw->scheme)
|
||||
+ return;
|
||||
+
|
||||
+ /* direction=1 draws right arrow */
|
||||
+ x = direction ? x : x + w;
|
||||
+ w = direction ? w : -w;
|
||||
+ /* slash=1 draws slash instead of arrow */
|
||||
+ unsigned int hh = slash ? (direction ? 0 : h) : h/2;
|
||||
+
|
||||
+ XPoint points[] = {
|
||||
+ {x , y },
|
||||
+ {x + w, y + hh },
|
||||
+ {x , y + h },
|
||||
+ };
|
||||
+
|
||||
+ XPoint bg[] = {
|
||||
+ {x , y },
|
||||
+ {x + w, y },
|
||||
+ {x + w, y + h},
|
||||
+ {x , y + h},
|
||||
+ };
|
||||
+
|
||||
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
|
||||
+ XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin);
|
||||
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel);
|
||||
+ XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin);
|
||||
+}
|
||||
+
|
||||
void
|
||||
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||
{
|
||||
diff --git a/drw.h b/drw.h
|
||||
index 4bcd5ad..fc4f3bb 100644
|
||||
--- a/drw.h
|
||||
+++ b/drw.h
|
||||
@@ -48,10 +48,12 @@ void drw_cur_free(Drw *drw, Cur *cursor);
|
||||
/* Drawing context manipulation */
|
||||
void drw_setfontset(Drw *drw, Fnt *set);
|
||||
void drw_setscheme(Drw *drw, Clr *scm);
|
||||
+void drw_settrans(Drw *drw, Clr *psc, Clr *nsc);
|
||||
|
||||
/* Drawing functions */
|
||||
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
|
||||
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
|
||||
+void drw_arrow(Drw* drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash);
|
||||
|
||||
/* Map functions */
|
||||
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..ad9c174 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -48,7 +48,7 @@
|
||||
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#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)))
|
||||
+ * 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 LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
@@ -59,13 +59,13 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
-enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeTitle, SchemeTitleSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
- ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
@@ -162,6 +162,7 @@ static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
static void drawbar(Monitor *m);
|
||||
+static int drawstatus(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
static void expose(XEvent *e);
|
||||
@@ -240,7 +241,7 @@ static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
-static int bh, blw = 0; /* bar geometry */
|
||||
+static int bh, plw, blw = 0; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
@@ -264,6 +265,7 @@ static Atom wmatom[WMLast], netatom[NetLast];
|
||||
static int running = 1;
|
||||
static Cur *cursor[CurLast];
|
||||
static Clr **scheme;
|
||||
+static Clr **statusscheme;
|
||||
static Display *dpy;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
@@ -431,9 +433,9 @@ buttonpress(XEvent *e)
|
||||
focus(NULL);
|
||||
}
|
||||
if (ev->window == selmon->barwin) {
|
||||
- i = x = 0;
|
||||
+ i = 0; x = plw;
|
||||
do
|
||||
- x += TEXTW(tags[i]);
|
||||
+ x += TEXTW(tags[i]) + plw;
|
||||
while (ev->x >= x && ++i < LENGTH(tags));
|
||||
if (i < LENGTH(tags)) {
|
||||
click = ClkTagBar;
|
||||
@@ -696,11 +698,11 @@ dirtomon(int dir)
|
||||
void
|
||||
drawbar(Monitor *m)
|
||||
{
|
||||
- int x, w, tw = 0;
|
||||
- int boxs = drw->fonts->h / 9;
|
||||
- int boxw = drw->fonts->h / 6 + 2;
|
||||
- unsigned int i, occ = 0, urg = 0;
|
||||
+ int x, w, wt, tw = 0;
|
||||
+ unsigned int i, occ = 0, urg = 0, n = 0;
|
||||
+ plw = drw->fonts->h / 2 + 1;
|
||||
Client *c;
|
||||
+ Clr *prevscheme, *nxtscheme;
|
||||
|
||||
if (!m->showbar)
|
||||
return;
|
||||
@@ -708,44 +710,109 @@ drawbar(Monitor *m)
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
+ tw = drawstatus(m);
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
+ if (ISVISIBLE(c)) n++;
|
||||
occ |= c->tags;
|
||||
if (c->isurgent)
|
||||
urg |= c->tags;
|
||||
}
|
||||
x = 0;
|
||||
+
|
||||
+ prevscheme = scheme[SchemeNorm];
|
||||
for (i = 0; i < LENGTH(tags); i++) {
|
||||
w = TEXTW(tags[i]);
|
||||
- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||
+ drw_settrans(drw, prevscheme, (nxtscheme = scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]));
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 1, 0);
|
||||
+ x += plw;
|
||||
+
|
||||
+ drw_setscheme(drw, nxtscheme);
|
||||
drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
|
||||
- if (occ & 1 << i)
|
||||
- drw_rect(drw, x + boxs, boxs, boxw, boxw,
|
||||
- m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
|
||||
- urg & 1 << i);
|
||||
x += w;
|
||||
+
|
||||
+ prevscheme = nxtscheme;
|
||||
+
|
||||
}
|
||||
+ nxtscheme = scheme[SchemeNorm];
|
||||
+
|
||||
+ drw_settrans(drw, prevscheme, nxtscheme);
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 1, 0);
|
||||
+ x += plw;
|
||||
+
|
||||
w = blw = TEXTW(m->ltsymbol);
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
||||
|
||||
- if ((w = m->ww - tw - x) > bh) {
|
||||
- if (m->sel) {
|
||||
- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
||||
- 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 {
|
||||
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- drw_rect(drw, x, 0, w, bh, 1, 1);
|
||||
+ if ((m->ww - tw - x) > bh && n > 0) {
|
||||
+ wt = (m->ww - tw - x) / n - 2 * plw;
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (!ISVISIBLE(c)) continue; /* only show titles of windows on current tag */
|
||||
+ drw_setscheme(drw, c == m->sel ? scheme[SchemeTitleSel] : scheme[SchemeTitle]);
|
||||
+ drw_text(drw, x + plw, 0, wt, bh, lrpad / 2, c->name, 0);
|
||||
+
|
||||
+ drw_settrans(drw, c == m->sel ? scheme[SchemeTitleSel] : scheme[SchemeTitle], scheme[SchemeNorm]);
|
||||
+ drw_arrow(drw, x, 0, plw, bh, 0, 1);
|
||||
+ drw_arrow(drw, x + wt + plw, 0, plw, bh, 1, 1);
|
||||
+
|
||||
+ x += wt + 2 * plw;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if (x < m->ww - sw) { /* when empty or not enough space to draw, clear out the title space */
|
||||
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
+ drw_rect(drw, x, 0, m->ww - sw - x, bh, 1, 1);
|
||||
+ }
|
||||
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
|
||||
}
|
||||
|
||||
+int
|
||||
+drawstatus(Monitor* m)
|
||||
+{
|
||||
+ char status[256];
|
||||
+ int i, n = strlen(stext), cn = 0;
|
||||
+ int x = m->ww, w = 0;
|
||||
+ char *bs, bp = '|';
|
||||
+ Clr *prevscheme = statusscheme[0], *nxtscheme;
|
||||
+
|
||||
+ strcpy(status, stext);
|
||||
+
|
||||
+ for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) {
|
||||
+ if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '|') { /* block start */
|
||||
+ cn = ((int) *(bs+1)) - 1;
|
||||
+
|
||||
+ if (cn < LENGTH(statuscolors)) {
|
||||
+ drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[cn]));
|
||||
+ } else {
|
||||
+ drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[0]));
|
||||
+ }
|
||||
+
|
||||
+ if (bp != '|') {
|
||||
+ drw_arrow(drw, x - plw, 0, plw, bh, bp == '\\' ? 1 : 0, bp == '<' ? 0 : 1);
|
||||
+ x -= plw;
|
||||
+ }
|
||||
+
|
||||
+ drw_setscheme(drw, nxtscheme);
|
||||
+ w = TEXTW(bs+2);
|
||||
+ drw_text(drw, x - w, 0, w, bh, lrpad / 2, bs+2, 0);
|
||||
+ x -= w;
|
||||
+
|
||||
+ bp = *bs;
|
||||
+ *bs = 0;
|
||||
+ prevscheme = nxtscheme;
|
||||
+ }
|
||||
+ }
|
||||
+ if (bp != '|') {
|
||||
+ drw_settrans(drw, prevscheme, scheme[SchemeNorm]);
|
||||
+ drw_arrow(drw, x - plw, 0, plw, bh, bp == '\\' ? 1 : 0, bp == '<' ? 0 : 1);
|
||||
+ drw_rect(drw, x - 2 * plw, 0, plw, bh, 1, 1);
|
||||
+ x -= plw * 2;
|
||||
+ }
|
||||
+
|
||||
+ return m->ww - x;
|
||||
+}
|
||||
+
|
||||
void
|
||||
drawbars(void)
|
||||
{
|
||||
@@ -1574,6 +1641,9 @@ setup(void)
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||
+ statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *));
|
||||
+ for (i = 0; i < LENGTH(statuscolors); i++)
|
||||
+ statusscheme[i] = drw_scm_create(drw, statuscolors[i], 3);
|
||||
/* init bars */
|
||||
updatebars();
|
||||
updatestatus();
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,357 @@
|
||||
From 07804818ec69a86887533f47f4393f040de5a447 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:23:00 +0100
|
||||
Subject: [PATCH] Named scratchpad variant
|
||||
|
||||
---
|
||||
config.def.h | 17 ++++-
|
||||
dwm.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 186 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..049b29f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -12,10 +12,14 @@ static const char col_gray2[] = "#444444";
|
||||
static const char col_gray3[] = "#bbbbbb";
|
||||
static const char col_gray4[] = "#eeeeee";
|
||||
static const char col_cyan[] = "#005577";
|
||||
+static const char col_red[] = "#FF0000";
|
||||
+static const char col_orange[] = "#FF8800";
|
||||
static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeScratchSel] = { col_gray4, col_cyan, col_red },
|
||||
+ [SchemeScratchNorm] = { col_gray4, col_cyan, col_orange },
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
@@ -26,9 +30,10 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating monitor scratch key */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, -1, 0 },
|
||||
+ { "firefox", NULL, NULL, 1 << 8, 0, -1, 0 },
|
||||
+ { NULL, NULL, "scratchpad", 0, 1, -1, 's' },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -60,10 +65,16 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
|
||||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
+/*First arg only serves to match against key in rules*/
|
||||
+static const char *scratchpadcmd[] = {"s", "st", "-t", "scratchpad", NULL};
|
||||
+
|
||||
static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_g, togglescratch, {.v = scratchpadcmd } },
|
||||
+ { MODKEY|ShiftMask, XK_g, removescratch, {.v = scratchpadcmd } },
|
||||
+ { MODKEY|ControlMask, XK_g, setscratch, {.v = scratchpadcmd } },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..c58c6ed 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
-enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeScratchNorm, SchemeScratchSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ char scratchkey;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -139,6 +140,7 @@ typedef struct {
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ const char scratchkey;
|
||||
} Rule;
|
||||
|
||||
/* function declarations */
|
||||
@@ -189,6 +191,7 @@ static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
+static void removescratch(const Arg *arg);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
@@ -202,16 +205,19 @@ static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
+static void setscratch(const Arg *arg);
|
||||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static void spawnscratch(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglescratch(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -288,6 +294,7 @@ applyrules(Client *c)
|
||||
/* rule matching */
|
||||
c->isfloating = 0;
|
||||
c->tags = 0;
|
||||
+ c->scratchkey = 0;
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
class = ch.res_class ? ch.res_class : broken;
|
||||
instance = ch.res_name ? ch.res_name : broken;
|
||||
@@ -300,6 +307,7 @@ applyrules(Client *c)
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
+ c->scratchkey = r->scratchkey;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
@@ -309,6 +317,7 @@ applyrules(Client *c)
|
||||
XFree(ch.res_class);
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
+
|
||||
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
|
||||
}
|
||||
|
||||
@@ -799,7 +808,10 @@ focus(Client *c)
|
||||
detachstack(c);
|
||||
attachstack(c);
|
||||
grabbuttons(c, 1);
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
+ if (c->scratchkey != 0)
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel);
|
||||
+ else
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
setfocus(c);
|
||||
} else {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
@@ -1269,6 +1281,15 @@ recttomon(int x, int y, int w, int h)
|
||||
return r;
|
||||
}
|
||||
|
||||
+void
|
||||
+removescratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ c->scratchkey = 0;
|
||||
+}
|
||||
+
|
||||
void
|
||||
resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
{
|
||||
@@ -1530,6 +1551,16 @@ setmfact(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+setscratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ c->scratchkey = ((char**)arg->v)[0][0];
|
||||
+}
|
||||
+
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
@@ -1626,6 +1657,9 @@ showhide(Client *c)
|
||||
resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
showhide(c->snext);
|
||||
} else {
|
||||
+ /* optional: auto-hide scratchpads when moving to other tags */
|
||||
+ if (c->scratchkey != 0 && !(c->tags & c->mon->tagset[c->mon->seltags]))
|
||||
+ c->tags = 0;
|
||||
/* hide clients bottom up */
|
||||
showhide(c->snext);
|
||||
XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
|
||||
@@ -1656,6 +1690,19 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void spawnscratch(const Arg *arg)
|
||||
+{
|
||||
+ if (fork() == 0) {
|
||||
+ if (dpy)
|
||||
+ close(ConnectionNumber(dpy));
|
||||
+ setsid();
|
||||
+ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
|
||||
+ fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[1]);
|
||||
+ perror(" failed");
|
||||
+ exit(EXIT_SUCCESS);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@@ -1725,6 +1772,125 @@ togglefloating(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglescratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
|
||||
+ Monitor *mon;
|
||||
+ int scratchvisible = 0; // whether the scratchpads are currently visible or not
|
||||
+ int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
|
||||
+ int scratchmon = -1; // the monitor where the scratchpads exist
|
||||
+ int numscratchpads = 0; // count of scratchpads
|
||||
+
|
||||
+ /* Looping through monitors and client's twice, the first time to work out whether we need
|
||||
+ to move clients across from one monitor to another or not */
|
||||
+ for (mon = mons; mon; mon = mon->next)
|
||||
+ for (c = mon->clients; c; c = c->next) {
|
||||
+ if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
+ continue;
|
||||
+ if (scratchmon != -1 && scratchmon != mon->num)
|
||||
+ multimonscratch = 1;
|
||||
+ if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
|
||||
+ ++scratchvisible;
|
||||
+ scratchmon = mon->num;
|
||||
+ ++numscratchpads;
|
||||
+ }
|
||||
+
|
||||
+ /* Now for the real deal. The logic should go like:
|
||||
+ - hidden scratchpads will be shown
|
||||
+ - shown scratchpads will be hidden, unless they are being moved to the current monitor
|
||||
+ - the scratchpads will be moved to the current monitor if they all reside on the same monitor
|
||||
+ - multiple scratchpads residing on separate monitors will be left in place
|
||||
+ */
|
||||
+ for (mon = mons; mon; mon = mon->next) {
|
||||
+ for (c = mon->stack; c; c = next) {
|
||||
+ next = c->snext;
|
||||
+ if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
+ continue;
|
||||
+
|
||||
+ /* awesomebar / wintitleactions compatibility, unhide scratchpad if hidden
|
||||
+ if (HIDDEN(c)) {
|
||||
+ XMapWindow(dpy, c->win);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ }
|
||||
+ */
|
||||
+
|
||||
+ /* Record the first found scratchpad client for focus purposes, but prioritise the
|
||||
+ scratchpad on the current monitor if one exists */
|
||||
+ if (!found || (mon == selmon && found->mon != selmon))
|
||||
+ found = c;
|
||||
+
|
||||
+ /* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
+ as we are looping through monitors we could be moving a client to a monitor that has
|
||||
+ not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
+ this we detach them and add them to a temporary list (monclients) which is to be
|
||||
+ processed later. */
|
||||
+ if (!multimonscratch && c->mon != selmon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = NULL;
|
||||
+ /* Note that we are adding clients at the end of the list, this is to preserve the
|
||||
+ order of clients as they were on the adjacent monitor (relevant when tiled) */
|
||||
+ if (last)
|
||||
+ last = last->next = c;
|
||||
+ else
|
||||
+ last = monclients = c;
|
||||
+ } else if (scratchvisible == numscratchpads) {
|
||||
+ c->tags = 0;
|
||||
+ } else {
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
+ c->tags = c->mon->tagset[c->mon->seltags];
|
||||
+ if (c->isfloating)
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Attach moved scratchpad clients on the selected monitor */
|
||||
+ for (c = monclients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ mon = c->mon;
|
||||
+ c->mon = selmon;
|
||||
+ c->tags = selmon->tagset[selmon->seltags];
|
||||
+ /* Attach scratchpad clients from other monitors at the bottom of the stack */
|
||||
+ if (selmon->clients) {
|
||||
+ for (last = selmon->clients; last && last->next; last = last->next);
|
||||
+ last->next = c;
|
||||
+ } else
|
||||
+ selmon->clients = c;
|
||||
+ c->next = NULL;
|
||||
+ attachstack(c);
|
||||
+
|
||||
+ /* Center floating scratchpad windows when moved from one monitor to another */
|
||||
+ if (c->isfloating) {
|
||||
+ if (c->w > selmon->ww)
|
||||
+ c->w = selmon->ww - c->bw * 2;
|
||||
+ if (c->h > selmon->wh)
|
||||
+ c->h = selmon->wh - c->bw * 2;
|
||||
+
|
||||
+ if (numscratchpads > 1) {
|
||||
+ c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
|
||||
+ c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
|
||||
+ } else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
|
||||
+ c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
|
||||
+ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
||||
+ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
||||
+ }
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (found) {
|
||||
+ focus(ISVISIBLE(found) ? found : NULL);
|
||||
+ arrange(NULL);
|
||||
+ if (found->isfloating)
|
||||
+ XRaiseWindow(dpy, found->win);
|
||||
+ } else {
|
||||
+ spawnscratch(arg);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
@@ -1758,7 +1924,10 @@ unfocus(Client *c, int setfocus)
|
||||
if (!c)
|
||||
return;
|
||||
grabbuttons(c, 0);
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
||||
+ if (c->scratchkey != 0)
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
+ else
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
||||
if (setfocus) {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,33 @@
|
||||
From 5c5a096d1b07d1840d5f6f5e14af459705e195f1 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:26:37 +0100
|
||||
Subject: [PATCH 2/2] Named scratchpad variant (without scratch color scheme)
|
||||
|
||||
---
|
||||
dwm.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index c58c6ed..67e5079 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1820,6 +1820,8 @@ togglescratch(const Arg *arg)
|
||||
if (!found || (mon == selmon && found->mon != selmon))
|
||||
found = c;
|
||||
|
||||
+ unfocus(c, 0); // unfocus to avoid client border discrepancies
|
||||
+
|
||||
/* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
as we are looping through monitors we could be moving a client to a monitor that has
|
||||
not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
@@ -1838,7 +1840,6 @@ togglescratch(const Arg *arg)
|
||||
} else if (scratchvisible == numscratchpads) {
|
||||
c->tags = 0;
|
||||
} else {
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
c->tags = c->mon->tagset[c->mon->seltags];
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,391 @@
|
||||
From 07804818ec69a86887533f47f4393f040de5a447 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:23:00 +0100
|
||||
Subject: [PATCH 1/2] Named scratchpad variant
|
||||
|
||||
---
|
||||
config.def.h | 17 ++++-
|
||||
dwm.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 186 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..049b29f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -12,10 +12,14 @@ static const char col_gray2[] = "#444444";
|
||||
static const char col_gray3[] = "#bbbbbb";
|
||||
static const char col_gray4[] = "#eeeeee";
|
||||
static const char col_cyan[] = "#005577";
|
||||
+static const char col_red[] = "#FF0000";
|
||||
+static const char col_orange[] = "#FF8800";
|
||||
static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeScratchSel] = { col_gray4, col_cyan, col_red },
|
||||
+ [SchemeScratchNorm] = { col_gray4, col_cyan, col_orange },
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
@@ -26,9 +30,10 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating monitor scratch key */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, -1, 0 },
|
||||
+ { "firefox", NULL, NULL, 1 << 8, 0, -1, 0 },
|
||||
+ { NULL, NULL, "scratchpad", 0, 1, -1, 's' },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -60,10 +65,16 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
|
||||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
+/*First arg only serves to match against key in rules*/
|
||||
+static const char *scratchpadcmd[] = {"s", "st", "-t", "scratchpad", NULL};
|
||||
+
|
||||
static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_g, togglescratch, {.v = scratchpadcmd } },
|
||||
+ { MODKEY|ShiftMask, XK_g, removescratch, {.v = scratchpadcmd } },
|
||||
+ { MODKEY|ControlMask, XK_g, setscratch, {.v = scratchpadcmd } },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..c58c6ed 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
-enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeScratchNorm, SchemeScratchSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ char scratchkey;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -139,6 +140,7 @@ typedef struct {
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ const char scratchkey;
|
||||
} Rule;
|
||||
|
||||
/* function declarations */
|
||||
@@ -189,6 +191,7 @@ static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
+static void removescratch(const Arg *arg);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
@@ -202,16 +205,19 @@ static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
+static void setscratch(const Arg *arg);
|
||||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static void spawnscratch(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglescratch(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -288,6 +294,7 @@ applyrules(Client *c)
|
||||
/* rule matching */
|
||||
c->isfloating = 0;
|
||||
c->tags = 0;
|
||||
+ c->scratchkey = 0;
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
class = ch.res_class ? ch.res_class : broken;
|
||||
instance = ch.res_name ? ch.res_name : broken;
|
||||
@@ -300,6 +307,7 @@ applyrules(Client *c)
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
+ c->scratchkey = r->scratchkey;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
@@ -309,6 +317,7 @@ applyrules(Client *c)
|
||||
XFree(ch.res_class);
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
+
|
||||
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
|
||||
}
|
||||
|
||||
@@ -799,7 +808,10 @@ focus(Client *c)
|
||||
detachstack(c);
|
||||
attachstack(c);
|
||||
grabbuttons(c, 1);
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
+ if (c->scratchkey != 0)
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel);
|
||||
+ else
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
setfocus(c);
|
||||
} else {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
@@ -1269,6 +1281,15 @@ recttomon(int x, int y, int w, int h)
|
||||
return r;
|
||||
}
|
||||
|
||||
+void
|
||||
+removescratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ c->scratchkey = 0;
|
||||
+}
|
||||
+
|
||||
void
|
||||
resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
{
|
||||
@@ -1530,6 +1551,16 @@ setmfact(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+setscratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ c->scratchkey = ((char**)arg->v)[0][0];
|
||||
+}
|
||||
+
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
@@ -1626,6 +1657,9 @@ showhide(Client *c)
|
||||
resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
showhide(c->snext);
|
||||
} else {
|
||||
+ /* optional: auto-hide scratchpads when moving to other tags */
|
||||
+ if (c->scratchkey != 0 && !(c->tags & c->mon->tagset[c->mon->seltags]))
|
||||
+ c->tags = 0;
|
||||
/* hide clients bottom up */
|
||||
showhide(c->snext);
|
||||
XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
|
||||
@@ -1656,6 +1690,19 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void spawnscratch(const Arg *arg)
|
||||
+{
|
||||
+ if (fork() == 0) {
|
||||
+ if (dpy)
|
||||
+ close(ConnectionNumber(dpy));
|
||||
+ setsid();
|
||||
+ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
|
||||
+ fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[1]);
|
||||
+ perror(" failed");
|
||||
+ exit(EXIT_SUCCESS);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@@ -1725,6 +1772,125 @@ togglefloating(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglescratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
|
||||
+ Monitor *mon;
|
||||
+ int scratchvisible = 0; // whether the scratchpads are currently visible or not
|
||||
+ int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
|
||||
+ int scratchmon = -1; // the monitor where the scratchpads exist
|
||||
+ int numscratchpads = 0; // count of scratchpads
|
||||
+
|
||||
+ /* Looping through monitors and client's twice, the first time to work out whether we need
|
||||
+ to move clients across from one monitor to another or not */
|
||||
+ for (mon = mons; mon; mon = mon->next)
|
||||
+ for (c = mon->clients; c; c = c->next) {
|
||||
+ if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
+ continue;
|
||||
+ if (scratchmon != -1 && scratchmon != mon->num)
|
||||
+ multimonscratch = 1;
|
||||
+ if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
|
||||
+ ++scratchvisible;
|
||||
+ scratchmon = mon->num;
|
||||
+ ++numscratchpads;
|
||||
+ }
|
||||
+
|
||||
+ /* Now for the real deal. The logic should go like:
|
||||
+ - hidden scratchpads will be shown
|
||||
+ - shown scratchpads will be hidden, unless they are being moved to the current monitor
|
||||
+ - the scratchpads will be moved to the current monitor if they all reside on the same monitor
|
||||
+ - multiple scratchpads residing on separate monitors will be left in place
|
||||
+ */
|
||||
+ for (mon = mons; mon; mon = mon->next) {
|
||||
+ for (c = mon->stack; c; c = next) {
|
||||
+ next = c->snext;
|
||||
+ if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
+ continue;
|
||||
+
|
||||
+ /* awesomebar / wintitleactions compatibility, unhide scratchpad if hidden
|
||||
+ if (HIDDEN(c)) {
|
||||
+ XMapWindow(dpy, c->win);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ }
|
||||
+ */
|
||||
+
|
||||
+ /* Record the first found scratchpad client for focus purposes, but prioritise the
|
||||
+ scratchpad on the current monitor if one exists */
|
||||
+ if (!found || (mon == selmon && found->mon != selmon))
|
||||
+ found = c;
|
||||
+
|
||||
+ /* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
+ as we are looping through monitors we could be moving a client to a monitor that has
|
||||
+ not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
+ this we detach them and add them to a temporary list (monclients) which is to be
|
||||
+ processed later. */
|
||||
+ if (!multimonscratch && c->mon != selmon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = NULL;
|
||||
+ /* Note that we are adding clients at the end of the list, this is to preserve the
|
||||
+ order of clients as they were on the adjacent monitor (relevant when tiled) */
|
||||
+ if (last)
|
||||
+ last = last->next = c;
|
||||
+ else
|
||||
+ last = monclients = c;
|
||||
+ } else if (scratchvisible == numscratchpads) {
|
||||
+ c->tags = 0;
|
||||
+ } else {
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
+ c->tags = c->mon->tagset[c->mon->seltags];
|
||||
+ if (c->isfloating)
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Attach moved scratchpad clients on the selected monitor */
|
||||
+ for (c = monclients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ mon = c->mon;
|
||||
+ c->mon = selmon;
|
||||
+ c->tags = selmon->tagset[selmon->seltags];
|
||||
+ /* Attach scratchpad clients from other monitors at the bottom of the stack */
|
||||
+ if (selmon->clients) {
|
||||
+ for (last = selmon->clients; last && last->next; last = last->next);
|
||||
+ last->next = c;
|
||||
+ } else
|
||||
+ selmon->clients = c;
|
||||
+ c->next = NULL;
|
||||
+ attachstack(c);
|
||||
+
|
||||
+ /* Center floating scratchpad windows when moved from one monitor to another */
|
||||
+ if (c->isfloating) {
|
||||
+ if (c->w > selmon->ww)
|
||||
+ c->w = selmon->ww - c->bw * 2;
|
||||
+ if (c->h > selmon->wh)
|
||||
+ c->h = selmon->wh - c->bw * 2;
|
||||
+
|
||||
+ if (numscratchpads > 1) {
|
||||
+ c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
|
||||
+ c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
|
||||
+ } else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
|
||||
+ c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
|
||||
+ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
||||
+ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
||||
+ }
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (found) {
|
||||
+ focus(ISVISIBLE(found) ? found : NULL);
|
||||
+ arrange(NULL);
|
||||
+ if (found->isfloating)
|
||||
+ XRaiseWindow(dpy, found->win);
|
||||
+ } else {
|
||||
+ spawnscratch(arg);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
@@ -1758,7 +1924,10 @@ unfocus(Client *c, int setfocus)
|
||||
if (!c)
|
||||
return;
|
||||
grabbuttons(c, 0);
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
||||
+ if (c->scratchkey != 0)
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
+ else
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
||||
if (setfocus) {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From 5c5a096d1b07d1840d5f6f5e14af459705e195f1 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:26:37 +0100
|
||||
Subject: [PATCH 2/2] Named scratchpad variant (without scratch color scheme)
|
||||
|
||||
---
|
||||
dwm.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index c58c6ed..67e5079 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1820,6 +1820,8 @@ togglescratch(const Arg *arg)
|
||||
if (!found || (mon == selmon && found->mon != selmon))
|
||||
found = c;
|
||||
|
||||
+ unfocus(c, 0); // unfocus to avoid client border discrepancies
|
||||
+
|
||||
/* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
as we are looping through monitors we could be moving a client to a monitor that has
|
||||
not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
@@ -1838,7 +1840,6 @@ togglescratch(const Arg *arg)
|
||||
} else if (scratchvisible == numscratchpads) {
|
||||
c->tags = 0;
|
||||
} else {
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
c->tags = c->mon->tagset[c->mon->seltags];
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,139 @@
|
||||
From fb46e7d8f708a5ba87ac36f3a614869a1f266cc7 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:30:39 +0100
|
||||
Subject: [PATCH 2/2] Another namedscratchpads variant where scratchpads remain
|
||||
on the monitors where they reside
|
||||
|
||||
---
|
||||
dwm.c | 101 ++++++++++------------------------------------------------
|
||||
1 file changed, 16 insertions(+), 85 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index c58c6ed..6e49100 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1775,34 +1775,12 @@ togglefloating(const Arg *arg)
|
||||
void
|
||||
togglescratch(const Arg *arg)
|
||||
{
|
||||
- Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
|
||||
+ Client *c, *next, *found = NULL;
|
||||
Monitor *mon;
|
||||
- int scratchvisible = 0; // whether the scratchpads are currently visible or not
|
||||
- int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
|
||||
- int scratchmon = -1; // the monitor where the scratchpads exist
|
||||
- int numscratchpads = 0; // count of scratchpads
|
||||
-
|
||||
- /* Looping through monitors and client's twice, the first time to work out whether we need
|
||||
- to move clients across from one monitor to another or not */
|
||||
- for (mon = mons; mon; mon = mon->next)
|
||||
- for (c = mon->clients; c; c = c->next) {
|
||||
- if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
- continue;
|
||||
- if (scratchmon != -1 && scratchmon != mon->num)
|
||||
- multimonscratch = 1;
|
||||
- if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
|
||||
- ++scratchvisible;
|
||||
- scratchmon = mon->num;
|
||||
- ++numscratchpads;
|
||||
- }
|
||||
+ int tags = 0, monfound;
|
||||
|
||||
- /* Now for the real deal. The logic should go like:
|
||||
- - hidden scratchpads will be shown
|
||||
- - shown scratchpads will be hidden, unless they are being moved to the current monitor
|
||||
- - the scratchpads will be moved to the current monitor if they all reside on the same monitor
|
||||
- - multiple scratchpads residing on separate monitors will be left in place
|
||||
- */
|
||||
for (mon = mons; mon; mon = mon->next) {
|
||||
+ monfound = 0;
|
||||
for (c = mon->stack; c; c = next) {
|
||||
next = c->snext;
|
||||
if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
@@ -1815,70 +1793,23 @@ togglescratch(const Arg *arg)
|
||||
}
|
||||
*/
|
||||
|
||||
- /* Record the first found scratchpad client for focus purposes, but prioritise the
|
||||
- scratchpad on the current monitor if one exists */
|
||||
- if (!found || (mon == selmon && found->mon != selmon))
|
||||
- found = c;
|
||||
+ unfocus(c, 0);
|
||||
+ monfound = 1;
|
||||
|
||||
- /* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
- as we are looping through monitors we could be moving a client to a monitor that has
|
||||
- not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
- this we detach them and add them to a temporary list (monclients) which is to be
|
||||
- processed later. */
|
||||
- if (!multimonscratch && c->mon != selmon) {
|
||||
- detach(c);
|
||||
- detachstack(c);
|
||||
- c->next = NULL;
|
||||
- /* Note that we are adding clients at the end of the list, this is to preserve the
|
||||
- order of clients as they were on the adjacent monitor (relevant when tiled) */
|
||||
- if (last)
|
||||
- last = last->next = c;
|
||||
- else
|
||||
- last = monclients = c;
|
||||
- } else if (scratchvisible == numscratchpads) {
|
||||
- c->tags = 0;
|
||||
- } else {
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
- c->tags = c->mon->tagset[c->mon->seltags];
|
||||
- if (c->isfloating)
|
||||
- XRaiseWindow(dpy, c->win);
|
||||
+ if (!found || mon == selmon) {
|
||||
+ found = c;
|
||||
+ tags = (c->tags == 0 ? c->mon->tagset[c->mon->seltags] : 0);
|
||||
}
|
||||
- }
|
||||
- }
|
||||
|
||||
- /* Attach moved scratchpad clients on the selected monitor */
|
||||
- for (c = monclients; c; c = next) {
|
||||
- next = c->next;
|
||||
- mon = c->mon;
|
||||
- c->mon = selmon;
|
||||
- c->tags = selmon->tagset[selmon->seltags];
|
||||
- /* Attach scratchpad clients from other monitors at the bottom of the stack */
|
||||
- if (selmon->clients) {
|
||||
- for (last = selmon->clients; last && last->next; last = last->next);
|
||||
- last->next = c;
|
||||
- } else
|
||||
- selmon->clients = c;
|
||||
- c->next = NULL;
|
||||
- attachstack(c);
|
||||
-
|
||||
- /* Center floating scratchpad windows when moved from one monitor to another */
|
||||
- if (c->isfloating) {
|
||||
- if (c->w > selmon->ww)
|
||||
- c->w = selmon->ww - c->bw * 2;
|
||||
- if (c->h > selmon->wh)
|
||||
- c->h = selmon->wh - c->bw * 2;
|
||||
-
|
||||
- if (numscratchpads > 1) {
|
||||
- c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
|
||||
- c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
|
||||
- } else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
|
||||
- c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
|
||||
- c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
||||
- c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
||||
- }
|
||||
- resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- XRaiseWindow(dpy, c->win);
|
||||
+ detachstack(c);
|
||||
+ attachstack(c);
|
||||
+ c->tags = tags;
|
||||
+ if (c->tags && c->isfloating)
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
}
|
||||
+
|
||||
+ if (monfound)
|
||||
+ arrange(mon);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,497 @@
|
||||
From 07804818ec69a86887533f47f4393f040de5a447 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:23:00 +0100
|
||||
Subject: [PATCH 1/2] Named scratchpad variant
|
||||
|
||||
---
|
||||
config.def.h | 17 ++++-
|
||||
dwm.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 186 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..049b29f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -12,10 +12,14 @@ static const char col_gray2[] = "#444444";
|
||||
static const char col_gray3[] = "#bbbbbb";
|
||||
static const char col_gray4[] = "#eeeeee";
|
||||
static const char col_cyan[] = "#005577";
|
||||
+static const char col_red[] = "#FF0000";
|
||||
+static const char col_orange[] = "#FF8800";
|
||||
static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||
+ [SchemeScratchSel] = { col_gray4, col_cyan, col_red },
|
||||
+ [SchemeScratchNorm] = { col_gray4, col_cyan, col_orange },
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
@@ -26,9 +30,10 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating monitor scratch key */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, -1, 0 },
|
||||
+ { "firefox", NULL, NULL, 1 << 8, 0, -1, 0 },
|
||||
+ { NULL, NULL, "scratchpad", 0, 1, -1, 's' },
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
@@ -60,10 +65,16 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
|
||||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
|
||||
+/*First arg only serves to match against key in rules*/
|
||||
+static const char *scratchpadcmd[] = {"s", "st", "-t", "scratchpad", NULL};
|
||||
+
|
||||
static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_g, togglescratch, {.v = scratchpadcmd } },
|
||||
+ { MODKEY|ShiftMask, XK_g, removescratch, {.v = scratchpadcmd } },
|
||||
+ { MODKEY|ControlMask, XK_g, setscratch, {.v = scratchpadcmd } },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..c58c6ed 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
-enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
+enum { SchemeNorm, SchemeSel, SchemeScratchNorm, SchemeScratchSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ char scratchkey;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -139,6 +140,7 @@ typedef struct {
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
int monitor;
|
||||
+ const char scratchkey;
|
||||
} Rule;
|
||||
|
||||
/* function declarations */
|
||||
@@ -189,6 +191,7 @@ static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
+static void removescratch(const Arg *arg);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
@@ -202,16 +205,19 @@ static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
+static void setscratch(const Arg *arg);
|
||||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static void spawnscratch(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
+static void togglescratch(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@@ -288,6 +294,7 @@ applyrules(Client *c)
|
||||
/* rule matching */
|
||||
c->isfloating = 0;
|
||||
c->tags = 0;
|
||||
+ c->scratchkey = 0;
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
class = ch.res_class ? ch.res_class : broken;
|
||||
instance = ch.res_name ? ch.res_name : broken;
|
||||
@@ -300,6 +307,7 @@ applyrules(Client *c)
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
+ c->scratchkey = r->scratchkey;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
if (m)
|
||||
c->mon = m;
|
||||
@@ -309,6 +317,7 @@ applyrules(Client *c)
|
||||
XFree(ch.res_class);
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
+
|
||||
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
|
||||
}
|
||||
|
||||
@@ -799,7 +808,10 @@ focus(Client *c)
|
||||
detachstack(c);
|
||||
attachstack(c);
|
||||
grabbuttons(c, 1);
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
+ if (c->scratchkey != 0)
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel);
|
||||
+ else
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
||||
setfocus(c);
|
||||
} else {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
@@ -1269,6 +1281,15 @@ recttomon(int x, int y, int w, int h)
|
||||
return r;
|
||||
}
|
||||
|
||||
+void
|
||||
+removescratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+ c->scratchkey = 0;
|
||||
+}
|
||||
+
|
||||
void
|
||||
resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
{
|
||||
@@ -1530,6 +1551,16 @@ setmfact(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+setscratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = selmon->sel;
|
||||
+ if (!c)
|
||||
+ return;
|
||||
+
|
||||
+ c->scratchkey = ((char**)arg->v)[0][0];
|
||||
+}
|
||||
+
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
@@ -1626,6 +1657,9 @@ showhide(Client *c)
|
||||
resize(c, c->x, c->y, c->w, c->h, 0);
|
||||
showhide(c->snext);
|
||||
} else {
|
||||
+ /* optional: auto-hide scratchpads when moving to other tags */
|
||||
+ if (c->scratchkey != 0 && !(c->tags & c->mon->tagset[c->mon->seltags]))
|
||||
+ c->tags = 0;
|
||||
/* hide clients bottom up */
|
||||
showhide(c->snext);
|
||||
XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
|
||||
@@ -1656,6 +1690,19 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+void spawnscratch(const Arg *arg)
|
||||
+{
|
||||
+ if (fork() == 0) {
|
||||
+ if (dpy)
|
||||
+ close(ConnectionNumber(dpy));
|
||||
+ setsid();
|
||||
+ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
|
||||
+ fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[1]);
|
||||
+ perror(" failed");
|
||||
+ exit(EXIT_SUCCESS);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@@ -1725,6 +1772,125 @@ togglefloating(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+void
|
||||
+togglescratch(const Arg *arg)
|
||||
+{
|
||||
+ Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
|
||||
+ Monitor *mon;
|
||||
+ int scratchvisible = 0; // whether the scratchpads are currently visible or not
|
||||
+ int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
|
||||
+ int scratchmon = -1; // the monitor where the scratchpads exist
|
||||
+ int numscratchpads = 0; // count of scratchpads
|
||||
+
|
||||
+ /* Looping through monitors and client's twice, the first time to work out whether we need
|
||||
+ to move clients across from one monitor to another or not */
|
||||
+ for (mon = mons; mon; mon = mon->next)
|
||||
+ for (c = mon->clients; c; c = c->next) {
|
||||
+ if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
+ continue;
|
||||
+ if (scratchmon != -1 && scratchmon != mon->num)
|
||||
+ multimonscratch = 1;
|
||||
+ if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
|
||||
+ ++scratchvisible;
|
||||
+ scratchmon = mon->num;
|
||||
+ ++numscratchpads;
|
||||
+ }
|
||||
+
|
||||
+ /* Now for the real deal. The logic should go like:
|
||||
+ - hidden scratchpads will be shown
|
||||
+ - shown scratchpads will be hidden, unless they are being moved to the current monitor
|
||||
+ - the scratchpads will be moved to the current monitor if they all reside on the same monitor
|
||||
+ - multiple scratchpads residing on separate monitors will be left in place
|
||||
+ */
|
||||
+ for (mon = mons; mon; mon = mon->next) {
|
||||
+ for (c = mon->stack; c; c = next) {
|
||||
+ next = c->snext;
|
||||
+ if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
+ continue;
|
||||
+
|
||||
+ /* awesomebar / wintitleactions compatibility, unhide scratchpad if hidden
|
||||
+ if (HIDDEN(c)) {
|
||||
+ XMapWindow(dpy, c->win);
|
||||
+ setclientstate(c, NormalState);
|
||||
+ }
|
||||
+ */
|
||||
+
|
||||
+ /* Record the first found scratchpad client for focus purposes, but prioritise the
|
||||
+ scratchpad on the current monitor if one exists */
|
||||
+ if (!found || (mon == selmon && found->mon != selmon))
|
||||
+ found = c;
|
||||
+
|
||||
+ /* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
+ as we are looping through monitors we could be moving a client to a monitor that has
|
||||
+ not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
+ this we detach them and add them to a temporary list (monclients) which is to be
|
||||
+ processed later. */
|
||||
+ if (!multimonscratch && c->mon != selmon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ c->next = NULL;
|
||||
+ /* Note that we are adding clients at the end of the list, this is to preserve the
|
||||
+ order of clients as they were on the adjacent monitor (relevant when tiled) */
|
||||
+ if (last)
|
||||
+ last = last->next = c;
|
||||
+ else
|
||||
+ last = monclients = c;
|
||||
+ } else if (scratchvisible == numscratchpads) {
|
||||
+ c->tags = 0;
|
||||
+ } else {
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
+ c->tags = c->mon->tagset[c->mon->seltags];
|
||||
+ if (c->isfloating)
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Attach moved scratchpad clients on the selected monitor */
|
||||
+ for (c = monclients; c; c = next) {
|
||||
+ next = c->next;
|
||||
+ mon = c->mon;
|
||||
+ c->mon = selmon;
|
||||
+ c->tags = selmon->tagset[selmon->seltags];
|
||||
+ /* Attach scratchpad clients from other monitors at the bottom of the stack */
|
||||
+ if (selmon->clients) {
|
||||
+ for (last = selmon->clients; last && last->next; last = last->next);
|
||||
+ last->next = c;
|
||||
+ } else
|
||||
+ selmon->clients = c;
|
||||
+ c->next = NULL;
|
||||
+ attachstack(c);
|
||||
+
|
||||
+ /* Center floating scratchpad windows when moved from one monitor to another */
|
||||
+ if (c->isfloating) {
|
||||
+ if (c->w > selmon->ww)
|
||||
+ c->w = selmon->ww - c->bw * 2;
|
||||
+ if (c->h > selmon->wh)
|
||||
+ c->h = selmon->wh - c->bw * 2;
|
||||
+
|
||||
+ if (numscratchpads > 1) {
|
||||
+ c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
|
||||
+ c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
|
||||
+ } else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
|
||||
+ c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
|
||||
+ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
||||
+ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
||||
+ }
|
||||
+ resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (found) {
|
||||
+ focus(ISVISIBLE(found) ? found : NULL);
|
||||
+ arrange(NULL);
|
||||
+ if (found->isfloating)
|
||||
+ XRaiseWindow(dpy, found->win);
|
||||
+ } else {
|
||||
+ spawnscratch(arg);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
@@ -1758,7 +1924,10 @@ unfocus(Client *c, int setfocus)
|
||||
if (!c)
|
||||
return;
|
||||
grabbuttons(c, 0);
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
||||
+ if (c->scratchkey != 0)
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
+ else
|
||||
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
||||
if (setfocus) {
|
||||
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From fb46e7d8f708a5ba87ac36f3a614869a1f266cc7 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:30:39 +0100
|
||||
Subject: [PATCH 2/2] Another namedscratchpads variant where scratchpads remain
|
||||
on the monitors where they reside
|
||||
|
||||
---
|
||||
dwm.c | 101 ++++++++++------------------------------------------------
|
||||
1 file changed, 16 insertions(+), 85 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index c58c6ed..6e49100 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1775,34 +1775,12 @@ togglefloating(const Arg *arg)
|
||||
void
|
||||
togglescratch(const Arg *arg)
|
||||
{
|
||||
- Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
|
||||
+ Client *c, *next, *found = NULL;
|
||||
Monitor *mon;
|
||||
- int scratchvisible = 0; // whether the scratchpads are currently visible or not
|
||||
- int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
|
||||
- int scratchmon = -1; // the monitor where the scratchpads exist
|
||||
- int numscratchpads = 0; // count of scratchpads
|
||||
-
|
||||
- /* Looping through monitors and client's twice, the first time to work out whether we need
|
||||
- to move clients across from one monitor to another or not */
|
||||
- for (mon = mons; mon; mon = mon->next)
|
||||
- for (c = mon->clients; c; c = c->next) {
|
||||
- if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
- continue;
|
||||
- if (scratchmon != -1 && scratchmon != mon->num)
|
||||
- multimonscratch = 1;
|
||||
- if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
|
||||
- ++scratchvisible;
|
||||
- scratchmon = mon->num;
|
||||
- ++numscratchpads;
|
||||
- }
|
||||
+ int tags = 0, monfound;
|
||||
|
||||
- /* Now for the real deal. The logic should go like:
|
||||
- - hidden scratchpads will be shown
|
||||
- - shown scratchpads will be hidden, unless they are being moved to the current monitor
|
||||
- - the scratchpads will be moved to the current monitor if they all reside on the same monitor
|
||||
- - multiple scratchpads residing on separate monitors will be left in place
|
||||
- */
|
||||
for (mon = mons; mon; mon = mon->next) {
|
||||
+ monfound = 0;
|
||||
for (c = mon->stack; c; c = next) {
|
||||
next = c->snext;
|
||||
if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
@@ -1815,70 +1793,23 @@ togglescratch(const Arg *arg)
|
||||
}
|
||||
*/
|
||||
|
||||
- /* Record the first found scratchpad client for focus purposes, but prioritise the
|
||||
- scratchpad on the current monitor if one exists */
|
||||
- if (!found || (mon == selmon && found->mon != selmon))
|
||||
- found = c;
|
||||
+ unfocus(c, 0);
|
||||
+ monfound = 1;
|
||||
|
||||
- /* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
- as we are looping through monitors we could be moving a client to a monitor that has
|
||||
- not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
- this we detach them and add them to a temporary list (monclients) which is to be
|
||||
- processed later. */
|
||||
- if (!multimonscratch && c->mon != selmon) {
|
||||
- detach(c);
|
||||
- detachstack(c);
|
||||
- c->next = NULL;
|
||||
- /* Note that we are adding clients at the end of the list, this is to preserve the
|
||||
- order of clients as they were on the adjacent monitor (relevant when tiled) */
|
||||
- if (last)
|
||||
- last = last->next = c;
|
||||
- else
|
||||
- last = monclients = c;
|
||||
- } else if (scratchvisible == numscratchpads) {
|
||||
- c->tags = 0;
|
||||
- } else {
|
||||
- XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
- c->tags = c->mon->tagset[c->mon->seltags];
|
||||
- if (c->isfloating)
|
||||
- XRaiseWindow(dpy, c->win);
|
||||
+ if (!found || mon == selmon) {
|
||||
+ found = c;
|
||||
+ tags = (c->tags == 0 ? c->mon->tagset[c->mon->seltags] : 0);
|
||||
}
|
||||
- }
|
||||
- }
|
||||
|
||||
- /* Attach moved scratchpad clients on the selected monitor */
|
||||
- for (c = monclients; c; c = next) {
|
||||
- next = c->next;
|
||||
- mon = c->mon;
|
||||
- c->mon = selmon;
|
||||
- c->tags = selmon->tagset[selmon->seltags];
|
||||
- /* Attach scratchpad clients from other monitors at the bottom of the stack */
|
||||
- if (selmon->clients) {
|
||||
- for (last = selmon->clients; last && last->next; last = last->next);
|
||||
- last->next = c;
|
||||
- } else
|
||||
- selmon->clients = c;
|
||||
- c->next = NULL;
|
||||
- attachstack(c);
|
||||
-
|
||||
- /* Center floating scratchpad windows when moved from one monitor to another */
|
||||
- if (c->isfloating) {
|
||||
- if (c->w > selmon->ww)
|
||||
- c->w = selmon->ww - c->bw * 2;
|
||||
- if (c->h > selmon->wh)
|
||||
- c->h = selmon->wh - c->bw * 2;
|
||||
-
|
||||
- if (numscratchpads > 1) {
|
||||
- c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
|
||||
- c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
|
||||
- } else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
|
||||
- c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
|
||||
- c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
||||
- c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
||||
- }
|
||||
- resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
- XRaiseWindow(dpy, c->win);
|
||||
+ detachstack(c);
|
||||
+ attachstack(c);
|
||||
+ c->tags = tags;
|
||||
+ if (c->tags && c->isfloating)
|
||||
+ XRaiseWindow(dpy, c->win);
|
||||
}
|
||||
+
|
||||
+ if (monfound)
|
||||
+ arrange(mon);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,89 @@
|
||||
From c605528712e408504cac41cbd5566e0e2cfdbc76 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:31:21 +0100
|
||||
Subject: [PATCH] Resize a floating window from any corner
|
||||
|
||||
By default, windows only from the bottom right corner.
|
||||
With this patch the mouse is warped to the nearest corner and you
|
||||
resize from there.
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/resizecorners/
|
||||
|
||||
Authors:
|
||||
dusty - dusty@teknik.io
|
||||
Klemens Nanni kl3@posteo.org (6.1 version)
|
||||
---
|
||||
dwm.c | 27 ++++++++++++++++++++++++---
|
||||
1 file changed, 24 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..67cfb1b 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1295,9 +1295,14 @@ void
|
||||
resizemouse(const Arg *arg)
|
||||
{
|
||||
int ocx, ocy, nw, nh;
|
||||
+ int ocx2, ocy2, nx, ny;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
XEvent ev;
|
||||
+ int horizcorner, vertcorner;
|
||||
+ int di;
|
||||
+ unsigned int dui;
|
||||
+ Window dummy;
|
||||
Time lasttime = 0;
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
@@ -1307,10 +1312,19 @@ resizemouse(const Arg *arg)
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
ocy = c->y;
|
||||
+ ocx2 = c->x + c->w;
|
||||
+ ocy2 = c->y + c->h;
|
||||
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
||||
return;
|
||||
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
||||
+ if (!XQueryPointer (dpy, c->win, &dummy, &dummy, &di, &di, &nx, &ny, &dui))
|
||||
+ return;
|
||||
+ horizcorner = nx < c->w / 2;
|
||||
+ vertcorner = ny < c->h / 2;
|
||||
+ XWarpPointer (dpy, None, c->win, 0, 0, 0, 0,
|
||||
+ horizcorner ? (-c->bw) : (c->w + c->bw - 1),
|
||||
+ vertcorner ? (-c->bw) : (c->h + c->bw - 1));
|
||||
+
|
||||
do {
|
||||
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
switch(ev.type) {
|
||||
@@ -1326,6 +1340,11 @@ resizemouse(const Arg *arg)
|
||||
|
||||
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
|
||||
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
|
||||
+ nx = horizcorner ? ev.xmotion.x : c->x;
|
||||
+ ny = vertcorner ? ev.xmotion.y : c->y;
|
||||
+ nw = MAX(horizcorner ? (ocx2 - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1);
|
||||
+ nh = MAX(vertcorner ? (ocy2 - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1);
|
||||
+
|
||||
if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
|
||||
&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
|
||||
{
|
||||
@@ -1334,11 +1353,13 @@ resizemouse(const Arg *arg)
|
||||
togglefloating(NULL);
|
||||
}
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
||||
- resize(c, c->x, c->y, nw, nh, 1);
|
||||
+ resize(c, nx, ny, nw, nh, 1);
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
||||
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
|
||||
+ horizcorner ? (-c->bw) : (c->w + c->bw - 1),
|
||||
+ vertcorner ? (-c->bw) : (c->h + c->bw - 1));
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,97 @@
|
||||
From 3ddd6032fb60b780cb628d0a1866f1f2d5febf0b Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:31:54 +0100
|
||||
Subject: [PATCH] resizepoint - Like resizecorners, but does not warp mouse
|
||||
pointer
|
||||
|
||||
---
|
||||
dwm.c | 30 +++++++++++++++++++++---------
|
||||
1 file changed, 21 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..6f5d833 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -58,7 +58,7 @@
|
||||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||
|
||||
/* enums */
|
||||
-enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
+enum { CurResizeBR, CurResizeBL, CurResizeTR, CurResizeTL, CurNormal, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
@@ -1294,10 +1294,13 @@ resizeclient(Client *c, int x, int y, int w, int h)
|
||||
void
|
||||
resizemouse(const Arg *arg)
|
||||
{
|
||||
- int ocx, ocy, nw, nh;
|
||||
+ int opx, opy, ocx, ocy, och, ocw, nx, ny, nw, nh;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
XEvent ev;
|
||||
+ int horizcorner, vertcorner;
|
||||
+ unsigned int dui;
|
||||
+ Window dummy;
|
||||
Time lasttime = 0;
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
@@ -1307,10 +1310,15 @@ resizemouse(const Arg *arg)
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
ocy = c->y;
|
||||
+ och = c->h;
|
||||
+ ocw = c->w;
|
||||
+ if (!XQueryPointer(dpy, c->win, &dummy, &dummy, &opx, &opy, &nx, &ny, &dui))
|
||||
+ return;
|
||||
+ horizcorner = nx < c->w / 2;
|
||||
+ vertcorner = ny < c->h / 2;
|
||||
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
||||
+ None, cursor[horizcorner | (vertcorner << 1)]->cursor, CurrentTime) != GrabSuccess)
|
||||
return;
|
||||
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
||||
do {
|
||||
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
switch(ev.type) {
|
||||
@@ -1324,8 +1332,10 @@ resizemouse(const Arg *arg)
|
||||
continue;
|
||||
lasttime = ev.xmotion.time;
|
||||
|
||||
- nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
|
||||
- nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
|
||||
+ nx = horizcorner ? (ocx + ev.xmotion.x - opx) : c->x;
|
||||
+ ny = vertcorner ? (ocy + ev.xmotion.y - opy) : c->y;
|
||||
+ nw = MAX(horizcorner ? (ocx + ocw - nx) : (ocw + (ev.xmotion.x - opx)), 1);
|
||||
+ nh = MAX(vertcorner ? (ocy + och - ny) : (och + (ev.xmotion.y - opy)), 1);
|
||||
if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
|
||||
&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
|
||||
{
|
||||
@@ -1334,11 +1344,10 @@ resizemouse(const Arg *arg)
|
||||
togglefloating(NULL);
|
||||
}
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
||||
- resize(c, c->x, c->y, nw, nh, 1);
|
||||
+ resizeclient(c, nx, ny, nw, nh);
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
||||
@@ -1568,7 +1577,10 @@ setup(void)
|
||||
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
||||
/* init cursors */
|
||||
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
||||
- cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
+ cursor[CurResizeBR] = drw_cur_create(drw, XC_bottom_right_corner);
|
||||
+ cursor[CurResizeBL] = drw_cur_create(drw, XC_bottom_left_corner);
|
||||
+ cursor[CurResizeTR] = drw_cur_create(drw, XC_top_right_corner);
|
||||
+ cursor[CurResizeTL] = drw_cur_create(drw, XC_top_left_corner);
|
||||
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
||||
/* init appearance */
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,451 @@
|
||||
From bd42e1d726234a591e0f08f4de2360fb5c051d6d Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:32:43 +0100
|
||||
Subject: [PATCH] Adding rio-like draw-to-resize windows.
|
||||
|
||||
This was backported from instantWM and depends on an external tool
|
||||
slop to be installed.
|
||||
|
||||
Contributed by jzbor.
|
||||
---
|
||||
config.def.h | 8 ++
|
||||
config.mk | 6 +-
|
||||
dwm.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
3 files changed, 248 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..bbbc6ca 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,12 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char slopspawnstyle[] = "-t 0 -c 0.92,0.85,0.69,0.3 -o"; /* do NOT define -f (format) here */
|
||||
+static const char slopresizestyle[] = "-t 0 -c 0.92,0.85,0.69,0.3"; /* do NOT define -f (format) here */
|
||||
+static const int riodraw_borders = 0; /* 0 or 1, indicates whether the area drawn using slop includes the window borders */
|
||||
+static const int riodraw_matchpid = 1; /* 0 or 1, indicates whether to match the PID of the client that was spawned with riospawn */
|
||||
+static const int riodraw_spawnasync = 0; /* 0 means that the application is only spawned after a successful selection while
|
||||
+ * 1 means that the application is being initialised in the background while the selection is made */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -64,6 +70,8 @@ static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY|ControlMask, XK_Return, riospawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_s, rioresize, {0} },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/config.mk b/config.mk
|
||||
index b6eb7e0..ee5c46e 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -19,10 +19,14 @@ FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = ${X11INC}/freetype2
|
||||
+#KVMLIB = -lkvm
|
||||
+
|
||||
+# This is needed for the swallow patch
|
||||
+XCBLIBS = -lX11-xcb -lxcb -lxcb-res
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XCBLIBS} ${KVMLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..95cfcb5 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -40,6 +40,12 @@
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif /* XINERAMA */
|
||||
#include <X11/Xft/Xft.h>
|
||||
+#include <X11/Xlib-xcb.h>
|
||||
+#include <xcb/res.h>
|
||||
+#ifdef __OpenBSD__
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <kvm.h>
|
||||
+#endif /* __OpenBSD */
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
@@ -48,7 +54,7 @@
|
||||
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#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)))
|
||||
+ * 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 LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
@@ -61,11 +67,11 @@
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
- ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
@@ -93,6 +99,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ pid_t pid;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -170,12 +177,14 @@ static void focusin(XEvent *e);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static Atom getatomprop(Client *c, Atom prop);
|
||||
+static pid_t getparentprocess(pid_t p);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
+static int isdescprocess(pid_t p, pid_t c);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
@@ -193,6 +202,10 @@ static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
+static int riodraw(Client *c, const char slopstyle[]);
|
||||
+static void rioposition(Client *c, int x, int y, int w, int h);
|
||||
+static void rioresize(const Arg *arg);
|
||||
+static void riospawn(const Arg *arg);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
@@ -207,6 +220,7 @@ static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static pid_t spawncmd(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
@@ -228,6 +242,7 @@ static void updatetitle(Client *c);
|
||||
static void updatewindowtype(Client *c);
|
||||
static void updatewmhints(Client *c);
|
||||
static void view(const Arg *arg);
|
||||
+static pid_t winpid(Window w);
|
||||
static Client *wintoclient(Window w);
|
||||
static Monitor *wintomon(Window w);
|
||||
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||
@@ -244,6 +259,8 @@ static int bh, blw = 0; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
+static int riodimensions[4] = { -1, -1, -1, -1 };
|
||||
+static pid_t riopid = 0;
|
||||
static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[ButtonPress] = buttonpress,
|
||||
[ClientMessage] = clientmessage,
|
||||
@@ -268,6 +285,7 @@ static Display *dpy;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
+static xcb_connection_t *xcon;
|
||||
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
@@ -875,6 +893,39 @@ getatomprop(Client *c, Atom prop)
|
||||
return atom;
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+getparentprocess(pid_t p)
|
||||
+{
|
||||
+ unsigned int v = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ FILE *f;
|
||||
+ char buf[256];
|
||||
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
|
||||
+
|
||||
+ if (!(f = fopen(buf, "r")))
|
||||
+ return 0;
|
||||
+
|
||||
+ fscanf(f, "%*u %*s %*c %u", &v);
|
||||
+ fclose(f);
|
||||
+#endif /* __linux__*/
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ int n;
|
||||
+ kvm_t *kd;
|
||||
+ struct kinfo_proc *kp;
|
||||
+
|
||||
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
+ if (!kd)
|
||||
+ return 0;
|
||||
+
|
||||
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
+ v = kp->p_ppid;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ return (pid_t)v;
|
||||
+}
|
||||
+
|
||||
int
|
||||
getrootptr(int *x, int *y)
|
||||
{
|
||||
@@ -974,6 +1025,15 @@ incnmaster(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+int
|
||||
+isdescprocess(pid_t p, pid_t c)
|
||||
+{
|
||||
+ while (p != c && c != 0)
|
||||
+ c = getparentprocess(c);
|
||||
+
|
||||
+ return (int)c;
|
||||
+}
|
||||
+
|
||||
#ifdef XINERAMA
|
||||
static int
|
||||
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
||||
@@ -1027,6 +1087,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
+ c->pid = winpid(w);
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
@@ -1075,6 +1136,15 @@ manage(Window w, XWindowAttributes *wa)
|
||||
if (c->mon == selmon)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
+
|
||||
+ if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
||||
+ if (riodimensions[3] != -1)
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ else {
|
||||
+ killclient(&((Arg) { .v = c }));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
focus(NULL);
|
||||
@@ -1373,6 +1443,104 @@ restack(Monitor *m)
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
+int
|
||||
+riodraw(Client *c, const char slopstyle[])
|
||||
+{
|
||||
+ int i;
|
||||
+ char str[100] = {0};
|
||||
+ char strout[100] = {0};
|
||||
+ char tmpstring[30] = {0};
|
||||
+ char slopcmd[100] = "slop -f x%xx%yx%wx%hx ";
|
||||
+ int firstchar = 0;
|
||||
+ int counter = 0;
|
||||
+
|
||||
+ strcat(slopcmd, slopstyle);
|
||||
+ FILE *fp = popen(slopcmd, "r");
|
||||
+
|
||||
+ while (fgets(str, 100, fp) != NULL)
|
||||
+ strcat(strout, str);
|
||||
+
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ if (strlen(strout) < 6)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < strlen(strout); i++){
|
||||
+ if (!firstchar) {
|
||||
+ if (strout[i] == 'x')
|
||||
+ firstchar = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strout[i] != 'x')
|
||||
+ tmpstring[strlen(tmpstring)] = strout[i];
|
||||
+ else {
|
||||
+ riodimensions[counter] = atoi(tmpstring);
|
||||
+ counter++;
|
||||
+ memset(tmpstring,0,strlen(tmpstring));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (riodimensions[0] <= -40 || riodimensions[1] <= -40 || riodimensions[2] <= 50 || riodimensions[3] <= 50) {
|
||||
+ riodimensions[3] = -1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (c) {
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+rioposition(Client *c, int x, int y, int w, int h)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ if ((m = recttomon(x, y, w, h)) && m != c->mon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ arrange(c->mon);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ selmon = m;
|
||||
+ focus(c);
|
||||
+ }
|
||||
+
|
||||
+ c->isfloating = 1;
|
||||
+ if (riodraw_borders)
|
||||
+ resizeclient(c, x, y, w - (c->bw * 2), h - (c->bw * 2));
|
||||
+ else
|
||||
+ resizeclient(c, x - c->bw, y - c->bw, w, h);
|
||||
+ arrange(c->mon);
|
||||
+
|
||||
+ riodimensions[3] = -1;
|
||||
+ riopid = 0;
|
||||
+}
|
||||
+
|
||||
+/* drag out an area using slop and resize the selected window to it */
|
||||
+void
|
||||
+rioresize(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = (arg && arg->v ? (Client*)arg->v : selmon->sel);
|
||||
+ if (c)
|
||||
+ riodraw(c, slopresizestyle);
|
||||
+}
|
||||
+
|
||||
+/* spawn a new window and drag out an area using slop to position it */
|
||||
+void
|
||||
+riospawn(const Arg *arg)
|
||||
+{
|
||||
+ if (riodraw_spawnasync) {
|
||||
+ riopid = spawncmd(arg);
|
||||
+ riodraw(NULL, slopspawnstyle);
|
||||
+ } else if (riodraw(NULL, slopspawnstyle))
|
||||
+ riopid = spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
@@ -1643,9 +1811,16 @@ sigchld(int unused)
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
+ spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
+pid_t
|
||||
+spawncmd(const Arg *arg)
|
||||
+{
|
||||
+ pid_t pid;
|
||||
if (arg->v == dmenucmd)
|
||||
dmenumon[0] = '0' + selmon->num;
|
||||
- if (fork() == 0) {
|
||||
+ if ((pid = fork()) == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
setsid();
|
||||
@@ -1654,6 +1829,7 @@ spawn(const Arg *arg)
|
||||
perror(" failed");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+ return pid;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2050,6 +2226,58 @@ view(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+winpid(Window w)
|
||||
+{
|
||||
+ pid_t result = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ xcb_res_client_id_spec_t spec = {0};
|
||||
+ spec.client = w;
|
||||
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
|
||||
+
|
||||
+ xcb_generic_error_t *e = NULL;
|
||||
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
|
||||
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
|
||||
+
|
||||
+ if (!r)
|
||||
+ return (pid_t)0;
|
||||
+
|
||||
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
|
||||
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
|
||||
+ spec = i.data->spec;
|
||||
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
|
||||
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
|
||||
+ result = *t;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ free(r);
|
||||
+
|
||||
+ if (result == (pid_t)-1)
|
||||
+ result = 0;
|
||||
+
|
||||
+#endif /* __linux__ */
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ Atom type;
|
||||
+ int format;
|
||||
+ unsigned long len, bytes;
|
||||
+ unsigned char *prop;
|
||||
+ pid_t ret;
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = *(pid_t*)prop;
|
||||
+ XFree(prop);
|
||||
+ result = ret;
|
||||
+
|
||||
+#endif /* __OpenBSD__ */
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
Client *
|
||||
wintoclient(Window w)
|
||||
{
|
||||
@@ -2141,6 +2369,8 @@ main(int argc, char *argv[])
|
||||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("dwm: cannot open display");
|
||||
+ if (!(xcon = XGetXCBConnection(dpy)))
|
||||
+ die("dwm: cannot get xcb connection\n");
|
||||
checkotherwm();
|
||||
setup();
|
||||
#ifdef __OpenBSD__
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,126 @@
|
||||
From b99f734407e5a60b7250f4e109e9f03f2de0b7f2 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:35:44 +0100
|
||||
Subject: [PATCH 2/2] Adding riodraw patch with no PID matching
|
||||
|
||||
---
|
||||
config.def.h | 1 -
|
||||
dwm.c | 55 +++++++---------------------------------------------
|
||||
2 files changed, 7 insertions(+), 49 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index bbbc6ca..bb3d58f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -8,7 +8,6 @@ static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char slopspawnstyle[] = "-t 0 -c 0.92,0.85,0.69,0.3 -o"; /* do NOT define -f (format) here */
|
||||
static const char slopresizestyle[] = "-t 0 -c 0.92,0.85,0.69,0.3"; /* do NOT define -f (format) here */
|
||||
static const int riodraw_borders = 0; /* 0 or 1, indicates whether the area drawn using slop includes the window borders */
|
||||
-static const int riodraw_matchpid = 1; /* 0 or 1, indicates whether to match the PID of the client that was spawned with riospawn */
|
||||
static const int riodraw_spawnasync = 0; /* 0 means that the application is only spawned after a successful selection while
|
||||
* 1 means that the application is being initialised in the background while the selection is made */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 95cfcb5..0a72d89 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -177,14 +177,12 @@ static void focusin(XEvent *e);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static Atom getatomprop(Client *c, Atom prop);
|
||||
-static pid_t getparentprocess(pid_t p);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
-static int isdescprocess(pid_t p, pid_t c);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
@@ -893,39 +891,6 @@ getatomprop(Client *c, Atom prop)
|
||||
return atom;
|
||||
}
|
||||
|
||||
-pid_t
|
||||
-getparentprocess(pid_t p)
|
||||
-{
|
||||
- unsigned int v = 0;
|
||||
-
|
||||
-#ifdef __linux__
|
||||
- FILE *f;
|
||||
- char buf[256];
|
||||
- snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
|
||||
-
|
||||
- if (!(f = fopen(buf, "r")))
|
||||
- return 0;
|
||||
-
|
||||
- fscanf(f, "%*u %*s %*c %u", &v);
|
||||
- fclose(f);
|
||||
-#endif /* __linux__*/
|
||||
-
|
||||
-#ifdef __OpenBSD__
|
||||
- int n;
|
||||
- kvm_t *kd;
|
||||
- struct kinfo_proc *kp;
|
||||
-
|
||||
- kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
- if (!kd)
|
||||
- return 0;
|
||||
-
|
||||
- kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
- v = kp->p_ppid;
|
||||
-#endif /* __OpenBSD__ */
|
||||
-
|
||||
- return (pid_t)v;
|
||||
-}
|
||||
-
|
||||
int
|
||||
getrootptr(int *x, int *y)
|
||||
{
|
||||
@@ -1025,15 +990,6 @@ incnmaster(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
-int
|
||||
-isdescprocess(pid_t p, pid_t c)
|
||||
-{
|
||||
- while (p != c && c != 0)
|
||||
- c = getparentprocess(c);
|
||||
-
|
||||
- return (int)c;
|
||||
-}
|
||||
-
|
||||
#ifdef XINERAMA
|
||||
static int
|
||||
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
||||
@@ -1137,7 +1093,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
|
||||
- if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
||||
+ if (riopid) {
|
||||
if (riodimensions[3] != -1)
|
||||
rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
else {
|
||||
@@ -1535,10 +1491,13 @@ void
|
||||
riospawn(const Arg *arg)
|
||||
{
|
||||
if (riodraw_spawnasync) {
|
||||
- riopid = spawncmd(arg);
|
||||
+ spawn(arg);
|
||||
+ riopid = 1;
|
||||
riodraw(NULL, slopspawnstyle);
|
||||
- } else if (riodraw(NULL, slopspawnstyle))
|
||||
- riopid = spawncmd(arg);
|
||||
+ } else if (riodraw(NULL, slopspawnstyle)) {
|
||||
+ spawn(arg);
|
||||
+ riopid = 1;
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,578 @@
|
||||
From bd42e1d726234a591e0f08f4de2360fb5c051d6d Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:32:43 +0100
|
||||
Subject: [PATCH 1/2] Adding rio-like draw-to-resize windows.
|
||||
|
||||
This was backported from instantWM and depends on an external tool
|
||||
slop to be installed.
|
||||
|
||||
Contributed by jzbor.
|
||||
---
|
||||
config.def.h | 8 ++
|
||||
config.mk | 6 +-
|
||||
dwm.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
3 files changed, 248 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..bbbc6ca 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,12 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char slopspawnstyle[] = "-t 0 -c 0.92,0.85,0.69,0.3 -o"; /* do NOT define -f (format) here */
|
||||
+static const char slopresizestyle[] = "-t 0 -c 0.92,0.85,0.69,0.3"; /* do NOT define -f (format) here */
|
||||
+static const int riodraw_borders = 0; /* 0 or 1, indicates whether the area drawn using slop includes the window borders */
|
||||
+static const int riodraw_matchpid = 1; /* 0 or 1, indicates whether to match the PID of the client that was spawned with riospawn */
|
||||
+static const int riodraw_spawnasync = 0; /* 0 means that the application is only spawned after a successful selection while
|
||||
+ * 1 means that the application is being initialised in the background while the selection is made */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -64,6 +70,8 @@ static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY|ControlMask, XK_Return, riospawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_s, rioresize, {0} },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/config.mk b/config.mk
|
||||
index b6eb7e0..ee5c46e 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -19,10 +19,14 @@ FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = ${X11INC}/freetype2
|
||||
+#KVMLIB = -lkvm
|
||||
+
|
||||
+# This is needed for the swallow patch
|
||||
+XCBLIBS = -lX11-xcb -lxcb -lxcb-res
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XCBLIBS} ${KVMLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..95cfcb5 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -40,6 +40,12 @@
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif /* XINERAMA */
|
||||
#include <X11/Xft/Xft.h>
|
||||
+#include <X11/Xlib-xcb.h>
|
||||
+#include <xcb/res.h>
|
||||
+#ifdef __OpenBSD__
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <kvm.h>
|
||||
+#endif /* __OpenBSD */
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
@@ -48,7 +54,7 @@
|
||||
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#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)))
|
||||
+ * 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 LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
@@ -61,11 +67,11 @@
|
||||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||
enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
- NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
- ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
|
||||
typedef union {
|
||||
int i;
|
||||
@@ -93,6 +99,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ pid_t pid;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -170,12 +177,14 @@ static void focusin(XEvent *e);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static Atom getatomprop(Client *c, Atom prop);
|
||||
+static pid_t getparentprocess(pid_t p);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
+static int isdescprocess(pid_t p, pid_t c);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
@@ -193,6 +202,10 @@ static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
+static int riodraw(Client *c, const char slopstyle[]);
|
||||
+static void rioposition(Client *c, int x, int y, int w, int h);
|
||||
+static void rioresize(const Arg *arg);
|
||||
+static void riospawn(const Arg *arg);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
@@ -207,6 +220,7 @@ static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static pid_t spawncmd(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
@@ -228,6 +242,7 @@ static void updatetitle(Client *c);
|
||||
static void updatewindowtype(Client *c);
|
||||
static void updatewmhints(Client *c);
|
||||
static void view(const Arg *arg);
|
||||
+static pid_t winpid(Window w);
|
||||
static Client *wintoclient(Window w);
|
||||
static Monitor *wintomon(Window w);
|
||||
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||
@@ -244,6 +259,8 @@ static int bh, blw = 0; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
+static int riodimensions[4] = { -1, -1, -1, -1 };
|
||||
+static pid_t riopid = 0;
|
||||
static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[ButtonPress] = buttonpress,
|
||||
[ClientMessage] = clientmessage,
|
||||
@@ -268,6 +285,7 @@ static Display *dpy;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
+static xcb_connection_t *xcon;
|
||||
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
@@ -875,6 +893,39 @@ getatomprop(Client *c, Atom prop)
|
||||
return atom;
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+getparentprocess(pid_t p)
|
||||
+{
|
||||
+ unsigned int v = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ FILE *f;
|
||||
+ char buf[256];
|
||||
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
|
||||
+
|
||||
+ if (!(f = fopen(buf, "r")))
|
||||
+ return 0;
|
||||
+
|
||||
+ fscanf(f, "%*u %*s %*c %u", &v);
|
||||
+ fclose(f);
|
||||
+#endif /* __linux__*/
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ int n;
|
||||
+ kvm_t *kd;
|
||||
+ struct kinfo_proc *kp;
|
||||
+
|
||||
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
+ if (!kd)
|
||||
+ return 0;
|
||||
+
|
||||
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
+ v = kp->p_ppid;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ return (pid_t)v;
|
||||
+}
|
||||
+
|
||||
int
|
||||
getrootptr(int *x, int *y)
|
||||
{
|
||||
@@ -974,6 +1025,15 @@ incnmaster(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+int
|
||||
+isdescprocess(pid_t p, pid_t c)
|
||||
+{
|
||||
+ while (p != c && c != 0)
|
||||
+ c = getparentprocess(c);
|
||||
+
|
||||
+ return (int)c;
|
||||
+}
|
||||
+
|
||||
#ifdef XINERAMA
|
||||
static int
|
||||
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
||||
@@ -1027,6 +1087,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
+ c->pid = winpid(w);
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
@@ -1075,6 +1136,15 @@ manage(Window w, XWindowAttributes *wa)
|
||||
if (c->mon == selmon)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
+
|
||||
+ if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
||||
+ if (riodimensions[3] != -1)
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ else {
|
||||
+ killclient(&((Arg) { .v = c }));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
focus(NULL);
|
||||
@@ -1373,6 +1443,104 @@ restack(Monitor *m)
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
+int
|
||||
+riodraw(Client *c, const char slopstyle[])
|
||||
+{
|
||||
+ int i;
|
||||
+ char str[100] = {0};
|
||||
+ char strout[100] = {0};
|
||||
+ char tmpstring[30] = {0};
|
||||
+ char slopcmd[100] = "slop -f x%xx%yx%wx%hx ";
|
||||
+ int firstchar = 0;
|
||||
+ int counter = 0;
|
||||
+
|
||||
+ strcat(slopcmd, slopstyle);
|
||||
+ FILE *fp = popen(slopcmd, "r");
|
||||
+
|
||||
+ while (fgets(str, 100, fp) != NULL)
|
||||
+ strcat(strout, str);
|
||||
+
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ if (strlen(strout) < 6)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < strlen(strout); i++){
|
||||
+ if (!firstchar) {
|
||||
+ if (strout[i] == 'x')
|
||||
+ firstchar = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strout[i] != 'x')
|
||||
+ tmpstring[strlen(tmpstring)] = strout[i];
|
||||
+ else {
|
||||
+ riodimensions[counter] = atoi(tmpstring);
|
||||
+ counter++;
|
||||
+ memset(tmpstring,0,strlen(tmpstring));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (riodimensions[0] <= -40 || riodimensions[1] <= -40 || riodimensions[2] <= 50 || riodimensions[3] <= 50) {
|
||||
+ riodimensions[3] = -1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (c) {
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+rioposition(Client *c, int x, int y, int w, int h)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ if ((m = recttomon(x, y, w, h)) && m != c->mon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ arrange(c->mon);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ selmon = m;
|
||||
+ focus(c);
|
||||
+ }
|
||||
+
|
||||
+ c->isfloating = 1;
|
||||
+ if (riodraw_borders)
|
||||
+ resizeclient(c, x, y, w - (c->bw * 2), h - (c->bw * 2));
|
||||
+ else
|
||||
+ resizeclient(c, x - c->bw, y - c->bw, w, h);
|
||||
+ arrange(c->mon);
|
||||
+
|
||||
+ riodimensions[3] = -1;
|
||||
+ riopid = 0;
|
||||
+}
|
||||
+
|
||||
+/* drag out an area using slop and resize the selected window to it */
|
||||
+void
|
||||
+rioresize(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = (arg && arg->v ? (Client*)arg->v : selmon->sel);
|
||||
+ if (c)
|
||||
+ riodraw(c, slopresizestyle);
|
||||
+}
|
||||
+
|
||||
+/* spawn a new window and drag out an area using slop to position it */
|
||||
+void
|
||||
+riospawn(const Arg *arg)
|
||||
+{
|
||||
+ if (riodraw_spawnasync) {
|
||||
+ riopid = spawncmd(arg);
|
||||
+ riodraw(NULL, slopspawnstyle);
|
||||
+ } else if (riodraw(NULL, slopspawnstyle))
|
||||
+ riopid = spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
@@ -1643,9 +1811,16 @@ sigchld(int unused)
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
+ spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
+pid_t
|
||||
+spawncmd(const Arg *arg)
|
||||
+{
|
||||
+ pid_t pid;
|
||||
if (arg->v == dmenucmd)
|
||||
dmenumon[0] = '0' + selmon->num;
|
||||
- if (fork() == 0) {
|
||||
+ if ((pid = fork()) == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
setsid();
|
||||
@@ -1654,6 +1829,7 @@ spawn(const Arg *arg)
|
||||
perror(" failed");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+ return pid;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2050,6 +2226,58 @@ view(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+winpid(Window w)
|
||||
+{
|
||||
+ pid_t result = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ xcb_res_client_id_spec_t spec = {0};
|
||||
+ spec.client = w;
|
||||
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
|
||||
+
|
||||
+ xcb_generic_error_t *e = NULL;
|
||||
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
|
||||
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
|
||||
+
|
||||
+ if (!r)
|
||||
+ return (pid_t)0;
|
||||
+
|
||||
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
|
||||
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
|
||||
+ spec = i.data->spec;
|
||||
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
|
||||
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
|
||||
+ result = *t;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ free(r);
|
||||
+
|
||||
+ if (result == (pid_t)-1)
|
||||
+ result = 0;
|
||||
+
|
||||
+#endif /* __linux__ */
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ Atom type;
|
||||
+ int format;
|
||||
+ unsigned long len, bytes;
|
||||
+ unsigned char *prop;
|
||||
+ pid_t ret;
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = *(pid_t*)prop;
|
||||
+ XFree(prop);
|
||||
+ result = ret;
|
||||
+
|
||||
+#endif /* __OpenBSD__ */
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
Client *
|
||||
wintoclient(Window w)
|
||||
{
|
||||
@@ -2141,6 +2369,8 @@ main(int argc, char *argv[])
|
||||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("dwm: cannot open display");
|
||||
+ if (!(xcon = XGetXCBConnection(dpy)))
|
||||
+ die("dwm: cannot get xcb connection\n");
|
||||
checkotherwm();
|
||||
setup();
|
||||
#ifdef __OpenBSD__
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From b99f734407e5a60b7250f4e109e9f03f2de0b7f2 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:35:44 +0100
|
||||
Subject: [PATCH 2/2] Adding riodraw patch with no PID matching
|
||||
|
||||
---
|
||||
config.def.h | 1 -
|
||||
dwm.c | 55 +++++++---------------------------------------------
|
||||
2 files changed, 7 insertions(+), 49 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index bbbc6ca..bb3d58f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -8,7 +8,6 @@ static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char slopspawnstyle[] = "-t 0 -c 0.92,0.85,0.69,0.3 -o"; /* do NOT define -f (format) here */
|
||||
static const char slopresizestyle[] = "-t 0 -c 0.92,0.85,0.69,0.3"; /* do NOT define -f (format) here */
|
||||
static const int riodraw_borders = 0; /* 0 or 1, indicates whether the area drawn using slop includes the window borders */
|
||||
-static const int riodraw_matchpid = 1; /* 0 or 1, indicates whether to match the PID of the client that was spawned with riospawn */
|
||||
static const int riodraw_spawnasync = 0; /* 0 means that the application is only spawned after a successful selection while
|
||||
* 1 means that the application is being initialised in the background while the selection is made */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 95cfcb5..0a72d89 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -177,14 +177,12 @@ static void focusin(XEvent *e);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static Atom getatomprop(Client *c, Atom prop);
|
||||
-static pid_t getparentprocess(pid_t p);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys(void);
|
||||
static void incnmaster(const Arg *arg);
|
||||
-static int isdescprocess(pid_t p, pid_t c);
|
||||
static void keypress(XEvent *e);
|
||||
static void killclient(const Arg *arg);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
@@ -893,39 +891,6 @@ getatomprop(Client *c, Atom prop)
|
||||
return atom;
|
||||
}
|
||||
|
||||
-pid_t
|
||||
-getparentprocess(pid_t p)
|
||||
-{
|
||||
- unsigned int v = 0;
|
||||
-
|
||||
-#ifdef __linux__
|
||||
- FILE *f;
|
||||
- char buf[256];
|
||||
- snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
|
||||
-
|
||||
- if (!(f = fopen(buf, "r")))
|
||||
- return 0;
|
||||
-
|
||||
- fscanf(f, "%*u %*s %*c %u", &v);
|
||||
- fclose(f);
|
||||
-#endif /* __linux__*/
|
||||
-
|
||||
-#ifdef __OpenBSD__
|
||||
- int n;
|
||||
- kvm_t *kd;
|
||||
- struct kinfo_proc *kp;
|
||||
-
|
||||
- kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
- if (!kd)
|
||||
- return 0;
|
||||
-
|
||||
- kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
- v = kp->p_ppid;
|
||||
-#endif /* __OpenBSD__ */
|
||||
-
|
||||
- return (pid_t)v;
|
||||
-}
|
||||
-
|
||||
int
|
||||
getrootptr(int *x, int *y)
|
||||
{
|
||||
@@ -1025,15 +990,6 @@ incnmaster(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
-int
|
||||
-isdescprocess(pid_t p, pid_t c)
|
||||
-{
|
||||
- while (p != c && c != 0)
|
||||
- c = getparentprocess(c);
|
||||
-
|
||||
- return (int)c;
|
||||
-}
|
||||
-
|
||||
#ifdef XINERAMA
|
||||
static int
|
||||
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
||||
@@ -1137,7 +1093,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
|
||||
- if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
||||
+ if (riopid) {
|
||||
if (riodimensions[3] != -1)
|
||||
rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
else {
|
||||
@@ -1535,10 +1491,13 @@ void
|
||||
riospawn(const Arg *arg)
|
||||
{
|
||||
if (riodraw_spawnasync) {
|
||||
- riopid = spawncmd(arg);
|
||||
+ spawn(arg);
|
||||
+ riopid = 1;
|
||||
riodraw(NULL, slopspawnstyle);
|
||||
- } else if (riodraw(NULL, slopspawnstyle))
|
||||
- riopid = spawncmd(arg);
|
||||
+ } else if (riodraw(NULL, slopspawnstyle)) {
|
||||
+ spawn(arg);
|
||||
+ riopid = 1;
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,121 @@
|
||||
From b1026a04c1c7c49826a17d1aca2e44f59f4b5bf3 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:36:14 +0100
|
||||
Subject: [PATCH] rotatestack, allows you to scroll through the stack
|
||||
|
||||
Stack rotation moves a client from the bottom to the top of the stack (or the other way round). This effectively rotates the clients by one position clockwise (or CCW, respectively).
|
||||
|
||||
It should play well with arbitrary stack layouts and nmaster values.
|
||||
|
||||
One may think of it as moving the zoom through the list of clients, very much in the same way as scrolling moves the view port around a pane.
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/rotatestack/
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 58 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..546087f 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -67,6 +67,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
+ { MODKEY|ShiftMask, XK_j, rotatestack, {.i = +1 } },
|
||||
+ { MODKEY|ShiftMask, XK_k, rotatestack, {.i = -1 } },
|
||||
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..091cc8a 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -163,6 +163,8 @@ static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
+static void enqueue(Client *c);
|
||||
+static void enqueuestack(Client *c);
|
||||
static void enternotify(XEvent *e);
|
||||
static void expose(XEvent *e);
|
||||
static void focus(Client *c);
|
||||
@@ -193,6 +195,7 @@ static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
+static void rotatestack(const Arg *arg);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
@@ -755,6 +758,28 @@ drawbars(void)
|
||||
drawbar(m);
|
||||
}
|
||||
|
||||
+void
|
||||
+enqueue(Client *c)
|
||||
+{
|
||||
+ Client *l;
|
||||
+ for (l = c->mon->clients; l && l->next; l = l->next);
|
||||
+ if (l) {
|
||||
+ l->next = c;
|
||||
+ c->next = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+enqueuestack(Client *c)
|
||||
+{
|
||||
+ Client *l;
|
||||
+ for (l = c->mon->stack; l && l->snext; l = l->snext);
|
||||
+ if (l) {
|
||||
+ l->snext = c;
|
||||
+ c->snext = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
enternotify(XEvent *e)
|
||||
{
|
||||
@@ -1373,6 +1398,37 @@ restack(Monitor *m)
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
+void
|
||||
+rotatestack(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = NULL, *f;
|
||||
+
|
||||
+ if (!selmon->sel)
|
||||
+ return;
|
||||
+ f = selmon->sel;
|
||||
+ if (arg->i > 0) {
|
||||
+ for (c = nexttiled(selmon->clients); c && nexttiled(c->next); c = nexttiled(c->next));
|
||||
+ if (c){
|
||||
+ detach(c);
|
||||
+ attach(c);
|
||||
+ detachstack(c);
|
||||
+ attachstack(c);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if ((c = nexttiled(selmon->clients))){
|
||||
+ detach(c);
|
||||
+ enqueue(c);
|
||||
+ detachstack(c);
|
||||
+ enqueuestack(c);
|
||||
+ }
|
||||
+ }
|
||||
+ if (c){
|
||||
+ arrange(selmon);
|
||||
+ focus(f);
|
||||
+ restack(selmon);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,55 @@
|
||||
From d8cd51f56a9089aa2d492ddbce88c2e563633c8d Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:37:00 +0100
|
||||
Subject: [PATCH] Savefloats, saves size and position of floating windows
|
||||
|
||||
Refer to https://dwm.suckless.org/patches/save_floats/
|
||||
---
|
||||
dwm.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..faa3c54 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -88,6 +88,7 @@ struct Client {
|
||||
char name[256];
|
||||
float mina, maxa;
|
||||
int x, y, w, h;
|
||||
+ int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
|
||||
int oldx, oldy, oldw, oldh;
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
int bw, oldbw;
|
||||
@@ -1060,6 +1061,10 @@ manage(Window w, XWindowAttributes *wa)
|
||||
updatewindowtype(c);
|
||||
updatesizehints(c);
|
||||
updatewmhints(c);
|
||||
+ c->sfx = c->x;
|
||||
+ c->sfy = c->y;
|
||||
+ c->sfw = c->w;
|
||||
+ c->sfh = c->h;
|
||||
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
||||
grabbuttons(c, 0);
|
||||
if (!c->isfloating)
|
||||
@@ -1720,8 +1725,16 @@ togglefloating(const Arg *arg)
|
||||
return;
|
||||
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
||||
if (selmon->sel->isfloating)
|
||||
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
||||
- selmon->sel->w, selmon->sel->h, 0);
|
||||
+ /* restore last known float dimensions */
|
||||
+ resize(selmon->sel, selmon->sel->sfx, selmon->sel->sfy,
|
||||
+ selmon->sel->sfw, selmon->sel->sfh, False);
|
||||
+ else {
|
||||
+ /* save last known float dimensions */
|
||||
+ selmon->sel->sfx = selmon->sel->x;
|
||||
+ selmon->sel->sfy = selmon->sel->y;
|
||||
+ selmon->sel->sfw = selmon->sel->w;
|
||||
+ selmon->sel->sfh = selmon->sel->h;
|
||||
+ }
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,40 @@
|
||||
From aa3796065846a03a81c10c9ea5cbcee85ab9e41e Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:37:27 +0100
|
||||
Subject: [PATCH] Adding sendmon_keepfocus patch
|
||||
|
||||
---
|
||||
dwm.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..f46e77e 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -1416,15 +1416,21 @@ sendmon(Client *c, Monitor *m)
|
||||
{
|
||||
if (c->mon == m)
|
||||
return;
|
||||
+ int hadfocus = (c == selmon->sel);
|
||||
unfocus(c, 1);
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
+ arrange(c->mon);
|
||||
c->mon = m;
|
||||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
attach(c);
|
||||
attachstack(c);
|
||||
- focus(NULL);
|
||||
- arrange(NULL);
|
||||
+ arrange(m);
|
||||
+ if (hadfocus) {
|
||||
+ focus(c);
|
||||
+ restack(m);
|
||||
+ } else
|
||||
+ focus(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,86 @@
|
||||
From ad9512714214ea2cfb54babd8fc72de81a094c4b Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:38:05 +0100
|
||||
Subject: [PATCH] This variant of the shiftview patch adds left and right
|
||||
circular shift through tags, but skips tags where there are no clients.
|
||||
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 43 insertions(+)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..ad7cabe 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -73,6 +73,8 @@ static Key keys[] = {
|
||||
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
{ MODKEY, XK_Return, zoom, {0} },
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
+ { MODKEY|ShiftMask, XK_Tab, shiftviewclients, { .i = +1 } },
|
||||
+ { MODKEY|ShiftMask, XK_backslash, shiftviewclients, { .i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..0f8fd34 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -204,6 +204,7 @@ static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setup(void);
|
||||
static void seturgent(Client *c, int urg);
|
||||
+static void shiftviewclients(const Arg *arg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
@@ -1614,6 +1615,46 @@ seturgent(Client *c, int urg)
|
||||
XFree(wmh);
|
||||
}
|
||||
|
||||
+void
|
||||
+shiftviewclients(const Arg *arg)
|
||||
+{
|
||||
+ Arg shifted;
|
||||
+ Client *c;
|
||||
+ unsigned int tagmask = 0;
|
||||
+
|
||||
+ for (c = selmon->clients; c; c = c->next)
|
||||
+ #if SCRATCHPADS_PATCH
|
||||
+ if (!(c->tags & SPTAGMASK))
|
||||
+ tagmask = tagmask | c->tags;
|
||||
+ #else
|
||||
+ tagmask = tagmask | c->tags;
|
||||
+ #endif // SCRATCHPADS_PATCH
|
||||
+
|
||||
+ #if SCRATCHPADS_PATCH
|
||||
+ shifted.ui = selmon->tagset[selmon->seltags] & ~SPTAGMASK;
|
||||
+ #else
|
||||
+ shifted.ui = selmon->tagset[selmon->seltags];
|
||||
+ #endif // SCRATCHPADS_PATCH
|
||||
+ if (arg->i > 0) // left circular shift
|
||||
+ do {
|
||||
+ shifted.ui = (shifted.ui << arg->i)
|
||||
+ | (shifted.ui >> (LENGTH(tags) - arg->i));
|
||||
+ #if SCRATCHPADS_PATCH
|
||||
+ shifted.ui &= ~SPTAGMASK;
|
||||
+ #endif // SCRATCHPADS_PATCH
|
||||
+ } while (tagmask && !(shifted.ui & tagmask));
|
||||
+ else // right circular shift
|
||||
+ do {
|
||||
+ shifted.ui = (shifted.ui >> (- arg->i)
|
||||
+ | shifted.ui << (LENGTH(tags) + arg->i));
|
||||
+ #if SCRATCHPADS_PATCH
|
||||
+ shifted.ui &= ~SPTAGMASK;
|
||||
+ #endif // SCRATCHPADS_PATCH
|
||||
+ } while (tagmask && !(shifted.ui & tagmask));
|
||||
+
|
||||
+ view(&shifted);
|
||||
+}
|
||||
+
|
||||
void
|
||||
showhide(Client *c)
|
||||
{
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,541 @@
|
||||
From 8591e832ea3c584841dfaf71c9e87aea8f01ce9e Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:40:01 +0100
|
||||
Subject: [PATCH] Adding single tagset
|
||||
|
||||
Author: Jan Christoph Ebersbach <jceb@e-jc.de>
|
||||
URL: http://dwm.suckless.org/patches/single_tagset
|
||||
This patch addresses the multi-monitor setup. Instead of having separate tags
|
||||
for every monitor there is just one list of tags for all monitors. Instead of
|
||||
moving windows from one monitor to the other, the desired tag from the
|
||||
other monitor can just be selected and all windows will be drawn on the
|
||||
current monitor.
|
||||
|
||||
Several deep changes needed to be made:
|
||||
1. Macro ISVISIBLE expects a second parameter, the monitor
|
||||
2. Monitor->clients and Monitor->stack were moved to the global variable
|
||||
Clientlist cl. All monitors refer to this one list.
|
||||
3. A new method attachclients was added. When changing between tags this
|
||||
function ensures that all clients are pointing to the right monitor.
|
||||
|
||||
Please be aware that this patch probably breaks any other patch!
|
||||
---
|
||||
dwm.c | 214 +++++++++++++++++++++++++++++++++++++++++++---------------
|
||||
1 file changed, 159 insertions(+), 55 deletions(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..81eec26 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -49,7 +49,7 @@
|
||||
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
||||
#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 ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags]))
|
||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
|
||||
@@ -82,6 +82,7 @@ typedef struct {
|
||||
const Arg arg;
|
||||
} Button;
|
||||
|
||||
+typedef struct Clientlist Clientlist;
|
||||
typedef struct Monitor Monitor;
|
||||
typedef struct Client Client;
|
||||
struct Client {
|
||||
@@ -124,14 +125,18 @@ struct Monitor {
|
||||
unsigned int tagset[2];
|
||||
int showbar;
|
||||
int topbar;
|
||||
- Client *clients;
|
||||
+ Clientlist *cl;
|
||||
Client *sel;
|
||||
- Client *stack;
|
||||
Monitor *next;
|
||||
Window barwin;
|
||||
const Layout *lt[2];
|
||||
};
|
||||
|
||||
+struct Clientlist {
|
||||
+ Client *clients;
|
||||
+ Client *stack;
|
||||
+};
|
||||
+
|
||||
typedef struct {
|
||||
const char *class;
|
||||
const char *instance;
|
||||
@@ -147,6 +152,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac
|
||||
static void arrange(Monitor *m);
|
||||
static void arrangemon(Monitor *m);
|
||||
static void attach(Client *c);
|
||||
+static void attachclients(Monitor *m);
|
||||
static void attachstack(Client *c);
|
||||
static void buttonpress(XEvent *e);
|
||||
static void checkotherwm(void);
|
||||
@@ -184,7 +190,7 @@ static void maprequest(XEvent *e);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionnotify(XEvent *e);
|
||||
static void movemouse(const Arg *arg);
|
||||
-static Client *nexttiled(Client *c);
|
||||
+static Client *nexttiled(Client *c, Monitor *m);
|
||||
static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
@@ -268,6 +274,7 @@ static Display *dpy;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
+static Clientlist *cl;
|
||||
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
@@ -300,7 +307,7 @@ applyrules(Client *c)
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
- for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
+ for (m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next) ;
|
||||
if (m)
|
||||
c->mon = m;
|
||||
}
|
||||
@@ -382,9 +389,9 @@ void
|
||||
arrange(Monitor *m)
|
||||
{
|
||||
if (m)
|
||||
- showhide(m->stack);
|
||||
+ showhide(m->cl->stack);
|
||||
else for (m = mons; m; m = m->next)
|
||||
- showhide(m->stack);
|
||||
+ showhide(m->cl->stack);
|
||||
if (m) {
|
||||
arrangemon(m);
|
||||
restack(m);
|
||||
@@ -403,15 +410,48 @@ arrangemon(Monitor *m)
|
||||
void
|
||||
attach(Client *c)
|
||||
{
|
||||
- c->next = c->mon->clients;
|
||||
- c->mon->clients = c;
|
||||
+ c->next = c->mon->cl->clients;
|
||||
+ c->mon->cl->clients = c;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+attachclients(Monitor *m) {
|
||||
+ /* attach clients to the specified monitor */
|
||||
+ Monitor *tm;
|
||||
+ Client *c;
|
||||
+ unsigned int utags = 0;
|
||||
+ Bool rmons = False;
|
||||
+ if (!m)
|
||||
+ return;
|
||||
+
|
||||
+ /* collect information about the tags in use */
|
||||
+ for (tm = mons; tm; tm = tm->next)
|
||||
+ if(tm != m)
|
||||
+ utags |= tm->tagset[tm->seltags];
|
||||
+
|
||||
+ for (c = m->cl->clients; c; c = c->next)
|
||||
+ if (ISVISIBLE(c, m)) {
|
||||
+ /* if client is also visible on other tags that are displayed on
|
||||
+ * other monitors, remove these tags */
|
||||
+ if (c->tags & utags) {
|
||||
+ c->tags = c->tags & m->tagset[m->seltags];
|
||||
+ rmons = True;
|
||||
+ }
|
||||
+ unfocus(c, True);
|
||||
+ c->mon = m;
|
||||
+ }
|
||||
+
|
||||
+ if (rmons)
|
||||
+ for (tm = mons; tm; tm = tm->next)
|
||||
+ if(tm != m)
|
||||
+ arrange(tm);
|
||||
}
|
||||
|
||||
void
|
||||
attachstack(Client *c)
|
||||
{
|
||||
- c->snext = c->mon->stack;
|
||||
- c->mon->stack = c;
|
||||
+ c->snext = c->mon->cl->stack;
|
||||
+ c->mon->cl->stack = c;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -478,8 +518,8 @@ cleanup(void)
|
||||
view(&a);
|
||||
selmon->lt[selmon->sellt] = &foo;
|
||||
for (m = mons; m; m = m->next)
|
||||
- while (m->stack)
|
||||
- unmanage(m->stack, 0);
|
||||
+ while (m->cl->stack)
|
||||
+ unmanage(m->cl->stack, 0);
|
||||
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||
while (mons)
|
||||
cleanupmon(mons);
|
||||
@@ -565,7 +605,7 @@ configurenotify(XEvent *e)
|
||||
drw_resize(drw, sw, bh);
|
||||
updatebars();
|
||||
for (m = mons; m; m = m->next) {
|
||||
- for (c = m->clients; c; c = c->next)
|
||||
+ for (c = m->cl->clients; c; c = c->next)
|
||||
if (c->isfullscreen)
|
||||
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
||||
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
||||
@@ -611,7 +651,7 @@ configurerequest(XEvent *e)
|
||||
c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
|
||||
if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
|
||||
configure(c);
|
||||
- if (ISVISIBLE(c))
|
||||
+ if (ISVISIBLE(c, m))
|
||||
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
|
||||
} else
|
||||
configure(c);
|
||||
@@ -631,10 +671,32 @@ configurerequest(XEvent *e)
|
||||
Monitor *
|
||||
createmon(void)
|
||||
{
|
||||
- Monitor *m;
|
||||
+ Monitor *m, *tm;
|
||||
+ int i;
|
||||
+
|
||||
+ /* bail out if the number of monitors exceeds the number of tags */
|
||||
+ for (i=1, tm=mons; tm; i++, tm=tm->next);
|
||||
+ if (i > LENGTH(tags)) {
|
||||
+ fprintf(stderr, "dwm: failed to add monitor, number of tags exceeded\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ /* find the first tag that isn't in use */
|
||||
+ for (i=0; i < LENGTH(tags); i++) {
|
||||
+ for (tm=mons; tm && !(tm->tagset[tm->seltags] & (1<<i)); tm=tm->next);
|
||||
+ if (!tm)
|
||||
+ break;
|
||||
+ }
|
||||
+ /* reassign all tags to monitors since there's currently no free tag for the
|
||||
+ * new monitor */
|
||||
+ if (i >= LENGTH(tags))
|
||||
+ for (i=0, tm=mons; tm; tm=tm->next, i++) {
|
||||
+ tm->seltags ^= 1;
|
||||
+ tm->tagset[tm->seltags] = (1<<i) & TAGMASK;
|
||||
+ }
|
||||
|
||||
m = ecalloc(1, sizeof(Monitor));
|
||||
- m->tagset[0] = m->tagset[1] = 1;
|
||||
+ m->cl = cl;
|
||||
+ m->tagset[0] = m->tagset[1] = (1<<i) & TAGMASK;
|
||||
m->mfact = mfact;
|
||||
m->nmaster = nmaster;
|
||||
m->showbar = showbar;
|
||||
@@ -660,7 +722,7 @@ detach(Client *c)
|
||||
{
|
||||
Client **tc;
|
||||
|
||||
- for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
|
||||
+ for (tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next);
|
||||
*tc = c->next;
|
||||
}
|
||||
|
||||
@@ -669,11 +731,11 @@ detachstack(Client *c)
|
||||
{
|
||||
Client **tc, *t;
|
||||
|
||||
- for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
|
||||
+ for (tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext);
|
||||
*tc = c->snext;
|
||||
|
||||
if (c == c->mon->sel) {
|
||||
- for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
|
||||
+ for (t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext);
|
||||
c->mon->sel = t;
|
||||
}
|
||||
}
|
||||
@@ -712,7 +774,7 @@ drawbar(Monitor *m)
|
||||
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
}
|
||||
|
||||
- for (c = m->clients; c; c = c->next) {
|
||||
+ for (c = m->cl->clients; c; c = c->next) {
|
||||
occ |= c->tags;
|
||||
if (c->isurgent)
|
||||
urg |= c->tags;
|
||||
@@ -787,8 +849,8 @@ expose(XEvent *e)
|
||||
void
|
||||
focus(Client *c)
|
||||
{
|
||||
- if (!c || !ISVISIBLE(c))
|
||||
- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
||||
+ if (!c || !ISVISIBLE(c, selmon))
|
||||
+ for (c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext);
|
||||
if (selmon->sel && selmon->sel != c)
|
||||
unfocus(selmon->sel, 0);
|
||||
if (c) {
|
||||
@@ -841,16 +903,16 @@ focusstack(const Arg *arg)
|
||||
if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
||||
return;
|
||||
if (arg->i > 0) {
|
||||
- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
+ for (c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next);
|
||||
if (!c)
|
||||
- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
|
||||
+ for (c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next);
|
||||
} else {
|
||||
- for (i = selmon->clients; i != selmon->sel; i = i->next)
|
||||
- if (ISVISIBLE(i))
|
||||
+ for (i = selmon->cl->clients; i != selmon->sel; i = i->next)
|
||||
+ if (ISVISIBLE(i, selmon))
|
||||
c = i;
|
||||
if (!c)
|
||||
for (; i; i = i->next)
|
||||
- if (ISVISIBLE(i))
|
||||
+ if (ISVISIBLE(i, selmon))
|
||||
c = i;
|
||||
}
|
||||
if (c) {
|
||||
@@ -1110,12 +1172,12 @@ monocle(Monitor *m)
|
||||
unsigned int n = 0;
|
||||
Client *c;
|
||||
|
||||
- for (c = m->clients; c; c = c->next)
|
||||
- if (ISVISIBLE(c))
|
||||
+ for (c = m->cl->clients; c; c = c->next)
|
||||
+ if (ISVISIBLE(c, m))
|
||||
n++;
|
||||
if (n > 0) /* override layout symbol */
|
||||
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
|
||||
- for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
|
||||
+ for (c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m))
|
||||
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
|
||||
}
|
||||
|
||||
@@ -1197,9 +1259,9 @@ movemouse(const Arg *arg)
|
||||
}
|
||||
|
||||
Client *
|
||||
-nexttiled(Client *c)
|
||||
+nexttiled(Client *c, Monitor *m)
|
||||
{
|
||||
- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
|
||||
+ for (; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -1363,8 +1425,8 @@ restack(Monitor *m)
|
||||
if (m->lt[m->sellt]->arrange) {
|
||||
wc.stack_mode = Below;
|
||||
wc.sibling = m->barwin;
|
||||
- for (c = m->stack; c; c = c->snext)
|
||||
- if (!c->isfloating && ISVISIBLE(c)) {
|
||||
+ for (c = m->cl->stack; c; c = c->snext)
|
||||
+ if (!c->isfloating && ISVISIBLE(c, m)) {
|
||||
XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
|
||||
wc.sibling = c->win;
|
||||
}
|
||||
@@ -1417,11 +1479,9 @@ sendmon(Client *c, Monitor *m)
|
||||
if (c->mon == m)
|
||||
return;
|
||||
unfocus(c, 1);
|
||||
- detach(c);
|
||||
detachstack(c);
|
||||
c->mon = m;
|
||||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||
- attach(c);
|
||||
attachstack(c);
|
||||
focus(NULL);
|
||||
arrange(NULL);
|
||||
@@ -1544,6 +1604,8 @@ setup(void)
|
||||
screen = DefaultScreen(dpy);
|
||||
sw = DisplayWidth(dpy, screen);
|
||||
sh = DisplayHeight(dpy, screen);
|
||||
+ if (!(cl = (Clientlist *)calloc(1, sizeof(Clientlist))))
|
||||
+ die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist));
|
||||
root = RootWindow(dpy, screen);
|
||||
drw = drw_create(dpy, screen, root, sw, sh);
|
||||
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||
@@ -1619,7 +1681,7 @@ showhide(Client *c)
|
||||
{
|
||||
if (!c)
|
||||
return;
|
||||
- if (ISVISIBLE(c)) {
|
||||
+ if (ISVISIBLE(c, c->mon)) {
|
||||
/* show clients top down */
|
||||
XMoveWindow(dpy, c->win, c->x, c->y);
|
||||
if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
|
||||
@@ -1659,7 +1721,22 @@ spawn(const Arg *arg)
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
+ Monitor *m;
|
||||
+ unsigned int newtags;
|
||||
if (selmon->sel && arg->ui & TAGMASK) {
|
||||
+ newtags = arg->ui & TAGMASK;
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ /* if tag is visible on another monitor, move client to the new monitor */
|
||||
+ if (m != selmon && m->tagset[m->seltags] & newtags) {
|
||||
+ /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */
|
||||
+ if(newtags & selmon->tagset[selmon->seltags])
|
||||
+ return;
|
||||
+ selmon->sel->tags = newtags;
|
||||
+ selmon->sel->mon = m;
|
||||
+ arrange(m);
|
||||
+ break;
|
||||
+ }
|
||||
+ /* workaround in case just one monitor is connected */
|
||||
selmon->sel->tags = arg->ui & TAGMASK;
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
@@ -1680,7 +1757,7 @@ tile(Monitor *m)
|
||||
unsigned int i, n, h, mw, my, ty;
|
||||
Client *c;
|
||||
|
||||
- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
+ for (n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++);
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
@@ -1688,7 +1765,7 @@ tile(Monitor *m)
|
||||
mw = m->nmaster ? m->ww * m->mfact : 0;
|
||||
else
|
||||
mw = m->ww;
|
||||
- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||
+ for (i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++)
|
||||
if (i < m->nmaster) {
|
||||
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
|
||||
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
|
||||
@@ -1728,12 +1805,17 @@ togglefloating(const Arg *arg)
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
+ Monitor *m;
|
||||
unsigned int newtags;
|
||||
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
|
||||
if (newtags) {
|
||||
+ /* prevent adding tags that are in use on other monitors */
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ if (m != selmon && newtags & m->tagset[m->seltags])
|
||||
+ return;
|
||||
selmon->sel->tags = newtags;
|
||||
focus(NULL);
|
||||
arrange(selmon);
|
||||
@@ -1743,12 +1825,17 @@ toggletag(const Arg *arg)
|
||||
void
|
||||
toggleview(const Arg *arg)
|
||||
{
|
||||
+ Monitor *m;
|
||||
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
||||
|
||||
if (newtagset) {
|
||||
+ /* prevent displaying the same tags on multiple monitors */
|
||||
+ for(m = mons; m; m = m->next)
|
||||
+ if(m != selmon && newtagset & m->tagset[m->seltags])
|
||||
+ return;
|
||||
selmon->tagset[selmon->seltags] = newtagset;
|
||||
focus(NULL);
|
||||
- arrange(selmon);
|
||||
+ attachclients(selmon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1847,7 +1934,7 @@ updateclientlist()
|
||||
|
||||
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
||||
for (m = mons; m; m = m->next)
|
||||
- for (c = m->clients; c; c = c->next)
|
||||
+ for (c = m->cl->clients; c; c = c->next)
|
||||
XChangeProperty(dpy, root, netatom[NetClientList],
|
||||
XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
@@ -1877,8 +1964,10 @@ updategeom(void)
|
||||
if (n <= nn) { /* new monitors available */
|
||||
for (i = 0; i < (nn - n); i++) {
|
||||
for (m = mons; m && m->next; m = m->next);
|
||||
- if (m)
|
||||
+ if (m) {
|
||||
m->next = createmon();
|
||||
+ attachclients(m->next);
|
||||
+ }
|
||||
else
|
||||
mons = createmon();
|
||||
}
|
||||
@@ -1898,16 +1987,13 @@ updategeom(void)
|
||||
} else { /* less monitors available nn < n */
|
||||
for (i = nn; i < n; i++) {
|
||||
for (m = mons; m && m->next; m = m->next);
|
||||
- while ((c = m->clients)) {
|
||||
- dirty = 1;
|
||||
- m->clients = c->next;
|
||||
- detachstack(c);
|
||||
- c->mon = mons;
|
||||
- attach(c);
|
||||
- attachstack(c);
|
||||
- }
|
||||
if (m == selmon)
|
||||
selmon = mons;
|
||||
+ for (c = m->cl->clients; c; c = c->next) {
|
||||
+ dirty = True;
|
||||
+ if (c->mon == m)
|
||||
+ c->mon = selmon;
|
||||
+ }
|
||||
cleanupmon(m);
|
||||
}
|
||||
}
|
||||
@@ -2041,13 +2127,31 @@ updatewmhints(Client *c)
|
||||
void
|
||||
view(const Arg *arg)
|
||||
{
|
||||
+ Monitor *m;
|
||||
+ unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1];
|
||||
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
+ /* swap tags when trying to display a tag from another monitor */
|
||||
+ if (arg->ui & TAGMASK)
|
||||
+ newtagset = arg->ui & TAGMASK;
|
||||
+ for (m = mons; m; m = m->next)
|
||||
+ if (m != selmon && newtagset & m->tagset[m->seltags]) {
|
||||
+ /* prevent displaying all tags (MODKEY-0) when multiple monitors
|
||||
+ * are connected */
|
||||
+ if (newtagset & selmon->tagset[selmon->seltags])
|
||||
+ return;
|
||||
+ m->sel = selmon->sel;
|
||||
+ m->seltags ^= 1;
|
||||
+ m->tagset[m->seltags] = selmon->tagset[selmon->seltags];
|
||||
+ attachclients(m);
|
||||
+ arrange(m);
|
||||
+ break;
|
||||
+ }
|
||||
selmon->seltags ^= 1; /* toggle sel tagset */
|
||||
if (arg->ui & TAGMASK)
|
||||
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
||||
focus(NULL);
|
||||
- arrange(selmon);
|
||||
+ attachclients(selmon);
|
||||
}
|
||||
|
||||
Client *
|
||||
@@ -2057,7 +2161,7 @@ wintoclient(Window w)
|
||||
Monitor *m;
|
||||
|
||||
for (m = mons; m; m = m->next)
|
||||
- for (c = m->clients; c; c = c->next)
|
||||
+ for (c = m->cl->clients; c; c = c->next)
|
||||
if (c->win == w)
|
||||
return c;
|
||||
return NULL;
|
||||
@@ -2124,8 +2228,8 @@ zoom(const Arg *arg)
|
||||
if (!selmon->lt[selmon->sellt]->arrange
|
||||
|| (selmon->sel && selmon->sel->isfloating))
|
||||
return;
|
||||
- if (c == nexttiled(selmon->clients))
|
||||
- if (!c || !(c = nexttiled(c->next)))
|
||||
+ if (c == nexttiled(selmon->cl->clients, selmon))
|
||||
+ if (!c || !(c = nexttiled(c->next, selmon)))
|
||||
return;
|
||||
pop(c);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,44 @@
|
||||
From 3c1393381a78b7991e5702a3f2082cbe1352c841 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:40:38 +0100
|
||||
Subject: [PATCH] Workaround for programs like spotify which do not offer
|
||||
instance or class hints when they initially map, resulting in no rules
|
||||
applying
|
||||
|
||||
---
|
||||
dwm.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..51f4900 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -63,7 +63,7 @@ enum { SchemeNorm, SchemeSel }; /* color schemes */
|
||||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
||||
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
||||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
|
||||
-enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
+enum { WMClass, WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||
|
||||
@@ -1246,6 +1246,8 @@ propertynotify(XEvent *e)
|
||||
}
|
||||
if (ev->atom == netatom[NetWMWindowType])
|
||||
updatewindowtype(c);
|
||||
+ if (ev->atom == wmatom[WMClass])
|
||||
+ applyrules(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,6 +1555,7 @@ setup(void)
|
||||
updategeom();
|
||||
/* init atoms */
|
||||
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
+ wmatom[WMClass] = XInternAtom(dpy, "WM_CLASS", False);
|
||||
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
||||
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
||||
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,54 @@
|
||||
From 3b58e394ee65fdbf425746922853b1dc7530daa1 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:42:17 +0100
|
||||
Subject: [PATCH] Adding statuspadding patch
|
||||
|
||||
Refer to:
|
||||
https://dwm.suckless.org/patches/statuspadding/
|
||||
---
|
||||
config.def.h | 2 ++
|
||||
dwm.c | 8 ++++----
|
||||
2 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..6cb845c 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const int horizpadbar = 2; /* horizontal padding for statusbar */
|
||||
+static const int vertpadbar = 0; /* vertical padding for statusbar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..a1b8c95 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -708,8 +708,8 @@ drawbar(Monitor *m)
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
||||
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
|
||||
+ tw = TEXTW(stext);
|
||||
+ drw_text(drw, m->ww - tw, 0, tw, bh, lrpad / 2, stext, 0);
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
@@ -1548,8 +1548,8 @@ setup(void)
|
||||
drw = drw_create(dpy, screen, root, sw, sh);
|
||||
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||
die("no fonts could be loaded.");
|
||||
- lrpad = drw->fonts->h;
|
||||
- bh = drw->fonts->h + 2;
|
||||
+ lrpad = drw->fonts->h + horizpadbar;
|
||||
+ bh = drw->fonts->h + vertpadbar;
|
||||
updategeom();
|
||||
/* init atoms */
|
||||
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,72 @@
|
||||
From 4cc3588c2601e6a2edb8d7117723d28d77f0fc61 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:42:45 +0100
|
||||
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 a96f33c..318491b 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -93,6 +93,7 @@ struct Client {
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int issteam;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
Monitor *mon;
|
||||
@@ -292,6 +293,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))
|
||||
@@ -589,13 +593,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;
|
||||
@@ -1470,6 +1476,8 @@ setfocus(Client *c)
|
||||
XA_WINDOW, 32, PropModeReplace,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
}
|
||||
+ if (c->issteam)
|
||||
+ setclientstate(c, NormalState);
|
||||
sendevent(c, wmatom[WMTakeFocus]);
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,506 @@
|
||||
From 66c7e6fef8a900a03e4ca861fdb11aff1f1af690 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:43:13 +0100
|
||||
Subject: [PATCH] Alternative swallow patch that replaces clients instead of
|
||||
swapping windows offering better resize hints
|
||||
|
||||
---
|
||||
config.def.h | 9 +-
|
||||
config.mk | 6 +-
|
||||
dwm.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
3 files changed, 288 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..dba4b83 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -3,6 +3,7 @@
|
||||
/* appearance */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
+static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
@@ -26,9 +27,11 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating isterminal noswallow monitor */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
|
||||
+ { "St", NULL, NULL, 0, 0, 1, 0, -1 },
|
||||
+ { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/config.mk b/config.mk
|
||||
index b6eb7e0..ee5c46e 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -19,10 +19,14 @@ FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = ${X11INC}/freetype2
|
||||
+#KVMLIB = -lkvm
|
||||
+
|
||||
+# This is needed for the swallow patch
|
||||
+XCBLIBS = -lX11-xcb -lxcb -lxcb-res
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XCBLIBS} ${KVMLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..8735093 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -40,6 +40,12 @@
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif /* XINERAMA */
|
||||
#include <X11/Xft/Xft.h>
|
||||
+#include <X11/Xlib-xcb.h>
|
||||
+#include <xcb/res.h>
|
||||
+#ifdef __OpenBSD__
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <kvm.h>
|
||||
+#endif /* __OpenBSD */
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
@@ -92,9 +98,12 @@ struct Client {
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
|
||||
+ int ignorecfgreqpos, ignorecfgreqsize;
|
||||
+ pid_t pid;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
+ Client *swallowing;
|
||||
Monitor *mon;
|
||||
Window win;
|
||||
};
|
||||
@@ -138,6 +147,8 @@ typedef struct {
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ int isterminal;
|
||||
+ int noswallow;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -189,6 +200,7 @@ static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
+static void replaceclient(Client *old, Client *new);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
@@ -235,6 +247,14 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
+static int swallow(Client *p, Client *c);
|
||||
+static void unswallow(Client *c);
|
||||
+static pid_t getparentprocess(pid_t p);
|
||||
+static int isdescprocess(pid_t p, pid_t c);
|
||||
+static Client *swallowingclient(Window w);
|
||||
+static Client *termforwin(const Client *c);
|
||||
+static pid_t winpid(Window w);
|
||||
+
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
@@ -268,6 +288,7 @@ static Display *dpy;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
+static xcb_connection_t *xcon;
|
||||
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
@@ -298,6 +319,8 @@ applyrules(Client *c)
|
||||
&& (!r->class || strstr(class, r->class))
|
||||
&& (!r->instance || strstr(instance, r->instance)))
|
||||
{
|
||||
+ c->isterminal = r->isterminal;
|
||||
+ c->noswallow = r->noswallow;
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
@@ -588,22 +611,29 @@ configurerequest(XEvent *e)
|
||||
if (ev->value_mask & CWBorderWidth)
|
||||
c->bw = ev->border_width;
|
||||
else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
|
||||
+ if (c->ignorecfgreqpos && c->ignorecfgreqsize)
|
||||
+ return;
|
||||
+
|
||||
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 (ev->value_mask & CWWidth) {
|
||||
- c->oldw = c->w;
|
||||
- c->w = ev->width;
|
||||
+ if (!c->ignorecfgreqpos) {
|
||||
+ 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 & CWHeight) {
|
||||
- c->oldh = c->h;
|
||||
- c->h = ev->height;
|
||||
+ if (!c->ignorecfgreqsize) {
|
||||
+ if (ev->value_mask & CWWidth) {
|
||||
+ c->oldw = c->w;
|
||||
+ c->w = ev->width;
|
||||
+ }
|
||||
+ if (ev->value_mask & CWHeight) {
|
||||
+ c->oldh = c->h;
|
||||
+ c->h = ev->height;
|
||||
+ }
|
||||
}
|
||||
if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
|
||||
c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
|
||||
@@ -653,6 +683,8 @@ destroynotify(XEvent *e)
|
||||
|
||||
if ((c = wintoclient(ev->window)))
|
||||
unmanage(c, 1);
|
||||
+ else if ((c = swallowingclient(ev->window)))
|
||||
+ unmanage(c->swallowing, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1021,12 +1053,14 @@ killclient(const Arg *arg)
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
- Client *c, *t = NULL;
|
||||
+ Client *c, *t = NULL, *term = NULL;
|
||||
Window trans = None;
|
||||
XWindowChanges wc;
|
||||
+ int focusclient = 1;
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
+ c->pid = winpid(w);
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
@@ -1041,6 +1075,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
} else {
|
||||
c->mon = selmon;
|
||||
applyrules(c);
|
||||
+ term = termforwin(c);
|
||||
}
|
||||
|
||||
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
|
||||
@@ -1066,18 +1101,35 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- attach(c);
|
||||
- attachstack(c);
|
||||
+
|
||||
+ /* Do not attach client if it is being swallowed */
|
||||
+ if (term && swallow(term, c)) {
|
||||
+ /* Do not let swallowed client steal focus unless the terminal has focus */
|
||||
+ focusclient = (term == selmon->sel);
|
||||
+ } else {
|
||||
+ attach(c);
|
||||
+
|
||||
+ if (focusclient || !c->mon->sel || !c->mon->stack)
|
||||
+ attachstack(c);
|
||||
+ else {
|
||||
+ c->snext = c->mon->sel->snext;
|
||||
+ c->mon->sel->snext = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
- unfocus(selmon->sel, 0);
|
||||
- c->mon->sel = c;
|
||||
+ if (focusclient) {
|
||||
+ if (c->mon == selmon)
|
||||
+ unfocus(selmon->sel, 0);
|
||||
+ c->mon->sel = c;
|
||||
+ }
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
- focus(NULL);
|
||||
+ if (focusclient)
|
||||
+ focus(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1269,6 +1321,46 @@ recttomon(int x, int y, int w, int h)
|
||||
return r;
|
||||
}
|
||||
|
||||
+void
|
||||
+replaceclient(Client *old, Client *new)
|
||||
+{
|
||||
+ Client *c = NULL;
|
||||
+ Monitor *mon = old->mon;
|
||||
+
|
||||
+ new->mon = mon;
|
||||
+ new->tags = old->tags;
|
||||
+ new->isfloating = old->isfloating;
|
||||
+
|
||||
+ new->next = old->next;
|
||||
+ new->snext = old->snext;
|
||||
+
|
||||
+ if (old == mon->clients)
|
||||
+ mon->clients = new;
|
||||
+ else {
|
||||
+ for (c = mon->clients; c && c->next != old; c = c->next);
|
||||
+ c->next = new;
|
||||
+ }
|
||||
+
|
||||
+ if (old == mon->stack)
|
||||
+ mon->stack = new;
|
||||
+ else {
|
||||
+ for (c = mon->stack; c && c->snext != old; c = c->snext);
|
||||
+ c->snext = new;
|
||||
+ }
|
||||
+
|
||||
+ old->next = NULL;
|
||||
+ old->snext = NULL;
|
||||
+
|
||||
+ XMoveWindow(dpy, old->win, WIDTH(old) * -2, old->y);
|
||||
+
|
||||
+ if (ISVISIBLE(new) && !new->isfullscreen) {
|
||||
+ if (new->isfloating)
|
||||
+ resize(new, old->x, old->y, new->w, new->h, 0);
|
||||
+ else
|
||||
+ resize(new, old->x, old->y, old->w, old->h, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
{
|
||||
@@ -1656,6 +1748,31 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+int
|
||||
+swallow(Client *t, Client *c)
|
||||
+{
|
||||
+ if (c->noswallow || c->isterminal)
|
||||
+ return 0;
|
||||
+ if (!swallowfloating && c->isfloating)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (t->isfullscreen)
|
||||
+ setfullscreen(c, 1);
|
||||
+
|
||||
+ replaceclient(t, c);
|
||||
+ c->ignorecfgreqpos = 1;
|
||||
+ c->swallowing = t;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+unswallow(Client *c)
|
||||
+{
|
||||
+ replaceclient(c, c->swallowing);
|
||||
+ c->swallowing = NULL;
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@@ -1768,9 +1885,17 @@ unfocus(Client *c, int setfocus)
|
||||
void
|
||||
unmanage(Client *c, int destroyed)
|
||||
{
|
||||
+ Client *s;
|
||||
Monitor *m = c->mon;
|
||||
XWindowChanges wc;
|
||||
|
||||
+ if (c->swallowing)
|
||||
+ unswallow(c);
|
||||
+
|
||||
+ s = swallowingclient(c->win);
|
||||
+ if (s)
|
||||
+ s->swallowing = NULL;
|
||||
+
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
if (!destroyed) {
|
||||
@@ -2050,6 +2175,133 @@ view(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+winpid(Window w)
|
||||
+{
|
||||
+ pid_t result = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ xcb_res_client_id_spec_t spec = {0};
|
||||
+ spec.client = w;
|
||||
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
|
||||
+
|
||||
+ xcb_generic_error_t *e = NULL;
|
||||
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
|
||||
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
|
||||
+
|
||||
+ if (!r)
|
||||
+ return (pid_t)0;
|
||||
+
|
||||
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
|
||||
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
|
||||
+ spec = i.data->spec;
|
||||
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
|
||||
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
|
||||
+ result = *t;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ free(r);
|
||||
+
|
||||
+ if (result == (pid_t)-1)
|
||||
+ result = 0;
|
||||
+#endif /* __linux__ */
|
||||
+#ifdef __OpenBSD__
|
||||
+ Atom type;
|
||||
+ int format;
|
||||
+ unsigned long len, bytes;
|
||||
+ unsigned char *prop;
|
||||
+ pid_t ret;
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = *(pid_t*)prop;
|
||||
+ XFree(prop);
|
||||
+ result = ret;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+pid_t
|
||||
+getparentprocess(pid_t p)
|
||||
+{
|
||||
+ unsigned int v = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ FILE *f;
|
||||
+ char buf[256];
|
||||
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
|
||||
+
|
||||
+ if (!(f = fopen(buf, "r")))
|
||||
+ return 0;
|
||||
+
|
||||
+ fscanf(f, "%*u %*s %*c %u", &v);
|
||||
+ fclose(f);
|
||||
+#endif /* __linux__*/
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ int n;
|
||||
+ kvm_t *kd;
|
||||
+ struct kinfo_proc *kp;
|
||||
+
|
||||
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
+ if (!kd)
|
||||
+ return 0;
|
||||
+
|
||||
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
+ v = kp->p_ppid;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ return (pid_t)v;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+isdescprocess(pid_t p, pid_t c)
|
||||
+{
|
||||
+ while (p != c && c != 0)
|
||||
+ c = getparentprocess(c);
|
||||
+
|
||||
+ return (int)c;
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+termforwin(const Client *w)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m;
|
||||
+
|
||||
+ if (!w->pid || w->isterminal)
|
||||
+ return NULL;
|
||||
+
|
||||
+ for (m = mons; m; m = m->next) {
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
|
||||
+ return c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+swallowingclient(Window w)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m;
|
||||
+
|
||||
+ for (m = mons; m; m = m->next) {
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (c->swallowing && c->swallowing->win == w)
|
||||
+ return c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
Client *
|
||||
wintoclient(Window w)
|
||||
{
|
||||
@@ -2141,10 +2393,12 @@ main(int argc, char *argv[])
|
||||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("dwm: cannot open display");
|
||||
+ if (!(xcon = XGetXCBConnection(dpy)))
|
||||
+ die("dwm: cannot get xcb connection\n");
|
||||
checkotherwm();
|
||||
setup();
|
||||
#ifdef __OpenBSD__
|
||||
- if (pledge("stdio rpath proc exec", NULL) == -1)
|
||||
+ if (pledge("stdio rpath proc exec ps", NULL) == -1)
|
||||
die("pledge");
|
||||
#endif /* __OpenBSD__ */
|
||||
scan();
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,222 @@
|
||||
From d27eb690b062552395732ff71c046f11e91bdaf2 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:44:42 +0100
|
||||
Subject: [PATCH 2/2] Adding riodraw on top of swallow
|
||||
|
||||
---
|
||||
config.def.h | 8 ++++
|
||||
dwm.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 135 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index dba4b83..191190b 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -6,6 +6,12 @@ static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char slopspawnstyle[] = "-t 0 -c 0.92,0.85,0.69,0.3 -o"; /* do NOT define -f (format) here */
|
||||
+static const char slopresizestyle[] = "-t 0 -c 0.92,0.85,0.69,0.3"; /* do NOT define -f (format) here */
|
||||
+static const int riodraw_borders = 0; /* 0 or 1, indicates whether the area drawn using slop includes the window borders */
|
||||
+static const int riodraw_matchpid = 1; /* 0 or 1, indicates whether to match the PID of the client that was spawned with riospawn */
|
||||
+static const int riodraw_spawnasync = 0; /* 0 means that the application is only spawned after a successful selection while
|
||||
+ * 1 means that the application is being initialised in the background while the selection is made */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -67,6 +73,8 @@ static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY|ControlMask, XK_Return, riospawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_s, rioresize, {0} },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 8735093..8dc28d3 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -205,6 +205,10 @@ static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
+static int riodraw(Client *c, const char slopstyle[]);
|
||||
+static void rioposition(Client *c, int x, int y, int w, int h);
|
||||
+static void rioresize(const Arg *arg);
|
||||
+static void riospawn(const Arg *arg);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
@@ -219,6 +223,7 @@ static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static pid_t spawncmd(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
@@ -264,6 +269,8 @@ static int bh, blw = 0; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
+static int riodimensions[4] = { -1, -1, -1, -1 };
|
||||
+static pid_t riopid = 0;
|
||||
static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[ButtonPress] = buttonpress,
|
||||
[ClientMessage] = clientmessage,
|
||||
@@ -1126,6 +1133,18 @@ manage(Window w, XWindowAttributes *wa)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
}
|
||||
+
|
||||
+ if (!c->swallowing) {
|
||||
+ if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
||||
+ if (riodimensions[3] != -1)
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ else {
|
||||
+ killclient(&((Arg) { .v = c }));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
if (focusclient)
|
||||
@@ -1465,6 +1484,105 @@ restack(Monitor *m)
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
+int
|
||||
+riodraw(Client *c, const char slopstyle[])
|
||||
+{
|
||||
+ int i;
|
||||
+ char str[100];
|
||||
+ char strout[100];
|
||||
+ char tmpstring[30] = {0};
|
||||
+ char slopcmd[100] = "slop -f x%xx%yx%wx%hx ";
|
||||
+ int firstchar = 0;
|
||||
+ int counter = 0;
|
||||
+
|
||||
+ strcat(slopcmd, slopstyle);
|
||||
+ FILE *fp = popen(slopcmd, "r");
|
||||
+
|
||||
+ while (fgets(str, 100, fp) != NULL)
|
||||
+ strcat(strout, str);
|
||||
+
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ if (strlen(strout) < 6)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < strlen(strout); i++){
|
||||
+ if (!firstchar) {
|
||||
+ if (strout[i] == 'x')
|
||||
+ firstchar = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strout[i] != 'x')
|
||||
+ tmpstring[strlen(tmpstring)] = strout[i];
|
||||
+ else {
|
||||
+ riodimensions[counter] = atoi(tmpstring);
|
||||
+ counter++;
|
||||
+ memset(tmpstring,0,strlen(tmpstring));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (riodimensions[0] <= -40 || riodimensions[1] <= -40 || riodimensions[2] <= 50 || riodimensions[3] <= 50) {
|
||||
+ riodimensions[3] = -1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (c) {
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+rioposition(Client *c, int x, int y, int w, int h)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ if ((m = recttomon(x, y, w, h)) && m != c->mon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ arrange(c->mon);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ selmon = m;
|
||||
+ focus(c);
|
||||
+ }
|
||||
+
|
||||
+ c->isfloating = 1;
|
||||
+ if (riodraw_borders)
|
||||
+ resizeclient(c, x, y, w - (c->bw * 2), h - (c->bw * 2));
|
||||
+ else
|
||||
+ resizeclient(c, x - c->bw, y - c->bw, w, h);
|
||||
+ drawbar(c->mon);
|
||||
+ arrange(c->mon);
|
||||
+
|
||||
+ riodimensions[3] = -1;
|
||||
+ riopid = 0;
|
||||
+}
|
||||
+
|
||||
+/* drag out an area using slop and resize the selected window to it */
|
||||
+void
|
||||
+rioresize(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = (arg && arg->v ? (Client*)arg->v : selmon->sel);
|
||||
+ if (c)
|
||||
+ riodraw(c, slopresizestyle);
|
||||
+}
|
||||
+
|
||||
+/* spawn a new window and drag out an area using slop to postiion it */
|
||||
+void
|
||||
+riospawn(const Arg *arg)
|
||||
+{
|
||||
+ if (riodraw_spawnasync) {
|
||||
+ riopid = spawncmd(arg);
|
||||
+ riodraw(NULL, slopspawnstyle);
|
||||
+ } else if (riodraw(NULL, slopspawnstyle))
|
||||
+ riopid = spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
@@ -1735,9 +1853,16 @@ sigchld(int unused)
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
+ spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
+pid_t
|
||||
+spawncmd(const Arg *arg)
|
||||
+{
|
||||
+ pid_t pid;
|
||||
if (arg->v == dmenucmd)
|
||||
dmenumon[0] = '0' + selmon->num;
|
||||
- if (fork() == 0) {
|
||||
+ if ((pid = fork()) == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
setsid();
|
||||
@@ -1746,6 +1871,7 @@ spawn(const Arg *arg)
|
||||
perror(" failed");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+ return pid;
|
||||
}
|
||||
|
||||
int
|
||||
--
|
||||
2.19.1
|
||||
|
@ -0,0 +1,729 @@
|
||||
From 66c7e6fef8a900a03e4ca861fdb11aff1f1af690 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:43:13 +0100
|
||||
Subject: [PATCH 1/2] Alternative swallow patch that replaces clients instead
|
||||
of swapping windows offering better resize hints
|
||||
|
||||
---
|
||||
config.def.h | 9 +-
|
||||
config.mk | 6 +-
|
||||
dwm.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
3 files changed, 288 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a2ac963..dba4b83 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -3,6 +3,7 @@
|
||||
/* appearance */
|
||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||
static const unsigned int snap = 32; /* snap pixel */
|
||||
+static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
@@ -26,9 +27,11 @@ static const Rule rules[] = {
|
||||
* WM_CLASS(STRING) = instance, class
|
||||
* WM_NAME(STRING) = title
|
||||
*/
|
||||
- /* class instance title tags mask isfloating monitor */
|
||||
- { "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
+ /* class instance title tags mask isfloating isterminal noswallow monitor */
|
||||
+ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 },
|
||||
+ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1, -1 },
|
||||
+ { "St", NULL, NULL, 0, 0, 1, 0, -1 },
|
||||
+ { NULL, NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
diff --git a/config.mk b/config.mk
|
||||
index b6eb7e0..ee5c46e 100644
|
||||
--- a/config.mk
|
||||
+++ b/config.mk
|
||||
@@ -19,10 +19,14 @@ FREETYPELIBS = -lfontconfig -lXft
|
||||
FREETYPEINC = /usr/include/freetype2
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = ${X11INC}/freetype2
|
||||
+#KVMLIB = -lkvm
|
||||
+
|
||||
+# This is needed for the swallow patch
|
||||
+XCBLIBS = -lX11-xcb -lxcb -lxcb-res
|
||||
|
||||
# includes and libs
|
||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XCBLIBS} ${KVMLIB}
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index a96f33c..8735093 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -40,6 +40,12 @@
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif /* XINERAMA */
|
||||
#include <X11/Xft/Xft.h>
|
||||
+#include <X11/Xlib-xcb.h>
|
||||
+#include <xcb/res.h>
|
||||
+#ifdef __OpenBSD__
|
||||
+#include <sys/sysctl.h>
|
||||
+#include <kvm.h>
|
||||
+#endif /* __OpenBSD */
|
||||
|
||||
#include "drw.h"
|
||||
#include "util.h"
|
||||
@@ -92,9 +98,12 @@ struct Client {
|
||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
||||
int bw, oldbw;
|
||||
unsigned int tags;
|
||||
- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||
+ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
|
||||
+ int ignorecfgreqpos, ignorecfgreqsize;
|
||||
+ pid_t pid;
|
||||
Client *next;
|
||||
Client *snext;
|
||||
+ Client *swallowing;
|
||||
Monitor *mon;
|
||||
Window win;
|
||||
};
|
||||
@@ -138,6 +147,8 @@ typedef struct {
|
||||
const char *title;
|
||||
unsigned int tags;
|
||||
int isfloating;
|
||||
+ int isterminal;
|
||||
+ int noswallow;
|
||||
int monitor;
|
||||
} Rule;
|
||||
|
||||
@@ -189,6 +200,7 @@ static void pop(Client *);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
+static void replaceclient(Client *old, Client *new);
|
||||
static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
@@ -235,6 +247,14 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
+static int swallow(Client *p, Client *c);
|
||||
+static void unswallow(Client *c);
|
||||
+static pid_t getparentprocess(pid_t p);
|
||||
+static int isdescprocess(pid_t p, pid_t c);
|
||||
+static Client *swallowingclient(Window w);
|
||||
+static Client *termforwin(const Client *c);
|
||||
+static pid_t winpid(Window w);
|
||||
+
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
static char stext[256];
|
||||
@@ -268,6 +288,7 @@ static Display *dpy;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window root, wmcheckwin;
|
||||
+static xcb_connection_t *xcon;
|
||||
|
||||
/* configuration, allows nested code to access above variables */
|
||||
#include "config.h"
|
||||
@@ -298,6 +319,8 @@ applyrules(Client *c)
|
||||
&& (!r->class || strstr(class, r->class))
|
||||
&& (!r->instance || strstr(instance, r->instance)))
|
||||
{
|
||||
+ c->isterminal = r->isterminal;
|
||||
+ c->noswallow = r->noswallow;
|
||||
c->isfloating = r->isfloating;
|
||||
c->tags |= r->tags;
|
||||
for (m = mons; m && m->num != r->monitor; m = m->next);
|
||||
@@ -588,22 +611,29 @@ configurerequest(XEvent *e)
|
||||
if (ev->value_mask & CWBorderWidth)
|
||||
c->bw = ev->border_width;
|
||||
else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
|
||||
+ if (c->ignorecfgreqpos && c->ignorecfgreqsize)
|
||||
+ return;
|
||||
+
|
||||
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 (ev->value_mask & CWWidth) {
|
||||
- c->oldw = c->w;
|
||||
- c->w = ev->width;
|
||||
+ if (!c->ignorecfgreqpos) {
|
||||
+ 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 & CWHeight) {
|
||||
- c->oldh = c->h;
|
||||
- c->h = ev->height;
|
||||
+ if (!c->ignorecfgreqsize) {
|
||||
+ if (ev->value_mask & CWWidth) {
|
||||
+ c->oldw = c->w;
|
||||
+ c->w = ev->width;
|
||||
+ }
|
||||
+ if (ev->value_mask & CWHeight) {
|
||||
+ c->oldh = c->h;
|
||||
+ c->h = ev->height;
|
||||
+ }
|
||||
}
|
||||
if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
|
||||
c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
|
||||
@@ -653,6 +683,8 @@ destroynotify(XEvent *e)
|
||||
|
||||
if ((c = wintoclient(ev->window)))
|
||||
unmanage(c, 1);
|
||||
+ else if ((c = swallowingclient(ev->window)))
|
||||
+ unmanage(c->swallowing, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1021,12 +1053,14 @@ killclient(const Arg *arg)
|
||||
void
|
||||
manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
- Client *c, *t = NULL;
|
||||
+ Client *c, *t = NULL, *term = NULL;
|
||||
Window trans = None;
|
||||
XWindowChanges wc;
|
||||
+ int focusclient = 1;
|
||||
|
||||
c = ecalloc(1, sizeof(Client));
|
||||
c->win = w;
|
||||
+ c->pid = winpid(w);
|
||||
/* geometry */
|
||||
c->x = c->oldx = wa->x;
|
||||
c->y = c->oldy = wa->y;
|
||||
@@ -1041,6 +1075,7 @@ manage(Window w, XWindowAttributes *wa)
|
||||
} else {
|
||||
c->mon = selmon;
|
||||
applyrules(c);
|
||||
+ term = termforwin(c);
|
||||
}
|
||||
|
||||
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
|
||||
@@ -1066,18 +1101,35 @@ manage(Window w, XWindowAttributes *wa)
|
||||
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
- attach(c);
|
||||
- attachstack(c);
|
||||
+
|
||||
+ /* Do not attach client if it is being swallowed */
|
||||
+ if (term && swallow(term, c)) {
|
||||
+ /* Do not let swallowed client steal focus unless the terminal has focus */
|
||||
+ focusclient = (term == selmon->sel);
|
||||
+ } else {
|
||||
+ attach(c);
|
||||
+
|
||||
+ if (focusclient || !c->mon->sel || !c->mon->stack)
|
||||
+ attachstack(c);
|
||||
+ else {
|
||||
+ c->snext = c->mon->sel->snext;
|
||||
+ c->mon->sel->snext = c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
|
||||
(unsigned char *) &(c->win), 1);
|
||||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||
setclientstate(c, NormalState);
|
||||
- if (c->mon == selmon)
|
||||
- unfocus(selmon->sel, 0);
|
||||
- c->mon->sel = c;
|
||||
+ if (focusclient) {
|
||||
+ if (c->mon == selmon)
|
||||
+ unfocus(selmon->sel, 0);
|
||||
+ c->mon->sel = c;
|
||||
+ }
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
- focus(NULL);
|
||||
+ if (focusclient)
|
||||
+ focus(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1269,6 +1321,46 @@ recttomon(int x, int y, int w, int h)
|
||||
return r;
|
||||
}
|
||||
|
||||
+void
|
||||
+replaceclient(Client *old, Client *new)
|
||||
+{
|
||||
+ Client *c = NULL;
|
||||
+ Monitor *mon = old->mon;
|
||||
+
|
||||
+ new->mon = mon;
|
||||
+ new->tags = old->tags;
|
||||
+ new->isfloating = old->isfloating;
|
||||
+
|
||||
+ new->next = old->next;
|
||||
+ new->snext = old->snext;
|
||||
+
|
||||
+ if (old == mon->clients)
|
||||
+ mon->clients = new;
|
||||
+ else {
|
||||
+ for (c = mon->clients; c && c->next != old; c = c->next);
|
||||
+ c->next = new;
|
||||
+ }
|
||||
+
|
||||
+ if (old == mon->stack)
|
||||
+ mon->stack = new;
|
||||
+ else {
|
||||
+ for (c = mon->stack; c && c->snext != old; c = c->snext);
|
||||
+ c->snext = new;
|
||||
+ }
|
||||
+
|
||||
+ old->next = NULL;
|
||||
+ old->snext = NULL;
|
||||
+
|
||||
+ XMoveWindow(dpy, old->win, WIDTH(old) * -2, old->y);
|
||||
+
|
||||
+ if (ISVISIBLE(new) && !new->isfullscreen) {
|
||||
+ if (new->isfloating)
|
||||
+ resize(new, old->x, old->y, new->w, new->h, 0);
|
||||
+ else
|
||||
+ resize(new, old->x, old->y, old->w, old->h, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
resize(Client *c, int x, int y, int w, int h, int interact)
|
||||
{
|
||||
@@ -1656,6 +1748,31 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
+int
|
||||
+swallow(Client *t, Client *c)
|
||||
+{
|
||||
+ if (c->noswallow || c->isterminal)
|
||||
+ return 0;
|
||||
+ if (!swallowfloating && c->isfloating)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (t->isfullscreen)
|
||||
+ setfullscreen(c, 1);
|
||||
+
|
||||
+ replaceclient(t, c);
|
||||
+ c->ignorecfgreqpos = 1;
|
||||
+ c->swallowing = t;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+unswallow(Client *c)
|
||||
+{
|
||||
+ replaceclient(c, c->swallowing);
|
||||
+ c->swallowing = NULL;
|
||||
+}
|
||||
+
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@@ -1768,9 +1885,17 @@ unfocus(Client *c, int setfocus)
|
||||
void
|
||||
unmanage(Client *c, int destroyed)
|
||||
{
|
||||
+ Client *s;
|
||||
Monitor *m = c->mon;
|
||||
XWindowChanges wc;
|
||||
|
||||
+ if (c->swallowing)
|
||||
+ unswallow(c);
|
||||
+
|
||||
+ s = swallowingclient(c->win);
|
||||
+ if (s)
|
||||
+ s->swallowing = NULL;
|
||||
+
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
if (!destroyed) {
|
||||
@@ -2050,6 +2175,133 @@ view(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
+pid_t
|
||||
+winpid(Window w)
|
||||
+{
|
||||
+ pid_t result = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ xcb_res_client_id_spec_t spec = {0};
|
||||
+ spec.client = w;
|
||||
+ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
|
||||
+
|
||||
+ xcb_generic_error_t *e = NULL;
|
||||
+ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
|
||||
+ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
|
||||
+
|
||||
+ if (!r)
|
||||
+ return (pid_t)0;
|
||||
+
|
||||
+ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
|
||||
+ for (; i.rem; xcb_res_client_id_value_next(&i)) {
|
||||
+ spec = i.data->spec;
|
||||
+ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
|
||||
+ uint32_t *t = xcb_res_client_id_value_value(i.data);
|
||||
+ result = *t;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ free(r);
|
||||
+
|
||||
+ if (result == (pid_t)-1)
|
||||
+ result = 0;
|
||||
+#endif /* __linux__ */
|
||||
+#ifdef __OpenBSD__
|
||||
+ Atom type;
|
||||
+ int format;
|
||||
+ unsigned long len, bytes;
|
||||
+ unsigned char *prop;
|
||||
+ pid_t ret;
|
||||
+
|
||||
+ if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = *(pid_t*)prop;
|
||||
+ XFree(prop);
|
||||
+ result = ret;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+pid_t
|
||||
+getparentprocess(pid_t p)
|
||||
+{
|
||||
+ unsigned int v = 0;
|
||||
+
|
||||
+#ifdef __linux__
|
||||
+ FILE *f;
|
||||
+ char buf[256];
|
||||
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
|
||||
+
|
||||
+ if (!(f = fopen(buf, "r")))
|
||||
+ return 0;
|
||||
+
|
||||
+ fscanf(f, "%*u %*s %*c %u", &v);
|
||||
+ fclose(f);
|
||||
+#endif /* __linux__*/
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ int n;
|
||||
+ kvm_t *kd;
|
||||
+ struct kinfo_proc *kp;
|
||||
+
|
||||
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
+ if (!kd)
|
||||
+ return 0;
|
||||
+
|
||||
+ kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n);
|
||||
+ v = kp->p_ppid;
|
||||
+#endif /* __OpenBSD__ */
|
||||
+
|
||||
+ return (pid_t)v;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+isdescprocess(pid_t p, pid_t c)
|
||||
+{
|
||||
+ while (p != c && c != 0)
|
||||
+ c = getparentprocess(c);
|
||||
+
|
||||
+ return (int)c;
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+termforwin(const Client *w)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m;
|
||||
+
|
||||
+ if (!w->pid || w->isterminal)
|
||||
+ return NULL;
|
||||
+
|
||||
+ for (m = mons; m; m = m->next) {
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
|
||||
+ return c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+Client *
|
||||
+swallowingclient(Window w)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ Monitor *m;
|
||||
+
|
||||
+ for (m = mons; m; m = m->next) {
|
||||
+ for (c = m->clients; c; c = c->next) {
|
||||
+ if (c->swallowing && c->swallowing->win == w)
|
||||
+ return c;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
Client *
|
||||
wintoclient(Window w)
|
||||
{
|
||||
@@ -2141,10 +2393,12 @@ main(int argc, char *argv[])
|
||||
fputs("warning: no locale support\n", stderr);
|
||||
if (!(dpy = XOpenDisplay(NULL)))
|
||||
die("dwm: cannot open display");
|
||||
+ if (!(xcon = XGetXCBConnection(dpy)))
|
||||
+ die("dwm: cannot get xcb connection\n");
|
||||
checkotherwm();
|
||||
setup();
|
||||
#ifdef __OpenBSD__
|
||||
- if (pledge("stdio rpath proc exec", NULL) == -1)
|
||||
+ if (pledge("stdio rpath proc exec ps", NULL) == -1)
|
||||
die("pledge");
|
||||
#endif /* __OpenBSD__ */
|
||||
scan();
|
||||
--
|
||||
2.19.1
|
||||
|
||||
|
||||
From d27eb690b062552395732ff71c046f11e91bdaf2 Mon Sep 17 00:00:00 2001
|
||||
From: Bakkeby <bakkeby@gmail.com>
|
||||
Date: Mon, 10 Jan 2022 13:44:42 +0100
|
||||
Subject: [PATCH 2/2] Adding riodraw on top of swallow
|
||||
|
||||
---
|
||||
config.def.h | 8 ++++
|
||||
dwm.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 135 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index dba4b83..191190b 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -6,6 +6,12 @@ static const unsigned int snap = 32; /* snap pixel */
|
||||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
|
||||
static const int showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
+static const char slopspawnstyle[] = "-t 0 -c 0.92,0.85,0.69,0.3 -o"; /* do NOT define -f (format) here */
|
||||
+static const char slopresizestyle[] = "-t 0 -c 0.92,0.85,0.69,0.3"; /* do NOT define -f (format) here */
|
||||
+static const int riodraw_borders = 0; /* 0 or 1, indicates whether the area drawn using slop includes the window borders */
|
||||
+static const int riodraw_matchpid = 1; /* 0 or 1, indicates whether to match the PID of the client that was spawned with riospawn */
|
||||
+static const int riodraw_spawnasync = 0; /* 0 means that the application is only spawned after a successful selection while
|
||||
+ * 1 means that the application is being initialised in the background while the selection is made */
|
||||
static const char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const char col_gray1[] = "#222222";
|
||||
@@ -67,6 +73,8 @@ static Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
+ { MODKEY|ControlMask, XK_Return, riospawn, {.v = termcmd } },
|
||||
+ { MODKEY, XK_s, rioresize, {0} },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
diff --git a/dwm.c b/dwm.c
|
||||
index 8735093..8dc28d3 100644
|
||||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -205,6 +205,10 @@ static void resize(Client *c, int x, int y, int w, int h, int interact);
|
||||
static void resizeclient(Client *c, int x, int y, int w, int h);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
+static int riodraw(Client *c, const char slopstyle[]);
|
||||
+static void rioposition(Client *c, int x, int y, int w, int h);
|
||||
+static void rioresize(const Arg *arg);
|
||||
+static void riospawn(const Arg *arg);
|
||||
static void run(void);
|
||||
static void scan(void);
|
||||
static int sendevent(Client *c, Atom proto);
|
||||
@@ -219,6 +223,7 @@ static void seturgent(Client *c, int urg);
|
||||
static void showhide(Client *c);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
+static pid_t spawncmd(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tile(Monitor *);
|
||||
@@ -264,6 +269,8 @@ static int bh, blw = 0; /* bar geometry */
|
||||
static int lrpad; /* sum of left and right padding for text */
|
||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||
static unsigned int numlockmask = 0;
|
||||
+static int riodimensions[4] = { -1, -1, -1, -1 };
|
||||
+static pid_t riopid = 0;
|
||||
static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[ButtonPress] = buttonpress,
|
||||
[ClientMessage] = clientmessage,
|
||||
@@ -1126,6 +1133,18 @@ manage(Window w, XWindowAttributes *wa)
|
||||
unfocus(selmon->sel, 0);
|
||||
c->mon->sel = c;
|
||||
}
|
||||
+
|
||||
+ if (!c->swallowing) {
|
||||
+ if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
||||
+ if (riodimensions[3] != -1)
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ else {
|
||||
+ killclient(&((Arg) { .v = c }));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
arrange(c->mon);
|
||||
XMapWindow(dpy, c->win);
|
||||
if (focusclient)
|
||||
@@ -1465,6 +1484,105 @@ restack(Monitor *m)
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
}
|
||||
|
||||
+int
|
||||
+riodraw(Client *c, const char slopstyle[])
|
||||
+{
|
||||
+ int i;
|
||||
+ char str[100];
|
||||
+ char strout[100];
|
||||
+ char tmpstring[30] = {0};
|
||||
+ char slopcmd[100] = "slop -f x%xx%yx%wx%hx ";
|
||||
+ int firstchar = 0;
|
||||
+ int counter = 0;
|
||||
+
|
||||
+ strcat(slopcmd, slopstyle);
|
||||
+ FILE *fp = popen(slopcmd, "r");
|
||||
+
|
||||
+ while (fgets(str, 100, fp) != NULL)
|
||||
+ strcat(strout, str);
|
||||
+
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ if (strlen(strout) < 6)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < strlen(strout); i++){
|
||||
+ if (!firstchar) {
|
||||
+ if (strout[i] == 'x')
|
||||
+ firstchar = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (strout[i] != 'x')
|
||||
+ tmpstring[strlen(tmpstring)] = strout[i];
|
||||
+ else {
|
||||
+ riodimensions[counter] = atoi(tmpstring);
|
||||
+ counter++;
|
||||
+ memset(tmpstring,0,strlen(tmpstring));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (riodimensions[0] <= -40 || riodimensions[1] <= -40 || riodimensions[2] <= 50 || riodimensions[3] <= 50) {
|
||||
+ riodimensions[3] = -1;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (c) {
|
||||
+ rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+rioposition(Client *c, int x, int y, int w, int h)
|
||||
+{
|
||||
+ Monitor *m;
|
||||
+ if ((m = recttomon(x, y, w, h)) && m != c->mon) {
|
||||
+ detach(c);
|
||||
+ detachstack(c);
|
||||
+ arrange(c->mon);
|
||||
+ c->mon = m;
|
||||
+ c->tags = m->tagset[m->seltags];
|
||||
+ attach(c);
|
||||
+ attachstack(c);
|
||||
+ selmon = m;
|
||||
+ focus(c);
|
||||
+ }
|
||||
+
|
||||
+ c->isfloating = 1;
|
||||
+ if (riodraw_borders)
|
||||
+ resizeclient(c, x, y, w - (c->bw * 2), h - (c->bw * 2));
|
||||
+ else
|
||||
+ resizeclient(c, x - c->bw, y - c->bw, w, h);
|
||||
+ drawbar(c->mon);
|
||||
+ arrange(c->mon);
|
||||
+
|
||||
+ riodimensions[3] = -1;
|
||||
+ riopid = 0;
|
||||
+}
|
||||
+
|
||||
+/* drag out an area using slop and resize the selected window to it */
|
||||
+void
|
||||
+rioresize(const Arg *arg)
|
||||
+{
|
||||
+ Client *c = (arg && arg->v ? (Client*)arg->v : selmon->sel);
|
||||
+ if (c)
|
||||
+ riodraw(c, slopresizestyle);
|
||||
+}
|
||||
+
|
||||
+/* spawn a new window and drag out an area using slop to postiion it */
|
||||
+void
|
||||
+riospawn(const Arg *arg)
|
||||
+{
|
||||
+ if (riodraw_spawnasync) {
|
||||
+ riopid = spawncmd(arg);
|
||||
+ riodraw(NULL, slopspawnstyle);
|
||||
+ } else if (riodraw(NULL, slopspawnstyle))
|
||||
+ riopid = spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
void
|
||||
run(void)
|
||||
{
|
||||
@@ -1735,9 +1853,16 @@ sigchld(int unused)
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
+ spawncmd(arg);
|
||||
+}
|
||||
+
|
||||
+pid_t
|
||||
+spawncmd(const Arg *arg)
|
||||
+{
|
||||
+ pid_t pid;
|
||||
if (arg->v == dmenucmd)
|
||||
dmenumon[0] = '0' + selmon->num;
|
||||
- if (fork() == 0) {
|
||||
+ if ((pid = fork()) == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
setsid();
|
||||
@@ -1746,6 +1871,7 @@ spawn(const Arg *arg)
|
||||
perror(" failed");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
+ return pid;
|
||||
}
|
||||
|
||||
int
|
||||
--
|
||||
2.19.1
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue