Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4677 lines
124 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. /* See LICENSE file for copyright and license details.
  2. *
  3. * dynamic window manager is designed like any other X client as well. It is
  4. * driven through handling X events. In contrast to other X clients, a window
  5. * manager selects for SubstructureRedirectMask on the root window, to receive
  6. * events about window (dis-)appearance. Only one X connection at a time is
  7. * allowed to select for this event mask.
  8. *
  9. * The event handlers of dwm are organized in an array which is accessed
  10. * whenever a new event has been fetched. This allows event dispatching
  11. * in O(1) time.
  12. *
  13. * Each child of the root window is called a client, except windows which have
  14. * set the override_redirect flag. Clients are organized in a linked client
  15. * list on each monitor, the focus history is remembered through a stack list
  16. * on each monitor. Each client contains a bit array to indicate the tags of a
  17. * client.
  18. *
  19. * Keys and tagging rules are organized as arrays and defined in config.h.
  20. *
  21. * To understand everything else, start reading main().
  22. */
  23. #include <errno.h>
  24. #include <locale.h>
  25. #include <signal.h>
  26. #include <stdarg.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #include <sys/types.h>
  32. #include <sys/wait.h>
  33. #include <X11/cursorfont.h>
  34. #include <X11/keysym.h>
  35. #include <X11/Xatom.h>
  36. #include <X11/Xlib.h>
  37. #include <X11/Xproto.h>
  38. #include <X11/Xutil.h>
  39. #ifdef XINERAMA
  40. #include <X11/extensions/Xinerama.h>
  41. #endif /* XINERAMA */
  42. #include <X11/Xft/Xft.h>
  43. #include "patches.h"
  44. #include "drw.h"
  45. #include "util.h"
  46. #if BAR_FLEXWINTITLE_PATCH
  47. #ifndef FLEXTILE_DELUXE_LAYOUT
  48. #define FLEXTILE_DELUXE_LAYOUT 1
  49. #endif
  50. #endif
  51. #if BAR_PANGO_PATCH
  52. #include <pango/pango.h>
  53. #endif // BAR_PANGO_PATCH
  54. #if SPAWNCMD_PATCH
  55. #include <assert.h>
  56. #include <libgen.h>
  57. #include <sys/stat.h>
  58. #define SPAWN_CWD_DELIM " []{}()<>\"':"
  59. #endif // SPAWNCMD_PATCH
  60. /* macros */
  61. #define Button6 6
  62. #define Button7 7
  63. #define Button8 8
  64. #define Button9 9
  65. #define NUMTAGS 9
  66. #define BARRULES 20
  67. #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
  68. #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
  69. #if BAR_ANYBAR_PATCH
  70. #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
  71. * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
  72. #else
  73. #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
  74. * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
  75. #endif // BAR_ANYBAR_PATCH
  76. #if ATTACHASIDE_PATCH && STICKY_PATCH
  77. #define ISVISIBLEONTAG(C, T) ((C->tags & T) || C->issticky)
  78. #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags])
  79. #elif ATTACHASIDE_PATCH
  80. #define ISVISIBLEONTAG(C, T) ((C->tags & T))
  81. #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags])
  82. #elif STICKY_PATCH
  83. #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
  84. #else
  85. #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
  86. #endif // ATTACHASIDE_PATCH
  87. #define LENGTH(X) (sizeof X / sizeof X[0])
  88. #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
  89. #define WIDTH(X) ((X)->w + 2 * (X)->bw)
  90. #define HEIGHT(X) ((X)->h + 2 * (X)->bw)
  91. #define WTYPE "_NET_WM_WINDOW_TYPE_"
  92. #if SCRATCHPADS_PATCH
  93. #define TOTALTAGS (NUMTAGS + LENGTH(scratchpads))
  94. #define TAGMASK ((1 << TOTALTAGS) - 1)
  95. #define SPTAG(i) ((1 << NUMTAGS) << (i))
  96. #define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << NUMTAGS)
  97. #else
  98. #define TAGMASK ((1 << NUMTAGS) - 1)
  99. #endif // SCRATCHPADS_PATCH
  100. #define TEXTWM(X) (drw_fontset_getwidth(drw, (X), True) + lrpad)
  101. #define TEXTW(X) (drw_fontset_getwidth(drw, (X), False) + lrpad)
  102. #define HIDDEN(C) ((getstate(C->win) == IconicState))
  103. /* enums */
  104. enum {
  105. #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
  106. CurResizeBR,
  107. CurResizeBL,
  108. CurResizeTR,
  109. CurResizeTL,
  110. #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
  111. #if DRAGMFACT_PATCH
  112. CurResizeHorzArrow,
  113. CurResizeVertArrow,
  114. #endif // DRAGMFACT_PATCH
  115. #if DRAGCFACT_PATCH
  116. CurIronCross,
  117. #endif // DRAGCFACT_PATCH
  118. CurNormal,
  119. CurResize,
  120. CurMove,
  121. CurLast
  122. }; /* cursor */
  123. enum {
  124. SchemeNorm,
  125. SchemeSel,
  126. SchemeTitleNorm,
  127. SchemeTitleSel,
  128. SchemeTagsNorm,
  129. SchemeTagsSel,
  130. SchemeHid,
  131. SchemeUrg,
  132. #if BAR_FLEXWINTITLE_PATCH
  133. SchemeFlexActTTB,
  134. SchemeFlexActLTR,
  135. SchemeFlexActMONO,
  136. SchemeFlexActGRID,
  137. SchemeFlexActGRD1,
  138. SchemeFlexActGRD2,
  139. SchemeFlexActGRDM,
  140. SchemeFlexActHGRD,
  141. SchemeFlexActDWDL,
  142. SchemeFlexActSPRL,
  143. SchemeFlexInaTTB,
  144. SchemeFlexInaLTR,
  145. SchemeFlexInaMONO,
  146. SchemeFlexInaGRID,
  147. SchemeFlexInaGRD1,
  148. SchemeFlexInaGRD2,
  149. SchemeFlexInaGRDM,
  150. SchemeFlexInaHGRD,
  151. SchemeFlexInaDWDL,
  152. SchemeFlexInaSPRL,
  153. SchemeFlexSelTTB,
  154. SchemeFlexSelLTR,
  155. SchemeFlexSelMONO,
  156. SchemeFlexSelGRID,
  157. SchemeFlexSelGRD1,
  158. SchemeFlexSelGRD2,
  159. SchemeFlexSelGRDM,
  160. SchemeFlexSelHGRD,
  161. SchemeFlexSelDWDL,
  162. SchemeFlexSelSPRL,
  163. SchemeFlexActFloat,
  164. SchemeFlexInaFloat,
  165. SchemeFlexSelFloat,
  166. #endif // BAR_FLEXWINTITLE_PATCH
  167. }; /* color schemes */
  168. enum {
  169. NetSupported, NetWMName, NetWMState, NetWMCheck,
  170. NetWMFullscreen, NetActiveWindow, NetWMWindowType,
  171. #if BAR_SYSTRAY_PATCH
  172. NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
  173. NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz,
  174. #endif // BAR_SYSTRAY_PATCH
  175. #if BAR_EWMHTAGS_PATCH
  176. NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop,
  177. #endif // BAR_EWMHTAGS_PATCH
  178. NetClientList,
  179. #if NET_CLIENT_LIST_STACKING_PATCH
  180. NetClientListStacking,
  181. #endif // NET_CLIENT_LIST_STACKING_PATCH
  182. NetLast
  183. }; /* EWMH atoms */
  184. enum {
  185. WMProtocols,
  186. WMDelete,
  187. WMState,
  188. WMTakeFocus,
  189. #if WINDOWROLERULE_PATCH
  190. WMWindowRole,
  191. #endif // WINDOWROLERULE_PATCH
  192. WMLast
  193. }; /* default atoms */
  194. enum {
  195. #if BAR_STATUSBUTTON_PATCH
  196. ClkButton,
  197. #endif // BAR_STATUSBUTTON_PATCH
  198. ClkTagBar,
  199. ClkLtSymbol,
  200. ClkStatusText,
  201. ClkWinTitle,
  202. ClkClientWin,
  203. ClkRootWin,
  204. ClkLast
  205. }; /* clicks */
  206. enum {
  207. BAR_ALIGN_LEFT,
  208. BAR_ALIGN_CENTER,
  209. BAR_ALIGN_RIGHT,
  210. BAR_ALIGN_LEFT_LEFT,
  211. BAR_ALIGN_LEFT_RIGHT,
  212. BAR_ALIGN_LEFT_CENTER,
  213. BAR_ALIGN_NONE,
  214. BAR_ALIGN_RIGHT_LEFT,
  215. BAR_ALIGN_RIGHT_RIGHT,
  216. BAR_ALIGN_RIGHT_CENTER,
  217. BAR_ALIGN_LAST
  218. }; /* bar alignment */
  219. #if IPC_PATCH
  220. typedef struct TagState TagState;
  221. struct TagState {
  222. int selected;
  223. int occupied;
  224. int urgent;
  225. };
  226. typedef struct ClientState ClientState;
  227. struct ClientState {
  228. int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
  229. };
  230. #endif // IPC_PATCH
  231. typedef union {
  232. #if IPC_PATCH
  233. long i;
  234. unsigned long ui;
  235. #else
  236. int i;
  237. unsigned int ui;
  238. #endif // IPC_PATCH
  239. float f;
  240. const void *v;
  241. } Arg;
  242. typedef struct Monitor Monitor;
  243. typedef struct Bar Bar;
  244. struct Bar {
  245. Window win;
  246. Monitor *mon;
  247. Bar *next;
  248. int idx;
  249. int showbar;
  250. int topbar;
  251. int external;
  252. int borderpx;
  253. int borderscheme;
  254. int bx, by, bw, bh; /* bar geometry */
  255. int w[BARRULES]; // width, array length == barrules, then use r index for lookup purposes
  256. int x[BARRULES]; // x position, array length == ^
  257. };
  258. typedef struct {
  259. int x;
  260. int y;
  261. int h;
  262. int w;
  263. } BarArg;
  264. typedef struct {
  265. int monitor;
  266. int bar;
  267. int alignment; // see bar alignment enum
  268. int (*widthfunc)(Bar *bar, BarArg *a);
  269. int (*drawfunc)(Bar *bar, BarArg *a);
  270. int (*clickfunc)(Bar *bar, Arg *arg, BarArg *a);
  271. char *name; // for debugging
  272. int x, w; // position, width for internal use
  273. } BarRule;
  274. typedef struct {
  275. unsigned int click;
  276. unsigned int mask;
  277. unsigned int button;
  278. void (*func)(const Arg *arg);
  279. const Arg arg;
  280. } Button;
  281. typedef struct Client Client;
  282. struct Client {
  283. char name[256];
  284. float mina, maxa;
  285. #if CFACTS_PATCH
  286. float cfact;
  287. #endif // CFACTS_PATCH
  288. int x, y, w, h;
  289. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  290. int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
  291. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  292. int oldx, oldy, oldw, oldh;
  293. int basew, baseh, incw, inch, maxw, maxh, minw, minh;
  294. int bw, oldbw;
  295. unsigned int tags;
  296. #if SWITCHTAG_PATCH
  297. unsigned int switchtag;
  298. #endif // SWITCHTAG_PATCH
  299. int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
  300. #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
  301. int fakefullscreen;
  302. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  303. #if EXRESIZE_PATCH
  304. unsigned char expandmask;
  305. int expandx1, expandy1, expandx2, expandy2;
  306. #if !MAXIMIZE_PATCH
  307. int wasfloating;
  308. #endif // MAXIMIZE_PATCH
  309. #endif // EXRESIZE_PATCH
  310. #if MAXIMIZE_PATCH
  311. int ismax, wasfloating;
  312. #endif // MAXIMIZE_PATCH
  313. #if AUTORESIZE_PATCH
  314. int needresize;
  315. #endif // AUTORESIZE_PATCH
  316. #if CENTER_PATCH
  317. int iscentered;
  318. #endif // CENTER_PATCH
  319. #if ISPERMANENT_PATCH
  320. int ispermanent;
  321. #endif // ISPERMANENT_PATCH
  322. #if PLACEMOUSE_PATCH
  323. int beingmoved;
  324. #endif // PLACEMOUSE_PATCH
  325. #if SWALLOW_PATCH
  326. int isterminal, noswallow;
  327. pid_t pid;
  328. #endif // SWALLOW_PATCH
  329. #if STEAM_PATCH
  330. int issteam;
  331. #endif // STEAM_PATCH
  332. #if STICKY_PATCH
  333. int issticky;
  334. #endif // STICKY_PATCH
  335. Client *next;
  336. Client *snext;
  337. #if SWALLOW_PATCH
  338. Client *swallowing;
  339. #endif // SWALLOW_PATCH
  340. Monitor *mon;
  341. Window win;
  342. #if IPC_PATCH
  343. ClientState prevstate;
  344. #endif // IPC_PATCH
  345. };
  346. typedef struct {
  347. unsigned int mod;
  348. KeySym keysym;
  349. void (*func)(const Arg *);
  350. const Arg arg;
  351. } Key;
  352. #if FLEXTILE_DELUXE_LAYOUT
  353. typedef struct {
  354. int nmaster;
  355. int nstack;
  356. int layout;
  357. int masteraxis; // master stack area
  358. int stack1axis; // primary stack area
  359. int stack2axis; // secondary stack area, e.g. centered master
  360. void (*symbolfunc)(Monitor *, unsigned int);
  361. } LayoutPreset;
  362. #endif // FLEXTILE_DELUXE_LAYOUT
  363. typedef struct {
  364. const char *symbol;
  365. void (*arrange)(Monitor *);
  366. #if FLEXTILE_DELUXE_LAYOUT
  367. LayoutPreset preset;
  368. #endif // FLEXTILE_DELUXE_LAYOUT
  369. } Layout;
  370. #if INSETS_PATCH
  371. typedef struct {
  372. int x;
  373. int y;
  374. int w;
  375. int h;
  376. } Inset;
  377. #endif // INSETS_PATCH
  378. #if PERTAG_PATCH
  379. typedef struct Pertag Pertag;
  380. #endif // PERTAG_PATCH
  381. struct Monitor {
  382. int index;
  383. char ltsymbol[16];
  384. float mfact;
  385. #if FLEXTILE_DELUXE_LAYOUT
  386. int ltaxis[4];
  387. int nstack;
  388. #endif // FLEXTILE_DELUXE_LAYOUT
  389. int nmaster;
  390. int num;
  391. int mx, my, mw, mh; /* screen size */
  392. int wx, wy, ww, wh; /* window area */
  393. #if VANITYGAPS_PATCH
  394. int gappih; /* horizontal gap between windows */
  395. int gappiv; /* vertical gap between windows */
  396. int gappoh; /* horizontal outer gaps */
  397. int gappov; /* vertical outer gaps */
  398. #endif // VANITYGAPS_PATCH
  399. #if SETBORDERPX_PATCH
  400. unsigned int borderpx;
  401. #endif // SETBORDERPX_PATCH
  402. unsigned int seltags;
  403. unsigned int sellt;
  404. unsigned int tagset[2];
  405. int showbar;
  406. Client *clients;
  407. Client *sel;
  408. Client *stack;
  409. Monitor *next;
  410. Bar *bar;
  411. const Layout *lt[2];
  412. #if BAR_ALTERNATIVE_TAGS_PATCH
  413. unsigned int alttag;
  414. #endif // BAR_ALTERNATIVE_TAGS_PATCH
  415. #if PERTAG_PATCH
  416. Pertag *pertag;
  417. #endif // PERTAG_PATCH
  418. #if INSETS_PATCH
  419. Inset inset;
  420. #endif // INSETS_PATCH
  421. #if IPC_PATCH
  422. char lastltsymbol[16];
  423. TagState tagstate;
  424. Client *lastsel;
  425. const Layout *lastlt;
  426. #endif // IPC_PATCH
  427. };
  428. typedef struct {
  429. const char *class;
  430. #if WINDOWROLERULE_PATCH
  431. const char *role;
  432. #endif // WINDOWROLERULE_PATCH
  433. const char *instance;
  434. const char *title;
  435. const char *wintype;
  436. unsigned int tags;
  437. #if SWITCHTAG_PATCH
  438. int switchtag;
  439. #endif // SWITCHTAG_PATCH
  440. #if CENTER_PATCH
  441. int iscentered;
  442. #endif // CENTER_PATCH
  443. int isfloating;
  444. #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
  445. int isfakefullscreen;
  446. #endif // SELECTIVEFAKEFULLSCREEN_PATCH
  447. #if ISPERMANENT_PATCH
  448. int ispermanent;
  449. #endif // ISPERMANENT_PATCH
  450. #if SWALLOW_PATCH
  451. int isterminal;
  452. int noswallow;
  453. #endif // SWALLOW_PATCH
  454. #if FLOATPOS_PATCH
  455. const char *floatpos;
  456. #endif // FLOATPOS_PATCH
  457. int monitor;
  458. } Rule;
  459. #define RULE(...) { .monitor = -1, ##__VA_ARGS__ },
  460. /* Cross patch compatibility rule macro helper macros */
  461. #define FLOATING , .isfloating = 1
  462. #if CENTER_PATCH
  463. #define CENTERED , .iscentered = 1
  464. #else
  465. #define CENTERED
  466. #endif // CENTER_PATCH
  467. #if ISPERMANENT_PATCH
  468. #define PERMANENT , .ispermanent = 1
  469. #else
  470. #define PERMANENT
  471. #endif // ISPERMANENT_PATCH
  472. #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
  473. #define FAKEFULLSCREEN , .isfakefullscreen = 1
  474. #else
  475. #define FAKEFULLSCREEN
  476. #endif // SELECTIVEFAKEFULLSCREEN_PATCH
  477. #if SWALLOW_PATCH
  478. #define NOSWALLOW , .noswallow = 1
  479. #define TERMINAL , .isterminal = 1
  480. #else
  481. #define NOSWALLOW
  482. #define TERMINAL
  483. #endif // SWALLOW_PATCH
  484. #if SWITCHTAG_PATCH
  485. #define SWITCHTAG , .switchtag = 1
  486. #else
  487. #define SWITCHTAG
  488. #endif // SWITCHTAG_PATCH
  489. #if MONITOR_RULES_PATCH
  490. typedef struct {
  491. int monitor;
  492. #if PERTAG_PATCH
  493. int tag;
  494. #endif // PERTAG_PATCH
  495. int layout;
  496. float mfact;
  497. int nmaster;
  498. int showbar;
  499. int topbar;
  500. } MonitorRule;
  501. #endif // MONITOR_RULES_PATCH
  502. /* function declarations */
  503. static void applyrules(Client *c);
  504. static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
  505. static void arrange(Monitor *m);
  506. static void arrangemon(Monitor *m);
  507. static void attach(Client *c);
  508. static void attachstack(Client *c);
  509. static void buttonpress(XEvent *e);
  510. static void checkotherwm(void);
  511. static void cleanup(void);
  512. static void cleanupmon(Monitor *mon);
  513. static void clientmessage(XEvent *e);
  514. static void configure(Client *c);
  515. static void configurenotify(XEvent *e);
  516. static void configurerequest(XEvent *e);
  517. static Monitor *createmon(void);
  518. static void destroynotify(XEvent *e);
  519. static void detach(Client *c);
  520. static void detachstack(Client *c);
  521. static Monitor *dirtomon(int dir);
  522. static void drawbar(Monitor *m);
  523. static void drawbars(void);
  524. static void drawbarwin(Bar *bar);
  525. #if !FOCUSONCLICK_PATCH
  526. static void enternotify(XEvent *e);
  527. #endif // FOCUSONCLICK_PATCH
  528. static void expose(XEvent *e);
  529. static void focus(Client *c);
  530. static void focusin(XEvent *e);
  531. static void focusmon(const Arg *arg);
  532. #if !STACKER_PATCH
  533. static void focusstack(const Arg *arg);
  534. #endif // STACKER_PATCH
  535. static Atom getatomprop(Client *c, Atom prop);
  536. static int getrootptr(int *x, int *y);
  537. static long getstate(Window w);
  538. static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
  539. static void grabbuttons(Client *c, int focused);
  540. #if KEYMODES_PATCH
  541. static void grabdefkeys(void);
  542. #else
  543. static void grabkeys(void);
  544. #endif // KEYMODES_PATCH
  545. static void incnmaster(const Arg *arg);
  546. #if KEYMODES_PATCH
  547. static void keydefpress(XEvent *e);
  548. #else
  549. static void keypress(XEvent *e);
  550. #endif // KEYMODES_PATCH
  551. static void killclient(const Arg *arg);
  552. static void manage(Window w, XWindowAttributes *wa);
  553. static void mappingnotify(XEvent *e);
  554. static void maprequest(XEvent *e);
  555. #if !FOCUSONCLICK_PATCH
  556. static void motionnotify(XEvent *e);
  557. #endif // FOCUSONCLICK_PATCH
  558. static void movemouse(const Arg *arg);
  559. static Client *nexttiled(Client *c);
  560. #if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH
  561. static void pop(Client *);
  562. #endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
  563. static void propertynotify(XEvent *e);
  564. static void quit(const Arg *arg);
  565. static Monitor *recttomon(int x, int y, int w, int h);
  566. static void resize(Client *c, int x, int y, int w, int h, int interact);
  567. static void resizeclient(Client *c, int x, int y, int w, int h);
  568. static void resizemouse(const Arg *arg);
  569. static void restack(Monitor *m);
  570. static void run(void);
  571. static void scan(void);
  572. #if BAR_SYSTRAY_PATCH
  573. static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
  574. #else
  575. static int sendevent(Client *c, Atom proto);
  576. #endif // BAR_SYSTRAY_PATCH
  577. static void sendmon(Client *c, Monitor *m);
  578. static void setclientstate(Client *c, long state);
  579. static void setfocus(Client *c);
  580. static void setfullscreen(Client *c, int fullscreen);
  581. static void setlayout(const Arg *arg);
  582. static void setmfact(const Arg *arg);
  583. static void setup(void);
  584. static void seturgent(Client *c, int urg);
  585. static void showhide(Client *c);
  586. static void sigchld(int unused);
  587. static void spawn(const Arg *arg);
  588. #if RIODRAW_PATCH
  589. static pid_t spawncmd(const Arg *arg);
  590. #endif // RIODRAW_PATCH
  591. static void tag(const Arg *arg);
  592. static void tagmon(const Arg *arg);
  593. static void togglebar(const Arg *arg);
  594. static void togglefloating(const Arg *arg);
  595. static void toggletag(const Arg *arg);
  596. static void toggleview(const Arg *arg);
  597. static void unfocus(Client *c, int setfocus, Client *nextfocus);
  598. static void unmanage(Client *c, int destroyed);
  599. static void unmapnotify(XEvent *e);
  600. static void updatebarpos(Monitor *m);
  601. static void updatebars(void);
  602. static void updateclientlist(void);
  603. static int updategeom(void);
  604. static void updatenumlockmask(void);
  605. static void updatesizehints(Client *c);
  606. static void updatestatus(void);
  607. static void updatetitle(Client *c);
  608. static void updatewmhints(Client *c);
  609. static void view(const Arg *arg);
  610. static Client *wintoclient(Window w);
  611. static Monitor *wintomon(Window w);
  612. static int xerror(Display *dpy, XErrorEvent *ee);
  613. static int xerrordummy(Display *dpy, XErrorEvent *ee);
  614. static int xerrorstart(Display *dpy, XErrorEvent *ee);
  615. static void zoom(const Arg *arg);
  616. /* bar functions */
  617. #include "patch/include.h"
  618. /* variables */
  619. static const char broken[] = "broken";
  620. #if BAR_PANGO_PATCH || BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
  621. static char stext[1024];
  622. #else
  623. static char stext[512];
  624. #endif // BAR_PANGO_PATCH | BAR_STATUS2D_PATCH
  625. #if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH
  626. #if BAR_STATUS2D_PATCH
  627. static char rawstext[1024];
  628. #else
  629. static char rawstext[512];
  630. #endif // BAR_STATUS2D_PATCH
  631. #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
  632. #if BAR_EXTRASTATUS_PATCH
  633. #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
  634. static char estext[1024];
  635. #else
  636. static char estext[512];
  637. #endif // BAR_STATUS2D_PATCH
  638. #if BAR_STATUSCMD_PATCH
  639. static char rawestext[1024];
  640. #endif // BAR_STATUS2D_PATCH | BAR_STATUSCMD_PATCH
  641. #endif // BAR_EXTRASTATUS_PATCH
  642. static int screen;
  643. static int sw, sh; /* X display screen geometry width, height */
  644. static int bh; /* bar geometry */
  645. static int lrpad; /* sum of left and right padding for text */
  646. /* Some clients (e.g. alacritty) helpfully send configure requests with a new size or position
  647. * when they detect that they have been moved to another monitor. This can cause visual glitches
  648. * when moving (or resizing) client windows from one monitor to another. This variable is used
  649. * internally to ignore such configure requests while movemouse or resizemouse are being used. */
  650. static int ignoreconfigurerequests = 0;
  651. #if WARP_PATCH
  652. static int force_warp = 0; // force warp in some situations, e.g. killclient
  653. static int ignore_warp = 0; // force skip warp in some situations, e.g. dragmfact, dragcfact
  654. #endif // WARP_PATCH
  655. static int (*xerrorxlib)(Display *, XErrorEvent *);
  656. static unsigned int numlockmask = 0;
  657. #if RIODRAW_PATCH
  658. static int riodimensions[4] = { -1, -1, -1, -1 };
  659. static pid_t riopid = 0;
  660. #endif // RIODRAW_PATCH
  661. static void (*handler[LASTEvent]) (XEvent *) = {
  662. [ButtonPress] = buttonpress,
  663. #if COMBO_PATCH || BAR_HOLDBAR_PATCH
  664. [ButtonRelease] = keyrelease,
  665. #endif // COMBO_PATCH / BAR_HOLDBAR_PATCH
  666. [ClientMessage] = clientmessage,
  667. [ConfigureRequest] = configurerequest,
  668. [ConfigureNotify] = configurenotify,
  669. [DestroyNotify] = destroynotify,
  670. #if !FOCUSONCLICK_PATCH
  671. [EnterNotify] = enternotify,
  672. #endif // FOCUSONCLICK_PATCH
  673. [Expose] = expose,
  674. [FocusIn] = focusin,
  675. [KeyPress] = keypress,
  676. #if COMBO_PATCH || BAR_HOLDBAR_PATCH
  677. [KeyRelease] = keyrelease,
  678. #endif // COMBO_PATCH / BAR_HOLDBAR_PATCH
  679. [MappingNotify] = mappingnotify,
  680. [MapRequest] = maprequest,
  681. #if !FOCUSONCLICK_PATCH
  682. [MotionNotify] = motionnotify,
  683. #endif // FOCUSONCLICK_PATCH
  684. [PropertyNotify] = propertynotify,
  685. #if BAR_SYSTRAY_PATCH
  686. [ResizeRequest] = resizerequest,
  687. #endif // BAR_SYSTRAY_PATCH
  688. [UnmapNotify] = unmapnotify
  689. };
  690. #if BAR_SYSTRAY_PATCH
  691. static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
  692. #else
  693. static Atom wmatom[WMLast], netatom[NetLast];
  694. #endif // BAR_SYSTRAY_PATCH
  695. #if ON_EMPTY_KEYS_PATCH
  696. static int isempty = 0;
  697. #endif // ON_EMPTY_KEYS_PATCH
  698. static int running = 1;
  699. static Cur *cursor[CurLast];
  700. static Clr **scheme;
  701. static Display *dpy;
  702. static Drw *drw;
  703. static Monitor *mons, *selmon;
  704. static Window root, wmcheckwin;
  705. /* configuration, allows nested code to access above variables */
  706. #include "config.h"
  707. #include "theme.h"
  708. #include "rules.h"
  709. #include "keybind.h"
  710. #include "patch/include.c"
  711. /* compile-time check if all tags fit into an unsigned int bit array. */
  712. #if SCRATCHPAD_ALT_1_PATCH
  713. struct NumTags { char limitexceeded[NUMTAGS > 30 ? -1 : 1]; };
  714. #else
  715. struct NumTags { char limitexceeded[NUMTAGS > 31 ? -1 : 1]; };
  716. #endif // SCRATCHPAD_ALT_1_PATCH
  717. /* function implementations */
  718. void
  719. applyrules(Client *c)
  720. {
  721. const char *class, *instance;
  722. Atom wintype;
  723. #if WINDOWROLERULE_PATCH
  724. char role[64];
  725. #endif // WINDOWROLERULE_PATCH
  726. unsigned int i;
  727. #if SWITCHTAG_PATCH
  728. unsigned int newtagset;
  729. #endif // SWITCHTAG_PATCH
  730. const Rule *r;
  731. Monitor *m;
  732. XClassHint ch = { NULL, NULL };
  733. /* rule matching */
  734. #if SWALLOW_PATCH
  735. c->noswallow = -1;
  736. #endif // SWALLOW_PATCH
  737. c->isfloating = 0;
  738. c->tags = 0;
  739. XGetClassHint(dpy, c->win, &ch);
  740. class = ch.res_class ? ch.res_class : broken;
  741. instance = ch.res_name ? ch.res_name : broken;
  742. wintype = getatomprop(c, netatom[NetWMWindowType]);
  743. #if WINDOWROLERULE_PATCH
  744. gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
  745. #endif // WINDOWROLERULE_PATCH
  746. #if STEAM_PATCH
  747. if (strstr(class, "Steam") || strstr(class, "steam_app_"))
  748. c->issteam = 1;
  749. #endif // STEAM_PATCH
  750. for (i = 0; i < LENGTH(rules); i++) {
  751. r = &rules[i];
  752. if ((!r->title || strstr(c->name, r->title))
  753. && (!r->class || strstr(class, r->class))
  754. #if WINDOWROLERULE_PATCH
  755. && (!r->role || strstr(role, r->role))
  756. #endif // WINDOWROLERULE_PATCH
  757. && (!r->instance || strstr(instance, r->instance))
  758. && (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False)))
  759. {
  760. #if CENTER_PATCH
  761. c->iscentered = r->iscentered;
  762. #endif // CENTER_PATCH
  763. #if ISPERMANENT_PATCH
  764. c->ispermanent = r->ispermanent;
  765. #endif // ISPERMANENT_PATCH
  766. #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
  767. c->fakefullscreen = r->isfakefullscreen;
  768. #endif // SELECTIVEFAKEFULLSCREEN_PATCH
  769. #if SWALLOW_PATCH
  770. c->isterminal = r->isterminal;
  771. c->noswallow = r->noswallow;
  772. #endif // SWALLOW_PATCH
  773. c->isfloating = r->isfloating;
  774. c->tags |= r->tags;
  775. #if SCRATCHPADS_PATCH
  776. if ((r->tags & SPTAGMASK) && r->isfloating) {
  777. c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
  778. c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
  779. }
  780. #endif // SCRATCHPADS_PATCH
  781. for (m = mons; m && m->num != r->monitor; m = m->next);
  782. if (m)
  783. c->mon = m;
  784. #if FLOATPOS_PATCH
  785. if (c->isfloating && r->floatpos) {
  786. #if CENTER_PATCH
  787. c->iscentered = 0;
  788. #endif // CENTER_PATCH
  789. setfloatpos(c, r->floatpos);
  790. }
  791. #endif // FLOATPOS_PATCH
  792. #if SWITCHTAG_PATCH
  793. #if SWALLOW_PATCH
  794. if (r->switchtag && (
  795. c->noswallow > 0 ||
  796. !termforwin(c) ||
  797. !(c->isfloating && swallowfloating && c->noswallow < 0)))
  798. #else
  799. if (r->switchtag)
  800. #endif // SWALLOW_PATCH
  801. {
  802. selmon = c->mon;
  803. if (r->switchtag == 2 || r->switchtag == 4)
  804. newtagset = c->mon->tagset[c->mon->seltags] ^ c->tags;
  805. else
  806. newtagset = c->tags;
  807. /* Switch to the client's tag, but only if that tag is not already shown */
  808. if (newtagset && !(c->tags & c->mon->tagset[c->mon->seltags])) {
  809. if (r->switchtag == 3 || r->switchtag == 4)
  810. c->switchtag = c->mon->tagset[c->mon->seltags];
  811. if (r->switchtag == 1 || r->switchtag == 3) {
  812. #if PERTAG_PATCH
  813. pertagview(&((Arg) { .ui = newtagset }));
  814. arrange(c->mon);
  815. #else
  816. view(&((Arg) { .ui = newtagset }));
  817. #endif // PERTAG_PATCH
  818. } else {
  819. c->mon->tagset[c->mon->seltags] = newtagset;
  820. arrange(c->mon);
  821. }
  822. }
  823. }
  824. #endif // SWITCHTAG_PATCH
  825. #if ONLY_ONE_RULE_MATCH_PATCH
  826. break;
  827. #endif // ONLY_ONE_RULE_MATCH_PATCH
  828. }
  829. }
  830. if (ch.res_class)
  831. XFree(ch.res_class);
  832. if (ch.res_name)
  833. XFree(ch.res_name);
  834. #if EMPTYVIEW_PATCH
  835. if (c->tags & TAGMASK) c->tags = c->tags & TAGMASK;
  836. #if SCRATCHPADS_PATCH
  837. else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags] & ~SPTAGMASK;
  838. #elif SCRATCHPAD_ALT_1_PATCH
  839. else if (c->tags != SCRATCHPAD_MASK && c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags];
  840. #else
  841. else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags];
  842. #endif // SCRATCHPADS_PATCH
  843. else c->tags = 1;
  844. #elif SCRATCHPADS_PATCH
  845. c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK);
  846. #elif SCRATCHPAD_ALT_1_PATCH
  847. if (c->tags != SCRATCHPAD_MASK)
  848. c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
  849. #else
  850. c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
  851. #endif // EMPTYVIEW_PATCH
  852. }
  853. int
  854. applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
  855. {
  856. int baseismin;
  857. Monitor *m = c->mon;
  858. /* set minimum possible */
  859. *w = MAX(1, *w);
  860. *h = MAX(1, *h);
  861. if (interact) {
  862. if (*x > sw)
  863. *x = sw - WIDTH(c);
  864. if (*y > sh)
  865. *y = sh - HEIGHT(c);
  866. if (*x + *w + 2 * c->bw < 0)
  867. *x = 0;
  868. if (*y + *h + 2 * c->bw < 0)
  869. *y = 0;
  870. } else {
  871. if (*x >= m->wx + m->ww)
  872. *x = m->wx + m->ww - WIDTH(c);
  873. if (*y >= m->wy + m->wh)
  874. *y = m->wy + m->wh - HEIGHT(c);
  875. if (*x + *w + 2 * c->bw <= m->wx)
  876. *x = m->wx;
  877. if (*y + *h + 2 * c->bw <= m->wy)
  878. *y = m->wy;
  879. }
  880. if (*h < bh)
  881. *h = bh;
  882. if (*w < bh)
  883. *w = bh;
  884. if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
  885. /* see last two sentences in ICCCM 4.1.2.3 */
  886. baseismin = c->basew == c->minw && c->baseh == c->minh;
  887. if (!baseismin) { /* temporarily remove base dimensions */
  888. *w -= c->basew;
  889. *h -= c->baseh;
  890. }
  891. /* adjust for aspect limits */
  892. if (c->mina > 0 && c->maxa > 0) {
  893. if (c->maxa < (float)*w / *h)
  894. *w = *h * c->maxa + 0.5;
  895. else if (c->mina < (float)*h / *w)
  896. *h = *w * c->mina + 0.5;
  897. }
  898. if (baseismin) { /* increment calculation requires this */
  899. *w -= c->basew;
  900. *h -= c->baseh;
  901. }
  902. /* adjust for increment value */
  903. if (c->incw)
  904. *w -= *w % c->incw;
  905. if (c->inch)
  906. *h -= *h % c->inch;
  907. /* restore base dimensions */
  908. *w = MAX(*w + c->basew, c->minw);
  909. *h = MAX(*h + c->baseh, c->minh);
  910. if (c->maxw)
  911. *w = MIN(*w, c->maxw);
  912. if (c->maxh)
  913. *h = MIN(*h, c->maxh);
  914. }
  915. return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
  916. }
  917. void
  918. arrange(Monitor *m)
  919. {
  920. if (m)
  921. showhide(m->stack);
  922. else for (m = mons; m; m = m->next)
  923. showhide(m->stack);
  924. if (m) {
  925. arrangemon(m);
  926. restack(m);
  927. } else for (m = mons; m; m = m->next)
  928. arrangemon(m);
  929. }
  930. void
  931. arrangemon(Monitor *m)
  932. {
  933. strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
  934. if (m->lt[m->sellt]->arrange)
  935. m->lt[m->sellt]->arrange(m);
  936. #if ROUNDED_CORNERS_PATCH
  937. Client *c;
  938. for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
  939. drawroundedcorners(c);
  940. #endif // ROUNDED_CORNERS_PATCH
  941. }
  942. void
  943. attach(Client *c)
  944. {
  945. c->next = c->mon->clients;
  946. c->mon->clients = c;
  947. }
  948. void
  949. attachstack(Client *c)
  950. {
  951. c->snext = c->mon->stack;
  952. c->mon->stack = c;
  953. }
  954. void
  955. buttonpress(XEvent *e)
  956. {
  957. int click, i, r;
  958. Arg arg = {0};
  959. Client *c;
  960. Monitor *m;
  961. Bar *bar;
  962. XButtonPressedEvent *ev = &e->xbutton;
  963. const BarRule *br;
  964. BarArg carg = { 0, 0, 0, 0 };
  965. click = ClkRootWin;
  966. /* focus monitor if necessary */
  967. if ((m = wintomon(ev->window)) && m != selmon
  968. #if FOCUSONCLICK_PATCH
  969. && (focusonwheel || (ev->button != Button4 && ev->button != Button5))
  970. #endif // FOCUSONCLICK_PATCH
  971. ) {
  972. unfocus(selmon->sel, 1, NULL);
  973. selmon = m;
  974. focus(NULL);
  975. }
  976. for (bar = selmon->bar; bar; bar = bar->next) {
  977. if (ev->window == bar->win) {
  978. for (r = 0; r < LENGTH(barrules); r++) {
  979. br = &barrules[r];
  980. if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL)
  981. continue;
  982. if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->index)
  983. continue;
  984. if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) {
  985. carg.x = ev->x - bar->x[r];
  986. carg.y = ev->y - bar->borderpx;
  987. carg.w = bar->w[r];
  988. carg.h = bar->bh - 2 * bar->borderpx;
  989. click = br->clickfunc(bar, &arg, &carg);
  990. if (click < 0)
  991. return;
  992. break;
  993. }
  994. }
  995. break;
  996. }
  997. }
  998. if (click == ClkRootWin && (c = wintoclient(ev->window))) {
  999. #if FOCUSONCLICK_PATCH
  1000. if (focusonwheel || (ev->button != Button4 && ev->button != Button5))
  1001. focus(c);
  1002. #else
  1003. focus(c);
  1004. restack(selmon);
  1005. #endif // FOCUSONCLICK_PATCH
  1006. XAllowEvents(dpy, ReplayPointer, CurrentTime);
  1007. click = ClkClientWin;
  1008. }
  1009. for (i = 0; i < LENGTH(buttons); i++) {
  1010. if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
  1011. && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
  1012. #if BAR_WINTITLEACTIONS_PATCH
  1013. buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
  1014. #else
  1015. buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
  1016. #endif // BAR_WINTITLEACTIONS_PATCH
  1017. }
  1018. }
  1019. }
  1020. void
  1021. checkotherwm(void)
  1022. {
  1023. xerrorxlib = XSetErrorHandler(xerrorstart);
  1024. /* this causes an error if some other window manager is running */
  1025. XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
  1026. XSync(dpy, False);
  1027. XSetErrorHandler(xerror);
  1028. XSync(dpy, False);
  1029. }
  1030. void
  1031. cleanup(void)
  1032. {
  1033. Arg a = {.ui = ~0};
  1034. Layout foo = { "", NULL };
  1035. Monitor *m;
  1036. size_t i;
  1037. view(&a);
  1038. selmon->lt[selmon->sellt] = &foo;
  1039. for (m = mons; m; m = m->next)
  1040. while (m->stack)
  1041. unmanage(m->stack, 0);
  1042. XUngrabKey(dpy, AnyKey, AnyModifier, root);
  1043. while (mons)
  1044. cleanupmon(mons);
  1045. #if BAR_SYSTRAY_PATCH
  1046. if (showsystray && systray) {
  1047. if (systray->win) {
  1048. XUnmapWindow(dpy, systray->win);
  1049. XDestroyWindow(dpy, systray->win);
  1050. }
  1051. free(systray);
  1052. }
  1053. #endif // BAR_SYSTRAY_PATCH
  1054. for (i = 0; i < CurLast; i++)
  1055. drw_cur_free(drw, cursor[i]);
  1056. #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
  1057. for (i = 0; i < LENGTH(colors) + 1; i++)
  1058. #else
  1059. for (i = 0; i < LENGTH(colors); i++)
  1060. #endif // BAR_STATUS2D_PATCH
  1061. free(scheme[i]);
  1062. free(scheme);
  1063. XDestroyWindow(dpy, wmcheckwin);
  1064. drw_free(drw);
  1065. XSync(dpy, False);
  1066. XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  1067. XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
  1068. #if IPC_PATCH
  1069. ipc_cleanup();
  1070. if (close(epoll_fd) < 0)
  1071. fprintf(stderr, "Failed to close epoll file descriptor\n");
  1072. #endif // IPC_PATCH
  1073. }
  1074. void
  1075. cleanupmon(Monitor *mon)
  1076. {
  1077. Monitor *m;
  1078. Bar *bar;
  1079. if (mon == mons)
  1080. mons = mons->next;
  1081. else {
  1082. for (m = mons; m && m->next != mon; m = m->next);
  1083. m->next = mon->next;
  1084. }
  1085. for (bar = mon->bar; bar; bar = mon->bar) {
  1086. if (!bar->external) {
  1087. XUnmapWindow(dpy, bar->win);
  1088. XDestroyWindow(dpy, bar->win);
  1089. }
  1090. mon->bar = bar->next;
  1091. #if BAR_SYSTRAY_PATCH
  1092. if (systray && bar == systray->bar)
  1093. systray->bar = NULL;
  1094. #endif // BAR_SYSTRAY_PATCH
  1095. free(bar);
  1096. }
  1097. free(mon);
  1098. }
  1099. void
  1100. clientmessage(XEvent *e)
  1101. {
  1102. #if BAR_SYSTRAY_PATCH
  1103. XWindowAttributes wa;
  1104. XSetWindowAttributes swa;
  1105. #endif // BAR_SYSTRAY_PATCH
  1106. XClientMessageEvent *cme = &e->xclient;
  1107. Client *c = wintoclient(cme->window);
  1108. #if FOCUSONNETACTIVE_PATCH
  1109. unsigned int i;
  1110. #endif // FOCUSONNETACTIVE_PATCH
  1111. #if BAR_SYSTRAY_PATCH
  1112. if (showsystray && systray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
  1113. /* add systray icons */
  1114. if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
  1115. if (!(c = (Client *)calloc(1, sizeof(Client))))
  1116. die("fatal: could not malloc() %u bytes\n", sizeof(Client));
  1117. if (!(c->win = cme->data.l[2])) {
  1118. free(c);
  1119. return;
  1120. }
  1121. c->mon = selmon;
  1122. c->next = systray->icons;
  1123. systray->icons = c;
  1124. XGetWindowAttributes(dpy, c->win, &wa);
  1125. c->x = c->oldx = c->y = c->oldy = 0;
  1126. c->w = c->oldw = wa.width;
  1127. c->h = c->oldh = wa.height;
  1128. c->oldbw = wa.border_width;
  1129. c->bw = 0;
  1130. c->isfloating = True;
  1131. /* reuse tags field as mapped status */
  1132. c->tags = 1;
  1133. updatesizehints(c);
  1134. updatesystrayicongeom(c, wa.width, wa.height);
  1135. XAddToSaveSet(dpy, c->win);
  1136. XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
  1137. XClassHint ch = {"dwmsystray", "dwmsystray"};
  1138. XSetClassHint(dpy, c->win, &ch);
  1139. XReparentWindow(dpy, c->win, systray->win, 0, 0);
  1140. /* use parents background color */
  1141. swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
  1142. XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
  1143. sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
  1144. XSync(dpy, False);
  1145. setclientstate(c, NormalState);
  1146. }
  1147. return;
  1148. }
  1149. #endif // BAR_SYSTRAY_PATCH
  1150. if (!c)
  1151. return;
  1152. if (cme->message_type == netatom[NetWMState]) {
  1153. if (cme->data.l[1] == netatom[NetWMFullscreen]
  1154. || cme->data.l[2] == netatom[NetWMFullscreen]) {
  1155. #if FAKEFULLSCREEN_CLIENT_PATCH
  1156. if (c->fakefullscreen == 2 && c->isfullscreen)
  1157. c->fakefullscreen = 3;
  1158. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  1159. setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
  1160. || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */
  1161. #if !FAKEFULLSCREEN_PATCH
  1162. && !c->isfullscreen
  1163. #endif // !FAKEFULLSCREEN_PATCH
  1164. )));
  1165. }
  1166. } else if (cme->message_type == netatom[NetActiveWindow]) {
  1167. #if FOCUSONNETACTIVE_PATCH
  1168. if (c->tags & c->mon->tagset[c->mon->seltags])
  1169. focus(c);
  1170. else {
  1171. for (i = 0; i < NUMTAGS && !((1 << i) & c->tags); i++);
  1172. if (i < NUMTAGS) {
  1173. if (c != selmon->sel)
  1174. unfocus(selmon->sel, 0, NULL);
  1175. selmon = c->mon;
  1176. if (((1 << i) & TAGMASK) != selmon->tagset[selmon->seltags])
  1177. view(&((Arg) { .ui = 1 << i }));
  1178. focus(c);
  1179. restack(selmon);
  1180. }
  1181. }
  1182. #else
  1183. if (c != selmon->sel && !c->isurgent)
  1184. seturgent(c, 1);
  1185. #endif // FOCUSONNETACTIVE_PATCH
  1186. }
  1187. }
  1188. void
  1189. configure(Client *c)
  1190. {
  1191. XConfigureEvent ce;
  1192. ce.type = ConfigureNotify;
  1193. ce.display = dpy;
  1194. ce.event = c->win;
  1195. ce.window = c->win;
  1196. ce.x = c->x;
  1197. ce.y = c->y;
  1198. ce.width = c->w;
  1199. ce.height = c->h;
  1200. ce.border_width = c->bw;
  1201. ce.above = None;
  1202. ce.override_redirect = False;
  1203. XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
  1204. }
  1205. void
  1206. configurenotify(XEvent *e)
  1207. {
  1208. Monitor *m;
  1209. Bar *bar;
  1210. #if !FAKEFULLSCREEN_PATCH
  1211. Client *c;
  1212. #endif // !FAKEFULLSCREEN_PATCH
  1213. XConfigureEvent *ev = &e->xconfigure;
  1214. int dirty;
  1215. /* TODO: updategeom handling sucks, needs to be simplified */
  1216. if (ev->window == root) {
  1217. dirty = (sw != ev->width || sh != ev->height);
  1218. sw = ev->width;
  1219. sh = ev->height;
  1220. if (updategeom() || dirty) {
  1221. drw_resize(drw, sw, sh);
  1222. updatebars();
  1223. for (m = mons; m; m = m->next) {
  1224. #if !FAKEFULLSCREEN_PATCH
  1225. for (c = m->clients; c; c = c->next)
  1226. #if FAKEFULLSCREEN_CLIENT_PATCH
  1227. if (c->isfullscreen && c->fakefullscreen != 1)
  1228. #else
  1229. if (c->isfullscreen)
  1230. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  1231. resizeclient(c, m->mx, m->my, m->mw, m->mh);
  1232. #endif // !FAKEFULLSCREEN_PATCH
  1233. for (bar = m->bar; bar; bar = bar->next)
  1234. XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
  1235. }
  1236. focus(NULL);
  1237. arrange(NULL);
  1238. }
  1239. }
  1240. }
  1241. void
  1242. configurerequest(XEvent *e)
  1243. {
  1244. Client *c;
  1245. Monitor *m;
  1246. #if BAR_ANYBAR_PATCH
  1247. Bar *bar;
  1248. #endif // BAR_ANYBAR_PATCH
  1249. XConfigureRequestEvent *ev = &e->xconfigurerequest;
  1250. XWindowChanges wc;
  1251. if (ignoreconfigurerequests)
  1252. return;
  1253. if ((c = wintoclient(ev->window))) {
  1254. if (ev->value_mask & CWBorderWidth)
  1255. c->bw = ev->border_width;
  1256. else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
  1257. m = c->mon;
  1258. #if STEAM_PATCH
  1259. if (!c->issteam) {
  1260. if (ev->value_mask & CWX) {
  1261. c->oldx = c->x;
  1262. c->x = m->mx + ev->x;
  1263. }
  1264. if (ev->value_mask & CWY) {
  1265. c->oldy = c->y;
  1266. c->y = m->my + ev->y;
  1267. }
  1268. }
  1269. #else
  1270. if (ev->value_mask & CWX) {
  1271. c->oldx = c->x;
  1272. c->x = m->mx + ev->x;
  1273. }
  1274. if (ev->value_mask & CWY) {
  1275. c->oldy = c->y;
  1276. c->y = m->my + ev->y;
  1277. }
  1278. #endif // STEAM_PATCH
  1279. if (ev->value_mask & CWWidth) {
  1280. c->oldw = c->w;
  1281. c->w = ev->width;
  1282. }
  1283. if (ev->value_mask & CWHeight) {
  1284. c->oldh = c->h;
  1285. c->h = ev->height;
  1286. }
  1287. if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
  1288. c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
  1289. if ((c->y + c->h) > m->my + m->mh && c->isfloating)
  1290. c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
  1291. if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
  1292. configure(c);
  1293. if (ISVISIBLE(c))
  1294. XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
  1295. #if AUTORESIZE_PATCH
  1296. else
  1297. c->needresize = 1;
  1298. #endif // AUTORESIZE_PATCH
  1299. } else
  1300. configure(c);
  1301. } else {
  1302. wc.x = ev->x;
  1303. wc.y = ev->y;
  1304. #if BAR_ANYBAR_PATCH
  1305. m = wintomon(ev->window);
  1306. for (bar = m->bar; bar; bar = bar->next) {
  1307. if (bar->win == ev->window) {
  1308. wc.y = bar->by;
  1309. wc.x = bar->bx;
  1310. }
  1311. }
  1312. #endif // BAR_ANYBAR_PATCH
  1313. wc.width = ev->width;
  1314. wc.height = ev->height;
  1315. wc.border_width = ev->border_width;
  1316. wc.sibling = ev->above;
  1317. wc.stack_mode = ev->detail;
  1318. XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
  1319. }
  1320. XSync(dpy, False);
  1321. }
  1322. Monitor *
  1323. createmon(void)
  1324. {
  1325. Monitor *m, *mon;
  1326. int i, n, mi, max_bars = 2, istopbar = topbar;
  1327. #if MONITOR_RULES_PATCH
  1328. int layout;
  1329. #endif // MONITOR_RULES_PATCH
  1330. const BarRule *br;
  1331. Bar *bar;
  1332. #if MONITOR_RULES_PATCH
  1333. int j;
  1334. const MonitorRule *mr;
  1335. #endif // MONITOR_RULES_PATCH
  1336. m = ecalloc(1, sizeof(Monitor));
  1337. #if EMPTYVIEW_PATCH
  1338. m->tagset[0] = m->tagset[1] = 0;
  1339. #else
  1340. m->tagset[0] = m->tagset[1] = 1;
  1341. #endif // EMPTYVIEW_PATCH
  1342. m->mfact = mfact;
  1343. m->nmaster = nmaster;
  1344. #if FLEXTILE_DELUXE_LAYOUT
  1345. m->nstack = nstack;
  1346. #endif // FLEXTILE_DELUXE_LAYOUT
  1347. m->showbar = showbar;
  1348. #if SETBORDERPX_PATCH
  1349. m->borderpx = borderpx;
  1350. #endif // SETBORDERPX_PATCH
  1351. #if VANITYGAPS_PATCH
  1352. m->gappih = gappih;
  1353. m->gappiv = gappiv;
  1354. m->gappoh = gappoh;
  1355. m->gappov = gappov;
  1356. #endif // VANITYGAPS_PATCH
  1357. for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index
  1358. m->index = mi;
  1359. #if MONITOR_RULES_PATCH
  1360. for (j = 0; j < LENGTH(monrules); j++) {
  1361. mr = &monrules[j];
  1362. if ((mr->monitor == -1 || mr->monitor == mi)
  1363. #if PERTAG_PATCH
  1364. && (mr->tag <= 0 || (m->tagset[0] & (1 << (mr->tag - 1))))
  1365. #endif // PERTAG_PATCH
  1366. ) {
  1367. layout = MAX(mr->layout, 0);
  1368. layout = MIN(layout, LENGTH(layouts) - 1);
  1369. m->lt[0] = &layouts[layout];
  1370. m->lt[1] = &layouts[1 % LENGTH(layouts)];
  1371. strncpy(m->ltsymbol, layouts[layout].symbol, sizeof m->ltsymbol);
  1372. if (mr->mfact > -1)
  1373. m->mfact = mr->mfact;
  1374. if (mr->nmaster > -1)
  1375. m->nmaster = mr->nmaster;
  1376. if (mr->showbar > -1)
  1377. m->showbar = mr->showbar;
  1378. if (mr->topbar > -1)
  1379. istopbar = mr->topbar;
  1380. break;
  1381. }
  1382. }
  1383. #else
  1384. m->lt[0] = &layouts[0];
  1385. m->lt[1] = &layouts[1 % LENGTH(layouts)];
  1386. strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
  1387. #endif // MONITOR_RULES_PATCH
  1388. /* Derive the number of bars for this monitor based on bar rules */
  1389. for (n = -1, i = 0; i < LENGTH(barrules); i++) {
  1390. br = &barrules[i];
  1391. if (br->monitor == 'A' || br->monitor == -1 || br->monitor == mi)
  1392. n = MAX(br->bar, n);
  1393. }
  1394. for (i = 0; i <= n && i < max_bars; i++) {
  1395. bar = ecalloc(1, sizeof(Bar));
  1396. bar->mon = m;
  1397. bar->idx = i;
  1398. bar->next = m->bar;
  1399. bar->topbar = istopbar;
  1400. m->bar = bar;
  1401. istopbar = !istopbar;
  1402. bar->showbar = 1;
  1403. bar->external = 0;
  1404. #if BAR_BORDER_PATCH
  1405. bar->borderpx = borderpx;
  1406. #else
  1407. bar->borderpx = 0;
  1408. #endif // BAR_BORDER_PATCH
  1409. bar->bh = bh + bar->borderpx * 2;
  1410. bar->borderscheme = SchemeNorm;
  1411. }
  1412. #if FLEXTILE_DELUXE_LAYOUT
  1413. m->ltaxis[LAYOUT] = m->lt[0]->preset.layout;
  1414. m->ltaxis[MASTER] = m->lt[0]->preset.masteraxis;
  1415. m->ltaxis[STACK] = m->lt[0]->preset.stack1axis;
  1416. m->ltaxis[STACK2] = m->lt[0]->preset.stack2axis;
  1417. #endif // FLEXTILE_DELUXE_LAYOUT
  1418. #if PERTAG_PATCH
  1419. if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
  1420. die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
  1421. m->pertag->curtag = m->pertag->prevtag = 1;
  1422. for (i = 0; i <= NUMTAGS; i++) {
  1423. #if FLEXTILE_DELUXE_LAYOUT
  1424. m->pertag->nstacks[i] = m->nstack;
  1425. #endif // FLEXTILE_DELUXE_LAYOUT
  1426. #if !MONITOR_RULES_PATCH
  1427. /* init nmaster */
  1428. m->pertag->nmasters[i] = m->nmaster;
  1429. /* init mfacts */
  1430. m->pertag->mfacts[i] = m->mfact;
  1431. #if PERTAGBAR_PATCH
  1432. /* init showbar */
  1433. m->pertag->showbars[i] = m->showbar;
  1434. #endif // PERTAGBAR_PATCH
  1435. #endif // MONITOR_RULES_PATCH
  1436. #if ZOOMSWAP_PATCH
  1437. m->pertag->prevzooms[i] = NULL;
  1438. #endif // ZOOMSWAP_PATCH
  1439. /* init layouts */
  1440. #if MONITOR_RULES_PATCH
  1441. for (j = 0; j < LENGTH(monrules); j++) {
  1442. mr = &monrules[j];
  1443. if ((mr->monitor == -1 || mr->monitor == mi) && (mr->tag == -1 || mr->tag == i)) {
  1444. layout = MAX(mr->layout, 0);
  1445. layout = MIN(layout, LENGTH(layouts) - 1);
  1446. m->pertag->ltidxs[i][0] = &layouts[layout];
  1447. m->pertag->ltidxs[i][1] = m->lt[0];
  1448. m->pertag->nmasters[i] = (mr->nmaster > -1 ? mr->nmaster : m->nmaster);
  1449. m->pertag->mfacts[i] = (mr->mfact > -1 ? mr->mfact : m->mfact);
  1450. #if PERTAGBAR_PATCH
  1451. m->pertag->showbars[i] = (mr->showbar > -1 ? mr->showbar : m->showbar);
  1452. #endif // PERTAGBAR_PATCH
  1453. #if FLEXTILE_DELUXE_LAYOUT
  1454. m->pertag->ltaxis[i][LAYOUT] = m->pertag->ltidxs[i][0]->preset.layout;
  1455. m->pertag->ltaxis[i][MASTER] = m->pertag->ltidxs[i][0]->preset.masteraxis;
  1456. m->pertag->ltaxis[i][STACK] = m->pertag->ltidxs[i][0]->preset.stack1axis;
  1457. m->pertag->ltaxis[i][STACK2] = m->pertag->ltidxs[i][0]->preset.stack2axis;
  1458. #endif // FLEXTILE_DELUXE_LAYOUT
  1459. break;
  1460. }
  1461. }
  1462. #else
  1463. m->pertag->ltidxs[i][0] = m->lt[0];
  1464. m->pertag->ltidxs[i][1] = m->lt[1];
  1465. #if FLEXTILE_DELUXE_LAYOUT
  1466. /* init flextile axes */
  1467. m->pertag->ltaxis[i][LAYOUT] = m->ltaxis[LAYOUT];
  1468. m->pertag->ltaxis[i][MASTER] = m->ltaxis[MASTER];
  1469. m->pertag->ltaxis[i][STACK] = m->ltaxis[STACK];
  1470. m->pertag->ltaxis[i][STACK2] = m->ltaxis[STACK2];
  1471. #endif // FLEXTILE_DELUXE_LAYOUT
  1472. #endif // MONITOR_RULES_PATCH
  1473. m->pertag->sellts[i] = m->sellt;
  1474. #if VANITYGAPS_PATCH
  1475. m->pertag->enablegaps[i] = 1;
  1476. #endif // VANITYGAPS_PATCH
  1477. }
  1478. #endif // PERTAG_PATCH
  1479. #if INSETS_PATCH
  1480. m->inset = default_inset;
  1481. #endif // INSETS_PATCH
  1482. return m;
  1483. }
  1484. void
  1485. destroynotify(XEvent *e)
  1486. {
  1487. Client *c;
  1488. #if BAR_ANYBAR_PATCH
  1489. Monitor *m;
  1490. Bar *bar;
  1491. #endif // BAR_ANYBAR_PATCH
  1492. XDestroyWindowEvent *ev = &e->xdestroywindow;
  1493. if ((c = wintoclient(ev->window)))
  1494. unmanage(c, 1);
  1495. #if SWALLOW_PATCH
  1496. else if ((c = swallowingclient(ev->window)))
  1497. unmanage(c->swallowing, 1);
  1498. #endif // SWALLOW_PATCH
  1499. #if BAR_SYSTRAY_PATCH
  1500. else if (showsystray && (c = wintosystrayicon(ev->window))) {
  1501. removesystrayicon(c);
  1502. drawbarwin(systray->bar);
  1503. }
  1504. #endif // BAR_SYSTRAY_PATCH
  1505. #if BAR_ANYBAR_PATCH
  1506. else {
  1507. m = wintomon(ev->window);
  1508. for (bar = m->bar; bar; bar = bar->next) {
  1509. if (bar->win == ev->window) {
  1510. unmanagealtbar(ev->window);
  1511. break;
  1512. }
  1513. }
  1514. }
  1515. #endif // BAR_ANYBAR_PATCH
  1516. }
  1517. void
  1518. detach(Client *c)
  1519. {
  1520. Client **tc;
  1521. for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
  1522. *tc = c->next;
  1523. }
  1524. void
  1525. detachstack(Client *c)
  1526. {
  1527. Client **tc, *t;
  1528. for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
  1529. *tc = c->snext;
  1530. if (c == c->mon->sel) {
  1531. for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
  1532. c->mon->sel = t;
  1533. }
  1534. }
  1535. Monitor *
  1536. dirtomon(int dir)
  1537. {
  1538. Monitor *m = NULL;
  1539. if (dir > 0) {
  1540. if (!(m = selmon->next))
  1541. m = mons;
  1542. } else if (selmon == mons)
  1543. for (m = mons; m->next; m = m->next);
  1544. else
  1545. for (m = mons; m->next != selmon; m = m->next);
  1546. return m;
  1547. }
  1548. void
  1549. drawbar(Monitor *m)
  1550. {
  1551. Bar *bar;
  1552. for (bar = m->bar; bar; bar = bar->next)
  1553. drawbarwin(bar);
  1554. }
  1555. void
  1556. drawbars(void)
  1557. {
  1558. Monitor *m;
  1559. for (m = mons; m; m = m->next)
  1560. drawbar(m);
  1561. }
  1562. void
  1563. drawbarwin(Bar *bar)
  1564. {
  1565. if (!bar || !bar->win || bar->external)
  1566. return;
  1567. int r, w, total_drawn = 0;
  1568. int rx, lx, rw, lw; // bar size, split between left and right if a center module is added
  1569. const BarRule *br;
  1570. if (bar->borderpx) {
  1571. XSetForeground(drw->dpy, drw->gc, scheme[bar->borderscheme][ColBorder].pixel);
  1572. XFillRectangle(drw->dpy, drw->drawable, drw->gc, 0, 0, bar->bw, bar->bh);
  1573. }
  1574. BarArg warg = { 0 };
  1575. BarArg darg = { 0 };
  1576. warg.h = bar->bh - 2 * bar->borderpx;
  1577. rw = lw = bar->bw - 2 * bar->borderpx;
  1578. rx = lx = bar->borderpx;
  1579. drw_setscheme(drw, scheme[SchemeNorm]);
  1580. drw_rect(drw, lx, bar->borderpx, lw, bar->bh - 2 * bar->borderpx, 1, 1);
  1581. for (r = 0; r < LENGTH(barrules); r++) {
  1582. br = &barrules[r];
  1583. if (br->bar != bar->idx || !br->widthfunc || (br->monitor == 'A' && bar->mon != selmon))
  1584. continue;
  1585. if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->index)
  1586. continue;
  1587. drw_setscheme(drw, scheme[SchemeNorm]);
  1588. warg.w = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw);
  1589. w = br->widthfunc(bar, &warg);
  1590. w = MIN(warg.w, w);
  1591. if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa
  1592. lw = rw;
  1593. lx = rx;
  1594. } else if (rw <= 0) {
  1595. rw = lw;
  1596. rx = lx;
  1597. }
  1598. switch(br->alignment) {
  1599. default:
  1600. case BAR_ALIGN_NONE:
  1601. case BAR_ALIGN_LEFT_LEFT:
  1602. case BAR_ALIGN_LEFT:
  1603. bar->x[r] = lx;
  1604. if (lx == rx) {
  1605. rx += w;
  1606. rw -= w;
  1607. }
  1608. lx += w;
  1609. lw -= w;
  1610. break;
  1611. case BAR_ALIGN_LEFT_RIGHT:
  1612. case BAR_ALIGN_RIGHT:
  1613. bar->x[r] = lx + lw - w;
  1614. if (lx == rx)
  1615. rw -= w;
  1616. lw -= w;
  1617. break;
  1618. case BAR_ALIGN_LEFT_CENTER:
  1619. case BAR_ALIGN_CENTER:
  1620. bar->x[r] = lx + lw / 2 - w / 2;
  1621. if (lx == rx) {
  1622. rw = rx + rw - bar->x[r] - w;
  1623. rx = bar->x[r] + w;
  1624. }
  1625. lw = bar->x[r] - lx;
  1626. break;
  1627. case BAR_ALIGN_RIGHT_LEFT:
  1628. bar->x[r] = rx;
  1629. if (lx == rx) {
  1630. lx += w;
  1631. lw -= w;
  1632. }
  1633. rx += w;
  1634. rw -= w;
  1635. break;
  1636. case BAR_ALIGN_RIGHT_RIGHT:
  1637. bar->x[r] = rx + rw - w;
  1638. if (lx == rx)
  1639. lw -= w;
  1640. rw -= w;
  1641. break;
  1642. case BAR_ALIGN_RIGHT_CENTER:
  1643. bar->x[r] = rx + rw / 2 - w / 2;
  1644. if (lx == rx) {
  1645. lw = lx + lw - bar->x[r] + w;
  1646. lx = bar->x[r] + w;
  1647. }
  1648. rw = bar->x[r] - rx;
  1649. break;
  1650. }
  1651. bar->w[r] = w;
  1652. darg.x = bar->x[r];
  1653. darg.y = bar->borderpx;
  1654. darg.h = bar->bh - 2 * bar->borderpx;
  1655. darg.w = bar->w[r];
  1656. if (br->drawfunc)
  1657. total_drawn += br->drawfunc(bar, &darg);
  1658. }
  1659. if (total_drawn == 0 && bar->showbar) {
  1660. bar->showbar = 0;
  1661. updatebarpos(bar->mon);
  1662. XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
  1663. arrange(bar->mon);
  1664. }
  1665. else if (total_drawn > 0 && !bar->showbar) {
  1666. bar->showbar = 1;
  1667. updatebarpos(bar->mon);
  1668. XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
  1669. drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
  1670. arrange(bar->mon);
  1671. } else
  1672. drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh);
  1673. }
  1674. #if !FOCUSONCLICK_PATCH
  1675. void
  1676. enternotify(XEvent *e)
  1677. {
  1678. Client *c;
  1679. #if LOSEFULLSCREEN_PATCH
  1680. Client *sel;
  1681. #endif // LOSEFULLSCREEN_PATCH
  1682. Monitor *m;
  1683. XCrossingEvent *ev = &e->xcrossing;
  1684. if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
  1685. return;
  1686. c = wintoclient(ev->window);
  1687. m = c ? c->mon : wintomon(ev->window);
  1688. if (m != selmon) {
  1689. #if LOSEFULLSCREEN_PATCH
  1690. sel = selmon->sel;
  1691. selmon = m;
  1692. unfocus(sel, 1, c);
  1693. #else
  1694. unfocus(selmon->sel, 1, c);
  1695. selmon = m;
  1696. #endif // LOSEFULLSCREEN_PATCH
  1697. } else if (!c || c == selmon->sel)
  1698. return;
  1699. focus(c);
  1700. }
  1701. #endif // FOCUSONCLICK_PATCH
  1702. void
  1703. expose(XEvent *e)
  1704. {
  1705. Monitor *m;
  1706. XExposeEvent *ev = &e->xexpose;
  1707. if (ev->count == 0 && (m = wintomon(ev->window)))
  1708. drawbar(m);
  1709. }
  1710. void
  1711. focus(Client *c)
  1712. {
  1713. if (!c || !ISVISIBLE(c))
  1714. for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
  1715. if (selmon->sel && selmon->sel != c)
  1716. unfocus(selmon->sel, 0, c);
  1717. if (c) {
  1718. if (c->mon != selmon)
  1719. selmon = c->mon;
  1720. if (c->isurgent)
  1721. seturgent(c, 0);
  1722. detachstack(c);
  1723. attachstack(c);
  1724. grabbuttons(c, 1);
  1725. #if !BAR_FLEXWINTITLE_PATCH
  1726. if (c->isfloating)
  1727. XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
  1728. else
  1729. XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
  1730. #endif // BAR_FLEXWINTITLE_PATCH
  1731. setfocus(c);
  1732. } else {
  1733. XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
  1734. XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
  1735. }
  1736. selmon->sel = c;
  1737. drawbars();
  1738. #if ON_EMPTY_KEYS_PATCH
  1739. if ((isempty && selmon->sel) || (!isempty && !selmon->sel)) {
  1740. isempty = !isempty;
  1741. grabkeys();
  1742. }
  1743. #endif // ON_EMPTY_KEYS_PATCH
  1744. }
  1745. /* there are some broken focus acquiring clients needing extra handling */
  1746. void
  1747. focusin(XEvent *e)
  1748. {
  1749. XFocusChangeEvent *ev = &e->xfocus;
  1750. if (selmon->sel && ev->window != selmon->sel->win)
  1751. setfocus(selmon->sel);
  1752. }
  1753. void
  1754. focusmon(const Arg *arg)
  1755. {
  1756. Monitor *m;
  1757. #if LOSEFULLSCREEN_PATCH
  1758. Client *sel;
  1759. #endif // LOSEFULLSCREEN_PATCH
  1760. if (!mons->next)
  1761. return;
  1762. if ((m = dirtomon(arg->i)) == selmon)
  1763. return;
  1764. #if LOSEFULLSCREEN_PATCH
  1765. sel = selmon->sel;
  1766. selmon = m;
  1767. unfocus(sel, 0, NULL);
  1768. #else
  1769. unfocus(selmon->sel, 0, NULL);
  1770. selmon = m;
  1771. #endif // LOSEFULLSCREEN_PATCH
  1772. focus(NULL);
  1773. #if WARP_PATCH
  1774. warp(selmon->sel);
  1775. #endif // WARP_PATCH
  1776. }
  1777. #if !STACKER_PATCH
  1778. void
  1779. focusstack(const Arg *arg)
  1780. {
  1781. Client *c = NULL, *i;
  1782. if (!selmon->sel)
  1783. return;
  1784. #if ALWAYSFULLSCREEN_PATCH
  1785. if (selmon->sel->isfullscreen)
  1786. return;
  1787. #endif // ALWAYSFULLSCREEN_PATCH
  1788. #if BAR_WINTITLEACTIONS_PATCH
  1789. if (arg->i > 0) {
  1790. for (c = selmon->sel->next; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next);
  1791. if (!c)
  1792. for (c = selmon->clients; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next);
  1793. } else {
  1794. for (i = selmon->clients; i != selmon->sel; i = i->next)
  1795. if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i)))
  1796. c = i;
  1797. if (!c)
  1798. for (; i; i = i->next)
  1799. if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i)))
  1800. c = i;
  1801. }
  1802. #else
  1803. if (arg->i > 0) {
  1804. for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
  1805. if (!c)
  1806. for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
  1807. } else {
  1808. for (i = selmon->clients; i != selmon->sel; i = i->next)
  1809. if (ISVISIBLE(i))
  1810. c = i;
  1811. if (!c)
  1812. for (; i; i = i->next)
  1813. if (ISVISIBLE(i))
  1814. c = i;
  1815. }
  1816. #endif // BAR_WINTITLEACTIONS_PATCH
  1817. if (c) {
  1818. focus(c);
  1819. restack(selmon);
  1820. }
  1821. }
  1822. #endif // STACKER_PATCH
  1823. Atom
  1824. getatomprop(Client *c, Atom prop)
  1825. {
  1826. int di;
  1827. unsigned long dl;
  1828. unsigned char *p = NULL;
  1829. Atom da, atom = None;
  1830. #if BAR_SYSTRAY_PATCH
  1831. /* FIXME getatomprop should return the number of items and a pointer to
  1832. * the stored data instead of this workaround */
  1833. Atom req = XA_ATOM;
  1834. if (prop == xatom[XembedInfo])
  1835. req = xatom[XembedInfo];
  1836. if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
  1837. &da, &di, &dl, &dl, &p) == Success && p) {
  1838. atom = *(Atom *)p;
  1839. if (da == xatom[XembedInfo] && dl == 2)
  1840. atom = ((Atom *)p)[1];
  1841. XFree(p);
  1842. }
  1843. #else
  1844. if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
  1845. &da, &di, &dl, &dl, &p) == Success && p) {
  1846. atom = *(Atom *)p;
  1847. XFree(p);
  1848. }
  1849. #endif // BAR_SYSTRAY_PATCH
  1850. return atom;
  1851. }
  1852. int
  1853. getrootptr(int *x, int *y)
  1854. {
  1855. int di;
  1856. unsigned int dui;
  1857. Window dummy;
  1858. return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
  1859. }
  1860. long
  1861. getstate(Window w)
  1862. {
  1863. int format;
  1864. long result = -1;
  1865. unsigned char *p = NULL;
  1866. unsigned long n, extra;
  1867. Atom real;
  1868. if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
  1869. &real, &format, &n, &extra, (unsigned char **)&p) != Success)
  1870. return -1;
  1871. if (n != 0)
  1872. result = *p;
  1873. XFree(p);
  1874. return result;
  1875. }
  1876. int
  1877. gettextprop(Window w, Atom atom, char *text, unsigned int size)
  1878. {
  1879. char **list = NULL;
  1880. int n;
  1881. XTextProperty name;
  1882. if (!text || size == 0)
  1883. return 0;
  1884. text[0] = '\0';
  1885. if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
  1886. return 0;
  1887. if (name.encoding == XA_STRING)
  1888. strncpy(text, (char *)name.value, size - 1);
  1889. else {
  1890. if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
  1891. strncpy(text, *list, size - 1);
  1892. XFreeStringList(list);
  1893. }
  1894. }
  1895. text[size - 1] = '\0';
  1896. XFree(name.value);
  1897. return 1;
  1898. }
  1899. void
  1900. grabbuttons(Client *c, int focused)
  1901. {
  1902. updatenumlockmask();
  1903. {
  1904. unsigned int i, j;
  1905. unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
  1906. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  1907. if (!focused)
  1908. XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
  1909. BUTTONMASK, GrabModeSync, GrabModeSync, None, None);
  1910. for (i = 0; i < LENGTH(buttons); i++)
  1911. if (buttons[i].click == ClkClientWin
  1912. #if NO_MOD_BUTTONS_PATCH
  1913. && (nomodbuttons || buttons[i].mask != 0)
  1914. #endif // NO_MOD_BUTTONS_PATCH
  1915. )
  1916. for (j = 0; j < LENGTH(modifiers); j++)
  1917. XGrabButton(dpy, buttons[i].button,
  1918. buttons[i].mask | modifiers[j],
  1919. c->win, False, BUTTONMASK,
  1920. GrabModeAsync, GrabModeSync, None, None);
  1921. }
  1922. }
  1923. void
  1924. #if KEYMODES_PATCH
  1925. grabdefkeys(void)
  1926. #else
  1927. grabkeys(void)
  1928. #endif // KEYMODES_PATCH
  1929. {
  1930. updatenumlockmask();
  1931. {
  1932. unsigned int i, j;
  1933. unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
  1934. KeyCode code;
  1935. XUngrabKey(dpy, AnyKey, AnyModifier, root);
  1936. for (i = 0; i < LENGTH(keys); i++)
  1937. if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
  1938. for (j = 0; j < LENGTH(modifiers); j++)
  1939. XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
  1940. True, GrabModeAsync, GrabModeAsync);
  1941. #if ON_EMPTY_KEYS_PATCH
  1942. if (!selmon->sel)
  1943. for (i = 0; i < LENGTH(on_empty_keys); i++)
  1944. if ((code = XKeysymToKeycode(dpy, on_empty_keys[i].keysym)))
  1945. for (j = 0; j < LENGTH(modifiers); j++)
  1946. XGrabKey(dpy, code, on_empty_keys[i].mod | modifiers[j], root,
  1947. True, GrabModeAsync, GrabModeAsync);
  1948. #endif // ON_EMPTY_KEYS_PATCH
  1949. }
  1950. }
  1951. void
  1952. incnmaster(const Arg *arg)
  1953. {
  1954. #if PERTAG_PATCH
  1955. selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
  1956. #else
  1957. selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
  1958. #endif // PERTAG_PATCH
  1959. arrange(selmon);
  1960. }
  1961. #ifdef XINERAMA
  1962. static int
  1963. isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
  1964. {
  1965. while (n--)
  1966. if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
  1967. && unique[n].width == info->width && unique[n].height == info->height)
  1968. return 0;
  1969. return 1;
  1970. }
  1971. #endif /* XINERAMA */
  1972. void
  1973. #if KEYMODES_PATCH
  1974. keydefpress(XEvent *e)
  1975. #else
  1976. keypress(XEvent *e)
  1977. #endif // KEYMODES_PATCH
  1978. {
  1979. unsigned int i;
  1980. int keysyms_return;
  1981. KeySym* keysym;
  1982. XKeyEvent *ev;
  1983. ev = &e->xkey;
  1984. keysym = XGetKeyboardMapping(dpy, (KeyCode)ev->keycode, 1, &keysyms_return);
  1985. for (i = 0; i < LENGTH(keys); i++)
  1986. if (*keysym == keys[i].keysym
  1987. && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
  1988. && keys[i].func)
  1989. keys[i].func(&(keys[i].arg));
  1990. #if ON_EMPTY_KEYS_PATCH
  1991. if (!selmon->sel)
  1992. for (i = 0; i < LENGTH(on_empty_keys); i++)
  1993. if (*keysym == on_empty_keys[i].keysym
  1994. && CLEANMASK(on_empty_keys[i].mod) == CLEANMASK(ev->state)
  1995. && on_empty_keys[i].func)
  1996. on_empty_keys[i].func(&(on_empty_keys[i].arg));
  1997. #endif // ON_EMPTY_KEYS_PATCH
  1998. XFree(keysym);
  1999. }
  2000. void
  2001. killclient(const Arg *arg)
  2002. {
  2003. #if ISPERMANENT_PATCH
  2004. if (!selmon->sel || selmon->sel->ispermanent)
  2005. #else
  2006. if (!selmon->sel)
  2007. #endif // ISPERMANENT_PATCH
  2008. return;
  2009. #if BAR_SYSTRAY_PATCH
  2010. if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0))
  2011. #else
  2012. if (!sendevent(selmon->sel, wmatom[WMDelete]))
  2013. #endif // BAR_SYSTRAY_PATCH
  2014. {
  2015. XGrabServer(dpy);
  2016. XSetErrorHandler(xerrordummy);
  2017. XSetCloseDownMode(dpy, DestroyAll);
  2018. XKillClient(dpy, selmon->sel->win);
  2019. XSync(dpy, False);
  2020. XSetErrorHandler(xerror);
  2021. XUngrabServer(dpy);
  2022. #if WARP_PATCH
  2023. force_warp = 1;
  2024. #endif // WARP_PATCH
  2025. }
  2026. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  2027. selmon->pertag->prevclient[selmon->pertag->curtag] = NULL;
  2028. #endif // SWAPFOCUS_PATCH
  2029. }
  2030. void
  2031. manage(Window w, XWindowAttributes *wa)
  2032. {
  2033. Client *c, *t = NULL;
  2034. #if SWALLOW_PATCH
  2035. Client *term = NULL;
  2036. #endif // SWALLOW_PATCH
  2037. Window trans = None;
  2038. XWindowChanges wc;
  2039. c = ecalloc(1, sizeof(Client));
  2040. c->win = w;
  2041. #if SWALLOW_PATCH
  2042. c->pid = winpid(w);
  2043. #endif // SWALLOW_PATCH
  2044. /* geometry */
  2045. c->x = c->oldx = wa->x;
  2046. c->y = c->oldy = wa->y;
  2047. c->w = c->oldw = wa->width;
  2048. c->h = c->oldh = wa->height;
  2049. c->oldbw = wa->border_width;
  2050. #if CFACTS_PATCH
  2051. c->cfact = 1.0;
  2052. #endif // CFACTS_PATCH
  2053. updatetitle(c);
  2054. if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
  2055. c->mon = t->mon;
  2056. c->tags = t->tags;
  2057. #if SETBORDERPX_PATCH
  2058. c->bw = c->mon->borderpx;
  2059. #else
  2060. c->bw = borderpx;
  2061. #endif // SETBORDERPX_PATCH
  2062. #if CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH
  2063. c->x = t->x + WIDTH(t) / 2 - WIDTH(c) / 2;
  2064. c->y = t->y + HEIGHT(t) / 2 - HEIGHT(c) / 2;
  2065. #elif CENTER_PATCH && CENTER_TRANSIENT_WINDOWS_PATCH
  2066. c->iscentered = 1;
  2067. #elif CENTER_TRANSIENT_WINDOWS_PATCH
  2068. c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
  2069. c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
  2070. #elif CENTER_PATCH
  2071. if (c->x == c->mon->wx && c->y == c->mon->wy)
  2072. c->iscentered = 1;
  2073. #endif // CENTER_TRANSIENT_WINDOWS_PATCH | CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH | CENTER_PATCH
  2074. } else {
  2075. c->mon = selmon;
  2076. #if CENTER_PATCH
  2077. if (c->x == c->mon->wx && c->y == c->mon->wy)
  2078. c->iscentered = 1;
  2079. #endif // CENTER_PATCH
  2080. #if SETBORDERPX_PATCH
  2081. c->bw = c->mon->borderpx;
  2082. #else
  2083. c->bw = borderpx;
  2084. #endif // SETBORDERPX_PATCH
  2085. applyrules(c);
  2086. #if SWALLOW_PATCH
  2087. term = termforwin(c);
  2088. if (term)
  2089. c->mon = term->mon;
  2090. #endif // SWALLOW_PATCH
  2091. }
  2092. if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
  2093. c->x = c->mon->mx + c->mon->mw - WIDTH(c);
  2094. if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
  2095. c->y = c->mon->my + c->mon->mh - HEIGHT(c);
  2096. c->x = MAX(c->x, c->mon->mx);
  2097. /* only fix client y-offset, if the client center might cover the bar */
  2098. c->y = MAX(c->y, ((c->mon->bar->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
  2099. && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
  2100. wc.border_width = c->bw;
  2101. XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  2102. #if !BAR_FLEXWINTITLE_PATCH
  2103. if (c->isfloating)
  2104. XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
  2105. else
  2106. XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
  2107. #endif // BAR_FLEXWINTITLE_PATCH
  2108. configure(c); /* propagates border_width, if size doesn't change */
  2109. #if !FLOATPOS_PATCH
  2110. updatesizehints(c);
  2111. #endif // FLOATPOS_PATCH
  2112. if (getatomprop(c, netatom[NetWMState]) == netatom[NetWMFullscreen])
  2113. setfullscreen(c, 1);
  2114. updatewmhints(c);
  2115. #if DECORATION_HINTS_PATCH
  2116. updatemotifhints(c);
  2117. #endif // DECORATION_HINTS_PATCH
  2118. #if CENTER_PATCH
  2119. if (c->iscentered) {
  2120. c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2;
  2121. c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2;
  2122. }
  2123. #endif // CENTER_PATCH
  2124. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  2125. c->sfx = -9999;
  2126. c->sfy = -9999;
  2127. c->sfw = c->w;
  2128. c->sfh = c->h;
  2129. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  2130. XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
  2131. grabbuttons(c, 0);
  2132. #if MAXIMIZE_PATCH
  2133. c->wasfloating = 0;
  2134. c->ismax = 0;
  2135. #elif EXRESIZE_PATCH
  2136. c->wasfloating = 0;
  2137. #endif // MAXIMIZE_PATCH / EXRESIZE_PATCH
  2138. if (!c->isfloating)
  2139. c->isfloating = c->oldstate = trans != None || c->isfixed;
  2140. if (c->isfloating) {
  2141. XRaiseWindow(dpy, c->win);
  2142. XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel);
  2143. }
  2144. #if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
  2145. attachx(c);
  2146. #else
  2147. attach(c);
  2148. #endif
  2149. attachstack(c);
  2150. XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
  2151. (unsigned char *) &(c->win), 1);
  2152. #if NET_CLIENT_LIST_STACKING_PATCH
  2153. XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend,
  2154. (unsigned char *) &(c->win), 1);
  2155. #endif // NET_CLIENT_LIST_STACKING_PATCH
  2156. XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
  2157. #if BAR_WINTITLEACTIONS_PATCH
  2158. if (!HIDDEN(c))
  2159. setclientstate(c, NormalState);
  2160. #else
  2161. setclientstate(c, NormalState);
  2162. #endif // BAR_WINTITLEACTIONS_PATCH
  2163. if (c->mon == selmon)
  2164. unfocus(selmon->sel, 0, c);
  2165. c->mon->sel = c;
  2166. #if SWALLOW_PATCH
  2167. if (!(term && swallow(term, c))) {
  2168. #if RIODRAW_PATCH
  2169. if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) {
  2170. if (riodimensions[3] != -1)
  2171. rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
  2172. else {
  2173. killclient(&((Arg) { .v = c }));
  2174. return;
  2175. }
  2176. }
  2177. #endif // RIODRAW_PATCH
  2178. arrange(c->mon);
  2179. #if BAR_WINTITLEACTIONS_PATCH
  2180. if (!HIDDEN(c))
  2181. XMapWindow(dpy, c->win);
  2182. #else
  2183. XMapWindow(dpy, c->win);
  2184. #endif // BAR_WINTITLEACTIONS_PATCH
  2185. }
  2186. #else
  2187. #if RIODRAW_PATCH
  2188. if (riopid) {
  2189. if (riodimensions[3] != -1)
  2190. rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]);
  2191. else {
  2192. killclient(&((Arg) { .v = c }));
  2193. return;
  2194. }
  2195. }
  2196. #endif // RIODRAW_PATCH
  2197. arrange(c->mon);
  2198. #if BAR_WINTITLEACTIONS_PATCH
  2199. if (!HIDDEN(c))
  2200. XMapWindow(dpy, c->win);
  2201. #else
  2202. XMapWindow(dpy, c->win);
  2203. #endif // BAR_WINTITLEACTIONS_PATCH
  2204. #endif // SWALLOW_PATCH
  2205. focus(NULL);
  2206. #if BAR_EWMHTAGS_PATCH
  2207. setfloatinghint(c);
  2208. #endif // BAR_EWMHTAGS_PATCH
  2209. }
  2210. void
  2211. mappingnotify(XEvent *e)
  2212. {
  2213. XMappingEvent *ev = &e->xmapping;
  2214. XRefreshKeyboardMapping(ev);
  2215. if (ev->request == MappingKeyboard)
  2216. grabkeys();
  2217. }
  2218. void
  2219. maprequest(XEvent *e)
  2220. {
  2221. static XWindowAttributes wa;
  2222. XMapRequestEvent *ev = &e->xmaprequest;
  2223. #if BAR_SYSTRAY_PATCH
  2224. Client *i;
  2225. if (showsystray && systray && (i = wintosystrayicon(ev->window))) {
  2226. sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
  2227. drawbarwin(systray->bar);
  2228. }
  2229. #endif // BAR_SYSTRAY_PATCH
  2230. if (!XGetWindowAttributes(dpy, ev->window, &wa))
  2231. return;
  2232. if (wa.override_redirect)
  2233. return;
  2234. #if BAR_ANYBAR_PATCH
  2235. if (wmclasscontains(ev->window, altbarclass, ""))
  2236. managealtbar(ev->window, &wa);
  2237. else
  2238. #endif // BAR_ANYBAR_PATCH
  2239. if (!wintoclient(ev->window))
  2240. manage(ev->window, &wa);
  2241. }
  2242. #if !FOCUSONCLICK_PATCH
  2243. void
  2244. motionnotify(XEvent *e)
  2245. {
  2246. static Monitor *mon = NULL;
  2247. Monitor *m;
  2248. #if LOSEFULLSCREEN_PATCH
  2249. Client *sel;
  2250. #endif // LOSEFULLSCREEN_PATCH
  2251. XMotionEvent *ev = &e->xmotion;
  2252. if (ev->window != root)
  2253. return;
  2254. if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
  2255. #if LOSEFULLSCREEN_PATCH
  2256. sel = selmon->sel;
  2257. selmon = m;
  2258. unfocus(sel, 1, NULL);
  2259. #else
  2260. unfocus(selmon->sel, 1, NULL);
  2261. selmon = m;
  2262. #endif // LOSEFULLSCREEN_PATCH
  2263. focus(NULL);
  2264. }
  2265. mon = m;
  2266. }
  2267. #endif // FOCUSONCLICK_PATCH
  2268. void
  2269. movemouse(const Arg *arg)
  2270. {
  2271. int x, y, ocx, ocy, nx, ny;
  2272. Client *c;
  2273. Monitor *m;
  2274. XEvent ev;
  2275. Time lasttime = 0;
  2276. if (!(c = selmon->sel))
  2277. return;
  2278. #if !FAKEFULLSCREEN_PATCH
  2279. #if FAKEFULLSCREEN_CLIENT_PATCH
  2280. if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
  2281. return;
  2282. #else
  2283. if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
  2284. return;
  2285. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  2286. #endif // FAKEFULLSCREEN_PATCH
  2287. restack(selmon);
  2288. ocx = c->x;
  2289. ocy = c->y;
  2290. if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  2291. None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
  2292. return;
  2293. if (!getrootptr(&x, &y))
  2294. return;
  2295. ignoreconfigurerequests = 1;
  2296. do {
  2297. XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  2298. switch(ev.type) {
  2299. case ConfigureRequest:
  2300. case Expose:
  2301. case MapRequest:
  2302. handler[ev.type](&ev);
  2303. break;
  2304. case MotionNotify:
  2305. if ((ev.xmotion.time - lasttime) <= (1000 / 60))
  2306. continue;
  2307. lasttime = ev.xmotion.time;
  2308. nx = ocx + (ev.xmotion.x - x);
  2309. ny = ocy + (ev.xmotion.y - y);
  2310. if (abs(selmon->wx - nx) < snap)
  2311. nx = selmon->wx;
  2312. else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
  2313. nx = selmon->wx + selmon->ww - WIDTH(c);
  2314. if (abs(selmon->wy - ny) < snap)
  2315. ny = selmon->wy;
  2316. else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
  2317. ny = selmon->wy + selmon->wh - HEIGHT(c);
  2318. if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
  2319. && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) {
  2320. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  2321. c->sfx = -9999; // disable savefloats when using movemouse
  2322. #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH
  2323. togglefloating(NULL);
  2324. }
  2325. if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
  2326. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  2327. resize(c, nx, ny, c->w, c->h, 1);
  2328. /* save last known float coordinates */
  2329. c->sfx = nx;
  2330. c->sfy = ny;
  2331. #else
  2332. resize(c, nx, ny, c->w, c->h, 1);
  2333. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  2334. }
  2335. #if ROUNDED_CORNERS_PATCH
  2336. drawroundedcorners(c);
  2337. #endif // ROUNDED_CORNERS_PATCH
  2338. break;
  2339. }
  2340. } while (ev.type != ButtonRelease);
  2341. XUngrabPointer(dpy, CurrentTime);
  2342. if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
  2343. #if SCRATCHPADS_PATCH
  2344. if (c->tags & SPTAGMASK) {
  2345. c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK);
  2346. m->tagset[m->seltags] |= (c->tags & SPTAGMASK);
  2347. }
  2348. #endif // SCRATCHPADS_PATCH
  2349. sendmon(c, m);
  2350. selmon = m;
  2351. focus(NULL);
  2352. }
  2353. #if ROUNDED_CORNERS_PATCH
  2354. drawroundedcorners(c);
  2355. #endif // ROUNDED_CORNERS_PATCH
  2356. ignoreconfigurerequests = 0;
  2357. }
  2358. Client *
  2359. nexttiled(Client *c)
  2360. {
  2361. #if BAR_WINTITLEACTIONS_PATCH
  2362. for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next);
  2363. #else
  2364. for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
  2365. #endif // BAR_WINTITLEACTIONS_PATCH
  2366. return c;
  2367. }
  2368. #if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH
  2369. void
  2370. pop(Client *c)
  2371. {
  2372. detach(c);
  2373. attach(c);
  2374. focus(c);
  2375. arrange(c->mon);
  2376. }
  2377. #endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
  2378. void
  2379. propertynotify(XEvent *e)
  2380. {
  2381. Client *c;
  2382. Window trans;
  2383. XPropertyEvent *ev = &e->xproperty;
  2384. #if BAR_SYSTRAY_PATCH
  2385. if (showsystray && (c = wintosystrayicon(ev->window))) {
  2386. if (ev->atom == XA_WM_NORMAL_HINTS) {
  2387. updatesizehints(c);
  2388. updatesystrayicongeom(c, c->w, c->h);
  2389. }
  2390. else
  2391. updatesystrayiconstate(c, ev);
  2392. drawbarwin(systray->bar);
  2393. }
  2394. #endif // BAR_SYSTRAY_PATCH
  2395. if ((ev->window == root) && (ev->atom == XA_WM_NAME)) {
  2396. #if DWMC_PATCH || FSIGNAL_PATCH
  2397. if (!fake_signal())
  2398. updatestatus();
  2399. #else
  2400. updatestatus();
  2401. #endif // DWMC_PATCH / FSIGNAL_PATCH
  2402. } else if (ev->state == PropertyDelete) {
  2403. return; /* ignore */
  2404. } else if ((c = wintoclient(ev->window))) {
  2405. switch(ev->atom) {
  2406. default: break;
  2407. case XA_WM_TRANSIENT_FOR:
  2408. if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
  2409. (c->isfloating = (wintoclient(trans)) != NULL))
  2410. arrange(c->mon);
  2411. break;
  2412. case XA_WM_NORMAL_HINTS:
  2413. updatesizehints(c);
  2414. break;
  2415. case XA_WM_HINTS:
  2416. updatewmhints(c);
  2417. if (c->isurgent)
  2418. drawbars();
  2419. break;
  2420. }
  2421. if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  2422. updatetitle(c);
  2423. if (c == c->mon->sel)
  2424. drawbar(c->mon);
  2425. }
  2426. #if DECORATION_HINTS_PATCH
  2427. if (ev->atom == motifatom)
  2428. updatemotifhints(c);
  2429. #endif // DECORATION_HINTS_PATCH
  2430. }
  2431. }
  2432. void
  2433. quit(const Arg *arg)
  2434. {
  2435. #if COOL_AUTOSTART_PATCH
  2436. size_t i;
  2437. #endif // COOL_AUTOSTART_PATCH
  2438. #if ONLYQUITONEMPTY_PATCH
  2439. unsigned int n;
  2440. Window *junk = malloc(1);
  2441. XQueryTree(dpy, root, junk, junk, &junk, &n);
  2442. #if COOL_AUTOSTART_PATCH
  2443. if (n - autostart_len <= quit_empty_window_count)
  2444. #else
  2445. if (n <= quit_empty_window_count)
  2446. #endif // COOL_AUTOSTART_PATCH
  2447. {
  2448. #if RESTARTSIG_PATCH
  2449. if (arg->i)
  2450. restart = 1;
  2451. #endif // RESTARTSIG_PATCH
  2452. running = 0;
  2453. }
  2454. else
  2455. printf("[dwm] not exiting (n=%d)\n", n);
  2456. free(junk);
  2457. #else
  2458. #if RESTARTSIG_PATCH
  2459. if (arg->i)
  2460. restart = 1;
  2461. #endif // RESTARTSIG_PATCH
  2462. running = 0;
  2463. #endif // ONLYQUITONEMPTY_PATCH
  2464. #if COOL_AUTOSTART_PATCH
  2465. /* kill child processes */
  2466. for (i = 0; i < autostart_len; i++) {
  2467. if (0 < autostart_pids[i]) {
  2468. kill(autostart_pids[i], SIGTERM);
  2469. waitpid(autostart_pids[i], NULL, 0);
  2470. }
  2471. }
  2472. #endif // COOL_AUTOSTART_PATCH
  2473. }
  2474. Monitor *
  2475. recttomon(int x, int y, int w, int h)
  2476. {
  2477. Monitor *m, *r = selmon;
  2478. int a, area = 0;
  2479. for (m = mons; m; m = m->next)
  2480. if ((a = INTERSECT(x, y, w, h, m)) > area) {
  2481. area = a;
  2482. r = m;
  2483. }
  2484. return r;
  2485. }
  2486. void
  2487. resize(Client *c, int x, int y, int w, int h, int interact)
  2488. {
  2489. if (applysizehints(c, &x, &y, &w, &h, interact))
  2490. resizeclient(c, x, y, w, h);
  2491. }
  2492. void
  2493. resizeclient(Client *c, int x, int y, int w, int h)
  2494. {
  2495. XWindowChanges wc;
  2496. c->oldx = c->x; c->x = wc.x = x;
  2497. c->oldy = c->y; c->y = wc.y = y;
  2498. c->oldw = c->w; c->w = wc.width = w;
  2499. c->oldh = c->h; c->h = wc.height = h;
  2500. #if EXRESIZE_PATCH
  2501. c->expandmask = 0;
  2502. #endif // EXRESIZE_PATCH
  2503. wc.border_width = c->bw;
  2504. #if NOBORDER_PATCH
  2505. if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next))
  2506. #if MONOCLE_LAYOUT
  2507. || &monocle == c->mon->lt[c->mon->sellt]->arrange
  2508. #endif // MONOCLE_LAYOUT
  2509. #if DECK_LAYOUT
  2510. || (&deck == c->mon->lt[c->mon->sellt]->arrange &&
  2511. c->mon->nmaster == 0)
  2512. #endif // DECK_LAYOUT
  2513. #if FLEXTILE_DELUXE_LAYOUT
  2514. || (&flextile == c->mon->lt[c->mon->sellt]->arrange && (
  2515. (c->mon->ltaxis[LAYOUT] == NO_SPLIT &&
  2516. c->mon->ltaxis[MASTER] == MONOCLE) ||
  2517. (c->mon->ltaxis[STACK] == MONOCLE &&
  2518. c->mon->nmaster == 0)))
  2519. #endif //FLEXTILE_DELUXE_LAYOUT
  2520. )
  2521. #if FAKEFULLSCREEN_CLIENT_PATCH
  2522. && (c->fakefullscreen == 1 || !c->isfullscreen)
  2523. #else
  2524. && !c->isfullscreen
  2525. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  2526. && !c->isfloating
  2527. && c->mon->lt[c->mon->sellt]->arrange) {
  2528. wc.width += c->bw * 2;
  2529. wc.height += c->bw * 2;
  2530. wc.border_width = 0;
  2531. }
  2532. #endif // NOBORDER_PATCH
  2533. XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
  2534. configure(c);
  2535. #if FAKEFULLSCREEN_CLIENT_PATCH
  2536. if (c->fakefullscreen == 1)
  2537. /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
  2538. * mode, then the focus would drift to whichever window is under the mouse cursor at the
  2539. * time. To avoid this we pass True to XSync which will make the X server disregard any
  2540. * other events in the queue thus cancelling the EnterNotify event that would otherwise
  2541. * have changed focus. */
  2542. XSync(dpy, True);
  2543. else
  2544. XSync(dpy, False);
  2545. #else
  2546. XSync(dpy, False);
  2547. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  2548. }
  2549. void
  2550. resizemouse(const Arg *arg)
  2551. {
  2552. int ocx, ocy, nw, nh;
  2553. #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
  2554. int opx, opy, och, ocw, nx, ny;
  2555. int horizcorner, vertcorner;
  2556. unsigned int dui;
  2557. Window dummy;
  2558. #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
  2559. Client *c;
  2560. Monitor *m;
  2561. XEvent ev;
  2562. Time lasttime = 0;
  2563. if (!(c = selmon->sel))
  2564. return;
  2565. #if !FAKEFULLSCREEN_PATCH
  2566. #if FAKEFULLSCREEN_CLIENT_PATCH
  2567. if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
  2568. return;
  2569. #else
  2570. if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
  2571. return;
  2572. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  2573. #endif // !FAKEFULLSCREEN_PATCH
  2574. restack(selmon);
  2575. ocx = c->x;
  2576. ocy = c->y;
  2577. #if RESIZEPOINT_PATCH
  2578. och = c->h;
  2579. ocw = c->w;
  2580. #elif RESIZECORNERS_PATCH
  2581. och = c->y + c->h;
  2582. ocw = c->x + c->w;
  2583. #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
  2584. #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
  2585. if (!XQueryPointer(dpy, c->win, &dummy, &dummy, &opx, &opy, &nx, &ny, &dui))
  2586. return;
  2587. horizcorner = nx < c->w / 2;
  2588. vertcorner = ny < c->h / 2;
  2589. if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  2590. None, cursor[horizcorner | (vertcorner << 1)]->cursor, CurrentTime) != GrabSuccess)
  2591. return;
  2592. #if RESIZECORNERS_PATCH
  2593. XWarpPointer (dpy, None, c->win, 0, 0, 0, 0,
  2594. horizcorner ? (-c->bw) : (c->w + c->bw - 1),
  2595. vertcorner ? (-c->bw) : (c->h + c->bw - 1));
  2596. #endif // RESIZECORNERS_PATCH
  2597. #else
  2598. if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  2599. None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
  2600. return;
  2601. XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  2602. #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
  2603. ignoreconfigurerequests = 1;
  2604. do {
  2605. XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  2606. switch(ev.type) {
  2607. case ConfigureRequest:
  2608. case Expose:
  2609. case MapRequest:
  2610. handler[ev.type](&ev);
  2611. break;
  2612. case MotionNotify:
  2613. if ((ev.xmotion.time - lasttime) <= (1000 / 60))
  2614. continue;
  2615. lasttime = ev.xmotion.time;
  2616. #if RESIZEPOINT_PATCH
  2617. nx = horizcorner ? (ocx + ev.xmotion.x - opx) : c->x;
  2618. ny = vertcorner ? (ocy + ev.xmotion.y - opy) : c->y;
  2619. nw = MAX(horizcorner ? (ocx + ocw - nx) : (ocw + (ev.xmotion.x - opx)), 1);
  2620. nh = MAX(vertcorner ? (ocy + och - ny) : (och + (ev.xmotion.y - opy)), 1);
  2621. #elif RESIZECORNERS_PATCH
  2622. nx = horizcorner ? ev.xmotion.x : c->x;
  2623. ny = vertcorner ? ev.xmotion.y : c->y;
  2624. nw = MAX(horizcorner ? (ocw - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1);
  2625. nh = MAX(vertcorner ? (och - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1);
  2626. #else
  2627. nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
  2628. nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
  2629. #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
  2630. if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
  2631. && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
  2632. {
  2633. if (!c->isfloating && selmon->lt[selmon->sellt]->arrange
  2634. && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) {
  2635. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  2636. c->sfx = -9999; // disable savefloats when using resizemouse
  2637. #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH
  2638. togglefloating(NULL);
  2639. }
  2640. }
  2641. if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) {
  2642. #if RESIZECORNERS_PATCH || RESIZEPOINT_PATCH
  2643. resizeclient(c, nx, ny, nw, nh);
  2644. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  2645. /* save last known float dimensions */
  2646. c->sfx = nx;
  2647. c->sfy = ny;
  2648. c->sfw = nw;
  2649. c->sfh = nh;
  2650. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  2651. #else
  2652. resize(c, c->x, c->y, nw, nh, 1);
  2653. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  2654. c->sfx = c->x;
  2655. c->sfy = c->y;
  2656. c->sfw = nw;
  2657. c->sfh = nh;
  2658. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  2659. #endif // RESIZECORNERS_PATCH
  2660. #if ROUNDED_CORNERS_PATCH
  2661. drawroundedcorners(c);
  2662. #endif // ROUNDED_CORNERS_PATCH
  2663. }
  2664. break;
  2665. }
  2666. } while (ev.type != ButtonRelease);
  2667. #if !RESIZEPOINT_PATCH
  2668. #if RESIZECORNERS_PATCH
  2669. XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
  2670. horizcorner ? (-c->bw) : (c->w + c->bw - 1),
  2671. vertcorner ? (-c->bw) : (c->h + c->bw - 1));
  2672. #else
  2673. XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  2674. #endif // RESIZECORNERS_PATCH
  2675. #endif // RESIZEPOINT_PATCH
  2676. XUngrabPointer(dpy, CurrentTime);
  2677. while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  2678. if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
  2679. #if SCRATCHPADS_PATCH
  2680. if (c->tags & SPTAGMASK) {
  2681. c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK);
  2682. m->tagset[m->seltags] |= (c->tags & SPTAGMASK);
  2683. }
  2684. #endif // SCRATCHPADS_PATCH
  2685. sendmon(c, m);
  2686. selmon = m;
  2687. focus(NULL);
  2688. }
  2689. ignoreconfigurerequests = 0;
  2690. }
  2691. void
  2692. restack(Monitor *m)
  2693. {
  2694. Client *c;
  2695. XEvent ev;
  2696. XWindowChanges wc;
  2697. #if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT
  2698. int n;
  2699. #endif // WARP_PATCH
  2700. drawbar(m);
  2701. if (!m->sel)
  2702. return;
  2703. if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
  2704. XRaiseWindow(dpy, m->sel->win);
  2705. if (m->lt[m->sellt]->arrange) {
  2706. wc.stack_mode = Below;
  2707. wc.sibling = m->bar->win;
  2708. for (c = m->stack; c; c = c->snext)
  2709. if (!c->isfloating && ISVISIBLE(c)) {
  2710. XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
  2711. wc.sibling = c->win;
  2712. }
  2713. }
  2714. XSync(dpy, False);
  2715. while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  2716. #if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT || WARP_PATCH && MONOCLE_LAYOUT
  2717. #if FLEXTILE_DELUXE_LAYOUT
  2718. for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
  2719. #endif // FLEXTILE_DELUXE_LAYOUT
  2720. if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && (
  2721. #if MONOCLE_LAYOUT && FLEXTILE_DELUXE_LAYOUT
  2722. (m->lt[m->sellt]->arrange != &monocle
  2723. && !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster))))
  2724. #elif MONOCLE_LAYOUT
  2725. m->lt[m->sellt]->arrange != &monocle
  2726. #else
  2727. !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster)))
  2728. #endif // FLEXTILE_DELUXE_LAYOUT
  2729. || m->sel->isfloating)
  2730. )
  2731. warp(m->sel);
  2732. #endif // WARP_PATCH
  2733. }
  2734. #if IPC_PATCH
  2735. void
  2736. run(void)
  2737. {
  2738. int event_count = 0;
  2739. const int MAX_EVENTS = 10;
  2740. struct epoll_event events[MAX_EVENTS];
  2741. XSync(dpy, False);
  2742. /* main event loop */
  2743. while (running) {
  2744. event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
  2745. for (int i = 0; i < event_count; i++) {
  2746. int event_fd = events[i].data.fd;
  2747. DEBUG("Got event from fd %d\n", event_fd);
  2748. if (event_fd == dpy_fd) {
  2749. // -1 means EPOLLHUP
  2750. if (handlexevent(events + i) == -1)
  2751. return;
  2752. } else if (event_fd == ipc_get_sock_fd()) {
  2753. ipc_handle_socket_epoll_event(events + i);
  2754. } else if (ipc_is_client_registered(event_fd)) {
  2755. if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon,
  2756. NUMTAGS, layouts, LENGTH(layouts)) < 0) {
  2757. fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd);
  2758. }
  2759. } else {
  2760. fprintf(stderr, "Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu",
  2761. event_fd, events[i].data.ptr, events[i].data.u32,
  2762. events[i].data.u64);
  2763. fprintf(stderr, " with events %d\n", events[i].events);
  2764. return;
  2765. }
  2766. }
  2767. }
  2768. }
  2769. #else
  2770. void
  2771. run(void)
  2772. {
  2773. XEvent ev;
  2774. /* main event loop */
  2775. XSync(dpy, False);
  2776. while (running && !XNextEvent(dpy, &ev))
  2777. if (handler[ev.type])
  2778. handler[ev.type](&ev); /* call handler */
  2779. }
  2780. #endif // IPC_PATCH
  2781. void
  2782. scan(void)
  2783. {
  2784. #if SWALLOW_PATCH
  2785. scanner = 1;
  2786. char swin[256];
  2787. #endif // SWALLOW_PATCH
  2788. unsigned int i, num;
  2789. Window d1, d2, *wins = NULL;
  2790. XWindowAttributes wa;
  2791. if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
  2792. for (i = 0; i < num; i++) {
  2793. if (!XGetWindowAttributes(dpy, wins[i], &wa)
  2794. || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
  2795. continue;
  2796. #if BAR_ANYBAR_PATCH
  2797. if (wmclasscontains(wins[i], altbarclass, ""))
  2798. managealtbar(wins[i], &wa);
  2799. else
  2800. #endif // BAR_ANYBAR_PATCH
  2801. if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
  2802. manage(wins[i], &wa);
  2803. #if SWALLOW_PATCH
  2804. else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin))
  2805. manage(wins[i], &wa);
  2806. #endif // SWALLOW_PATCH
  2807. }
  2808. for (i = 0; i < num; i++) { /* now the transients */
  2809. if (!XGetWindowAttributes(dpy, wins[i], &wa))
  2810. continue;
  2811. if (XGetTransientForHint(dpy, wins[i], &d1)
  2812. && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
  2813. manage(wins[i], &wa);
  2814. }
  2815. XFree(wins);
  2816. }
  2817. #if SWALLOW_PATCH
  2818. scanner = 0;
  2819. #endif // SWALLOW_PATCH
  2820. }
  2821. void
  2822. sendmon(Client *c, Monitor *m)
  2823. {
  2824. #if EXRESIZE_PATCH
  2825. Monitor *oldm = selmon;
  2826. #endif // EXRESIZE_PATCH
  2827. if (c->mon == m)
  2828. return;
  2829. #if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH
  2830. int hadfocus = (c == selmon->sel);
  2831. #endif // SENDMON_KEEPFOCUS_PATCH
  2832. unfocus(c, 1, NULL);
  2833. detach(c);
  2834. detachstack(c);
  2835. #if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH
  2836. arrange(c->mon);
  2837. #endif // SENDMON_KEEPFOCUS_PATCH
  2838. c->mon = m;
  2839. #if SCRATCHPADS_PATCH
  2840. if (!(c->tags & SPTAGMASK))
  2841. #endif // SCRATCHPADS_PATCH
  2842. #if EMPTYVIEW_PATCH
  2843. c->tags = (m->tagset[m->seltags] ? m->tagset[m->seltags] : 1);
  2844. #else
  2845. c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
  2846. #endif // EMPTYVIEW_PATCH
  2847. #if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH
  2848. attachx(c);
  2849. #else
  2850. attach(c);
  2851. #endif
  2852. attachstack(c);
  2853. #if EXRESIZE_PATCH
  2854. if (oldm != m)
  2855. arrange(oldm);
  2856. arrange(m);
  2857. focus(c);
  2858. restack(m);
  2859. #elif SENDMON_KEEPFOCUS_PATCH
  2860. arrange(m);
  2861. if (hadfocus) {
  2862. focus(c);
  2863. restack(m);
  2864. } else
  2865. focus(NULL);
  2866. #else
  2867. focus(NULL);
  2868. arrange(NULL);
  2869. #endif // EXRESIZE_PATCH / SENDMON_KEEPFOCUS_PATCH
  2870. #if SWITCHTAG_PATCH
  2871. if (c->switchtag)
  2872. c->switchtag = 0;
  2873. #endif // SWITCHTAG_PATCH
  2874. }
  2875. void
  2876. setclientstate(Client *c, long state)
  2877. {
  2878. long data[] = { state, None };
  2879. XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  2880. PropModeReplace, (unsigned char *)data, 2);
  2881. }
  2882. int
  2883. #if BAR_SYSTRAY_PATCH
  2884. sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
  2885. #else
  2886. sendevent(Client *c, Atom proto)
  2887. #endif // BAR_SYSTRAY_PATCH
  2888. {
  2889. int n;
  2890. Atom *protocols;
  2891. #if BAR_SYSTRAY_PATCH
  2892. Atom mt;
  2893. #endif // BAR_SYSTRAY_PATCH
  2894. int exists = 0;
  2895. XEvent ev;
  2896. #if BAR_SYSTRAY_PATCH
  2897. if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
  2898. mt = wmatom[WMProtocols];
  2899. if (XGetWMProtocols(dpy, w, &protocols, &n)) {
  2900. while (!exists && n--)
  2901. exists = protocols[n] == proto;
  2902. XFree(protocols);
  2903. }
  2904. } else {
  2905. exists = True;
  2906. mt = proto;
  2907. }
  2908. #else
  2909. if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
  2910. while (!exists && n--)
  2911. exists = protocols[n] == proto;
  2912. XFree(protocols);
  2913. }
  2914. #endif // BAR_SYSTRAY_PATCH
  2915. if (exists) {
  2916. #if BAR_SYSTRAY_PATCH
  2917. ev.type = ClientMessage;
  2918. ev.xclient.window = w;
  2919. ev.xclient.message_type = mt;
  2920. ev.xclient.format = 32;
  2921. ev.xclient.data.l[0] = d0;
  2922. ev.xclient.data.l[1] = d1;
  2923. ev.xclient.data.l[2] = d2;
  2924. ev.xclient.data.l[3] = d3;
  2925. ev.xclient.data.l[4] = d4;
  2926. XSendEvent(dpy, w, False, mask, &ev);
  2927. #else
  2928. ev.type = ClientMessage;
  2929. ev.xclient.window = c->win;
  2930. ev.xclient.message_type = wmatom[WMProtocols];
  2931. ev.xclient.format = 32;
  2932. ev.xclient.data.l[0] = proto;
  2933. ev.xclient.data.l[1] = CurrentTime;
  2934. XSendEvent(dpy, c->win, False, NoEventMask, &ev);
  2935. #endif // BAR_SYSTRAY_PATCH
  2936. }
  2937. return exists;
  2938. }
  2939. void
  2940. setfocus(Client *c)
  2941. {
  2942. if (!c->neverfocus) {
  2943. XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  2944. XChangeProperty(dpy, root, netatom[NetActiveWindow],
  2945. XA_WINDOW, 32, PropModeReplace,
  2946. (unsigned char *) &(c->win), 1);
  2947. }
  2948. #if BAR_SYSTRAY_PATCH
  2949. sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
  2950. #else
  2951. sendevent(c, wmatom[WMTakeFocus]);
  2952. #endif // BAR_SYSTRAY_PATCH
  2953. }
  2954. #if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH
  2955. void
  2956. setfullscreen(Client *c, int fullscreen)
  2957. {
  2958. int savestate = 0, restorestate = 0;
  2959. if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
  2960. || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
  2961. savestate = 1; // go actual fullscreen
  2962. else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
  2963. || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
  2964. restorestate = 1; // go back into tiled
  2965. /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
  2966. * that while staying in fullscreen. The exception to this is if we are in said state, but
  2967. * the client itself disables fullscreen (3) then we let the client go out of fullscreen
  2968. * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
  2969. * client and the window manager's perception of the client's fullscreen state). */
  2970. if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
  2971. c->fakefullscreen = 1;
  2972. c->isfullscreen = 1;
  2973. fullscreen = 1;
  2974. } else if (c->fakefullscreen == 3) // client exiting actual fullscreen
  2975. c->fakefullscreen = 1;
  2976. if (fullscreen != c->isfullscreen) { // only send property change if necessary
  2977. if (fullscreen)
  2978. XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
  2979. PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
  2980. else
  2981. XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
  2982. PropModeReplace, (unsigned char*)0, 0);
  2983. }
  2984. c->isfullscreen = fullscreen;
  2985. /* Some clients, e.g. firefox, will send a client message informing the window manager
  2986. * that it is going into fullscreen after receiving the above signal. This has the side
  2987. * effect of this function (setfullscreen) sometimes being called twice when toggling
  2988. * fullscreen on and off via the window manager as opposed to the application itself.
  2989. * To protect against obscure issues where the client settings are stored or restored
  2990. * when they are not supposed to we add an additional bit-lock on the old state so that
  2991. * settings can only be stored and restored in that precise order. */
  2992. if (savestate && !(c->oldstate & (1 << 1))) {
  2993. c->oldbw = c->bw;
  2994. c->oldstate = c->isfloating | (1 << 1);
  2995. c->bw = 0;
  2996. c->isfloating = 1;
  2997. resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
  2998. XRaiseWindow(dpy, c->win);
  2999. } else if (restorestate && (c->oldstate & (1 << 1))) {
  3000. c->bw = c->oldbw;
  3001. c->isfloating = c->oldstate = c->oldstate & 1;
  3002. c->x = c->oldx;
  3003. c->y = c->oldy;
  3004. c->w = c->oldw;
  3005. c->h = c->oldh;
  3006. resizeclient(c, c->x, c->y, c->w, c->h);
  3007. restack(c->mon);
  3008. } else
  3009. resizeclient(c, c->x, c->y, c->w, c->h);
  3010. }
  3011. #else
  3012. void
  3013. setfullscreen(Client *c, int fullscreen)
  3014. {
  3015. if (fullscreen && !c->isfullscreen) {
  3016. XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
  3017. PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
  3018. c->isfullscreen = 1;
  3019. #if !FAKEFULLSCREEN_PATCH
  3020. c->oldbw = c->bw;
  3021. c->oldstate = c->isfloating;
  3022. c->bw = 0;
  3023. c->isfloating = 1;
  3024. resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
  3025. XRaiseWindow(dpy, c->win);
  3026. #endif // !FAKEFULLSCREEN_PATCH
  3027. } else if (!fullscreen && c->isfullscreen){
  3028. XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
  3029. PropModeReplace, (unsigned char*)0, 0);
  3030. c->isfullscreen = 0;
  3031. #if !FAKEFULLSCREEN_PATCH
  3032. c->bw = c->oldbw;
  3033. c->isfloating = c->oldstate;
  3034. c->x = c->oldx;
  3035. c->y = c->oldy;
  3036. c->w = c->oldw;
  3037. c->h = c->oldh;
  3038. resizeclient(c, c->x, c->y, c->w, c->h);
  3039. arrange(c->mon);
  3040. #endif // !FAKEFULLSCREEN_PATCH
  3041. }
  3042. }
  3043. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  3044. void
  3045. setlayout(const Arg *arg)
  3046. {
  3047. if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
  3048. #if PERTAG_PATCH
  3049. selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
  3050. selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  3051. #else
  3052. selmon->sellt ^= 1;
  3053. #endif // PERTAG_PATCH
  3054. #if EXRESIZE_PATCH
  3055. if (!selmon->lt[selmon->sellt]->arrange) {
  3056. for (Client *c = selmon->clients ; c ; c = c->next) {
  3057. if (!c->isfloating) {
  3058. /*restore last known float dimensions*/
  3059. resize(c, selmon->mx + c->sfx, selmon->my + c->sfy,
  3060. c->sfw, c->sfh, False);
  3061. }
  3062. }
  3063. }
  3064. #endif // EXRESIZE_PATCH
  3065. }
  3066. if (arg && arg->v)
  3067. #if PERTAG_PATCH
  3068. selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
  3069. selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  3070. #else
  3071. selmon->lt[selmon->sellt] = (Layout *)arg->v;
  3072. #endif // PERTAG_PATCH
  3073. #if FLEXTILE_DELUXE_LAYOUT
  3074. if (selmon->lt[selmon->sellt]->preset.nmaster && selmon->lt[selmon->sellt]->preset.nmaster != -1)
  3075. selmon->nmaster = selmon->lt[selmon->sellt]->preset.nmaster;
  3076. if (selmon->lt[selmon->sellt]->preset.nstack && selmon->lt[selmon->sellt]->preset.nstack != -1)
  3077. selmon->nstack = selmon->lt[selmon->sellt]->preset.nstack;
  3078. selmon->ltaxis[LAYOUT] = selmon->lt[selmon->sellt]->preset.layout;
  3079. selmon->ltaxis[MASTER] = selmon->lt[selmon->sellt]->preset.masteraxis;
  3080. selmon->ltaxis[STACK] = selmon->lt[selmon->sellt]->preset.stack1axis;
  3081. selmon->ltaxis[STACK2] = selmon->lt[selmon->sellt]->preset.stack2axis;
  3082. #if PERTAG_PATCH
  3083. selmon->pertag->ltaxis[selmon->pertag->curtag][LAYOUT] = selmon->ltaxis[LAYOUT];
  3084. selmon->pertag->ltaxis[selmon->pertag->curtag][MASTER] = selmon->ltaxis[MASTER];
  3085. selmon->pertag->ltaxis[selmon->pertag->curtag][STACK] = selmon->ltaxis[STACK];
  3086. selmon->pertag->ltaxis[selmon->pertag->curtag][STACK2] = selmon->ltaxis[STACK2];
  3087. #endif // PERTAG_PATCH
  3088. #endif // FLEXTILE_DELUXE_LAYOUT
  3089. strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
  3090. if (selmon->sel)
  3091. arrange(selmon);
  3092. else
  3093. drawbar(selmon);
  3094. }
  3095. /* arg > 1.0 will set mfact absolutely */
  3096. void
  3097. setmfact(const Arg *arg)
  3098. {
  3099. float f;
  3100. if (!arg || !selmon->lt[selmon->sellt]->arrange)
  3101. return;
  3102. f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
  3103. if (f < 0.05 || f > 0.95)
  3104. return;
  3105. #if PERTAG_PATCH
  3106. selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
  3107. #else
  3108. selmon->mfact = f;
  3109. #endif // PERTAG_PATCH
  3110. arrange(selmon);
  3111. }
  3112. void
  3113. setup(void)
  3114. {
  3115. int i;
  3116. XSetWindowAttributes wa;
  3117. Atom utf8string;
  3118. /* clean up any zombies immediately */
  3119. sigchld(0);
  3120. #if RESTARTSIG_PATCH
  3121. signal(SIGHUP, sighup);
  3122. signal(SIGTERM, sigterm);
  3123. #endif // RESTARTSIG_PATCH
  3124. /* init screen */
  3125. screen = DefaultScreen(dpy);
  3126. sw = DisplayWidth(dpy, screen);
  3127. sh = DisplayHeight(dpy, screen);
  3128. root = RootWindow(dpy, screen);
  3129. #if BAR_ALPHA_PATCH
  3130. xinitvisual();
  3131. drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
  3132. #else
  3133. drw = drw_create(dpy, screen, root, sw, sh);
  3134. #endif // BAR_ALPHA_PATCH
  3135. #if BAR_PANGO_PATCH
  3136. if (!drw_font_create(drw, font))
  3137. #else
  3138. if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
  3139. #endif // BAR_PANGO_PATCH
  3140. die("no fonts could be loaded.");
  3141. #if BAR_STATUSPADDING_PATCH
  3142. lrpad = drw->fonts->h + horizpadbar;
  3143. bh = drw->fonts->h + vertpadbar;
  3144. #else
  3145. lrpad = drw->fonts->h;
  3146. #if BAR_HEIGHT_PATCH
  3147. bh = bar_height ? bar_height : drw->fonts->h + 2;
  3148. #else
  3149. bh = drw->fonts->h + 2;
  3150. #endif // BAR_HEIGHT_PATCH
  3151. #endif // BAR_STATUSPADDING_PATCH
  3152. updategeom();
  3153. /* init atoms */
  3154. utf8string = XInternAtom(dpy, "UTF8_STRING", False);
  3155. wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  3156. wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  3157. wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  3158. wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
  3159. #if WINDOWROLERULE_PATCH
  3160. wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
  3161. #endif // WINDOWROLERULE_PATCH
  3162. netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
  3163. netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  3164. #if BAR_SYSTRAY_PATCH
  3165. netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
  3166. netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
  3167. netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
  3168. netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
  3169. netatom[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False);
  3170. netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
  3171. xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
  3172. xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
  3173. xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
  3174. #endif // BAR_SYSTRAY_PATCH
  3175. #if BAR_EWMHTAGS_PATCH
  3176. netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False);
  3177. netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
  3178. netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
  3179. netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
  3180. #endif // BAR_EWMHTAGS_PATCH
  3181. netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  3182. netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  3183. netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
  3184. netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
  3185. netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
  3186. netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
  3187. #if NET_CLIENT_LIST_STACKING_PATCH
  3188. netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
  3189. #endif // NET_CLIENT_LIST_STACKING_PATCH
  3190. #if DECORATION_HINTS_PATCH
  3191. motifatom = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
  3192. #endif // DECORATION_HINTS_PATCH
  3193. /* init cursors */
  3194. cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
  3195. cursor[CurResize] = drw_cur_create(drw, XC_sizing);
  3196. #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH
  3197. cursor[CurResizeBR] = drw_cur_create(drw, XC_bottom_right_corner);
  3198. cursor[CurResizeBL] = drw_cur_create(drw, XC_bottom_left_corner);
  3199. cursor[CurResizeTR] = drw_cur_create(drw, XC_top_right_corner);
  3200. cursor[CurResizeTL] = drw_cur_create(drw, XC_top_left_corner);
  3201. #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH
  3202. #if DRAGMFACT_PATCH
  3203. cursor[CurResizeHorzArrow] = drw_cur_create(drw, XC_sb_h_double_arrow);
  3204. cursor[CurResizeVertArrow] = drw_cur_create(drw, XC_sb_v_double_arrow);
  3205. #endif // DRAGMFACT_PATCH
  3206. #if DRAGCFACT_PATCH
  3207. cursor[CurIronCross] = drw_cur_create(drw, XC_iron_cross);
  3208. #endif // DRAGCFACT_PATCH
  3209. cursor[CurMove] = drw_cur_create(drw, XC_fleur);
  3210. /* init appearance */
  3211. #if BAR_VTCOLORS_PATCH
  3212. get_vt_colors();
  3213. if (get_luminance(colors[SchemeTagsNorm][ColBg]) > 50) {
  3214. strcpy(colors[SchemeTitleNorm][ColBg], title_bg_light);
  3215. strcpy(colors[SchemeTitleSel][ColBg], title_bg_light);
  3216. } else {
  3217. strcpy(colors[SchemeTitleNorm][ColBg], title_bg_dark);
  3218. strcpy(colors[SchemeTitleSel][ColBg], title_bg_dark);
  3219. }
  3220. #endif // BAR_VTCOLORS_PATCH
  3221. #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH
  3222. scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
  3223. #if BAR_ALPHA_PATCH
  3224. scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], alphas[0], ColCount);
  3225. #else
  3226. scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], ColCount);
  3227. #endif // BAR_ALPHA_PATCH
  3228. #else
  3229. scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
  3230. #endif // BAR_STATUS2D_PATCH
  3231. for (i = 0; i < LENGTH(colors); i++)
  3232. #if BAR_ALPHA_PATCH
  3233. scheme[i] = drw_scm_create(drw, colors[i], alphas[i], ColCount);
  3234. #else
  3235. scheme[i] = drw_scm_create(drw, colors[i], ColCount);
  3236. #endif // BAR_ALPHA_PATCH
  3237. #if BAR_POWERLINE_STATUS_PATCH
  3238. statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *));
  3239. for (i = 0; i < LENGTH(statuscolors); i++)
  3240. #if BAR_ALPHA_PATCH
  3241. statusscheme[i] = drw_scm_create(drw, statuscolors[i], alphas[0], ColCount);
  3242. #else
  3243. statusscheme[i] = drw_scm_create(drw, statuscolors[i], ColCount);
  3244. #endif // BAR_ALPHA_PATCH
  3245. #endif // BAR_POWERLINE_STATUS_PATCH
  3246. updatebars();
  3247. updatestatus();
  3248. /* supporting window for NetWMCheck */
  3249. wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
  3250. XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
  3251. PropModeReplace, (unsigned char *) &wmcheckwin, 1);
  3252. XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
  3253. PropModeReplace, (unsigned char *) "dwm", 3);
  3254. XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
  3255. PropModeReplace, (unsigned char *) &wmcheckwin, 1);
  3256. /* EWMH support per view */
  3257. XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  3258. PropModeReplace, (unsigned char *) netatom, NetLast);
  3259. #if BAR_EWMHTAGS_PATCH
  3260. setnumdesktops();
  3261. setcurrentdesktop();
  3262. setdesktopnames();
  3263. setviewport();
  3264. #endif // BAR_EWMHTAGS_PATCH
  3265. XDeleteProperty(dpy, root, netatom[NetClientList]);
  3266. #if NET_CLIENT_LIST_STACKING_PATCH
  3267. XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
  3268. #endif // NET_CLIENT_LIST_STACKING_PATCH
  3269. /* select events */
  3270. wa.cursor = cursor[CurNormal]->cursor;
  3271. wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
  3272. |ButtonPressMask|PointerMotionMask|EnterWindowMask
  3273. |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
  3274. XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  3275. XSelectInput(dpy, root, wa.event_mask);
  3276. grabkeys();
  3277. focus(NULL);
  3278. #if IPC_PATCH
  3279. setupepoll();
  3280. #endif // IPC_PATCH
  3281. #if BAR_ANYBAR_PATCH
  3282. if (usealtbar)
  3283. spawnbar();
  3284. #endif // BAR_ANYBAR_PATCH
  3285. }
  3286. void
  3287. seturgent(Client *c, int urg)
  3288. {
  3289. XWMHints *wmh;
  3290. c->isurgent = urg;
  3291. if (!(wmh = XGetWMHints(dpy, c->win)))
  3292. return;
  3293. wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
  3294. XSetWMHints(dpy, c->win, wmh);
  3295. XFree(wmh);
  3296. }
  3297. void
  3298. showhide(Client *c)
  3299. {
  3300. if (!c)
  3301. return;
  3302. if (ISVISIBLE(c)) {
  3303. #if SCRATCHPADS_PATCH && SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH
  3304. if (
  3305. (c->tags & SPTAGMASK) &&
  3306. c->isfloating &&
  3307. (
  3308. c->x < c->mon->mx ||
  3309. c->x > c->mon->mx + c->mon->mw ||
  3310. c->y < c->mon->my ||
  3311. c->y > c->mon->my + c->mon->mh
  3312. )
  3313. ) {
  3314. c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
  3315. c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
  3316. }
  3317. #elif SCRATCHPADS_PATCH
  3318. if ((c->tags & SPTAGMASK) && c->isfloating) {
  3319. c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
  3320. c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
  3321. }
  3322. #endif // SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH | SCRATCHPADS_PATCH
  3323. /* show clients top down */
  3324. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  3325. if (!c->mon->lt[c->mon->sellt]->arrange && c->sfx != -9999 && !c->isfullscreen) {
  3326. XMoveWindow(dpy, c->win, c->sfx, c->sfy);
  3327. resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
  3328. showhide(c->snext);
  3329. return;
  3330. }
  3331. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  3332. #if AUTORESIZE_PATCH
  3333. if (c->needresize) {
  3334. c->needresize = 0;
  3335. XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
  3336. } else {
  3337. XMoveWindow(dpy, c->win, c->x, c->y);
  3338. }
  3339. #else
  3340. XMoveWindow(dpy, c->win, c->x, c->y);
  3341. #endif // AUTORESIZE_PATCH
  3342. if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating)
  3343. #if !FAKEFULLSCREEN_PATCH
  3344. && !c->isfullscreen
  3345. #endif // !FAKEFULLSCREEN_PATCH
  3346. )
  3347. resize(c, c->x, c->y, c->w, c->h, 0);
  3348. showhide(c->snext);
  3349. } else {
  3350. /* hide clients bottom up */
  3351. showhide(c->snext);
  3352. XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
  3353. }
  3354. }
  3355. void
  3356. sigchld(int unused)
  3357. {
  3358. #if COOL_AUTOSTART_PATCH
  3359. pid_t pid;
  3360. #endif // COOL_AUTOSTART_PATCH
  3361. if (signal(SIGCHLD, sigchld) == SIG_ERR)
  3362. die("can't install SIGCHLD handler:");
  3363. #if COOL_AUTOSTART_PATCH
  3364. while (0 < (pid = waitpid(-1, NULL, WNOHANG))) {
  3365. pid_t *p, *lim;
  3366. if (!(p = autostart_pids))
  3367. continue;
  3368. lim = &p[autostart_len];
  3369. for (; p < lim; p++) {
  3370. if (*p == pid) {
  3371. *p = -1;
  3372. break;
  3373. }
  3374. }
  3375. }
  3376. #else
  3377. while (0 < waitpid(-1, NULL, WNOHANG));
  3378. #endif // COOL_AUTOSTART_PATCH
  3379. }
  3380. #if RIODRAW_PATCH
  3381. void
  3382. spawn(const Arg *arg)
  3383. {
  3384. spawncmd(arg);
  3385. }
  3386. pid_t
  3387. spawncmd(const Arg *arg)
  3388. #else
  3389. void
  3390. spawn(const Arg *arg)
  3391. #endif // RIODRAW_PATCH
  3392. {
  3393. #if RIODRAW_PATCH
  3394. pid_t pid;
  3395. #endif // RIODRAW_PATCH
  3396. #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH
  3397. char *cmd = NULL;
  3398. #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH
  3399. #if !NODMENU_PATCH
  3400. if (arg->v == dmenucmd)
  3401. dmenumon[0] = '0' + selmon->num;
  3402. #endif // NODMENU_PATCH
  3403. #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH
  3404. #if !NODMENU_PATCH
  3405. else if (arg->v == statuscmd)
  3406. #else
  3407. if (arg->v == statuscmd)
  3408. #endif // NODMENU_PATCH
  3409. {
  3410. int len = strlen(statuscmds[statuscmdn]) + 1;
  3411. if (!(cmd = malloc(sizeof(char)*len + sizeof(statusexport))))
  3412. die("malloc:");
  3413. strcpy(cmd, statusexport);
  3414. strcat(cmd, statuscmds[statuscmdn]);
  3415. cmd[LENGTH(statusexport)-3] = '0' + lastbutton;
  3416. statuscmd[2] = cmd;
  3417. }
  3418. #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH
  3419. #if RIODRAW_PATCH
  3420. if ((pid = fork()) == 0)
  3421. #else
  3422. if (fork() == 0)
  3423. #endif // RIODRAW_PATCH
  3424. {
  3425. if (dpy)
  3426. close(ConnectionNumber(dpy));
  3427. #if SPAWNCMD_PATCH
  3428. if (selmon->sel) {
  3429. const char* const home = getenv("HOME");
  3430. assert(home && strchr(home, '/'));
  3431. const size_t homelen = strlen(home);
  3432. char *cwd, *pathbuf = NULL;
  3433. struct stat statbuf;
  3434. cwd = strtok(selmon->sel->name, SPAWN_CWD_DELIM);
  3435. /* NOTE: strtok() alters selmon->sel->name in-place,
  3436. * but that does not matter because we are going to
  3437. * exec() below anyway; nothing else will use it */
  3438. while (cwd) {
  3439. if (*cwd == '~') { /* replace ~ with $HOME */
  3440. if (!(pathbuf = malloc(homelen + strlen(cwd)))) /* ~ counts for NULL term */
  3441. die("fatal: could not malloc() %u bytes\n", homelen + strlen(cwd));
  3442. strcpy(strcpy(pathbuf, home) + homelen, cwd + 1);
  3443. cwd = pathbuf;
  3444. }
  3445. if (strchr(cwd, '/') && !stat(cwd, &statbuf)) {
  3446. if (!S_ISDIR(statbuf.st_mode))
  3447. cwd = dirname(cwd);
  3448. if (!chdir(cwd))
  3449. break;
  3450. }
  3451. cwd = strtok(NULL, SPAWN_CWD_DELIM);
  3452. }
  3453. free(pathbuf);
  3454. }
  3455. #endif // SPAWNCMD_PATCH
  3456. setsid();
  3457. execvp(((char **)arg->v)[0], (char **)arg->v);
  3458. fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
  3459. perror(" failed");
  3460. exit(EXIT_SUCCESS);
  3461. }
  3462. #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH
  3463. free(cmd);
  3464. #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH
  3465. #if RIODRAW_PATCH
  3466. return pid;
  3467. #endif // RIODRAW_PATCH
  3468. }
  3469. void
  3470. tag(const Arg *arg)
  3471. {
  3472. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  3473. unsigned int tagmask, tagindex;
  3474. #endif // SWAPFOCUS_PATCH
  3475. if (selmon->sel && arg->ui & TAGMASK) {
  3476. selmon->sel->tags = arg->ui & TAGMASK;
  3477. #if SWITCHTAG_PATCH
  3478. if (selmon->sel->switchtag)
  3479. selmon->sel->switchtag = 0;
  3480. #endif // SWITCHTAG_PATCH
  3481. focus(NULL);
  3482. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  3483. selmon->pertag->prevclient[selmon->pertag->curtag] = NULL;
  3484. for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++)
  3485. if (tagmask & 1)
  3486. selmon->pertag->prevclient[tagindex] = NULL;
  3487. #endif // SWAPFOCUS_PATCH
  3488. arrange(selmon);
  3489. #if VIEWONTAG_PATCH
  3490. if ((arg->ui & TAGMASK) != selmon->tagset[selmon->seltags])
  3491. view(arg);
  3492. #endif // VIEWONTAG_PATCH
  3493. }
  3494. }
  3495. void
  3496. tagmon(const Arg *arg)
  3497. {
  3498. #if TAGMONFIXFS_PATCH
  3499. Client *c = selmon->sel;
  3500. if (!c || !mons->next)
  3501. return;
  3502. if (c->isfullscreen) {
  3503. c->isfullscreen = 0;
  3504. sendmon(c, dirtomon(arg->i));
  3505. c->isfullscreen = 1;
  3506. #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH
  3507. if (c->fakefullscreen != 1) {
  3508. resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
  3509. XRaiseWindow(dpy, c->win);
  3510. }
  3511. #elif !FAKEFULLSCREEN_PATCH
  3512. resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
  3513. XRaiseWindow(dpy, c->win);
  3514. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  3515. } else
  3516. sendmon(c, dirtomon(arg->i));
  3517. #else
  3518. if (!selmon->sel || !mons->next)
  3519. return;
  3520. sendmon(selmon->sel, dirtomon(arg->i));
  3521. #endif // TAGMONFIXFS_PATCH
  3522. }
  3523. void
  3524. togglebar(const Arg *arg)
  3525. {
  3526. Bar *bar;
  3527. #if BAR_HOLDBAR_PATCH && PERTAG_PATCH && PERTAGBAR_PATCH
  3528. selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = (selmon->showbar == 2 ? 1 : !selmon->showbar);
  3529. #elif BAR_HOLDBAR_PATCH
  3530. selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar);
  3531. #elif PERTAG_PATCH && PERTAGBAR_PATCH
  3532. selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
  3533. #else
  3534. selmon->showbar = !selmon->showbar;
  3535. #endif // BAR_HOLDBAR_PATCH | PERTAG_PATCH
  3536. updatebarpos(selmon);
  3537. for (bar = selmon->bar; bar; bar = bar->next)
  3538. XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
  3539. arrange(selmon);
  3540. }
  3541. void
  3542. togglefloating(const Arg *arg)
  3543. {
  3544. Client *c = selmon->sel;
  3545. if (arg && arg->v)
  3546. c = (Client*)arg->v;
  3547. if (!c)
  3548. return;
  3549. #if !FAKEFULLSCREEN_PATCH
  3550. #if FAKEFULLSCREEN_CLIENT_PATCH
  3551. if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
  3552. return;
  3553. #else
  3554. if (c->isfullscreen) /* no support for fullscreen windows */
  3555. return;
  3556. #endif // FAKEFULLSCREEN_CLIENT_PATCH
  3557. #endif // !FAKEFULLSCREEN_PATCH
  3558. c->isfloating = !c->isfloating || c->isfixed;
  3559. #if !BAR_FLEXWINTITLE_PATCH
  3560. if (c->isfloating)
  3561. XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel);
  3562. else
  3563. XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
  3564. #endif // BAR_FLEXWINTITLE_PATCH
  3565. if (c->isfloating) {
  3566. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  3567. if (c->sfx != -9999) {
  3568. /* restore last known float dimensions */
  3569. resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0);
  3570. } else
  3571. #endif // SAVEFLOATS_PATCH // EXRESIZE_PATCH
  3572. resize(c, c->x, c->y, c->w, c->h, 0);
  3573. #if SAVEFLOATS_PATCH || EXRESIZE_PATCH
  3574. } else {
  3575. /* save last known float dimensions */
  3576. c->sfx = c->x;
  3577. c->sfy = c->y;
  3578. c->sfw = c->w;
  3579. c->sfh = c->h;
  3580. #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH
  3581. }
  3582. arrange(c->mon);
  3583. #if BAR_EWMHTAGS_PATCH
  3584. setfloatinghint(c);
  3585. #endif // BAR_EWMHTAGS_PATCH
  3586. }
  3587. void
  3588. toggletag(const Arg *arg)
  3589. {
  3590. unsigned int newtags;
  3591. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  3592. unsigned int tagmask, tagindex;
  3593. #endif // SWAPFOCUS_PATCH
  3594. if (!selmon->sel)
  3595. return;
  3596. newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
  3597. if (newtags) {
  3598. selmon->sel->tags = newtags;
  3599. focus(NULL);
  3600. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  3601. for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++)
  3602. if (tagmask & 1)
  3603. selmon->pertag->prevclient[tagindex] = NULL;
  3604. #endif // SWAPFOCUS_PATCH
  3605. arrange(selmon);
  3606. }
  3607. #if BAR_EWMHTAGS_PATCH
  3608. updatecurrentdesktop();
  3609. #endif // BAR_EWMHTAGS_PATCH
  3610. }
  3611. void
  3612. toggleview(const Arg *arg)
  3613. {
  3614. unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
  3615. #if PERTAG_PATCH
  3616. int i;
  3617. #endif // PERTAG_PATCH
  3618. #if TAGINTOSTACK_ALLMASTER_PATCH
  3619. Client *const selected = selmon->sel;
  3620. // clients in the master area should be the same after we add a new tag
  3621. Client **const masters = calloc(selmon->nmaster, sizeof(Client *));
  3622. if (!masters) {
  3623. die("fatal: could not calloc() %u bytes \n", selmon->nmaster * sizeof(Client *));
  3624. }
  3625. // collect (from last to first) references to all clients in the master area
  3626. Client *c;
  3627. size_t j;
  3628. for (c = nexttiled(selmon->clients), j = 0; c && j < selmon->nmaster; c = nexttiled(c->next), ++j)
  3629. masters[selmon->nmaster - (j + 1)] = c;
  3630. // put the master clients at the front of the list
  3631. // > go from the 'last' master to the 'first'
  3632. for (j = 0; j < selmon->nmaster; ++j)
  3633. if (masters[j])
  3634. pop(masters[j]);
  3635. free(masters);
  3636. // we also want to be sure not to mutate the focus
  3637. focus(selected);
  3638. #elif TAGINTOSTACK_ONEMASTER_PATCH
  3639. // the first visible client should be the same after we add a new tag
  3640. // we also want to be sure not to mutate the focus
  3641. Client *const c = nexttiled(selmon->clients);
  3642. if (c) {
  3643. Client * const selected = selmon->sel;
  3644. pop(c);
  3645. focus(selected);
  3646. }
  3647. #endif // TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH
  3648. #if !EMPTYVIEW_PATCH
  3649. if (newtagset) {
  3650. #endif // EMPTYVIEW_PATCH
  3651. selmon->tagset[selmon->seltags] = newtagset;
  3652. #if PERTAG_PATCH
  3653. #if SCRATCHPADS_PATCH
  3654. if (newtagset == ~SPTAGMASK)
  3655. #else
  3656. if (newtagset == ~0)
  3657. #endif // SCRATCHPADS_PATCH
  3658. {
  3659. selmon->pertag->prevtag = selmon->pertag->curtag;
  3660. selmon->pertag->curtag = 0;
  3661. }
  3662. /* test if the user did not select the same tag */
  3663. if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
  3664. selmon->pertag->prevtag = selmon->pertag->curtag;
  3665. for (i = 0; !(newtagset & 1 << i); i++) ;
  3666. selmon->pertag->curtag = i + 1;
  3667. }
  3668. /* apply settings for this view */
  3669. selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
  3670. selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
  3671. selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  3672. selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  3673. selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
  3674. #if PERTAGBAR_PATCH
  3675. if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
  3676. togglebar(NULL);
  3677. #endif // PERTAGBAR_PATCH
  3678. #endif // PERTAG_PATCH
  3679. focus(NULL);
  3680. arrange(selmon);
  3681. #if !EMPTYVIEW_PATCH
  3682. }
  3683. #endif // EMPTYVIEW_PATCH
  3684. #if BAR_EWMHTAGS_PATCH
  3685. updatecurrentdesktop();
  3686. #endif // BAR_EWMHTAGS_PATCH
  3687. }
  3688. void
  3689. unfocus(Client *c, int setfocus, Client *nextfocus)
  3690. {
  3691. if (!c)
  3692. return;
  3693. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  3694. selmon->pertag->prevclient[selmon->pertag->curtag] = c;
  3695. #endif // SWAPFOCUS_PATCH
  3696. #if LOSEFULLSCREEN_PATCH
  3697. if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon && nextfocus && !nextfocus->isfloating)
  3698. #if FAKEFULLSCREEN_CLIENT_PATCH
  3699. if (c->fakefullscreen != 1)
  3700. setfullscreen(c, 0);
  3701. #else
  3702. setfullscreen(c, 0);
  3703. #endif // #if FAKEFULLSCREEN_CLIENT_PATCH
  3704. #endif // LOSEFULLSCREEN_PATCH
  3705. grabbuttons(c, 0);
  3706. #if !BAR_FLEXWINTITLE_PATCH
  3707. if (c->isfloating)
  3708. XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel);
  3709. else
  3710. XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
  3711. #endif // BAR_FLEXWINTITLE_PATCH
  3712. if (setfocus) {
  3713. XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
  3714. XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
  3715. }
  3716. }
  3717. void
  3718. unmanage(Client *c, int destroyed)
  3719. {
  3720. Monitor *m = c->mon;
  3721. #if SWITCHTAG_PATCH
  3722. unsigned int switchtag = c->switchtag;
  3723. #endif // SWITCHTAG_PATCH
  3724. XWindowChanges wc;
  3725. #if SWALLOW_PATCH
  3726. if (c->swallowing) {
  3727. unswallow(c);
  3728. return;
  3729. }
  3730. Client *s = swallowingclient(c->win);
  3731. if (s) {
  3732. free(s->swallowing);
  3733. s->swallowing = NULL;
  3734. arrange(m);
  3735. focus(NULL);
  3736. return;
  3737. }
  3738. #endif // SWALLOW_PATCH
  3739. detach(c);
  3740. detachstack(c);
  3741. if (!destroyed) {
  3742. wc.border_width = c->oldbw;
  3743. XGrabServer(dpy); /* avoid race conditions */
  3744. XSetErrorHandler(xerrordummy);
  3745. XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
  3746. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  3747. setclientstate(c, WithdrawnState);
  3748. XSync(dpy, False);
  3749. XSetErrorHandler(xerror);
  3750. XUngrabServer(dpy);
  3751. }
  3752. free(c);
  3753. #if SWALLOW_PATCH
  3754. if (s)
  3755. return;
  3756. #endif // SWALLOW_PATCH
  3757. focus(NULL);
  3758. updateclientlist();
  3759. arrange(m);
  3760. #if SWITCHTAG_PATCH
  3761. if (switchtag && ((switchtag & TAGMASK) != selmon->tagset[selmon->seltags]))
  3762. view(&((Arg) { .ui = switchtag }));
  3763. #endif // SWITCHTAG_PATCH
  3764. }
  3765. void
  3766. unmapnotify(XEvent *e)
  3767. {
  3768. Client *c;
  3769. #if BAR_ANYBAR_PATCH
  3770. Monitor *m;
  3771. Bar *bar;
  3772. #endif // BAR_ANYBAR_PATCH
  3773. XUnmapEvent *ev = &e->xunmap;
  3774. if ((c = wintoclient(ev->window))) {
  3775. if (ev->send_event)
  3776. setclientstate(c, WithdrawnState);
  3777. else
  3778. unmanage(c, 0);
  3779. #if BAR_SYSTRAY_PATCH
  3780. } else if (showsystray && (c = wintosystrayicon(ev->window))) {
  3781. /* KLUDGE! sometimes icons occasionally unmap their windows, but do
  3782. * _not_ destroy them. We map those windows back */
  3783. XMapRaised(dpy, c->win);
  3784. removesystrayicon(c);
  3785. drawbarwin(systray->bar);
  3786. #endif // BAR_SYSTRAY_PATCH
  3787. }
  3788. #if BAR_ANYBAR_PATCH
  3789. else {
  3790. m = wintomon(ev->window);
  3791. for (bar = m->bar; bar; bar = bar->next) {
  3792. if (bar->win == ev->window) {
  3793. unmanagealtbar(ev->window);
  3794. break;
  3795. }
  3796. }
  3797. }
  3798. #endif // BAR_ANYBAR_PATCH
  3799. }
  3800. void
  3801. updatebars(void)
  3802. {
  3803. Bar *bar;
  3804. Monitor *m;
  3805. XSetWindowAttributes wa = {
  3806. .override_redirect = True,
  3807. #if BAR_ALPHA_PATCH
  3808. .background_pixel = 0,
  3809. .border_pixel = 0,
  3810. .colormap = cmap,
  3811. #else
  3812. .background_pixmap = ParentRelative,
  3813. #endif // BAR_ALPHA_PATCH
  3814. .event_mask = ButtonPressMask|ExposureMask
  3815. };
  3816. XClassHint ch = {"dwm", "dwm"};
  3817. for (m = mons; m; m = m->next) {
  3818. for (bar = m->bar; bar; bar = bar->next) {
  3819. if (bar->external)
  3820. continue;
  3821. if (!bar->win) {
  3822. #if BAR_ALPHA_PATCH
  3823. bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth,
  3824. InputOutput, visual,
  3825. CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
  3826. #else
  3827. bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen),
  3828. CopyFromParent, DefaultVisual(dpy, screen),
  3829. CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  3830. #endif // BAR_ALPHA_PATCH
  3831. XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor);
  3832. XMapRaised(dpy, bar->win);
  3833. XSetClassHint(dpy, bar->win, &ch);
  3834. }
  3835. }
  3836. }
  3837. }
  3838. void
  3839. updatebarpos(Monitor *m)
  3840. {
  3841. m->wx = m->mx;
  3842. m->wy = m->my;
  3843. m->ww = m->mw;
  3844. m->wh = m->mh;
  3845. Bar *bar;
  3846. #if BAR_PADDING_PATCH
  3847. int y_pad = vertpad;
  3848. int x_pad = sidepad;
  3849. #else
  3850. int y_pad = 0;
  3851. int x_pad = 0;
  3852. #endif // BAR_PADDING_PATCH
  3853. #if INSETS_PATCH
  3854. // Custom insets
  3855. Inset inset = m->inset;
  3856. m->wx += inset.x;
  3857. m->wy += inset.y;
  3858. m->ww -= inset.w + inset.x;
  3859. m->wh -= inset.h + inset.y;
  3860. #endif // INSETS_PATCH
  3861. for (bar = m->bar; bar; bar = bar->next) {
  3862. bar->bx = m->wx + x_pad;
  3863. bar->bw = m->ww - 2 * x_pad;
  3864. }
  3865. for (bar = m->bar; bar; bar = bar->next)
  3866. if (!m->showbar || !bar->showbar)
  3867. bar->by = -bar->bh - y_pad;
  3868. if (!m->showbar)
  3869. return;
  3870. for (bar = m->bar; bar; bar = bar->next) {
  3871. if (!bar->showbar)
  3872. continue;
  3873. if (bar->topbar)
  3874. m->wy = m->wy + bar->bh + y_pad;
  3875. m->wh -= y_pad + bar->bh;
  3876. }
  3877. for (bar = m->bar; bar; bar = bar->next)
  3878. bar->by = (bar->topbar ? m->wy - bar->bh : m->wy + m->wh);
  3879. }
  3880. void
  3881. updateclientlist()
  3882. {
  3883. Client *c;
  3884. Monitor *m;
  3885. XDeleteProperty(dpy, root, netatom[NetClientList]);
  3886. for (m = mons; m; m = m->next)
  3887. for (c = m->clients; c; c = c->next)
  3888. XChangeProperty(dpy, root, netatom[NetClientList],
  3889. XA_WINDOW, 32, PropModeAppend,
  3890. (unsigned char *) &(c->win), 1);
  3891. #if NET_CLIENT_LIST_STACKING_PATCH
  3892. XDeleteProperty(dpy, root, netatom[NetClientListStacking]);
  3893. for (m = mons; m; m = m->next)
  3894. for (c = m->stack; c; c = c->snext)
  3895. XChangeProperty(dpy, root, netatom[NetClientListStacking],
  3896. XA_WINDOW, 32, PropModeAppend,
  3897. (unsigned char *) &(c->win), 1);
  3898. #endif // NET_CLIENT_LIST_STACKING_PATCH
  3899. }
  3900. int
  3901. updategeom(void)
  3902. {
  3903. int dirty = 0;
  3904. #ifdef XINERAMA
  3905. if (XineramaIsActive(dpy)) {
  3906. int i, j, n, nn;
  3907. Client *c;
  3908. Monitor *m;
  3909. XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
  3910. XineramaScreenInfo *unique = NULL;
  3911. for (n = 0, m = mons; m; m = m->next, n++);
  3912. /* only consider unique geometries as separate screens */
  3913. unique = ecalloc(nn, sizeof(XineramaScreenInfo));
  3914. for (i = 0, j = 0; i < nn; i++)
  3915. if (isuniquegeom(unique, j, &info[i]))
  3916. memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
  3917. XFree(info);
  3918. nn = j;
  3919. #if SORTSCREENS_PATCH
  3920. sortscreens(unique, nn);
  3921. #endif // SORTSCREENS_PATCH
  3922. if (n <= nn) { /* new monitors available */
  3923. for (i = 0; i < (nn - n); i++) {
  3924. for (m = mons; m && m->next; m = m->next);
  3925. if (m)
  3926. m->next = createmon();
  3927. else
  3928. mons = createmon();
  3929. }
  3930. for (i = 0, m = mons; i < nn && m; m = m->next, i++) {
  3931. if (i >= n
  3932. || unique[i].x_org != m->mx || unique[i].y_org != m->my
  3933. || unique[i].width != m->mw || unique[i].height != m->mh)
  3934. {
  3935. dirty = 1;
  3936. m->num = i;
  3937. m->mx = m->wx = unique[i].x_org;
  3938. m->my = m->wy = unique[i].y_org;
  3939. m->mw = m->ww = unique[i].width;
  3940. m->mh = m->wh = unique[i].height;
  3941. updatebarpos(m);
  3942. }
  3943. }
  3944. } else { /* less monitors available nn < n */
  3945. for (i = nn; i < n; i++) {
  3946. for (m = mons; m && m->next; m = m->next);
  3947. while ((c = m->clients)) {
  3948. dirty = 1;
  3949. m->clients = c->next;
  3950. detachstack(c);
  3951. c->mon = mons;
  3952. attach(c);
  3953. attachstack(c);
  3954. }
  3955. if (m == selmon)
  3956. selmon = mons;
  3957. cleanupmon(m);
  3958. }
  3959. }
  3960. for (i = 0, m = mons; m; m = m->next, i++)
  3961. m->index = i;
  3962. free(unique);
  3963. } else
  3964. #endif /* XINERAMA */
  3965. { /* default monitor setup */
  3966. if (!mons)
  3967. mons = createmon();
  3968. if (mons->mw != sw || mons->mh != sh) {
  3969. dirty = 1;
  3970. mons->mw = mons->ww = sw;
  3971. mons->mh = mons->wh = sh;
  3972. updatebarpos(mons);
  3973. }
  3974. }
  3975. if (dirty) {
  3976. selmon = mons;
  3977. selmon = wintomon(root);
  3978. }
  3979. return dirty;
  3980. }
  3981. void
  3982. updatenumlockmask(void)
  3983. {
  3984. unsigned int i, j;
  3985. XModifierKeymap *modmap;
  3986. numlockmask = 0;
  3987. modmap = XGetModifierMapping(dpy);
  3988. for (i = 0; i < 8; i++)
  3989. for (j = 0; j < modmap->max_keypermod; j++)
  3990. if (modmap->modifiermap[i * modmap->max_keypermod + j]
  3991. == XKeysymToKeycode(dpy, XK_Num_Lock))
  3992. numlockmask = (1 << i);
  3993. XFreeModifiermap(modmap);
  3994. }
  3995. void
  3996. updatesizehints(Client *c)
  3997. {
  3998. long msize;
  3999. XSizeHints size;
  4000. if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
  4001. /* size is uninitialized, ensure that size.flags aren't used */
  4002. #if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH
  4003. size.flags = 0;
  4004. #else
  4005. size.flags = PSize;
  4006. #endif // SIZEHINTS_PATCH | SIZEHINTS_RULED_PATCH
  4007. if (size.flags & PBaseSize) {
  4008. c->basew = size.base_width;
  4009. c->baseh = size.base_height;
  4010. } else if (size.flags & PMinSize) {
  4011. c->basew = size.min_width;
  4012. c->baseh = size.min_height;
  4013. } else
  4014. c->basew = c->baseh = 0;
  4015. if (size.flags & PResizeInc) {
  4016. c->incw = size.width_inc;
  4017. c->inch = size.height_inc;
  4018. } else
  4019. c->incw = c->inch = 0;
  4020. if (size.flags & PMaxSize) {
  4021. c->maxw = size.max_width;
  4022. c->maxh = size.max_height;
  4023. } else
  4024. c->maxw = c->maxh = 0;
  4025. if (size.flags & PMinSize) {
  4026. c->minw = size.min_width;
  4027. c->minh = size.min_height;
  4028. } else if (size.flags & PBaseSize) {
  4029. c->minw = size.base_width;
  4030. c->minh = size.base_height;
  4031. } else
  4032. c->minw = c->minh = 0;
  4033. if (size.flags & PAspect) {
  4034. c->mina = (float)size.min_aspect.y / size.min_aspect.x;
  4035. c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
  4036. } else
  4037. c->maxa = c->mina = 0.0;
  4038. #if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH
  4039. if (size.flags & PSize) {
  4040. c->basew = size.base_width;
  4041. c->baseh = size.base_height;
  4042. c->isfloating = 1;
  4043. }
  4044. #if SIZEHINTS_RULED_PATCH
  4045. checkfloatingrules(c);
  4046. #endif // SIZEHINTS_RULED_PATCH
  4047. #endif // SIZEHINTS_PATCH
  4048. c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
  4049. }
  4050. void
  4051. updatestatus(void)
  4052. {
  4053. Monitor *m;
  4054. #if BAR_EXTRASTATUS_PATCH
  4055. if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) {
  4056. strcpy(stext, "dwm-"VERSION);
  4057. estext[0] = '\0';
  4058. } else {
  4059. char *e = strchr(rawstext, statussep);
  4060. if (e) {
  4061. *e = '\0'; e++;
  4062. #if BAR_STATUSCMD_PATCH
  4063. strncpy(rawestext, e, sizeof(estext) - 1);
  4064. copyvalidchars(estext, rawestext);
  4065. #else
  4066. strncpy(estext, e, sizeof(estext) - 1);
  4067. #endif // BAR_STATUSCMD_PATCH
  4068. } else {
  4069. estext[0] = '\0';
  4070. }
  4071. #if BAR_STATUSCMD_PATCH
  4072. copyvalidchars(stext, rawstext);
  4073. #else
  4074. strncpy(stext, rawstext, sizeof(stext) - 1);
  4075. #endif // BAR_STATUSCMD_PATCH
  4076. }
  4077. #elif BAR_STATUSCMD_PATCH
  4078. if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext)))
  4079. strcpy(stext, "dwm-"VERSION);
  4080. else
  4081. copyvalidchars(stext, rawstext);
  4082. #else
  4083. if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
  4084. strcpy(stext, "dwm-"VERSION);
  4085. #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH
  4086. for (m = mons; m; m = m->next)
  4087. drawbar(m);
  4088. }
  4089. void
  4090. updatetitle(Client *c)
  4091. {
  4092. #if IPC_PATCH
  4093. char oldname[sizeof(c->name)];
  4094. strcpy(oldname, c->name);
  4095. #endif // IPC_PATCH
  4096. if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
  4097. gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
  4098. if (c->name[0] == '\0') /* hack to mark broken clients */
  4099. strcpy(c->name, broken);
  4100. #if IPC_PATCH
  4101. for (Monitor *m = mons; m; m = m->next) {
  4102. if (m->sel == c && strcmp(oldname, c->name) != 0)
  4103. ipc_focused_title_change_event(m->num, c->win, oldname, c->name);
  4104. }
  4105. #endif // IPC_PATCH
  4106. }
  4107. void
  4108. updatewmhints(Client *c)
  4109. {
  4110. XWMHints *wmh;
  4111. if ((wmh = XGetWMHints(dpy, c->win))) {
  4112. if (c == selmon->sel && wmh->flags & XUrgencyHint) {
  4113. wmh->flags &= ~XUrgencyHint;
  4114. XSetWMHints(dpy, c->win, wmh);
  4115. } else
  4116. c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0;
  4117. if (c->isurgent) {
  4118. if (c->isfloating)
  4119. XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColFloat].pixel);
  4120. else
  4121. XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel);
  4122. }
  4123. if (wmh->flags & InputHint)
  4124. c->neverfocus = !wmh->input;
  4125. else
  4126. c->neverfocus = 0;
  4127. XFree(wmh);
  4128. }
  4129. }
  4130. void
  4131. view(const Arg *arg)
  4132. {
  4133. #if EMPTYVIEW_PATCH
  4134. if (arg->ui && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  4135. #else
  4136. if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  4137. #endif // EMPTYVIEW_PATCH
  4138. {
  4139. #if VIEW_SAME_TAG_GIVES_PREVIOUS_TAG_PATCH
  4140. view(&((Arg) { .ui = 0 }));
  4141. #endif // VIEW_SAME_TAG_GIVES_PREVIOUS_TAG_PATCH
  4142. return;
  4143. }
  4144. selmon->seltags ^= 1; /* toggle sel tagset */
  4145. #if PERTAG_PATCH
  4146. pertagview(arg);
  4147. #if SWAPFOCUS_PATCH
  4148. Client *unmodified = selmon->pertag->prevclient[selmon->pertag->curtag];
  4149. #endif // SWAPFOCUS_PATCH
  4150. #else
  4151. if (arg->ui & TAGMASK)
  4152. selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
  4153. #endif // PERTAG_PATCH
  4154. focus(NULL);
  4155. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  4156. selmon->pertag->prevclient[selmon->pertag->curtag] = unmodified;
  4157. #endif // SWAPFOCUS_PATCH
  4158. arrange(selmon);
  4159. #if BAR_EWMHTAGS_PATCH
  4160. updatecurrentdesktop();
  4161. #endif // BAR_EWMHTAGS_PATCH
  4162. }
  4163. Client *
  4164. wintoclient(Window w)
  4165. {
  4166. Client *c;
  4167. Monitor *m;
  4168. for (m = mons; m; m = m->next)
  4169. for (c = m->clients; c; c = c->next)
  4170. if (c->win == w)
  4171. return c;
  4172. return NULL;
  4173. }
  4174. Monitor *
  4175. wintomon(Window w)
  4176. {
  4177. int x, y;
  4178. Client *c;
  4179. Monitor *m;
  4180. Bar *bar;
  4181. if (w == root && getrootptr(&x, &y))
  4182. return recttomon(x, y, 1, 1);
  4183. for (m = mons; m; m = m->next)
  4184. for (bar = m->bar; bar; bar = bar->next)
  4185. if (w == bar->win)
  4186. return m;
  4187. if ((c = wintoclient(w)))
  4188. return c->mon;
  4189. return selmon;
  4190. }
  4191. /* There's no way to check accesses to destroyed windows, thus those cases are
  4192. * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
  4193. * default error handler, which may call exit. */
  4194. int
  4195. xerror(Display *dpy, XErrorEvent *ee)
  4196. {
  4197. if (ee->error_code == BadWindow
  4198. || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
  4199. || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
  4200. || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
  4201. || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
  4202. || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
  4203. || (ee->request_code == X_GrabButton && ee->error_code == BadAccess)
  4204. || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
  4205. || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
  4206. return 0;
  4207. fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
  4208. ee->request_code, ee->error_code);
  4209. return xerrorxlib(dpy, ee); /* may call exit */
  4210. }
  4211. int
  4212. xerrordummy(Display *dpy, XErrorEvent *ee)
  4213. {
  4214. return 0;
  4215. }
  4216. /* Startup Error handler to check if another window manager
  4217. * is already running. */
  4218. int
  4219. xerrorstart(Display *dpy, XErrorEvent *ee)
  4220. {
  4221. die("dwm: another window manager is already running");
  4222. return -1;
  4223. }
  4224. void
  4225. zoom(const Arg *arg)
  4226. {
  4227. Client *c = selmon->sel;
  4228. if (arg && arg->v)
  4229. c = (Client*)arg->v;
  4230. if (!c)
  4231. return;
  4232. #if ZOOMSWAP_PATCH
  4233. Client *at = NULL, *cold, *cprevious = NULL, *p;
  4234. #endif // ZOOMSWAP_PATCH
  4235. #if ZOOMFLOATING_PATCH
  4236. if (c && c->isfloating)
  4237. togglefloating(&((Arg) { .v = c }));
  4238. #endif // ZOOMFLOATING_PATCH
  4239. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  4240. c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->mon->clients);
  4241. #endif // SWAPFOCUS_PATCH
  4242. if (!c->mon->lt[c->mon->sellt]->arrange
  4243. || (c && c->isfloating)
  4244. #if ZOOMSWAP_PATCH
  4245. || !c
  4246. #endif // ZOOMSWAP_PATCH
  4247. )
  4248. return;
  4249. #if ZOOMSWAP_PATCH
  4250. if (c == nexttiled(c->mon->clients)) {
  4251. #if PERTAG_PATCH
  4252. p = c->mon->pertag->prevzooms[c->mon->pertag->curtag];
  4253. #else
  4254. p = prevzoom;
  4255. #endif // PERTAG_PATCH
  4256. at = findbefore(p);
  4257. if (at)
  4258. cprevious = nexttiled(at->next);
  4259. if (!cprevious || cprevious != p) {
  4260. #if PERTAG_PATCH
  4261. c->mon->pertag->prevzooms[c->mon->pertag->curtag] = NULL;
  4262. #else
  4263. prevzoom = NULL;
  4264. #endif // PERTAG_PATCH
  4265. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  4266. if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next)))
  4267. #else
  4268. if (!c || !(c = nexttiled(c->next)))
  4269. #endif // SWAPFOCUS_PATCH
  4270. return;
  4271. } else
  4272. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  4273. c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = cprevious;
  4274. #else
  4275. c = cprevious;
  4276. #endif // SWAPFOCUS_PATCH
  4277. }
  4278. cold = nexttiled(c->mon->clients);
  4279. if (c != cold && !at)
  4280. at = findbefore(c);
  4281. detach(c);
  4282. attach(c);
  4283. /* swap windows instead of pushing the previous one down */
  4284. if (c != cold && at) {
  4285. #if PERTAG_PATCH
  4286. c->mon->pertag->prevzooms[c->mon->pertag->curtag] = cold;
  4287. #else
  4288. prevzoom = cold;
  4289. #endif // PERTAG_PATCH
  4290. if (cold && at != cold) {
  4291. detach(cold);
  4292. cold->next = at->next;
  4293. at->next = cold;
  4294. }
  4295. }
  4296. focus(c);
  4297. arrange(c->mon);
  4298. #else
  4299. if (c == nexttiled(c->mon->clients))
  4300. #if SWAPFOCUS_PATCH && PERTAG_PATCH
  4301. if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next)))
  4302. #else
  4303. if (!c || !(c = nexttiled(c->next)))
  4304. #endif // SWAPFOCUS_PATCH
  4305. return;
  4306. pop(c);
  4307. #endif // ZOOMSWAP_PATCH
  4308. }
  4309. int
  4310. main(int argc, char *argv[])
  4311. {
  4312. #if CMDCUSTOMIZE_PATCH
  4313. for (int i=1;i<argc;i+=1)
  4314. if (!strcmp("-v", argv[i]))
  4315. die("dwm-"VERSION);
  4316. else if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]))
  4317. die(help());
  4318. else if (!strcmp("-fn", argv[i])) /* font set */
  4319. #if BAR_PANGO_PATCH
  4320. strcpy(font, argv[++i]);
  4321. #else
  4322. fonts[0] = argv[++i];
  4323. #endif // BAR_PANGO_PATCH
  4324. #if !BAR_VTCOLORS_PATCH
  4325. else if (!strcmp("-nb", argv[i])) /* normal background color */
  4326. colors[SchemeNorm][1] = argv[++i];
  4327. else if (!strcmp("-nf", argv[i])) /* normal foreground color */
  4328. colors[SchemeNorm][0] = argv[++i];
  4329. else if (!strcmp("-sb", argv[i])) /* selected background color */
  4330. colors[SchemeSel][1] = argv[++i];
  4331. else if (!strcmp("-sf", argv[i])) /* selected foreground color */
  4332. colors[SchemeSel][0] = argv[++i];
  4333. #endif // !BAR_VTCOLORS_PATCH
  4334. #if NODMENU_PATCH
  4335. else if (!strcmp("-df", argv[i])) /* dmenu font */
  4336. dmenucmd[2] = argv[++i];
  4337. else if (!strcmp("-dnb", argv[i])) /* dmenu normal background color */
  4338. dmenucmd[4] = argv[++i];
  4339. else if (!strcmp("-dnf", argv[i])) /* dmenu normal foreground color */
  4340. dmenucmd[6] = argv[++i];
  4341. else if (!strcmp("-dsb", argv[i])) /* dmenu selected background color */
  4342. dmenucmd[8] = argv[++i];
  4343. else if (!strcmp("-dsf", argv[i])) /* dmenu selected foreground color */
  4344. dmenucmd[10] = argv[++i];
  4345. #else
  4346. else if (!strcmp("-df", argv[i])) /* dmenu font */
  4347. dmenucmd[4] = argv[++i];
  4348. else if (!strcmp("-dnb", argv[i])) /* dmenu normal background color */
  4349. dmenucmd[6] = argv[++i];
  4350. else if (!strcmp("-dnf", argv[i])) /* dmenu normal foreground color */
  4351. dmenucmd[8] = argv[++i];
  4352. else if (!strcmp("-dsb", argv[i])) /* dmenu selected background color */
  4353. dmenucmd[10] = argv[++i];
  4354. else if (!strcmp("-dsf", argv[i])) /* dmenu selected foreground color */
  4355. dmenucmd[12] = argv[++i];
  4356. #endif // NODMENU_PATCH
  4357. else die(help());
  4358. #else
  4359. if (argc == 2 && !strcmp("-v", argv[1]))
  4360. die("dwm-"VERSION);
  4361. else if (argc != 1)
  4362. die("usage: dwm [-v]");
  4363. #endif // CMDCUSTOMIZE_PATCH
  4364. if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  4365. fputs("warning: no locale support\n", stderr);
  4366. if (!(dpy = XOpenDisplay(NULL)))
  4367. die("dwm: cannot open display");
  4368. #if SWALLOW_PATCH
  4369. if (!(xcon = XGetXCBConnection(dpy)))
  4370. die("dwm: cannot get xcb connection\n");
  4371. #endif // SWALLOW_PATCH
  4372. checkotherwm();
  4373. #if XRDB_PATCH && !BAR_VTCOLORS_PATCH
  4374. XrmInitialize();
  4375. loadxrdb();
  4376. #endif // XRDB_PATCH && !BAR_VTCOLORS_PATCH
  4377. #if COOL_AUTOSTART_PATCH
  4378. autostart_exec();
  4379. #endif // COOL_AUTOSTART_PATCH
  4380. setup();
  4381. #ifdef __OpenBSD__
  4382. #if SWALLOW_PATCH
  4383. if (pledge("stdio rpath proc exec ps", NULL) == -1)
  4384. #else
  4385. if (pledge("stdio rpath proc exec", NULL) == -1)
  4386. #endif // SWALLOW_PATCH
  4387. die("pledge");
  4388. #endif /* __OpenBSD__ */
  4389. scan();
  4390. #if AUTOSTART_PATCH
  4391. runautostart();
  4392. #endif
  4393. run();
  4394. #if RESTARTSIG_PATCH
  4395. if (restart)
  4396. execvp(argv[0], argv);
  4397. #endif // RESTARTSIG_PATCH
  4398. cleanup();
  4399. XCloseDisplay(dpy);
  4400. return EXIT_SUCCESS;
  4401. }