/* Configuration */
static int border = 2;
static int no_capture = 0;
+static int stack = 25;
/* Internal structures */
struct win_sys {
typedef enum {
WM_PROTO, WM_FOCUS, WM_DELETE,
NET_STATE, NET_FULL, NET_STRUT,
+ NET_TYPE, NET_DIALOG,
NATOMS
} atom_t;
} color_t;
/* Global data */
+static win_t *root;
+static win_t *last;
static int running;
static void *cache;
static Atom atoms[NATOMS];
static list_t *screens;
static list_t *struts;
+/* Debug functions */
+static char *state_map[] = {
+ [ST_HIDE ] "hide ",
+ [ST_SHOW ] "show ",
+ [ST_FULL ] "full ",
+ [ST_MAX ] "max ",
+ [ST_SHADE] "shade",
+ [ST_ICON ] "icon ",
+ [ST_CLOSE] "close",
+};
+
/* Conversion functions */
static event_map_t ev2sym[] = {
{EV_LEFT , XK_Left },
if (status != Success || ret_size != 32 || ret_items != 4)
return 0;
- win->sys->strut.left = ((int*)xdata)[0];
- win->sys->strut.right = ((int*)xdata)[1];
- win->sys->strut.top = ((int*)xdata)[2];
- win->sys->strut.bottom = ((int*)xdata)[3];
+ win->sys->strut.left = ((long*)xdata)[0];
+ win->sys->strut.right = ((long*)xdata)[1];
+ win->sys->strut.top = ((long*)xdata)[2];
+ win->sys->strut.bottom = ((long*)xdata)[3];
struts = list_insert(struts, win);
for (list_t *cur = screens; cur; cur = cur->next)
strut_copy(cur->data, win, 1);
}
/* Window functions */
+static Atom win_prop(win_t *win, atom_t prop);
+static win_t *win_find(Display *dpy, Window xid, int create);
+
static win_t *win_new(Display *dpy, Window xid)
{
+ Window trans;
XWindowAttributes attr;
if (XGetWindowAttributes(dpy, xid, &attr))
if (attr.override_redirect)
return NULL;
+
win_t *win = new0(win_t);
win->x = attr.x;
win->y = attr.y;
win->sys = new0(win_sys_t);
win->sys->dpy = dpy;
win->sys->xid = xid;
- printf("win_new: %p = %p, %d (%d,%d %dx%d)\n",
- win, dpy, (int)xid,
- win->x, win->y, win->w, win->h);
+
+ if (root) {
+ if (strut_add(root, win))
+ win->type = TYPE_TOOLBAR;
+
+ if (win_prop(win, NET_TYPE) == atoms[NET_DIALOG])
+ win->type = TYPE_DIALOG;
+
+ if (win_prop(win, NET_STATE) == atoms[NET_FULL])
+ win->state = ST_FULL;
+
+ if (XGetTransientForHint(dpy, xid, &trans))
+ win->parent = win_find(dpy, trans, 0);
+
+ XSelectInput(dpy, xid, PropertyChangeMask);
+ }
+
+ printf("win_new: win=%p x11=(%p,%d) state=%x pos=(%d,%d %dx%d) type=%s\n",
+ win, dpy, (int)xid, win->state,
+ win->x, win->y, win->w, win->h,
+ win->type == TYPE_NORMAL ? "normal" :
+ win->type == TYPE_DIALOG ? "dialog" :
+ win->type == TYPE_TOOLBAR ? "toolbar" : "unknown");
+
+ if (root)
+ wm_insert(win);
+
return win;
}
static void win_free(win_t *win)
{
+ if (win == last)
+ last = NULL;
free(win->sys);
free(win);
}
static void win_remove(win_t *win)
{
+ if (win != root) {
+ strut_del(root, win);
+ wm_remove(win);
+ }
tdelete(win, &cache, win_cmp);
win_free(win);
}
-static int win_viewable(win_t *win)
+static int win_viewable(Display *dpy, Window xid)
{
XWindowAttributes attr;
- if (XGetWindowAttributes(win->sys->dpy, win->sys->xid, &attr))
+ if (XGetWindowAttributes(dpy, xid, &attr))
return attr.map_state == IsViewable;
else
return True;
return 0;
XSendEvent(win->sys->dpy, win->sys->xid, False, NoEventMask, &(XEvent){
- .type = ClientMessage,
+ .xclient.type = ClientMessage,
.xclient.window = win->sys->xid,
.xclient.message_type = atoms[WM_PROTO],
.xclient.format = 32,
return 1;
}
-#if 0
-static int win_full(win_t *win)
+static Atom win_prop(win_t *win, atom_t prop)
{
- Atom ret_type;
- int ret_size;
- unsigned long ret_items, bytes_left;
- unsigned char *xdata;
- int status = XGetWindowProperty(win->sys->dpy, win->sys->xid,
- atoms[NET_FULL], 0L, 1L, False, XA_ATOM,
- &ret_type, &ret_size, &ret_items, &bytes_left, &xdata);
- printf("is_fullscreen:\n");
- printf("\t%d\n", status);
- printf("\t%d\n", ret_size);
- printf("\t%ld\n", ret_items);
- printf("\t%p\n", xdata);
- if (xdata)
- printf("\t%d\n", xdata[0]);
- return status == Success && ret_size == 32 && ret_items == 1 &&
- xdata[0] == atoms[NET_FULL];
-}
-#endif
+ int format;
+ unsigned long nitems, bytes;
+ unsigned char *buf = NULL;
+ Atom atom, type = XA_ATOM;
+ if (XGetWindowProperty(win->sys->dpy, win->sys->xid, atoms[prop],
+ 0L, sizeof(Atom), False, type, &type, &format, &nitems, &bytes, &buf) || !buf)
+ return 0;
+ atom = *(Atom *)buf;
+ XFree(buf);
+ return atom;
+}
/* Drawing functions */
static unsigned long get_color(Display *dpy, const char *name)
/* Split based on event */
if (type == KeyPress) {
while (XCheckTypedEvent(dpy, KeyPress, xe));
- KeySym sym = XKeycodeToKeysym(dpy, xe->xkey.keycode, 0);
- printf("got xe %c %hhx\n", xk2ev(sym), mod2int(mod));
+ KeySym sym = XLookupKeysym(&xe->xkey, 0);
+ //printf("got xe %c %hhx\n", xk2ev(sym), mod2int(mod));
wm_handle_event(win, xk2ev(sym), mod, ptr);
}
else if (type == KeyRelease) {
- //printf("release: %d\n", type);
+ //printf("release: %lx\n", xe->xkey.window);
}
else if (type == ButtonPress) {
if (wm_handle_event(win, xb2ev(xe->xbutton.button), mod, ptr)) {
wm_handle_ptr(win, ptr);
}
else if (type == EnterNotify || type == LeaveNotify) {
- printf("%s: %d\n", type==EnterNotify?"enter":"leave", type);
+ printf("%s: %lx\n", type==EnterNotify?"enter":"leave",
+ xe->xcrossing.window);
event_t ev = type == EnterNotify ? EV_ENTER : EV_LEAVE;
if ((win = win_find(dpy,xe->xcrossing.window,0)))
wm_handle_event(win, ev, MOD(), PTR());
}
else if (type == FocusIn || type == FocusOut) {
- //printf("focus: %d\n", type);
- event_t ev = FocusIn ? EV_FOCUS : EV_UNFOCUS;
+ //printf("focus: %lx\n", xe->xfocus.window);
+ event_t ev = type == FocusIn ? EV_FOCUS : EV_UNFOCUS;
if ((win = win_find(dpy,xe->xfocus.window,0)))
wm_handle_event(win, ev, MOD(), PTR());
}
else if (type == ConfigureNotify) {
- printf("configure: %d\n", type);
+ //printf("configure: %lx\n", xe->xconfigure.window);
}
else if (type == MapNotify) {
- printf("map: %d\n", type);
+ printf("map: %lx\n", xe->xmap.window);
}
else if (type == UnmapNotify) {
if ((win = win_find(dpy,xe->xunmap.window,0)) &&
win->state != ST_HIDE) {
- if (!strut_del(root, win))
- wm_remove(win);
- else
- wm_update();
+ printf("unmap: %lx\n", xe->xunmap.window);
+ wm_handle_state(win, win->state, ST_HIDE);
win->state = ST_HIDE;
}
}
else if (type == DestroyNotify) {
- //printf("destroy: %d\n", type);
+ printf("destroy: %lx\n", xe->xdestroywindow.window);
if ((win = win_find(dpy,xe->xdestroywindow.window,0)))
win_remove(win);
}
else if (type == ConfigureRequest) {
XConfigureRequestEvent *cre = &xe->xconfigurerequest;
- printf("configure_req: %d - %x, (0x%lx) %dx%d @ %d,%d\n",
- type, (int)cre->window, cre->value_mask,
+ printf("configure_req: %lx - (0x%lx) %dx%d @ %d,%d\n",
+ cre->window, cre->value_mask,
cre->height, cre->width, cre->x, cre->y);
- if ((win = win_find(dpy,xe->xconfigurerequest.window,1))) {
+ if ((win = win_find(dpy,cre->window,1))) {
XSendEvent(dpy, cre->window, False, StructureNotifyMask, &(XEvent){
.xconfigure.type = ConfigureNotify,
.xconfigure.display = win->sys->dpy,
}
}
else if (type == MapRequest) {
- printf("map_req: %d\n", type);
- if ((win = win_find(dpy,xe->xmaprequest.window,1)) &&
- win->state == ST_HIDE) {
- XSelectInput(win->sys->dpy, win->sys->xid, PropertyChangeMask);
- if (!strut_add(root, win))
- wm_insert(win);
- else
- wm_update();
+ printf("map_req: %lx\n", xe->xmaprequest.window);
+ win = win_find(dpy,xe->xmaprequest.window,1);
+ // fixme, for hide -> max, etc
+ if (win->state == ST_HIDE) {
+ wm_handle_state(win, win->state, ST_SHOW);
+ win->state = ST_SHOW;
}
- sys_show(win, ST_SHOW);
+ sys_show(win, win->state);
}
else if (type == ClientMessage) {
XClientMessageEvent *cme = &xe->xclient;
- printf("msg: %d - %ld %ld,%ld,%ld,%ld,%ld\n",
- type, cme->message_type,
+ printf("client_msg: %lx - %ld %ld,%ld,%ld,%ld,%ld\n",
+ cme->window, cme->message_type,
cme->data.l[0], cme->data.l[1], cme->data.l[2],
cme->data.l[3], cme->data.l[4]);
if ((win = win_find(dpy,cme->window,0)) &&
}
}
else if (type == PropertyNotify) {
- printf("prop: %d - %d\n", type, xe->xproperty.state);
+ printf("prop: %lx - %d\n", xe->xproperty.window, xe->xproperty.state);
}
else {
printf("unknown event: %d\n", type);
win->x = x; win->y = y;
win->w = MAX(w,1+b); win->h = MAX(h,1+b);
w = MAX(w-b,1); h = MAX(h-b,1);
+ XConfigureWindow(win->sys->dpy, win->sys->xid, CWX|CWY|CWWidth|CWHeight,
+ &(XWindowChanges) { .x=x, .y=y, .width=w, .height=h });
XMoveResizeWindow(win->sys->dpy, win->sys->xid, x, y, w, h);
/* Flush events, so moving window doesn't cause re-focus
void sys_focus(win_t *win)
{
- printf("sys_focus: %p\n", win);
+ //printf("sys_focus: %p\n", win);
/* Set actual focus */
XSetInputFocus(win->sys->dpy, win->sys->xid,
RevertToPointerRoot, CurrentTime);
- win_msg(win, WM_FOCUS);
+ //win_msg(win, WM_FOCUS);
/* Set border on focused window */
- static win_t *last = NULL;
if (last)
XSetWindowBorder(last->sys->dpy, last->sys->xid, colors[CLR_UNFOCUS]);
XSync(win->sys->dpy, False);
void sys_show(win_t *win, state_t state)
{
- switch (state) {
- case ST_HIDE:
- printf("sys_show: hide %p\n", win);
- XUnmapWindow(win->sys->dpy, win->sys->xid);
- break;
- case ST_SHOW:
- printf("sys_show: show %p\n", win);
- if (win->state == ST_FULL)
- sys_move(win, win->x, win->y, win->w, win->h);
- XSetWindowBorderWidth(win->sys->dpy, win->sys->xid, border);
- XMapWindow(win->sys->dpy, win->sys->xid);
- XSync(win->sys->dpy, False);
- break;
- case ST_MAX:
- printf("sys_show: max %p\n", win);
- XMapWindow(win->sys->dpy, win->sys->xid);
- break;
- case ST_FULL:
- printf("sys_show: full %p\n", win);
- win_t *screen = NULL;
+ //if (win->state == state)
+ // return;
+
+ /* Debug */
+ printf("sys_show: %p: %s -> %s\n", win,
+ state_map[win->state], state_map[state]);
+
+ /* Find screen */
+ win_t *screen = NULL;
+ if (state == ST_FULL || state == ST_MAX) {
for (list_t *cur = screens; cur; cur = cur->next) {
screen = cur->data;
if (win->x >= screen->x && win->x <= screen->x+screen->w &&
win->y >= screen->y && win->y <= screen->y+screen->h)
break;
}
+ }
+
+ /* Update properties */
+ if (state == ST_FULL)
+ XChangeProperty(win->sys->dpy, win->sys->xid, atoms[NET_STATE], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)&atoms[NET_FULL], 1);
+ else if (state != ST_FULL)
+ XChangeProperty(win->sys->dpy, win->sys->xid, atoms[NET_STATE], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)0, 0);
+
+ /* Update border */
+ if (state == ST_SHOW || state == ST_MAX || state == ST_SHADE)
+ XSetWindowBorderWidth(win->sys->dpy, win->sys->xid, border);
+ else if (state == ST_FULL)
XSetWindowBorderWidth(win->sys->dpy, win->sys->xid, 0);
+
+ /* Map/Unmap window */
+ if (state == ST_SHOW || state == ST_FULL || state == ST_MAX || state == ST_SHADE)
XMapWindow(win->sys->dpy, win->sys->xid);
- XMoveResizeWindow(win->sys->dpy, win->sys->xid,
- screen->x - screen->sys->strut.left,
- screen->y - screen->sys->strut.top,
- screen->w + screen->sys->strut.left + screen->sys->strut.right,
- screen->h + screen->sys->strut.top + screen->sys->strut.bottom);
+ else if (state == ST_HIDE)
+ XUnmapWindow(win->sys->dpy, win->sys->xid);
+
+ /* Resize windows */
+ if (state == ST_SHOW) {
+ sys_move(win, win->x, win->y, win->w, win->h);
+ } else if (state == ST_MAX) {
+ sys_move(win, screen->x, screen->y, screen->w, screen->h);
+ } else if (state == ST_FULL) {
+ XWindowChanges wc = {
+ .x = screen->x - screen->sys->strut.left ,
+ .y = screen->y - screen->sys->strut.top ,
+ .width = screen->w + screen->sys->strut.left + screen->sys->strut.right,
+ .height = screen->h + screen->sys->strut.top + screen->sys->strut.bottom
+ };
+ win->x = wc.x; win->y = wc.y;
+ win->w = wc.width; win->h = wc.height;
+ XConfigureWindow(win->sys->dpy, win->sys->xid, CWX|CWY|CWWidth|CWHeight, &wc);
+ XMoveResizeWindow(win->sys->dpy, win->sys->xid, wc.x, wc.y, wc.width, wc.height);
+ } else if (state == ST_SHADE) {
+ XConfigureWindow(win->sys->dpy, win->sys->xid, CWHeight,
+ &(XWindowChanges) { .height = stack });
+ }
+
+ /* Raise window */
+ if (state == ST_FULL || state == ST_MAX)
XRaiseWindow(win->sys->dpy, win->sys->xid);
- break;
- case ST_SHADE:
- printf("sys_show: shade %p\n", win);
- XMapWindow(win->sys->dpy, win->sys->xid);
- break;
- case ST_ICON:
- printf("sys_show: icon %p\n", win);
- break;
- case ST_CLOSE:
- printf("sys_show: close %p\n", win);
+
+ /* Close windows */
+ if (state == ST_CLOSE) {
if (!win_msg(win, WM_DELETE)) {
XGrabServer(win->sys->dpy);
XSetErrorHandler(xnoerror);
XSetErrorHandler(xerror);
XUngrabServer(win->sys->dpy);
}
- XDestroyWindow(win->sys->dpy, win->sys->xid);
- break;
}
+
+ /* Update state */
win->state = state;
}
Window xid;
/* Load configuration */
+ stack = conf_get_int("main.stack", stack);
border = conf_get_int("main.border", border);
no_capture = conf_get_int("main.no-capture", no_capture);
error("Unable to get root window");
/* Setup X11 data */
- atoms[WM_PROTO] = XInternAtom(dpy, "WM_PROTOCOLS", False);
- atoms[WM_FOCUS] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
- atoms[WM_DELETE] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
- atoms[NET_STATE] = XInternAtom(dpy, "_NET_WM_STATE", False);
- atoms[NET_FULL] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
- atoms[NET_STRUT] = XInternAtom(dpy, "_NET_WM_STRUT", False);
+ atoms[WM_PROTO] = XInternAtom(dpy, "WM_PROTOCOLS", False);
+ atoms[WM_FOCUS] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ atoms[WM_DELETE] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+ atoms[NET_STATE] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ atoms[NET_FULL] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ atoms[NET_STRUT] = XInternAtom(dpy, "_NET_WM_STRUT", False);
+ atoms[NET_TYPE] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+ atoms[NET_DIALOG] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
colors[CLR_FOCUS] = get_color(dpy, "#a0a0ff");
colors[CLR_UNFOCUS] = get_color(dpy, "#101066");
XSelectInput(dpy, xid, SubstructureRedirectMask|SubstructureNotifyMask);
xerrorxlib = XSetErrorHandler(xerror);
- return win_find(dpy, xid, 1);
+ return root = win_find(dpy, xid, 1);
}
void sys_run(win_t *root)
Window par, xid, *kids = NULL;
if (XQueryTree(root->sys->dpy, root->sys->xid,
&par, &xid, &kids, &nkids)) {
- for(int i = 0; i < nkids; i++) {
- win_t *win = win_find(root->sys->dpy, kids[i], 1);
- if (win && win_viewable(win) && !strut_add(root,win))
- wm_insert(win);
- }
+ for(int i = 0; i < nkids; i++)
+ if (win_viewable(root->sys->dpy, kids[i]))
+ win_find(root->sys->dpy, kids[i], 1);
XFree(kids);
}
- wm_update(); // For struts
}
/* Main loop */