X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=sys-x11.c;h=4d88cf09bde123a129357f68b07642c8ab44fe5f;hb=d04ebe4c6b229aeb2bef9fa144e2eb4403a514b7;hp=a947e196747bf95ad765954e87126b3e04226611;hpb=7c451aa4d38c4658fa3eb1130b420380d081b40d;p=wmpus diff --git a/sys-x11.c b/sys-x11.c index a947e19..4d88cf0 100644 --- a/sys-x11.c +++ b/sys-x11.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Andy Spencer + * Copyright (c) 2011-2012, Andy Spencer * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,7 +49,9 @@ typedef struct { } event_map_t; typedef enum { - WM_PROTO, WM_FOCUS, NET_STRUT, NATOMS + WM_PROTO, WM_FOCUS, + NET_STATE, NET_FULL, NET_STRUT, + NATOMS } atom_t; typedef enum { @@ -167,6 +169,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; } @@ -270,6 +276,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) { @@ -295,6 +347,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); } @@ -310,17 +363,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) { @@ -332,8 +381,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()); } @@ -369,27 +418,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->xmaprequest.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))) { + XSelectInput(win->sys->dpy, win->sys->xid, PropertyChangeMask); if (!strut_add(root, win)) wm_insert(win); else wm_update(); } - XMapWindow(dpy,xe->xmaprequest.window); + XMapWindow(dpy, xe->xmaprequest.window); + } + 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])) { + if (cme->data.l[0] == 1 || /* _NET_WM_STATE_ADD */ + (cme->data.l[0] == 2 && /* _NET_WM_STATE_TOGGLE */ + win->sys->state != ST_FULL)) + sys_show(win, ST_FULL); + else + sys_show(win, ST_SHOW); + } + } + else if (type == PropertyNotify) { + printf("prop: %d - %d\n", type, xe->xproperty.state); } else { printf("unknown event: %d\n", type); @@ -408,6 +482,8 @@ 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); } @@ -442,56 +518,69 @@ void sys_raise(win_t *win) 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; + /* Restore from fullscreen */ switch (state) { case ST_SHOW: printf("sys_show: show\n"); + if (win->sys->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_FULL: printf("sys_show: full\n"); - return; + 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; + XMapWindow(win->sys->dpy, win->sys->xid); + break; case ST_ICON: printf("sys_show: icon\n"); - return; + break; case ST_HIDE: printf("sys_show: hide\n"); XUnmapWindow(win->sys->dpy, win->sys->xid); - return; + break; case ST_CLOSE: printf("sys_show: close\n"); XDestroyWindow(win->sys->dpy, win->sys->xid); - return; + break; } + win->sys->state = state; } void sys_watch(win_t *win, event_t ev, mod_t mod) @@ -503,7 +592,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) @@ -536,6 +625,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); } } @@ -566,12 +656,14 @@ win_t *sys_init(void) /* Setup X11 data */ atoms[WM_PROTO] = XInternAtom(dpy, "WM_PROTOCOLS", False); atoms[WM_FOCUS] = XInternAtom(dpy, "WM_TAKE_FOCUS", 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); @@ -616,7 +708,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); }