I'd like to start a discussion about adding tiling to cwm with
these two diffs.
First diff adds a helper function to get the area of the screen.
I don't have a second screen here, so no idea if it works with
Xinerama (please test!).
Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.146
diff -u -r1.146 calmwm.h
--- calmwm.h 16 May 2012 01:17:14 -0000 1.146
+++ calmwm.h 2 Jun 2012 15:16:26 -0000
@@ -103,6 +103,13 @@
int right;
};
+struct rect {
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
struct winname {
TAILQ_ENTRY(winname) entry;
char *name;
@@ -118,12 +125,7 @@
XSizeHints *size;
Colormap cmap;
u_int bwidth; /* border width */
- struct {
- int x; /* x position */
- int y; /* y position */
- int width; /* width */
- int height;/* height */
- } geom, savegeom;
+ struct rect geom, savegeom;
struct {
int basew; /* desired width */
int baseh; /* desired height */
@@ -361,6 +363,7 @@
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
struct screen_ctx *screen_fromroot(Window);
void screen_init_xinerama(struct screen_ctx *);
+struct rect *screen_get_area(struct screen_ctx *, int);
void screen_update_geometry(struct screen_ctx *, int, int);
void screen_updatestackingorder(struct screen_ctx *);
Index: client.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/client.c,v
retrieving revision 1.94
diff -u -r1.94 client.c
--- client.c 16 May 2012 01:09:17 -0000 1.94
+++ client.c 2 Jun 2012 15:16:27 -0000
@@ -277,8 +277,7 @@
client_maximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
- int xmax = sc->xmax, ymax = sc->ymax;
- int x_org = 0, y_org = 0;
+ struct rect *sa;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -300,28 +299,9 @@
cc->savegeom.x = cc->geom.x;
}
- if (HasXinerama) {
- XineramaScreenInfo *xine;
- /*
- * pick screen that the middle of the window is on.
- * that's probably more fair than if just the origin of
- * a window is poking over a boundary
- */
- xine = screen_find_xinerama(sc,
- cc->geom.x + cc->geom.width / 2,
- cc->geom.y + cc->geom.height / 2);
- if (xine == NULL)
- goto calc;
- x_org = xine->x_org;
- y_org = xine->y_org;
- xmax = xine->width;
- ymax = xine->height;
- }
-calc:
- cc->geom.x = x_org + sc->gap.left;
- cc->geom.y = y_org + sc->gap.top;
- cc->geom.height = ymax - (sc->gap.top + sc->gap.bottom);
- cc->geom.width = xmax - (sc->gap.left + sc->gap.right);
+ sa = screen_get_area(sc, 1);
+ memcpy(&cc->geom, sa, sizeof(*sa));
+ free(sa);
cc->bwidth = 0;
cc->flags |= CLIENT_MAXIMIZED;
@@ -333,7 +313,7 @@
client_vertmaximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
- int y_org = 0, ymax = sc->ymax;
+ struct rect *sa;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -357,21 +337,11 @@
cc->bwidth = 0;
}
- if (HasXinerama) {
- XineramaScreenInfo *xine;
- xine = screen_find_xinerama(sc,
- cc->geom.x + cc->geom.width / 2,
- cc->geom.y + cc->geom.height / 2);
- if (xine == NULL)
- goto calc;
- y_org = xine->y_org;
- ymax = xine->height;
- }
-calc:
- cc->geom.y = y_org + sc->gap.top;
- cc->geom.height = ymax - (cc->bwidth * 2) - (sc->gap.top +
- sc->gap.bottom);
+ sa = screen_get_area(sc, 1);
+ cc->geom.y = sa->y;
+ cc->geom.height = sa->height - (cc->bwidth * 2);
cc->flags |= CLIENT_VMAXIMIZED;
+ free(sa);
resize:
client_resize(cc);
@@ -381,7 +351,7 @@
client_horizmaximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
- int x_org = 0, xmax = sc->xmax;
+ struct rect *sa;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -405,21 +375,11 @@
cc->bwidth = 0;
}
- if (HasXinerama) {
- XineramaScreenInfo *xine;
- xine = screen_find_xinerama(sc,
- cc->geom.x + cc->geom.width / 2,
- cc->geom.y + cc->geom.height / 2);
- if (xine == NULL)
- goto calc;
- x_org = xine->x_org;
- xmax = xine->width;
- }
-calc:
- cc->geom.x = x_org + sc->gap.left;
- cc->geom.width = xmax - (cc->bwidth * 2) - (sc->gap.left +
- sc->gap.right);
+ sa = screen_get_area(sc, 1);
+ cc->geom.x = sa->x;
+ cc->geom.width = sa->width - (cc->bwidth * 2);
cc->flags |= CLIENT_HMAXIMIZED;
+ free(sa);
resize:
client_resize(cc);
Index: screen.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/screen.c,v
retrieving revision 1.28
diff -u -r1.28 screen.c
--- screen.c 11 May 2011 13:53:51 -0000 1.28
+++ screen.c 2 Jun 2012 15:16:27 -0000
@@ -131,3 +131,34 @@
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
}
+
+struct rect*
+screen_get_area(struct screen_ctx *sc, int gap)
+{
+ int px, py;
+ struct rect *r;
+
+ r = calloc(1, sizeof(*r));
+ r->width = sc->xmax;
+ r->height = sc->ymax;
+
+ if (HasXinerama) {
+ XineramaScreenInfo *xine;
+ xu_ptr_getpos(sc->rootwin, &px, &py);
+ xine = screen_find_xinerama(sc, px, py);
+ if (xine == NULL)
+ goto calc;
+ r->x = xine->x_org;
+ r->width = xine->width;
+ r->y = xine->y_org;
+ r->height = xine->height;
+ }
+calc:
+ if (gap) {
+ r->x += sc->gap.left;
+ r->y += sc->gap.top;
+ r->width -= sc->gap.left + sc->gap.right;
+ r->height -= sc->gap.top + sc->gap.bottom;
+ }
+ return r;
+}
This diff adds support support for "horizontal tiling" (a la dwm's
"bottom stack layout"). You have one "master" in a group, you set
its height as usual (and it doesn't change) and every other window
in the same group is resized to fit into the screen. The layout is
not dynamic, which means that new windows are *not* automatically
tiled. You have to press htile hotkey to tile them.
It looks like this:
___________________
| |
| master |
| |
-------------------
| 1 | 2 | 3 |
|_____|_____|_____|
This layout fits all my tiling needs for now, but I anticipate
requests to add "right stack layout" by people with wide-screen
monitors. It would be easy, but at first I'd like to know, do we
want tiling in cwm? Do we want it done this way, or, maybe,
dwm-way? Or some other way?
diff --git a/Makefile b/Makefile
index a6c5ea8..e7543d6 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ PROG= cwm
SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \
search.c util.c xutil.c conf.c xevents.c group.c \
- kbfunc.c mousefunc.c font.c parse.y
+ kbfunc.c mousefunc.c font.c tile.c parse.y
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
diff --git a/calmwm.h b/calmwm.h
index 30df5e6..1ff4a77 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -406,6 +406,7 @@ void kbfunc_quit_wm(struct
client_ctx *, union arg *);
void kbfunc_reload(struct client_ctx *, union arg *);
void kbfunc_ssh(struct client_ctx *, union arg *);
void kbfunc_term(struct client_ctx *, union arg *);
+void kbfunc_tile(struct client_ctx *, union arg *);
void mousefunc_menu_cmd(struct client_ctx *, void *);
void mousefunc_menu_group(struct client_ctx *, void *);
@@ -450,6 +451,8 @@ void font_init(struct screen_ctx *,
const char *);
int font_width(struct screen_ctx *, const char *, int);
XftFont *font_make(struct screen_ctx *, const char *);
+void tile_horiz(struct client_ctx *cc);
+
void xev_loop(void);
void xu_btn_grab(Window, int, u_int);
diff --git a/conf.c b/conf.c
index 60e49ca..fee764b 100644
--- a/conf.c
+++ b/conf.c
@@ -422,6 +422,7 @@ static struct {
{.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} },
{ "bigptrmoveright", kbfunc_moveresize, 0,
{.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} },
+ { "htile", kbfunc_tile, KBFLAG_NEEDCLIENT, { .i = 0 } },
};
/*
diff --git a/kbfunc.c b/kbfunc.c
index 224b9af..577dbc8 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -502,3 +502,9 @@ kbfunc_reload(struct client_ctx *cc, union arg *arg)
{
conf_reload(&Conf);
}
+
+void
+kbfunc_tile(struct client_ctx *cc, union arg *arg)
+{
+ tile_horiz(cc);
+}
diff --git a/tile.c b/tile.c
new file mode 100644
index 0000000..aef94a9
--- /dev/null
+++ b/tile.c
@@ -0,0 +1,73 @@
+/*
+ * calmwm - the calm window manager
+ *
+ * Copyright (c) 2004 Marius Aamodt Eriksen <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include "calmwm.h"
+
+void
+tile_horiz(struct client_ctx *cc)
+{
+ struct client_ctx *ci;
+ struct group_ctx *gc = cc->group;
+ struct screen_ctx *sc = cc->sc;
+ struct rect *sa;
+ int i, n, mh, x, h, w;
+
+ if (!gc)
+ return;
+ i = n = 0;
+
+ TAILQ_FOREACH(ci, &gc->clients, group_entry) {
+ if (ci->flags & CLIENT_HIDDEN ||
+ ci->flags & CLIENT_IGNORE || (ci == cc))
+ continue;
+ n++;
+ }
+ if (n == 0)
+ return;
+
+ sa = screen_get_area(sc, 1);
+ cc->geom.x = sa->x;
+ cc->geom.y = sa->y;
+ cc->geom.width = sa->width - 2*cc->bwidth;
+ client_resize(cc);
+ client_ptrwarp(cc);
+
+ mh = cc->geom.height + 2*cc->bwidth;
+ x = sa->x;
+ w = sa->width/n;
+ h = sa->height - mh;
+ TAILQ_FOREACH(ci, &gc->clients, group_entry) {
+ if (ci->flags & CLIENT_HIDDEN ||
+ ci->flags & CLIENT_IGNORE || (ci == cc))
+ continue;
+ ci->geom.y = sa->y + mh;
+ ci->geom.x = x;
+ ci->geom.height = h - 2*ci->bwidth;
+ ci->geom.width = w - 2*ci->bwidth;
+ if (i+1 == n)
+ ci->geom.width = sa->x + sa->width - ci->geom.x -
2*ci->bwidth;
+ x += w;
+ client_resize(ci);
+ i++;
+ }
+}