]> Pileus Git - wmpus/blobdiff - sys-x11.c
Get rid of undefine..
[wmpus] / sys-x11.c
index 3ea7ded09edfad989c40657e102b51d84499ae5b..2120ee07931b427dc4be43c6486655f3c0f73197 100644 (file)
--- a/sys-x11.c
+++ b/sys-x11.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Andy Spencer <andy753421@gmail.com>
+ * Copyright (c) 2011-2012, Andy Spencer <andy753421@gmail.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -40,7 +40,6 @@ struct win_sys {
        struct {
                int left, right, top, bottom;
        } strut;
-       state_t  state;
 };
 
 typedef struct {
@@ -49,7 +48,9 @@ typedef struct {
 } event_map_t;
 
 typedef enum {
-       WM_PROTO, WM_FOCUS, NET_STRUT, NATOMS
+       WM_PROTO, WM_FOCUS, WM_DELETE,
+       NET_STATE, NET_FULL, NET_STRUT,
+       NATOMS
 } atom_t;
 
 typedef enum {
@@ -63,6 +64,7 @@ static Atom atoms[NATOMS];
 static int (*xerrorxlib)(Display *, XErrorEvent *);
 static unsigned long colors[NCOLORS];
 static list_t *screens;
+static list_t *struts;
 
 /* Conversion functions */
 static event_map_t ev2sym[] = {
@@ -166,6 +168,10 @@ static int strut_copy(win_t *to, win_t *from, int scale)
        to->y += scale*(top       );
        to->w -= scale*(left+right);
        to->h -= scale*(top+bottom);
+       to->sys->strut.left   += scale*left;
+       to->sys->strut.right  += scale*right;
+       to->sys->strut.top    += scale*top;
+       to->sys->strut.bottom += scale*bottom;
        return 1;
 }
 
@@ -186,6 +192,7 @@ static int strut_add(win_t *root, win_t *win)
        win->sys->strut.right  = ((int*)xdata)[1];
        win->sys->strut.top    = ((int*)xdata)[2];
        win->sys->strut.bottom = ((int*)xdata)[3];
+       struts = list_insert(struts, win);
        for (list_t *cur = screens; cur; cur = cur->next)
                strut_copy(cur->data, win, 1);
        return strut_copy(root, win, 1);
@@ -193,6 +200,9 @@ static int strut_add(win_t *root, win_t *win)
 
 static int strut_del(win_t *root, win_t *win)
 {
+       list_t *lwin = list_find(struts, win);
+       if (lwin)
+               struts = list_remove(struts, lwin, 0);
        for (list_t *cur = screens; cur; cur = cur->next)
                strut_copy(cur->data, win, -1);
        return strut_copy(root, win, -1);
@@ -265,6 +275,52 @@ static int win_viewable(win_t *win)
                return True;
 }
 
+static int win_msg(win_t *win, atom_t msg)
+{
+       int n, found = 0;
+       Atom *protos;
+       if (!XGetWMProtocols(win->sys->dpy, win->sys->xid, &protos, &n))
+               return 0;
+
+       while (!found && n--)
+               found = protos[n] == atoms[msg];
+       XFree(protos);
+       if (!found)
+               return 0;
+
+       XSendEvent(win->sys->dpy, win->sys->xid, False, NoEventMask, &(XEvent){
+               .type                 = ClientMessage,
+               .xclient.window       = win->sys->xid,
+               .xclient.message_type = atoms[WM_PROTO],
+               .xclient.format       = 32,
+               .xclient.data.l[0]    = atoms[msg],
+               .xclient.data.l[1]    = CurrentTime,
+       });
+       return 1;
+}
+
+#if 0
+static int win_full(win_t *win)
+{
+       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
+
 /* Drawing functions */
 static unsigned long get_color(Display *dpy, const char *name)
 {
@@ -290,6 +346,7 @@ static void process_event(int type, XEvent *xe, win_t *root)
                Window xid = getfocus(root, xe);
                if (!(win = win_find(dpy,xid,0)))
                        return;
+               //printf("button-press %p\n", win);
                ptr = x2ptr(xe);
                mod = x2mod(xe->xkey.state, type==KeyRelease||type==ButtonRelease);
        }
@@ -305,17 +362,13 @@ static void process_event(int type, XEvent *xe, win_t *root)
                //printf("release: %d\n", type);
        }
        else if (type == ButtonPress) {
-               if (wm_handle_event(win, xb2ev(xe->xbutton.button), mod, ptr))
+               if (wm_handle_event(win, xb2ev(xe->xbutton.button), mod, ptr)) {
+                       //printf("grab pointer\n");
                        XGrabPointer(dpy, xe->xbutton.root, True, PointerMotionMask|ButtonReleaseMask,
                                        GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
-               else {
-                       printf("resending event\n");
-                       XSendEvent(win->sys->dpy, xe->xbutton.window,    True,  NoEventMask, xe);
-                       XSendEvent(win->sys->dpy, xe->xbutton.window,    False, NoEventMask, xe);
-                       XSendEvent(win->sys->dpy, xe->xbutton.root,      True,  NoEventMask, xe);
-                       XSendEvent(win->sys->dpy, xe->xbutton.root,      False, NoEventMask, xe);
-                       XSendEvent(win->sys->dpy, xe->xbutton.subwindow, True,  NoEventMask, xe);
-                       XSendEvent(win->sys->dpy, xe->xbutton.subwindow, False, NoEventMask, xe);
+               } else {
+                       //printf("allow events\n");
+                       XAllowEvents(win->sys->dpy, ReplayPointer, xe->xbutton.time);
                }
        }
        else if (type == ButtonRelease) {
@@ -327,8 +380,8 @@ static void process_event(int type, XEvent *xe, win_t *root)
                wm_handle_ptr(win, ptr);
        }
        else if (type == EnterNotify || type == LeaveNotify) {
-               printf("enter: %d\n", type);
-               event_t ev = EnterNotify ? EV_ENTER : EV_LEAVE;
+               printf("%s: %d\n", type==EnterNotify?"enter":"leave", type);
+               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());
        }
@@ -346,12 +399,12 @@ static void process_event(int type, XEvent *xe, win_t *root)
        }
        else if (type == UnmapNotify) {
                if ((win = win_find(dpy,xe->xunmap.window,0)) &&
-                    win->sys->state != ST_HIDE) {
+                    win->state != ST_HIDE) {
                        if (!strut_del(root, win))
                                wm_remove(win);
                        else
                                wm_update();
-                       win->sys->state = ST_HIDE;
+                       win->state = ST_HIDE;
                }
        }
        else if (type == DestroyNotify) {
@@ -364,27 +417,52 @@ static void process_event(int type, XEvent *xe, win_t *root)
                printf("configure_req: %d - %x, (0x%lx) %dx%d @ %d,%d\n",
                                type, (int)cre->window, cre->value_mask,
                                cre->height, cre->width, cre->x, cre->y);
-               XConfigureWindow(dpy, cre->window, cre->value_mask, &(XWindowChanges){
-                       .x      = cre->x,
-                       .y      = cre->y,
-                       .width  = cre->width,
-                       .height = cre->height,
-               });
-
-               /* This seems necessary for, but causes flicker
-                * there could be a better way to do this */
-               if ((win = win_find(dpy,xe->xmaprequest.window,0)))
-                       sys_move(win, win->x, win->y, win->w, win->h);
+               if ((win = win_find(dpy,xe->xconfigurerequest.window,1))) {
+                       XSendEvent(dpy, cre->window, False, StructureNotifyMask, &(XEvent){
+                               .xconfigure.type              = ConfigureNotify,
+                               .xconfigure.display           = win->sys->dpy,
+                               .xconfigure.event             = win->sys->xid,
+                               .xconfigure.window            = win->sys->xid,
+                               .xconfigure.x                 = win->x,
+                               .xconfigure.y                 = win->y,
+                               .xconfigure.width             = win->w,
+                               .xconfigure.height            = win->h,
+                               .xconfigure.border_width      = border,
+                       });
+                       XSync(win->sys->dpy, False);
+               }
        }
        else if (type == MapRequest) {
                printf("map_req: %d\n", type);
-               if ((win = win_find(dpy,xe->xmaprequest.window,1))) {
+               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();
                }
-               XMapWindow(dpy,xe->xmaprequest.window);
+               sys_show(win, ST_SHOW);
+       }
+       else if (type == ClientMessage) {
+               XClientMessageEvent *cme = &xe->xclient;
+               printf("msg: %d - %ld %ld,%ld,%ld,%ld,%ld\n",
+                               type, 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))     &&
+                   (cme->message_type == atoms[NET_STATE]) &&
+                   (cme->data.l[1] == atoms[NET_FULL] ||
+                    cme->data.l[2] == atoms[NET_FULL])) {
+                       state_t next = (cme->data.l[0] == 1 || /* _NET_WM_STATE_ADD    */
+                                      (cme->data.l[0] == 2 && /* _NET_WM_STATE_TOGGLE */
+                                       win->state != ST_FULL)) ? ST_FULL : ST_SHOW;
+                       wm_handle_state(win, win->state, next);
+                       sys_show(win, next);
+               }
+       }
+       else if (type == PropertyNotify) {
+               printf("prop: %d - %d\n", type, xe->xproperty.state);
        }
        else {
                printf("unknown event: %d\n", type);
@@ -403,9 +481,17 @@ static int xerror(Display *dpy, XErrorEvent *err)
            (err->request_code == X_GrabKey           && err->error_code == BadAccess  ) ||
            (err->request_code == X_CopyArea          && err->error_code == BadDrawable))
                return 0;
+       if (err->request_code == X_ChangeWindowAttributes && err->error_code == BadAccess)
+               error("Another window manager is already running");
        return xerrorxlib(dpy, err);
 }
 
+static int xnoerror(Display *dpy, XErrorEvent *err)
+{
+       return 0;
+}
+
+
 /********************
  * System functions *
  ********************/
@@ -430,60 +516,88 @@ void sys_raise(win_t *win)
 {
        //printf("sys_raise: %p\n", win);
        XRaiseWindow(win->sys->dpy, win->sys->xid);
+       for (list_t *cur = struts; cur; cur = cur->next)
+               XRaiseWindow(((win_t*)cur->data)->sys->dpy,
+                            ((win_t*)cur->data)->sys->xid);
 }
 
 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);
 
        /* 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);
        XSetWindowBorder(win->sys->dpy, win->sys->xid, colors[CLR_FOCUS]);
-       XSetWindowBorderWidth(win->sys->dpy, win->sys->xid, border);
        last = win;
-
-       /* Set actual focus */
-       XSetInputFocus(win->sys->dpy, win->sys->xid,
-                       RevertToPointerRoot, CurrentTime);
-       XSendEvent(win->sys->dpy, win->sys->xid, False, NoEventMask, &(XEvent){
-               .type                 = ClientMessage,
-               .xclient.window       = win->sys->xid,
-               .xclient.message_type = atoms[WM_PROTO],
-               .xclient.format       = 32,
-               .xclient.data.l[0]    = atoms[WM_FOCUS],
-               .xclient.data.l[1]    = CurrentTime,
-       });
 }
 
 void sys_show(win_t *win, state_t state)
 {
-       win->sys->state = 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\n");
+               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);
-               return;
+               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\n");
-               return;
+               printf("sys_show: full %p\n", win);
+               win_t *screen = NULL;
+               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;
+               }
+               XSetWindowBorderWidth(win->sys->dpy, win->sys->xid, 0);
+               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);
+               XRaiseWindow(win->sys->dpy, win->sys->xid);
+               break;
        case ST_SHADE:
-               printf("sys_show: shade\n");
-               return;
+               printf("sys_show: shade %p\n", win);
+               XMapWindow(win->sys->dpy, win->sys->xid);
+               break;
        case ST_ICON:
-               printf("sys_show: icon\n");
-               return;
-       case ST_HIDE:
-               printf("sys_show: hide\n");
-               XUnmapWindow(win->sys->dpy, win->sys->xid);
-               return;
+               printf("sys_show: icon %p\n", win);
+               break;
        case ST_CLOSE:
-               printf("sys_show: close\n");
+               printf("sys_show: close %p\n", win);
+               if (!win_msg(win, WM_DELETE)) {
+                       XGrabServer(win->sys->dpy);
+                       XSetErrorHandler(xnoerror);
+                       XSetCloseDownMode(win->sys->dpy, DestroyAll);
+                       XKillClient(win->sys->dpy, win->sys->xid);
+                       XSync(win->sys->dpy, False);
+                       XSetErrorHandler(xerror);
+                       XUngrabServer(win->sys->dpy);
+               }
                XDestroyWindow(win->sys->dpy, win->sys->xid);
-               return;
+               break;
        }
+       win->state = state;
 }
 
 void sys_watch(win_t *win, event_t ev, mod_t mod)
@@ -495,7 +609,7 @@ void sys_watch(win_t *win, event_t ev, mod_t mod)
        if (EV_MOUSE0 <= ev && ev <= EV_MOUSE7)
                XGrabButton(win->sys->dpy, ev2xb(ev), mod2x(mod), win->sys->xid, False,
                                mod.up ? ButtonReleaseMask : ButtonPressMask,
-                               GrabModeAsync, GrabModeAsync, None, None);
+                               GrabModeSync, GrabModeAsync, None, None);
        else if (ev == EV_ENTER)
                XSelectInput(win->sys->dpy, win->sys->xid, EnterWindowMask|mask);
        else if (ev == EV_LEAVE)
@@ -528,6 +642,7 @@ list_t *sys_info(win_t *win)
                        screen->y = info[i].y_org;
                        screen->w = info[i].width;
                        screen->h = info[i].height;
+                       screen->sys = new0(win_sys_t);
                        screens = list_append(screens, screen);
                }
        }
@@ -556,14 +671,17 @@ win_t *sys_init(void)
                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[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);
 
        colors[CLR_FOCUS]   = get_color(dpy, "#a0a0ff");
        colors[CLR_UNFOCUS] = get_color(dpy, "#101066");
        colors[CLR_URGENT]  = get_color(dpy, "#ff0000");
-       printf("colors = #%06lx #%06lx #%06lx\n", colors[0], colors[1], colors[2]);
+       //printf("colors = #%06lx #%06lx #%06lx\n", colors[0], colors[1], colors[2]);
 
        /* Select window management events */
        XSelectInput(dpy, xid, SubstructureRedirectMask|SubstructureNotifyMask);
@@ -608,7 +726,9 @@ void sys_exit(void)
 void sys_free(win_t *root)
 {
        XCloseDisplay(root->sys->dpy);
-       while (screens)
-               screens = list_remove(screens, screens, 1);
+       while (screens) {
+               win_free(screens->data);
+               screens = list_remove(screens, screens, 0);
+       }
        tdestroy(cache, (void(*)(void*))win_free);
 }