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"
|
|
|
|
|
2020-08-25 14:27:14 +00:00
|
|
|
#if BAR_FLEXWINTITLE_PATCH
|
|
|
|
#ifndef FLEXTILE_DELUXE_LAYOUT
|
|
|
|
#define FLEXTILE_DELUXE_LAYOUT 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_PANGO_PATCH
|
2020-06-11 17:42:00 +00:00
|
|
|
#include <pango/pango.h>
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_PANGO_PATCH
|
2020-06-11 17:42:00 +00:00
|
|
|
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
#include <X11/XKBlib.h>
|
|
|
|
#endif // XKB_PATCH
|
|
|
|
|
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 */
|
2020-08-27 05:34:21 +00:00
|
|
|
#define Button6 6
|
|
|
|
#define Button7 7
|
|
|
|
#define Button8 8
|
|
|
|
#define Button9 9
|
2020-08-25 14:27:14 +00:00
|
|
|
#define NUMTAGS 9
|
2020-07-15 06:57:30 +00:00
|
|
|
#define BARRULES 20
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
#define MAXTABS 50
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
|
|
|
|
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
|
|
|
|
* MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
#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)))
|
2020-09-10 11:32:28 +00:00
|
|
|
#endif // BAR_ANYBAR_PATCH
|
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-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)
|
2020-06-15 11:24:23 +00:00
|
|
|
#define WTYPE "_NET_WM_WINDOW_TYPE_"
|
2020-06-05 09:23:22 +00:00
|
|
|
#if SCRATCHPADS_PATCH
|
2020-08-25 14:27:14 +00:00
|
|
|
#define TOTALTAGS (NUMTAGS + LENGTH(scratchpads))
|
|
|
|
#define TAGMASK ((1 << TOTALTAGS) - 1)
|
|
|
|
#define SPTAG(i) ((1 << NUMTAGS) << (i))
|
|
|
|
#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << NUMTAGS)
|
[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-08-25 14:27:14 +00:00
|
|
|
#define TAGMASK ((1 << NUMTAGS) - 1)
|
2020-06-05 09:23:22 +00:00
|
|
|
#endif // SCRATCHPADS_PATCH
|
2020-08-22 18:31:17 +00:00
|
|
|
#define TEXTWM(X) (drw_fontset_getwidth(drw, (X), True) + lrpad)
|
|
|
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X), False) + lrpad)
|
2020-08-23 16:18:05 +00:00
|
|
|
#define HIDDEN(C) ((getstate(C->win) == IconicState))
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
/* enums */
|
2020-06-25 09:56:41 +00:00
|
|
|
enum {
|
|
|
|
#if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
|
|
|
|
CurResizeBR,
|
|
|
|
CurResizeBL,
|
|
|
|
CurResizeTR,
|
|
|
|
CurResizeTL,
|
|
|
|
#endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
|
|
|
|
#if DRAGMFACT_PATCH
|
|
|
|
CurResizeHorzArrow,
|
|
|
|
CurResizeVertArrow,
|
|
|
|
#endif // DRAGMFACT_PATCH
|
|
|
|
#if DRAGCFACT_PATCH
|
|
|
|
CurIronCross,
|
|
|
|
#endif // DRAGCFACT_PATCH
|
|
|
|
CurNormal,
|
|
|
|
CurResize,
|
|
|
|
CurMove,
|
|
|
|
CurLast
|
|
|
|
}; /* cursor */
|
2019-09-13 21:56:05 +00:00
|
|
|
|
|
|
|
enum {
|
2020-08-13 13:42:49 +00:00
|
|
|
SchemeNorm,
|
|
|
|
SchemeSel,
|
|
|
|
SchemeTitleNorm,
|
|
|
|
SchemeTitleSel,
|
2020-08-21 13:49:15 +00:00
|
|
|
SchemeTagsNorm,
|
|
|
|
SchemeTagsSel,
|
2021-05-21 08:16:49 +00:00
|
|
|
SchemeHidNorm,
|
|
|
|
SchemeHidSel,
|
2020-08-21 13:49:15 +00:00
|
|
|
SchemeUrg,
|
2020-08-20 11:30:12 +00:00
|
|
|
#if BAR_FLEXWINTITLE_PATCH
|
|
|
|
SchemeFlexActTTB,
|
|
|
|
SchemeFlexActLTR,
|
|
|
|
SchemeFlexActMONO,
|
|
|
|
SchemeFlexActGRID,
|
|
|
|
SchemeFlexActGRD1,
|
|
|
|
SchemeFlexActGRD2,
|
|
|
|
SchemeFlexActGRDM,
|
|
|
|
SchemeFlexActHGRD,
|
|
|
|
SchemeFlexActDWDL,
|
|
|
|
SchemeFlexActSPRL,
|
|
|
|
SchemeFlexInaTTB,
|
|
|
|
SchemeFlexInaLTR,
|
|
|
|
SchemeFlexInaMONO,
|
|
|
|
SchemeFlexInaGRID,
|
|
|
|
SchemeFlexInaGRD1,
|
|
|
|
SchemeFlexInaGRD2,
|
|
|
|
SchemeFlexInaGRDM,
|
|
|
|
SchemeFlexInaHGRD,
|
|
|
|
SchemeFlexInaDWDL,
|
|
|
|
SchemeFlexInaSPRL,
|
|
|
|
SchemeFlexSelTTB,
|
|
|
|
SchemeFlexSelLTR,
|
|
|
|
SchemeFlexSelMONO,
|
|
|
|
SchemeFlexSelGRID,
|
|
|
|
SchemeFlexSelGRD1,
|
|
|
|
SchemeFlexSelGRD2,
|
|
|
|
SchemeFlexSelGRDM,
|
|
|
|
SchemeFlexSelHGRD,
|
|
|
|
SchemeFlexSelDWDL,
|
|
|
|
SchemeFlexSelSPRL,
|
|
|
|
SchemeFlexActFloat,
|
|
|
|
SchemeFlexInaFloat,
|
|
|
|
SchemeFlexSelFloat,
|
|
|
|
#endif // BAR_FLEXWINTITLE_PATCH
|
2019-09-13 21:56:05 +00:00
|
|
|
}; /* color schemes */
|
|
|
|
|
2020-05-20 13:25:07 +00:00
|
|
|
enum {
|
|
|
|
NetSupported, NetWMName, NetWMState, NetWMCheck,
|
|
|
|
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
|
2021-07-27 11:40:53 +00:00
|
|
|
#if BAR_WINICON_PATCH
|
|
|
|
NetWMIcon,
|
|
|
|
#endif // BAR_WINICON_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2020-05-20 13:25:07 +00:00
|
|
|
NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
|
|
|
|
NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
|
|
|
#if BAR_EWMHTAGS_PATCH
|
2020-05-20 13:25:07 +00:00
|
|
|
NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2020-10-26 10:10:14 +00:00
|
|
|
NetClientList,
|
|
|
|
#if NET_CLIENT_LIST_STACKING_PATCH
|
|
|
|
NetClientListStacking,
|
|
|
|
#endif // NET_CLIENT_LIST_STACKING_PATCH
|
|
|
|
NetLast
|
2019-09-11 22:48:29 +00:00
|
|
|
}; /* EWMH atoms */
|
|
|
|
|
2020-06-24 14:36:51 +00:00
|
|
|
enum {
|
|
|
|
WMProtocols,
|
|
|
|
WMDelete,
|
|
|
|
WMState,
|
|
|
|
WMTakeFocus,
|
|
|
|
#if WINDOWROLERULE_PATCH
|
|
|
|
WMWindowRole,
|
|
|
|
#endif // WINDOWROLERULE_PATCH
|
|
|
|
WMLast
|
|
|
|
}; /* default atoms */
|
|
|
|
|
|
|
|
enum {
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_STATUSBUTTON_PATCH
|
2020-06-24 14:36:51 +00:00
|
|
|
ClkButton,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUSBUTTON_PATCH
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
ClkTabBar,
|
|
|
|
#endif // TAB_PATCH
|
2020-06-24 14:36:51 +00:00
|
|
|
ClkTagBar,
|
|
|
|
ClkLtSymbol,
|
|
|
|
ClkStatusText,
|
|
|
|
ClkWinTitle,
|
|
|
|
ClkClientWin,
|
|
|
|
ClkRootWin,
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
ClkXKB,
|
|
|
|
#endif // XKB_PATCH
|
2020-06-24 14:36:51 +00:00
|
|
|
ClkLast
|
|
|
|
}; /* clicks */
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
enum {
|
|
|
|
BAR_ALIGN_LEFT,
|
|
|
|
BAR_ALIGN_CENTER,
|
|
|
|
BAR_ALIGN_RIGHT,
|
|
|
|
BAR_ALIGN_LEFT_LEFT,
|
|
|
|
BAR_ALIGN_LEFT_RIGHT,
|
|
|
|
BAR_ALIGN_LEFT_CENTER,
|
|
|
|
BAR_ALIGN_NONE,
|
|
|
|
BAR_ALIGN_RIGHT_LEFT,
|
|
|
|
BAR_ALIGN_RIGHT_RIGHT,
|
|
|
|
BAR_ALIGN_RIGHT_CENTER,
|
|
|
|
BAR_ALIGN_LAST
|
|
|
|
}; /* bar alignment */
|
|
|
|
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
typedef struct TagState TagState;
|
|
|
|
struct TagState {
|
|
|
|
int selected;
|
|
|
|
int occupied;
|
|
|
|
int urgent;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct ClientState ClientState;
|
|
|
|
struct ClientState {
|
|
|
|
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
|
|
|
};
|
|
|
|
#endif // IPC_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
typedef union {
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
long i;
|
|
|
|
unsigned long ui;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
int i;
|
|
|
|
unsigned int ui;
|
2020-09-07 15:48:58 +00:00
|
|
|
#endif // IPC_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
float f;
|
|
|
|
const void *v;
|
|
|
|
} Arg;
|
|
|
|
|
2020-07-18 11:03:30 +00:00
|
|
|
typedef struct Monitor Monitor;
|
2020-07-15 06:57:30 +00:00
|
|
|
typedef struct Bar Bar;
|
|
|
|
struct Bar {
|
|
|
|
Window win;
|
2020-07-18 11:03:30 +00:00
|
|
|
Monitor *mon;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *next;
|
2020-07-18 11:03:30 +00:00
|
|
|
int idx;
|
2020-08-22 06:43:07 +00:00
|
|
|
int showbar;
|
2020-07-18 16:58:39 +00:00
|
|
|
int topbar;
|
2020-09-10 13:24:51 +00:00
|
|
|
int external;
|
2020-09-09 15:24:02 +00:00
|
|
|
int borderpx;
|
|
|
|
int borderscheme;
|
2020-07-15 06:57:30 +00:00
|
|
|
int bx, by, bw, bh; /* bar geometry */
|
|
|
|
int w[BARRULES]; // width, array length == barrules, then use r index for lookup purposes
|
|
|
|
int x[BARRULES]; // x position, array length == ^
|
|
|
|
};
|
|
|
|
|
2020-07-15 12:10:47 +00:00
|
|
|
typedef struct {
|
|
|
|
int x;
|
2020-09-09 15:24:02 +00:00
|
|
|
int y;
|
|
|
|
int h;
|
2020-07-15 12:10:47 +00:00
|
|
|
int w;
|
2020-09-09 15:24:02 +00:00
|
|
|
} BarArg;
|
2020-07-15 12:10:47 +00:00
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
typedef struct {
|
|
|
|
int monitor;
|
|
|
|
int bar;
|
|
|
|
int alignment; // see bar alignment enum
|
2020-09-09 15:24:02 +00:00
|
|
|
int (*widthfunc)(Bar *bar, BarArg *a);
|
|
|
|
int (*drawfunc)(Bar *bar, BarArg *a);
|
|
|
|
int (*clickfunc)(Bar *bar, Arg *arg, BarArg *a);
|
2020-07-15 06:57:30 +00:00
|
|
|
char *name; // for debugging
|
|
|
|
int x, w; // position, width for internal use
|
|
|
|
} BarRule;
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
typedef struct {
|
|
|
|
unsigned int click;
|
|
|
|
unsigned int mask;
|
|
|
|
unsigned int button;
|
|
|
|
void (*func)(const Arg *arg);
|
|
|
|
const Arg arg;
|
|
|
|
} Button;
|
|
|
|
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
typedef struct XkbInfo XkbInfo;
|
|
|
|
struct XkbInfo {
|
|
|
|
XkbInfo *next;
|
|
|
|
XkbInfo *prev;
|
|
|
|
int group;
|
|
|
|
Window w;
|
|
|
|
};
|
|
|
|
#endif // XKB_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
manage: propertynotify: Reduce cost of unused size hints
This patch defers all size hint calculations until they are actually
needed, drastically reducing the number of calls to updatesizehints(),
which can be expensive when called repeatedly (as it currently is during
resizes).
In my unscientific testing this reduces calls to updatesizehints() by
over 90% during a typical work session. There are no functional changes
for users other than an increase in responsiveness after resizes and
a reduction in CPU time.
In slower environments or X servers, this patch also offers an
improvement in responsiveness that is often tangible after resizing a
client that changes hints during resizes.
There are two main motivations to defer this work to the time of hint
application:
1. Some clients, especially terminals using incremental size hints,
resend XA_WM_NORMAL_HINTS events on resize to avoid fighting with the
WM or mouse resizing. For example, some terminals like urxvt clear
PBaseSize and PResizeInc during XResizeWindow and restore them
afterwards.
For this reason, after the resize is concluded, we typically receive
a backlogged XA_WM_NORMAL_HINTS message for each update period with
movement, which is useless. In some cases one may get hundreds or
thousands of XA_WM_NORMAL_HINTS messages on large resizes, and
currently all of these result in a separate updatesizehints() call,
of which all but the final one are immediately outdated.
(We can't just blindly discard these messages during resizes like we
do for EnterNotify, because some of them might actually be for other
windows, and may not be XA_WM_NORMAL_HINTS events.)
2. For users which use resizehints=0 most of these updates are unused
anyway -- in the normal case where the client is not floating these
values won't be used, so there's no need to calculate them up front.
A synthetic test using the mouse to resize a floating terminal window
from roughly 256x256 to 1024x1024 and back again shows that the number
of calls to updatesizehints() goes from over 500 before this patch (one
for each update interval with movement) to 2 after this patch (one for
each hint application), with no change in user visible behaviour.
This also reduces the delay before dwm is ready to process new events
again after a large resize on such a client, as it avoids the thundering
herd of updatesizehints() calls when hundreds of backlogged
XA_WM_NORMAL_HINTS messages appear at once after a resize is finished.
ref.
https://git.suckless.org/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.html#h0-0-4
2022-04-17 08:15:22 +00:00
|
|
|
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2021-01-22 10:28:55 +00:00
|
|
|
#if PLACEMOUSE_PATCH
|
|
|
|
int beingmoved;
|
|
|
|
#endif // PLACEMOUSE_PATCH
|
2022-02-11 09:10:28 +00:00
|
|
|
#if SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
int isfreesize;
|
|
|
|
#endif // SIZEHINTS_ISFREESIZE_PATCH
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
int isterminal, noswallow;
|
|
|
|
pid_t pid;
|
|
|
|
#endif // SWALLOW_PATCH
|
2020-08-10 15:09:20 +00:00
|
|
|
#if STEAM_PATCH
|
|
|
|
int issteam;
|
|
|
|
#endif // STEAM_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;
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
ClientState prevstate;
|
|
|
|
#endif // IPC_PATCH
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
XkbInfo *xkb;
|
|
|
|
#endif // XKB_PATCH
|
2021-07-27 11:40:53 +00:00
|
|
|
#if BAR_WINICON_PATCH
|
2022-03-06 10:38:22 +00:00
|
|
|
unsigned int icw, ich;
|
|
|
|
Picture icon;
|
2021-07-27 11:40:53 +00:00
|
|
|
#endif // BAR_WINICON_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-08-10 10:32:58 +00:00
|
|
|
#if INSETS_PATCH
|
|
|
|
typedef struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
int w;
|
|
|
|
int h;
|
|
|
|
} Inset;
|
|
|
|
#endif // INSETS_PATCH
|
|
|
|
|
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 mx, my, mw, mh; /* screen size */
|
|
|
|
int wx, wy, ww, wh; /* window area */
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
int ty; /* tab bar geometry */
|
|
|
|
#endif // TAB_PATCH
|
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;
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
int showtab;
|
|
|
|
int toptab;
|
|
|
|
Window tabwin;
|
|
|
|
int ntabs;
|
|
|
|
int tab_widths[MAXTABS];
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Client *clients;
|
|
|
|
Client *sel;
|
|
|
|
Client *stack;
|
|
|
|
Monitor *next;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2019-09-04 22:16:39 +00:00
|
|
|
const Layout *lt[2];
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_ALTERNATIVE_TAGS_PATCH
|
2019-09-09 21:27:10 +00:00
|
|
|
unsigned int alttag;
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_ALTERNATIVE_TAGS_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
Pertag *pertag;
|
|
|
|
#endif // PERTAG_PATCH
|
2020-08-10 10:32:58 +00:00
|
|
|
#if INSETS_PATCH
|
|
|
|
Inset inset;
|
|
|
|
#endif // INSETS_PATCH
|
2021-11-23 21:36:53 +00:00
|
|
|
#if BAR_TAGLABELS_PATCH
|
|
|
|
char taglabel[NUMTAGS][64];
|
|
|
|
#endif // BAR_TAGLABELS_PATCH
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
char lastltsymbol[16];
|
|
|
|
TagState tagstate;
|
|
|
|
Client *lastsel;
|
|
|
|
const Layout *lastlt;
|
|
|
|
#endif // IPC_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;
|
2020-06-15 11:24:23 +00:00
|
|
|
const char *wintype;
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2021-05-13 12:25:26 +00:00
|
|
|
#if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2020-09-16 09:00:31 +00:00
|
|
|
int isfakefullscreen;
|
|
|
|
#endif // SELECTIVEFAKEFULLSCREEN_PATCH
|
2022-02-11 09:10:28 +00:00
|
|
|
#if SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
int isfreesize;
|
|
|
|
#endif // SIZEHINTS_ISFREESIZE_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;
|
|
|
|
int noswallow;
|
|
|
|
#endif // SWALLOW_PATCH
|
2020-06-21 13:33:29 +00:00
|
|
|
#if FLOATPOS_PATCH
|
|
|
|
const char *floatpos;
|
|
|
|
#endif // FLOATPOS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int monitor;
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
int xkb_layout;
|
|
|
|
#endif // XKB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} Rule;
|
|
|
|
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
2021-06-14 09:09:22 +00:00
|
|
|
#define RULE(...) { .monitor = -1, .xkb_layout = -1, __VA_ARGS__ },
|
2021-04-07 13:35:56 +00:00
|
|
|
#else
|
2021-06-14 09:09:22 +00:00
|
|
|
#define RULE(...) { .monitor = -1, __VA_ARGS__ },
|
2021-04-07 13:35:56 +00:00
|
|
|
#endif // XKB_PATCH
|
2020-06-14 13:52:47 +00:00
|
|
|
|
2020-06-15 13:34:44 +00:00
|
|
|
/* Cross patch compatibility rule macro helper macros */
|
|
|
|
#define FLOATING , .isfloating = 1
|
|
|
|
#if CENTER_PATCH
|
|
|
|
#define CENTERED , .iscentered = 1
|
|
|
|
#else
|
|
|
|
#define CENTERED
|
|
|
|
#endif // CENTER_PATCH
|
|
|
|
#if ISPERMANENT_PATCH
|
|
|
|
#define PERMANENT , .ispermanent = 1
|
|
|
|
#else
|
|
|
|
#define PERMANENT
|
|
|
|
#endif // ISPERMANENT_PATCH
|
2021-05-13 12:25:26 +00:00
|
|
|
#if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2020-09-16 09:00:31 +00:00
|
|
|
#define FAKEFULLSCREEN , .isfakefullscreen = 1
|
|
|
|
#else
|
|
|
|
#define FAKEFULLSCREEN
|
|
|
|
#endif // SELECTIVEFAKEFULLSCREEN_PATCH
|
2020-06-15 13:34:44 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
#define NOSWALLOW , .noswallow = 1
|
|
|
|
#define TERMINAL , .isterminal = 1
|
|
|
|
#else
|
|
|
|
#define NOSWALLOW
|
|
|
|
#define TERMINAL
|
|
|
|
#endif // SWALLOW_PATCH
|
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
#define SWITCHTAG , .switchtag = 1
|
|
|
|
#else
|
|
|
|
#define SWITCHTAG
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2020-06-14 13:52:47 +00:00
|
|
|
|
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;
|
2020-04-26 14:26:36 +00:00
|
|
|
int nmaster;
|
|
|
|
int showbar;
|
|
|
|
int topbar;
|
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);
|
2020-07-18 11:03:30 +00:00
|
|
|
static void drawbarwin(Bar *bar);
|
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);
|
2020-05-31 13:14:29 +00:00
|
|
|
#if KEYMODES_PATCH
|
|
|
|
static void grabdefkeys(void);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
static void grabkeys(void);
|
2020-05-31 13:14:29 +00:00
|
|
|
#endif // KEYMODES_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void incnmaster(const Arg *arg);
|
2020-05-31 13:14:29 +00:00
|
|
|
#if KEYMODES_PATCH
|
|
|
|
static void keydefpress(XEvent *e);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
static void keypress(XEvent *e);
|
2020-05-31 13:14:29 +00:00
|
|
|
#endif // KEYMODES_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_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);
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
static pid_t spawncmd(const Arg *arg);
|
|
|
|
#endif // RIODRAW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2020-09-05 09:38:09 +00:00
|
|
|
static void unfocus(Client *c, int setfocus, Client *nextfocus);
|
2019-09-04 22:16:39 +00:00
|
|
|
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 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);
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
/* bar functions */
|
|
|
|
|
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";
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_PANGO_PATCH || BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
static char stext[1024];
|
|
|
|
#else
|
2020-07-07 16:25:00 +00:00
|
|
|
static char stext[512];
|
2020-07-19 03:01:38 +00:00
|
|
|
#endif // BAR_PANGO_PATCH | BAR_STATUS2D_PATCH
|
2020-07-18 19:12:30 +00:00
|
|
|
#if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_STATUS2D_PATCH
|
2020-07-05 19:53:36 +00:00
|
|
|
static char rawstext[1024];
|
|
|
|
#else
|
|
|
|
static char rawstext[512];
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUS2D_PATCH
|
2020-07-18 19:12:30 +00:00
|
|
|
#endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
|
|
|
|
#if BAR_EXTRASTATUS_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
static char estext[1024];
|
|
|
|
#else
|
2020-07-07 16:25:00 +00:00
|
|
|
static char estext[512];
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUS2D_PATCH
|
|
|
|
#if BAR_STATUSCMD_PATCH
|
2020-07-05 19:53:36 +00:00
|
|
|
static char rawestext[1024];
|
2020-07-19 14:57:30 +00:00
|
|
|
#endif // BAR_STATUS2D_PATCH | BAR_STATUSCMD_PATCH
|
2020-07-18 19:12:30 +00:00
|
|
|
#endif // BAR_EXTRASTATUS_PATCH
|
2020-07-05 19:53:36 +00:00
|
|
|
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
static int xkbEventType = 0;
|
|
|
|
#endif // XKB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static int screen;
|
|
|
|
static int sw, sh; /* X display screen geometry width, height */
|
2020-07-15 06:57:30 +00:00
|
|
|
static int bh; /* bar geometry */
|
2019-09-04 22:16:39 +00:00
|
|
|
static int lrpad; /* sum of left and right padding for text */
|
2020-09-14 08:08:47 +00:00
|
|
|
/* Some clients (e.g. alacritty) helpfully send configure requests with a new size or position
|
|
|
|
* when they detect that they have been moved to another monitor. This can cause visual glitches
|
|
|
|
* when moving (or resizing) client windows from one monitor to another. This variable is used
|
|
|
|
* internally to ignore such configure requests while movemouse or resizemouse are being used. */
|
|
|
|
static int ignoreconfigurerequests = 0;
|
2020-10-06 06:45:17 +00:00
|
|
|
#if WARP_PATCH
|
|
|
|
static int force_warp = 0; // force warp in some situations, e.g. killclient
|
|
|
|
static int ignore_warp = 0; // force skip warp in some situations, e.g. dragmfact, dragcfact
|
|
|
|
#endif // WARP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
|
|
|
static unsigned int numlockmask = 0;
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
static int riodimensions[4] = { -1, -1, -1, -1 };
|
|
|
|
static pid_t riopid = 0;
|
|
|
|
#endif // RIODRAW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
static void (*handler[LASTEvent]) (XEvent *) = {
|
|
|
|
[ButtonPress] = buttonpress,
|
2020-07-15 06:57:30 +00:00
|
|
|
#if COMBO_PATCH || BAR_HOLDBAR_PATCH
|
2019-09-11 21:35:43 +00:00
|
|
|
[ButtonRelease] = keyrelease,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // COMBO_PATCH / BAR_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,
|
2020-07-15 06:57:30 +00:00
|
|
|
#if COMBO_PATCH || BAR_HOLDBAR_PATCH
|
2019-09-11 21:35:43 +00:00
|
|
|
[KeyRelease] = keyrelease,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // COMBO_PATCH / BAR_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,
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
[ResizeRequest] = resizerequest,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
[UnmapNotify] = unmapnotify
|
|
|
|
};
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
static Atom wmatom[WMLast], netatom[NetLast];
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2020-09-29 13:49:51 +00:00
|
|
|
#if ON_EMPTY_KEYS_PATCH
|
|
|
|
static int isempty = 0;
|
|
|
|
#endif // ON_EMPTY_KEYS_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. */
|
2020-06-05 07:43:27 +00:00
|
|
|
#if SCRATCHPAD_ALT_1_PATCH
|
2020-08-25 14:27:14 +00:00
|
|
|
struct NumTags { char limitexceeded[NUMTAGS > 30 ? -1 : 1]; };
|
2020-06-05 07:43:27 +00:00
|
|
|
#else
|
2020-08-25 14:27:14 +00:00
|
|
|
struct NumTags { char limitexceeded[NUMTAGS > 31 ? -1 : 1]; };
|
2020-06-05 07:43:27 +00:00
|
|
|
#endif // SCRATCHPAD_ALT_1_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
/* function implementations */
|
|
|
|
void
|
|
|
|
applyrules(Client *c)
|
|
|
|
{
|
|
|
|
const char *class, *instance;
|
2020-06-15 11:24:23 +00:00
|
|
|
Atom wintype;
|
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;
|
2020-07-03 11:30:21 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
unsigned int newtagset;
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
const Rule *r;
|
|
|
|
Monitor *m;
|
|
|
|
XClassHint ch = { NULL, NULL };
|
|
|
|
|
|
|
|
/* rule matching */
|
2020-09-11 09:47:57 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
c->noswallow = -1;
|
|
|
|
#endif // SWALLOW_PATCH
|
2022-02-11 09:10:28 +00:00
|
|
|
#if SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
c->isfreesize = 1;
|
|
|
|
#endif // SIZEHINTS_ISFREESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-06-15 11:24:23 +00:00
|
|
|
wintype = getatomprop(c, netatom[NetWMWindowType]);
|
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
|
|
|
|
2020-08-10 15:09:20 +00:00
|
|
|
#if STEAM_PATCH
|
|
|
|
if (strstr(class, "Steam") || strstr(class, "steam_app_"))
|
|
|
|
c->issteam = 1;
|
|
|
|
#endif // STEAM_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
|
2020-06-15 11:24:23 +00:00
|
|
|
&& (!r->instance || strstr(instance, r->instance))
|
|
|
|
&& (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False)))
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
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
|
2021-05-13 12:25:26 +00:00
|
|
|
#if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2020-09-16 09:00:31 +00:00
|
|
|
c->fakefullscreen = r->isfakefullscreen;
|
|
|
|
#endif // SELECTIVEFAKEFULLSCREEN_PATCH
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
c->isterminal = r->isterminal;
|
|
|
|
c->noswallow = r->noswallow;
|
|
|
|
#endif // SWALLOW_PATCH
|
2022-02-11 09:10:28 +00:00
|
|
|
#if SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
c->isfreesize = r->isfreesize;
|
|
|
|
#endif // SIZEHINTS_ISFREESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
c->isfloating = r->isfloating;
|
|
|
|
c->tags |= r->tags;
|
2020-09-07 07:50:42 +00:00
|
|
|
#if SCRATCHPADS_PATCH
|
[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 ((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);
|
|
|
|
}
|
2020-09-07 07:50:42 +00:00
|
|
|
#endif // SCRATCHPADS_PATCH
|
2020-06-23 09:55:55 +00:00
|
|
|
for (m = mons; m && m->num != r->monitor; m = m->next);
|
|
|
|
if (m)
|
|
|
|
c->mon = m;
|
2020-06-21 13:33:29 +00:00
|
|
|
#if FLOATPOS_PATCH
|
2020-09-29 11:26:05 +00:00
|
|
|
if (c->isfloating && r->floatpos) {
|
|
|
|
#if CENTER_PATCH
|
|
|
|
c->iscentered = 0;
|
|
|
|
#endif // CENTER_PATCH
|
2020-06-21 13:33:29 +00:00
|
|
|
setfloatpos(c, r->floatpos);
|
2020-09-29 11:26:05 +00:00
|
|
|
}
|
2020-06-21 13:33:29 +00:00
|
|
|
#endif // FLOATPOS_PATCH
|
|
|
|
|
2019-09-07 22:23:30 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
2020-04-23 15:19:17 +00:00
|
|
|
#if SWALLOW_PATCH
|
2020-09-11 09:47:57 +00:00
|
|
|
if (r->switchtag && (
|
|
|
|
c->noswallow > 0 ||
|
|
|
|
!termforwin(c) ||
|
|
|
|
!(c->isfloating && swallowfloating && c->noswallow < 0)))
|
2020-04-23 15:19:17 +00:00
|
|
|
#else
|
|
|
|
if (r->switchtag)
|
|
|
|
#endif // SWALLOW_PATCH
|
|
|
|
{
|
2020-07-03 11:30:21 +00:00
|
|
|
selmon = c->mon;
|
|
|
|
if (r->switchtag == 2 || r->switchtag == 4)
|
2019-09-07 22:23:30 +00:00
|
|
|
newtagset = c->mon->tagset[c->mon->seltags] ^ c->tags;
|
|
|
|
else
|
|
|
|
newtagset = c->tags;
|
|
|
|
|
2020-07-02 08:09:24 +00:00
|
|
|
/* Switch to the client's tag, but only if that tag is not already shown */
|
2020-07-03 11:30:21 +00:00
|
|
|
if (newtagset && !(c->tags & c->mon->tagset[c->mon->seltags])) {
|
|
|
|
if (r->switchtag == 3 || r->switchtag == 4)
|
|
|
|
c->switchtag = c->mon->tagset[c->mon->seltags];
|
|
|
|
if (r->switchtag == 1 || r->switchtag == 3) {
|
2019-11-26 19:23:58 +00:00
|
|
|
#if PERTAG_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
pertagview(&((Arg) { .ui = newtagset }));
|
2020-07-03 11:30:21 +00:00
|
|
|
arrange(c->mon);
|
2019-11-26 19:23:58 +00:00
|
|
|
#else
|
|
|
|
view(&((Arg) { .ui = newtagset }));
|
|
|
|
#endif // PERTAG_PATCH
|
2020-07-03 13:57:14 +00:00
|
|
|
} else {
|
2022-02-11 15:57:53 +00:00
|
|
|
#if TAGSYNC_PATCH
|
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
m->tagset[m->seltags] = newtagset;
|
|
|
|
arrange(NULL);
|
|
|
|
#else
|
2020-07-03 13:57:14 +00:00
|
|
|
c->mon->tagset[c->mon->seltags] = newtagset;
|
2020-07-03 11:30:21 +00:00
|
|
|
arrange(c->mon);
|
2022-02-11 15:57:53 +00:00
|
|
|
#endif // TAGSYNC_PATCH
|
2020-07-03 13:57:14 +00:00
|
|
|
}
|
2019-09-07 22:23:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
if (r->xkb_layout > -1)
|
|
|
|
c->xkb->group = r->xkb_layout;
|
|
|
|
#endif // XKB_PATCH
|
2020-09-16 09:00:31 +00:00
|
|
|
#if ONLY_ONE_RULE_MATCH_PATCH
|
|
|
|
break;
|
|
|
|
#endif // ONLY_ONE_RULE_MATCH_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;
|
2020-06-05 09:23:22 +00:00
|
|
|
#if SCRATCHPADS_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;
|
2020-06-05 07:43:27 +00:00
|
|
|
#elif SCRATCHPAD_ALT_1_PATCH
|
|
|
|
else if (c->tags != SCRATCHPAD_MASK && 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
|
|
|
#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];
|
2020-06-05 09:23:22 +00:00
|
|
|
#endif // SCRATCHPADS_PATCH
|
2020-07-03 11:30:21 +00:00
|
|
|
else c->tags = 1;
|
2020-06-05 09:23:22 +00:00
|
|
|
#elif SCRATCHPADS_PATCH
|
[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
|
|
|
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK);
|
2020-06-05 07:43:27 +00:00
|
|
|
#elif SCRATCHPAD_ALT_1_PATCH
|
|
|
|
if (c->tags != SCRATCHPAD_MASK)
|
|
|
|
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
|
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) {
|
manage: propertynotify: Reduce cost of unused size hints
This patch defers all size hint calculations until they are actually
needed, drastically reducing the number of calls to updatesizehints(),
which can be expensive when called repeatedly (as it currently is during
resizes).
In my unscientific testing this reduces calls to updatesizehints() by
over 90% during a typical work session. There are no functional changes
for users other than an increase in responsiveness after resizes and
a reduction in CPU time.
In slower environments or X servers, this patch also offers an
improvement in responsiveness that is often tangible after resizing a
client that changes hints during resizes.
There are two main motivations to defer this work to the time of hint
application:
1. Some clients, especially terminals using incremental size hints,
resend XA_WM_NORMAL_HINTS events on resize to avoid fighting with the
WM or mouse resizing. For example, some terminals like urxvt clear
PBaseSize and PResizeInc during XResizeWindow and restore them
afterwards.
For this reason, after the resize is concluded, we typically receive
a backlogged XA_WM_NORMAL_HINTS message for each update period with
movement, which is useless. In some cases one may get hundreds or
thousands of XA_WM_NORMAL_HINTS messages on large resizes, and
currently all of these result in a separate updatesizehints() call,
of which all but the final one are immediately outdated.
(We can't just blindly discard these messages during resizes like we
do for EnterNotify, because some of them might actually be for other
windows, and may not be XA_WM_NORMAL_HINTS events.)
2. For users which use resizehints=0 most of these updates are unused
anyway -- in the normal case where the client is not floating these
values won't be used, so there's no need to calculate them up front.
A synthetic test using the mouse to resize a floating terminal window
from roughly 256x256 to 1024x1024 and back again shows that the number
of calls to updatesizehints() goes from over 500 before this patch (one
for each update interval with movement) to 2 after this patch (one for
each hint application), with no change in user visible behaviour.
This also reduces the delay before dwm is ready to process new events
again after a large resize on such a client, as it avoids the thundering
herd of updatesizehints() calls when hundreds of backlogged
XA_WM_NORMAL_HINTS messages appear at once after a resize is finished.
ref.
https://git.suckless.org/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.html#h0-0-4
2022-04-17 08:15:22 +00:00
|
|
|
if (!c->hintsvalid)
|
|
|
|
updatesizehints(c);
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
updatebarpos(m);
|
|
|
|
XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2021-03-09 12:47:21 +00:00
|
|
|
int click, i, r;
|
|
|
|
#if TAB_PATCH
|
|
|
|
int x;
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
Arg arg = {0};
|
|
|
|
Client *c;
|
|
|
|
Monitor *m;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2019-09-04 22:16:39 +00:00
|
|
|
XButtonPressedEvent *ev = &e->xbutton;
|
2020-07-15 06:57:30 +00:00
|
|
|
const BarRule *br;
|
2020-09-09 15:24:02 +00:00
|
|
|
BarArg carg = { 0, 0, 0, 0 };
|
2019-09-04 22:16:39 +00:00
|
|
|
click = ClkRootWin;
|
2021-04-14 09:23:18 +00:00
|
|
|
|
|
|
|
#if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH
|
|
|
|
*lastbutton = '0' + ev->button;
|
|
|
|
#endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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
|
|
|
|
) {
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(selmon->sel, 1, NULL);
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon = m;
|
|
|
|
focus(NULL);
|
|
|
|
}
|
2019-09-09 22:18:46 +00:00
|
|
|
|
2020-07-18 16:58:39 +00:00
|
|
|
for (bar = selmon->bar; bar; bar = bar->next) {
|
|
|
|
if (ev->window == bar->win) {
|
2020-07-15 06:57:30 +00:00
|
|
|
for (r = 0; r < LENGTH(barrules); r++) {
|
|
|
|
br = &barrules[r];
|
2020-07-18 16:58:39 +00:00
|
|
|
if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL)
|
2020-07-18 11:03:30 +00:00
|
|
|
continue;
|
2022-04-17 08:33:26 +00:00
|
|
|
if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
|
2020-07-15 06:57:30 +00:00
|
|
|
continue;
|
2020-07-18 16:58:39 +00:00
|
|
|
if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) {
|
2020-09-09 15:24:02 +00:00
|
|
|
carg.x = ev->x - bar->x[r];
|
|
|
|
carg.y = ev->y - bar->borderpx;
|
|
|
|
carg.w = bar->w[r];
|
|
|
|
carg.h = bar->bh - 2 * bar->borderpx;
|
2020-07-18 16:58:39 +00:00
|
|
|
click = br->clickfunc(bar, &arg, &carg);
|
2020-07-15 12:10:47 +00:00
|
|
|
if (click < 0)
|
|
|
|
return;
|
2020-07-15 06:57:30 +00:00
|
|
|
break;
|
2020-07-05 19:53:36 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
break;
|
2020-07-05 19:53:36 +00:00
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
}
|
|
|
|
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
if (ev->window == selmon->tabwin) {
|
|
|
|
for (i = 0, x = 0, c = selmon->clients; c; c = c->next) {
|
|
|
|
if (!ISVISIBLE(c) || HIDDEN(c))
|
|
|
|
continue;
|
|
|
|
x += selmon->tab_widths[i];
|
|
|
|
if (ev->x > x)
|
|
|
|
++i;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
if (i >= m->ntabs)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (c) {
|
|
|
|
click = ClkTabBar;
|
|
|
|
arg.ui = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // TAB_PATCH
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
if (click == ClkRootWin && (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;
|
|
|
|
}
|
2020-07-15 12:10:47 +00:00
|
|
|
|
|
|
|
for (i = 0; i < LENGTH(buttons); i++) {
|
2019-09-04 22:16:39 +00:00
|
|
|
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
|
2020-07-15 12:10:47 +00:00
|
|
|
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
|
2021-03-09 12:23:39 +00:00
|
|
|
buttons[i].func(
|
|
|
|
(
|
|
|
|
click == ClkTagBar
|
|
|
|
#if TAB_PATCH
|
|
|
|
|| click == ClkTabBar
|
|
|
|
#endif // TAB_PATCH
|
|
|
|
#if BAR_WINTITLEACTIONS_PATCH
|
|
|
|
|| click == ClkWinTitle
|
|
|
|
#endif // BAR_WINTITLEACTIONS_PATCH
|
|
|
|
) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg
|
|
|
|
);
|
2020-07-15 06:57:30 +00:00
|
|
|
}
|
2020-07-15 12:10:47 +00:00
|
|
|
}
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2020-08-10 09:36:10 +00:00
|
|
|
if (showsystray && systray) {
|
2021-04-28 11:35:22 +00:00
|
|
|
while (systray->icons)
|
|
|
|
removesystrayicon(systray->icons);
|
2020-08-10 09:36:10 +00:00
|
|
|
if (systray->win) {
|
|
|
|
XUnmapWindow(dpy, systray->win);
|
|
|
|
XDestroyWindow(dpy, systray->win);
|
|
|
|
}
|
2019-09-05 20:10:00 +00:00
|
|
|
free(systray);
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
for (i = 0; i < CurLast; i++)
|
|
|
|
drw_cur_free(drw, cursor[i]);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
for (i = 0; i < LENGTH(colors) + 1; i++)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
for (i = 0; i < LENGTH(colors); i++)
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUS2D_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
free(scheme[i]);
|
2020-01-27 08:15:20 +00:00
|
|
|
free(scheme);
|
2019-09-04 22:16:39 +00:00
|
|
|
XDestroyWindow(dpy, wmcheckwin);
|
|
|
|
drw_free(drw);
|
|
|
|
XSync(dpy, False);
|
|
|
|
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
|
|
|
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
2020-09-07 15:48:58 +00:00
|
|
|
|
|
|
|
#if IPC_PATCH
|
|
|
|
ipc_cleanup();
|
|
|
|
|
|
|
|
if (close(epoll_fd) < 0)
|
|
|
|
fprintf(stderr, "Failed to close epoll file descriptor\n");
|
|
|
|
#endif // IPC_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cleanupmon(Monitor *mon)
|
|
|
|
{
|
|
|
|
Monitor *m;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
if (mon == mons)
|
|
|
|
mons = mons->next;
|
|
|
|
else {
|
|
|
|
for (m = mons; m && m->next != mon; m = m->next);
|
|
|
|
m->next = mon->next;
|
|
|
|
}
|
2020-07-18 16:58:39 +00:00
|
|
|
for (bar = mon->bar; bar; bar = mon->bar) {
|
2020-09-10 13:24:51 +00:00
|
|
|
if (!bar->external) {
|
2020-09-10 11:32:28 +00:00
|
|
|
XUnmapWindow(dpy, bar->win);
|
|
|
|
XDestroyWindow(dpy, bar->win);
|
|
|
|
}
|
2020-07-18 16:58:39 +00:00
|
|
|
mon->bar = bar->next;
|
2020-11-06 18:46:42 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2020-11-05 11:08:18 +00:00
|
|
|
if (systray && bar == systray->bar)
|
|
|
|
systray->bar = NULL;
|
2020-11-06 18:46:42 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2020-07-18 16:58:39 +00:00
|
|
|
free(bar);
|
2020-07-07 16:25:00 +00:00
|
|
|
}
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
XUnmapWindow(dpy, mon->tabwin);
|
|
|
|
XDestroyWindow(dpy, mon->tabwin);
|
|
|
|
#endif // TAB_PATCH
|
2021-04-28 11:35:22 +00:00
|
|
|
#if PERTAG_PATCH
|
|
|
|
free(mon->pertag);
|
|
|
|
#endif // PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
free(mon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
clientmessage(XEvent *e)
|
|
|
|
{
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
XWindowAttributes wa;
|
|
|
|
XSetWindowAttributes swa;
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_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
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2020-09-07 10:07:51 +00:00
|
|
|
if (showsystray && systray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
|
2019-09-05 20:10:00 +00:00
|
|
|
/* add systray icons */
|
|
|
|
if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
|
|
|
|
if (!(c = (Client *)calloc(1, sizeof(Client))))
|
|
|
|
die("fatal: could not malloc() %u bytes\n", sizeof(Client));
|
|
|
|
if (!(c->win = cme->data.l[2])) {
|
|
|
|
free(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
c->mon = selmon;
|
|
|
|
c->next = systray->icons;
|
|
|
|
systray->icons = c;
|
|
|
|
XGetWindowAttributes(dpy, c->win, &wa);
|
|
|
|
c->x = c->oldx = c->y = c->oldy = 0;
|
|
|
|
c->w = c->oldw = wa.width;
|
|
|
|
c->h = c->oldh = wa.height;
|
|
|
|
c->oldbw = wa.border_width;
|
|
|
|
c->bw = 0;
|
|
|
|
c->isfloating = True;
|
|
|
|
/* reuse tags field as mapped status */
|
|
|
|
c->tags = 1;
|
|
|
|
updatesizehints(c);
|
|
|
|
updatesystrayicongeom(c, wa.width, wa.height);
|
|
|
|
XAddToSaveSet(dpy, c->win);
|
|
|
|
XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
|
2020-07-31 08:31:20 +00:00
|
|
|
XClassHint ch = {"dwmsystray", "dwmsystray"};
|
|
|
|
XSetClassHint(dpy, c->win, &ch);
|
2019-09-05 20:10:00 +00:00
|
|
|
XReparentWindow(dpy, c->win, systray->win, 0, 0);
|
|
|
|
/* use parents background color */
|
2020-07-21 09:35:26 +00:00
|
|
|
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
2019-09-05 20:10:00 +00:00
|
|
|
XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
|
|
|
|
sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
|
|
|
|
XSync(dpy, False);
|
|
|
|
setclientstate(c, NormalState);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
|
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]) {
|
2021-05-13 12:25:26 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2020-09-13 11:35:15 +00:00
|
|
|
if (c->fakefullscreen == 2 && c->isfullscreen)
|
|
|
|
c->fakefullscreen = 3;
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
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-09-11 09:49:21 +00:00
|
|
|
}
|
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
|
2020-11-22 11:52:02 +00:00
|
|
|
if (c->tags & c->mon->tagset[c->mon->seltags])
|
2019-09-06 22:03:04 +00:00
|
|
|
focus(c);
|
2020-11-22 11:52:02 +00:00
|
|
|
else {
|
2020-08-25 14:27:14 +00:00
|
|
|
for (i = 0; i < NUMTAGS && !((1 << i) & c->tags); i++);
|
|
|
|
if (i < NUMTAGS) {
|
2020-11-22 11:52:02 +00:00
|
|
|
if (c != selmon->sel)
|
|
|
|
unfocus(selmon->sel, 0, NULL);
|
2020-07-02 08:09:24 +00:00
|
|
|
selmon = c->mon;
|
2020-09-05 07:11:12 +00:00
|
|
|
if (((1 << i) & TAGMASK) != selmon->tagset[selmon->seltags])
|
|
|
|
view(&((Arg) { .ui = 1 << i }));
|
2020-07-02 08:09:24 +00:00
|
|
|
focus(c);
|
|
|
|
restack(selmon);
|
|
|
|
}
|
2019-09-06 22:03:04 +00:00
|
|
|
}
|
|
|
|
#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;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
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) {
|
2020-11-05 11:08:18 +00:00
|
|
|
drw_resize(drw, sw, sh);
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2020-09-05 12:20:53 +00:00
|
|
|
if (c->isfullscreen && c->fakefullscreen != 1)
|
2019-11-21 11:15:16 +00:00
|
|
|
#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-07-18 16:58:39 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next)
|
|
|
|
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
focus(NULL);
|
|
|
|
arrange(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
configurerequest(XEvent *e)
|
|
|
|
{
|
|
|
|
Client *c;
|
|
|
|
Monitor *m;
|
2020-09-10 13:24:51 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
Bar *bar;
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XConfigureRequestEvent *ev = &e->xconfigurerequest;
|
|
|
|
XWindowChanges wc;
|
2020-09-13 12:35:30 +00:00
|
|
|
|
2020-09-14 08:08:47 +00:00
|
|
|
if (ignoreconfigurerequests)
|
2020-09-13 12:35:30 +00:00
|
|
|
return;
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-08-10 15:09:20 +00:00
|
|
|
#if STEAM_PATCH
|
|
|
|
if (!c->issteam) {
|
|
|
|
if (ev->value_mask & CWX) {
|
|
|
|
c->oldx = c->x;
|
|
|
|
c->x = m->mx + ev->x;
|
|
|
|
}
|
|
|
|
if (ev->value_mask & CWY) {
|
|
|
|
c->oldy = c->y;
|
|
|
|
c->y = m->my + ev->y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
|
|
|
}
|
2020-08-10 15:09:20 +00:00
|
|
|
#endif // STEAM_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
2020-09-13 12:22:31 +00:00
|
|
|
c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-09-10 13:24:51 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
m = wintomon(ev->window);
|
|
|
|
for (bar = m->bar; bar; bar = bar->next) {
|
|
|
|
if (bar->win == ev->window) {
|
|
|
|
wc.y = bar->by;
|
|
|
|
wc.x = bar->bx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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)
|
|
|
|
{
|
2020-07-19 03:01:38 +00:00
|
|
|
Monitor *m, *mon;
|
2020-08-23 16:18:05 +00:00
|
|
|
int i, n, mi, max_bars = 2, istopbar = topbar;
|
|
|
|
#if MONITOR_RULES_PATCH
|
|
|
|
int layout;
|
|
|
|
#endif // MONITOR_RULES_PATCH
|
2020-07-18 16:58:39 +00:00
|
|
|
|
|
|
|
const BarRule *br;
|
|
|
|
Bar *bar;
|
2019-09-11 06:28:00 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
2020-07-18 16:58:39 +00:00
|
|
|
int j;
|
2019-09-11 06:28:00 +00:00
|
|
|
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;
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
m->showtab = showtab;
|
|
|
|
m->toptab = toptab;
|
|
|
|
m->ntabs = 0;
|
|
|
|
#endif // TAB_PATCH
|
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
|
2020-07-18 11:03:30 +00:00
|
|
|
for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index
|
2022-04-17 08:33:26 +00:00
|
|
|
m->num = mi;
|
2019-09-11 06:28:00 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
for (j = 0; j < LENGTH(monrules); j++) {
|
|
|
|
mr = &monrules[j];
|
2022-04-17 08:33:26 +00:00
|
|
|
if ((mr->monitor == -1 || mr->monitor == m->num)
|
2019-09-30 21:52:51 +00:00
|
|
|
#if PERTAG_PATCH
|
2020-07-27 08:45:13 +00:00
|
|
|
&& (mr->tag <= 0 || (m->tagset[0] & (1 << (mr->tag - 1))))
|
2019-09-30 21:52:51 +00:00
|
|
|
#endif // PERTAG_PATCH
|
|
|
|
) {
|
2020-07-27 08:45:13 +00:00
|
|
|
layout = MAX(mr->layout, 0);
|
|
|
|
layout = MIN(layout, LENGTH(layouts) - 1);
|
|
|
|
m->lt[0] = &layouts[layout];
|
2019-09-11 06:28:00 +00:00
|
|
|
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
2020-07-27 08:45:13 +00:00
|
|
|
strncpy(m->ltsymbol, layouts[layout].symbol, sizeof m->ltsymbol);
|
2020-04-26 14:26:36 +00:00
|
|
|
|
|
|
|
if (mr->mfact > -1)
|
|
|
|
m->mfact = mr->mfact;
|
|
|
|
if (mr->nmaster > -1)
|
|
|
|
m->nmaster = mr->nmaster;
|
|
|
|
if (mr->showbar > -1)
|
|
|
|
m->showbar = mr->showbar;
|
|
|
|
if (mr->topbar > -1)
|
2020-07-18 16:58:39 +00:00
|
|
|
istopbar = mr->topbar;
|
2019-09-11 06:28:00 +00:00
|
|
|
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
|
|
|
|
2020-07-18 16:58:39 +00:00
|
|
|
/* Derive the number of bars for this monitor based on bar rules */
|
|
|
|
for (n = -1, i = 0; i < LENGTH(barrules); i++) {
|
|
|
|
br = &barrules[i];
|
2022-04-17 08:33:26 +00:00
|
|
|
if (br->monitor == 'A' || br->monitor == -1 || br->monitor == m->num)
|
2020-07-18 16:58:39 +00:00
|
|
|
n = MAX(br->bar, n);
|
|
|
|
}
|
|
|
|
|
2021-04-27 11:31:41 +00:00
|
|
|
m->bar = NULL;
|
2020-07-18 16:58:39 +00:00
|
|
|
for (i = 0; i <= n && i < max_bars; i++) {
|
|
|
|
bar = ecalloc(1, sizeof(Bar));
|
|
|
|
bar->mon = m;
|
|
|
|
bar->idx = i;
|
|
|
|
bar->next = m->bar;
|
|
|
|
bar->topbar = istopbar;
|
|
|
|
m->bar = bar;
|
|
|
|
istopbar = !istopbar;
|
2020-08-22 06:43:07 +00:00
|
|
|
bar->showbar = 1;
|
2020-09-10 13:24:51 +00:00
|
|
|
bar->external = 0;
|
2020-09-09 15:24:02 +00:00
|
|
|
#if BAR_BORDER_PATCH
|
|
|
|
bar->borderpx = borderpx;
|
|
|
|
#else
|
|
|
|
bar->borderpx = 0;
|
|
|
|
#endif // BAR_BORDER_PATCH
|
2020-09-10 13:24:51 +00:00
|
|
|
bar->bh = bh + bar->borderpx * 2;
|
2020-09-09 15:24:02 +00:00
|
|
|
bar->borderscheme = SchemeNorm;
|
2020-07-18 16:58:39 +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;
|
2020-08-25 14:27:14 +00:00
|
|
|
for (i = 0; i <= NUMTAGS; i++) {
|
2019-09-30 21:52:51 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
m->pertag->nstacks[i] = m->nstack;
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
|
2020-04-26 14:26:36 +00:00
|
|
|
#if !MONITOR_RULES_PATCH
|
|
|
|
/* init nmaster */
|
|
|
|
m->pertag->nmasters[i] = m->nmaster;
|
|
|
|
|
2019-09-05 20:58:16 +00:00
|
|
|
/* init mfacts */
|
|
|
|
m->pertag->mfacts[i] = m->mfact;
|
|
|
|
|
2020-04-26 14:26:36 +00:00
|
|
|
#if PERTAGBAR_PATCH
|
|
|
|
/* init showbar */
|
|
|
|
m->pertag->showbars[i] = m->showbar;
|
|
|
|
#endif // PERTAGBAR_PATCH
|
|
|
|
#endif // MONITOR_RULES_PATCH
|
|
|
|
|
|
|
|
#if ZOOMSWAP_PATCH
|
|
|
|
m->pertag->prevzooms[i] = NULL;
|
|
|
|
#endif // ZOOMSWAP_PATCH
|
|
|
|
|
2019-09-05 20:58:16 +00:00
|
|
|
/* init layouts */
|
2019-09-30 21:52:51 +00:00
|
|
|
#if MONITOR_RULES_PATCH
|
|
|
|
for (j = 0; j < LENGTH(monrules); j++) {
|
|
|
|
mr = &monrules[j];
|
2022-04-17 08:33:26 +00:00
|
|
|
if ((mr->monitor == -1 || mr->monitor == m->num) && (mr->tag == -1 || mr->tag == i)) {
|
2020-07-27 08:45:13 +00:00
|
|
|
layout = MAX(mr->layout, 0);
|
|
|
|
layout = MIN(layout, LENGTH(layouts) - 1);
|
|
|
|
m->pertag->ltidxs[i][0] = &layouts[layout];
|
2019-09-30 21:52:51 +00:00
|
|
|
m->pertag->ltidxs[i][1] = m->lt[0];
|
2020-04-26 14:26:36 +00:00
|
|
|
m->pertag->nmasters[i] = (mr->nmaster > -1 ? mr->nmaster : m->nmaster);
|
|
|
|
m->pertag->mfacts[i] = (mr->mfact > -1 ? mr->mfact : m->mfact);
|
|
|
|
#if PERTAGBAR_PATCH
|
|
|
|
m->pertag->showbars[i] = (mr->showbar > -1 ? mr->showbar : m->showbar);
|
|
|
|
#endif // PERTAGBAR_PATCH
|
2019-09-30 21:52:51 +00:00
|
|
|
#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
|
|
|
|
2021-05-19 15:41:25 +00:00
|
|
|
#if PERTAG_VANITYGAPS_PATCH && VANITYGAPS_PATCH
|
2020-03-07 11:44:42 +00:00
|
|
|
m->pertag->enablegaps[i] = 1;
|
2021-04-05 06:14:27 +00:00
|
|
|
m->pertag->gaps[i] =
|
|
|
|
((gappoh & 0xFF) << 0) | ((gappov & 0xFF) << 8) | ((gappih & 0xFF) << 16) | ((gappiv & 0xFF) << 24);
|
2021-05-19 15:41:25 +00:00
|
|
|
#endif // PERTAG_VANITYGAPS_PATCH | VANITYGAPS_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
}
|
|
|
|
#endif // PERTAG_PATCH
|
2020-08-10 10:32:58 +00:00
|
|
|
#if INSETS_PATCH
|
|
|
|
m->inset = default_inset;
|
|
|
|
#endif // INSETS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
destroynotify(XEvent *e)
|
|
|
|
{
|
|
|
|
Client *c;
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
Monitor *m;
|
|
|
|
Bar *bar;
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
else if (showsystray && (c = wintosystrayicon(ev->window))) {
|
|
|
|
removesystrayicon(c);
|
2020-07-18 11:03:30 +00:00
|
|
|
drawbarwin(systray->bar);
|
2019-09-05 20:10:00 +00:00
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
else {
|
|
|
|
m = wintomon(ev->window);
|
|
|
|
for (bar = m->bar; bar; bar = bar->next) {
|
|
|
|
if (bar->win == ev->window) {
|
|
|
|
unmanagealtbar(ev->window);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // BAR_ANYBAR_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-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2022-01-10 16:16:09 +00:00
|
|
|
|
2022-03-14 08:39:19 +00:00
|
|
|
#if !BAR_FLEXWINTITLE_PATCH
|
2022-01-10 16:16:09 +00:00
|
|
|
if (m->showbar)
|
2022-03-14 08:39:19 +00:00
|
|
|
#endif // BAR_FLEXWINTITLE_PATCH
|
2022-01-10 16:16:09 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next)
|
|
|
|
drawbarwin(bar);
|
2020-07-18 11:03:30 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
|
2020-07-18 11:03:30 +00:00
|
|
|
void
|
|
|
|
drawbars(void)
|
|
|
|
{
|
|
|
|
Monitor *m;
|
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
drawbar(m);
|
|
|
|
}
|
2019-09-05 20:10:00 +00:00
|
|
|
|
2020-07-18 11:03:30 +00:00
|
|
|
void
|
|
|
|
drawbarwin(Bar *bar)
|
|
|
|
{
|
2020-11-05 11:08:18 +00:00
|
|
|
if (!bar || !bar->win || bar->external)
|
2020-07-18 11:03:30 +00:00
|
|
|
return;
|
2020-08-25 14:27:14 +00:00
|
|
|
int r, w, total_drawn = 0;
|
2020-07-15 06:57:30 +00:00
|
|
|
int rx, lx, rw, lw; // bar size, split between left and right if a center module is added
|
|
|
|
const BarRule *br;
|
|
|
|
|
2020-09-09 15:24:02 +00:00
|
|
|
if (bar->borderpx) {
|
|
|
|
XSetForeground(drw->dpy, drw->gc, scheme[bar->borderscheme][ColBorder].pixel);
|
|
|
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, 0, 0, bar->bw, bar->bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
BarArg warg = { 0 };
|
|
|
|
BarArg darg = { 0 };
|
|
|
|
warg.h = bar->bh - 2 * bar->borderpx;
|
|
|
|
|
|
|
|
rw = lw = bar->bw - 2 * bar->borderpx;
|
|
|
|
rx = lx = bar->borderpx;
|
2019-09-05 20:10:00 +00:00
|
|
|
|
2020-06-24 14:36:51 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-09-09 15:24:02 +00:00
|
|
|
drw_rect(drw, lx, bar->borderpx, lw, bar->bh - 2 * bar->borderpx, 1, 1);
|
2020-07-18 11:03:30 +00:00
|
|
|
for (r = 0; r < LENGTH(barrules); r++) {
|
|
|
|
br = &barrules[r];
|
2020-09-10 09:57:01 +00:00
|
|
|
if (br->bar != bar->idx || !br->widthfunc || (br->monitor == 'A' && bar->mon != selmon))
|
2020-07-18 11:03:30 +00:00
|
|
|
continue;
|
2022-04-17 08:33:26 +00:00
|
|
|
if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
|
2020-07-18 11:03:30 +00:00
|
|
|
continue;
|
2019-09-04 22:16:39 +00:00
|
|
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
2020-09-09 15:24:02 +00:00
|
|
|
warg.w = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw);
|
|
|
|
|
2020-07-18 11:03:30 +00:00
|
|
|
w = br->widthfunc(bar, &warg);
|
2020-09-09 15:24:02 +00:00
|
|
|
w = MIN(warg.w, w);
|
2020-07-18 11:03:30 +00:00
|
|
|
|
2020-07-18 16:58:39 +00:00
|
|
|
if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa
|
2020-07-18 11:03:30 +00:00
|
|
|
lw = rw;
|
|
|
|
lx = rx;
|
|
|
|
} else if (rw <= 0) {
|
|
|
|
rw = lw;
|
|
|
|
rx = lx;
|
|
|
|
}
|
2019-09-13 21:56:05 +00:00
|
|
|
|
2020-07-18 11:03:30 +00:00
|
|
|
switch(br->alignment) {
|
|
|
|
default:
|
|
|
|
case BAR_ALIGN_NONE:
|
|
|
|
case BAR_ALIGN_LEFT_LEFT:
|
|
|
|
case BAR_ALIGN_LEFT:
|
|
|
|
bar->x[r] = lx;
|
|
|
|
if (lx == rx) {
|
2020-07-15 06:57:30 +00:00
|
|
|
rx += w;
|
|
|
|
rw -= w;
|
2019-09-09 22:18:46 +00:00
|
|
|
}
|
2020-07-18 11:03:30 +00:00
|
|
|
lx += w;
|
|
|
|
lw -= w;
|
|
|
|
break;
|
|
|
|
case BAR_ALIGN_LEFT_RIGHT:
|
|
|
|
case BAR_ALIGN_RIGHT:
|
|
|
|
bar->x[r] = lx + lw - w;
|
|
|
|
if (lx == rx)
|
2020-07-15 06:57:30 +00:00
|
|
|
rw -= w;
|
2020-07-18 11:03:30 +00:00
|
|
|
lw -= w;
|
|
|
|
break;
|
|
|
|
case BAR_ALIGN_LEFT_CENTER:
|
|
|
|
case BAR_ALIGN_CENTER:
|
|
|
|
bar->x[r] = lx + lw / 2 - w / 2;
|
|
|
|
if (lx == rx) {
|
|
|
|
rw = rx + rw - bar->x[r] - w;
|
|
|
|
rx = bar->x[r] + w;
|
2019-09-06 21:47:06 +00:00
|
|
|
}
|
2020-07-18 11:03:30 +00:00
|
|
|
lw = bar->x[r] - lx;
|
|
|
|
break;
|
|
|
|
case BAR_ALIGN_RIGHT_LEFT:
|
|
|
|
bar->x[r] = rx;
|
|
|
|
if (lx == rx) {
|
|
|
|
lx += w;
|
|
|
|
lw -= w;
|
2019-09-06 21:47:06 +00:00
|
|
|
}
|
2020-07-18 11:03:30 +00:00
|
|
|
rx += w;
|
|
|
|
rw -= w;
|
|
|
|
break;
|
|
|
|
case BAR_ALIGN_RIGHT_RIGHT:
|
|
|
|
bar->x[r] = rx + rw - w;
|
|
|
|
if (lx == rx)
|
|
|
|
lw -= w;
|
|
|
|
rw -= w;
|
|
|
|
break;
|
|
|
|
case BAR_ALIGN_RIGHT_CENTER:
|
|
|
|
bar->x[r] = rx + rw / 2 - w / 2;
|
|
|
|
if (lx == rx) {
|
|
|
|
lw = lx + lw - bar->x[r] + w;
|
|
|
|
lx = bar->x[r] + w;
|
|
|
|
}
|
|
|
|
rw = bar->x[r] - rx;
|
|
|
|
break;
|
2020-01-30 07:43:00 +00:00
|
|
|
}
|
2020-07-18 11:03:30 +00:00
|
|
|
bar->w[r] = w;
|
|
|
|
darg.x = bar->x[r];
|
2020-09-09 15:24:02 +00:00
|
|
|
darg.y = bar->borderpx;
|
|
|
|
darg.h = bar->bh - 2 * bar->borderpx;
|
2020-07-18 11:03:30 +00:00
|
|
|
darg.w = bar->w[r];
|
2020-09-09 15:24:02 +00:00
|
|
|
if (br->drawfunc)
|
|
|
|
total_drawn += br->drawfunc(bar, &darg);
|
2020-08-22 06:43:07 +00:00
|
|
|
}
|
2020-09-09 15:24:02 +00:00
|
|
|
|
2020-08-22 06:43:07 +00:00
|
|
|
if (total_drawn == 0 && bar->showbar) {
|
|
|
|
bar->showbar = 0;
|
|
|
|
updatebarpos(bar->mon);
|
|
|
|
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
|
|
|
arrange(bar->mon);
|
2019-10-24 05:35:00 +00:00
|
|
|
}
|
2020-08-22 06:43:07 +00:00
|
|
|
else if (total_drawn > 0 && !bar->showbar) {
|
|
|
|
bar->showbar = 1;
|
|
|
|
updatebarpos(bar->mon);
|
|
|
|
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
|
|
|
drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
|
|
|
|
arrange(bar->mon);
|
|
|
|
} else
|
|
|
|
drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
|
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;
|
2020-08-20 13:31:09 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
Client *sel;
|
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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) {
|
2020-08-20 13:31:09 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
sel = selmon->sel;
|
|
|
|
selmon = m;
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(sel, 1, c);
|
2020-08-20 13:31:09 +00:00
|
|
|
#else
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(selmon->sel, 1, c);
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon = m;
|
2020-08-20 13:31:09 +00:00
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} 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;
|
|
|
|
|
2021-03-09 12:23:39 +00:00
|
|
|
if (ev->count == 0 && (m = wintomon(ev->window))) {
|
2019-09-04 22:16:39 +00:00
|
|
|
drawbar(m);
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
drawtabs();
|
|
|
|
#endif // TAB_PATCH
|
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
focus(Client *c)
|
|
|
|
{
|
|
|
|
if (!c || !ISVISIBLE(c))
|
|
|
|
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
|
|
|
|
if (selmon->sel && selmon->sel != c)
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(selmon->sel, 0, c);
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c) {
|
|
|
|
if (c->mon != selmon)
|
|
|
|
selmon = c->mon;
|
|
|
|
if (c->isurgent)
|
|
|
|
seturgent(c, 0);
|
|
|
|
detachstack(c);
|
|
|
|
attachstack(c);
|
|
|
|
grabbuttons(c, 1);
|
2020-08-27 19:37:19 +00:00
|
|
|
#if !BAR_FLEXWINTITLE_PATCH
|
2019-09-10 22:51:37 +00:00
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
2020-08-27 19:37:19 +00:00
|
|
|
#endif // BAR_FLEXWINTITLE_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();
|
2020-09-29 13:24:44 +00:00
|
|
|
|
|
|
|
#if ON_EMPTY_KEYS_PATCH
|
2020-09-29 13:49:51 +00:00
|
|
|
if ((isempty && selmon->sel) || (!isempty && !selmon->sel)) {
|
|
|
|
isempty = !isempty;
|
2020-09-29 13:24:44 +00:00
|
|
|
grabkeys();
|
|
|
|
}
|
|
|
|
#endif // ON_EMPTY_KEYS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
2020-08-20 13:31:09 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
Client *sel;
|
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
if (!mons->next)
|
|
|
|
return;
|
|
|
|
if ((m = dirtomon(arg->i)) == selmon)
|
|
|
|
return;
|
2020-08-20 13:31:09 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
sel = selmon->sel;
|
|
|
|
selmon = m;
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(sel, 0, NULL);
|
2020-08-20 13:31:09 +00:00
|
|
|
#else
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(selmon->sel, 0, NULL);
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon = m;
|
2020-08-20 13:31:09 +00:00
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
|
|
|
|
2021-03-29 17:33:05 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!selmon->sel)
|
|
|
|
return;
|
2021-05-13 12:25:26 +00:00
|
|
|
#elif FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2021-04-29 07:05:32 +00:00
|
|
|
if (!selmon->sel || (selmon->sel->isfullscreen && !selmon->sel->fakefullscreen))
|
|
|
|
return;
|
2021-03-29 17:33:05 +00:00
|
|
|
#else
|
2022-01-10 16:18:45 +00:00
|
|
|
if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
|
2020-01-30 07:43:00 +00:00
|
|
|
return;
|
2021-03-29 17:33:05 +00:00
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2020-08-13 13:42:49 +00:00
|
|
|
#if BAR_WINTITLEACTIONS_PATCH
|
2020-08-01 14:58:43 +00:00
|
|
|
if (arg->i > 0) {
|
|
|
|
for (c = selmon->sel->next; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next);
|
|
|
|
if (!c)
|
|
|
|
for (c = selmon->clients; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next);
|
|
|
|
} else {
|
|
|
|
for (i = selmon->clients; i != selmon->sel; i = i->next)
|
|
|
|
if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i)))
|
|
|
|
c = i;
|
|
|
|
if (!c)
|
|
|
|
for (; i; i = i->next)
|
|
|
|
if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i)))
|
|
|
|
c = i;
|
|
|
|
}
|
|
|
|
#else
|
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;
|
|
|
|
}
|
2020-08-13 13:42:49 +00:00
|
|
|
#endif // BAR_WINTITLEACTIONS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_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++)
|
2020-09-18 08:53:07 +00:00
|
|
|
if (buttons[i].click == ClkClientWin
|
|
|
|
#if NO_MOD_BUTTONS_PATCH
|
|
|
|
&& (nomodbuttons || buttons[i].mask != 0)
|
|
|
|
#endif // NO_MOD_BUTTONS_PATCH
|
|
|
|
)
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2020-05-31 13:14:29 +00:00
|
|
|
#if KEYMODES_PATCH
|
|
|
|
grabdefkeys(void)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
grabkeys(void)
|
2020-05-31 13:14:29 +00:00
|
|
|
#endif // KEYMODES_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
|
|
|
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);
|
2020-09-29 13:24:44 +00:00
|
|
|
#if ON_EMPTY_KEYS_PATCH
|
|
|
|
if (!selmon->sel)
|
|
|
|
for (i = 0; i < LENGTH(on_empty_keys); i++)
|
|
|
|
if ((code = XKeysymToKeycode(dpy, on_empty_keys[i].keysym)))
|
|
|
|
for (j = 0; j < LENGTH(modifiers); j++)
|
|
|
|
XGrabKey(dpy, code, on_empty_keys[i].mod | modifiers[j], root,
|
|
|
|
True, GrabModeAsync, GrabModeAsync);
|
|
|
|
#endif // ON_EMPTY_KEYS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-05-31 13:14:29 +00:00
|
|
|
#if KEYMODES_PATCH
|
|
|
|
keydefpress(XEvent *e)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
keypress(XEvent *e)
|
2020-05-31 13:14:29 +00:00
|
|
|
#endif // KEYMODES_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2020-09-18 08:39:07 +00:00
|
|
|
int keysyms_return;
|
|
|
|
KeySym* keysym;
|
2019-09-04 22:16:39 +00:00
|
|
|
XKeyEvent *ev;
|
|
|
|
|
|
|
|
ev = &e->xkey;
|
2020-09-18 08:39:07 +00:00
|
|
|
keysym = XGetKeyboardMapping(dpy, (KeyCode)ev->keycode, 1, &keysyms_return);
|
2019-09-04 22:16:39 +00:00
|
|
|
for (i = 0; i < LENGTH(keys); i++)
|
2020-09-18 08:39:07 +00:00
|
|
|
if (*keysym == keys[i].keysym
|
|
|
|
&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
|
|
|
|
&& keys[i].func)
|
2019-09-04 22:16:39 +00:00
|
|
|
keys[i].func(&(keys[i].arg));
|
2020-09-29 13:24:44 +00:00
|
|
|
#if ON_EMPTY_KEYS_PATCH
|
|
|
|
if (!selmon->sel)
|
|
|
|
for (i = 0; i < LENGTH(on_empty_keys); i++)
|
|
|
|
if (*keysym == on_empty_keys[i].keysym
|
|
|
|
&& CLEANMASK(on_empty_keys[i].mod) == CLEANMASK(ev->state)
|
|
|
|
&& on_empty_keys[i].func)
|
|
|
|
on_empty_keys[i].func(&(on_empty_keys[i].arg));
|
|
|
|
#endif // ON_EMPTY_KEYS_PATCH
|
2020-09-18 08:39:07 +00:00
|
|
|
XFree(keysym);
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2020-10-06 06:45:17 +00:00
|
|
|
if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0))
|
2019-09-05 20:10:00 +00:00
|
|
|
#else
|
2020-10-06 06:45:17 +00:00
|
|
|
if (!sendevent(selmon->sel, wmatom[WMDelete]))
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2020-10-06 06:45:17 +00:00
|
|
|
{
|
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-10-06 06:45:17 +00:00
|
|
|
#if WARP_PATCH
|
|
|
|
force_warp = 1;
|
|
|
|
#endif // WARP_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] = 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
|
2021-07-27 11:40:53 +00:00
|
|
|
#if BAR_WINICON_PATCH
|
|
|
|
updateicon(c);
|
|
|
|
#endif // BAR_WINICON_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
updatetitle(c);
|
2021-04-07 13:35:56 +00:00
|
|
|
|
|
|
|
#if XKB_PATCH
|
|
|
|
/* Setting current xkb state must be before applyrules */
|
|
|
|
if (!(c->xkb = findxkb(c->win)))
|
|
|
|
c->xkb = createxkb(c->win);
|
|
|
|
#endif // XKB_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
|
|
|
|
c->mon = t->mon;
|
|
|
|
c->tags = t->tags;
|
2020-06-23 09:55:55 +00:00
|
|
|
#if SETBORDERPX_PATCH
|
|
|
|
c->bw = c->mon->borderpx;
|
|
|
|
#else
|
|
|
|
c->bw = borderpx;
|
|
|
|
#endif // SETBORDERPX_PATCH
|
2020-07-04 19:40:29 +00:00
|
|
|
#if CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH
|
|
|
|
c->x = t->x + WIDTH(t) / 2 - WIDTH(c) / 2;
|
|
|
|
c->y = t->y + HEIGHT(t) / 2 - HEIGHT(c) / 2;
|
2020-09-29 11:26:05 +00:00
|
|
|
#elif CENTER_PATCH && CENTER_TRANSIENT_WINDOWS_PATCH
|
|
|
|
c->iscentered = 1;
|
2020-07-04 19:40:29 +00:00
|
|
|
#elif CENTER_TRANSIENT_WINDOWS_PATCH
|
|
|
|
c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
|
|
|
|
c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
|
2020-09-29 13:28:57 +00:00
|
|
|
#elif CENTER_PATCH
|
|
|
|
if (c->x == c->mon->wx && c->y == c->mon->wy)
|
|
|
|
c->iscentered = 1;
|
|
|
|
#endif // CENTER_TRANSIENT_WINDOWS_PATCH | CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH | CENTER_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
} else {
|
|
|
|
c->mon = selmon;
|
2020-09-29 13:24:44 +00:00
|
|
|
#if CENTER_PATCH
|
|
|
|
if (c->x == c->mon->wx && c->y == c->mon->wy)
|
|
|
|
c->iscentered = 1;
|
|
|
|
#endif // CENTER_PATCH
|
2020-06-21 13:33:29 +00:00
|
|
|
#if SETBORDERPX_PATCH
|
|
|
|
c->bw = c->mon->borderpx;
|
|
|
|
#else
|
|
|
|
c->bw = borderpx;
|
|
|
|
#endif // SETBORDERPX_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
applyrules(c);
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
term = termforwin(c);
|
2020-09-11 09:47:57 +00:00
|
|
|
if (term)
|
|
|
|
c->mon = term->mon;
|
2019-10-22 17:08:00 +00:00
|
|
|
#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 */
|
2021-04-27 11:31:41 +00:00
|
|
|
c->y = MAX(c->y, ((!c->mon->bar || c->mon->bar->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
|
2019-09-04 22:16:39 +00:00
|
|
|
&& (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
|
|
|
|
|
|
|
|
wc.border_width = c->bw;
|
|
|
|
XConfigureWindow(dpy, w, CWBorderWidth, &wc);
|
2020-08-27 19:37:19 +00:00
|
|
|
#if !BAR_FLEXWINTITLE_PATCH
|
2019-09-10 22:51:37 +00:00
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
|
2020-08-27 19:37:19 +00:00
|
|
|
#endif // BAR_FLEXWINTITLE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
configure(c); /* propagates border_width, if size doesn't change */
|
2022-04-26 15:25:20 +00:00
|
|
|
updatesizehints(c);
|
2020-06-15 11:24:23 +00:00
|
|
|
if (getatomprop(c, netatom[NetWMState]) == netatom[NetWMFullscreen])
|
|
|
|
setfullscreen(c, 1);
|
2019-09-04 22:16:39 +00:00
|
|
|
updatewmhints(c);
|
2020-08-11 08:17:02 +00:00
|
|
|
#if DECORATION_HINTS_PATCH
|
|
|
|
updatemotifhints(c);
|
|
|
|
#endif // DECORATION_HINTS_PATCH
|
2021-09-08 15:20:40 +00:00
|
|
|
|
2021-09-09 06:50:17 +00:00
|
|
|
#if CENTER_PATCH && SAVEFLOATS_PATCH || CENTER_PATCH && EXRESIZE_PATCH
|
2021-09-08 15:20:40 +00:00
|
|
|
c->sfx = -9999;
|
|
|
|
c->sfy = -9999;
|
|
|
|
if (c->iscentered) {
|
|
|
|
c->sfx = c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
|
|
|
|
c->sfy = c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
|
|
|
|
}
|
|
|
|
#elif CENTER_PATCH
|
2019-09-07 22:23:30 +00:00
|
|
|
if (c->iscentered) {
|
2020-06-21 13:33:29 +00:00
|
|
|
c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
|
|
|
|
c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
|
2019-09-07 22:23:30 +00:00
|
|
|
}
|
2021-09-09 06:50:17 +00:00
|
|
|
#elif ALWAYSCENTER_PATCH && SAVEFLOATS_PATCH || ALWAYSCENTER_PATCH && EXRESIZE_PATCH
|
2021-09-08 15:20:40 +00:00
|
|
|
c->sfx = c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
|
|
|
|
c->sfy = c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
|
2021-09-08 07:42:47 +00:00
|
|
|
#elif ALWAYSCENTER_PATCH
|
2021-09-08 15:20:40 +00:00
|
|
|
c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
|
|
|
|
c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
|
|
|
|
#elif SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
c->sfx = -9999;
|
|
|
|
c->sfy = -9999;
|
2021-09-08 15:20:40 +00:00
|
|
|
#endif // CENTER_PATCH / ALWAYSCENTER_PATCH / SAVEFLOATS_PATCH
|
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2019-09-07 21:08:53 +00:00
|
|
|
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)
|
2022-04-26 15:22:11 +00:00
|
|
|
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
2020-08-21 13:49:15 +00:00
|
|
|
if (c->isfloating) {
|
2019-09-04 22:16:39 +00:00
|
|
|
XRaiseWindow(dpy, c->win);
|
2019-09-10 22:51:37 +00:00
|
|
|
XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
|
2020-08-21 13:49:15 +00:00
|
|
|
}
|
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);
|
2020-10-26 10:10:14 +00:00
|
|
|
#if NET_CLIENT_LIST_STACKING_PATCH
|
|
|
|
XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend,
|
|
|
|
(unsigned char *) &(c->win), 1);
|
|
|
|
#endif // NET_CLIENT_LIST_STACKING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
|
|
|
2020-08-13 13:42:49 +00:00
|
|
|
#if BAR_WINTITLEACTIONS_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
if (!HIDDEN(c))
|
|
|
|
setclientstate(c, NormalState);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
setclientstate(c, NormalState);
|
2020-08-13 13:42:49 +00:00
|
|
|
#endif // BAR_WINTITLEACTIONS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (c->mon == selmon)
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(selmon->sel, 0, c);
|
2019-09-04 22:16:39 +00:00
|
|
|
c->mon->sel = c;
|
2019-10-22 17:08:00 +00:00
|
|
|
#if SWALLOW_PATCH
|
2020-10-10 13:25:35 +00:00
|
|
|
if (!(term && swallow(term, c))) {
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
|
|
|
|
if (riodimensions[3] != -1)
|
|
|
|
rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
|
|
|
else {
|
|
|
|
killclient(&((Arg) { .v = c }));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // RIODRAW_PATCH
|
2020-09-11 15:33:15 +00:00
|
|
|
arrange(c->mon);
|
2020-10-10 13:25:35 +00:00
|
|
|
#if BAR_WINTITLEACTIONS_PATCH
|
|
|
|
if (!HIDDEN(c))
|
|
|
|
XMapWindow(dpy, c->win);
|
|
|
|
#else
|
|
|
|
XMapWindow(dpy, c->win);
|
|
|
|
#endif // BAR_WINTITLEACTIONS_PATCH
|
|
|
|
}
|
2020-09-11 15:33:15 +00:00
|
|
|
#else
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
if (riopid) {
|
|
|
|
if (riodimensions[3] != -1)
|
|
|
|
rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
|
|
|
|
else {
|
|
|
|
killclient(&((Arg) { .v = c }));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // RIODRAW_PATCH
|
2020-09-11 09:47:57 +00:00
|
|
|
arrange(c->mon);
|
2020-10-10 13:04:36 +00:00
|
|
|
#if BAR_WINTITLEACTIONS_PATCH
|
|
|
|
if (!HIDDEN(c))
|
|
|
|
XMapWindow(dpy, c->win);
|
|
|
|
#else
|
|
|
|
XMapWindow(dpy, c->win);
|
|
|
|
#endif // BAR_WINTITLEACTIONS_PATCH
|
2020-10-10 13:25:35 +00:00
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
2020-09-28 12:39:17 +00:00
|
|
|
|
|
|
|
#if BAR_EWMHTAGS_PATCH
|
|
|
|
setfloatinghint(c);
|
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
Client *i;
|
2020-09-07 10:43:37 +00:00
|
|
|
if (showsystray && systray && (i = wintosystrayicon(ev->window))) {
|
2019-09-05 20:10:00 +00:00
|
|
|
sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
|
2020-07-18 11:03:30 +00:00
|
|
|
drawbarwin(systray->bar);
|
2019-09-05 20:10:00 +00:00
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!XGetWindowAttributes(dpy, ev->window, &wa))
|
|
|
|
return;
|
|
|
|
if (wa.override_redirect)
|
|
|
|
return;
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
if (wmclasscontains(ev->window, altbarclass, ""))
|
|
|
|
managealtbar(ev->window, &wa);
|
|
|
|
else
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-08-20 13:31:09 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
Client *sel;
|
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XMotionEvent *ev = &e->xmotion;
|
|
|
|
|
|
|
|
if (ev->window != root)
|
|
|
|
return;
|
|
|
|
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
|
2020-08-20 13:31:09 +00:00
|
|
|
#if LOSEFULLSCREEN_PATCH
|
|
|
|
sel = selmon->sel;
|
|
|
|
selmon = m;
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(sel, 1, NULL);
|
2020-08-20 13:31:09 +00:00
|
|
|
#else
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(selmon->sel, 1, NULL);
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon = m;
|
2020-08-20 13:31:09 +00:00
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2021-05-13 12:25:26 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2020-09-05 12:20:53 +00:00
|
|
|
if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
|
2019-11-21 11:15:16 +00:00
|
|
|
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;
|
2020-09-14 08:08:47 +00:00
|
|
|
ignoreconfigurerequests = 1;
|
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;
|
|
|
|
|
|
|
|
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
|
2020-10-11 09:59:11 +00:00
|
|
|
&& (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) {
|
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
|
|
|
c->sfx = -9999; // disable savefloats when using movemouse
|
|
|
|
#endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
togglefloating(NULL);
|
2020-10-11 09:59:11 +00:00
|
|
|
}
|
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) {
|
2020-09-13 12:22:31 +00:00
|
|
|
#if SCRATCHPADS_PATCH
|
|
|
|
if (c->tags & SPTAGMASK) {
|
|
|
|
c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK);
|
|
|
|
m->tagset[m->seltags] |= (c->tags & SPTAGMASK);
|
|
|
|
}
|
|
|
|
#endif // SCRATCHPADS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2020-09-14 08:08:47 +00:00
|
|
|
ignoreconfigurerequests = 0;
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Client *
|
|
|
|
nexttiled(Client *c)
|
|
|
|
{
|
2020-08-13 13:42:49 +00:00
|
|
|
#if BAR_WINTITLEACTIONS_PATCH
|
2019-09-09 22:18:46 +00:00
|
|
|
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);
|
2020-08-13 13:42:49 +00:00
|
|
|
#endif // BAR_WINTITLEACTIONS_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;
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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);
|
2020-07-18 11:03:30 +00:00
|
|
|
drawbarwin(systray->bar);
|
2019-09-05 20:10:00 +00:00
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
|
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:
|
manage: propertynotify: Reduce cost of unused size hints
This patch defers all size hint calculations until they are actually
needed, drastically reducing the number of calls to updatesizehints(),
which can be expensive when called repeatedly (as it currently is during
resizes).
In my unscientific testing this reduces calls to updatesizehints() by
over 90% during a typical work session. There are no functional changes
for users other than an increase in responsiveness after resizes and
a reduction in CPU time.
In slower environments or X servers, this patch also offers an
improvement in responsiveness that is often tangible after resizing a
client that changes hints during resizes.
There are two main motivations to defer this work to the time of hint
application:
1. Some clients, especially terminals using incremental size hints,
resend XA_WM_NORMAL_HINTS events on resize to avoid fighting with the
WM or mouse resizing. For example, some terminals like urxvt clear
PBaseSize and PResizeInc during XResizeWindow and restore them
afterwards.
For this reason, after the resize is concluded, we typically receive
a backlogged XA_WM_NORMAL_HINTS message for each update period with
movement, which is useless. In some cases one may get hundreds or
thousands of XA_WM_NORMAL_HINTS messages on large resizes, and
currently all of these result in a separate updatesizehints() call,
of which all but the final one are immediately outdated.
(We can't just blindly discard these messages during resizes like we
do for EnterNotify, because some of them might actually be for other
windows, and may not be XA_WM_NORMAL_HINTS events.)
2. For users which use resizehints=0 most of these updates are unused
anyway -- in the normal case where the client is not floating these
values won't be used, so there's no need to calculate them up front.
A synthetic test using the mouse to resize a floating terminal window
from roughly 256x256 to 1024x1024 and back again shows that the number
of calls to updatesizehints() goes from over 500 before this patch (one
for each update interval with movement) to 2 after this patch (one for
each hint application), with no change in user visible behaviour.
This also reduces the delay before dwm is ready to process new events
again after a large resize on such a client, as it avoids the thundering
herd of updatesizehints() calls when hundreds of backlogged
XA_WM_NORMAL_HINTS messages appear at once after a resize is finished.
ref.
https://git.suckless.org/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.html#h0-0-4
2022-04-17 08:15:22 +00:00
|
|
|
c->hintsvalid = 0;
|
2019-09-04 22:16:39 +00:00
|
|
|
break;
|
|
|
|
case XA_WM_HINTS:
|
|
|
|
updatewmhints(c);
|
2019-10-06 22:46:23 +00:00
|
|
|
if (c->isurgent)
|
2020-07-18 11:03:30 +00:00
|
|
|
drawbars();
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
drawtabs();
|
|
|
|
#endif // TAB_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);
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
drawtab(c->mon);
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2020-08-11 08:17:02 +00:00
|
|
|
#if DECORATION_HINTS_PATCH
|
|
|
|
if (ev->atom == motifatom)
|
|
|
|
updatemotifhints(c);
|
|
|
|
#endif // DECORATION_HINTS_PATCH
|
2021-07-27 11:40:53 +00:00
|
|
|
#if BAR_WINICON_PATCH
|
|
|
|
else if (ev->atom == netatom[NetWMIcon]) {
|
|
|
|
updateicon(c);
|
|
|
|
if (c == c->mon->sel)
|
|
|
|
drawbar(c->mon);
|
|
|
|
}
|
|
|
|
#endif // BAR_WINICON_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
quit(const Arg *arg)
|
|
|
|
{
|
2020-08-10 08:22:21 +00:00
|
|
|
#if COOL_AUTOSTART_PATCH
|
|
|
|
size_t i;
|
|
|
|
#endif // COOL_AUTOSTART_PATCH
|
2021-10-31 12:45:18 +00:00
|
|
|
#if RESTARTSIG_PATCH
|
|
|
|
restart = arg->i;
|
|
|
|
#endif // RESTARTSIG_PATCH
|
2019-10-03 20:58:58 +00:00
|
|
|
#if ONLYQUITONEMPTY_PATCH
|
2021-10-31 12:45:18 +00:00
|
|
|
Monitor *m;
|
|
|
|
Client *c;
|
|
|
|
unsigned int n = 0;
|
2019-10-03 20:58:58 +00:00
|
|
|
|
2021-10-31 12:45:18 +00:00
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
for (c = m->clients; c; c = c->next, n++);
|
2019-10-03 20:58:58 +00:00
|
|
|
|
2021-11-11 08:21:58 +00:00
|
|
|
#if RESTARTSIG_PATCH
|
2021-10-31 12:45:18 +00:00
|
|
|
if (restart || n <= quit_empty_window_count)
|
2021-11-11 08:21:58 +00:00
|
|
|
#else
|
|
|
|
if (n <= quit_empty_window_count)
|
|
|
|
#endif // RESTARTSIG_PATCH
|
2019-10-03 20:58:58 +00:00
|
|
|
running = 0;
|
|
|
|
else
|
2021-10-31 12:45:18 +00:00
|
|
|
fprintf(stderr, "[dwm] not exiting (n=%d)\n", n);
|
2019-10-03 20:58:58 +00:00
|
|
|
|
2021-10-25 13:43:14 +00:00
|
|
|
#else // !ONLYQUITONEMPTY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
running = 0;
|
2019-10-03 20:58:58 +00:00
|
|
|
#endif // ONLYQUITONEMPTY_PATCH
|
2020-08-10 08:22:21 +00:00
|
|
|
|
|
|
|
#if COOL_AUTOSTART_PATCH
|
|
|
|
/* kill child processes */
|
2021-10-25 13:43:14 +00:00
|
|
|
for (i = 0; i < autostart_len && !running; i++) {
|
2020-08-10 08:22:21 +00:00
|
|
|
if (0 < autostart_pids[i]) {
|
|
|
|
kill(autostart_pids[i], SIGTERM);
|
|
|
|
waitpid(autostart_pids[i], NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // COOL_AUTOSTART_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
|
2020-09-16 09:00:31 +00:00
|
|
|
|| &monocle == c->mon->lt[c->mon->sellt]->arrange
|
|
|
|
#endif // MONOCLE_LAYOUT
|
2020-11-24 16:37:49 +00:00
|
|
|
#if DECK_LAYOUT
|
|
|
|
|| (&deck == c->mon->lt[c->mon->sellt]->arrange &&
|
|
|
|
c->mon->nmaster == 0)
|
|
|
|
#endif // DECK_LAYOUT
|
2020-11-20 13:48:57 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
2020-11-24 16:37:49 +00:00
|
|
|
|| (&flextile == c->mon->lt[c->mon->sellt]->arrange && (
|
|
|
|
(c->mon->ltaxis[LAYOUT] == NO_SPLIT &&
|
|
|
|
c->mon->ltaxis[MASTER] == MONOCLE) ||
|
|
|
|
(c->mon->ltaxis[STACK] == MONOCLE &&
|
|
|
|
c->mon->nmaster == 0)))
|
2020-11-20 13:48:57 +00:00
|
|
|
#endif //FLEXTILE_DELUXE_LAYOUT
|
2020-09-16 09:00:31 +00:00
|
|
|
)
|
2021-05-13 12:25:26 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
2020-09-16 09:00:31 +00:00
|
|
|
&& (c->fakefullscreen == 1 || !c->isfullscreen)
|
|
|
|
#else
|
|
|
|
&& !c->isfullscreen
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
&& !c->isfloating
|
|
|
|
&& c->mon->lt[c->mon->sellt]->arrange) {
|
2021-10-25 08:02:51 +00:00
|
|
|
c->w = wc.width += c->bw * 2;
|
|
|
|
c->h = wc.height += c->bw * 2;
|
2019-10-04 21:39:01 +00:00
|
|
|
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;
|
2020-06-25 09:56:41 +00:00
|
|
|
#if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
|
2020-06-24 12:49:30 +00:00
|
|
|
int opx, opy, och, ocw, nx, ny;
|
|
|
|
int horizcorner, vertcorner;
|
|
|
|
unsigned int dui;
|
|
|
|
Window dummy;
|
|
|
|
#endif // RESIZEPOINT_PATCH | 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
|
2020-09-05 12:20:53 +00:00
|
|
|
if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
|
2019-11-21 11:15:16 +00:00
|
|
|
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;
|
2020-06-24 12:49:30 +00:00
|
|
|
#if RESIZEPOINT_PATCH
|
|
|
|
och = c->h;
|
|
|
|
ocw = c->w;
|
|
|
|
#elif RESIZECORNERS_PATCH
|
2020-06-25 09:56:41 +00:00
|
|
|
och = c->y + c->h;
|
|
|
|
ocw = c->x + c->w;
|
2020-06-24 12:49:30 +00:00
|
|
|
#endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
|
2020-06-25 09:56:41 +00:00
|
|
|
#if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
|
2020-06-24 12:49:30 +00:00
|
|
|
if (!XQueryPointer(dpy, c->win, &dummy, &dummy, &opx, &opy, &nx, &ny, &dui))
|
|
|
|
return;
|
|
|
|
horizcorner = nx < c->w / 2;
|
|
|
|
vertcorner = ny < c->h / 2;
|
2020-06-25 09:56:41 +00:00
|
|
|
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
|
|
|
None, cursor[horizcorner | (vertcorner << 1)]->cursor, CurrentTime) != GrabSuccess)
|
2020-01-30 07:43:00 +00:00
|
|
|
return;
|
2020-06-25 09:56:41 +00:00
|
|
|
#if RESIZECORNERS_PATCH
|
2019-09-07 20:35:37 +00:00
|
|
|
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));
|
2020-06-25 09:56:41 +00:00
|
|
|
#endif // RESIZECORNERS_PATCH
|
2019-09-07 20:35:37 +00:00
|
|
|
#else
|
2020-06-25 09:56:41 +00:00
|
|
|
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
|
|
|
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
|
|
|
return;
|
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);
|
2020-06-24 12:49:30 +00:00
|
|
|
#endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
|
2020-09-14 08:08:47 +00:00
|
|
|
ignoreconfigurerequests = 1;
|
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;
|
|
|
|
|
2020-06-24 12:49:30 +00:00
|
|
|
#if RESIZEPOINT_PATCH
|
|
|
|
nx = horizcorner ? (ocx + ev.xmotion.x - opx) : c->x;
|
|
|
|
ny = vertcorner ? (ocy + ev.xmotion.y - opy) : c->y;
|
|
|
|
nw = MAX(horizcorner ? (ocx + ocw - nx) : (ocw + (ev.xmotion.x - opx)), 1);
|
|
|
|
nh = MAX(vertcorner ? (ocy + och - ny) : (och + (ev.xmotion.y - opy)), 1);
|
|
|
|
#elif RESIZECORNERS_PATCH
|
2019-09-07 20:35:37 +00:00
|
|
|
nx = horizcorner ? ev.xmotion.x : c->x;
|
|
|
|
ny = vertcorner ? ev.xmotion.y : c->y;
|
2020-06-25 09:56:41 +00:00
|
|
|
nw = MAX(horizcorner ? (ocw - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1);
|
|
|
|
nh = MAX(vertcorner ? (och - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1);
|
2020-06-24 12:49:30 +00:00
|
|
|
#else
|
|
|
|
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
|
|
|
|
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
|
|
|
|
#endif // RESIZEPOINT_PATCH | 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
|
2020-10-11 09:59:11 +00:00
|
|
|
&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) {
|
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
|
|
|
c->sfx = -9999; // disable savefloats when using resizemouse
|
|
|
|
#endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
togglefloating(NULL);
|
2020-10-11 09:59:11 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2019-09-07 20:35:37 +00:00
|
|
|
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
|
2020-06-24 12:49:30 +00:00
|
|
|
#if RESIZECORNERS_PATCH || RESIZEPOINT_PATCH
|
|
|
|
resizeclient(c, nx, ny, nw, nh);
|
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);
|
2020-06-24 12:49:30 +00:00
|
|
|
#if !RESIZEPOINT_PATCH
|
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
|
2020-06-24 12:49:30 +00:00
|
|
|
#endif // RESIZEPOINT_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) {
|
2020-09-13 12:22:31 +00:00
|
|
|
#if SCRATCHPADS_PATCH
|
|
|
|
if (c->tags & SPTAGMASK) {
|
|
|
|
c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK);
|
|
|
|
m->tagset[m->seltags] |= (c->tags & SPTAGMASK);
|
|
|
|
}
|
|
|
|
#endif // SCRATCHPADS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
sendmon(c, m);
|
|
|
|
selmon = m;
|
|
|
|
focus(NULL);
|
|
|
|
}
|
2020-09-14 08:08:47 +00:00
|
|
|
ignoreconfigurerequests = 0;
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
restack(Monitor *m)
|
|
|
|
{
|
2022-01-18 10:08:34 +00:00
|
|
|
Client *c, *f = NULL;
|
2019-09-04 22:16:39 +00:00
|
|
|
XEvent ev;
|
|
|
|
XWindowChanges wc;
|
2020-08-27 04:26:48 +00:00
|
|
|
#if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT
|
|
|
|
int n;
|
|
|
|
#endif // WARP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
drawbar(m);
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
drawtab(m);
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!m->sel)
|
|
|
|
return;
|
|
|
|
if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
|
|
|
|
XRaiseWindow(dpy, m->sel->win);
|
2022-01-18 10:08:34 +00:00
|
|
|
if (m->lt[m->sellt]->arrange) {
|
2019-09-04 22:16:39 +00:00
|
|
|
wc.stack_mode = Below;
|
2022-01-18 10:08:34 +00:00
|
|
|
if (m->bar) {
|
|
|
|
wc.sibling = m->bar->win;
|
|
|
|
} else {
|
|
|
|
for (f = m->stack; f && (f->isfloating || !ISVISIBLE(f)); f = f->snext); // find first tiled stack client
|
|
|
|
if (f)
|
|
|
|
wc.sibling = f->win;
|
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
for (c = m->stack; c; c = c->snext)
|
2022-01-18 10:08:34 +00:00
|
|
|
if (!c->isfloating && ISVISIBLE(c) && c != f) {
|
2019-09-04 22:16:39 +00:00
|
|
|
XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
|
|
|
|
wc.sibling = c->win;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XSync(dpy, False);
|
|
|
|
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
2020-08-30 03:17:16 +00:00
|
|
|
#if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT || WARP_PATCH && MONOCLE_LAYOUT
|
2020-08-27 04:26:48 +00:00
|
|
|
#if FLEXTILE_DELUXE_LAYOUT
|
|
|
|
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && (
|
|
|
|
#if MONOCLE_LAYOUT && FLEXTILE_DELUXE_LAYOUT
|
|
|
|
(m->lt[m->sellt]->arrange != &monocle
|
|
|
|
&& !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster))))
|
|
|
|
#elif MONOCLE_LAYOUT
|
2020-09-26 21:44:15 +00:00
|
|
|
m->lt[m->sellt]->arrange != &monocle
|
2020-08-27 04:26:48 +00:00
|
|
|
#else
|
|
|
|
!(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster)))
|
|
|
|
#endif // FLEXTILE_DELUXE_LAYOUT
|
|
|
|
|| m->sel->isfloating)
|
|
|
|
)
|
2019-09-14 22:43:35 +00:00
|
|
|
warp(m->sel);
|
|
|
|
#endif // WARP_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
void
|
|
|
|
run(void)
|
|
|
|
{
|
|
|
|
int event_count = 0;
|
|
|
|
const int MAX_EVENTS = 10;
|
|
|
|
struct epoll_event events[MAX_EVENTS];
|
|
|
|
|
|
|
|
XSync(dpy, False);
|
|
|
|
|
|
|
|
/* main event loop */
|
|
|
|
while (running) {
|
|
|
|
event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
|
|
|
|
|
|
|
for (int i = 0; i < event_count; i++) {
|
|
|
|
int event_fd = events[i].data.fd;
|
|
|
|
DEBUG("Got event from fd %d\n", event_fd);
|
|
|
|
|
|
|
|
if (event_fd == dpy_fd) {
|
|
|
|
// -1 means EPOLLHUP
|
|
|
|
if (handlexevent(events + i) == -1)
|
|
|
|
return;
|
|
|
|
} else if (event_fd == ipc_get_sock_fd()) {
|
|
|
|
ipc_handle_socket_epoll_event(events + i);
|
|
|
|
} else if (ipc_is_client_registered(event_fd)) {
|
|
|
|
if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon,
|
|
|
|
NUMTAGS, layouts, LENGTH(layouts)) < 0) {
|
|
|
|
fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu",
|
|
|
|
event_fd, events[i].data.ptr, events[i].data.u32,
|
|
|
|
events[i].data.u64);
|
|
|
|
fprintf(stderr, " with events %d\n", events[i].events);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
void
|
|
|
|
run(void)
|
|
|
|
{
|
|
|
|
XEvent ev;
|
|
|
|
/* main event loop */
|
|
|
|
XSync(dpy, False);
|
2021-04-07 13:35:56 +00:00
|
|
|
while (running && !XNextEvent(dpy, &ev)) {
|
|
|
|
|
|
|
|
#if XKB_PATCH
|
|
|
|
/* Unfortunately the xkbEventType is not constant hence it can't be part of the
|
|
|
|
* normal event handler below */
|
|
|
|
if (ev.type == xkbEventType) {
|
|
|
|
xkbeventnotify(&ev);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif // XKB_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (handler[ev.type])
|
|
|
|
handler[ev.type](&ev); /* call handler */
|
2021-04-07 13:35:56 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2020-09-07 15:48:58 +00:00
|
|
|
#endif // IPC_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
scan(void)
|
|
|
|
{
|
2020-09-11 09:47:57 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
scanner = 1;
|
|
|
|
char swin[256];
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
if (wmclasscontains(wins[i], altbarclass, ""))
|
|
|
|
managealtbar(wins[i], &wa);
|
|
|
|
else
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
|
|
|
|
manage(wins[i], &wa);
|
2020-09-11 09:47:57 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin))
|
|
|
|
manage(wins[i], &wa);
|
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
}
|
2020-09-11 09:47:57 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
scanner = 0;
|
|
|
|
#endif // SWALLOW_PATCH
|
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;
|
2020-06-25 08:28:31 +00:00
|
|
|
#if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH
|
|
|
|
int hadfocus = (c == selmon->sel);
|
|
|
|
#endif // SENDMON_KEEPFOCUS_PATCH
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(c, 1, NULL);
|
2019-09-04 22:16:39 +00:00
|
|
|
detach(c);
|
|
|
|
detachstack(c);
|
2020-06-24 15:12:54 +00:00
|
|
|
#if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH
|
|
|
|
arrange(c->mon);
|
|
|
|
#endif // SENDMON_KEEPFOCUS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
c->mon = m;
|
2020-09-07 07:50:42 +00:00
|
|
|
#if SCRATCHPADS_PATCH
|
|
|
|
if (!(c->tags & SPTAGMASK))
|
|
|
|
#endif // SCRATCHPADS_PATCH
|
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);
|
2020-06-24 15:12:54 +00:00
|
|
|
#elif SENDMON_KEEPFOCUS_PATCH
|
|
|
|
arrange(m);
|
2020-06-25 08:28:31 +00:00
|
|
|
if (hadfocus) {
|
|
|
|
focus(c);
|
|
|
|
restack(m);
|
|
|
|
} else
|
|
|
|
focus(NULL);
|
2019-10-24 06:47:00 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
|
|
|
arrange(NULL);
|
2020-06-24 15:12:54 +00:00
|
|
|
#endif // EXRESIZE_PATCH / SENDMON_KEEPFOCUS_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
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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)
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
Atom *protocols;
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
Atom mt;
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
int exists = 0;
|
|
|
|
XEvent ev;
|
|
|
|
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
if (exists) {
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_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);
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
XkbLockGroup(dpy, XkbUseCoreKbd, c->xkb->group);
|
|
|
|
#endif // XKB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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]);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-09-13 11:35:15 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
|
|
|
|
void
|
|
|
|
setfullscreen(Client *c, int fullscreen)
|
|
|
|
{
|
2021-05-12 13:00:04 +00:00
|
|
|
XEvent ev;
|
2020-09-13 11:35:15 +00:00
|
|
|
int savestate = 0, restorestate = 0;
|
|
|
|
|
|
|
|
if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
|
|
|
|
|| (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
|
|
|
|
savestate = 1; // go actual fullscreen
|
|
|
|
else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
|
|
|
|
|| (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
|
|
|
|
restorestate = 1; // go back into tiled
|
|
|
|
|
|
|
|
/* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
|
|
|
|
* that while staying in fullscreen. The exception to this is if we are in said state, but
|
|
|
|
* the client itself disables fullscreen (3) then we let the client go out of fullscreen
|
|
|
|
* while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
|
|
|
|
* client and the window manager's perception of the client's fullscreen state). */
|
|
|
|
if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
|
|
|
|
c->fakefullscreen = 1;
|
|
|
|
c->isfullscreen = 1;
|
|
|
|
fullscreen = 1;
|
|
|
|
} else if (c->fakefullscreen == 3) // client exiting actual fullscreen
|
|
|
|
c->fakefullscreen = 1;
|
|
|
|
|
|
|
|
if (fullscreen != c->isfullscreen) { // only send property change if necessary
|
|
|
|
if (fullscreen)
|
|
|
|
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
|
|
|
PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
|
|
|
|
else
|
|
|
|
XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
|
|
|
|
PropModeReplace, (unsigned char*)0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
c->isfullscreen = fullscreen;
|
|
|
|
|
|
|
|
/* Some clients, e.g. firefox, will send a client message informing the window manager
|
|
|
|
* that it is going into fullscreen after receiving the above signal. This has the side
|
|
|
|
* effect of this function (setfullscreen) sometimes being called twice when toggling
|
|
|
|
* fullscreen on and off via the window manager as opposed to the application itself.
|
|
|
|
* To protect against obscure issues where the client settings are stored or restored
|
|
|
|
* when they are not supposed to we add an additional bit-lock on the old state so that
|
|
|
|
* settings can only be stored and restored in that precise order. */
|
|
|
|
if (savestate && !(c->oldstate & (1 << 1))) {
|
|
|
|
c->oldbw = c->bw;
|
|
|
|
c->oldstate = c->isfloating | (1 << 1);
|
|
|
|
c->bw = 0;
|
|
|
|
c->isfloating = 1;
|
|
|
|
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
|
|
|
XRaiseWindow(dpy, c->win);
|
|
|
|
} else if (restorestate && (c->oldstate & (1 << 1))) {
|
|
|
|
c->bw = c->oldbw;
|
|
|
|
c->isfloating = c->oldstate = c->oldstate & 1;
|
|
|
|
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);
|
|
|
|
restack(c->mon);
|
2021-01-22 10:16:41 +00:00
|
|
|
} else
|
|
|
|
resizeclient(c, c->x, c->y, c->w, c->h);
|
2021-05-12 13:00:04 +00:00
|
|
|
|
|
|
|
/* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
|
|
|
|
* mode, then the focus would sometimes drift to whichever window is under the mouse cursor
|
|
|
|
* at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
|
|
|
|
*/
|
|
|
|
if (!c->isfullscreen)
|
|
|
|
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
2020-09-13 11:35:15 +00:00
|
|
|
}
|
|
|
|
#else
|
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
|
2020-09-09 15:24:02 +00:00
|
|
|
c->oldbw = c->bw;
|
2020-09-12 11:33:02 +00:00
|
|
|
c->oldstate = c->isfloating;
|
2019-09-04 22:16:39 +00:00
|
|
|
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-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
|
2020-09-09 15:24:02 +00:00
|
|
|
c->bw = c->oldbw;
|
2020-09-12 11:33:02 +00:00
|
|
|
c->isfloating = c->oldstate;
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2020-09-13 11:35:15 +00:00
|
|
|
arrange(c->mon);
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-13 11:35:15 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
setlayout(const Arg *arg)
|
|
|
|
{
|
2021-05-30 17:22:00 +00:00
|
|
|
#if !TOGGLELAYOUT_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
2021-05-30 17:22:00 +00:00
|
|
|
#endif // TOGGLELAYOUT_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
#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
|
2021-05-30 17:22:00 +00:00
|
|
|
#if !TOGGLELAYOUT_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
}
|
2021-05-30 17:22:00 +00:00
|
|
|
#endif // TOGGLELAYOUT_PATCH
|
|
|
|
#if TOGGLELAYOUT_PATCH
|
|
|
|
if (arg && arg->v && arg->v != selmon->lt[selmon->sellt ^ 1])
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (arg && arg->v)
|
2021-05-30 17:22:00 +00:00
|
|
|
#endif // TOGGLELAYOUT_PATCH
|
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;
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
XkbStateRec xkbstate;
|
|
|
|
#endif // XKB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
|
|
|
|
2021-11-25 08:15:27 +00:00
|
|
|
/* the one line of bloat that would have saved a lot of time for a lot of people */
|
|
|
|
putenv("_JAVA_AWT_WM_NONREPARENTING=1");
|
|
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_ALPHA_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
xinitvisual();
|
|
|
|
drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
|
|
|
|
#else
|
|
|
|
drw = drw_create(dpy, screen, root, sw, sh);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_ALPHA_PATCH
|
|
|
|
#if BAR_PANGO_PATCH
|
2020-06-11 17:42:00 +00:00
|
|
|
if (!drw_font_create(drw, font))
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_PANGO_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
die("no fonts could be loaded.");
|
2020-07-19 14:57:30 +00:00
|
|
|
#if BAR_STATUSPADDING_PATCH
|
2019-09-07 21:29:37 +00:00
|
|
|
lrpad = drw->fonts->h + horizpadbar;
|
|
|
|
bh = drw->fonts->h + vertpadbar;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
lrpad = drw->fonts->h;
|
2020-06-21 18:04:56 +00:00
|
|
|
#if BAR_HEIGHT_PATCH
|
|
|
|
bh = bar_height ? bar_height : drw->fonts->h + 2;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
bh = drw->fonts->h + 2;
|
2020-06-21 18:04:56 +00:00
|
|
|
#endif // BAR_HEIGHT_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUSPADDING_PATCH
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
th = bh;
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
updategeom();
|
|
|
|
/* init atoms */
|
|
|
|
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
|
|
|
|
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
|
|
|
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
|
|
|
wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
|
|
|
|
wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
|
|
|
#if BAR_EWMHTAGS_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2021-07-27 11:40:53 +00:00
|
|
|
#if BAR_WINICON_PATCH
|
|
|
|
netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False);
|
|
|
|
#endif // BAR_WINICON_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[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
2020-10-26 10:10:14 +00:00
|
|
|
#if NET_CLIENT_LIST_STACKING_PATCH
|
|
|
|
netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
|
|
|
|
#endif // NET_CLIENT_LIST_STACKING_PATCH
|
2020-08-11 08:17:02 +00:00
|
|
|
#if DECORATION_HINTS_PATCH
|
|
|
|
motifatom = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
|
|
|
|
#endif // DECORATION_HINTS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* init cursors */
|
|
|
|
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
|
|
|
|
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
2020-06-25 09:56:41 +00:00
|
|
|
#if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
|
|
|
|
cursor[CurResizeBR] = drw_cur_create(drw, XC_bottom_right_corner);
|
|
|
|
cursor[CurResizeBL] = drw_cur_create(drw, XC_bottom_left_corner);
|
|
|
|
cursor[CurResizeTR] = drw_cur_create(drw, XC_top_right_corner);
|
|
|
|
cursor[CurResizeTL] = drw_cur_create(drw, XC_top_left_corner);
|
|
|
|
#endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
|
|
|
|
#if DRAGMFACT_PATCH
|
|
|
|
cursor[CurResizeHorzArrow] = drw_cur_create(drw, XC_sb_h_double_arrow);
|
|
|
|
cursor[CurResizeVertArrow] = drw_cur_create(drw, XC_sb_v_double_arrow);
|
|
|
|
#endif // DRAGMFACT_PATCH
|
|
|
|
#if DRAGCFACT_PATCH
|
|
|
|
cursor[CurIronCross] = drw_cur_create(drw, XC_iron_cross);
|
|
|
|
#endif // DRAGCFACT_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
|
|
|
/* init appearance */
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_VTCOLORS_PATCH
|
2020-02-11 17:31:11 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_VTCOLORS_PATCH
|
|
|
|
#if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_ALPHA_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], alphas[0], ColCount);
|
|
|
|
#else
|
|
|
|
scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], ColCount);
|
2020-08-20 11:30:12 +00:00
|
|
|
#endif // BAR_ALPHA_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUS2D_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
for (i = 0; i < LENGTH(colors); i++)
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_ALPHA_PATCH
|
2020-05-26 18:53:53 +00:00
|
|
|
scheme[i] = drw_scm_create(drw, colors[i], alphas[i], ColCount);
|
2019-09-10 22:51:37 +00:00
|
|
|
#else
|
2020-05-26 18:53:53 +00:00
|
|
|
scheme[i] = drw_scm_create(drw, colors[i], ColCount);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_ALPHA_PATCH
|
2020-07-19 14:57:30 +00:00
|
|
|
#if BAR_POWERLINE_STATUS_PATCH
|
|
|
|
statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *));
|
|
|
|
for (i = 0; i < LENGTH(statuscolors); i++)
|
|
|
|
#if BAR_ALPHA_PATCH
|
|
|
|
statusscheme[i] = drw_scm_create(drw, statuscolors[i], alphas[0], ColCount);
|
|
|
|
#else
|
|
|
|
statusscheme[i] = drw_scm_create(drw, statuscolors[i], ColCount);
|
|
|
|
#endif // BAR_ALPHA_PATCH
|
|
|
|
#endif // BAR_POWERLINE_STATUS_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
updatebars();
|
|
|
|
updatestatus();
|
2020-07-15 06:57:30 +00:00
|
|
|
|
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);
|
2021-03-09 12:47:21 +00:00
|
|
|
#if LG3D_PATCH
|
|
|
|
XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
|
|
|
|
PropModeReplace, (unsigned char *) "LG3D", 4);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
|
|
|
|
PropModeReplace, (unsigned char *) "dwm", 3);
|
2021-03-09 12:47:21 +00:00
|
|
|
#endif // LG3D_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_EWMHTAGS_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
setnumdesktops();
|
|
|
|
setcurrentdesktop();
|
|
|
|
setdesktopnames();
|
|
|
|
setviewport();
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XDeleteProperty(dpy, root, netatom[NetClientList]);
|
2020-10-26 10:10:14 +00:00
|
|
|
#if NET_CLIENT_LIST_STACKING_PATCH
|
|
|
|
XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
|
|
|
|
#endif // NET_CLIENT_LIST_STACKING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
/* 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);
|
2021-04-07 13:35:56 +00:00
|
|
|
|
|
|
|
#if XKB_PATCH
|
|
|
|
/* get xkb extension info, events and current state */
|
|
|
|
if (!XkbQueryExtension(dpy, NULL, &xkbEventType, NULL, NULL, NULL))
|
|
|
|
fputs("warning: can not query xkb extension\n", stderr);
|
|
|
|
XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify,
|
|
|
|
XkbAllStateComponentsMask, XkbGroupStateMask);
|
|
|
|
XkbGetState(dpy, XkbUseCoreKbd, &xkbstate);
|
|
|
|
xkbGlobal.group = xkbstate.locked_group;
|
|
|
|
#endif // XKB_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
grabkeys();
|
|
|
|
focus(NULL);
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
setupepoll();
|
|
|
|
#endif // IPC_PATCH
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
if (usealtbar)
|
|
|
|
spawnbar();
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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)) {
|
2020-09-09 15:24:02 +00:00
|
|
|
#if SCRATCHPADS_PATCH && SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH
|
2020-09-07 07:50:42 +00:00
|
|
|
if (
|
|
|
|
(c->tags & SPTAGMASK) &&
|
|
|
|
c->isfloating &&
|
|
|
|
(
|
|
|
|
c->x < c->mon->mx ||
|
|
|
|
c->x > c->mon->mx + c->mon->mw ||
|
|
|
|
c->y < c->mon->my ||
|
|
|
|
c->y > c->mon->my + c->mon->mh
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
|
|
|
c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
|
|
|
}
|
|
|
|
#elif SCRATCHPADS_PATCH
|
[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 ((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);
|
|
|
|
}
|
2020-09-07 07:50:42 +00:00
|
|
|
#endif // SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH | SCRATCHPADS_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)
|
|
|
|
{
|
2020-08-10 08:22:21 +00:00
|
|
|
#if COOL_AUTOSTART_PATCH
|
|
|
|
pid_t pid;
|
|
|
|
#endif // COOL_AUTOSTART_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
if (signal(SIGCHLD, sigchld) == SIG_ERR)
|
|
|
|
die("can't install SIGCHLD handler:");
|
2020-08-10 08:22:21 +00:00
|
|
|
#if COOL_AUTOSTART_PATCH
|
|
|
|
while (0 < (pid = waitpid(-1, NULL, WNOHANG))) {
|
|
|
|
pid_t *p, *lim;
|
|
|
|
|
|
|
|
if (!(p = autostart_pids))
|
|
|
|
continue;
|
|
|
|
lim = &p[autostart_len];
|
|
|
|
|
|
|
|
for (; p < lim; p++) {
|
|
|
|
if (*p == pid) {
|
|
|
|
*p = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
while (0 < waitpid(-1, NULL, WNOHANG));
|
2020-08-10 08:22:21 +00:00
|
|
|
#endif // COOL_AUTOSTART_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
void
|
|
|
|
spawn(const Arg *arg)
|
|
|
|
{
|
|
|
|
spawncmd(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t
|
|
|
|
spawncmd(const Arg *arg)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
void
|
|
|
|
spawn(const Arg *arg)
|
2021-02-16 09:26:49 +00:00
|
|
|
#endif // RIODRAW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
pid_t pid;
|
|
|
|
#endif // RIODRAW_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
|
|
|
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
if ((pid = fork()) == 0)
|
|
|
|
#else
|
|
|
|
if (fork() == 0)
|
|
|
|
#endif // RIODRAW_PATCH
|
|
|
|
{
|
2019-09-04 22:16:39 +00:00
|
|
|
if (dpy)
|
|
|
|
close(ConnectionNumber(dpy));
|
2021-04-14 09:23:18 +00:00
|
|
|
|
|
|
|
#if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH
|
|
|
|
if (arg->v == statuscmd) {
|
|
|
|
for (int i = 0; i < LENGTH(statuscmds); i++) {
|
|
|
|
if (statuscmdn == statuscmds[i].id) {
|
|
|
|
statuscmd[2] = statuscmds[i].cmd;
|
|
|
|
setenv("BUTTON", lastbutton, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!statuscmd[2])
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
#endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH
|
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);
|
|
|
|
}
|
2021-02-16 09:26:49 +00:00
|
|
|
#if RIODRAW_PATCH
|
|
|
|
return pid;
|
|
|
|
#endif // RIODRAW_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;
|
2020-05-20 13:25:56 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
if (selmon->sel->switchtag)
|
|
|
|
selmon->sel->switchtag = 0;
|
|
|
|
#endif // SWITCHTAG_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] = 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
|
2020-09-05 07:11:12 +00:00
|
|
|
if ((arg->ui & TAGMASK) != selmon->tagset[selmon->seltags])
|
|
|
|
view(arg);
|
2019-09-15 21:42:47 +00:00
|
|
|
#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;
|
|
|
|
if (c->isfullscreen) {
|
2020-04-27 18:41:38 +00:00
|
|
|
c->isfullscreen = 0;
|
|
|
|
sendmon(c, dirtomon(arg->i));
|
|
|
|
c->isfullscreen = 1;
|
2020-08-24 13:03:55 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
|
2020-09-05 09:38:09 +00:00
|
|
|
if (c->fakefullscreen != 1) {
|
2020-04-27 18:41:38 +00:00
|
|
|
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
|
|
|
XRaiseWindow(dpy, c->win);
|
|
|
|
}
|
|
|
|
#elif !FAKEFULLSCREEN_PATCH
|
|
|
|
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
|
|
|
XRaiseWindow(dpy, c->win);
|
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
} else
|
|
|
|
sendmon(c, dirtomon(arg->i));
|
2019-09-05 21:39:25 +00:00
|
|
|
#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)
|
|
|
|
{
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_HOLDBAR_PATCH && PERTAG_PATCH && PERTAGBAR_PATCH
|
2020-06-30 08:15:36 +00:00
|
|
|
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = (selmon->showbar == 2 ? 1 : !selmon->showbar);
|
2020-07-15 06:57:30 +00:00
|
|
|
#elif BAR_HOLDBAR_PATCH
|
2020-06-30 08:15:36 +00:00
|
|
|
selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar);
|
|
|
|
#elif PERTAG_PATCH && PERTAGBAR_PATCH
|
2019-09-05 20:58:16 +00:00
|
|
|
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
selmon->showbar = !selmon->showbar;
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_HOLDBAR_PATCH | PERTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
updatebarpos(selmon);
|
2020-07-18 16:58:39 +00:00
|
|
|
for (bar = selmon->bar; bar; bar = bar->next)
|
|
|
|
XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
|
2022-01-10 16:16:09 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
|
|
|
if (!selmon->showbar && systray)
|
|
|
|
XMoveWindow(dpy, systray->win, -32000, -32000);
|
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
togglefloating(const Arg *arg)
|
|
|
|
{
|
2020-08-22 07:21:23 +00:00
|
|
|
Client *c = selmon->sel;
|
|
|
|
if (arg && arg->v)
|
|
|
|
c = (Client*)arg->v;
|
|
|
|
if (!c)
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
2019-10-08 21:15:11 +00:00
|
|
|
#if !FAKEFULLSCREEN_PATCH
|
2019-11-21 11:15:16 +00:00
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
2020-09-05 12:20:53 +00:00
|
|
|
if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
|
2019-11-21 11:15:16 +00:00
|
|
|
return;
|
|
|
|
#else
|
2020-08-22 07:21:23 +00:00
|
|
|
if (c->isfullscreen) /* no support for fullscreen windows */
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
2019-11-21 11:15:16 +00:00
|
|
|
#endif // FAKEFULLSCREEN_CLIENT_PATCH
|
2019-10-08 21:15:11 +00:00
|
|
|
#endif // !FAKEFULLSCREEN_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
c->isfloating = !c->isfloating || c->isfixed;
|
2020-08-27 19:37:19 +00:00
|
|
|
#if !BAR_FLEXWINTITLE_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
|
2019-09-10 22:51:37 +00:00
|
|
|
else
|
2020-08-22 07:21:23 +00:00
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
|
2020-08-27 19:37:19 +00:00
|
|
|
#endif // BAR_FLEXWINTITLE_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
if (c->isfloating) {
|
2019-10-24 06:47:00 +00:00
|
|
|
#if SAVEFLOATS_PATCH || EXRESIZE_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
if (c->sfx != -9999) {
|
2019-09-07 21:08:53 +00:00
|
|
|
/* restore last known float dimensions */
|
2020-08-22 07:21:23 +00:00
|
|
|
resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
|
2020-10-11 09:55:15 +00:00
|
|
|
} else
|
2019-10-24 06:47:00 +00:00
|
|
|
#endif // SAVEFLOATS_PATCH // EXRESIZE_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
resize(c, c->x, c->y, c->w, c->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 */
|
2020-08-22 07:21:23 +00:00
|
|
|
c->sfx = c->x;
|
|
|
|
c->sfy = c->y;
|
|
|
|
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
|
|
|
}
|
2020-08-22 07:21:23 +00:00
|
|
|
arrange(c->mon);
|
2020-09-28 12:39:17 +00:00
|
|
|
|
|
|
|
#if BAR_EWMHTAGS_PATCH
|
|
|
|
setfloatinghint(c);
|
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_EWMHTAGS_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
updatecurrentdesktop();
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
toggleview(const Arg *arg)
|
|
|
|
{
|
2022-02-11 15:57:53 +00:00
|
|
|
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);;
|
|
|
|
#if TAGSYNC_PATCH
|
|
|
|
Monitor *origselmon = selmon;
|
|
|
|
for (selmon = mons; selmon; selmon = selmon->next) {
|
|
|
|
#endif // TAGSYNC_PATCH
|
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
|
2020-09-28 15:48:49 +00:00
|
|
|
#if SCRATCHPADS_PATCH
|
|
|
|
if (newtagset == ~SPTAGMASK)
|
|
|
|
#else
|
|
|
|
if (newtagset == ~0)
|
|
|
|
#endif // SCRATCHPADS_PATCH
|
|
|
|
{
|
2019-09-05 20:58:16 +00:00
|
|
|
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;
|
2020-09-28 15:48:49 +00:00
|
|
|
for (i = 0; !(newtagset & 1 << i); i++) ;
|
2019-09-05 20:58:16 +00:00
|
|
|
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
|
2022-02-11 15:57:53 +00:00
|
|
|
#if !TAGSYNC_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
|
|
|
arrange(selmon);
|
2022-02-11 15:57:53 +00:00
|
|
|
#endif // TAGSYNC_PATCH
|
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
|
2022-02-11 15:57:53 +00:00
|
|
|
#if TAGSYNC_PATCH
|
|
|
|
}
|
|
|
|
selmon = origselmon;
|
|
|
|
#if !EMPTYVIEW_PATCH
|
|
|
|
if (newtagset) {
|
|
|
|
#endif // EMPTYVIEW_PATCH
|
|
|
|
focus(NULL);
|
|
|
|
arrange(NULL);
|
|
|
|
#if !EMPTYVIEW_PATCH
|
|
|
|
}
|
|
|
|
#endif // EMPTYVIEW_PATCH
|
|
|
|
#endif // TAGSYNC_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_EWMHTAGS_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
updatecurrentdesktop();
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_EWMHTAGS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-09-05 09:38:09 +00:00
|
|
|
unfocus(Client *c, int setfocus, Client *nextfocus)
|
2019-09-04 22:16:39 +00:00
|
|
|
{
|
|
|
|
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
|
2020-09-13 11:35:15 +00:00
|
|
|
if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon && nextfocus && !nextfocus->isfloating)
|
|
|
|
#if FAKEFULLSCREEN_CLIENT_PATCH
|
|
|
|
if (c->fakefullscreen != 1)
|
2020-09-05 09:38:09 +00:00
|
|
|
setfullscreen(c, 0);
|
|
|
|
#else
|
2020-04-05 07:10:00 +00:00
|
|
|
setfullscreen(c, 0);
|
2020-09-13 11:35:15 +00:00
|
|
|
#endif // #if FAKEFULLSCREEN_CLIENT_PATCH
|
2020-04-05 07:10:00 +00:00
|
|
|
#endif // LOSEFULLSCREEN_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
grabbuttons(c, 0);
|
2020-08-27 19:37:19 +00:00
|
|
|
#if !BAR_FLEXWINTITLE_PATCH
|
2019-09-10 22:51:37 +00:00
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel);
|
|
|
|
else
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
|
2020-08-27 19:37:19 +00:00
|
|
|
#endif // BAR_FLEXWINTITLE_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;
|
2020-07-03 11:30:21 +00:00
|
|
|
#if SWITCHTAG_PATCH
|
|
|
|
unsigned int switchtag = c->switchtag;
|
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XWindowChanges wc;
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
XkbInfo *xkb;
|
|
|
|
#endif // XKB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
|
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);
|
2021-07-27 11:40:53 +00:00
|
|
|
#if BAR_WINICON_PATCH
|
|
|
|
freeicon(c);
|
|
|
|
#endif // BAR_WINICON_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
|
|
|
}
|
2021-04-07 13:35:56 +00:00
|
|
|
#if XKB_PATCH
|
|
|
|
else {
|
|
|
|
xkb = findxkb(c->win);
|
|
|
|
if (xkb != NULL) {
|
|
|
|
if (xkb->prev)
|
|
|
|
xkb->prev->next = xkb->next;
|
|
|
|
if (xkb->next)
|
|
|
|
xkb->next->prev = xkb->prev;
|
|
|
|
free(xkb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // XKB_PATCH
|
|
|
|
|
2021-05-06 09:05:48 +00:00
|
|
|
#if SCRATCHPAD_ALT_1_PATCH
|
|
|
|
if (scratchpad_last_showed == c)
|
|
|
|
scratchpad_last_showed = NULL;
|
|
|
|
#endif // SCRATCHPAD_ALT_1_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
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
|
2020-09-05 07:11:12 +00:00
|
|
|
if (switchtag && ((switchtag & TAGMASK) != selmon->tagset[selmon->seltags]))
|
2020-07-03 11:30:21 +00:00
|
|
|
view(&((Arg) { .ui = switchtag }));
|
2019-11-26 19:23:58 +00:00
|
|
|
#endif // SWITCHTAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
unmapnotify(XEvent *e)
|
|
|
|
{
|
|
|
|
Client *c;
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
Monitor *m;
|
|
|
|
Bar *bar;
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
XUnmapEvent *ev = &e->xunmap;
|
|
|
|
|
|
|
|
if ((c = wintoclient(ev->window))) {
|
|
|
|
if (ev->send_event)
|
|
|
|
setclientstate(c, WithdrawnState);
|
|
|
|
else
|
|
|
|
unmanage(c, 0);
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_SYSTRAY_PATCH
|
2019-09-05 20:10:00 +00:00
|
|
|
} 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);
|
2020-07-18 11:03:30 +00:00
|
|
|
drawbarwin(systray->bar);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_SYSTRAY_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2020-09-10 11:32:28 +00:00
|
|
|
#if BAR_ANYBAR_PATCH
|
|
|
|
else {
|
|
|
|
m = wintomon(ev->window);
|
|
|
|
for (bar = m->bar; bar; bar = bar->next) {
|
|
|
|
if (bar->win == ev->window) {
|
|
|
|
unmanagealtbar(ev->window);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // BAR_ANYBAR_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatebars(void)
|
|
|
|
{
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2019-09-04 22:16:39 +00:00
|
|
|
Monitor *m;
|
|
|
|
XSetWindowAttributes wa = {
|
|
|
|
.override_redirect = True,
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_ALPHA_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
.background_pixel = 0,
|
|
|
|
.border_pixel = 0,
|
|
|
|
.colormap = cmap,
|
|
|
|
#else
|
|
|
|
.background_pixmap = ParentRelative,
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_ALPHA_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
.event_mask = ButtonPressMask|ExposureMask
|
|
|
|
};
|
|
|
|
XClassHint ch = {"dwm", "dwm"};
|
|
|
|
for (m = mons; m; m = m->next) {
|
2020-07-18 16:58:39 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next) {
|
2020-09-10 13:24:51 +00:00
|
|
|
if (bar->external)
|
|
|
|
continue;
|
2020-07-31 08:31:20 +00:00
|
|
|
if (!bar->win) {
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_ALPHA_PATCH
|
2020-07-18 16:58:39 +00:00
|
|
|
bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth,
|
2020-07-15 06:57:30 +00:00
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
|
|
|
#else
|
2020-07-18 16:58:39 +00:00
|
|
|
bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen),
|
2020-07-15 06:57:30 +00:00
|
|
|
CopyFromParent, DefaultVisual(dpy, screen),
|
|
|
|
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
|
|
|
#endif // BAR_ALPHA_PATCH
|
2020-07-18 16:58:39 +00:00
|
|
|
XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor);
|
|
|
|
XMapRaised(dpy, bar->win);
|
|
|
|
XSetClassHint(dpy, bar->win, &ch);
|
2020-07-15 06:57:30 +00:00
|
|
|
}
|
2019-10-24 05:35:00 +00:00
|
|
|
}
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
if (!m->tabwin) {
|
|
|
|
#if BAR_ALPHA_PATCH
|
|
|
|
m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, depth,
|
|
|
|
InputOutput, visual,
|
|
|
|
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
|
|
|
#else
|
|
|
|
m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
|
|
|
|
CopyFromParent, DefaultVisual(dpy, screen),
|
|
|
|
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
|
|
|
#endif // BAR_ALPHA_PATCH
|
|
|
|
XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
|
|
|
|
XMapRaised(dpy, m->tabwin);
|
|
|
|
}
|
|
|
|
#endif // TAB_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatebarpos(Monitor *m)
|
|
|
|
{
|
2021-03-09 12:23:39 +00:00
|
|
|
#if TAB_PATCH
|
|
|
|
Client *c;
|
|
|
|
int nvis = 0;
|
|
|
|
#endif // TAB_PATCH
|
|
|
|
|
2020-08-10 10:32:58 +00:00
|
|
|
m->wx = m->mx;
|
2019-09-04 22:16:39 +00:00
|
|
|
m->wy = m->my;
|
2020-08-10 10:32:58 +00:00
|
|
|
m->ww = m->mw;
|
2019-09-04 22:16:39 +00:00
|
|
|
m->wh = m->mh;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2021-12-26 12:59:55 +00:00
|
|
|
int y_pad = 0;
|
|
|
|
int x_pad = 0;
|
2022-02-11 10:43:06 +00:00
|
|
|
#if BAR_PADDING_VANITYGAPS_PATCH && VANITYGAPS_PATCH
|
2021-12-26 15:56:32 +00:00
|
|
|
#if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH
|
2022-02-11 10:43:06 +00:00
|
|
|
if (!selmon || selmon->pertag->enablegaps[selmon->pertag->curtag])
|
2021-12-26 15:56:32 +00:00
|
|
|
#else
|
2022-02-11 10:43:06 +00:00
|
|
|
if (enablegaps)
|
2021-12-26 15:56:32 +00:00
|
|
|
#endif // PERTAG_VANITYGAPS_PATCH
|
2022-02-11 10:43:06 +00:00
|
|
|
{
|
|
|
|
y_pad = gappoh;
|
|
|
|
x_pad = gappov;
|
2021-12-26 12:59:55 +00:00
|
|
|
}
|
|
|
|
#elif BAR_PADDING_PATCH
|
2022-02-11 10:43:06 +00:00
|
|
|
y_pad = vertpad;
|
|
|
|
x_pad = sidepad;
|
|
|
|
#endif // BAR_PADDING_PATCH | BAR_PADDING_VANITYGAPS_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
|
2020-08-10 10:32:58 +00:00
|
|
|
#if INSETS_PATCH
|
|
|
|
// Custom insets
|
|
|
|
Inset inset = m->inset;
|
|
|
|
m->wx += inset.x;
|
|
|
|
m->wy += inset.y;
|
|
|
|
m->ww -= inset.w + inset.x;
|
|
|
|
m->wh -= inset.h + inset.y;
|
|
|
|
#endif // INSETS_PATCH
|
|
|
|
|
2020-07-27 08:45:13 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next) {
|
2020-08-10 10:32:58 +00:00
|
|
|
bar->bx = m->wx + x_pad;
|
2021-04-28 08:52:59 +00:00
|
|
|
#if BAR_ANYBAR_PATCH && !BAR_ANYBAR_MANAGE_WIDTH_PATCH
|
|
|
|
if (bar->external)
|
|
|
|
continue;
|
|
|
|
#endif // BAR_ANYBAR_PATCH | BAR_ANYBAR_MANAGE_WIDTH_PATCH
|
2020-07-27 08:45:13 +00:00
|
|
|
bar->bw = m->ww - 2 * x_pad;
|
|
|
|
}
|
|
|
|
|
2020-08-22 06:43:07 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next)
|
|
|
|
if (!m->showbar || !bar->showbar)
|
2020-09-10 13:24:51 +00:00
|
|
|
bar->by = -bar->bh - y_pad;
|
2021-03-09 12:23:39 +00:00
|
|
|
|
|
|
|
#if TAB_PATCH
|
|
|
|
for (c = m->clients; c; c = c->next) {
|
|
|
|
if (ISVISIBLE(c) && !HIDDEN(c))
|
|
|
|
++nvis;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->showtab == showtab_always
|
|
|
|
|| ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))) {
|
|
|
|
m->wh -= th;
|
|
|
|
m->ty = m->toptab ? m->wy : m->wy + m->wh;
|
|
|
|
if (m->toptab)
|
|
|
|
m->wy += th;
|
|
|
|
} else {
|
|
|
|
m->ty = -th;
|
|
|
|
}
|
|
|
|
#endif // TAB_PATCH
|
|
|
|
|
2020-08-22 06:43:07 +00:00
|
|
|
if (!m->showbar)
|
2020-07-21 09:35:26 +00:00
|
|
|
return;
|
2020-09-09 15:24:02 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next) {
|
2020-08-22 06:43:07 +00:00
|
|
|
if (!bar->showbar)
|
|
|
|
continue;
|
2020-07-21 09:35:26 +00:00
|
|
|
if (bar->topbar)
|
2020-09-10 13:24:51 +00:00
|
|
|
m->wy = m->wy + bar->bh + y_pad;
|
|
|
|
m->wh -= y_pad + bar->bh;
|
|
|
|
bar->by = (bar->topbar ? m->wy - bar->bh : m->wy + m->wh);
|
2021-04-28 08:52:59 +00:00
|
|
|
}
|
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);
|
2020-10-26 10:10:14 +00:00
|
|
|
|
|
|
|
#if NET_CLIENT_LIST_STACKING_PATCH
|
|
|
|
XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
|
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
for (c = m->stack; c; c = c->snext)
|
|
|
|
XChangeProperty(dpy, root, netatom[NetClientListStacking],
|
|
|
|
XA_WINDOW, 32, PropModeAppend,
|
|
|
|
(unsigned char *) &(c->win), 1);
|
|
|
|
#endif // NET_CLIENT_LIST_STACKING_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2022-04-17 08:24:02 +00:00
|
|
|
/* new monitors if nn > n */
|
|
|
|
for (i = n; i < nn; 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);
|
2020-06-10 09:52:35 +00:00
|
|
|
}
|
2022-04-17 08:24:02 +00:00
|
|
|
/* removed monitors if n > nn */
|
|
|
|
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);
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
2022-04-17 08:24:02 +00:00
|
|
|
if (m == selmon)
|
|
|
|
selmon = mons;
|
|
|
|
cleanupmon(m);
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
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 */
|
2022-02-11 09:10:28 +00:00
|
|
|
#if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH || SIZEHINTS_ISFREESIZE_PATCH
|
2020-06-15 19:01:05 +00:00
|
|
|
size.flags = 0;
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
size.flags = PSize;
|
2022-02-11 09:10:28 +00:00
|
|
|
#endif // SIZEHINTS_PATCH | SIZEHINTS_RULED_PATCH | SIZEHINTS_ISFREESIZE_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2022-02-11 09:10:28 +00:00
|
|
|
#if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH || SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
#if SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
if ((size.flags & PSize) && c->isfreesize)
|
|
|
|
#else
|
|
|
|
if (size.flags & PSize)
|
|
|
|
#endif // SIZEHINTS_ISFREESIZE_PATCH
|
|
|
|
{
|
2020-06-15 19:01:05 +00:00
|
|
|
c->basew = size.base_width;
|
|
|
|
c->baseh = size.base_height;
|
|
|
|
c->isfloating = 1;
|
|
|
|
}
|
|
|
|
#if SIZEHINTS_RULED_PATCH
|
|
|
|
checkfloatingrules(c);
|
|
|
|
#endif // SIZEHINTS_RULED_PATCH
|
|
|
|
#endif // SIZEHINTS_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
|
manage: propertynotify: Reduce cost of unused size hints
This patch defers all size hint calculations until they are actually
needed, drastically reducing the number of calls to updatesizehints(),
which can be expensive when called repeatedly (as it currently is during
resizes).
In my unscientific testing this reduces calls to updatesizehints() by
over 90% during a typical work session. There are no functional changes
for users other than an increase in responsiveness after resizes and
a reduction in CPU time.
In slower environments or X servers, this patch also offers an
improvement in responsiveness that is often tangible after resizing a
client that changes hints during resizes.
There are two main motivations to defer this work to the time of hint
application:
1. Some clients, especially terminals using incremental size hints,
resend XA_WM_NORMAL_HINTS events on resize to avoid fighting with the
WM or mouse resizing. For example, some terminals like urxvt clear
PBaseSize and PResizeInc during XResizeWindow and restore them
afterwards.
For this reason, after the resize is concluded, we typically receive
a backlogged XA_WM_NORMAL_HINTS message for each update period with
movement, which is useless. In some cases one may get hundreds or
thousands of XA_WM_NORMAL_HINTS messages on large resizes, and
currently all of these result in a separate updatesizehints() call,
of which all but the final one are immediately outdated.
(We can't just blindly discard these messages during resizes like we
do for EnterNotify, because some of them might actually be for other
windows, and may not be XA_WM_NORMAL_HINTS events.)
2. For users which use resizehints=0 most of these updates are unused
anyway -- in the normal case where the client is not floating these
values won't be used, so there's no need to calculate them up front.
A synthetic test using the mouse to resize a floating terminal window
from roughly 256x256 to 1024x1024 and back again shows that the number
of calls to updatesizehints() goes from over 500 before this patch (one
for each update interval with movement) to 2 after this patch (one for
each hint application), with no change in user visible behaviour.
This also reduces the delay before dwm is ready to process new events
again after a large resize on such a client, as it avoids the thundering
herd of updatesizehints() calls when hundreds of backlogged
XA_WM_NORMAL_HINTS messages appear at once after a resize is finished.
ref.
https://git.suckless.org/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.html#h0-0-4
2022-04-17 08:15:22 +00:00
|
|
|
c->hintsvalid = 1;
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatestatus(void)
|
|
|
|
{
|
2020-07-18 11:03:30 +00:00
|
|
|
Monitor *m;
|
2020-07-18 19:12:30 +00:00
|
|
|
#if BAR_EXTRASTATUS_PATCH
|
2020-07-05 19:53:36 +00:00
|
|
|
if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) {
|
2019-10-24 05:35:00 +00:00
|
|
|
strcpy(stext, "dwm-"VERSION);
|
|
|
|
estext[0] = '\0';
|
|
|
|
} else {
|
2020-07-05 19:53:36 +00:00
|
|
|
char *e = strchr(rawstext, statussep);
|
2019-10-24 05:35:00 +00:00
|
|
|
if (e) {
|
|
|
|
*e = '\0'; e++;
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_STATUSCMD_PATCH
|
2020-07-05 19:53:36 +00:00
|
|
|
strncpy(rawestext, e, sizeof(estext) - 1);
|
|
|
|
copyvalidchars(estext, rawestext);
|
|
|
|
#else
|
2019-10-24 05:35:00 +00:00
|
|
|
strncpy(estext, e, sizeof(estext) - 1);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUSCMD_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
} else {
|
|
|
|
estext[0] = '\0';
|
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_STATUSCMD_PATCH
|
2020-07-05 19:53:36 +00:00
|
|
|
copyvalidchars(stext, rawstext);
|
2020-04-13 12:59:58 +00:00
|
|
|
#else
|
2020-07-05 19:53:36 +00:00
|
|
|
strncpy(stext, rawstext, sizeof(stext) - 1);
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_STATUSCMD_PATCH
|
2019-10-24 05:35:00 +00:00
|
|
|
}
|
2020-07-15 06:57:30 +00:00
|
|
|
#elif BAR_STATUSCMD_PATCH
|
2020-04-13 12:59:58 +00:00
|
|
|
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);
|
2020-07-18 19:12:30 +00:00
|
|
|
#endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
|
2019-10-06 21:43:51 +00:00
|
|
|
for (m = mons; m; m = m->next)
|
|
|
|
drawbar(m);
|
2019-09-04 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
updatetitle(Client *c)
|
|
|
|
{
|
2020-09-07 15:48:58 +00:00
|
|
|
#if IPC_PATCH
|
|
|
|
char oldname[sizeof(c->name)];
|
|
|
|
strcpy(oldname, c->name);
|
|
|
|
#endif // IPC_PATCH
|
|
|
|
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
2020-09-07 15:48:58 +00:00
|
|
|
|
|
|
|
#if IPC_PATCH
|
|
|
|
for (Monitor *m = mons; m; m = m->next) {
|
|
|
|
if (m->sel == c && strcmp(oldname, c->name) != 0)
|
|
|
|
ipc_focused_title_change_event(m->num, c->win, oldname, c->name);
|
|
|
|
}
|
|
|
|
#endif // IPC_PATCH
|
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);
|
2020-07-18 11:03:30 +00:00
|
|
|
} else
|
2019-09-04 22:16:39 +00:00
|
|
|
c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
|
2020-07-18 11:03:30 +00:00
|
|
|
if (c->isurgent) {
|
|
|
|
if (c->isfloating)
|
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColFloat].pixel);
|
|
|
|
else
|
2020-08-21 13:49:15 +00:00
|
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel);
|
2019-09-15 22:13:03 +00:00
|
|
|
}
|
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)
|
|
|
|
{
|
2022-02-11 15:57:53 +00:00
|
|
|
#if TAGSYNC_PATCH
|
|
|
|
Monitor *origselmon = selmon;
|
|
|
|
for (selmon = mons; selmon; selmon = selmon->next) {
|
|
|
|
#endif // TAGSYNC_PATCH
|
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
|
2020-09-05 07:11:12 +00:00
|
|
|
{
|
2021-05-30 17:26:27 +00:00
|
|
|
#if TOGGLETAG_PATCH
|
2020-09-05 07:11:12 +00:00
|
|
|
view(&((Arg) { .ui = 0 }));
|
2021-05-30 17:26:27 +00:00
|
|
|
#endif // TOGGLETAG_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
return;
|
2021-05-30 17:22:00 +00:00
|
|
|
}
|
2019-09-04 22:16:39 +00:00
|
|
|
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);
|
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
|
2022-02-11 15:57:53 +00:00
|
|
|
#if TAGSYNC_PATCH
|
|
|
|
}
|
|
|
|
selmon = origselmon;
|
|
|
|
#endif // TAGSYNC_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
focus(NULL);
|
2022-02-11 15:57:53 +00:00
|
|
|
#if TAGSYNC_PATCH
|
|
|
|
arrange(NULL);
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
arrange(selmon);
|
2022-02-11 15:57:53 +00:00
|
|
|
#endif // TAGSYNC_PATCH
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_EWMHTAGS_PATCH
|
2019-09-11 22:48:29 +00:00
|
|
|
updatecurrentdesktop();
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_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;
|
2020-07-18 16:58:39 +00:00
|
|
|
Bar *bar;
|
2019-09-04 22:16:39 +00:00
|
|
|
|
|
|
|
if (w == root && getrootptr(&x, &y))
|
|
|
|
return recttomon(x, y, 1, 1);
|
|
|
|
for (m = mons; m; m = m->next)
|
2020-07-18 16:58:39 +00:00
|
|
|
for (bar = m->bar; bar; bar = bar->next)
|
|
|
|
if (w == bar->win)
|
2020-07-15 06:57:30 +00:00
|
|
|
return m;
|
2019-09-04 22:16:39 +00:00
|
|
|
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;
|
2020-08-22 07:21:23 +00:00
|
|
|
if (arg && arg->v)
|
|
|
|
c = (Client*)arg->v;
|
|
|
|
if (!c)
|
|
|
|
return;
|
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-08-22 07:21:23 +00:00
|
|
|
#if ZOOMFLOATING_PATCH
|
|
|
|
if (c && c->isfloating)
|
|
|
|
togglefloating(&((Arg) { .v = c }));
|
|
|
|
#endif // ZOOMFLOATING_PATCH
|
|
|
|
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
2020-08-22 07:26:30 +00:00
|
|
|
c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->mon->clients);
|
2020-01-29 07:31:00 +00:00
|
|
|
#endif // SWAPFOCUS_PATCH
|
|
|
|
|
2020-08-22 07:21:23 +00:00
|
|
|
if (!c->mon->lt[c->mon->sellt]->arrange
|
|
|
|
|| (c && c->isfloating)
|
2019-09-05 21:19:23 +00:00
|
|
|
#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-08-22 07:21:23 +00:00
|
|
|
if (c == nexttiled(c->mon->clients)) {
|
2020-01-15 12:21:56 +00:00
|
|
|
#if PERTAG_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
p = c->mon->pertag->prevzooms[c->mon->pertag->curtag];
|
2020-01-15 12:21:56 +00:00
|
|
|
#else
|
|
|
|
p = prevzoom;
|
|
|
|
#endif // PERTAG_PATCH
|
2020-08-04 11:40:09 +00:00
|
|
|
at = findbefore(p);
|
2020-01-15 12:21:56 +00:00
|
|
|
if (at)
|
|
|
|
cprevious = nexttiled(at->next);
|
|
|
|
if (!cprevious || cprevious != p) {
|
2019-09-05 21:19:23 +00:00
|
|
|
#if PERTAG_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
c->mon->pertag->prevzooms[c->mon->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
|
2020-08-22 07:21:23 +00:00
|
|
|
if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next)))
|
2020-01-29 07:31:00 +00:00
|
|
|
#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
|
2020-08-22 07:21:23 +00:00
|
|
|
c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = cprevious;
|
2020-01-29 07:31:00 +00:00
|
|
|
#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-08-22 07:21:23 +00:00
|
|
|
cold = nexttiled(c->mon->clients);
|
2020-01-15 12:21:56 +00:00
|
|
|
if (c != cold && !at)
|
2020-08-04 11:40:09 +00:00
|
|
|
at = findbefore(c);
|
2020-01-15 12:21:56 +00:00
|
|
|
detach(c);
|
|
|
|
attach(c);
|
|
|
|
/* swap windows instead of pushing the previous one down */
|
|
|
|
if (c != cold && at) {
|
|
|
|
#if PERTAG_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
c->mon->pertag->prevzooms[c->mon->pertag->curtag] = cold;
|
2020-01-15 12:21:56 +00:00
|
|
|
#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
|
2020-08-22 07:21:23 +00:00
|
|
|
if (c == nexttiled(c->mon->clients))
|
2020-01-29 07:31:00 +00:00
|
|
|
#if SWAPFOCUS_PATCH && PERTAG_PATCH
|
2020-08-22 07:21:23 +00:00
|
|
|
if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next)))
|
2020-01-29 07:31:00 +00:00
|
|
|
#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 */
|
2020-07-15 06:57:30 +00:00
|
|
|
#if BAR_PANGO_PATCH
|
2020-06-14 13:52:47 +00:00
|
|
|
strcpy(font, argv[++i]);
|
|
|
|
#else
|
2019-10-05 21:56:43 +00:00
|
|
|
fonts[0] = argv[++i];
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // BAR_PANGO_PATCH
|
|
|
|
#if !BAR_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-07-15 06:57:30 +00:00
|
|
|
#endif // !BAR_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-07-15 06:57:30 +00:00
|
|
|
#if XRDB_PATCH && !BAR_VTCOLORS_PATCH
|
2019-09-15 20:45:22 +00:00
|
|
|
XrmInitialize();
|
|
|
|
loadxrdb();
|
2020-07-15 06:57:30 +00:00
|
|
|
#endif // XRDB_PATCH && !BAR_VTCOLORS_PATCH
|
2020-08-10 08:22:21 +00:00
|
|
|
#if COOL_AUTOSTART_PATCH
|
|
|
|
autostart_exec();
|
|
|
|
#endif // COOL_AUTOSTART_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
setup();
|
|
|
|
#ifdef __OpenBSD__
|
2020-09-11 15:21:38 +00:00
|
|
|
#if SWALLOW_PATCH
|
|
|
|
if (pledge("stdio rpath proc exec ps", NULL) == -1)
|
|
|
|
#else
|
2019-09-04 22:16:39 +00:00
|
|
|
if (pledge("stdio rpath proc exec", NULL) == -1)
|
2020-09-11 15:21:38 +00:00
|
|
|
#endif // SWALLOW_PATCH
|
2019-09-04 22:16:39 +00:00
|
|
|
die("pledge");
|
|
|
|
#endif /* __OpenBSD__ */
|
|
|
|
scan();
|
2019-09-06 21:37:30 +00:00
|
|
|
#if AUTOSTART_PATCH
|
2020-06-14 17:56:52 +00:00
|
|
|
runautostart();
|
2019-09-06 21:37:30 +00:00
|
|
|
#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;
|
|
|
|
}
|
2021-06-14 05:16:17 +00:00
|
|
|
|