2019-09-04 22:16:39 +00:00
|
|
|
/* 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 <errno.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <X11/cursorfont.h>
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xproto.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#ifdef XINERAMA
|
|
|
|
#include <X11/extensions/Xinerama.h>
|
|
|
|
#endif /* XINERAMA */
|
|
|
|
#include <X11/Xft/Xft.h>
|
|
|
|
|
2019-09-04 22:32:39 +00:00
|
|
|
#include "patches.h"
|
2019-09-04 22:16:39 +00:00
|
|
|
#include "drw.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
2019-10-10 21:50:30 +00:00
|
|
|
#if SPAWNCMD_PATCH
|
|
|
|
#include <assert.h>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#define SPAWN_CWD_DELIM " []{}()<>\"':"
|
|
|
|
#endif // SPAWNCMD_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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)))
|
2019-09-14 22:43:35 +00:00
|
|
|
#if ATTACHASIDE_PATCH && STICKY_PATCH
|
|
|
|
#define ISVISIBLEONTAG(C, T) ((C->tags & T) || C->issticky)
|
|
|
|
#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags])
|
|
|
|
#elif ATTACHASIDE_PATCH
|
2019-09-06 21:25:32 +00:00
|
|
|
#define ISVISIBLEONTAG(C, T) ((C->tags & T))
|
|
|
|
#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags])
|
2019-09-14 22:43:35 +00:00
|
|
|
#elif STICKY_PATCH
|
|
|
|
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
|
2019-09-06 21:25:32 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
|
2019-09-06 21:25:32 +00:00
|
|
|
#endif // ATTACHASIDE_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
#define HIDDEN(C) ((getstate(C->win) == IconicState))
|
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
#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)
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#if SCRATCHPAD_PATCH
|
|
|
|
#define NUMTAGS (LENGTH(tags) + LENGTH(scratchpads))
|
|
|
|
#define TAGMASK ((1 << NUMTAGS) - 1)
|
|
|
|
#define SPTAG(i) ((1 << LENGTH(tags)) << (i))
|
|
|
|
#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << LENGTH(tags))
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#endif // SCRATCHPAD_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
|
|
|
|
|
|
|
/* enums */
|
|
|
|
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
2019-09-13 21:56:05 +00:00
|
|
|
|
|
|
|
enum {
|
|
|
|
SchemeNorm
|
|
|
|
,SchemeSel
|
2019-10-06 22:46:23 +00:00
|
|
|
#if STATUSCOLORS_PATCH
|
|
|
|
,SchemeWarn
|
|
|
|
#endif // STATUSCOLORS_PATCH
|
|
|
|
#if URGENTBORDER_PATCH || STATUSCOLORS_PATCH
|
2019-09-15 22:13:03 +00:00
|
|
|
,SchemeUrg
|
2019-10-06 22:46:23 +00:00
|
|
|
#endif // URGENTBORDER_PATCH || STATUSCOLORS_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
,SchemeHid
|
|
|
|
#endif // AWESOMEBAR_PATCH
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
,SchemeTagsNorm
|
|
|
|
,SchemeTagsSel
|
|
|
|
,SchemeTitleNorm
|
|
|
|
,SchemeTitleSel
|
|
|
|
,SchemeStatus
|
|
|
|
#elif TITLECOLOR_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
,SchemeTitle
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
}; /* color schemes */
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
|
|
|
|
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
2019-09-11 22:48:29 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
|
|
|
|
NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz,
|
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
#if EWMHTAGS_PATCH
|
|
|
|
NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop,
|
|
|
|
#endif // EWMHTAGS_PATCH
|
|
|
|
NetWMWindowTypeDialog, NetClientList, NetLast
|
|
|
|
}; /* EWMH atoms */
|
|
|
|
|
2019-09-07 21:46:08 +00:00
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMWindowRole, WMLast }; /* default atoms */
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
|
2019-09-07 21:46:08 +00:00
|
|
|
#endif // WINDOWROLERULE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2019-09-08 22:18:47 +00:00
|
|
|
#if CFACTS_PATCH
|
|
|
|
float cfact;
|
|
|
|
#endif // CFACTS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int x, y, w, h;
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int oldx, oldy, oldw, oldh;
|
|
|
|
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
|
|
|
int bw, oldbw;
|
|
|
|
unsigned int tags;
|
2019-11-26 19:23:58 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
unsigned int switchtag;
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
2020-03-20 15:45:20 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
int fakefullscreen;
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-24 06:47:00 +00:00
|
|
|
#if EXRESIZE_PATCH
|
|
|
|
unsigned char expandmask;
|
|
|
|
int expandx1, expandy1, expandx2, expandy2;
|
|
|
|
#if !MAXIMIZE_PATCH
|
|
|
|
int wasfloating;
|
|
|
|
#endif // MAXIMIZE_PATCH
|
|
|
|
#endif // EXRESIZE_PATCH
|
2019-10-04 20:46:47 +00:00
|
|
|
#if MAXIMIZE_PATCH
|
|
|
|
int ismax, wasfloating;
|
|
|
|
#endif // MAXIMIZE_PATCH
|
2019-09-12 22:06:54 +00:00
|
|
|
#if AUTORESIZE_PATCH
|
|
|
|
int needresize;
|
|
|
|
#endif // AUTORESIZE_PATCH
|
2019-09-07 22:23:30 +00:00
|
|
|
#if CENTER_PATCH
|
|
|
|
int iscentered;
|
|
|
|
#endif // CENTER_PATCH
|
2019-10-22 16:30:00 +00:00
|
|
|
#if ISPERMANENT_PATCH
|
|
|
|
int ispermanent;
|
|
|
|
#endif // ISPERMANENT_PATCH
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
int isterminal, noswallow;
|
|
|
|
pid_t pid;
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-14 22:43:35 +00:00
|
|
|
#if STICKY_PATCH
|
|
|
|
int issticky;
|
|
|
|
#endif // STICKY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Client *next;
|
|
|
|
Client *snext;
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
Client *swallowing;
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Monitor *mon;
|
|
|
|
Window win;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
unsigned int mod;
|
|
|
|
KeySym keysym;
|
|
|
|
void (*func)(const Arg *);
|
|
|
|
const Arg arg;
|
|
|
|
} Key;
|
|
|
|
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
typedef struct {
|
|
|
|
int nmaster;
|
|
|
|
int nstack;
|
|
|
|
int layout;
|
|
|
|
int masteraxis; // master stack area
|
|
|
|
int stack1axis; // primary stack area
|
|
|
|
int stack2axis; // secondary stack area, e.g. centered master
|
|
|
|
void (*symbolfunc)(Monitor *, unsigned int);
|
|
|
|
} LayoutPreset;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
typedef struct {
|
|
|
|
const char *symbol;
|
|
|
|
void (*arrange)(Monitor *);
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
LayoutPreset preset;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
2019-09-04 22:16:39 +00:00
|
|
|
} Layout;
|
|
|
|
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
typedef struct Pertag Pertag;
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
struct Monitor {
|
|
|
|
char ltsymbol[16];
|
|
|
|
float mfact;
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
int ltaxis[4];
|
|
|
|
int nstack;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
2019-09-04 22:16:39 +00:00
|
|
|
int nmaster;
|
|
|
|
int num;
|
|
|
|
int by; /* bar geometry */
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
int eby; /* extra bar geometry */
|
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
int btw; /* width of tasks portion of bar */
|
|
|
|
int bt; /* number of tasks */
|
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int mx, my, mw, mh; /* screen size */
|
|
|
|
int wx, wy, ww, wh; /* window area */
|
2019-09-08 22:18:47 +00:00
|
|
|
#if VANITYGAPS_PATCH
|
|
|
|
int gappih; /* horizontal gap between windows */
|
|
|
|
int gappiv; /* vertical gap between windows */
|
|
|
|
int gappoh; /* horizontal outer gaps */
|
|
|
|
int gappov; /* vertical outer gaps */
|
|
|
|
#endif // VANITYGAPS_PATCH
|
2019-09-14 21:28:04 +00:00
|
|
|
#if SETBORDERPX_PATCH
|
|
|
|
unsigned int borderpx;
|
|
|
|
#endif // SETBORDERPX_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
unsigned int seltags;
|
|
|
|
unsigned int sellt;
|
|
|
|
unsigned int tagset[2];
|
|
|
|
int showbar;
|
|
|
|
int topbar;
|
|
|
|
Client *clients;
|
|
|
|
Client *sel;
|
|
|
|
Client *stack;
|
|
|
|
Monitor *next;
|
|
|
|
Window barwin;
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
Window extrabarwin;
|
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
const Layout *lt[2];
|
2019-09-09 21:27:10 +00:00
|
|
|
#if ALTERNATIVE_TAGS_PATCH
|
|
|
|
unsigned int alttag;
|
|
|
|
#endif // ALTERNATIVE_TAGS_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
Pertag *pertag;
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char *class;
|
2019-09-07 21:46:08 +00:00
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
const char *role;
|
|
|
|
#endif // WINDOWROLERULE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
const char *instance;
|
|
|
|
const char *title;
|
|
|
|
unsigned int tags;
|
2019-09-07 22:23:30 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
int switchtag;
|
|
|
|
#endif // SWITCHTAG_PATCH
|
|
|
|
#if CENTER_PATCH
|
|
|
|
int iscentered;
|
|
|
|
#endif // CENTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int isfloating;
|
2019-10-22 16:30:00 +00:00
|
|
|
#if ISPERMANENT_PATCH
|
|
|
|
int ispermanent;
|
|
|
|
#endif // ISPERMANENT_PATCH
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
int isterminal;
|
|
|
|
int noswallow;
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int monitor;
|
|
|
|
} Rule;
|
|
|
|
|
2019-09-11 06:28:00 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
|
|
|
typedef struct {
|
|
|
|
int monitor;
|
2019-09-30 21:52:51 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
int tag;
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-11 06:28:00 +00:00
|
|
|
int layout;
|
2019-09-30 21:52:51 +00:00
|
|
|
float mfact;
|
2019-09-11 06:28:00 +00:00
|
|
|
} MonitorRule;
|
|
|
|
#endif // MONITOR_RULES_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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);
|
2019-09-15 22:32:28 +00:00
|
|
|
#if !FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void enternotify(XEvent *e);
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void expose(XEvent *e);
|
|
|
|
static void focus(Client *c);
|
|
|
|
static void focusin(XEvent *e);
|
|
|
|
static void focusmon(const Arg *arg);
|
2020-03-23 11:15:50 +00:00
|
|
|
#if !STACKER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void focusstack(const Arg *arg);
|
2020-03-23 11:15:50 +00:00
|
|
|
#endif // STACKER_PATCH
|
2020-04-23 06:00:22 +00:00
|
|
|
static Atom getatomprop(Client *c, Atom prop);
|
2019-09-04 22:16:39 +00:00
|
|
|
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 manage(Window w, XWindowAttributes *wa);
|
|
|
|
static void mappingnotify(XEvent *e);
|
|
|
|
static void maprequest(XEvent *e);
|
2019-09-15 22:32:28 +00:00
|
|
|
#if !FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void motionnotify(XEvent *e);
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void movemouse(const Arg *arg);
|
|
|
|
static Client *nexttiled(Client *c);
|
2019-10-06 21:43:51 +00:00
|
|
|
#if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void pop(Client *);
|
2019-10-06 21:43:51 +00:00
|
|
|
#endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
static int sendevent(Client *c, Atom proto);
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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 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 togglebar(const Arg *arg);
|
|
|
|
static void togglefloating(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 zoom(const Arg *arg);
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#include "patch/include.h"
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* variables */
|
|
|
|
static const char broken[] = "broken";
|
|
|
|
static char stext[256];
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
static char estext[256];
|
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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 */
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
static int vp; /* vertical padding for bar */
|
|
|
|
static int sp; /* side padding for bar */
|
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
|
|
|
static unsigned int numlockmask = 0;
|
|
|
|
static void (*handler[LASTEvent]) (XEvent *) = {
|
|
|
|
[ButtonPress] = buttonpress,
|
2019-10-01 22:03:21 +00:00
|
|
|
#if COMBO_PATCH || HOLDBAR_PATCH
|
2019-09-11 21:35:43 +00:00
|
|
|
[ButtonRelease] = keyrelease,
|
2019-10-01 22:03:21 +00:00
|
|
|
#endif // COMBO_PATCH / HOLDBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[ClientMessage] = clientmessage,
|
|
|
|
[ConfigureRequest] = configurerequest,
|
|
|
|
[ConfigureNotify] = configurenotify,
|
|
|
|
[DestroyNotify] = destroynotify,
|
2019-09-15 22:32:28 +00:00
|
|
|
#if !FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[EnterNotify] = enternotify,
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[Expose] = expose,
|
|
|
|
[FocusIn] = focusin,
|
|
|
|
[KeyPress] = keypress,
|
2019-10-01 22:03:21 +00:00
|
|
|
#if COMBO_PATCH || HOLDBAR_PATCH
|
2019-09-11 21:35:43 +00:00
|
|
|
[KeyRelease] = keyrelease,
|
2019-10-01 22:03:21 +00:00
|
|
|
#endif // COMBO_PATCH / HOLDBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[MappingNotify] = mappingnotify,
|
|
|
|
[MapRequest] = maprequest,
|
2019-09-15 22:32:28 +00:00
|
|
|
#if !FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[MotionNotify] = motionnotify,
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[PropertyNotify] = propertynotify,
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
[ResizeRequest] = resizerequest,
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[UnmapNotify] = unmapnotify
|
|
|
|
};
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
static Atom wmatom[WMLast], netatom[NetLast];
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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"
|
|
|
|
|
2019-09-04 22:32:39 +00:00
|
|
|
#include "patch/include.c"
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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;
|
2019-09-07 21:46:08 +00:00
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
char role[64];
|
|
|
|
#endif // WINDOWROLERULE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2019-09-07 21:46:08 +00:00
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
|
|
|
|
#endif // WINDOWROLERULE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
for (i = 0; i < LENGTH(rules); i++) {
|
|
|
|
r = &rules[i];
|
|
|
|
if ((!r->title || strstr(c->name, r->title))
|
|
|
|
&& (!r->class || strstr(class, r->class))
|
2019-09-07 21:46:08 +00:00
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
&& (!r->role || strstr(role, r->role))
|
|
|
|
#endif // WINDOWROLERULE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
&& (!r->instance || strstr(instance, r->instance)))
|
|
|
|
{
|
2019-09-07 22:23:30 +00:00
|
|
|
#if CENTER_PATCH
|
|
|
|
c->iscentered = r->iscentered;
|
|
|
|
#endif // CENTER_PATCH
|
2019-10-22 16:30:00 +00:00
|
|
|
#if ISPERMANENT_PATCH
|
|
|
|
c->ispermanent = r->ispermanent;
|
|
|
|
#endif // ISPERMANENT_PATCH
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
c->isterminal = r->isterminal;
|
|
|
|
c->noswallow = r->noswallow;
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
c->isfloating = r->isfloating;
|
|
|
|
c->tags |= r->tags;
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#if SCRATCHPAD_PATCH && !SCRATCHPAD_KEEP_POSITION_AND_SIZE_PATCH
|
|
|
|
if ((r->tags & SPTAGMASK) && r->isfloating) {
|
|
|
|
c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
|
|
|
c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
|
|
|
}
|
|
|
|
#endif // SCRATCHPAD_PATCH | SCRATCHPAD_KEEP_POSITION_AND_SIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
for (m = mons; m && m->num != r->monitor; m = m->next);
|
|
|
|
if (m)
|
|
|
|
c->mon = m;
|
2019-09-07 22:23:30 +00:00
|
|
|
|
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
if (r->switchtag) {
|
|
|
|
unsigned int newtagset;
|
|
|
|
if (r->switchtag == 2)
|
|
|
|
newtagset = c->mon->tagset[c->mon->seltags] ^ c->tags;
|
|
|
|
else
|
|
|
|
newtagset = c->tags;
|
|
|
|
|
|
|
|
if (newtagset) {
|
2019-11-26 19:23:58 +00:00
|
|
|
c->switchtag = selmon->tagset[selmon->seltags];
|
2019-09-07 22:23:30 +00:00
|
|
|
c->mon->tagset[c->mon->seltags] = newtagset;
|
2019-09-30 21:52:51 +00:00
|
|
|
if (r->switchtag == 1)
|
2019-11-26 19:23:58 +00:00
|
|
|
#if PERTAG_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
pertagview(&((Arg) { .ui = newtagset }));
|
2019-11-26 19:23:58 +00:00
|
|
|
#else
|
|
|
|
view(&((Arg) { .ui = newtagset }));
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-07 22:23:30 +00:00
|
|
|
arrange(c->mon);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-23 11:16:13 +00:00
|
|
|
if (ch.res_class)
|
|
|
|
XFree(ch.res_class);
|
|
|
|
if (ch.res_name)
|
|
|
|
XFree(ch.res_name);
|
2019-10-02 21:22:04 +00:00
|
|
|
#if EMPTYVIEW_PATCH
|
2020-04-23 11:16:13 +00:00
|
|
|
if (c->tags & TAGMASK) c->tags = c->tags & TAGMASK;
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#if SCRATCHPAD_PATCH
|
2020-04-23 11:16:13 +00:00
|
|
|
else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags] & ~SPTAGMASK;
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#else
|
2020-04-23 11:16:13 +00:00
|
|
|
else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags];
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#endif // SCRATCHPAD_PATCH
|
2019-10-02 21:22:04 +00:00
|
|
|
else c->tags = 1;
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#elif SCRATCHPAD_PATCH
|
|
|
|
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK);
|
2019-10-02 21:22:04 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
|
2019-10-02 21:22:04 +00:00
|
|
|
#endif // EMPTYVIEW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-03-31 06:21:00 +00:00
|
|
|
#if ROUNDED_CORNERS_PATCH
|
|
|
|
Client *c;
|
|
|
|
for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
|
|
|
|
drawroundedcorners(c);
|
|
|
|
#endif // ROUNDED_CORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2020-04-13 12:59:58 +00:00
|
|
|
int padding = 0;
|
|
|
|
#if STATUSCMD_PATCH
|
|
|
|
unsigned int xc;
|
|
|
|
#endif // STATUSCMD_PATCH
|
2019-10-05 21:28:50 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
unsigned int columns;
|
|
|
|
#endif // TAGGRID_PATCH
|
2019-10-05 21:44:18 +00:00
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
unsigned int occ = 0;
|
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Arg arg = {0};
|
|
|
|
Client *c;
|
|
|
|
Monitor *m;
|
|
|
|
XButtonPressedEvent *ev = &e->xbutton;
|
2020-04-13 12:59:58 +00:00
|
|
|
#if STATUSCMD_PATCH
|
|
|
|
lastbutton = ev->button;
|
|
|
|
#endif // STATUSCMD_PATCH
|
|
|
|
#if AWESOMEBAR_PATCH || STATUSCMD_PATCH
|
|
|
|
padding += lrpad - 2;
|
|
|
|
#endif // AWESOMEBAR_PATCH | STATUSCMD_PATCH
|
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
padding -= getsystraywidth();
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2019-10-05 21:28:50 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
columns = LENGTH(tags) / tagrows + ((LENGTH(tags) % tagrows > 0) ? 1 : 0);
|
|
|
|
#endif // TAGGRID_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
click = ClkRootWin;
|
|
|
|
/* focus monitor if necessary */
|
2019-09-15 22:32:28 +00:00
|
|
|
if ((m = wintomon(ev->window)) && m != selmon
|
|
|
|
#if FOCUSONCLICK_PATCH
|
|
|
|
&& (focusonwheel || (ev->button != Button4 && ev->button != Button5))
|
|
|
|
#endif // FOCUSONCLICK_PATCH
|
|
|
|
) {
|
2019-09-04 22:16:39 +00:00
|
|
|
unfocus(selmon->sel, 1);
|
|
|
|
selmon = m;
|
|
|
|
focus(NULL);
|
|
|
|
}
|
|
|
|
if (ev->window == selmon->barwin) {
|
|
|
|
i = x = 0;
|
2019-10-01 20:46:24 +00:00
|
|
|
#if LEFTLAYOUT_PATCH
|
|
|
|
x += blw;
|
|
|
|
if (ev->x < x) {
|
2020-01-30 07:43:00 +00:00
|
|
|
click = ClkLtSymbol;
|
2019-10-01 20:46:24 +00:00
|
|
|
} else {
|
2019-10-07 22:54:06 +00:00
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
for (c = m->clients; c; c = c->next)
|
|
|
|
occ |= c->tags == 255 ? 0 : c->tags;
|
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
|
|
|
#if TAGGRID_PATCH
|
|
|
|
if (drawtagmask & DRAWCLASSICTAGS)
|
|
|
|
#endif // TAGGRID_PATCH
|
|
|
|
do {
|
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
/* do not reserve space for vacant tags */
|
|
|
|
if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
|
|
|
|
continue;
|
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-10-01 20:46:24 +00:00
|
|
|
x += TEXTW(tags[i]);
|
2019-10-07 22:54:06 +00:00
|
|
|
} while (ev->x >= x && ++i < LENGTH(tags));
|
2019-10-01 20:46:24 +00:00
|
|
|
if (i < LENGTH(tags)) {
|
|
|
|
click = ClkTagBar;
|
|
|
|
arg.ui = 1 << i;
|
2019-10-07 22:54:06 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
} else if (ev->x < x + columns * bh / tagrows && (drawtagmask & DRAWTAGGRID)) {
|
|
|
|
click = ClkTagBar;
|
|
|
|
i = (ev->x - x) / (bh / tagrows);
|
|
|
|
i = i + columns * (ev->y / (bh / tagrows));
|
|
|
|
if (i >= LENGTH(tags)) {
|
|
|
|
i = LENGTH(tags) - 1;
|
|
|
|
}
|
|
|
|
arg.ui = 1 << i;
|
2019-10-01 20:46:24 +00:00
|
|
|
}
|
2019-10-07 22:54:06 +00:00
|
|
|
else if (ev->x < x + blw + columns * bh / tagrows)
|
|
|
|
click = ClkLtSymbol;
|
|
|
|
#else // TAGGRID_PATCH
|
|
|
|
} else if (ev->x < x + blw)
|
|
|
|
click = ClkLtSymbol;
|
|
|
|
#endif // TAGGRID_PATCH
|
2020-04-13 12:59:58 +00:00
|
|
|
else if (ev->x > selmon->ww - TEXTW(stext) + padding)
|
|
|
|
#if !STATUSCMD_PATCH
|
|
|
|
click = ClkStatusText;
|
2019-10-01 20:46:24 +00:00
|
|
|
#else
|
2020-04-13 12:59:58 +00:00
|
|
|
{
|
2019-10-01 20:46:24 +00:00
|
|
|
click = ClkStatusText;
|
2020-04-13 12:59:58 +00:00
|
|
|
|
|
|
|
xc = selmon->ww - TEXTW(stext) + padding;
|
|
|
|
char *text = rawstext;
|
|
|
|
int i = -1;
|
|
|
|
char ch;
|
|
|
|
statuscmdn = 0;
|
|
|
|
while (text[++i]) {
|
|
|
|
if ((unsigned char)text[i] < ' ') {
|
|
|
|
ch = text[i];
|
|
|
|
text[i] = '\0';
|
|
|
|
xc += TEXTW(text) - lrpad;
|
|
|
|
text[i] = ch;
|
|
|
|
text += i+1;
|
|
|
|
i = -1;
|
|
|
|
if (xc >= ev->x)
|
|
|
|
break;
|
|
|
|
if (ch <= LENGTH(statuscmds))
|
|
|
|
statuscmdn = ch - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // STATUSCMD_PATCH
|
2019-10-01 20:46:24 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
else {
|
|
|
|
x += blw;
|
|
|
|
c = m->clients;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (!ISVISIBLE(c))
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
x += (1.0 / (double)m->bt) * m->btw;
|
|
|
|
} while (ev->x > x && (c = c->next));
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
click = ClkWinTitle;
|
|
|
|
arg.v = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2020-04-13 12:59:58 +00:00
|
|
|
} else
|
|
|
|
click = ClkWinTitle;
|
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-10-01 20:46:24 +00:00
|
|
|
}
|
|
|
|
#else // LEFTLAYOUT_PATCH
|
2019-10-05 21:44:18 +00:00
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
for (c = m->clients; c; c = c->next)
|
|
|
|
occ |= c->tags == 255 ? 0 : c->tags;
|
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-10-07 22:54:06 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
if (drawtagmask & DRAWCLASSICTAGS)
|
|
|
|
#endif // TAGGRID_PATCH
|
2019-10-05 21:44:18 +00:00
|
|
|
do {
|
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
/* do not reserve space for vacant tags */
|
|
|
|
if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
|
|
|
|
continue;
|
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
x += TEXTW(tags[i]);
|
2019-10-05 21:44:18 +00:00
|
|
|
} while (ev->x >= x && ++i < LENGTH(tags));
|
2019-10-05 21:28:50 +00:00
|
|
|
if (i < LENGTH(tags)
|
|
|
|
#if TAGGRID_PATCH
|
|
|
|
&& (drawtagmask & DRAWCLASSICTAGS)
|
|
|
|
#endif
|
|
|
|
) {
|
2019-09-04 22:16:39 +00:00
|
|
|
click = ClkTagBar;
|
|
|
|
arg.ui = 1 << i;
|
2019-10-05 21:28:50 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
} else if (ev->x < x + columns * bh / tagrows && (drawtagmask & DRAWTAGGRID)) {
|
|
|
|
click = ClkTagBar;
|
|
|
|
i = (ev->x - x) / (bh / tagrows);
|
|
|
|
i = i + columns * (ev->y / (bh / tagrows));
|
|
|
|
if (i >= LENGTH(tags)) {
|
|
|
|
i = LENGTH(tags) - 1;
|
|
|
|
}
|
|
|
|
arg.ui = 1 << i;
|
|
|
|
}
|
|
|
|
else if (ev->x < x + blw + columns * bh / tagrows)
|
|
|
|
click = ClkLtSymbol;
|
2019-10-07 22:54:06 +00:00
|
|
|
#else // TAGGRID_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} else if (ev->x < x + blw)
|
|
|
|
click = ClkLtSymbol;
|
2019-10-05 21:28:50 +00:00
|
|
|
#endif // TAGGRID_PATCH
|
2020-04-13 12:59:58 +00:00
|
|
|
else if (ev->x > selmon->ww - TEXTW(stext) + padding)
|
|
|
|
#if !STATUSCMD_PATCH
|
|
|
|
click = ClkStatusText;
|
2019-09-05 20:10:00 +00:00
|
|
|
#else
|
2020-04-13 12:59:58 +00:00
|
|
|
{
|
2019-09-04 22:16:39 +00:00
|
|
|
click = ClkStatusText;
|
2020-04-13 12:59:58 +00:00
|
|
|
|
|
|
|
xc = selmon->ww - TEXTW(stext) + padding;
|
|
|
|
char *text = rawstext;
|
|
|
|
int i = -1;
|
|
|
|
char ch;
|
|
|
|
statuscmdn = 0;
|
|
|
|
while (text[++i]) {
|
|
|
|
if ((unsigned char)text[i] < ' ') {
|
|
|
|
ch = text[i];
|
|
|
|
text[i] = '\0';
|
|
|
|
xc += TEXTW(text) - lrpad;
|
|
|
|
text[i] = ch;
|
|
|
|
text += i+1;
|
|
|
|
i = -1;
|
|
|
|
if (xc >= ev->x)
|
|
|
|
break;
|
|
|
|
if (ch <= LENGTH(statuscmds))
|
|
|
|
statuscmdn = ch - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // STATUSCMD_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
else {
|
|
|
|
x += blw;
|
|
|
|
c = m->clients;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (!ISVISIBLE(c))
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
x += (1.0 / (double)m->bt) * m->btw;
|
|
|
|
} while (ev->x > x && (c = c->next));
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
click = ClkWinTitle;
|
|
|
|
arg.v = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
else
|
|
|
|
click = ClkWinTitle;
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-10-01 20:46:24 +00:00
|
|
|
#endif // LEFTLAYOUT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} else if ((c = wintoclient(ev->window))) {
|
2019-09-15 22:32:28 +00:00
|
|
|
#if FOCUSONCLICK_PATCH
|
|
|
|
if (focusonwheel || (ev->button != Button4 && ev->button != Button5))
|
|
|
|
focus(c);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(c);
|
|
|
|
restack(selmon);
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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))
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray) {
|
|
|
|
XUnmapWindow(dpy, systray->win);
|
|
|
|
XDestroyWindow(dpy, systray->win);
|
|
|
|
free(systray);
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
for (i = 0; i < CurLast; i++)
|
|
|
|
drw_cur_free(drw, cursor[i]);
|
|
|
|
for (i = 0; i < LENGTH(colors); i++)
|
|
|
|
free(scheme[i]);
|
2020-01-27 08:15:20 +00:00
|
|
|
free(scheme);
|
2019-09-04 22:16:39 +00:00
|
|
|
XDestroyWindow(dpy, wmcheckwin);
|
2020-01-27 08:15:20 +00:00
|
|
|
drw_fontset_free(drw->fonts);
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
XUnmapWindow(dpy, mon->extrabarwin);
|
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XDestroyWindow(dpy, mon->barwin);
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
XDestroyWindow(dpy, mon->extrabarwin);
|
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
free(mon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
clientmessage(XEvent *e)
|
|
|
|
{
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
XWindowAttributes wa;
|
|
|
|
XSetWindowAttributes swa;
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XClientMessageEvent *cme = &e->xclient;
|
|
|
|
Client *c = wintoclient(cme->window);
|
2019-09-06 22:03:04 +00:00
|
|
|
#if FOCUSONNETACTIVE_PATCH
|
|
|
|
unsigned int i;
|
|
|
|
#endif // FOCUSONNETACTIVE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear status bar to avoid artifacts beneath systray icons */
|
|
|
|
drw_rect(drw, 0, 0, selmon->ww, bh, 1, 1);
|
|
|
|
drw_map(drw, selmon->barwin, 0, 0, selmon->ww, bh);
|
|
|
|
|
|
|
|
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);
|
|
|
|
drawbar(selmon);
|
|
|
|
updatesystray();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!c)
|
|
|
|
return;
|
|
|
|
if (cme->message_type == netatom[NetWMState]) {
|
|
|
|
if (cme->data.l[1] == netatom[NetWMFullscreen]
|
2020-04-03 14:57:19 +00:00
|
|
|
|| cme->data.l[2] == netatom[NetWMFullscreen]) {
|
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (c->fakefullscreen)
|
|
|
|
resizeclient(c, c->x, c->y, c->w, c->h);
|
|
|
|
else
|
|
|
|
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
|
|
|
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */
|
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
|
|
|
&& !c->isfullscreen
|
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
|
|
|
)));
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|
2019-10-08 21:15:11 +00:00
|
|
|
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */
|
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
|
|
|
&& !c->isfullscreen
|
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
|
|
|
)));
|
2020-04-03 14:57:19 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
} else if (cme->message_type == netatom[NetActiveWindow]) {
|
2019-09-06 22:03:04 +00:00
|
|
|
#if 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);
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c != selmon->sel && !c->isurgent)
|
|
|
|
seturgent(c, 1);
|
2019-09-06 22:03:04 +00:00
|
|
|
#endif // FOCUSONNETACTIVE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Client *c;
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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) {
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
for (c = m->clients; c; c = c->next)
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (c->isfullscreen && !c->fakefullscreen)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->isfullscreen)
|
2019-11-21 11:15:16 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
resizeclient(c, m->mx, m->my, m->mw, m->mh);
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
2020-01-24 19:41:08 +00:00
|
|
|
XMoveResizeWindow(dpy, m->extrabarwin, m->wx + sp, m->eby - vp, m->ww - 2 * sp, bh);
|
2020-01-24 09:47:13 +00:00
|
|
|
#else
|
2019-10-24 05:35:00 +00:00
|
|
|
XMoveResizeWindow(dpy, m->extrabarwin, m->wx, m->eby, m->ww, bh);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
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);
|
2019-09-12 22:06:54 +00:00
|
|
|
#if AUTORESIZE_PATCH
|
|
|
|
else
|
|
|
|
c->needresize = 1;
|
|
|
|
#endif // AUTORESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} 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;
|
2019-09-30 21:52:51 +00:00
|
|
|
#if PERTAG_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
int i;
|
2019-09-30 21:52:51 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-09-11 06:28:00 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
int mc, j;
|
2019-09-11 06:28:00 +00:00
|
|
|
Monitor *mi;
|
|
|
|
const MonitorRule *mr;
|
|
|
|
#endif // MONITOR_RULES_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
m = ecalloc(1, sizeof(Monitor));
|
2019-10-02 21:22:04 +00:00
|
|
|
#if EMPTYVIEW_PATCH
|
|
|
|
m->tagset[0] = m->tagset[1] = 0;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
m->tagset[0] = m->tagset[1] = 1;
|
2019-10-02 21:22:04 +00:00
|
|
|
#endif // EMPTYVIEW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
m->mfact = mfact;
|
|
|
|
m->nmaster = nmaster;
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
m->nstack = nstack;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
2019-09-04 22:16:39 +00:00
|
|
|
m->showbar = showbar;
|
|
|
|
m->topbar = topbar;
|
2019-09-14 21:28:04 +00:00
|
|
|
#if SETBORDERPX_PATCH
|
|
|
|
m->borderpx = borderpx;
|
|
|
|
#endif // SETBORDERPX_PATCH
|
2019-09-08 22:18:47 +00:00
|
|
|
#if VANITYGAPS_PATCH
|
|
|
|
m->gappih = gappih;
|
|
|
|
m->gappiv = gappiv;
|
|
|
|
m->gappoh = gappoh;
|
|
|
|
m->gappov = gappov;
|
|
|
|
#endif // VANITYGAPS_PATCH
|
2019-09-11 06:28:00 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
|
|
|
for (mc = 0, mi = mons; mi; mi = mi->next, mc++);
|
2019-09-30 21:52:51 +00:00
|
|
|
for (j = 0; j < LENGTH(monrules); j++) {
|
|
|
|
mr = &monrules[j];
|
|
|
|
if ((mr->monitor == -1 || mr->monitor == mc)
|
|
|
|
#if PERTAG_PATCH
|
|
|
|
&& (mr->tag == -1 || mr->tag == 0)
|
|
|
|
#endif // PERTAG_PATCH
|
|
|
|
) {
|
2019-09-11 06:28:00 +00:00
|
|
|
m->lt[0] = &layouts[mr->layout];
|
|
|
|
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
|
|
|
strncpy(m->ltsymbol, layouts[mr->layout].symbol, sizeof m->ltsymbol);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
m->lt[0] = &layouts[0];
|
|
|
|
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
|
|
|
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
|
|
|
#endif // MONITOR_RULES_PATCH
|
2019-09-09 20:25:19 +00:00
|
|
|
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
m->ltaxis[LAYOUT] = m->lt[0]->preset.layout;
|
|
|
|
m->ltaxis[MASTER] = m->lt[0]->preset.masteraxis;
|
|
|
|
m->ltaxis[STACK] = m->lt[0]->preset.stack1axis;
|
|
|
|
m->ltaxis[STACK2] = m->lt[0]->preset.stack2axis;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
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;
|
2019-09-11 06:28:00 +00:00
|
|
|
for (i = 0; i <= LENGTH(tags); i++) {
|
2019-09-05 20:58:16 +00:00
|
|
|
/* init nmaster */
|
|
|
|
m->pertag->nmasters[i] = m->nmaster;
|
|
|
|
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
m->pertag->nstacks[i] = m->nstack;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
|
2019-09-05 20:58:16 +00:00
|
|
|
/* init mfacts */
|
|
|
|
m->pertag->mfacts[i] = m->mfact;
|
|
|
|
|
|
|
|
/* init layouts */
|
2019-09-30 21:52:51 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
|
|
|
for (j = 0; j < LENGTH(monrules); j++) {
|
|
|
|
mr = &monrules[j];
|
|
|
|
if ((mr->monitor == -1 || mr->monitor == mc) && (mr->tag == -1 || mr->tag == i)) {
|
|
|
|
m->pertag->ltidxs[i][0] = &layouts[mr->layout];
|
|
|
|
m->pertag->ltidxs[i][1] = m->lt[0];
|
|
|
|
if (mr->mfact != -1)
|
|
|
|
m->pertag->mfacts[i] = mr->mfact;
|
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
m->pertag->ltaxis[i][LAYOUT] = m->pertag->ltidxs[i][0]->preset.layout;
|
|
|
|
m->pertag->ltaxis[i][MASTER] = m->pertag->ltidxs[i][0]->preset.masteraxis;
|
|
|
|
m->pertag->ltaxis[i][STACK] = m->pertag->ltidxs[i][0]->preset.stack1axis;
|
|
|
|
m->pertag->ltaxis[i][STACK2] = m->pertag->ltidxs[i][0]->preset.stack2axis;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2019-09-05 20:58:16 +00:00
|
|
|
m->pertag->ltidxs[i][0] = m->lt[0];
|
|
|
|
m->pertag->ltidxs[i][1] = m->lt[1];
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
2019-09-09 20:25:19 +00:00
|
|
|
/* init flextile axes */
|
2019-09-30 21:52:51 +00:00
|
|
|
m->pertag->ltaxis[i][LAYOUT] = m->ltaxis[LAYOUT];
|
|
|
|
m->pertag->ltaxis[i][MASTER] = m->ltaxis[MASTER];
|
|
|
|
m->pertag->ltaxis[i][STACK] = m->ltaxis[STACK];
|
|
|
|
m->pertag->ltaxis[i][STACK2] = m->ltaxis[STACK2];
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
#endif // MONITOR_RULES_PATCH
|
|
|
|
m->pertag->sellts[i] = m->sellt;
|
2019-09-09 20:25:19 +00:00
|
|
|
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAGBAR_PATCH
|
|
|
|
/* init showbar */
|
|
|
|
m->pertag->showbars[i] = m->showbar;
|
|
|
|
|
|
|
|
/* swap focus and zoomswap*/
|
2020-01-24 10:25:32 +00:00
|
|
|
#if ZOOMSWAP_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
m->pertag->prevzooms[i] = NULL;
|
2020-01-24 10:25:32 +00:00
|
|
|
#endif // ZOOMSWAP_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAGBAR_PATCH
|
2020-03-07 11:44:42 +00:00
|
|
|
|
|
|
|
#if VANITYGAPS_PATCH
|
|
|
|
m->pertag->enablegaps[i] = 1;
|
|
|
|
#endif // VANITYGAPS_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
}
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
destroynotify(XEvent *e)
|
|
|
|
{
|
|
|
|
Client *c;
|
|
|
|
XDestroyWindowEvent *ev = &e->xdestroywindow;
|
|
|
|
|
|
|
|
if ((c = wintoclient(ev->window)))
|
|
|
|
unmanage(c, 1);
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
else if ((c = swallowingclient(ev->window)))
|
|
|
|
unmanage(c->swallowing, 1);
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
else if (showsystray && (c = wintosystrayicon(ev->window))) {
|
|
|
|
removesystrayicon(c);
|
|
|
|
updatesystray();
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2020-04-23 06:07:29 +00:00
|
|
|
int x, w, tw = 0, stw = 0, stp = 0, invert;
|
2019-09-09 21:27:10 +00:00
|
|
|
#if ALTERNATIVE_TAGS_PATCH
|
|
|
|
int wdelta;
|
|
|
|
#endif // ALTERNATIVE_TAGS_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
int n = 0, scm;
|
|
|
|
#elif FANCYBAR_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
int tw, mw, ew = 0;
|
2019-09-09 22:18:46 +00:00
|
|
|
int n = 0;
|
|
|
|
#endif // FANCYBAR_PATCH, AWESOMEBAR_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
stw = 2 * sp;
|
|
|
|
#endif // BARPADDING_PATCH
|
|
|
|
#if STATUSPADDING_PATCH
|
|
|
|
stp = lrpad / 2;
|
|
|
|
#endif // STATUSPADDING_PATCH
|
2019-10-06 21:43:51 +00:00
|
|
|
#if !HIDEVACANTTAGS_PATCH
|
2019-09-12 22:06:54 +00:00
|
|
|
#if !ACTIVETAGINDICATORBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int boxs = drw->fonts->h / 9;
|
2019-09-12 22:06:54 +00:00
|
|
|
#endif // ACTIVETAGINDICATORBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int boxw = drw->fonts->h / 6 + 2;
|
2019-10-06 21:43:51 +00:00
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
unsigned int i, occ = 0, urg = 0;
|
2019-10-06 22:46:23 +00:00
|
|
|
#if STATUSCOLORS_PATCH
|
|
|
|
char *ts = stext;
|
|
|
|
char *tp = stext;
|
|
|
|
int tx = 0;
|
|
|
|
char ctmp;
|
|
|
|
#endif // STATUSCOLORS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Client *c;
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray && m == systraytomon(m))
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
stw = getsystraywidth() + 2 * sp;
|
|
|
|
#else
|
2019-09-05 20:10:00 +00:00
|
|
|
stw = getsystraywidth();
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* draw status first so it can be overdrawn by tags later */
|
2019-10-06 21:43:51 +00:00
|
|
|
#if !STATUSALLMONS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (m == selmon) { /* status is only drawn on selected monitor */
|
2019-10-06 21:43:51 +00:00
|
|
|
#endif // STATUSALLMONS_PATCH
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeStatus]);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2020-04-16 18:18:13 +00:00
|
|
|
#if STATUSCOLORS_PATCH
|
2019-09-07 21:29:37 +00:00
|
|
|
#if STATUSPADDING_PATCH
|
2020-04-23 06:07:29 +00:00
|
|
|
tw = textw_wosc(stext) + lrpad + 2;
|
2019-10-06 22:46:23 +00:00
|
|
|
#else
|
2020-04-23 06:07:29 +00:00
|
|
|
tw = textw_wosc(stext) + 2;
|
2019-10-06 22:46:23 +00:00
|
|
|
#endif // STATUSPADDING_PATCH
|
|
|
|
while (1) {
|
|
|
|
if ((unsigned int)*ts > LENGTH(colors)) {
|
|
|
|
ts++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ctmp = *ts;
|
|
|
|
*ts = '\0';
|
2020-04-23 06:07:29 +00:00
|
|
|
drw_text(drw, m->ww - tw - stw + tx, 0, tw - tx, bh, stp, tp, 0);
|
2019-10-06 22:46:23 +00:00
|
|
|
tx += TEXTW(tp) -lrpad;
|
2020-04-16 18:18:13 +00:00
|
|
|
if (ctmp == '\0')
|
2019-10-06 22:46:23 +00:00
|
|
|
break;
|
|
|
|
drw_setscheme(drw, scheme[(unsigned int)(ctmp-1)]);
|
|
|
|
*ts = ctmp;
|
|
|
|
tp = ++ts;
|
|
|
|
}
|
|
|
|
#else // STATUSCOLORS_PATCH
|
2020-04-16 18:18:13 +00:00
|
|
|
#if STATUSPADDING_PATCH
|
2020-04-23 06:07:29 +00:00
|
|
|
tw = TEXTW(stext);
|
2020-04-16 18:18:13 +00:00
|
|
|
#else
|
2020-04-23 06:07:29 +00:00
|
|
|
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
|
2020-04-16 18:18:13 +00:00
|
|
|
#endif // STATUSPADDING_PATCH
|
2020-04-23 06:07:29 +00:00
|
|
|
drw_text(drw, m->ww - tw - stw, 0, tw, bh, stp, stext, 0);
|
2019-10-06 22:46:23 +00:00
|
|
|
#endif // STATUSCOLORS_PATCH
|
2019-10-06 21:43:51 +00:00
|
|
|
#if !STATUSALLMONS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2019-10-06 21:43:51 +00:00
|
|
|
#endif // STATUSALLMONS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
for (c = m->clients; c; c = c->next) {
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH || FANCYBAR_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
if (ISVISIBLE(c))
|
|
|
|
n++;
|
|
|
|
#endif // FANCYBAR_PATCH
|
2019-10-05 21:44:18 +00:00
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
occ |= c->tags == 255 ? 0 : c->tags;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
occ |= c->tags;
|
2019-10-05 21:44:18 +00:00
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->isurgent)
|
|
|
|
urg |= c->tags;
|
|
|
|
}
|
|
|
|
x = 0;
|
2019-10-01 20:46:24 +00:00
|
|
|
#if LEFTLAYOUT_PATCH
|
|
|
|
w = blw = TEXTW(m->ltsymbol);
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTagsNorm]);
|
|
|
|
#else
|
2019-10-01 20:46:24 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-10-01 20:46:24 +00:00
|
|
|
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
|
|
|
#endif // LEFTLAYOUT_PATCH
|
2019-10-05 21:28:50 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
if (drawtagmask & DRAWCLASSICTAGS)
|
|
|
|
#endif // TAGGRID_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
for (i = 0; i < LENGTH(tags); i++) {
|
2019-10-06 22:46:23 +00:00
|
|
|
#if URGENTBORDER_PATCH
|
|
|
|
invert = 0;
|
|
|
|
#else
|
|
|
|
invert = urg & 1 << i;
|
|
|
|
#endif // URGENTBORDER_PATCH
|
2019-10-05 21:44:18 +00:00
|
|
|
#if HIDEVACANTTAGS_PATCH
|
|
|
|
/* do not draw vacant tags */
|
|
|
|
if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
|
|
|
|
continue;
|
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
w = TEXTW(tags[i]);
|
2019-09-09 21:27:10 +00:00
|
|
|
#if ALTERNATIVE_TAGS_PATCH
|
|
|
|
wdelta = selmon->alttag ? abs(TEXTW(tags[i]) - TEXTW(tagsalt[i])) / 2 : 0;
|
|
|
|
#endif // ALTERNATIVE_TAGS_PATCH
|
2019-10-06 22:46:23 +00:00
|
|
|
#if URGENTBORDER_PATCH
|
|
|
|
if (m->tagset[m->seltags] & 1 << i)
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTagsSel]);
|
|
|
|
#else
|
2019-10-06 22:46:23 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeSel]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-10-06 22:46:23 +00:00
|
|
|
else
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[urg & 1 << i ? SchemeUrg : SchemeTagsNorm]);
|
|
|
|
#else
|
2019-10-06 22:46:23 +00:00
|
|
|
drw_setscheme(drw, scheme[urg & 1 << i ? SchemeUrg : SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
|
|
|
#elif VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]);
|
2019-10-06 22:46:23 +00:00
|
|
|
#else // URGENTBORDER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
2019-10-06 22:46:23 +00:00
|
|
|
#endif // URGENTBORDER_PATCH
|
2019-09-09 21:27:10 +00:00
|
|
|
#if ALTERNATIVE_TAGS_PATCH
|
2019-10-06 22:46:23 +00:00
|
|
|
drw_text(drw, x, 0, w, bh, wdelta + lrpad / 2, (selmon->alttag ? tagsalt[i] : tags[i]), invert);
|
2019-09-09 21:27:10 +00:00
|
|
|
#else
|
2019-10-06 22:46:23 +00:00
|
|
|
drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], invert);
|
2019-09-09 21:27:10 +00:00
|
|
|
#endif // ALTERNATIVE_TAGS_PATCH
|
2019-10-05 21:44:18 +00:00
|
|
|
#if !HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (occ & 1 << i)
|
2019-09-12 22:06:54 +00:00
|
|
|
#if ACTIVETAGINDICATORBAR_PATCH
|
|
|
|
drw_rect(drw, x + boxw, 0, w - ( 2 * boxw + 1), boxw,
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_rect(drw, x + boxs, boxs, boxw, boxw,
|
2019-09-12 22:06:54 +00:00
|
|
|
#endif // ACTIVETAGINDICATORBAR_PATCH
|
2019-10-06 22:46:23 +00:00
|
|
|
m == selmon && selmon->sel && selmon->sel->tags & 1 << i, invert);
|
2019-10-05 21:44:18 +00:00
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
x += w;
|
|
|
|
}
|
2019-10-05 21:28:50 +00:00
|
|
|
#if TAGGRID_PATCH
|
|
|
|
if (drawtagmask & DRAWTAGGRID) {
|
|
|
|
drawtaggrid(m,&x,occ);
|
|
|
|
}
|
|
|
|
#endif // TAGGRID_PATCH
|
2019-10-01 20:46:24 +00:00
|
|
|
#if !LEFTLAYOUT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
w = blw = TEXTW(m->ltsymbol);
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTagsNorm]);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
2019-10-01 20:46:24 +00:00
|
|
|
#endif // LEFTLAYOUT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2020-04-23 06:07:29 +00:00
|
|
|
if ((w = m->ww - tw - stw - x) > bh)
|
2019-09-06 21:47:06 +00:00
|
|
|
{
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
if (n > 0) {
|
|
|
|
for (c = m->clients; c; c = c->next) {
|
|
|
|
if (!ISVISIBLE(c))
|
|
|
|
continue;
|
|
|
|
if (m->sel == c)
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
scm = SchemeTitleSel;
|
|
|
|
#elif TITLECOLOR_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
scm = SchemeTitle;
|
|
|
|
#else
|
2019-09-09 22:18:46 +00:00
|
|
|
scm = SchemeSel;
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH / TITLECOLOR_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
else if (HIDDEN(c))
|
|
|
|
scm = SchemeHid;
|
|
|
|
else
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
scm = SchemeTitleNorm;
|
|
|
|
#else
|
2019-09-09 22:18:46 +00:00
|
|
|
scm = SchemeNorm;
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
|
2019-09-09 22:18:46 +00:00
|
|
|
drw_setscheme(drw, scheme[scm]);
|
|
|
|
drw_text(drw, x, 0, (1.0 / (double)n) * w, bh, lrpad / 2, c->name, 0);
|
|
|
|
x += (1.0 / (double)n) * w;
|
|
|
|
}
|
2020-01-30 07:43:00 +00:00
|
|
|
} else {
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTitleNorm]);
|
|
|
|
#else
|
2020-01-30 07:43:00 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2020-01-30 07:43:00 +00:00
|
|
|
drw_rect(drw, x, 0, w, bh, 1, 1);
|
|
|
|
}
|
2019-09-09 22:18:46 +00:00
|
|
|
#elif FANCYBAR_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
if (n > 0) {
|
|
|
|
tw = TEXTW(m->sel->name) + lrpad;
|
|
|
|
mw = (tw >= w || n == 1) ? 0 : (w - tw) / (n - 1);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for (c = m->clients; c; c = c->next) {
|
|
|
|
if (!ISVISIBLE(c) || c == m->sel)
|
|
|
|
continue;
|
|
|
|
tw = TEXTW(c->name);
|
2019-09-10 22:51:37 +00:00
|
|
|
if (tw < mw)
|
2019-09-06 21:47:06 +00:00
|
|
|
ew += (mw - tw);
|
|
|
|
else
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i > 0)
|
|
|
|
mw += ew / i;
|
|
|
|
|
|
|
|
for (c = m->clients; c; c = c->next) {
|
|
|
|
if (!ISVISIBLE(c))
|
|
|
|
continue;
|
|
|
|
tw = MIN(m->sel == c ? w : mw, TEXTW(c->name));
|
|
|
|
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[m->sel == c ? SchemeTitleSel : SchemeTitleNorm]);
|
|
|
|
#elif TITLECOLOR_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
drw_setscheme(drw, scheme[m->sel == c ? SchemeTitle : SchemeNorm]);
|
|
|
|
#else
|
2019-09-06 21:47:06 +00:00
|
|
|
drw_setscheme(drw, scheme[m->sel == c ? SchemeSel : SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH / TITLECOLOR_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
if (tw > 0) /* trap special handling of 0 in drw_text */
|
|
|
|
drw_text(drw, x, 0, tw, bh, lrpad / 2, c->name, 0);
|
2020-01-29 12:17:15 +00:00
|
|
|
#if !HIDEVACANTTAGS_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
if (c->isfloating)
|
2019-10-07 22:54:06 +00:00
|
|
|
#if ACTIVETAGINDICATORBAR_PATCH
|
|
|
|
drw_rect(drw, x + boxw, 0, w - ( 2 * boxw + 1), boxw, c->isfixed, 0);
|
|
|
|
#else
|
2019-09-06 21:47:06 +00:00
|
|
|
drw_rect(drw, x + boxs, boxs, boxw, boxw, c->isfixed, 0);
|
2019-10-07 22:54:06 +00:00
|
|
|
#endif // ACTIVETAGINDICATORBAR_PATCH
|
2020-01-29 12:17:15 +00:00
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
x += tw;
|
|
|
|
w -= tw;
|
|
|
|
}
|
2020-01-30 07:43:00 +00:00
|
|
|
}
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTitleNorm]);
|
|
|
|
#else
|
2019-09-06 21:47:06 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-09-06 21:47:06 +00:00
|
|
|
drw_rect(drw, x, 0, w, bh, 1, 1);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (m->sel) {
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]);
|
|
|
|
#elif TITLECOLOR_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
drw_setscheme(drw, scheme[m == selmon ? SchemeTitle : SchemeNorm]);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH / TITLECOLOR_PATCH
|
2019-10-11 17:43:02 +00:00
|
|
|
#if IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
|
|
|
|
XSetErrorHandler(xerrordummy);
|
|
|
|
#endif // IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
|
2019-09-12 22:06:54 +00:00
|
|
|
#if CENTEREDWINDOWNAME_PATCH
|
|
|
|
int mid = (m->ww - TEXTW(m->sel->name)) / 2 - x;
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
drw_text(drw, x, 0, w - 2*sp, bh, mid, m->sel->name, 0);
|
2020-01-29 12:17:15 +00:00
|
|
|
#else
|
|
|
|
drw_text(drw, x, 0, w, bh, mid, m->sel->name, 0);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
|
|
|
#else
|
|
|
|
#if BARPADDING_PATCH
|
|
|
|
drw_text(drw, x, 0, w - 2*sp, bh, lrpad / 2, m->sel->name, 0);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-12 22:06:54 +00:00
|
|
|
#endif // CENTEREDWINDOWNAME_PATCH
|
2019-10-11 17:43:02 +00:00
|
|
|
#if IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
|
|
|
|
XSync(dpy, False);
|
|
|
|
XSetErrorHandler(xerror);
|
|
|
|
#endif // IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH
|
2020-01-29 12:17:15 +00:00
|
|
|
#if !HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (m->sel->isfloating)
|
2019-10-07 22:54:06 +00:00
|
|
|
#if ACTIVETAGINDICATORBAR_PATCH
|
|
|
|
drw_rect(drw, x + boxw, 0, w - ( 2 * boxw + 1), boxw, m->sel->isfixed, 0);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
|
2019-10-07 22:54:06 +00:00
|
|
|
#endif // ACTIVETAGINDICATORBAR_PATCH
|
2020-01-29 12:17:15 +00:00
|
|
|
#endif // HIDEVACANTTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} else {
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTitleNorm]);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_rect(drw, x, 0, w, bh, 1, 1);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif // FANCYBAR_PATCH, AWESOMEBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2019-09-09 22:18:46 +00:00
|
|
|
|
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
m->bt = n;
|
|
|
|
m->btw = w;
|
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
if (m == selmon) { /* extra status is only drawn on selected monitor */
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
drw_setscheme(drw, scheme[SchemeTitleNorm]);
|
|
|
|
#else
|
2019-10-24 05:35:00 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // VTCOLORS_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
drw_text(drw, 0, 0, mons->ww, bh, 0, estext, 0);
|
|
|
|
drw_map(drw, m->extrabarwin, 0, 0, m->ww, bh);
|
|
|
|
}
|
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
drawbars(void)
|
|
|
|
{
|
|
|
|
Monitor *m;
|
|
|
|
|
2019-09-10 22:51:37 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray) {
|
|
|
|
/* Clear status bar to avoid artifacts beneath systray icons */
|
2020-03-22 18:39:08 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2019-09-10 22:51:37 +00:00
|
|
|
drw_rect(drw, 0, 0, selmon->ww, bh, 1, 1);
|
|
|
|
drw_map(drw, selmon->barwin, 0, 0, selmon->ww, bh);
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
drawbar(m);
|
2019-09-10 22:51:37 +00:00
|
|
|
|
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray)
|
|
|
|
updatesystray();
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
2019-09-15 22:32:28 +00:00
|
|
|
#if !FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
expose(XEvent *e)
|
|
|
|
{
|
|
|
|
Monitor *m;
|
|
|
|
XExposeEvent *ev = &e->xexpose;
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
if (ev->count == 0 && (m = wintomon(ev->window))) {
|
2019-09-04 22:16:39 +00:00
|
|
|
drawbar(m);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray && m == selmon)
|
|
|
|
updatesystray();
|
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
focus(Client *c)
|
|
|
|
{
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
if (!c || !ISVISIBLE(c) || HIDDEN(c))
|
|
|
|
for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!c || !ISVISIBLE(c))
|
|
|
|
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-09-10 22:51:37 +00:00
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
2019-09-10 22:51:37 +00:00
|
|
|
#endif // FLOAT_BORDER_COLOR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-09-14 22:43:35 +00:00
|
|
|
#if WARP_PATCH
|
|
|
|
warp(selmon->sel);
|
|
|
|
#endif // WARP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-03-23 11:15:50 +00:00
|
|
|
#if !STACKER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
void
|
|
|
|
focusstack(const Arg *arg)
|
|
|
|
{
|
|
|
|
Client *c = NULL, *i;
|
|
|
|
|
|
|
|
if (!selmon->sel)
|
|
|
|
return;
|
2019-09-12 22:06:54 +00:00
|
|
|
#if ALWAYSFULLSCREEN_PATCH
|
|
|
|
if (selmon->sel->isfullscreen)
|
2020-01-30 07:43:00 +00:00
|
|
|
return;
|
2019-09-12 22:06:54 +00:00
|
|
|
#endif // ALWAYSFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2020-03-23 11:15:50 +00:00
|
|
|
#endif // STACKER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
Atom
|
|
|
|
getatomprop(Client *c, Atom prop)
|
|
|
|
{
|
|
|
|
int di;
|
|
|
|
unsigned long dl;
|
|
|
|
unsigned char *p = NULL;
|
|
|
|
Atom da, atom = None;
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
|
|
|
|
&da, &di, &dl, &dl, &p) == Success && p) {
|
|
|
|
atom = *(Atom *)p;
|
|
|
|
XFree(p);
|
|
|
|
}
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2019-10-22 16:30:00 +00:00
|
|
|
#if ISPERMANENT_PATCH
|
|
|
|
if (!selmon->sel || selmon->sel->ispermanent)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!selmon->sel)
|
2019-10-22 16:30:00 +00:00
|
|
|
#endif // ISPERMANENT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) {
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!sendevent(selmon->sel, wmatom[WMDelete])) {
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XGrabServer(dpy);
|
|
|
|
XSetErrorHandler(xerrordummy);
|
|
|
|
XSetCloseDownMode(dpy, DestroyAll);
|
|
|
|
XKillClient(dpy, selmon->sel->win);
|
|
|
|
XSync(dpy, False);
|
|
|
|
XSetErrorHandler(xerror);
|
|
|
|
XUngrabServer(dpy);
|
|
|
|
}
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
selmon->pertag->prevclient[selmon->pertag->curtag] = NULL;
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
manage(Window w, XWindowAttributes *wa)
|
|
|
|
{
|
|
|
|
Client *c, *t = NULL;
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
Client *term = NULL;
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Window trans = None;
|
|
|
|
XWindowChanges wc;
|
|
|
|
|
|
|
|
c = ecalloc(1, sizeof(Client));
|
|
|
|
c->win = w;
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
c->pid = winpid(w);
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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;
|
2019-09-08 22:18:47 +00:00
|
|
|
#if CFACTS_PATCH
|
|
|
|
c->cfact = 1.0;
|
|
|
|
#endif // CFACTS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
updatetitle(c);
|
|
|
|
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
|
|
|
c->mon = t->mon;
|
|
|
|
c->tags = t->tags;
|
|
|
|
} else {
|
|
|
|
c->mon = selmon;
|
|
|
|
applyrules(c);
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
term = termforwin(c);
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-09-14 21:28:04 +00:00
|
|
|
#if SETBORDERPX_PATCH
|
|
|
|
c->bw = c->mon->borderpx;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
c->bw = borderpx;
|
2019-09-14 21:28:04 +00:00
|
|
|
#endif // SETBORDERPX_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
wc.border_width = c->bw;
|
|
|
|
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
|
2019-09-10 22:51:37 +00:00
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
|
2019-09-10 22:51:37 +00:00
|
|
|
#endif // FLOAT_BORDER_COLOR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
configure(c); /* propagates border_width, if size doesn't change */
|
|
|
|
updatewindowtype(c);
|
|
|
|
updatesizehints(c);
|
|
|
|
updatewmhints(c);
|
2019-09-07 22:23:30 +00:00
|
|
|
#if CENTER_PATCH
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
#endif // CENTER_PATCH
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
c->sfx = -9999;
|
|
|
|
c->sfy = -9999;
|
|
|
|
c->sfw = c->w;
|
|
|
|
c->sfh = c->h;
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
|
|
|
grabbuttons(c, 0);
|
2019-10-04 20:46:47 +00:00
|
|
|
#if MAXIMIZE_PATCH
|
|
|
|
c->wasfloating = 0;
|
|
|
|
c->ismax = 0;
|
2019-10-24 06:47:00 +00:00
|
|
|
#elif EXRESIZE_PATCH
|
|
|
|
c->wasfloating = 0;
|
|
|
|
#endif // MAXIMIZE_PATCH / EXRESIZE_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!c->isfloating)
|
|
|
|
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
|
|
|
if (c->isfloating)
|
|
|
|
XRaiseWindow(dpy, c->win);
|
2019-09-10 22:51:37 +00:00
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
|
|
|
|
#endif // FLOAT_BORDER_COLOR_PATCH
|
2019-09-06 21:25:32 +00:00
|
|
|
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
|
|
|
|
attachx(c);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
attach(c);
|
2019-09-06 21:25:32 +00:00
|
|
|
#endif
|
2019-09-04 22:16:39 +00:00
|
|
|
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 */
|
2019-09-09 22:18:46 +00:00
|
|
|
|
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
if (!HIDDEN(c))
|
|
|
|
setclientstate(c, NormalState);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
setclientstate(c, NormalState);
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->mon == selmon)
|
|
|
|
unfocus(selmon->sel, 0);
|
|
|
|
c->mon->sel = c;
|
|
|
|
arrange(c->mon);
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
if (!HIDDEN(c))
|
|
|
|
XMapWindow(dpy, c->win);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XMapWindow(dpy, c->win);
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
if (term)
|
|
|
|
swallow(term, c);
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!XGetWindowAttributes(dpy, ev->window, &wa))
|
|
|
|
return;
|
|
|
|
if (wa.override_redirect)
|
|
|
|
return;
|
|
|
|
if (!wintoclient(ev->window))
|
|
|
|
manage(ev->window, &wa);
|
|
|
|
}
|
|
|
|
|
2019-09-15 22:32:28 +00:00
|
|
|
#if !FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-09-15 22:32:28 +00:00
|
|
|
#endif // FOCUSONCLICK_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
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;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (c->isfullscreen && !c->fakefullscreen) /* no support moving fullscreen windows by mouse */
|
|
|
|
return;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
|
|
|
return;
|
2019-11-21 11:15:16 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-09-07 21:08:53 +00:00
|
|
|
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
resize(c, nx, ny, c->w, c->h, 1);
|
2019-09-07 21:08:53 +00:00
|
|
|
/* save last known float coordinates */
|
|
|
|
c->sfx = nx;
|
|
|
|
c->sfy = ny;
|
|
|
|
#else
|
|
|
|
resize(c, nx, ny, c->w, c->h, 1);
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
}
|
2020-03-31 06:21:00 +00:00
|
|
|
#if ROUNDED_CORNERS_PATCH
|
|
|
|
drawroundedcorners(c);
|
|
|
|
#endif // ROUNDED_CORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-03-31 06:21:00 +00:00
|
|
|
#if ROUNDED_CORNERS_PATCH
|
|
|
|
drawroundedcorners(c);
|
|
|
|
#endif // ROUNDED_CORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Client *
|
|
|
|
nexttiled(Client *c)
|
|
|
|
{
|
2019-09-09 22:18:46 +00:00
|
|
|
#if AWESOMEBAR_PATCH
|
|
|
|
for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
|
2019-09-09 22:18:46 +00:00
|
|
|
#endif // AWESOMEBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2019-10-06 21:43:51 +00:00
|
|
|
#if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
void
|
|
|
|
pop(Client *c)
|
|
|
|
{
|
|
|
|
detach(c);
|
|
|
|
attach(c);
|
|
|
|
focus(c);
|
|
|
|
arrange(c->mon);
|
|
|
|
}
|
2019-10-06 21:43:51 +00:00
|
|
|
#endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
propertynotify(XEvent *e)
|
|
|
|
{
|
|
|
|
Client *c;
|
|
|
|
Window trans;
|
|
|
|
XPropertyEvent *ev = &e->xproperty;
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
|
2019-10-07 21:34:23 +00:00
|
|
|
if ((ev->window == root) && (ev->atom == XA_WM_NAME)) {
|
2020-02-02 10:40:24 +00:00
|
|
|
#if DWMC_PATCH || FSIGNAL_PATCH
|
2019-10-07 21:34:23 +00:00
|
|
|
if (!fake_signal())
|
2020-02-02 10:40:24 +00:00
|
|
|
updatestatus();
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
updatestatus();
|
2020-02-02 10:40:24 +00:00
|
|
|
#endif // DWMC_PATCH / FSIGNAL_PATCH
|
2019-10-07 21:34:23 +00:00
|
|
|
} else if (ev->state == PropertyDelete) {
|
2019-09-04 22:16:39 +00:00
|
|
|
return; /* ignore */
|
2019-10-07 21:34:23 +00:00
|
|
|
} else if ((c = wintoclient(ev->window))) {
|
2019-09-04 22:16:39 +00:00
|
|
|
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();
|
2019-10-06 22:46:23 +00:00
|
|
|
#if URGENTBORDER_PATCH
|
|
|
|
if (c->isurgent)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel);
|
|
|
|
#endif // URGENTBORDER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2019-10-03 20:58:58 +00:00
|
|
|
#if ONLYQUITONEMPTY_PATCH
|
|
|
|
unsigned int n;
|
|
|
|
Window *junk = malloc(1);
|
|
|
|
|
|
|
|
XQueryTree(dpy, root, junk, junk, &junk, &n);
|
|
|
|
|
2019-10-06 21:43:51 +00:00
|
|
|
if (n <= quit_empty_window_count) {
|
2019-10-03 20:58:58 +00:00
|
|
|
#if RESTARTSIG_PATCH
|
|
|
|
if (arg->i)
|
|
|
|
restart = 1;
|
|
|
|
#endif // RESTARTSIG_PATCH
|
|
|
|
running = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printf("[dwm] not exiting (n=%d)\n", n);
|
|
|
|
|
|
|
|
free(junk);
|
|
|
|
#else
|
2019-10-02 21:22:04 +00:00
|
|
|
#if RESTARTSIG_PATCH
|
|
|
|
if (arg->i)
|
|
|
|
restart = 1;
|
|
|
|
#endif // RESTARTSIG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
running = 0;
|
2019-10-03 20:58:58 +00:00
|
|
|
#endif // ONLYQUITONEMPTY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-10-24 06:47:00 +00:00
|
|
|
#if EXRESIZE_PATCH
|
|
|
|
c->expandmask = 0;
|
|
|
|
#endif // EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
wc.border_width = c->bw;
|
2019-10-04 21:39:01 +00:00
|
|
|
#if NOBORDER_PATCH
|
|
|
|
if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next))
|
2019-10-06 21:43:51 +00:00
|
|
|
#if MONOCLE_LAYOUT
|
|
|
|
|| &monocle == c->mon->lt[c->mon->sellt]->arrange
|
|
|
|
#endif // MONOCLE_LAYOUT
|
|
|
|
) && !c->isfullscreen && !c->isfloating) {
|
2019-10-04 21:39:01 +00:00
|
|
|
c->w = wc.width += c->bw * 2;
|
|
|
|
c->h = wc.height += c->bw * 2;
|
|
|
|
wc.border_width = 0;
|
|
|
|
}
|
|
|
|
#endif // NOBORDER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2019-09-07 20:35:37 +00:00
|
|
|
#if RESIZECORNERS_PATCH
|
|
|
|
int ocx2, ocy2, nx, ny;
|
|
|
|
int horizcorner, vertcorner;
|
|
|
|
int di;
|
|
|
|
unsigned int dui;
|
|
|
|
Window dummy;
|
|
|
|
#endif // RESIZECORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Client *c;
|
|
|
|
Monitor *m;
|
|
|
|
XEvent ev;
|
|
|
|
Time lasttime = 0;
|
|
|
|
|
|
|
|
if (!(c = selmon->sel))
|
|
|
|
return;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (c->isfullscreen && !c->fakefullscreen) /* no support resizing fullscreen windows by mouse */
|
|
|
|
return;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
|
|
|
|
return;
|
2019-11-21 11:15:16 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
restack(selmon);
|
|
|
|
ocx = c->x;
|
|
|
|
ocy = c->y;
|
2019-09-07 20:35:37 +00:00
|
|
|
#if RESIZECORNERS_PATCH
|
|
|
|
ocx2 = c->x + c->w;
|
|
|
|
ocy2 = c->y + c->h;
|
|
|
|
#endif // RESIZECORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
|
|
|
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
|
|
|
return;
|
2019-09-07 20:35:37 +00:00
|
|
|
#if RESIZECORNERS_PATCH
|
|
|
|
if (!XQueryPointer (dpy, c->win, &dummy, &dummy, &di, &di, &nx, &ny, &dui))
|
2020-01-30 07:43:00 +00:00
|
|
|
return;
|
2019-09-07 20:35:37 +00:00
|
|
|
horizcorner = nx < c->w / 2;
|
|
|
|
vertcorner = ny < c->h / 2;
|
|
|
|
XWarpPointer (dpy, None, c->win, 0, 0, 0, 0,
|
2019-10-24 04:52:00 +00:00
|
|
|
horizcorner ? (-c->bw) : (c->w + c->bw - 1),
|
|
|
|
vertcorner ? (-c->bw) : (c->h + c->bw - 1));
|
2019-09-07 20:35:37 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
2019-09-07 20:35:37 +00:00
|
|
|
#endif // RESIZECORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-09-07 20:35:37 +00:00
|
|
|
#if RESIZECORNERS_PATCH
|
|
|
|
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);
|
|
|
|
#endif // RESIZECORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-09-07 20:35:37 +00:00
|
|
|
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
|
|
|
|
#if RESIZECORNERS_PATCH
|
|
|
|
resize(c, nx, ny, nw, nh, 1);
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2020-01-30 07:43:00 +00:00
|
|
|
/* save last known float dimensions */
|
|
|
|
c->sfx = nx;
|
|
|
|
c->sfy = ny;
|
|
|
|
c->sfw = nw;
|
|
|
|
c->sfh = nh;
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-07 20:35:37 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
resize(c, c->x, c->y, nw, nh, 1);
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
c->sfx = c->x;
|
|
|
|
c->sfy = c->y;
|
|
|
|
c->sfw = nw;
|
|
|
|
c->sfh = nh;
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-07 20:35:37 +00:00
|
|
|
#endif // RESIZECORNERS_PATCH
|
2020-03-31 06:21:00 +00:00
|
|
|
#if ROUNDED_CORNERS_PATCH
|
|
|
|
drawroundedcorners(c);
|
|
|
|
#endif // ROUNDED_CORNERS_PATCH
|
2019-09-07 20:35:37 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (ev.type != ButtonRelease);
|
2019-09-07 20:35:37 +00:00
|
|
|
#if RESIZECORNERS_PATCH
|
|
|
|
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
|
2019-10-24 04:52:00 +00:00
|
|
|
horizcorner ? (-c->bw) : (c->w + c->bw - 1),
|
|
|
|
vertcorner ? (-c->bw) : (c->h + c->bw - 1));
|
2019-09-07 20:35:37 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
2019-09-07 20:35:37 +00:00
|
|
|
#endif // RESIZECORNERS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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));
|
2019-09-14 22:43:35 +00:00
|
|
|
#if WARP_PATCH
|
2019-10-03 20:58:58 +00:00
|
|
|
if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && selmon->lt[selmon->sellt] != &layouts[MONOCLE_LAYOUT_POS])
|
2019-09-14 22:43:35 +00:00
|
|
|
warp(m->sel);
|
|
|
|
#endif // WARP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2020-01-27 08:13:13 +00:00
|
|
|
XFree(wins);
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sendmon(Client *c, Monitor *m)
|
|
|
|
{
|
2019-10-24 06:47:00 +00:00
|
|
|
#if EXRESIZE_PATCH
|
|
|
|
Monitor *oldm = selmon;
|
|
|
|
#endif // EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->mon == m)
|
|
|
|
return;
|
|
|
|
unfocus(c, 1);
|
|
|
|
detach(c);
|
|
|
|
detachstack(c);
|
|
|
|
c->mon = m;
|
2019-10-02 21:22:04 +00:00
|
|
|
#if EMPTYVIEW_PATCH
|
|
|
|
c->tags = (m->tagset[m->seltags] ? m->tagset[m->seltags] : 1);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
2019-10-02 21:22:04 +00:00
|
|
|
#endif // EMPTYVIEW_PATCH
|
2019-09-06 21:25:32 +00:00
|
|
|
#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
|
|
|
|
attachx(c);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
attach(c);
|
2019-09-06 21:25:32 +00:00
|
|
|
#endif
|
2019-09-04 22:16:39 +00:00
|
|
|
attachstack(c);
|
2019-10-24 06:47:00 +00:00
|
|
|
#if EXRESIZE_PATCH
|
|
|
|
if (oldm != m)
|
|
|
|
arrange(oldm);
|
|
|
|
arrange(m);
|
|
|
|
focus(c);
|
|
|
|
restack(m);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
|
|
|
arrange(NULL);
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // EXRESIZE_PATCH
|
2020-01-25 17:37:35 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
if (c->switchtag)
|
|
|
|
c->switchtag = 0;
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
sendevent(Client *c, Atom proto)
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
Atom *protocols;
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
Atom mt;
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int exists = 0;
|
|
|
|
XEvent ev;
|
|
|
|
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
|
|
|
|
while (!exists && n--)
|
|
|
|
exists = protocols[n] == proto;
|
|
|
|
XFree(protocols);
|
|
|
|
}
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (exists) {
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
ev.type = ClientMessage;
|
|
|
|
ev.xclient.window = w;
|
|
|
|
ev.xclient.message_type = mt;
|
|
|
|
ev.xclient.format = 32;
|
|
|
|
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);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
sendevent(c, wmatom[WMTakeFocus]);
|
2019-09-05 20:10:00 +00:00
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (!c->fakefullscreen) {
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
}
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} else if (!fullscreen && c->isfullscreen){
|
|
|
|
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
|
|
|
PropModeReplace, (unsigned char*)0, 0);
|
|
|
|
c->isfullscreen = 0;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (!c->fakefullscreen) {
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
}
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
setlayout(const Arg *arg)
|
|
|
|
{
|
2019-09-05 20:58:16 +00:00
|
|
|
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
|
|
|
#if PERTAG_PATCH
|
|
|
|
selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
|
|
|
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->sellt ^= 1;
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-10-24 06:47:00 +00:00
|
|
|
#if EXRESIZE_PATCH
|
|
|
|
if (!selmon->lt[selmon->sellt]->arrange) {
|
|
|
|
for (Client *c = selmon->clients ; c ; c = c->next) {
|
|
|
|
if (!c->isfloating) {
|
|
|
|
/*restore last known float dimensions*/
|
|
|
|
resize(c, selmon->mx + c->sfx, selmon->my + c->sfy,
|
|
|
|
c->sfw, c->sfh, False);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // EXRESIZE_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
if (arg && arg->v)
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
|
|
|
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->lt[selmon->sellt] = (Layout *)arg->v;
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
|
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
2020-03-27 19:46:54 +00:00
|
|
|
if (selmon->lt[selmon->sellt]->preset.nmaster && selmon->lt[selmon->sellt]->preset.nmaster != -1)
|
2019-09-30 21:52:51 +00:00
|
|
|
selmon->nmaster = selmon->lt[selmon->sellt]->preset.nmaster;
|
2020-03-27 19:46:54 +00:00
|
|
|
if (selmon->lt[selmon->sellt]->preset.nstack && selmon->lt[selmon->sellt]->preset.nstack != -1)
|
2019-09-30 21:52:51 +00:00
|
|
|
selmon->nstack = selmon->lt[selmon->sellt]->preset.nstack;
|
|
|
|
|
|
|
|
selmon->ltaxis[LAYOUT] = selmon->lt[selmon->sellt]->preset.layout;
|
|
|
|
selmon->ltaxis[MASTER] = selmon->lt[selmon->sellt]->preset.masteraxis;
|
|
|
|
selmon->ltaxis[STACK] = selmon->lt[selmon->sellt]->preset.stack1axis;
|
|
|
|
selmon->ltaxis[STACK2] = selmon->lt[selmon->sellt]->preset.stack2axis;
|
|
|
|
|
|
|
|
#if PERTAG_PATCH
|
|
|
|
selmon->pertag->ltaxis[selmon->pertag->curtag][LAYOUT] = selmon->ltaxis[LAYOUT];
|
|
|
|
selmon->pertag->ltaxis[selmon->pertag->curtag][MASTER] = selmon->ltaxis[MASTER];
|
|
|
|
selmon->pertag->ltaxis[selmon->pertag->curtag][STACK] = selmon->ltaxis[STACK];
|
|
|
|
selmon->pertag->ltaxis[selmon->pertag->curtag][STACK2] = selmon->ltaxis[STACK2];
|
|
|
|
#endif // PERTAG_PATCH
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-04-20 16:40:25 +00:00
|
|
|
if (f < 0.05 || f > 0.95)
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->mfact = f;
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
setup(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
XSetWindowAttributes wa;
|
|
|
|
Atom utf8string;
|
|
|
|
|
|
|
|
/* clean up any zombies immediately */
|
|
|
|
sigchld(0);
|
|
|
|
|
2019-10-02 21:22:04 +00:00
|
|
|
#if RESTARTSIG_PATCH
|
|
|
|
signal(SIGHUP, sighup);
|
|
|
|
signal(SIGTERM, sigterm);
|
|
|
|
#endif // RESTARTSIG_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* init screen */
|
|
|
|
screen = DefaultScreen(dpy);
|
|
|
|
sw = DisplayWidth(dpy, screen);
|
|
|
|
sh = DisplayHeight(dpy, screen);
|
|
|
|
root = RootWindow(dpy, screen);
|
|
|
|
#if ALPHA_PATCH
|
|
|
|
xinitvisual();
|
|
|
|
drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
|
|
|
|
#else
|
|
|
|
drw = drw_create(dpy, screen, root, sw, sh);
|
|
|
|
#endif // ALPHA_PATCH
|
|
|
|
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
|
|
|
die("no fonts could be loaded.");
|
2019-09-07 21:29:37 +00:00
|
|
|
#if STATUSPADDING_PATCH
|
|
|
|
lrpad = drw->fonts->h + horizpadbar;
|
|
|
|
bh = drw->fonts->h + vertpadbar;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
lrpad = drw->fonts->h;
|
|
|
|
bh = drw->fonts->h + 2;
|
2019-09-07 21:29:37 +00:00
|
|
|
#endif // STATUSPADDING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
updategeom();
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
sp = sidepad;
|
|
|
|
vp = (topbar == 1) ? vertpad : - vertpad;
|
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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);
|
2019-09-07 21:46:08 +00:00
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
|
|
|
|
#endif // WINDOWROLERULE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
|
|
|
|
netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
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);
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
#if EWMHTAGS_PATCH
|
|
|
|
netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False);
|
|
|
|
netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
|
|
|
|
netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
|
|
|
|
netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
|
|
|
|
#endif // EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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 */
|
2020-02-11 17:31:11 +00:00
|
|
|
#if VTCOLORS_PATCH
|
|
|
|
get_vt_colors();
|
|
|
|
if (get_luminance(colors[SchemeTagsNorm][ColBg]) > 50) {
|
|
|
|
strcpy(colors[SchemeTitleNorm][ColBg], title_bg_light);
|
|
|
|
strcpy(colors[SchemeTitleSel][ColBg], title_bg_light);
|
|
|
|
} else {
|
|
|
|
strcpy(colors[SchemeTitleNorm][ColBg], title_bg_dark);
|
|
|
|
strcpy(colors[SchemeTitleSel][ColBg], title_bg_dark);
|
|
|
|
}
|
|
|
|
#endif // VTCOLORS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
|
|
|
for (i = 0; i < LENGTH(colors); i++)
|
2019-09-10 22:51:37 +00:00
|
|
|
scheme[i] = drw_scm_create(drw, colors[i],
|
2019-09-04 22:16:39 +00:00
|
|
|
#if ALPHA_PATCH
|
2019-09-10 22:51:37 +00:00
|
|
|
alphas[i],
|
2019-09-04 22:16:39 +00:00
|
|
|
#endif // ALPHA_PATCH
|
2019-09-10 22:51:37 +00:00
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
4
|
|
|
|
#else
|
|
|
|
3
|
|
|
|
#endif // FLOAT_BORDER_COLOR_PATCH
|
|
|
|
);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
/* init system tray */
|
|
|
|
if (showsystray)
|
|
|
|
updatesystray();
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* init bars */
|
|
|
|
updatebars();
|
|
|
|
updatestatus();
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
updatebarpos(selmon);
|
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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);
|
2019-09-11 22:48:29 +00:00
|
|
|
#if EWMHTAGS_PATCH
|
|
|
|
setnumdesktops();
|
|
|
|
setcurrentdesktop();
|
|
|
|
setdesktopnames();
|
|
|
|
setviewport();
|
|
|
|
#endif // EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)) {
|
[dwm][PATCH] Multiple scratchpads
This patch enables multiple scratchpads, each with one assigned window.
This enables the same scratchpad workflow that you have in i3.
Scratchpads are implemented as special tags, whose mask does not
apply to new spawned windows. To assign a window to a scratchpad you
have to set up a rule, as you do with regular tags.
Windows tagged with scratchpad tags can be set floating or not in the
rules array. Most users would probably want them floating (i3 style),
but having them tiled does also perfectly work and might fit better the
DWM approach. In case they are set floating, the patch moves them to the
center of the screen whenever the are shown. The patch can easily be
modified to make this last feature configurable in the rules array (see
the center patch).
The togglescratch function, borrowed from the previous scratchpad patch
and slightly modified, can be used to spawn a registered scratchpad
process or toggle its view. This function looks for a window tagged on
the selected scratchpad. If it is found its view is toggled. If it is
not found the corresponding registered command is spawned. The
config.def.h shows three examples of its use to spawn a terminal in the
first scratchpad tag, a second terminal running ranger on the second
scratchpad tag and the keepassxc application to manage passwords on a
third scratchpad tag.
If you prefer to spawn your scratchpad applications from the startup
script, you might opt for binding keys to toggleview instead, as
scratchpads are just special tags (you may even extend the TAGKEYS macro
to generalize the key bindings).
2020-04-16 14:39:22 +00:00
|
|
|
#if SCRATCHPAD_PATCH && !SCRATCHPAD_KEEP_POSITION_AND_SIZE_PATCH
|
|
|
|
if ((c->tags & SPTAGMASK) && c->isfloating) {
|
|
|
|
c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
|
|
|
c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
|
|
|
}
|
|
|
|
#endif // SCRATCHPAD_PATCH | SCRATCHPAD_KEEP_POSITION_AND_SIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* show clients top down */
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
if (!c->mon->lt[c->mon->sellt]->arrange && c->sfx != -9999 && !c->isfullscreen) {
|
|
|
|
XMoveWindow(dpy, c->win, c->sfx, c->sfy);
|
|
|
|
resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
|
|
|
|
showhide(c->snext);
|
|
|
|
return;
|
|
|
|
}
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-12 22:06:54 +00:00
|
|
|
#if AUTORESIZE_PATCH
|
|
|
|
if (c->needresize) {
|
|
|
|
c->needresize = 0;
|
|
|
|
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
|
|
|
|
} else {
|
|
|
|
XMoveWindow(dpy, c->win, c->x, c->y);
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XMoveWindow(dpy, c->win, c->x, c->y);
|
2019-09-12 22:06:54 +00:00
|
|
|
#endif // AUTORESIZE_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating)
|
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
|
|
|
&& !c->isfullscreen
|
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
|
|
|
)
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2020-04-13 12:59:58 +00:00
|
|
|
#if STATUSCMD_PATCH
|
|
|
|
char *cmd = NULL;
|
|
|
|
#endif // STATUSCMD_PATCH
|
2019-10-24 06:03:00 +00:00
|
|
|
#if !NODMENU_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (arg->v == dmenucmd)
|
|
|
|
dmenumon[0] = '0' + selmon->num;
|
2019-10-24 06:03:00 +00:00
|
|
|
#endif // NODMENU_PATCH
|
2020-04-13 12:59:58 +00:00
|
|
|
#if STATUSCMD_PATCH
|
|
|
|
#if !NODMENU_PATCH
|
|
|
|
else if (arg->v == statuscmd)
|
|
|
|
#else
|
|
|
|
if (arg->v == statuscmd)
|
|
|
|
#endif // NODMENU_PATCH
|
|
|
|
{
|
|
|
|
int len = strlen(statuscmds[statuscmdn]) + 1;
|
|
|
|
if (!(cmd = malloc(sizeof(char)*len + sizeof(statusexport))))
|
|
|
|
die("malloc:");
|
|
|
|
strcpy(cmd, statusexport);
|
|
|
|
strcat(cmd, statuscmds[statuscmdn]);
|
|
|
|
cmd[LENGTH(statusexport)-3] = '0' + lastbutton;
|
|
|
|
statuscmd[2] = cmd;
|
|
|
|
}
|
|
|
|
#endif // STATUSCMD_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (fork() == 0) {
|
|
|
|
if (dpy)
|
|
|
|
close(ConnectionNumber(dpy));
|
2019-10-10 21:50:30 +00:00
|
|
|
#if SPAWNCMD_PATCH
|
|
|
|
if (selmon->sel) {
|
|
|
|
const char* const home = getenv("HOME");
|
|
|
|
assert(home && strchr(home, '/'));
|
|
|
|
const size_t homelen = strlen(home);
|
|
|
|
char *cwd, *pathbuf = NULL;
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
cwd = strtok(selmon->sel->name, SPAWN_CWD_DELIM);
|
|
|
|
/* NOTE: strtok() alters selmon->sel->name in-place,
|
|
|
|
* but that does not matter because we are going to
|
|
|
|
* exec() below anyway; nothing else will use it */
|
|
|
|
while (cwd) {
|
|
|
|
if (*cwd == '~') { /* replace ~ with $HOME */
|
|
|
|
if (!(pathbuf = malloc(homelen + strlen(cwd)))) /* ~ counts for NULL term */
|
|
|
|
die("fatal: could not malloc() %u bytes\n", homelen + strlen(cwd));
|
|
|
|
strcpy(strcpy(pathbuf, home) + homelen, cwd + 1);
|
|
|
|
cwd = pathbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strchr(cwd, '/') && !stat(cwd, &statbuf)) {
|
|
|
|
if (!S_ISDIR(statbuf.st_mode))
|
|
|
|
cwd = dirname(cwd);
|
|
|
|
|
|
|
|
if (!chdir(cwd))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cwd = strtok(NULL, SPAWN_CWD_DELIM);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pathbuf);
|
|
|
|
}
|
|
|
|
#endif // SPAWNCMD_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
setsid();
|
|
|
|
execvp(((char **)arg->v)[0], (char **)arg->v);
|
|
|
|
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
|
|
|
|
perror(" failed");
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
2020-04-13 12:59:58 +00:00
|
|
|
#if STATUSCMD_PATCH
|
|
|
|
free(cmd);
|
|
|
|
#endif // STATUSCMD_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
tag(const Arg *arg)
|
|
|
|
{
|
2020-01-30 07:43:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
unsigned int tagmask, tagindex;
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (selmon->sel && arg->ui & TAGMASK) {
|
|
|
|
selmon->sel->tags = arg->ui & TAGMASK;
|
|
|
|
focus(NULL);
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
selmon->pertag->prevclient[selmon->pertag->curtag] = NULL;
|
2020-01-30 07:43:00 +00:00
|
|
|
for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++)
|
|
|
|
if (tagmask & 1)
|
|
|
|
selmon->pertag->prevclient[tagindex] = NULL;
|
2020-01-29 07:31:00 +00:00
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
2019-09-15 21:42:47 +00:00
|
|
|
#if VIEWONTAG_PATCH
|
|
|
|
view(arg);
|
|
|
|
#endif // VIEWONTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
tagmon(const Arg *arg)
|
|
|
|
{
|
2019-09-05 21:39:25 +00:00
|
|
|
#if TAGMONFIXFS_PATCH
|
|
|
|
Client *c = selmon->sel;
|
|
|
|
if (!c || !mons->next)
|
|
|
|
return;
|
|
|
|
sendmon(c, dirtomon(arg->i));
|
|
|
|
if (c->isfullscreen) {
|
|
|
|
setfullscreen(c, 0);
|
|
|
|
setfullscreen(c, 1);
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!selmon->sel || !mons->next)
|
|
|
|
return;
|
|
|
|
sendmon(selmon->sel, dirtomon(arg->i));
|
2019-09-05 21:39:25 +00:00
|
|
|
#endif // TAGMONFIXFS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
togglebar(const Arg *arg)
|
|
|
|
{
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH && PERTAGBAR_PATCH
|
|
|
|
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->showbar = !selmon->showbar;
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
updatebarpos(selmon);
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2*sp, bh);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
XMoveResizeWindow(dpy, selmon->extrabarwin, selmon->wx + sp, selmon->eby - vp, selmon->ww - 2*sp, bh);
|
|
|
|
#else
|
2019-10-24 05:35:00 +00:00
|
|
|
XMoveResizeWindow(dpy, selmon->extrabarwin, selmon->wx, selmon->eby, selmon->ww, bh);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray) {
|
|
|
|
XWindowChanges wc;
|
|
|
|
if (!selmon->showbar)
|
|
|
|
wc.y = -bh;
|
|
|
|
else if (selmon->showbar) {
|
|
|
|
wc.y = 0;
|
|
|
|
if (!selmon->topbar)
|
|
|
|
wc.y = selmon->mh - bh;
|
|
|
|
}
|
|
|
|
XConfigureWindow(dpy, systray->win, CWY, &wc);
|
|
|
|
}
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
togglefloating(const Arg *arg)
|
|
|
|
{
|
|
|
|
if (!selmon->sel)
|
|
|
|
return;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (selmon->sel->isfullscreen && !selmon->sel->fakefullscreen) /* no support for fullscreen windows */
|
|
|
|
return;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
|
|
|
|
return;
|
2019-11-21 11:15:16 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
|
2019-09-10 22:51:37 +00:00
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
if (selmon->sel->isfloating)
|
|
|
|
XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColBorder].pixel);
|
|
|
|
#endif // FLOAT_BORDER_COLOR_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
if (selmon->sel->isfloating) {
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
if (selmon->sel->sfx != -9999) {
|
|
|
|
/* restore last known float dimensions */
|
|
|
|
resize(selmon->sel, selmon->sel->sfx, selmon->sel->sfy,
|
|
|
|
selmon->sel->sfw, selmon->sel->sfh, 0);
|
|
|
|
arrange(selmon);
|
|
|
|
return;
|
|
|
|
}
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH // EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
resize(selmon->sel, selmon->sel->x, selmon->sel->y,
|
|
|
|
selmon->sel->w, selmon->sel->h, 0);
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
} 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;
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
toggletag(const Arg *arg)
|
|
|
|
{
|
|
|
|
unsigned int newtags;
|
2020-01-30 07:43:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
unsigned int tagmask, tagindex;
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
if (!selmon->sel)
|
|
|
|
return;
|
|
|
|
newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
|
|
|
|
if (newtags) {
|
|
|
|
selmon->sel->tags = newtags;
|
|
|
|
focus(NULL);
|
2020-01-30 07:43:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++)
|
|
|
|
if (tagmask & 1)
|
|
|
|
selmon->pertag->prevclient[tagindex] = NULL;
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
|
|
|
}
|
2019-09-11 22:48:29 +00:00
|
|
|
#if EWMHTAGS_PATCH
|
|
|
|
updatecurrentdesktop();
|
|
|
|
#endif // EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
toggleview(const Arg *arg)
|
|
|
|
{
|
|
|
|
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
int i;
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2019-10-04 22:12:52 +00:00
|
|
|
#if TAGINTOSTACK_ALLMASTER_PATCH
|
|
|
|
Client *const selected = selmon->sel;
|
|
|
|
|
|
|
|
// clients in the master area should be the same after we add a new tag
|
|
|
|
Client **const masters = calloc(selmon->nmaster, sizeof(Client *));
|
|
|
|
if (!masters) {
|
|
|
|
die("fatal: could not calloc() %u bytes \n", selmon->nmaster * sizeof(Client *));
|
|
|
|
}
|
|
|
|
// collect (from last to first) references to all clients in the master area
|
|
|
|
Client *c;
|
2019-10-06 21:43:51 +00:00
|
|
|
size_t j;
|
|
|
|
for (c = nexttiled(selmon->clients), j = 0; c && j < selmon->nmaster; c = nexttiled(c->next), ++j)
|
|
|
|
masters[selmon->nmaster - (j + 1)] = c;
|
2019-10-04 22:12:52 +00:00
|
|
|
// put the master clients at the front of the list
|
|
|
|
// > go from the 'last' master to the 'first'
|
2019-10-06 21:43:51 +00:00
|
|
|
for (j = 0; j < selmon->nmaster; ++j)
|
|
|
|
if (masters[j])
|
|
|
|
pop(masters[j]);
|
2019-10-04 22:12:52 +00:00
|
|
|
free(masters);
|
|
|
|
|
|
|
|
// we also want to be sure not to mutate the focus
|
|
|
|
focus(selected);
|
|
|
|
#elif TAGINTOSTACK_ONEMASTER_PATCH
|
|
|
|
// the first visible client should be the same after we add a new tag
|
|
|
|
// we also want to be sure not to mutate the focus
|
|
|
|
Client *const c = nexttiled(selmon->clients);
|
|
|
|
if (c) {
|
|
|
|
Client * const selected = selmon->sel;
|
|
|
|
pop(c);
|
|
|
|
focus(selected);
|
|
|
|
}
|
|
|
|
#endif // TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
|
|
|
|
|
2019-10-02 21:22:04 +00:00
|
|
|
#if !EMPTYVIEW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (newtagset) {
|
2019-10-02 21:22:04 +00:00
|
|
|
#endif // EMPTYVIEW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->tagset[selmon->seltags] = newtagset;
|
2019-09-05 20:58:16 +00:00
|
|
|
|
|
|
|
#if PERTAG_PATCH
|
|
|
|
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 PERTAGBAR_PATCH
|
|
|
|
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
|
|
|
togglebar(NULL);
|
|
|
|
#endif // PERTAGBAR_PATCH
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
|
|
|
arrange(selmon);
|
2019-10-02 21:22:04 +00:00
|
|
|
#if !EMPTYVIEW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2019-10-02 21:22:04 +00:00
|
|
|
#endif // EMPTYVIEW_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
#if EWMHTAGS_PATCH
|
|
|
|
updatecurrentdesktop();
|
|
|
|
#endif // EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
unfocus(Client *c, int setfocus)
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
return;
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
selmon->pertag->prevclient[selmon->pertag->curtag] = c;
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
2020-04-05 07:10:00 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (c->isfullscreen && !c->fakefullscreen && ISVISIBLE(c))
|
|
|
|
setfullscreen(c, 0);
|
|
|
|
#else
|
|
|
|
if (c->isfullscreen && ISVISIBLE(c))
|
|
|
|
setfullscreen(c, 0);
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
grabbuttons(c, 0);
|
2019-09-10 22:51:37 +00:00
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
2019-09-10 22:51:37 +00:00
|
|
|
#endif // FLOAT_BORDER_COLOR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (setfocus) {
|
|
|
|
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
|
|
|
|
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
unmanage(Client *c, int destroyed)
|
|
|
|
{
|
|
|
|
Monitor *m = c->mon;
|
|
|
|
XWindowChanges wc;
|
|
|
|
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
if (c->swallowing) {
|
|
|
|
unswallow(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Client *s = swallowingclient(c->win);
|
|
|
|
if (s) {
|
|
|
|
free(s->swallowing);
|
|
|
|
s->swallowing = NULL;
|
|
|
|
arrange(m);
|
|
|
|
focus(NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif // SWALLOW_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
if (s)
|
|
|
|
return;
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
|
|
|
updateclientlist();
|
|
|
|
arrange(m);
|
2019-11-26 19:23:58 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
if (c->switchtag)
|
|
|
|
view(&((Arg) { .ui = c->switchtag }));
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
} 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);
|
|
|
|
removesystrayicon(c);
|
|
|
|
updatesystray();
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatebars(void)
|
|
|
|
{
|
2019-09-05 20:10:00 +00:00
|
|
|
unsigned int w;
|
2019-09-04 22:16:39 +00:00
|
|
|
Monitor *m;
|
|
|
|
XSetWindowAttributes wa = {
|
|
|
|
.override_redirect = True,
|
|
|
|
#if ALPHA_PATCH
|
|
|
|
.background_pixel = 0,
|
|
|
|
.border_pixel = 0,
|
|
|
|
.colormap = cmap,
|
|
|
|
#else
|
|
|
|
.background_pixmap = ParentRelative,
|
|
|
|
#endif // ALPHA_PATCH
|
|
|
|
.event_mask = ButtonPressMask|ExposureMask
|
|
|
|
};
|
|
|
|
XClassHint ch = {"dwm", "dwm"};
|
|
|
|
for (m = mons; m; m = m->next) {
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
if (!m->barwin) {
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (m->barwin)
|
|
|
|
continue;
|
2019-10-24 05:35:00 +00:00
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
w = m->ww;
|
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray && m == systraytomon(m))
|
|
|
|
w -= getsystraywidth();
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
#if ALPHA_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, w - 2*sp, bh, 0, depth,
|
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
|
|
|
#else
|
2019-09-05 20:10:00 +00:00
|
|
|
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, depth,
|
2019-09-04 22:16:39 +00:00
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
|
|
|
#else
|
|
|
|
#if BARPADDING_PATCH
|
|
|
|
m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, w - 2*sp, bh, 0, DefaultDepth(dpy, screen),
|
|
|
|
CopyFromParent, DefaultVisual(dpy, screen),
|
|
|
|
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
2019-09-04 22:16:39 +00:00
|
|
|
#else
|
2019-09-05 20:10:00 +00:00
|
|
|
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
|
2019-09-04 22:16:39 +00:00
|
|
|
CopyFromParent, DefaultVisual(dpy, screen),
|
|
|
|
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
#endif // ALPHA_PATCH
|
|
|
|
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray && m == systraytomon(m))
|
|
|
|
XMapRaised(dpy, systray->win);
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XMapRaised(dpy, m->barwin);
|
|
|
|
XSetClassHint(dpy, m->barwin, &ch);
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
}
|
|
|
|
if (!m->extrabarwin) {
|
|
|
|
#if ALPHA_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
m->extrabarwin = XCreateWindow(dpy, root, m->wx + sp, m->eby - vp, m->ww - 2*sp, bh, 0, depth,
|
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
|
|
|
#else
|
2019-10-24 05:35:00 +00:00
|
|
|
m->extrabarwin = XCreateWindow(dpy, root, m->wx, m->eby, m->ww, bh, 0, depth,
|
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
|
|
|
#elif BARPADDING_PATCH
|
|
|
|
m->extrabarwin = XCreateWindow(dpy, root, m->wx + sp, m->eby - vp, m->ww - 2*sp, bh, 0, DefaultDepth(dpy, screen),
|
|
|
|
CopyFromParent, DefaultVisual(dpy, screen),
|
|
|
|
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
2019-10-24 05:35:00 +00:00
|
|
|
#else
|
|
|
|
m->extrabarwin = XCreateWindow(dpy, root, m->wx, m->eby, m->ww, bh, 0, DefaultDepth(dpy, screen),
|
|
|
|
CopyFromParent, DefaultVisual(dpy, screen),
|
|
|
|
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
|
|
|
#endif // ALPHA_PATCH
|
|
|
|
XDefineCursor(dpy, m->extrabarwin, cursor[CurNormal]->cursor);
|
|
|
|
XMapRaised(dpy, m->extrabarwin);
|
|
|
|
XSetClassHint(dpy, m->extrabarwin, &ch);
|
|
|
|
}
|
|
|
|
#endif // EXTRABAR_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatebarpos(Monitor *m)
|
|
|
|
{
|
|
|
|
m->wy = m->my;
|
|
|
|
m->wh = m->mh;
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
2020-01-24 09:47:13 +00:00
|
|
|
#if BARPADDING_PATCH
|
|
|
|
m->wh = m->wh - vertpad * m->showbar * 2 - bh * m->showbar * 2;
|
|
|
|
m->wy = m->showbar ? m->wy + bh + vertpad: m->wy;
|
|
|
|
if (m->showbar) {
|
|
|
|
m->by = m->topbar ? m->wy - bh - vertpad: m->wy + m->wh + vertpad;
|
|
|
|
m->eby = m->topbar ? m->wy + m->wh + vertpad: m->wy - bh - vertpad;
|
|
|
|
} else {
|
|
|
|
m->by = -bh - vertpad;
|
|
|
|
m->eby = -bh - vertpad;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
m->wh = m->wh - bh * m->showbar * 2;
|
2019-10-24 05:35:00 +00:00
|
|
|
m->wy = m->showbar ? m->wy + bh : m->wy;
|
|
|
|
if (m->showbar) {
|
|
|
|
m->by = m->topbar ? m->wy - bh : m->wy + m->wh;
|
|
|
|
m->eby = m->topbar ? m->wy + m->wh : m->wy - bh;
|
|
|
|
} else {
|
|
|
|
m->by = -bh;
|
|
|
|
m->eby = -bh;
|
|
|
|
}
|
2020-01-24 09:47:13 +00:00
|
|
|
#endif // BARPADDING_PATCH
|
|
|
|
#elif BARPADDING_PATCH
|
|
|
|
if (m->showbar) {
|
|
|
|
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 - vp;
|
2019-10-24 05:35:00 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2019-10-24 05:35:00 +00:00
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-10-07 20:56:53 +00:00
|
|
|
#if SORTSCREENS_PATCH
|
|
|
|
sortscreens(unique, nn);
|
|
|
|
#endif // SORTSCREENS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2019-10-06 21:43:51 +00:00
|
|
|
#if STATUSALLMONS_PATCH
|
|
|
|
Monitor* m;
|
|
|
|
#endif // STATUSALLMONS_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
char text[512];
|
|
|
|
if (!gettextprop(root, XA_WM_NAME, text, sizeof(text))) {
|
|
|
|
strcpy(stext, "dwm-"VERSION);
|
|
|
|
estext[0] = '\0';
|
|
|
|
} else {
|
|
|
|
char *e = strchr(text, statussep);
|
|
|
|
if (e) {
|
|
|
|
*e = '\0'; e++;
|
|
|
|
strncpy(estext, e, sizeof(estext) - 1);
|
|
|
|
} else {
|
|
|
|
estext[0] = '\0';
|
|
|
|
}
|
2020-04-13 12:59:58 +00:00
|
|
|
#if STATUSCMD_PATCH
|
|
|
|
copyvalidchars(stext, text);
|
|
|
|
#else
|
2019-10-24 05:35:00 +00:00
|
|
|
strncpy(stext, text, sizeof(stext) - 1);
|
2020-04-13 12:59:58 +00:00
|
|
|
#endif // STATUSCMD_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
}
|
2020-04-13 12:59:58 +00:00
|
|
|
#elif STATUSCMD_PATCH
|
|
|
|
if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext)))
|
|
|
|
strcpy(stext, "dwm-"VERSION);
|
|
|
|
else
|
|
|
|
copyvalidchars(stext, rawstext);
|
2019-10-24 05:35:00 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
|
|
|
|
strcpy(stext, "dwm-"VERSION);
|
2019-10-24 05:35:00 +00:00
|
|
|
#endif // EXTRABAR_PATCH
|
2019-10-06 21:43:51 +00:00
|
|
|
#if STATUSALLMONS_PATCH
|
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
drawbar(m);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
drawbar(selmon);
|
2019-10-06 21:43:51 +00:00
|
|
|
#endif // STATUSALLMONS_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
#if SYSTRAY_PATCH
|
|
|
|
if (showsystray)
|
|
|
|
updatesystray();
|
|
|
|
#endif // SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-09-07 22:23:30 +00:00
|
|
|
if (wtype == netatom[NetWMWindowTypeDialog]) {
|
|
|
|
#if CENTER_PATCH
|
|
|
|
c->iscentered = 1;
|
|
|
|
#endif // CENTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
c->isfloating = 1;
|
2019-09-07 22:23:30 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-09-15 22:13:03 +00:00
|
|
|
} else {
|
2019-09-04 22:16:39 +00:00
|
|
|
c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
|
2019-09-15 22:13:03 +00:00
|
|
|
#if URGENTBORDER_PATCH
|
|
|
|
if (c->isurgent) {
|
|
|
|
#if FLOAT_BORDER_COLOR_PATCH
|
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel);
|
|
|
|
}
|
|
|
|
#endif // URGENTBORDER_PATCH
|
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
if (wmh->flags & InputHint)
|
|
|
|
c->neverfocus = !wmh->input;
|
|
|
|
else
|
|
|
|
c->neverfocus = 0;
|
|
|
|
XFree(wmh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
view(const Arg *arg)
|
|
|
|
{
|
2019-10-02 21:22:04 +00:00
|
|
|
#if EMPTYVIEW_PATCH
|
|
|
|
if (arg->ui && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
2019-10-02 21:22:04 +00:00
|
|
|
#endif // EMPTYVIEW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
|
|
|
selmon->seltags ^= 1; /* toggle sel tagset */
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
pertagview(arg);
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH
|
|
|
|
Client *unmodified = selmon->pertag->prevclient[selmon->pertag->curtag];
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (arg->ui & TAGMASK)
|
|
|
|
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
2019-09-05 20:58:16 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
selmon->pertag->prevclient[selmon->pertag->curtag] = unmodified;
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
2019-09-11 22:48:29 +00:00
|
|
|
#if EWMHTAGS_PATCH
|
|
|
|
updatecurrentdesktop();
|
|
|
|
#endif // EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2019-10-24 05:35:00 +00:00
|
|
|
#if EXTRABAR_PATCH
|
|
|
|
if (w == m->barwin || w == m->extrabarwin)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (w == m->barwin)
|
2019-10-24 05:35:00 +00:00
|
|
|
#endif // EXTRABAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
|
|
|
zoom(const Arg *arg)
|
|
|
|
{
|
|
|
|
Client *c = selmon->sel;
|
2019-09-05 21:19:23 +00:00
|
|
|
#if ZOOMSWAP_PATCH
|
|
|
|
Client *at = NULL, *cold, *cprevious = NULL, *p;
|
|
|
|
#endif // ZOOMSWAP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
selmon->pertag->prevclient[selmon->pertag->curtag] = nexttiled(selmon->clients);
|
|
|
|
#endif // SWAPFOCUS_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!selmon->lt[selmon->sellt]->arrange
|
2019-09-05 21:19:23 +00:00
|
|
|
|| (selmon->sel && selmon->sel->isfloating)
|
|
|
|
#if ZOOMSWAP_PATCH
|
|
|
|
|| !c
|
|
|
|
#endif // ZOOMSWAP_PATCH
|
|
|
|
)
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
2019-09-05 21:19:23 +00:00
|
|
|
|
|
|
|
#if ZOOMSWAP_PATCH
|
2020-01-15 12:21:56 +00:00
|
|
|
if (c == nexttiled(selmon->clients)) {
|
|
|
|
#if PERTAG_PATCH
|
|
|
|
p = selmon->pertag->prevzooms[selmon->pertag->curtag];
|
|
|
|
#else
|
|
|
|
p = prevzoom;
|
|
|
|
#endif // PERTAG_PATCH
|
|
|
|
at = prevtiled(p);
|
|
|
|
if (at)
|
|
|
|
cprevious = nexttiled(at->next);
|
|
|
|
if (!cprevious || cprevious != p) {
|
2019-09-05 21:19:23 +00:00
|
|
|
#if PERTAG_PATCH
|
2020-01-15 12:21:56 +00:00
|
|
|
selmon->pertag->prevzooms[selmon->pertag->curtag] = NULL;
|
2019-09-05 21:19:23 +00:00
|
|
|
#else
|
2020-01-15 12:21:56 +00:00
|
|
|
prevzoom = NULL;
|
2019-09-05 21:19:23 +00:00
|
|
|
#endif // PERTAG_PATCH
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
if (!c || !(c = selmon->pertag->prevclient[selmon->pertag->curtag] = nexttiled(c->next)))
|
|
|
|
#else
|
2020-01-15 12:21:56 +00:00
|
|
|
if (!c || !(c = nexttiled(c->next)))
|
2020-01-29 07:31:00 +00:00
|
|
|
#endif // SWAPFOCUS_PATCH
|
2020-01-15 12:21:56 +00:00
|
|
|
return;
|
|
|
|
} else
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
c = selmon->pertag->prevclient[selmon->pertag->curtag] = cprevious;
|
|
|
|
#else
|
2020-01-15 12:21:56 +00:00
|
|
|
c = cprevious;
|
2020-01-29 07:31:00 +00:00
|
|
|
#endif // SWAPFOCUS_PATCH
|
2020-01-15 12:21:56 +00:00
|
|
|
}
|
2019-09-05 21:19:23 +00:00
|
|
|
|
2020-01-15 12:21:56 +00:00
|
|
|
cold = nexttiled(selmon->clients);
|
|
|
|
if (c != cold && !at)
|
|
|
|
at = prevtiled(c);
|
|
|
|
detach(c);
|
|
|
|
attach(c);
|
|
|
|
/* swap windows instead of pushing the previous one down */
|
|
|
|
if (c != cold && at) {
|
|
|
|
#if PERTAG_PATCH
|
|
|
|
selmon->pertag->prevzooms[selmon->pertag->curtag] = cold;
|
|
|
|
#else
|
|
|
|
prevzoom = cold;
|
|
|
|
#endif // PERTAG_PATCH
|
|
|
|
if (cold && at != cold) {
|
|
|
|
detach(cold);
|
|
|
|
cold->next = at->next;
|
|
|
|
at->next = cold;
|
2019-09-05 21:19:23 +00:00
|
|
|
}
|
2020-01-15 12:21:56 +00:00
|
|
|
}
|
|
|
|
focus(c);
|
|
|
|
arrange(c->mon);
|
2019-09-05 21:19:23 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c == nexttiled(selmon->clients))
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
|
|
|
if (!c || !(c = selmon->pertag->prevclient[selmon->pertag->curtag] = nexttiled(c->next)))
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!c || !(c = nexttiled(c->next)))
|
2020-01-29 07:31:00 +00:00
|
|
|
#endif // SWAPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
|
|
|
pop(c);
|
2019-09-05 21:19:23 +00:00
|
|
|
#endif // ZOOMSWAP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
2019-11-04 07:17:00 +00:00
|
|
|
#if CMDCUSTOMIZE_PATCH
|
2019-10-05 21:56:43 +00:00
|
|
|
for (int i=1;i<argc;i+=1)
|
|
|
|
if (!strcmp("-v", argv[i]))
|
|
|
|
die("dwm-"VERSION);
|
|
|
|
else if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]))
|
|
|
|
die(help());
|
|
|
|
else if (!strcmp("-fn", argv[i])) /* font set */
|
|
|
|
fonts[0] = argv[++i];
|
2020-02-11 17:31:11 +00:00
|
|
|
#if !VTCOLORS_PATCH
|
2019-10-05 21:56:43 +00:00
|
|
|
else if (!strcmp("-nb", argv[i])) /* normal background color */
|
|
|
|
colors[SchemeNorm][1] = argv[++i];
|
|
|
|
else if (!strcmp("-nf", argv[i])) /* normal foreground color */
|
|
|
|
colors[SchemeNorm][0] = argv[++i];
|
|
|
|
else if (!strcmp("-sb", argv[i])) /* selected background color */
|
|
|
|
colors[SchemeSel][1] = argv[++i];
|
|
|
|
else if (!strcmp("-sf", argv[i])) /* selected foreground color */
|
|
|
|
colors[SchemeSel][0] = argv[++i];
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // !VTCOLORS_PATCH
|
2019-11-04 07:17:00 +00:00
|
|
|
#if NODMENU_PATCH
|
|
|
|
else if (!strcmp("-df", argv[i])) /* dmenu font */
|
|
|
|
dmenucmd[2] = argv[++i];
|
|
|
|
else if (!strcmp("-dnb", argv[i])) /* dmenu normal background color */
|
|
|
|
dmenucmd[4] = argv[++i];
|
|
|
|
else if (!strcmp("-dnf", argv[i])) /* dmenu normal foreground color */
|
|
|
|
dmenucmd[6] = argv[++i];
|
|
|
|
else if (!strcmp("-dsb", argv[i])) /* dmenu selected background color */
|
|
|
|
dmenucmd[8] = argv[++i];
|
|
|
|
else if (!strcmp("-dsf", argv[i])) /* dmenu selected foreground color */
|
|
|
|
dmenucmd[10] = argv[++i];
|
|
|
|
#else
|
2019-10-05 21:56:43 +00:00
|
|
|
else if (!strcmp("-df", argv[i])) /* dmenu font */
|
|
|
|
dmenucmd[4] = argv[++i];
|
|
|
|
else if (!strcmp("-dnb", argv[i])) /* dmenu normal background color */
|
|
|
|
dmenucmd[6] = argv[++i];
|
|
|
|
else if (!strcmp("-dnf", argv[i])) /* dmenu normal foreground color */
|
|
|
|
dmenucmd[8] = argv[++i];
|
|
|
|
else if (!strcmp("-dsb", argv[i])) /* dmenu selected background color */
|
|
|
|
dmenucmd[10] = argv[++i];
|
|
|
|
else if (!strcmp("-dsf", argv[i])) /* dmenu selected foreground color */
|
|
|
|
dmenucmd[12] = argv[++i];
|
2019-11-04 07:17:00 +00:00
|
|
|
#endif // NODMENU_PATCH
|
2020-02-11 17:31:11 +00:00
|
|
|
else die(help());
|
2019-10-05 21:56:43 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (argc == 2 && !strcmp("-v", argv[1]))
|
|
|
|
die("dwm-"VERSION);
|
|
|
|
else if (argc != 1)
|
|
|
|
die("usage: dwm [-v]");
|
2019-11-04 07:17:00 +00:00
|
|
|
#endif // CMDCUSTOMIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
|
|
|
fputs("warning: no locale support\n", stderr);
|
|
|
|
if (!(dpy = XOpenDisplay(NULL)))
|
|
|
|
die("dwm: cannot open display");
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
if (!(xcon = XGetXCBConnection(dpy)))
|
|
|
|
die("dwm: cannot get xcb connection\n");
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
checkotherwm();
|
2020-02-11 17:31:11 +00:00
|
|
|
#if XRDB_PATCH && !VTCOLORS_PATCH
|
2019-09-15 20:45:22 +00:00
|
|
|
XrmInitialize();
|
|
|
|
loadxrdb();
|
2020-02-11 17:31:11 +00:00
|
|
|
#endif // XRDB_PATCH && !VTCOLORS_PATCH
|
2019-09-15 20:45:22 +00:00
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
setup();
|
|
|
|
#ifdef __OpenBSD__
|
|
|
|
if (pledge("stdio rpath proc exec", NULL) == -1)
|
|
|
|
die("pledge");
|
|
|
|
#endif /* __OpenBSD__ */
|
|
|
|
scan();
|
2019-09-06 21:37:30 +00:00
|
|
|
#if AUTOSTART_PATCH
|
|
|
|
runAutostart();
|
|
|
|
#endif
|
2019-09-04 22:16:39 +00:00
|
|
|
run();
|
2019-10-02 21:22:04 +00:00
|
|
|
#if RESTARTSIG_PATCH
|
|
|
|
if (restart)
|
|
|
|
execvp(argv[0], argv);
|
|
|
|
#endif // RESTARTSIG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
cleanup();
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|