You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

485 lines
14 KiB
Diff

From 7d9d6df932f76cd4d7bd74eabe7d847d01768fb8 Mon Sep 17 00:00:00 2001
From: Bakkeby <bakkeby@gmail.com>
Date: Tue, 10 Oct 2023 22:53:16 +0200
Subject: [PATCH] Adding mark patch
---
config.def.h | 10 ++
dwm.c | 285 +++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 254 insertions(+), 41 deletions(-)
diff --git a/config.def.h b/config.def.h
index 061ad66..c7dc54c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -12,10 +12,12 @@ 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_yellow[] = "#ecB820";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ [SchemeMarked] = { col_cyan, col_yellow, col_yellow },
};
/* tagging */
@@ -84,6 +86,11 @@ static const Key keys[] = {
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+ { MODKEY, XK_a, markall, {0} }, // marks all clients on the selected tag
+ { MODKEY|ControlMask, XK_a, markall, {1} }, // marks all floating clients on the selected tag
+ { MODKEY|Mod4Mask, XK_a, markall, {2} }, // marks all hidden clients on the selected tag
+ { MODKEY|ShiftMask, XK_a, unmarkall, {0} }, // unmarks all clients
+ { MODKEY, XK_z, togglemark, {0} }, // marks or unmarks the selected client for group action
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
@@ -105,6 +112,9 @@ static const Button buttons[] = {
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY|ControlMask, Button1, markmouse, {1} }, // marks clients under the mouse cursor for group action
+ { ClkClientWin, MODKEY|ControlMask|ShiftMask, Button1, markmouse, {0} }, // unmarks clients under the mouse cursor for group action
+ { ClkClientWin, MODKEY|ControlMask, Button3, markmouse, {2} }, // toggles marking of clients under the mouse cursor for group action
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
diff --git a/dwm.c b/dwm.c
index e5efb6a..601ca27 100644
--- a/dwm.c
+++ b/dwm.c
@@ -56,10 +56,13 @@
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
+#define CLIENT (arg && arg->v ? (Client*)arg->v : selmon->sel)
+#define ISMARKED(C) (C && (C)->marked)
+#define HIDDEN(C) ((getstate(C->win) == IconicState))
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { SchemeNorm, SchemeSel }; /* color schemes */
+enum { SchemeNorm, SchemeSel, SchemeMarked }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
@@ -91,6 +94,7 @@ struct Client {
int oldx, oldy, oldw, oldh;
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
int bw, oldbw;
+ int marked;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
Client *next;
@@ -170,6 +174,7 @@ 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 Client *getpointerclient(void);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
@@ -181,9 +186,14 @@ static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
+// static void mark(const Arg *arg);
+static void markall(const Arg *arg);
+static void markclient(Client *c);
+static void markmouse(const Arg *arg);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
+static Client *nextmarked(Client *prev, Client *def);
static Client *nexttiled(Client *c);
static void pop(Client *c);
static void propertynotify(XEvent *e);
@@ -212,11 +222,15 @@ static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
+static void togglemark(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
+// static void unmark(const Arg *arg);
+static void unmarkall(const Arg *arg);
+static void unmarkclient(Client *c);
static void updatebarpos(Monitor *m);
static void updatebars(void);
static void updateclientlist(void);
@@ -242,6 +256,9 @@ static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh; /* bar height */
static int lrpad; /* sum of left and right padding for text */
+static int num_marked = 0; /* keeps track of how many clients are marked */
+static int keepmarks = 0; /* not used by default, placeholder for combo compatibility */
+static int ignore_marked = 1; /* used to avoid marked clients when key functions are used internally */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
@@ -802,7 +819,7 @@ focus(Client *c)
detachstack(c);
attachstack(c);
grabbuttons(c, 1);
- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ XSetWindowBorder(dpy, c->win, scheme[ISMARKED(c) ? SchemeMarked : SchemeSel][ColBorder].pixel);
setfocus(c);
} else {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
@@ -878,6 +895,17 @@ getatomprop(Client *c, Atom prop)
return atom;
}
+Client *
+getpointerclient(void)
+{
+ Window dummy, win;
+ int di;
+ unsigned int dui;
+
+ XQueryPointer(dpy, root, &dummy, &win, &di, &di, &di, &di, &dui);
+ return wintoclient(win);
+}
+
int
getrootptr(int *x, int *y)
{
@@ -996,26 +1024,32 @@ keypress(XEvent *e)
ev = &e->xkey;
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
+ ignore_marked = 0;
for (i = 0; i < LENGTH(keys); i++)
if (keysym == keys[i].keysym
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
&& keys[i].func)
keys[i].func(&(keys[i].arg));
+ ignore_marked = 1;
}
void
killclient(const Arg *arg)
{
- if (!selmon->sel)
- return;
- if (!sendevent(selmon->sel, wmatom[WMDelete])) {
- XGrabServer(dpy);
- XSetErrorHandler(xerrordummy);
- XSetCloseDownMode(dpy, DestroyAll);
- XKillClient(dpy, selmon->sel->win);
- XSync(dpy, False);
- XSetErrorHandler(xerror);
- XUngrabServer(dpy);
+ Client *c = CLIENT, *next;
+
+ for (c = nextmarked(NULL, c); c; c = nextmarked(next, NULL)) {
+ next = c->next;
+
+ if (!sendevent(c, wmatom[WMDelete])) {
+ XGrabServer(dpy);
+ XSetErrorHandler(xerrordummy);
+ XSetCloseDownMode(dpy, DestroyAll);
+ XKillClient(dpy, c->win);
+ XSync(dpy, False);
+ XSetErrorHandler(xerror);
+ XUngrabServer(dpy);
+ }
}
}
@@ -1101,6 +1135,90 @@ maprequest(XEvent *e)
manage(ev->window, &wa);
}
+/* Placeholder for IPC command bindings */
+//void
+//mark(const Arg *arg)
+//{
+// Client *c = CLIENT;
+// if (!c || ISMARKED(c))
+// return;
+// markclient(c);
+// drawbar(c->mon);
+//}
+
+void
+markall(const Arg *arg)
+{
+ Client *c;
+ for (c = selmon->clients; c; c = c->next) {
+ if (ISMARKED(c) || !ISVISIBLE(c))
+ continue;
+
+ if ((arg->i == 2 && !HIDDEN(c)) || (arg->i != 2 && HIDDEN(c)))
+ continue;
+
+ if (arg->i == 1 && !c->isfloating)
+ continue;
+
+ markclient(c);
+ }
+ drawbar(selmon);
+}
+
+void
+markclient(Client *c)
+{
+ if (!ISMARKED(c)) {
+ c->marked = 1;
+ ++num_marked;
+ XSetWindowBorder(dpy, c->win, scheme[SchemeMarked][ColBorder].pixel);
+ }
+}
+
+void
+markmouse(const Arg *arg)
+{
+ Client *r = selmon->sel;
+ Client *prevr = r;
+ Monitor *m;
+ XEvent ev;
+ Time lasttime = 0;
+ int mark = arg->i;
+
+ if (r && mark != ISMARKED(r))
+ togglemark(&((Arg) { .v = r }));
+
+ if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ 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;
+
+ if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon)
+ selmon = m;
+
+ r = getpointerclient();
+ if (r != prevr && r && mark != ISMARKED(r))
+ togglemark(&((Arg) { .v = r }));
+
+ prevr = r;
+ break;
+ }
+ } while (ev.type != ButtonRelease);
+ XUngrabPointer(dpy, CurrentTime);
+}
+
void
monocle(Monitor *m)
{
@@ -1193,6 +1311,23 @@ movemouse(const Arg *arg)
}
}
+Client *
+nextmarked(Client *prev, Client *def)
+{
+ if (!num_marked || ignore_marked)
+ return def;
+
+ Client *c = NULL;
+ Monitor *m;
+
+ for (m = (prev ? prev->mon : mons); m && !c; m = m->next)
+ for (c = (prev ? prev : m->clients); c && !ISMARKED(c); c = c->next, prev = NULL);
+
+ if (c && ISMARKED(c) && !keepmarks)
+ unmarkclient(c);
+ return c;
+}
+
Client *
nexttiled(Client *c)
{
@@ -1411,15 +1546,19 @@ scan(void)
void
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);
+ Client *next;
+ for (c = nextmarked(NULL, c); c; c = nextmarked(next, NULL)) {
+ next = c->next;
+ 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);
}
@@ -1651,11 +1790,17 @@ spawn(const Arg *arg)
void
tag(const Arg *arg)
{
- if (selmon->sel && arg->ui & TAGMASK) {
- selmon->sel->tags = arg->ui & TAGMASK;
- focus(NULL);
- arrange(selmon);
+ Monitor *m = selmon;
+ Client *c = m->sel;
+
+ if (!(arg->ui & TAGMASK))
+ return;
+
+ for (c = nextmarked(NULL, c); c; c = nextmarked(c->next, NULL)) {
+ c->tags = arg->ui & TAGMASK;
}
+ focus(NULL);
+ arrange(m);
}
void
@@ -1706,30 +1851,59 @@ togglebar(const Arg *arg)
void
togglefloating(const Arg *arg)
{
- if (!selmon->sel)
- return;
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ Client *c = CLIENT;
+ Monitor *m = NULL;
+ XWindowChanges wc;
+ wc.stack_mode = Above;
+
+ for (c = nextmarked(NULL, c); c; c = nextmarked(c->next, NULL)) {
+
+ if (c->isfullscreen) /* no support for fullscreen windows */
+ continue;
+ if (m && c->mon != m)
+ arrange(m);
+ c->isfloating = !c->isfloating || c->isfixed;
+ if (c->isfloating) {
+ resize(c, c->x, c->y, c->w, c->h, 0);
+ wc.sibling = c->mon->barwin;
+ XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
+ }
+ m = c->mon;
+ }
+ if (m) {
+ XSync(dpy, False);
+ arrange(m);
+ }
+}
+
+void
+togglemark(const Arg *arg)
+{
+ Client *c = CLIENT;
+ if (!c)
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);
- arrange(selmon);
+ if (ISMARKED(c))
+ unmarkclient(c);
+ else
+ markclient(c);
+ drawbar(c->mon);
}
void
toggletag(const Arg *arg)
{
+ Monitor *m = selmon;
+ Client *c = m->sel;
unsigned int newtags;
- if (!selmon->sel)
- return;
- newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
- if (newtags) {
- selmon->sel->tags = newtags;
- focus(NULL);
- arrange(selmon);
+ for (c = nextmarked(NULL, c); c; c = nextmarked(c->next, NULL)) {
+ newtags = c->tags ^ (arg->ui & TAGMASK);
+ if (newtags) {
+ c->tags = newtags;
+ }
}
+ focus(NULL);
+ arrange(m);
}
void
@@ -1750,7 +1924,7 @@ unfocus(Client *c, int setfocus)
if (!c)
return;
grabbuttons(c, 0);
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ XSetWindowBorder(dpy, c->win, scheme[ISMARKED(c) ? SchemeMarked : SchemeNorm][ColBorder].pixel);
if (setfocus) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
@@ -1797,6 +1971,35 @@ unmapnotify(XEvent *e)
}
}
+/* Placeholder for IPC command bindings */
+//void
+//unmark(const Arg *arg)
+//{
+// Client *c = CLIENT;
+// if (!c)
+// return;
+// unmarkclient(c);
+// drawbar(c->mon);
+//}
+
+void
+unmarkall(const Arg *arg)
+{
+ keepmarks = 0;
+ for (Client *c = nextmarked(NULL, NULL); c; c = nextmarked(c->next, NULL));
+ drawbars();
+}
+
+void
+unmarkclient(Client *c)
+{
+ if (ISMARKED(c)) {
+ c->marked = 0;
+ --num_marked;
+ XSetWindowBorder(dpy, c->win, scheme[c == selmon->sel ? SchemeSel : SchemeNorm][ColBorder].pixel);
+ }
+}
+
void
updatebars(void)
{
--
2.19.1