Similar to Linux kernel approach, encapsulate some of the uglier conditional compilation into inline functions in header files.
The goal is to make dwl.c more attractive to people who embrace the suckless philosophy - simple, short, hackable, and easy to understand. We want dwm users to feel comfortable here, not scare them off. Plus, if we do this right, the main dwl.c code should require only minimal changes once XWayland is no longer a necessary evil.
According to cloc
, this also brings dwl.c down below 2000 lines of
non-blank, non-comment code.
2GP4MXKEDQMZ7E6TCRSMV2AGN7HLEAHR3QEAC2QFCQQNPMNJSIHQC
EUCFJIEMWL6XMBVSIAE7WNV36YFRFZ3PQ466CES2FENTTYPGLGMQC
BUKVDTE4YSZ5L3O5M5DUMMU53BNDCDTYVE4ZCYKJDPCFT4BGGFHAC
7QTKZEHTZVV5GLTPUSLQZFCJE3S6KLEMC6ZT4Y2G3O7ITZ35SVNAC
BFWKVWAIUKHCZVRA62GW6QZUEUKQLW365HUWIVKTEIPJNJSOZBAQC
ZTOYJ4G4UQ665FKUH376KJOOO5GXHI62SWVXNZS7X6F2Y4GG2FSQC
TOFCZFUYVBVEBHMKVG6G5MKCAEF2QCQ4GKMKGQUSJRLGLDZEJF4QC
7B74AT3BXYB7PVW4F6SGQNPMHOU5TEV5TZ54CG6VSQI46XSEKWXQC
4QUF4MKRSB5LYYS5FSYTCDSIEMYIERI2BQZLRGJ3GIGVYCPJVEPAC
OPA33YRIB5AVFBKVANDGJF4IO7ZPPSIAJ75RULIM46SI2YX54ODAC
IZ2KIIKXVGAUR2NRYJMZCTIXUCPWCRQFDXDAE2SAW6NFKINXRPWQC
LQPHYO7IIMLXHUD5IK657BO4BE3SGT5HYDRJDU5OFDF5YUXKIRTAC
OKQDKOVUGULJA6E4XL4VMUHPT4IOFYBFBJAU7QXNNPP6PJ4DYLVAC
BOH54DATFCM5ZC6GDQKEU23PQSIOOINLX3UAI47STL7PP56PQUYAC
HWS332I73ETH3YIIOCQO7WB7VPQICME6GGXFJ7EUWDH5O3KA27QQC
HQ3S6SWVJ2NFQZFG63PQDO4VSMJPMMSNTRO4P23ZNMYEBYRAVGPQC
E7UO6NRGXFDMBU3BSJYRDNOA3Y7VHD7NWPHI5PHCPHQF6ZNOPZLQC
VVVXTAJCZ4GUXO6RM3GOOEFHIZOHXRX4II3RSE2NM5HGNVHPMOUQC
D425ND7AT3F7QJ3CCSESMVDOC3J5C5P32M5SJDBHECZJXLHNQ2FAC
65GPTMYLVOQPVAKNBCN5RHHZEL7USZYSJ4VJQO7LYBCS7BZM7BYAC
PMRSYJRYQAXZ3OEDD7ANMXTECMT2DNJEC3XQABRNA63SAOUZWA3AC
WIS5F3QY5CUHYUK723DE2JWDB6AWZEWSQED67M2HDY5B7UAE6NVQC
2SBFINJKOJLIY2COLC4PD2LRMOAAMVA7CJFU57GUL43XGS6QJF5QC
Q6TUD4XK4U35XVS2VZEGO4OCNXYM5IL4QUW7YDMYRMQQDRJBGSNAC
WU3FVGGMDAGZ6E3YFQTFYTFGUJ5FRWCUZBVOWUEOK73MXK5ABMGQC
6TCDMCXLC4RNNQI6AEYYA6RZNHG3V2U6YDGXJOCU27F5TNKN26LQC
VB73LHGDVI7ZDLCT35D7TICLZAAVEFSDIAJXBJTT5HYMMNMFHJKQC
JJXQTKU5WR74D7XW3JTN4Y3JSYDQTZ54GTD4F5XHT5RR2UWR72AAC
5IGKKZ3URJE5EL5ZVCOKDTIBHRL7DTLKUJXIVYVJ4LRMKYARRNZAC
I2UG6WQKU6GNMQXFZXVONILKQFYXI7AIGK44KCMDWCQETA3UZW2AC
2FBILAASURBC6XQLU7Q4NOOTAZMWFFSIB66S4YHWJ5JHYEUAMJWQC
VYZMMYEO3CEHLATYEHS7G6XBGEVOWDMAXHMHMINACSNF75TH72UAC
YL6TMLW5YFLMKYPWGTNJHD5GQ2LR2Y7KC4N5U3Y4NBFQXZQ6NRZAC
2OQAWQSW5DDGUFJ4YWT5VXHZMRWQPDKZFO3JUPO4SV6JQHWT6HRAC
MO5ORR7VSER3YUNO77DZJVKGOVYC2KNDCSC72J4NF7JYOHHTLRQAC
VQFHLTRH5SLA7WGMCOUV2CJLDOCXRABFLQLTQQ2XB7LLJGUQFZ4QC
2LVBWMSDB23KDDSOFYYELLTIFLL556IQSNKZTQLLCNTMEBZUVXHAC
7BF4DJIZ4X73ADYFJZZJHQJJUTNHKLEYER6LNVAAWD5VJXPIMSIQC
ZIXAFAJJEKSFECJJW57MQ2Z666IZSJXU5FVAQ2JLG34BEJIV322AC
7UDWES3V56FD5L7VJXSFC6POZ7SXN4Z2JNJQ3XBVN7KBZD6AXTDQC
R6OKMSUKACWM6MN6IOICU5P2YZ3RRME6NO4JLYMYB5VYDFRLYSTQC
LJJH53FPOX3RP5PCHNORRMTUSV4DXYYP2A47X6VDZ5KZI6T2DEOAC
D64WESJYNP7BT2GW7BX6332GAXIWK72KRIBEKTE34ATA4APJMGNQC
OYZELWD247C2GT4QAW6YECUCA2GRLG4VI25BMOZKOGNRKERPZ6AQC
WH2QXAEHJ3UWIAS5YCRYXCTROAX4SNC3UESM56HUMM3UGUUAAZQAC
P3BVYOM6YV7M33KYMI5XNLZ6F44BBAP3I6NXPNTTCUAAPVPJ3PVQC
LRGGX34PR2PQEBW6U465VYOGIYOPD365PB444JGR6R3H7E524CCQC
PLJJLNS7E2UXW2YARGBSV6IHZEBGL5EW354IMMHPDATY5DQD77DAC
RWCXH2L4WZ4U5DZRUGRN6POD7C4WXXLCCSLINRXNBCNYGA7VJD7QC
7L3TU7JVWPBPHN7WF4TJ263BZ6BC3AYRRW6PULFUP5JZUGWWNUSAC
FJIYVCRICFJ7T52B2SLJOGFFX6AEYZNOSM3FJZ2B2ETFFYX2QXNAC
ZCTQJ724XCOD6BTABJD4UWCUIB4JBMOVNLVK2BTK2J6CCNCDJWSAC
QD3NDIJ4CRDN6QGCHALU2UG5DPMAYGE4MSGJPLYVXKLZNCV2WGIAC
STNAKFBNSAXICF6AJNYSCQKE4YYQGIMZHR7RSLZJBEOSSUMKBCNAC
HW2YJWC6AUWHZBS7KHF3PAWN44XGWSJ5WU47MCHTDCH32L5JN7EQC
#ifdef XWAYLAND
#define WLR_SURFACE(C) ((C)->type != XDGShell ? (C)->surface.xwayland->surface : (C)->surface.xdg->surface)
#else
#define WLR_SURFACE(C) ((C)->surface.xdg->surface)
#endif
#ifdef XWAYLAND
if (c->type != XDGShell) {
updatewindowtype(c);
appid = c->surface.xwayland->class;
title = c->surface.xwayland->title;
} else
#endif
{
appid = c->surface.xdg->toplevel->app_id;
title = c->surface.xdg->toplevel->title;
}
if (!appid)
c->isfloating = client_is_float_type(c);
if (!(appid = client_get_appid(c)))
#ifdef XWAYLAND
if (c->type == X11Managed)
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
else
#endif
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen);
client_set_fullscreen(c, fullscreen);
if (old && (!c || WLR_SURFACE(c) != old)) {
if (wlr_surface_is_xdg_surface(old))
wlr_xdg_toplevel_set_activated(
wlr_xdg_surface_from_wlr_surface(old), 0);
#ifdef XWAYLAND
else if (wlr_surface_is_xwayland_surface(old))
wlr_xwayland_surface_activate(
wlr_xwayland_surface_from_wlr_surface(old), 0);
#endif
if (old && (!c || client_surface(c) != old)) {
#ifdef XWAYLAND
if (c->type != XDGShell)
wlr_xwayland_surface_activate(c->surface.xwayland, 1);
else
#endif
wlr_xdg_toplevel_set_activated(c->surface.xdg, 1);
client_activate_surface(client_surface(c), 1);
#ifdef XWAYLAND
if (sel->type != XDGShell)
wlr_xwayland_surface_close(sel->surface.xwayland);
else
#endif
wlr_xdg_toplevel_send_close(sel->surface.xdg);
client_send_close(sel);
#ifdef XWAYLAND
if (c->type != XDGShell) {
c->geom.x = c->surface.xwayland->x;
c->geom.y = c->surface.xwayland->y;
c->geom.width = c->surface.xwayland->width + 2 * c->bw;
c->geom.height = c->surface.xwayland->height + 2 * c->bw;
} else
#endif
{
wlr_xdg_surface_get_geometry(c->surface.xdg, &c->geom);
c->geom.width += 2 * c->bw;
c->geom.height += 2 * c->bw;
}
client_get_geometry(c, &c->geom);
c->geom.width += 2 * c->bw;
c->geom.height += 2 * c->bw;
#ifdef XWAYLAND
if (c->type != XDGShell)
surface = wlr_surface_surface_at(c->surface.xwayland->surface,
cursor->x - c->geom.x - c->bw,
cursor->y - c->geom.y - c->bw, &sx, &sy);
else
#endif
surface = wlr_xdg_surface_surface_at(c->surface.xdg,
cursor->x - c->geom.x - c->bw,
cursor->y - c->geom.y - c->bw, &sx, &sy);
surface = client_surface_at(c, cursor->x - c->geom.x - c->bw,
cursor->y - c->geom.y - c->bw, &sx, &sy);
#ifdef XWAYLAND
if (c->type != XDGShell)
wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata);
else
#endif
wlr_xdg_surface_for_each_surface(c->surface.xdg, render, &rdata);
client_for_each_surface(c, render, &rdata);
#ifdef XWAYLAND
if (c->type != XDGShell)
wlr_xwayland_surface_configure(c->surface.xwayland,
c->geom.x, c->geom.y,
c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
else
#endif
c->resize = wlr_xdg_toplevel_set_size(c->surface.xdg,
c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
c->geom.height - 2 * c->bw);
}
void
updatewindowtype(Client *c)
{
for (size_t i = 0; i < c->surface.xwayland->window_type_len; i++)
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility])
c->isfloating = 1;
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-error=unused-function -Wdeclaration-after-statement
CFLAGS ?= -g -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wdeclaration-after-statement
/*
* Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
* file is not meant to be pretty. We use a .h file with static inline
* functions instead of a separate .c module, or function pointers like sway, so
* that they will simply compile out if the chosen #defines leave them unused.
*/
/* Leave this function first; it's used in the others */
static inline int
client_is_x11(Client *c)
{
#ifdef XWAYLAND
return c->type == X11Managed || c->type == X11Unmanaged;
#else
return 0;
#endif
}
/* The others */
static inline void
client_activate_surface(struct wlr_surface *s, int activated)
{
#ifdef XWAYLAND
if (wlr_surface_is_xwayland_surface(s)) {
wlr_xwayland_surface_activate(
wlr_xwayland_surface_from_wlr_surface(s), activated);
return;
}
#endif
if (wlr_surface_is_xdg_surface(s))
wlr_xdg_toplevel_set_activated(
wlr_xdg_surface_from_wlr_surface(s), activated);
}
static inline void
client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data)
{
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_surface_for_each_surface(c->surface.xwayland->surface,
fn, data);
return;
}
#endif
wlr_xdg_surface_for_each_surface(c->surface.xdg, fn, data);
}
static inline const char *
client_get_appid(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->class;
#endif
return c->surface.xdg->toplevel->app_id;
}
static inline void
client_get_geometry(Client *c, struct wlr_box *geom)
{
#ifdef XWAYLAND
if (client_is_x11(c)) {
geom->x = c->surface.xwayland->x;
geom->y = c->surface.xwayland->y;
geom->width = c->surface.xwayland->width;
geom->height = c->surface.xwayland->height;
return;
}
#endif
wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
}
static inline const char *
client_get_title(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->title;
#endif
return c->surface.xdg->toplevel->title;
}
static inline int
client_is_float_type(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
for (size_t i = 0; i < c->surface.xwayland->window_type_len; i++)
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] ||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility])
return 1;
#endif
return 0;
}
static inline int
client_is_unmanaged(Client *c)
{
#ifdef XWAYLAND
return c->type == X11Unmanaged;
#endif
return 0;
}
static inline void
client_send_close(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_close(c->surface.xwayland);
return;
}
#endif
wlr_xdg_toplevel_send_close(c->surface.xdg);
}
static inline void
client_set_fullscreen(Client *c, int fullscreen)
{
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
return;
}
#endif
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg, fullscreen);
}
static inline uint32_t
client_set_size(Client *c, uint32_t width, uint32_t height)
{
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_configure(c->surface.xwayland,
c->geom.x, c->geom.y, width, height);
return 0;
}
#endif
return wlr_xdg_toplevel_set_size(c->surface.xdg, width, height);
}
static inline struct wlr_surface *
client_surface(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->surface;
#endif
return c->surface.xdg->surface;
}
static inline struct wlr_surface *
client_surface_at(Client *c, double cx, double cy, double *sx, double *sy)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return wlr_surface_surface_at(c->surface.xwayland->surface,
cx, cy, sx, sy);
#endif
return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy);
}