struct {
int left, right, top, bottom;
} strut;
- state_t state;
};
typedef struct {
} event_map_t;
typedef enum {
- WM_PROTO, WM_FOCUS,
+ WM_PROTO, WM_FOCUS, WM_DELETE,
NET_STATE, NET_FULL, NET_STRUT,
+ NET_TYPE, NET_DIALOG,
NATOMS
} atom_t;
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);
return strut_copy(root, win, -1);
}
-#if 0
-static int is_fullscreen(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
-
/* 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)
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",
+ if (win_prop(win, NET_TYPE) == atoms[NET_DIALOG])
+ win->type = TYPE_DIALOG;
+ if (XGetTransientForHint(dpy, xid, &trans))
+ win->parent = win_find(dpy, trans, 0);
+ printf("win_new: %p = %p, %d (%d,%d %dx%d) - %s\n",
win, dpy, (int)xid,
- win->x, win->y, win->w, win->h);
+ win->x, win->y, win->w, win->h,
+ win->type ? "dialog" : "normal");
return 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;
+}
+
+static Atom win_prop(win_t *win, atom_t prop)
+{
+ 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)
{
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);
}
/* Split based on event */
if (type == KeyPress) {
while (XCheckTypedEvent(dpy, KeyPress, xe));
- KeySym sym = XKeycodeToKeysym(dpy, xe->xkey.keycode, 0);
+ KeySym sym = XLookupKeysym(&xe->xkey, 0);
printf("got xe %c %hhx\n", xk2ev(sym), mod2int(mod));
wm_handle_event(win, xk2ev(sym), mod, ptr);
}
//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
- XAllowEvents(win->sys->dpy, ReplayPointer, CurrentTime);
+ } else {
+ //printf("allow events\n");
+ XAllowEvents(win->sys->dpy, ReplayPointer, xe->xbutton.time);
+ }
}
else if (type == ButtonRelease) {
XUngrabPointer(dpy, CurrentTime);
}
else if (type == EnterNotify || type == LeaveNotify) {
printf("%s: %d\n", type==EnterNotify?"enter":"leave", type);
- event_t ev = EnterNotify ? EV_ENTER : EV_LEAVE;
+ 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 == 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) {
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);
- if ((win = win_find(dpy,xe->xmaprequest.window,1))) {
+ if ((win = win_find(dpy,xe->xconfigurerequest.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))) {
+ if ((win = win_find(dpy,xe->xmaprequest.window,1)) &&
+ win->state == ST_HIDE) {
+ win->state = ST_SHOW;
+ if (win_prop(win, NET_STATE) == atoms[NET_FULL])
+ win->state = ST_FULL;
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, win->state);
}
else if (type == ClientMessage) {
- printf("msg: %d\n", type);
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);
+ 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\n", type);
+ printf("prop: %d - %d\n", type, xe->xproperty.state);
}
else {
printf("unknown event: %d\n", type);
return xerrorxlib(dpy, err);
}
+static int xnoerror(Display *dpy, XErrorEvent *err)
+{
+ return 0;
+}
+
+
/********************
* System functions *
********************/
/* 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,
- });
+ win_msg(win, WM_FOCUS);
/* Set border on focused window */
static win_t *last = NULL;
void sys_show(win_t *win, state_t state)
{
- /* Restore from fullscreen */
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");
- if (win->sys->state == ST_FULL)
+ 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\n");
+ printf("sys_show: full %p\n", win);
win_t *screen = NULL;
for (list_t *cur = screens; cur; cur = cur->next) {
screen = cur->data;
XRaiseWindow(win->sys->dpy, win->sys->xid);
break;
case ST_SHADE:
- printf("sys_show: shade\n");
+ printf("sys_show: shade %p\n", win);
XMapWindow(win->sys->dpy, win->sys->xid);
break;
case ST_ICON:
- printf("sys_show: icon\n");
- break;
- case ST_HIDE:
- printf("sys_show: hide\n");
- XUnmapWindow(win->sys->dpy, win->sys->xid);
+ 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);
break;
}
- win->sys->state = state;
+ win->state = state;
}
void sys_watch(win_t *win, event_t ev, mod_t mod)
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_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");