Compare commits
2 Commits
e33e206e31
...
d2b40dc8e3
Author | SHA1 | Date |
---|---|---|
Alex Kotov | d2b40dc8e3 | |
Alex Kotov | 3d277c10fa |
1
Makefile
1
Makefile
|
@ -42,6 +42,7 @@ DWM_SRC = \
|
|||
src/dwm/bar.c \
|
||||
src/dwm/handlers.c \
|
||||
src/dwm/layouts.c \
|
||||
src/dwm/wmcheckwin.c \
|
||||
src/dwm/xerror.c
|
||||
|
||||
TEST_SRC = \
|
||||
|
|
729
src/dwm.c
729
src/dwm.c
|
@ -150,39 +150,27 @@ static void arrange(Monitor *m);
|
|||
static void arrangemon(Monitor *m);
|
||||
static void attach(Client *c);
|
||||
static void attachstack(Client *c);
|
||||
static void configborder(const Arg *arg);
|
||||
static void configgap(const Arg *arg);
|
||||
static void configure(Client *c);
|
||||
static void detach(Client *c);
|
||||
static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
static void dorestart(const Arg *arg);
|
||||
static void focus(Client *c);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static Atom getatomprop(Client *c, Atom prop);
|
||||
static int getrootptr(int *x, int *y);
|
||||
static long getstate(Window w);
|
||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||
static void grabbuttons(Client *c, int focused);
|
||||
static void grabkeys();
|
||||
static void incnmaster(const Arg *arg);
|
||||
static int isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info);
|
||||
static void killclient(const Arg *arg);
|
||||
static void manage(Window w, XWindowAttributes *wa);
|
||||
static void managepolybar(Window w, XWindowAttributes *wa);
|
||||
static Monitor *monitor_create();
|
||||
static void monitor_destroy(Monitor *mon);
|
||||
static void movemouse(const Arg *arg);
|
||||
static void movestack(const Arg *arg);
|
||||
static Client *nexttiled(Client *c);
|
||||
static void pop(Client *);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
static void resetnmaster(const Arg *arg);
|
||||
static void resize(Client *c, struct WinGeom win_geom, int interact);
|
||||
static void resizeclient(Client *c, struct WinGeom win_geom);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void restack(Monitor *m);
|
||||
static void run();
|
||||
static void scan();
|
||||
|
@ -193,14 +181,8 @@ static void sendmon(Client *c, Monitor *m);
|
|||
static void setclientstate(Client *c, long state);
|
||||
static void setfocus(Client *c);
|
||||
static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void seturgent(Client *c, bool is_urgent);
|
||||
static void showhide(Client *c);
|
||||
static void spawn(const Arg *arg);
|
||||
static void spawn_callback();
|
||||
static void tagmon(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
static void unmanage(Client *c, int destroyed);
|
||||
static void updateclientlist();
|
||||
|
@ -212,13 +194,14 @@ static void updatewindowtype(Client *c);
|
|||
static void updatewmhints(Client *c);
|
||||
static Client *wintoclient(Window w);
|
||||
static Monitor *wintomon(Window w);
|
||||
static void wmcheckwin_create();
|
||||
static void wmcheckwin_destroy();
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
extern const Layout layouts[];
|
||||
|
||||
#include "dwm/bar.h"
|
||||
#include "dwm/handlers.h"
|
||||
#include "dwm/interaction.h"
|
||||
#include "dwm/layouts.h"
|
||||
#include "dwm/wmcheckwin.h"
|
||||
#include "dwm/xerror.h"
|
||||
|
||||
/*************
|
||||
|
@ -236,7 +219,6 @@ static Cur *cursor[CurLast];
|
|||
static Clr **scheme;
|
||||
static Drw *drw;
|
||||
static Monitor *mons, *selmon;
|
||||
static Window wmcheckwin;
|
||||
|
||||
static void (*handler[LASTEvent])(XEvent*) = {
|
||||
[ButtonPress] = on_button_press,
|
||||
|
@ -267,7 +249,7 @@ static const char *colors[][3] = {
|
|||
[SchemeSel] = { col_gray4, col_cyan, "#d9b01c" },
|
||||
};
|
||||
|
||||
static const Layout layouts[] = {
|
||||
const Layout layouts[] = {
|
||||
/* symbol function, arrange function */
|
||||
{ layouts_symbol_monocle, monocle }, /* first entry is default */
|
||||
{ layouts_symbol_floating, NULL }, /* no layout function means floating behavior */
|
||||
|
@ -276,66 +258,15 @@ static const Layout layouts[] = {
|
|||
{ layouts_symbol_centeredmaster, centeredmaster },
|
||||
};
|
||||
|
||||
#define MODKEY Mod4Mask
|
||||
|
||||
static Key keys[] = {
|
||||
// WM
|
||||
{ MODKEY|ControlMask|ShiftMask, XK_q, quit, {0} },
|
||||
{ MODKEY|ControlMask|ShiftMask, XK_r, dorestart, {0} },
|
||||
// Monitor
|
||||
{ MODKEY, XK_bracketleft, focusmon, {.i = -1 } },
|
||||
{ MODKEY, XK_bracketright, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_bracketleft, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_bracketright, tagmon, {.i = +1 } },
|
||||
// Layout
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[0]} }, // Monocle
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, // Floating
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[2]} }, // Tile
|
||||
{ MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[3]} }, // Horizontile
|
||||
{ MODKEY, XK_u, setlayout, {.v = &layouts[4]} }, // Centeredmaster
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_i, resetnmaster, {.i = 1 } },
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_d, resetnmaster, {.i = 0 } },
|
||||
// Stack
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
|
||||
{ MODKEY, XK_Return, zoom, {0} },
|
||||
// Window
|
||||
{ MODKEY|ShiftMask, XK_x, killclient, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
// Appearance
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
{ MODKEY|Mod1Mask, XK_b, configborder, {.i = -1 } },
|
||||
{ MODKEY|Mod1Mask|ShiftMask, XK_b, configborder, {.i = +1 } },
|
||||
{ MODKEY|Mod1Mask, XK_g, configgap, {.i = -1 } },
|
||||
{ MODKEY|Mod1Mask|ShiftMask, XK_g, configgap, {.i = +1 } },
|
||||
// Starting applications
|
||||
{ MODKEY, XK_z, spawn, {.v = "lock" } },
|
||||
{ MODKEY, XK_slash, spawn, {.v = "menu" } },
|
||||
{ MODKEY|ShiftMask, XK_slash, spawn, {.v = "term" } },
|
||||
{ MODKEY|ShiftMask, XK_f, spawn, {.v = "firefox" } },
|
||||
};
|
||||
|
||||
// click can be ClkClientWin, or ClkRootWin
|
||||
static Button buttons[] = {
|
||||
/* click event mask button function argument */
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
};
|
||||
|
||||
/************************************
|
||||
* Private function implementations *
|
||||
************************************/
|
||||
|
||||
#include "dwm/bar.c"
|
||||
#include "dwm/handlers.c"
|
||||
#include "dwm/interaction.c"
|
||||
#include "dwm/layouts.c"
|
||||
#include "dwm/wmcheckwin.c"
|
||||
#include "dwm/xerror.c"
|
||||
|
||||
/***********************************
|
||||
|
@ -648,24 +579,6 @@ void attachstack(Client *c)
|
|||
c->mon->stack = c;
|
||||
}
|
||||
|
||||
void configborder(const Arg *const arg)
|
||||
{
|
||||
if (arg == NULL) return;
|
||||
const int old_border_width = settings_get_border_width();
|
||||
const int new_border_width = old_border_width + (arg->i >= 0 ? +1 : -1);
|
||||
settings_set_border_width(new_border_width);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void configgap(const Arg *const arg)
|
||||
{
|
||||
if (arg == NULL) return;
|
||||
const int old_gap_size = settings_get_gap_size();
|
||||
const int new_gap_size = old_gap_size + (arg->i >= 0 ? +2 : -2);
|
||||
settings_set_gap_size(new_gap_size);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void configure(Client *c)
|
||||
{
|
||||
XConfigureEvent ce = {
|
||||
|
@ -728,11 +641,6 @@ Monitor *dirtomon(int dir)
|
|||
return m;
|
||||
}
|
||||
|
||||
void dorestart(__attribute__((unused)) const Arg *const arg)
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
void focus(Client *c)
|
||||
{
|
||||
if (!c || !ISVISIBLE(c))
|
||||
|
@ -769,67 +677,6 @@ void focus(Client *c)
|
|||
selmon->sel = c;
|
||||
}
|
||||
|
||||
void focusmon(const Arg *arg)
|
||||
{
|
||||
if (!mons->next) return;
|
||||
|
||||
Monitor *m;
|
||||
if ((m = dirtomon(arg->i)) == selmon) return;
|
||||
|
||||
unfocus(selmon->sel, 0);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
|
||||
void focusstack(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel) return;
|
||||
|
||||
Client *c = NULL;
|
||||
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
|
||||
if (!c) {
|
||||
for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
|
||||
}
|
||||
} else {
|
||||
Client *i = selmon->clients;
|
||||
|
||||
for (; i != selmon->sel; i = i->next) {
|
||||
if (ISVISIBLE(i)) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
for (; i; i = i->next) {
|
||||
if (ISVISIBLE(i)) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
focus(c);
|
||||
restack(selmon);
|
||||
|
||||
{
|
||||
unsigned int n = 0;
|
||||
for (Client *cc = nexttiled(selmon->clients); cc; cc = nexttiled(cc->next), ++n);
|
||||
|
||||
// TODO: Maybe it's an unnecessary optimization
|
||||
// and we don't need the condition.
|
||||
if (n > 1) {
|
||||
// We have to rearrange because borders and gaps may have
|
||||
// changed in monocle layout.
|
||||
arrange(selmon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Atom getatomprop(Client *c, Atom prop)
|
||||
{
|
||||
Atom atom = None;
|
||||
|
@ -1027,19 +874,6 @@ void grabkeys()
|
|||
}
|
||||
}
|
||||
|
||||
void incnmaster(const Arg *arg)
|
||||
{
|
||||
const int max_clients_in_master = settings_get_max_clients_in_master();
|
||||
const int new_clients_in_master = MAX(0, selmon->nmaster + arg->i);
|
||||
|
||||
selmon->nmaster =
|
||||
max_clients_in_master == 0
|
||||
? new_clients_in_master
|
||||
: MIN(new_clients_in_master, max_clients_in_master);
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_XINERAMA
|
||||
int isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
||||
{
|
||||
|
@ -1051,21 +885,6 @@ int isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info)
|
|||
}
|
||||
#endif /* ENABLE_XINERAMA */
|
||||
|
||||
void killclient(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
if (!sendevent(selmon->sel, xbase->atoms->wmatom[WMDelete])) {
|
||||
XGrabServer(xbase->x_display);
|
||||
XSetErrorHandler(xerrordummy);
|
||||
XSetCloseDownMode(xbase->x_display, DestroyAll);
|
||||
XKillClient(xbase->x_display, selmon->sel->x_window);
|
||||
XSync(xbase->x_display, False);
|
||||
XSetErrorHandler(xerror);
|
||||
XUngrabServer(xbase->x_display);
|
||||
}
|
||||
}
|
||||
|
||||
void manage(Window w, XWindowAttributes *wa)
|
||||
{
|
||||
Client *const c = ecalloc(1, sizeof(Client));
|
||||
|
@ -1261,219 +1080,6 @@ void monitor_destroy(Monitor *mon)
|
|||
free(mon);
|
||||
}
|
||||
|
||||
void movemouse(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
Client *const c = selmon->sel;
|
||||
if (c == NULL) return;
|
||||
|
||||
restack(selmon);
|
||||
|
||||
if (
|
||||
XGrabPointer(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
False,
|
||||
MOUSEMASK,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
None,
|
||||
cursor[CurMove]->cursor,
|
||||
CurrentTime
|
||||
) != GrabSuccess
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
if (!getrootptr(&x, &y)) return;
|
||||
|
||||
const unsigned int snap_distance = settings_get_snap_distance();
|
||||
const int ocx = c->state.geom.basic.position.x;
|
||||
const int ocy = c->state.geom.basic.position.y;
|
||||
|
||||
Time lasttime = 0;
|
||||
|
||||
XEvent ev;
|
||||
|
||||
do {
|
||||
XMaskEvent(
|
||||
xbase->x_display,
|
||||
MOUSEMASK | ExposureMask | SubstructureRedirectMask,
|
||||
&ev
|
||||
);
|
||||
|
||||
switch (ev.type) {
|
||||
case ConfigureRequest:
|
||||
case Expose:
|
||||
case MapRequest:
|
||||
handler[ev.type](&ev);
|
||||
break;
|
||||
case MotionNotify:
|
||||
if ((ev.xmotion.time - lasttime) <= (1000 / 60)) continue;
|
||||
|
||||
lasttime = ev.xmotion.time;
|
||||
|
||||
int nx = ocx + (ev.xmotion.x - x);
|
||||
int ny = ocy + (ev.xmotion.y - y);
|
||||
|
||||
if (
|
||||
abs(selmon->window_area_geom.position.x - nx)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
nx = selmon->window_area_geom.position.x;
|
||||
} else if (
|
||||
abs(
|
||||
(
|
||||
selmon->window_area_geom.position.x
|
||||
+
|
||||
selmon->window_area_geom.sizes.w
|
||||
)
|
||||
-
|
||||
(nx + win_geom_total_width(&c->state.geom))
|
||||
)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
nx =
|
||||
selmon->window_area_geom.position.x
|
||||
+
|
||||
selmon->window_area_geom.sizes.w
|
||||
-
|
||||
win_geom_total_width(&c->state.geom);
|
||||
}
|
||||
|
||||
if (
|
||||
abs(selmon->window_area_geom.position.y - ny)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
ny = selmon->window_area_geom.position.y;
|
||||
} else if (
|
||||
abs(
|
||||
(
|
||||
selmon->window_area_geom.position.y
|
||||
+
|
||||
selmon->window_area_geom.sizes.h
|
||||
) - (ny + win_geom_total_height(&c->state.geom))
|
||||
)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
ny =
|
||||
selmon->window_area_geom.position.y
|
||||
+
|
||||
selmon->window_area_geom.sizes.h
|
||||
-
|
||||
win_geom_total_height(&c->state.geom);
|
||||
}
|
||||
|
||||
if (
|
||||
!c->state.is_floating
|
||||
&&
|
||||
(
|
||||
abs(nx - c->state.geom.basic.position.x) > snap_distance
|
||||
||
|
||||
abs(ny - c->state.geom.basic.position.y) > snap_distance)
|
||||
) {
|
||||
togglefloating(NULL);
|
||||
}
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->state.is_floating) {
|
||||
struct WinGeom win_geom = c->state.geom;
|
||||
position_init_from_args(&win_geom.basic.position, nx, ny);
|
||||
resize(c, win_geom, 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
|
||||
XUngrabPointer(xbase->x_display, CurrentTime);
|
||||
|
||||
Monitor *const m = recttomon(
|
||||
c->state.geom.basic.position.x,
|
||||
c->state.geom.basic.position.y,
|
||||
c->state.geom.basic.sizes.w,
|
||||
c->state.geom.basic.sizes.h
|
||||
);
|
||||
|
||||
if (m != selmon) {
|
||||
sendmon(c, m);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void movestack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *p = NULL, *pc = NULL, *i = NULL;
|
||||
|
||||
if (arg->i > 0) {
|
||||
/* find the client after selmon->sel */
|
||||
for (
|
||||
c = selmon->sel->next;
|
||||
c && (!ISVISIBLE(c) || c->state.is_floating);
|
||||
c = c->next
|
||||
);
|
||||
|
||||
if(!c) {
|
||||
for(
|
||||
c = selmon->clients;
|
||||
c && (!ISVISIBLE(c) || c->state.is_floating);
|
||||
c = c->next
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/* find the client before selmon->sel */
|
||||
for (i = selmon->clients; i != selmon->sel; i = i->next) {
|
||||
if (ISVISIBLE(i) && !i->state.is_floating) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
for (; i; i = i->next) {
|
||||
if (ISVISIBLE(i) && !i->state.is_floating) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* find the client before selmon->sel and c */
|
||||
for (i = selmon->clients; i && (!p || !pc); i = i->next) {
|
||||
if (i->next == selmon->sel) {
|
||||
p = i;
|
||||
}
|
||||
if (i->next == c) {
|
||||
pc = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* swap c and selmon->sel selmon->clients in the selmon->clients list */
|
||||
if (c && c != selmon->sel) {
|
||||
Client *temp = selmon->sel->next == c ? selmon->sel : selmon->sel->next;
|
||||
selmon->sel->next = c->next==selmon->sel?c:c->next;
|
||||
c->next = temp;
|
||||
|
||||
if (p && p != c) {
|
||||
p->next = c;
|
||||
}
|
||||
if (pc && pc != selmon->sel) {
|
||||
pc->next = selmon->sel;
|
||||
}
|
||||
|
||||
if (selmon->sel == selmon->clients) {
|
||||
selmon->clients = c;
|
||||
} else if (c == selmon->clients) {
|
||||
selmon->clients = selmon->sel;
|
||||
}
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
}
|
||||
|
||||
Client *nexttiled(Client *c)
|
||||
{
|
||||
for (; c && (c->state.is_floating || !ISVISIBLE(c)); c = c->next);
|
||||
|
@ -1488,11 +1094,6 @@ void pop(Client *c)
|
|||
arrange(c->mon);
|
||||
}
|
||||
|
||||
void quit(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
running = 0;
|
||||
}
|
||||
|
||||
Monitor *recttomon(int x, int y, int w, int h)
|
||||
{
|
||||
Monitor *m, *r = selmon;
|
||||
|
@ -1506,19 +1107,6 @@ Monitor *recttomon(int x, int y, int w, int h)
|
|||
return r;
|
||||
}
|
||||
|
||||
void resetnmaster(const Arg *arg)
|
||||
{
|
||||
const int max_clients_in_master = settings_get_max_clients_in_master();
|
||||
const int new_clients_in_master = arg->i == 0 ? 0 : settings_get_default_clients_in_master();
|
||||
|
||||
selmon->nmaster =
|
||||
max_clients_in_master == 0
|
||||
? new_clients_in_master
|
||||
: MIN(new_clients_in_master, max_clients_in_master);
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void resize(Client *c, struct WinGeom win_geom, int interact)
|
||||
{
|
||||
if (applysizehints(c, &win_geom, interact)) {
|
||||
|
@ -1544,164 +1132,6 @@ void resizeclient(Client *c, const struct WinGeom win_geom)
|
|||
XSync(xbase->x_display, False);
|
||||
}
|
||||
|
||||
void resizemouse(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
Client *const c = selmon->sel;
|
||||
if (c == NULL) return;
|
||||
|
||||
restack(selmon);
|
||||
|
||||
if (
|
||||
XGrabPointer(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
False,
|
||||
MOUSEMASK,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
None,
|
||||
cursor[CurResize]->cursor,
|
||||
CurrentTime
|
||||
) != GrabSuccess
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
XWarpPointer(
|
||||
xbase->x_display,
|
||||
None,
|
||||
c->x_window,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
c->state.geom.basic.sizes.w + c->state.geom.border_width - 1,
|
||||
c->state.geom.basic.sizes.h + c->state.geom.border_width - 1
|
||||
);
|
||||
|
||||
const unsigned int snap_distance = settings_get_snap_distance();
|
||||
const int ocx = c->state.geom.basic.position.x;
|
||||
const int ocy = c->state.geom.basic.position.y;
|
||||
|
||||
Time lasttime = 0;
|
||||
|
||||
XEvent ev;
|
||||
|
||||
do {
|
||||
XMaskEvent(
|
||||
xbase->x_display,
|
||||
MOUSEMASK | ExposureMask | SubstructureRedirectMask,
|
||||
&ev
|
||||
);
|
||||
|
||||
switch (ev.type) {
|
||||
case ConfigureRequest:
|
||||
case Expose:
|
||||
case MapRequest:
|
||||
handler[ev.type](&ev);
|
||||
break;
|
||||
case MotionNotify:
|
||||
if ((ev.xmotion.time - lasttime) <= (1000 / 60)) continue;
|
||||
|
||||
lasttime = ev.xmotion.time;
|
||||
|
||||
const int nw = MAX(
|
||||
ev.xmotion.x - ocx - 2 * c->state.geom.border_width + 1,
|
||||
1
|
||||
);
|
||||
const int nh = MAX(
|
||||
ev.xmotion.y - ocy - 2 * c->state.geom.border_width + 1,
|
||||
1
|
||||
);
|
||||
|
||||
if (
|
||||
(
|
||||
c->mon->window_area_geom.position.x + nw
|
||||
>=
|
||||
selmon->window_area_geom.position.x
|
||||
)
|
||||
&&
|
||||
(
|
||||
c->mon->window_area_geom.position.x + nw
|
||||
<=
|
||||
(
|
||||
selmon->window_area_geom.position.x
|
||||
+
|
||||
selmon->window_area_geom.sizes.w
|
||||
)
|
||||
)
|
||||
&&
|
||||
(
|
||||
c->mon->window_area_geom.position.y + nh
|
||||
>=
|
||||
selmon->window_area_geom.position.y
|
||||
)
|
||||
&&
|
||||
(
|
||||
c->mon->window_area_geom.position.y + nh
|
||||
<=
|
||||
(
|
||||
selmon->window_area_geom.position.y
|
||||
+
|
||||
selmon->window_area_geom.sizes.h
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!c->state.is_floating
|
||||
&&
|
||||
(
|
||||
selmon->lt[selmon->sellt]->arrange == NULL
|
||||
||
|
||||
abs(nw - c->state.geom.basic.sizes.w) > snap_distance
|
||||
||
|
||||
abs(nh - c->state.geom.basic.sizes.h) > snap_distance
|
||||
)
|
||||
) {
|
||||
togglefloating(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->state.is_floating) {
|
||||
struct WinGeom win_geom = c->state.geom;
|
||||
sizes_init_from_args(&win_geom.basic.sizes, nw, nh);
|
||||
resize(c, win_geom, 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
|
||||
XWarpPointer(
|
||||
xbase->x_display,
|
||||
None,
|
||||
c->x_window,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
c->state.geom.basic.sizes.w + c->state.geom.border_width - 1,
|
||||
c->state.geom.basic.sizes.h + c->state.geom.border_width - 1
|
||||
);
|
||||
|
||||
XUngrabPointer(xbase->x_display, CurrentTime);
|
||||
|
||||
while (XCheckMaskEvent(xbase->x_display, EnterWindowMask, &ev));
|
||||
|
||||
Monitor *const m = recttomon(
|
||||
c->state.geom.basic.position.x,
|
||||
c->state.geom.basic.position.y,
|
||||
c->state.geom.basic.sizes.w,
|
||||
c->state.geom.basic.sizes.h
|
||||
);
|
||||
|
||||
if (m != selmon) {
|
||||
sendmon(c, m);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void restack(Monitor *m)
|
||||
{
|
||||
Client *c;
|
||||
|
@ -1924,38 +1354,6 @@ void setfullscreen(Client *c, int fullscreen)
|
|||
}
|
||||
}
|
||||
|
||||
void setlayout(const Arg *arg)
|
||||
{
|
||||
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
selmon->sellt ^= 1;
|
||||
}
|
||||
|
||||
if (arg && arg->v) {
|
||||
const Layout *const new_layout = arg->v;
|
||||
selmon->lt[selmon->sellt] = new_layout;
|
||||
}
|
||||
|
||||
unsigned int visible_clients = 0;
|
||||
for (const Client *client = selmon->clients; client; client = client->next) {
|
||||
if (ISVISIBLE(client)) ++visible_clients;
|
||||
}
|
||||
|
||||
if (selmon->sel) {
|
||||
arrange(selmon);
|
||||
}
|
||||
}
|
||||
|
||||
void setmfact(const Arg *arg)
|
||||
{
|
||||
if (!arg) return;
|
||||
|
||||
unit_inc_master_area_factor(selmon->unit, arg->f);
|
||||
|
||||
for (Monitor *m = mons; m; m = m->next) {
|
||||
arrange(m);
|
||||
}
|
||||
}
|
||||
|
||||
void seturgent(Client *c, bool is_urgent)
|
||||
{
|
||||
XWMHints *wmh;
|
||||
|
@ -1998,54 +1396,6 @@ void showhide(Client *c)
|
|||
}
|
||||
}
|
||||
|
||||
void spawn(const Arg *arg)
|
||||
{
|
||||
const char *const command_name = arg->v;
|
||||
|
||||
spawn_command(command_name, spawn_callback, selmon->num);
|
||||
}
|
||||
|
||||
void spawn_callback()
|
||||
{
|
||||
if (xbase->x_display) {
|
||||
close(ConnectionNumber(xbase->x_display));
|
||||
}
|
||||
}
|
||||
|
||||
void tagmon(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel || !mons->next)
|
||||
return;
|
||||
sendmon(selmon->sel, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void togglefloating(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel) return;
|
||||
|
||||
selmon->sel->state.is_floating =
|
||||
!selmon->sel->state.is_floating || selmon->sel->state.is_fixed;
|
||||
|
||||
const int border_width = settings_get_border_width();
|
||||
|
||||
if (selmon->sel->state.is_floating) {
|
||||
struct WinGeom win_geom = selmon->sel->state.geom;
|
||||
|
||||
win_geom.basic.sizes = sizes_create_from_args(
|
||||
selmon->sel->state.geom.basic.sizes.w -
|
||||
2 * (border_width - selmon->sel->state.geom.border_width),
|
||||
selmon->sel->state.geom.basic.sizes.h -
|
||||
2 * (border_width - selmon->sel->state.geom.border_width)
|
||||
);
|
||||
|
||||
win_geom.border_width = border_width;
|
||||
|
||||
resize(selmon->sel, win_geom, 0);
|
||||
}
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void unfocus(Client *c, int setfocus)
|
||||
{
|
||||
if (!c)
|
||||
|
@ -2332,68 +1682,3 @@ Monitor *wintomon(Window w)
|
|||
|
||||
return selmon;
|
||||
}
|
||||
|
||||
void wmcheckwin_create()
|
||||
{
|
||||
wmcheckwin = XCreateSimpleWindow(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
XChangeProperty(
|
||||
xbase->x_display,
|
||||
wmcheckwin,
|
||||
xbase->atoms->netatom[NetWMCheck],
|
||||
XA_WINDOW,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char*)&wmcheckwin,
|
||||
1
|
||||
);
|
||||
XChangeProperty(
|
||||
xbase->x_display,
|
||||
wmcheckwin,
|
||||
xbase->atoms->netatom[NetWMName],
|
||||
xbase->atoms->utf8string,
|
||||
8,
|
||||
PropModeReplace,
|
||||
(unsigned char*)
|
||||
xbase->program_title,
|
||||
strlen(xbase->program_title)
|
||||
);
|
||||
XChangeProperty(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
xbase->atoms->netatom[NetWMCheck],
|
||||
XA_WINDOW,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char*)&wmcheckwin,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
void wmcheckwin_destroy()
|
||||
{
|
||||
XDestroyWindow(xbase->x_display, wmcheckwin);
|
||||
}
|
||||
|
||||
void zoom(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange
|
||||
|| (selmon->sel && selmon->sel->state.is_floating))
|
||||
return;
|
||||
if (c == nexttiled(selmon->clients))
|
||||
if (!c || !(c = nexttiled(c->next)))
|
||||
return;
|
||||
pop(c);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,593 @@
|
|||
void configborder(const Arg *const arg)
|
||||
{
|
||||
if (arg == NULL) return;
|
||||
const int old_border_width = settings_get_border_width();
|
||||
const int new_border_width = old_border_width + (arg->i >= 0 ? +1 : -1);
|
||||
settings_set_border_width(new_border_width);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void configgap(const Arg *const arg)
|
||||
{
|
||||
if (arg == NULL) return;
|
||||
const int old_gap_size = settings_get_gap_size();
|
||||
const int new_gap_size = old_gap_size + (arg->i >= 0 ? +2 : -2);
|
||||
settings_set_gap_size(new_gap_size);
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void dorestart(__attribute__((unused)) const Arg *const arg)
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
void focusmon(const Arg *arg)
|
||||
{
|
||||
if (!mons->next) return;
|
||||
|
||||
Monitor *m;
|
||||
if ((m = dirtomon(arg->i)) == selmon) return;
|
||||
|
||||
unfocus(selmon->sel, 0);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
|
||||
void focusstack(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel) return;
|
||||
|
||||
Client *c = NULL;
|
||||
|
||||
if (arg->i > 0) {
|
||||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
|
||||
|
||||
if (!c) {
|
||||
for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
|
||||
}
|
||||
} else {
|
||||
Client *i = selmon->clients;
|
||||
|
||||
for (; i != selmon->sel; i = i->next) {
|
||||
if (ISVISIBLE(i)) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
for (; i; i = i->next) {
|
||||
if (ISVISIBLE(i)) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
focus(c);
|
||||
restack(selmon);
|
||||
|
||||
{
|
||||
unsigned int n = 0;
|
||||
for (Client *cc = nexttiled(selmon->clients); cc; cc = nexttiled(cc->next), ++n);
|
||||
|
||||
// TODO: Maybe it's an unnecessary optimization
|
||||
// and we don't need the condition.
|
||||
if (n > 1) {
|
||||
// We have to rearrange because borders and gaps may have
|
||||
// changed in monocle layout.
|
||||
arrange(selmon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void incnmaster(const Arg *arg)
|
||||
{
|
||||
const int max_clients_in_master = settings_get_max_clients_in_master();
|
||||
const int new_clients_in_master = MAX(0, selmon->nmaster + arg->i);
|
||||
|
||||
selmon->nmaster =
|
||||
max_clients_in_master == 0
|
||||
? new_clients_in_master
|
||||
: MIN(new_clients_in_master, max_clients_in_master);
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void killclient(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
if (!sendevent(selmon->sel, xbase->atoms->wmatom[WMDelete])) {
|
||||
XGrabServer(xbase->x_display);
|
||||
XSetErrorHandler(xerrordummy);
|
||||
XSetCloseDownMode(xbase->x_display, DestroyAll);
|
||||
XKillClient(xbase->x_display, selmon->sel->x_window);
|
||||
XSync(xbase->x_display, False);
|
||||
XSetErrorHandler(xerror);
|
||||
XUngrabServer(xbase->x_display);
|
||||
}
|
||||
}
|
||||
|
||||
void movemouse(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
Client *const c = selmon->sel;
|
||||
if (c == NULL) return;
|
||||
|
||||
restack(selmon);
|
||||
|
||||
if (
|
||||
XGrabPointer(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
False,
|
||||
MOUSEMASK,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
None,
|
||||
cursor[CurMove]->cursor,
|
||||
CurrentTime
|
||||
) != GrabSuccess
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x, y;
|
||||
if (!getrootptr(&x, &y)) return;
|
||||
|
||||
const unsigned int snap_distance = settings_get_snap_distance();
|
||||
const int ocx = c->state.geom.basic.position.x;
|
||||
const int ocy = c->state.geom.basic.position.y;
|
||||
|
||||
Time lasttime = 0;
|
||||
|
||||
XEvent ev;
|
||||
|
||||
do {
|
||||
XMaskEvent(
|
||||
xbase->x_display,
|
||||
MOUSEMASK | ExposureMask | SubstructureRedirectMask,
|
||||
&ev
|
||||
);
|
||||
|
||||
switch (ev.type) {
|
||||
case ConfigureRequest:
|
||||
case Expose:
|
||||
case MapRequest:
|
||||
handler[ev.type](&ev);
|
||||
break;
|
||||
case MotionNotify:
|
||||
if ((ev.xmotion.time - lasttime) <= (1000 / 60)) continue;
|
||||
|
||||
lasttime = ev.xmotion.time;
|
||||
|
||||
int nx = ocx + (ev.xmotion.x - x);
|
||||
int ny = ocy + (ev.xmotion.y - y);
|
||||
|
||||
if (
|
||||
abs(selmon->window_area_geom.position.x - nx)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
nx = selmon->window_area_geom.position.x;
|
||||
} else if (
|
||||
abs(
|
||||
(
|
||||
selmon->window_area_geom.position.x
|
||||
+
|
||||
selmon->window_area_geom.sizes.w
|
||||
)
|
||||
-
|
||||
(nx + win_geom_total_width(&c->state.geom))
|
||||
)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
nx =
|
||||
selmon->window_area_geom.position.x
|
||||
+
|
||||
selmon->window_area_geom.sizes.w
|
||||
-
|
||||
win_geom_total_width(&c->state.geom);
|
||||
}
|
||||
|
||||
if (
|
||||
abs(selmon->window_area_geom.position.y - ny)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
ny = selmon->window_area_geom.position.y;
|
||||
} else if (
|
||||
abs(
|
||||
(
|
||||
selmon->window_area_geom.position.y
|
||||
+
|
||||
selmon->window_area_geom.sizes.h
|
||||
) - (ny + win_geom_total_height(&c->state.geom))
|
||||
)
|
||||
<
|
||||
snap_distance
|
||||
) {
|
||||
ny =
|
||||
selmon->window_area_geom.position.y
|
||||
+
|
||||
selmon->window_area_geom.sizes.h
|
||||
-
|
||||
win_geom_total_height(&c->state.geom);
|
||||
}
|
||||
|
||||
if (
|
||||
!c->state.is_floating
|
||||
&&
|
||||
(
|
||||
abs(nx - c->state.geom.basic.position.x) > snap_distance
|
||||
||
|
||||
abs(ny - c->state.geom.basic.position.y) > snap_distance)
|
||||
) {
|
||||
togglefloating(NULL);
|
||||
}
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->state.is_floating) {
|
||||
struct WinGeom win_geom = c->state.geom;
|
||||
position_init_from_args(&win_geom.basic.position, nx, ny);
|
||||
resize(c, win_geom, 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
|
||||
XUngrabPointer(xbase->x_display, CurrentTime);
|
||||
|
||||
Monitor *const m = recttomon(
|
||||
c->state.geom.basic.position.x,
|
||||
c->state.geom.basic.position.y,
|
||||
c->state.geom.basic.sizes.w,
|
||||
c->state.geom.basic.sizes.h
|
||||
);
|
||||
|
||||
if (m != selmon) {
|
||||
sendmon(c, m);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void movestack(const Arg *arg)
|
||||
{
|
||||
Client *c = NULL, *p = NULL, *pc = NULL, *i = NULL;
|
||||
|
||||
if (arg->i > 0) {
|
||||
/* find the client after selmon->sel */
|
||||
for (
|
||||
c = selmon->sel->next;
|
||||
c && (!ISVISIBLE(c) || c->state.is_floating);
|
||||
c = c->next
|
||||
);
|
||||
|
||||
if(!c) {
|
||||
for(
|
||||
c = selmon->clients;
|
||||
c && (!ISVISIBLE(c) || c->state.is_floating);
|
||||
c = c->next
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/* find the client before selmon->sel */
|
||||
for (i = selmon->clients; i != selmon->sel; i = i->next) {
|
||||
if (ISVISIBLE(i) && !i->state.is_floating) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
for (; i; i = i->next) {
|
||||
if (ISVISIBLE(i) && !i->state.is_floating) {
|
||||
c = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* find the client before selmon->sel and c */
|
||||
for (i = selmon->clients; i && (!p || !pc); i = i->next) {
|
||||
if (i->next == selmon->sel) {
|
||||
p = i;
|
||||
}
|
||||
if (i->next == c) {
|
||||
pc = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* swap c and selmon->sel selmon->clients in the selmon->clients list */
|
||||
if (c && c != selmon->sel) {
|
||||
Client *temp = selmon->sel->next == c ? selmon->sel : selmon->sel->next;
|
||||
selmon->sel->next = c->next==selmon->sel?c:c->next;
|
||||
c->next = temp;
|
||||
|
||||
if (p && p != c) {
|
||||
p->next = c;
|
||||
}
|
||||
if (pc && pc != selmon->sel) {
|
||||
pc->next = selmon->sel;
|
||||
}
|
||||
|
||||
if (selmon->sel == selmon->clients) {
|
||||
selmon->clients = c;
|
||||
} else if (c == selmon->clients) {
|
||||
selmon->clients = selmon->sel;
|
||||
}
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
}
|
||||
|
||||
void quit(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
running = 0;
|
||||
}
|
||||
|
||||
void resetnmaster(const Arg *arg)
|
||||
{
|
||||
const int max_clients_in_master = settings_get_max_clients_in_master();
|
||||
const int new_clients_in_master = arg->i == 0 ? 0 : settings_get_default_clients_in_master();
|
||||
|
||||
selmon->nmaster =
|
||||
max_clients_in_master == 0
|
||||
? new_clients_in_master
|
||||
: MIN(new_clients_in_master, max_clients_in_master);
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void resizemouse(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
Client *const c = selmon->sel;
|
||||
if (c == NULL) return;
|
||||
|
||||
restack(selmon);
|
||||
|
||||
if (
|
||||
XGrabPointer(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
False,
|
||||
MOUSEMASK,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
None,
|
||||
cursor[CurResize]->cursor,
|
||||
CurrentTime
|
||||
) != GrabSuccess
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
XWarpPointer(
|
||||
xbase->x_display,
|
||||
None,
|
||||
c->x_window,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
c->state.geom.basic.sizes.w + c->state.geom.border_width - 1,
|
||||
c->state.geom.basic.sizes.h + c->state.geom.border_width - 1
|
||||
);
|
||||
|
||||
const unsigned int snap_distance = settings_get_snap_distance();
|
||||
const int ocx = c->state.geom.basic.position.x;
|
||||
const int ocy = c->state.geom.basic.position.y;
|
||||
|
||||
Time lasttime = 0;
|
||||
|
||||
XEvent ev;
|
||||
|
||||
do {
|
||||
XMaskEvent(
|
||||
xbase->x_display,
|
||||
MOUSEMASK | ExposureMask | SubstructureRedirectMask,
|
||||
&ev
|
||||
);
|
||||
|
||||
switch (ev.type) {
|
||||
case ConfigureRequest:
|
||||
case Expose:
|
||||
case MapRequest:
|
||||
handler[ev.type](&ev);
|
||||
break;
|
||||
case MotionNotify:
|
||||
if ((ev.xmotion.time - lasttime) <= (1000 / 60)) continue;
|
||||
|
||||
lasttime = ev.xmotion.time;
|
||||
|
||||
const int nw = MAX(
|
||||
ev.xmotion.x - ocx - 2 * c->state.geom.border_width + 1,
|
||||
1
|
||||
);
|
||||
const int nh = MAX(
|
||||
ev.xmotion.y - ocy - 2 * c->state.geom.border_width + 1,
|
||||
1
|
||||
);
|
||||
|
||||
if (
|
||||
(
|
||||
c->mon->window_area_geom.position.x + nw
|
||||
>=
|
||||
selmon->window_area_geom.position.x
|
||||
)
|
||||
&&
|
||||
(
|
||||
c->mon->window_area_geom.position.x + nw
|
||||
<=
|
||||
(
|
||||
selmon->window_area_geom.position.x
|
||||
+
|
||||
selmon->window_area_geom.sizes.w
|
||||
)
|
||||
)
|
||||
&&
|
||||
(
|
||||
c->mon->window_area_geom.position.y + nh
|
||||
>=
|
||||
selmon->window_area_geom.position.y
|
||||
)
|
||||
&&
|
||||
(
|
||||
c->mon->window_area_geom.position.y + nh
|
||||
<=
|
||||
(
|
||||
selmon->window_area_geom.position.y
|
||||
+
|
||||
selmon->window_area_geom.sizes.h
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!c->state.is_floating
|
||||
&&
|
||||
(
|
||||
selmon->lt[selmon->sellt]->arrange == NULL
|
||||
||
|
||||
abs(nw - c->state.geom.basic.sizes.w) > snap_distance
|
||||
||
|
||||
abs(nh - c->state.geom.basic.sizes.h) > snap_distance
|
||||
)
|
||||
) {
|
||||
togglefloating(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->state.is_floating) {
|
||||
struct WinGeom win_geom = c->state.geom;
|
||||
sizes_init_from_args(&win_geom.basic.sizes, nw, nh);
|
||||
resize(c, win_geom, 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
|
||||
XWarpPointer(
|
||||
xbase->x_display,
|
||||
None,
|
||||
c->x_window,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
c->state.geom.basic.sizes.w + c->state.geom.border_width - 1,
|
||||
c->state.geom.basic.sizes.h + c->state.geom.border_width - 1
|
||||
);
|
||||
|
||||
XUngrabPointer(xbase->x_display, CurrentTime);
|
||||
|
||||
while (XCheckMaskEvent(xbase->x_display, EnterWindowMask, &ev));
|
||||
|
||||
Monitor *const m = recttomon(
|
||||
c->state.geom.basic.position.x,
|
||||
c->state.geom.basic.position.y,
|
||||
c->state.geom.basic.sizes.w,
|
||||
c->state.geom.basic.sizes.h
|
||||
);
|
||||
|
||||
if (m != selmon) {
|
||||
sendmon(c, m);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void setlayout(const Arg *arg)
|
||||
{
|
||||
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
|
||||
selmon->sellt ^= 1;
|
||||
}
|
||||
|
||||
if (arg && arg->v) {
|
||||
const Layout *const new_layout = arg->v;
|
||||
selmon->lt[selmon->sellt] = new_layout;
|
||||
}
|
||||
|
||||
unsigned int visible_clients = 0;
|
||||
for (const Client *client = selmon->clients; client; client = client->next) {
|
||||
if (ISVISIBLE(client)) ++visible_clients;
|
||||
}
|
||||
|
||||
if (selmon->sel) {
|
||||
arrange(selmon);
|
||||
}
|
||||
}
|
||||
|
||||
void setmfact(const Arg *arg)
|
||||
{
|
||||
if (!arg) return;
|
||||
|
||||
unit_inc_master_area_factor(selmon->unit, arg->f);
|
||||
|
||||
for (Monitor *m = mons; m; m = m->next) {
|
||||
arrange(m);
|
||||
}
|
||||
}
|
||||
|
||||
void spawn(const Arg *arg)
|
||||
{
|
||||
const char *const command_name = arg->v;
|
||||
|
||||
spawn_command(command_name, spawn_callback, selmon->num);
|
||||
}
|
||||
|
||||
void spawn_callback()
|
||||
{
|
||||
if (xbase->x_display) {
|
||||
close(ConnectionNumber(xbase->x_display));
|
||||
}
|
||||
}
|
||||
|
||||
void tagmon(const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel || !mons->next)
|
||||
return;
|
||||
sendmon(selmon->sel, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void togglefloating(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
if (!selmon->sel) return;
|
||||
|
||||
selmon->sel->state.is_floating =
|
||||
!selmon->sel->state.is_floating || selmon->sel->state.is_fixed;
|
||||
|
||||
const int border_width = settings_get_border_width();
|
||||
|
||||
if (selmon->sel->state.is_floating) {
|
||||
struct WinGeom win_geom = selmon->sel->state.geom;
|
||||
|
||||
win_geom.basic.sizes = sizes_create_from_args(
|
||||
selmon->sel->state.geom.basic.sizes.w -
|
||||
2 * (border_width - selmon->sel->state.geom.border_width),
|
||||
selmon->sel->state.geom.basic.sizes.h -
|
||||
2 * (border_width - selmon->sel->state.geom.border_width)
|
||||
);
|
||||
|
||||
win_geom.border_width = border_width;
|
||||
|
||||
resize(selmon->sel, win_geom, 0);
|
||||
}
|
||||
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void zoom(__attribute__((unused)) const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange
|
||||
|| (selmon->sel && selmon->sel->state.is_floating))
|
||||
return;
|
||||
if (c == nexttiled(selmon->clients))
|
||||
if (!c || !(c = nexttiled(c->next)))
|
||||
return;
|
||||
pop(c);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef _DWM_INTERACTION_H
|
||||
#define _DWM_INTERACTION_H
|
||||
|
||||
static void configborder(const Arg *arg);
|
||||
static void configgap(const Arg *arg);
|
||||
static void dorestart(const Arg *arg);
|
||||
static void focusmon(const Arg *arg);
|
||||
static void focusstack(const Arg *arg);
|
||||
static void incnmaster(const Arg *arg);
|
||||
static void killclient(const Arg *arg);
|
||||
static void movemouse(const Arg *arg);
|
||||
static void movestack(const Arg *arg);
|
||||
static void quit(const Arg *arg);
|
||||
static void resetnmaster(const Arg *arg);
|
||||
static void resizemouse(const Arg *arg);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
static void spawn_callback();
|
||||
|
||||
#define MODKEY Mod4Mask
|
||||
|
||||
static Key keys[] = {
|
||||
// WM
|
||||
{ MODKEY|ControlMask|ShiftMask, XK_q, quit, {0} },
|
||||
{ MODKEY|ControlMask|ShiftMask, XK_r, dorestart, {0} },
|
||||
// Monitor
|
||||
{ MODKEY, XK_bracketleft, focusmon, {.i = -1 } },
|
||||
{ MODKEY, XK_bracketright, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_bracketleft, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_bracketright, tagmon, {.i = +1 } },
|
||||
// Layout
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[0]} }, // Monocle
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, // Floating
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[2]} }, // Tile
|
||||
{ MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[3]} }, // Horizontile
|
||||
{ MODKEY, XK_u, setlayout, {.v = &layouts[4]} }, // Centeredmaster
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_i, resetnmaster, {.i = 1 } },
|
||||
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_d, resetnmaster, {.i = 0 } },
|
||||
// Stack
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
|
||||
{ MODKEY, XK_Return, zoom, {0} },
|
||||
// Window
|
||||
{ MODKEY|ShiftMask, XK_x, killclient, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
// Appearance
|
||||
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||
{ MODKEY|Mod1Mask, XK_b, configborder, {.i = -1 } },
|
||||
{ MODKEY|Mod1Mask|ShiftMask, XK_b, configborder, {.i = +1 } },
|
||||
{ MODKEY|Mod1Mask, XK_g, configgap, {.i = -1 } },
|
||||
{ MODKEY|Mod1Mask|ShiftMask, XK_g, configgap, {.i = +1 } },
|
||||
// Starting applications
|
||||
{ MODKEY, XK_z, spawn, {.v = "lock" } },
|
||||
{ MODKEY, XK_slash, spawn, {.v = "menu" } },
|
||||
{ MODKEY|ShiftMask, XK_slash, spawn, {.v = "term" } },
|
||||
{ MODKEY|ShiftMask, XK_f, spawn, {.v = "firefox" } },
|
||||
};
|
||||
|
||||
// click can be ClkClientWin, or ClkRootWin
|
||||
static Button buttons[] = {
|
||||
/* click event mask button function argument */
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
};
|
||||
|
||||
#endif // _DWM_INTERACTION_H
|
|
@ -0,0 +1,53 @@
|
|||
static Window wmcheckwin = 0;
|
||||
|
||||
void wmcheckwin_create()
|
||||
{
|
||||
wmcheckwin = XCreateSimpleWindow(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
XChangeProperty(
|
||||
xbase->x_display,
|
||||
wmcheckwin,
|
||||
xbase->atoms->netatom[NetWMCheck],
|
||||
XA_WINDOW,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char*)&wmcheckwin,
|
||||
1
|
||||
);
|
||||
XChangeProperty(
|
||||
xbase->x_display,
|
||||
wmcheckwin,
|
||||
xbase->atoms->netatom[NetWMName],
|
||||
xbase->atoms->utf8string,
|
||||
8,
|
||||
PropModeReplace,
|
||||
(unsigned char*)
|
||||
xbase->program_title,
|
||||
strlen(xbase->program_title)
|
||||
);
|
||||
XChangeProperty(
|
||||
xbase->x_display,
|
||||
xbase->x_root,
|
||||
xbase->atoms->netatom[NetWMCheck],
|
||||
XA_WINDOW,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char*)&wmcheckwin,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
void wmcheckwin_destroy()
|
||||
{
|
||||
XDestroyWindow(xbase->x_display, wmcheckwin);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _DWM_WMCHECKWIN_H
|
||||
#define _DWM_WMCHECKWIN_H
|
||||
|
||||
static void wmcheckwin_create();
|
||||
static void wmcheckwin_destroy();
|
||||
|
||||
#endif // _DWM_WMCHECKWIN_H
|
Loading…
Reference in New Issue