From 7be494dd01bfc1ed0be3d4a2fcd5f9e6b37e2314 Mon Sep 17 00:00:00 2001 From: krolyxon Date: Sun, 11 Sep 2022 02:46:59 +0530 Subject: [PATCH] actual fullscreen patch --- config.def.h | 5 +- config.def.h.orig | 133 + config.def.h.rej | 10 + config.h | 5 +- dwm | Bin 79408 -> 79472 bytes dwm.1 | 3 + dwm.c | 8 + dwm.c.orig | 2362 +++++++++++++++++ dwm.c.rej | 10 + ...dwm-actualfullscreen-20211013-cb3f58a.diff | 68 + 10 files changed, 2600 insertions(+), 4 deletions(-) create mode 100644 config.def.h.orig create mode 100644 config.def.h.rej create mode 100644 dwm.c.orig create mode 100644 dwm.c.rej create mode 100644 patch/dwm-actualfullscreen-20211013-cb3f58a.diff diff --git a/config.def.h b/config.def.h index 8c4e309..6f18817 100644 --- a/config.def.h +++ b/config.def.h @@ -82,15 +82,16 @@ static Key keys[] = { { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY, XK_f, zoom, {0} }, + { MODKEY, XK_space, zoom, {0} }, /* { MODKEY, XK_Tab, view, {0} }, */ { MODKEY|ShiftMask, XK_x, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_e, setlayout, {.v = &layouts[2]} }, { MODKEY, XK_n, setlayout, {.v = &layouts[3]} }, - { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_f, setlayout, {0} }, { MODKEY|ShiftMask, XK_r, togglefloating, {0} }, + { MODKEY, XK_f, togglefullscr, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, { MODKEY, XK_comma, focusmon, {.i = -1 } }, diff --git a/config.def.h.orig b/config.def.h.orig new file mode 100644 index 0000000..f1a2d78 --- /dev/null +++ b/config.def.h.orig @@ -0,0 +1,133 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 2; /* border pixel of windows */ +static const unsigned int gappx = 3; /* gaps between 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 user_bh = 17; /* 0 means that dwm will calculate bar height, >= 1 means dwm will user_bh as bar height */ +static const char *fonts[] = { "JetBrainsMono Nerd Font:size=11", "FontAwesome:size=10", "NotoColorEmoji:pixelsize=11:antialias=true:autohint=true" }; + +static char normbgcolor[] = "#222222"; +static char normbordercolor[] = "#444444"; +static char normfgcolor[] = "#bbbbbb"; +static char selfgcolor[] = "#eeeeee"; +static char selbordercolor[] = "#224488"; +static char selbgcolor[] = "#224488"; +static char *colors[][3] = { +/* fg bg border */ +[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor }, +[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor }, +}; +/* tagging */ +//static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +static const char *tags[] = { " ", " ", " ", " ", " ", " ", " ", " ", " " }; + +static const Rule rules[] = { + /* xprop(1): + * 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 }, +}; + +/* 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 */ +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 */ + +#include "fibonacci.c" +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "[M]", monocle }, + { "[@]", spiral }, + { "[\\]", dwindle }, + { "><>", NULL }, /* no layout function means floating behavior */ +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#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} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run" }; +static const char *termcmd[] = { "st", NULL }; +static const char scratchpadname[] = "scratchpad"; +static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL }; + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_r, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ShiftMask, XK_Return, togglescratch, {.v = scratchpadcmd } }, + { MODKEY, XK_F5, xrdb, {.v = NULL } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_Tab, focusstack, {.i = +1 } }, + { 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_space, zoom, {0} }, + /* { MODKEY, XK_Tab, view, {0} }, */ + { MODKEY|ShiftMask, XK_x, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_e, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_n, setlayout, {.v = &layouts[3]} }, + { MODKEY|ShiftMask, XK_f, setlayout, {0} }, + { MODKEY|ShiftMask, XK_r, 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 } }, + // { MODKEY|ShiftMask, XK_h, layoutscroll, {.i = -1 } }, + { MODKEY|ShiftMask, XK_Tab, layoutscroll, {.i = +1 } }, + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + diff --git a/config.def.h.rej b/config.def.h.rej new file mode 100644 index 0000000..9f4d609 --- /dev/null +++ b/config.def.h.rej @@ -0,0 +1,10 @@ +--- config.def.h ++++ config.def.h +@@ -78,6 +78,7 @@ static Key keys[] = { + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, diff --git a/config.h b/config.h index 8c4e309..6f18817 100644 --- a/config.h +++ b/config.h @@ -82,15 +82,16 @@ static Key keys[] = { { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY, XK_f, zoom, {0} }, + { MODKEY, XK_space, zoom, {0} }, /* { MODKEY, XK_Tab, view, {0} }, */ { MODKEY|ShiftMask, XK_x, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_e, setlayout, {.v = &layouts[2]} }, { MODKEY, XK_n, setlayout, {.v = &layouts[3]} }, - { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_f, setlayout, {0} }, { MODKEY|ShiftMask, XK_r, togglefloating, {0} }, + { MODKEY, XK_f, togglefullscr, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, { MODKEY, XK_comma, focusmon, {.i = -1 } }, diff --git a/dwm b/dwm index ec53d3f72d7a186fe886743a2c83e250c3a6c5cf..48faf7c8c8f8e062626117c907cfe0772bdb56aa 100755 GIT binary patch delta 15628 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 SKA!aQn%RX{i=7#9#PmN{i#OZ= delta 15682 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 + setfullscreen(selmon->sel, !selmon->sel->isfullscreen); +} + void toggletag(const Arg *arg) { diff --git a/dwm.c.orig b/dwm.c.orig new file mode 100644 index 0000000..331c78b --- /dev/null +++ b/dwm.c.orig @@ -0,0 +1,2362 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#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))) +#define ISVISIBLE(C) ((C->tags & 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) +#define HEIGHT(X) ((X)->h + 2 * (X)->bw) +#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +#define XRDB_LOAD_COLOR(R,V) if (XrmGetResource(xrdb, R, NULL, &type, &value) == True) { \ + if (value.addr != NULL && strnlen(value.addr, 8) == 7 && value.addr[0] == '#') { \ + int i = 1; \ + for (; i <= 6; i++) { \ + if (value.addr[i] < 48) break; \ + if (value.addr[i] > 57 && value.addr[i] < 65) break; \ + if (value.addr[i] > 70 && value.addr[i] < 97) break; \ + if (value.addr[i] > 102) break; \ + } \ + if (i == 7) { \ + strncpy(V, value.addr, 7); \ + V[7] = '\0'; \ + } \ + } \ + } + +/* enums */ +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 { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +typedef struct Pertag Pertag; +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; + int ltcur; /* current layout */ + Pertag *pertag; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +static void destroynotify(XEvent *e); +static void detach(Client *c); +static void detachstack(Client *c); +static Monitor *dirtomon(int dir); +static void drawbar(Monitor *m); +static void drawbars(void); +static void enternotify(XEvent *e); +static void expose(XEvent *e); +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 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 void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void loadxrdb(void); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +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 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 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 run(void); +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 setfocus(Client *c); +static void setfullscreen(Client *c, int fullscreen); +static void layoutscroll(const Arg *arg); +static void setgaps(const Arg *arg); +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 showhide(Client *c); +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 togglescratch(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 updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static int updategeom(void); +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); +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 xrdb(const Arg *arg); +static void zoom(const Arg *arg); + +/* 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 lrpad; /* sum of left and right padding for text */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +static unsigned int scratchtag = 1 << LENGTH(tags); + +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 */ + int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ +}; + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + 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))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + 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]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (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 */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + 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))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + 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); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); + free(scheme); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clientmessage(XEvent *e) +{ + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] + || 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->message_type == netatom[NetActiveWindow]) { + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) { + 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); + } + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + 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 (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 */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + 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)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + unsigned int i; + + 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->ltcur = 0; + m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + } + + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->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); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +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); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) + drawbar(m); +} + +void +focus(Client *c) +{ + if (!c || !ISVISIBLE(c)) + for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); + if (selmon->sel && selmon->sel != c) + unfocus(selmon->sel, 0); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; + + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + XFree(p); + } + return atom; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +int +gettextprop(Window w, Atom atom, char *text, unsigned int size) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + if (!focused) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +void +grabkeys(void) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 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)); +} + +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); + } +} + +void +loadxrdb() +{ + Display *display; + char * resm; + XrmDatabase xrdb; + char *type; + XrmValue value; + + display = XOpenDisplay(NULL); + + if (display != NULL) { + resm = XResourceManagerString(display); + + if (resm != NULL) { + xrdb = XrmGetStringDatabase(resm); + + if (xrdb != NULL) { + XRDB_LOAD_COLOR("dwm.color0", normbordercolor); + XRDB_LOAD_COLOR("dwm.color8", selbordercolor); + XRDB_LOAD_COLOR("dwm.color0", normbgcolor); + XRDB_LOAD_COLOR("dwm.color6", normfgcolor); + XRDB_LOAD_COLOR("dwm.color0", selfgcolor); + XRDB_LOAD_COLOR("dwm.color14", selbgcolor); } + } + } + + XCloseDisplay(display); +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + 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->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + + selmon->tagset[selmon->seltags] &= ~scratchtag; + if (!strcmp(c->name, scratchpadname)) { + c->mon->tagset[c->mon->seltags] |= c->tags = scratchtag; + c->isfloating = True; + c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); + c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); + } + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); + XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = t || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(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; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +maprequest(XEvent *e) +{ + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; + if (wa.override_redirect) + return; + if (!wintoclient(ev->window)) + manage(ev->window, &wa); +} + +void +monocle(Monitor *m) +{ + unsigned int n = 0; + Client *c; + + for (c = m->clients; c; c = c->next) + if (ISVISIBLE(c)) + 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)) + resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + 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 (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + Window trans; + XPropertyEvent *ev = &e->xproperty; + + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +void +resize(Client *c, int x, int y, int w, int h, int interact) +{ + if (applysizehints(c, &x, &y, &w, &h, interact)) + resizeclient(c, x, y, w, h); +} + +void +resizeclient(Client *c, int x, int y, int w, int h) +{ + 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; + wc.border_width = c->bw; + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + 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); + 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; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(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) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, 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); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +void +restack(Monitor *m) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + 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)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +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); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +int +sendevent(Client *c, Atom proto) +{ + int n; + Atom *protocols; + int exists = 0; + XEvent ev; + + if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { + while (!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); + } + if (exists) { + ev.type = ClientMessage; + ev.xclient.window = c->win; + ev.xclient.message_type = wmatom[WMProtocols]; + ev.xclient.format = 32; + ev.xclient.data.l[0] = proto; + ev.xclient.data.l[1] = CurrentTime; + XSendEvent(dpy, c->win, False, NoEventMask, &ev); + } + return exists; +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); +} + +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); + c->isfullscreen = 1; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + 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; + 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); + arrange(c->mon); + } +} + +void +setgaps(const Arg *arg) +{ + if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) + selmon->gappx = 0; + else + selmon->gappx += arg->i; + arrange(selmon); +} + +void +layoutscroll(const Arg *arg) +{ + if (!arg || !arg->i) + return; + int switchto = selmon->ltcur + arg->i; + int l = LENGTH(layouts); + + if (switchto == l) + switchto = 0; + else if(switchto < 0) + switchto = l - 1; + + selmon->ltcur = switchto; + Arg arg2 = {.v= &layouts[switchto] }; + setlayout(&arg2); + +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.05 || f > 0.95) + return; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + 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 = user_bh ? user_bh : drw->fonts->h + 2; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", 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[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); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init bars */ + updatebars(); + updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} + + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +showhide(Client *c) +{ + if (!c) + return; + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + selmon->tagset[selmon->seltags] &= ~scratchtag; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +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++); + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww - m->gappx; + for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; + resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); + if (my + HEIGHT(c) + m->gappx < m->wh) + my += HEIGHT(c) + m->gappx; + } else { + h = (m->wh - ty) / (n - i) - m->gappx; + resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); + if (ty + HEIGHT(c) + m->gappx < m->wh) + ty += HEIGHT(c) + m->gappx; + } +} + +void +togglebar(const Arg *arg) +{ + 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); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + 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); +} + +void +togglescratch(const Arg *arg) +{ + Client *c; + unsigned int found = 0; + + for (c = selmon->clients; c && !(found = c->tags & scratchtag); c = c->next); + if (found) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + if (ISVISIBLE(c)) { + focus(c); + restack(selmon); + } + } else + spawn(arg); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; + + if (newtagset) { + selmon->tagset[selmon->seltags] = 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; + } + + /* 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); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + else + unmanage(c, 0); + } +} + +void +updatebars(void) +{ + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, + .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); + } +} + +void +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; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } 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; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + { /* default monitor setup */ + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + XFreeModifiermap(modmap); +} + +void +updatesizehints(Client *c) +{ + long msize; + XSizeHints size; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +updatestatus(void) +{ + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); +} + +void +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + 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) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +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) { + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + 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); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +Monitor * +wintomon(Window w) +{ + int x, y; + Client *c; + Monitor *m; + + 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; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* 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. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running"); + return -1; +} + +void +xrdb(const Arg *arg) +{ + loadxrdb(); + int i; + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + focus(NULL); + arrange(NULL); +} + +void +zoom(const Arg *arg) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + XrmInitialize(); + loadxrdb(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/dwm.c.rej b/dwm.c.rej new file mode 100644 index 0000000..46ebb95 --- /dev/null +++ b/dwm.c.rej @@ -0,0 +1,10 @@ +--- dwm.c ++++ dwm.c +@@ -211,6 +211,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglefullscr(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); diff --git a/patch/dwm-actualfullscreen-20211013-cb3f58a.diff b/patch/dwm-actualfullscreen-20211013-cb3f58a.diff new file mode 100644 index 0000000..d3be230 --- /dev/null +++ b/patch/dwm-actualfullscreen-20211013-cb3f58a.diff @@ -0,0 +1,68 @@ +From eea13010ffc3983392857ee1e3804e3aa1064d7a Mon Sep 17 00:00:00 2001 +From: Soenke Lambert +Date: Wed, 13 Oct 2021 18:21:09 +0200 +Subject: [PATCH] Fullscreen current window with [Alt]+[Shift]+[f] + +This actually fullscreens a window, instead of just hiding the statusbar +and applying the monocle layout. +--- + config.def.h | 1 + + dwm.1 | 3 +++ + dwm.c | 8 ++++++++ + 3 files changed, 12 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..8cd3204 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -78,6 +78,7 @@ static Key keys[] = { + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, +diff --git a/dwm.1 b/dwm.1 +index 13b3729..a368d05 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only). + .B Mod1\-Shift\-c + Close focused window. + .TP ++.B Mod1\-Shift\-f ++Toggle fullscreen for focused window. ++.TP + .B Mod1\-Shift\-space + Toggle focused window between tiled and floating state. + .TP +diff --git a/dwm.c b/dwm.c +index 4465af1..c1b899a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -211,6 +211,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglefullscr(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -1719,6 +1720,13 @@ togglefloating(const Arg *arg) + arrange(selmon); + } + ++void ++togglefullscr(const Arg *arg) ++{ ++ if(selmon->sel) ++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); ++} ++ + void + toggletag(const Arg *arg) + { +-- +2.30.2 +