summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--bar.c18
-rw-r--r--client.c89
-rw-r--r--config.h4
-rw-r--r--draw.c6
-rw-r--r--draw.h1
-rw-r--r--event.c264
-rw-r--r--menu.c9
-rw-r--r--util.c23
-rw-r--r--util.h6
-rw-r--r--wm.c51
-rw-r--r--wm.h40
12 files changed, 476 insertions, 39 deletions
diff --git a/Makefile b/Makefile
index 7a741494..c5c8db4d 100644
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,11 @@
include config.mk
-WMSRC = wm.c draw.c util.c
+WMSRC = bar.c client.c draw.c event.c util.c wm.c
WMOBJ = ${WMSRC:.c=.o}
MENSRC = menu.c draw.c util.c
MENOBJ = ${MENSRC:.c=.o}
-MAN = gridwm.1
+MAN1 = gridwm.1 gridmenu.1
BIN = gridwm gridmenu
all: config gridwm gridmenu
diff --git a/bar.c b/bar.c
new file mode 100644
index 00000000..8d4fb36f
--- /dev/null
+++ b/bar.c
@@ -0,0 +1,18 @@
+/*
+ * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
+ * See LICENSE file for license details.
+ */
+
+#include "wm.h"
+
+void
+draw_bar()
+{
+ brush.rect = barrect;
+ brush.rect.x = brush.rect.y = 0;
+ draw(dpy, &brush, False, 0);
+
+ XCopyArea(dpy, brush.drawable, barwin, brush.gc, 0, 0, barrect.width,
+ barrect.height, 0, 0);
+ XFlush(dpy);
+}
diff --git a/client.c b/client.c
new file mode 100644
index 00000000..a5141ea6
--- /dev/null
+++ b/client.c
@@ -0,0 +1,89 @@
+/*
+ * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
+ * See LICENSE file for license details.
+ */
+
+#include <string.h>
+#include <X11/Xatom.h>
+
+#include "util.h"
+#include "wm.h"
+
+static void
+update_client_name(Client *c)
+{
+ XTextProperty name;
+ int n;
+ char **list = 0;
+
+ name.nitems = 0;
+ c->name[0] = 0;
+ XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
+ if(!name.nitems)
+ XGetWMName(dpy, c->win, &name);
+ if(!name.nitems)
+ return;
+ if(name.encoding == XA_STRING)
+ strncpy(c->name, (char *)name.value, sizeof(c->name));
+ else {
+ if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
+ && n > 0 && *list)
+ {
+ strncpy(c->name, *list, sizeof(c->name));
+ XFreeStringList(list);
+ }
+ }
+ XFree(name.value);
+}
+
+Client *
+create_client(Window w, XWindowAttributes *wa)
+{
+ Client *c;
+ XSetWindowAttributes twa;
+ long msize;
+
+ c = emallocz(sizeof(Client));
+ c->win = w;
+ c->r[RFloat].x = wa->x;
+ c->r[RFloat].y = wa->y;
+ c->r[RFloat].width = wa->width;
+ c->r[RFloat].height = wa->height;
+ c->border = wa->border_width;
+ XSetWindowBorderWidth(dpy, c->win, 0);
+ c->proto = win_proto(c->win);
+ XGetTransientForHint(dpy, c->win, &c->trans);
+ if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags)
+ c->size.flags = PSize;
+ c->fixedsize =
+ (c->size.flags & PMinSize && c->size.flags & PMaxSize
+ && c->size.min_width == c->size.max_width
+ && c->size.min_height == c->size.max_height);
+ XAddToSaveSet(dpy, c->win);
+ update_client_name(c);
+ twa.override_redirect = 1;
+ twa.background_pixmap = ParentRelative;
+ twa.event_mask = ExposureMask;
+
+ c->title = XCreateWindow(dpy, root, c->r[RFloat].x, c->r[RFloat].y,
+ c->r[RFloat].width, barrect.height, 0,
+ DefaultDepth(dpy, screen), CopyFromParent,
+ DefaultVisual(dpy, screen),
+ CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
+ XFlush(dpy);
+
+#if 0
+ for(t=&client, i=0; *t; t=&(*t)->next, i++);
+ c->next = *t; /* *t == nil */
+ *t = c;
+#endif
+ return c;
+}
+
+void
+manage(Client *c)
+{
+ XMapRaised(dpy, c->win);
+ XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
+ XFlush(dpy);
+}
diff --git a/config.h b/config.h
index 6a768b69..ca05aa24 100644
--- a/config.h
+++ b/config.h
@@ -4,6 +4,6 @@
*/
#define FONT "-*-terminus-medium-*-*-*-14-*-*-*-*-*-iso10646-*"
-#define FGCOLOR "#000000"
-#define BGCOLOR "#ffaa00"
+#define BGCOLOR "#000000"
+#define FGCOLOR "#ffaa00"
#define BORDERCOLOR "#000000"
diff --git a/draw.c b/draw.c
index cf7f14e2..b89c3651 100644
--- a/draw.c
+++ b/draw.c
@@ -162,3 +162,9 @@ loadfont(Display *dpy, Fnt *font, const char *fontstr)
}
font->height = font->ascent + font->descent;
}
+
+unsigned int
+labelheight(Fnt *font)
+{
+ return font->height + 4;
+}
diff --git a/draw.h b/draw.h
index 710087f4..6c3d886e 100644
--- a/draw.h
+++ b/draw.h
@@ -33,3 +33,4 @@ extern void loadcolors(Display *dpy, int screen, Brush *b,
extern void loadfont(Display *dpy, Fnt *font, const char *fontstr);
extern unsigned int textwidth_l(Fnt *font, char *text, unsigned int len);
extern unsigned int textwidth(Fnt *font, char *text);
+extern unsigned int labelheight(Fnt *font);
diff --git a/event.c b/event.c
new file mode 100644
index 00000000..d6977d38
--- /dev/null
+++ b/event.c
@@ -0,0 +1,264 @@
+/*
+ * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
+ * See LICENSE file for license details.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/keysym.h>
+
+#include "wm.h"
+
+/* local functions */
+static void configurerequest(XEvent *e);
+static void destroynotify(XEvent *e);
+static void enternotify(XEvent *e);
+static void leavenotify(XEvent *e);
+static void expose(XEvent *e);
+static void keypress(XEvent *e);
+static void keymapnotify(XEvent *e);
+static void maprequest(XEvent *e);
+static void propertynotify(XEvent *e);
+static void unmapnotify(XEvent *e);
+
+void (*handler[LASTEvent]) (XEvent *) = {
+ [ConfigureRequest] = configurerequest,
+ [DestroyNotify] = destroynotify,
+ [EnterNotify] = enternotify,
+ [LeaveNotify] = leavenotify,
+ [Expose] = expose,
+ [KeyPress] = keypress,
+ [KeymapNotify] = keymapnotify,
+ [MapRequest] = maprequest,
+ [PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify
+};
+
+unsigned int
+flush_masked_events(long even_mask)
+{
+ XEvent ev;
+ unsigned int n = 0;
+ while(XCheckMaskEvent(dpy, even_mask, &ev)) n++;
+ return n;
+}
+
+static void
+configurerequest(XEvent *e)
+{
+#if 0
+ XConfigureRequestEvent *ev = &e->xconfigurerequest;
+ XWindowChanges wc;
+ XRectangle *frect;
+ Client *c;
+
+ c = client_of_win(ev->window);
+ ev->value_mask &= ~CWSibling;
+ if(c) {
+ gravitate_client(c, True);
+
+ if(ev->value_mask & CWX)
+ c->rect.x = ev->x;
+ if(ev->value_mask & CWY)
+ c->rect.y = ev->y;
+ if(ev->value_mask & CWWidth)
+ c->rect.width = ev->width;
+ if(ev->value_mask & CWHeight)
+ c->rect.height = ev->height;
+ if(ev->value_mask & CWBorderWidth)
+ c->border = ev->border_width;
+
+ gravitate_client(c, False);
+
+ if(c->frame) {
+ if(c->sel->area->floating)
+ frect=&c->sel->rect;
+ else
+ frect=&c->sel->revert;
+
+ if(c->rect.width >= screen->rect.width && c->rect.height >= screen->rect.height) {
+ frect->y = wc.y = -height_of_bar();
+ frect->x = wc.x = -def.border;
+ }
+ else {
+ frect->y = wc.y = c->rect.y - height_of_bar();
+ frect->x = wc.x = c->rect.x - def.border;
+ }
+ frect->width = wc.width = c->rect.width + 2 * def.border;
+ frect->height = wc.height = c->rect.height + def.border
+ + height_of_bar();
+ wc.border_width = 1;
+ wc.sibling = None;
+ wc.stack_mode = ev->detail;
+ if(c->sel->area->view != screen->sel)
+ wc.x += 2 * screen->rect.width;
+ if(c->sel->area->floating) {
+ XConfigureWindow(dpy, c->framewin, ev->value_mask, &wc);
+ configure_client(c);
+ }
+ }
+ }
+
+ wc.x = ev->x;
+ wc.y = ev->y;
+ wc.width = ev->width;
+ wc.height = ev->height;
+
+ if(c && c->frame) {
+ wc.x = def.border;
+ wc.y = height_of_bar();
+ wc.width = c->sel->rect.width - 2 * def.border;
+ wc.height = c->sel->rect.height - def.border - height_of_bar();
+ }
+
+ wc.border_width = 0;
+ wc.sibling = None;
+ wc.stack_mode = Above;
+ ev->value_mask &= ~CWStackMode;
+ ev->value_mask |= CWBorderWidth;
+ XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
+
+ XFlush(dpy);
+#endif
+}
+
+static void
+destroynotify(XEvent *e)
+{
+#if 0
+ Client *c;
+ XDestroyWindowEvent *ev = &e->xdestroywindow;
+
+ if((c = client_of_win(ev->window)))
+ destroy_client(c);
+#endif
+}
+
+static void
+enternotify(XEvent *e)
+{
+#if 0
+ XCrossingEvent *ev = &e->xcrossing;
+ Client *c;
+
+ if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
+ return;
+
+ if((c = client_of_win(ev->window))) {
+ Frame *f = c->sel;
+ Area *a = f->area;
+ if(a->mode == Colmax)
+ c = a->sel->client;
+ focus(c, False);
+ }
+ else if(ev->window == root) {
+ sel_screen = True;
+ draw_frames();
+ }
+#endif
+}
+
+static void
+leavenotify(XEvent *e)
+{
+ XCrossingEvent *ev = &e->xcrossing;
+
+ if((ev->window == root) && !ev->same_screen) {
+ sel_screen = True;
+ /*draw_frames();*/
+ }
+}
+
+static void
+expose(XEvent *e)
+{
+ XExposeEvent *ev = &e->xexpose;
+
+ if(ev->count == 0) {
+ if(ev->window == barwin)
+ draw_bar();
+ }
+}
+
+static void
+keypress(XEvent *e)
+{
+#if 0
+ XKeyEvent *ev = &e->xkey;
+ KeySym k = 0;
+ char buf[32];
+ int n;
+ static Frame *f;
+
+
+ ev->state &= valid_mask;
+ if((f = frame_of_win(ev->window))) {
+ buf[0] = 0;
+ n = XLookupString(ev, buf, sizeof(buf), &k, 0);
+ if(IsFunctionKey(k) || IsKeypadKey(k) || IsMiscFunctionKey(k)
+ || IsPFKey(k) || IsPrivateKeypadKey(k))
+ return;
+ buf[n] = 0;
+ blitz_kpress_input(&f->tagbar, ev->state, k, buf);
+ }
+ else
+ key(root, ev->state, (KeyCode) ev->keycode);
+#endif
+}
+
+static void
+keymapnotify(XEvent *e)
+{
+#if 0
+ update_keys();
+#endif
+}
+
+static void
+maprequest(XEvent *e)
+{
+#if 0
+ XMapRequestEvent *ev = &e->xmaprequest;
+ static XWindowAttributes wa;
+
+ if(!XGetWindowAttributes(dpy, ev->window, &wa))
+ return;
+
+ if(wa.override_redirect) {
+ XSelectInput(dpy, ev->window,
+ (StructureNotifyMask | PropertyChangeMask));
+ return;
+ }
+
+ if(!client_of_win(ev->window))
+ manage_client(create_client(ev->window, &wa));
+#endif
+}
+
+static void
+propertynotify(XEvent *e)
+{
+#if 0
+ XPropertyEvent *ev = &e->xproperty;
+ Client *c;
+
+ if(ev->state == PropertyDelete)
+ return; /* ignore */
+
+ if((c = client_of_win(ev->window)))
+ prop_client(c, ev);
+#endif
+}
+
+static void
+unmapnotify(XEvent *e)
+{
+#if 0
+ Client *c;
+ XUnmapEvent *ev = &e->xunmap;
+
+ if((c = client_of_win(ev->window)))
+ destroy_client(c);
+#endif
+}
diff --git a/menu.c b/menu.c
index b4e08d40..7c84305c 100644
--- a/menu.c
+++ b/menu.c
@@ -53,7 +53,7 @@ static const int seek = 30; /* 30px */
static Brush brush = {0};
-static void draw_menu(void);
+static void draw_menu();
static void kpress(XKeyEvent * e);
static char version[] = "gridmenu - " VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
@@ -397,11 +397,10 @@ main(int argc, char *argv[])
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
- wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask
- | SubstructureRedirectMask | SubstructureNotifyMask;
+ wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask;
rect.width = DisplayWidth(dpy, screen);
- rect.height = brush.font.height + 4;
+ rect.height = labelheight(&brush.font);
rect.y = DisplayHeight(dpy, screen) - rect.height;
rect.x = 0;
@@ -413,7 +412,7 @@ main(int argc, char *argv[])
XFlush(dpy);
/* pixmap */
- brush.gc = XCreateGC(dpy, win, 0, 0);
+ brush.gc = XCreateGC(dpy, root, 0, 0);
brush.drawable = XCreatePixmap(dpy, win, rect.width, rect.height,
DefaultDepth(dpy, screen));
XFlush(dpy);
diff --git a/util.c b/util.c
index 99842e9c..435069f9 100644
--- a/util.c
+++ b/util.c
@@ -7,6 +7,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "util.h"
void
error(char *errstr, ...) {
@@ -75,3 +80,21 @@ swap(void **p1, void **p2)
*p1 = *p2;
*p2 = tmp;
}
+
+void
+spawn(Display *dpy, const char *shell, const char *cmd)
+{
+ if(!cmd || !shell)
+ return;
+ if(fork() == 0) {
+ if(fork() == 0) {
+ if(dpy)
+ close(ConnectionNumber(dpy));
+ execl(shell, shell, "-c", cmd, (const char *)0);
+ fprintf(stderr, "gridwm: execl %s", shell);
+ perror(" failed");
+ }
+ exit (0);
+ }
+ wait(0);
+}
diff --git a/util.h b/util.h
index 8ba444b0..cac3df03 100644
--- a/util.h
+++ b/util.h
@@ -2,6 +2,7 @@
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
+#include <X11/Xlib.h>
extern void error(char *errstr, ...);
extern void *emallocz(unsigned int size);
@@ -12,5 +13,6 @@ extern char *estrdup(const char *str);
if(!(a)) \
failed_assert(#a, __FILE__, __LINE__); \
} while (0)
-void failed_assert(char *a, char *file, int line);
-void swap(void **p1, void **p2);
+extern void failed_assert(char *a, char *file, int line);
+extern void swap(void **p1, void **p2);
+extern void spawn(Display *dpy, const char *shell, const char *cmd);
diff --git a/wm.c b/wm.c
index c8bb0a4a..b8b30534 100644
--- a/wm.c
+++ b/wm.c
@@ -15,15 +15,15 @@
/* X structs */
Display *dpy;
-Window root;
-XRectangle rect;
-Pixmap pmap;
-Atom wm_atom[WMLast];
-Atom net_atom[NetLast];
+Window root, barwin;
+Atom wm_atom[WMLast], net_atom[NetLast];
Cursor cursor[CurLast];
+XRectangle rect, barrect;
+Bool running = True;
+char *bartext, *shell;
int screen, sel_screen;
-unsigned int kmask, numlock_mask;
+unsigned int lock_mask, numlock_mask;
/* draw structs */
Brush brush = {0};
@@ -166,7 +166,7 @@ init_lock_keys()
}
XFreeModifiermap(modmap);
- kmask = 255 & ~(numlock_mask | LockMask);
+ lock_mask = 255 & ~(numlock_mask | LockMask);
}
static void
@@ -187,6 +187,7 @@ main(int argc, char *argv[])
XSetWindowAttributes wa;
unsigned int mask;
Window w;
+ XEvent ev;
/* command line args */
for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
@@ -218,6 +219,9 @@ main(int argc, char *argv[])
if(other_wm_running)
error("gridwm: another window manager is already running\n");
+ if(!(shell = getenv("SHELL")))
+ shell = "/bin/sh";
+
rect.x = rect.y = 0;
rect.width = DisplayWidth(dpy, screen);
rect.height = DisplayHeight(dpy, screen);
@@ -244,19 +248,42 @@ main(int argc, char *argv[])
init_lock_keys();
- pmap = XCreatePixmap(dpy, root, rect.width, rect.height,
+ brush.drawable = XCreatePixmap(dpy, root, rect.width, rect.height,
DefaultDepth(dpy, screen));
-
- wa.event_mask = SubstructureRedirectMask | EnterWindowMask | LeaveWindowMask;
- wa.cursor = cursor[CurNormal];
- XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
+ brush.gc = XCreateGC(dpy, root, 0, 0);
/* style */
loadcolors(dpy, screen, &brush, BGCOLOR, FGCOLOR, BORDERCOLOR);
loadfont(dpy, &brush.font, FONT);
+ wa.override_redirect = 1;
+ wa.background_pixmap = ParentRelative;
+ wa.event_mask = ExposureMask;
+
+ barrect = rect;
+ barrect.height = labelheight(&brush.font);
+ barrect.y = rect.height - barrect.height;
+ barwin = XCreateWindow(dpy, root, barrect.x, barrect.y,
+ barrect.width, barrect.height, 0, DefaultDepth(dpy, screen),
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
+ bartext = 0;
+ XDefineCursor(dpy, barwin, cursor[CurNormal]);
+ XMapRaised(dpy, barwin);
+ draw_bar();
+
+ wa.event_mask = SubstructureRedirectMask | EnterWindowMask | LeaveWindowMask;
+ wa.cursor = cursor[CurNormal];
+ XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
+
scan_wins();
+ while(running) {
+ XNextEvent(dpy, &ev);
+ if(handler[ev.type])
+ (handler[ev.type]) (&ev); /* call handler */
+ }
+
cleanup();
XCloseDisplay(dpy);
diff --git a/wm.h b/wm.h
index 6bf0d5e4..038078ff 100644
--- a/wm.h
+++ b/wm.h
@@ -9,16 +9,14 @@
#include <X11/Xutil.h>
-/* WM atoms */
+/* atoms */
enum { WMState, WMProtocols, WMDelete, WMLast };
-
-/* NET atoms */
enum { NetSupported, NetWMName, NetLast };
-/* Cursor */
+/* cursor */
enum { CurNormal, CurResize, CurMove, CurInput, CurLast };
-/* Rects */
+/* rects */
enum { RFloat, RGrid, RLast };
typedef struct Client Client;
@@ -28,35 +26,45 @@ struct Client {
Tag *tag;
char name[256];
int proto;
+ unsigned int border;
+ Bool fixedsize;
Window win;
Window trans;
Window title;
- GC gc;
XSizeHints size;
XRectangle r[RLast];
Client *next;
- Client *tnext;
- Client *tprev;
+ Client *snext;
};
struct Tag {
char name[256];
- Client *clients;
- Client *sel;
+ Client *stack;
XRectangle r;
+ Tag *next;
+ Tag *cnext;
};
extern Display *dpy;
-extern Window root;
-extern XRectangle rect;
-extern Atom wm_atom[WMLast];
-extern Atom net_atom[NetLast];
+extern Window root, barwin;
+extern Atom wm_atom[WMLast], net_atom[NetLast];
extern Cursor cursor[CurLast];
-extern Pixmap pmap;
+extern XRectangle rect, barrect;
+extern Bool running;
+extern void (*handler[LASTEvent]) (XEvent *);
extern int screen, sel_screen;
-extern unsigned int kmask, numlock_mask;
+extern unsigned int lock_mask, numlock_mask;
+extern char *bartext, *shell;
extern Brush brush;
+/* bar.c */
+extern void draw_bar();
+
+/* client.c */
+extern Client *create_client(Window w, XWindowAttributes *wa);
+extern void manage(Client *c);
+
/* wm.c */
+extern int win_proto(Window w);