aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h19
-rw-r--r--dwl.c99
2 files changed, 109 insertions, 9 deletions
diff --git a/config.h b/config.h
index 633d035..28bcf26 100644
--- a/config.h
+++ b/config.h
@@ -1,14 +1,21 @@
/* appearance */
static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0};
+/* layout(s) */
+static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "[]=", tile },
+ { "><>", NULL }, /* no layout function means floating behavior */
+};
+
/* monitors */
static const MonitorRule monrules[] = {
- /* name scale */
- { "X11-1", 1 },
- { "eDP-1", 2 },
- { "HDMI-A-1", 1 },
- /* defaults */
- { NULL, 1 },
+ /* name mfact nmaster scale layout */
+ { "X11-1", 0.5, 1, 1, &layouts[0] },
+ { "eDP-1", 0.5, 1, 2, &layouts[0] },
+ { "HDMI-A-1", 0.5, 1, 1, &layouts[0] },
+ /* defaults (required) */
+ { NULL, 0.5, 1, 1, &layouts[0] },
};
/* keyboard */
diff --git a/dwl.c b/dwl.c
index 0c45ca5..177a946 100644
--- a/dwl.c
+++ b/dwl.c
@@ -29,7 +29,10 @@
#include <wlr/util/log.h>
#include <xkbcommon/xkbcommon.h>
+/* macros */
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
+#define VISIBLEON(C, M) ((C)->mon == (M))
#define LENGTH(X) (sizeof X / sizeof X[0])
/* enums */
@@ -49,6 +52,7 @@ typedef struct {
const Arg arg;
} Button;
+typedef struct Monitor Monitor;
typedef struct {
struct wl_list link;
struct wlr_xdg_surface *xdg_surface;
@@ -57,7 +61,8 @@ typedef struct {
struct wl_listener destroy;
struct wl_listener request_move;
struct wl_listener request_resize;
- int x, y;
+ Monitor *mon;
+ int x, y; /* layout-relative */
} Client;
typedef struct {
@@ -76,14 +81,28 @@ typedef struct {
} Keyboard;
typedef struct {
+ const char *symbol;
+ void (*arrange)(Monitor *);
+} Layout;
+
+struct Monitor {
struct wl_list link;
struct wlr_output *wlr_output;
struct wl_listener frame;
-} Monitor;
+ struct wlr_box *geom; /* layout-relative */
+ int wx, wy, ww, wh; /* layout-relative */
+ const Layout *lt[2];
+ unsigned int sellt;
+ double mfact;
+ int nmaster;
+};
typedef struct {
const char *name;
+ float mfact;
+ int nmaster;
float scale;
+ const Layout *lt;
} MonitorRule;
/* Used to move all of the data necessary to render a surface from the top-level
@@ -91,10 +110,11 @@ typedef struct {
struct render_data {
struct wlr_output *output;
struct timespec *when;
- int x, y;
+ int x, y; /* layout-relative */
};
/* function declarations */
+static void arrange(Monitor *m);
static void axisnotify(struct wl_listener *listener, void *data);
static void buttonpress(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_input_device *device);
@@ -118,11 +138,13 @@ static void moveresize(Client *c, unsigned int mode);
static void quit(const Arg *arg);
static void render(struct wlr_surface *surface, int sx, int sy, void *data);
static void rendermon(struct wl_listener *listener, void *data);
+static void resize(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void run(char *startup_cmd);
static void setcursor(struct wl_listener *listener, void *data);
static void setup(void);
static void spawn(const Arg *arg);
+static void tile(Monitor *m);
static void unmapnotify(struct wl_listener *listener, void *data);
static Client * xytoclient(double x, double y,
struct wlr_surface **surface, double *sx, double *sy);
@@ -156,10 +178,18 @@ static int grab_width, grab_height;
static struct wlr_output_layout *output_layout;
static struct wl_list mons;
static struct wl_listener new_output;
+static Monitor *selmon;
#include "config.h"
void
+arrange(Monitor *m)
+{
+ if (m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+}
+
+void
axisnotify(struct wl_listener *listener, void *data)
{
/* This event is forwarded by the cursor when a pointer emits an axis event,
@@ -259,7 +289,10 @@ createmon(struct wl_listener *listener, void *data)
for (i = 0; i < LENGTH(monrules); i++) {
if (!monrules[i].name ||
!strcmp(wlr_output->name, monrules[i].name)) {
+ m->mfact = monrules[i].mfact;
+ m->nmaster = monrules[i].nmaster;
wlr_output_set_scale(wlr_output, monrules[i].scale);
+ m->lt[0] = m->lt[1] = monrules[i].lt;
break;
}
}
@@ -268,6 +301,9 @@ createmon(struct wl_listener *listener, void *data)
wl_signal_add(&wlr_output->events.frame, &m->frame);
wl_list_insert(&mons, &m->link);
+ if (!selmon)
+ selmon = m;
+
/* Adds this to the output layout. The add_auto function arranges outputs
* from left-to-right in the order they appear. A more sophisticated
* compositor would let the user configure the arrangement of outputs in the
@@ -294,6 +330,9 @@ createnotify(struct wl_listener *listener, void *data)
Client *c = calloc(1, sizeof(*c));
c->xdg_surface = xdg_surface;
+ /* Tell the client not to try anything fancy */
+ wlr_xdg_toplevel_set_tiled(c->xdg_surface, true);
+
/* Listen to the various events it can emit */
c->map.notify = maprequest;
wl_signal_add(&xdg_surface->events.map, &c->map);
@@ -487,6 +526,7 @@ maprequest(struct wl_listener *listener, void *data)
Client *c = wl_container_of(listener, c, map);
/* Insert this client into the list and focus it. */
+ c->mon = selmon;
wl_list_insert(&clients, &c->link);
focus(c, c->xdg_surface->surface);
}
@@ -699,6 +739,15 @@ rendermon(struct wl_listener *listener, void *data)
if (!wlr_output_attach_render(m->wlr_output, NULL)) {
return;
}
+ /* Get effective monitor geometry and window area */
+ m->geom = wlr_output_layout_get_box(output_layout, m->wlr_output);
+ m->wx = m->geom->x;
+ m->wy = m->geom->y;
+ m->ww = m->geom->width;
+ m->wh = m->geom->height;
+
+ arrange(m);
+
/* Begin the renderer (calls glViewport and some other GL sanity checks) */
wlr_renderer_begin(renderer, m->wlr_output->width, m->wlr_output->height);
wlr_renderer_clear(renderer, rootcolor);
@@ -734,6 +783,14 @@ rendermon(struct wl_listener *listener, void *data)
}
void
+resize(Client *c, int x, int y, int w, int h)
+{
+ c->x = x;
+ c->y = y;
+ wlr_xdg_toplevel_set_size(c->xdg_surface, w, h);
+}
+
+void
resizemouse(const Arg *arg)
{
double sx, sy;
@@ -937,6 +994,42 @@ spawn(const Arg *arg)
}
void
+tile(Monitor *m)
+{
+ unsigned int i, n = 0, h, mw, my, ty;
+ Client *c;
+ struct wlr_box ca;
+
+ wl_list_for_each(c, &clients, link) {
+ if (VISIBLEON(c, m))
+ n++;
+ }
+ if (n == 0)
+ return;
+
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+ mw = m->ww;
+ i = my = ty = 0;
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m))
+ continue;
+ wlr_xdg_surface_get_geometry(c->xdg_surface, &ca);
+ if (i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx, m->wy + my, mw, h);
+ my += ca.height;
+ } else {
+ h = (m->wh - ty) / (n - i);
+ resize(c, m->wx + mw, m->wy + ty, m->ww - mw, h);
+ ty += ca.height;
+ }
+ i++;
+ }
+}
+
+void
unmapnotify(struct wl_listener *listener, void *data)
{
/* Called when the surface is unmapped, and should no longer be shown. */