X-Git-Url: https://jasonwoof.com/gitweb/?p=dwm.git;a=blobdiff_plain;f=dwm.c;h=2d444424b1347b12a6f764f5ff701ac249600c33;hp=344966b85f4247f38922b363a8d66faa3219f936;hb=54c3044decc9848ba18c137dd3558dc8bdf71f34;hpb=90af1ced3c634683ec4c0e51c5f1e69461a9192a diff --git a/dwm.c b/dwm.c index 344966b..2d44442 100644 --- a/dwm.c +++ b/dwm.c @@ -43,7 +43,8 @@ /* macros */ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) -#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MAX(A, B) ((A) > (B) ? (A) : (B)) @@ -58,7 +59,8 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ enum { NetSupported, NetWMName, NetWMState, - NetWMFullscreen, NetActiveWindow, NetLast }; /* EWMH atoms */ + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ @@ -198,12 +200,13 @@ static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); static void monocle(Monitor *m); +static void motionnotify(XEvent *e); static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); static void pop(Client *); static void propertynotify(XEvent *e); -static Monitor *ptrtomon(int x, int y); static void quit(const Arg *arg); +static Monitor *recttomon(int x, int y, int w, int h); static void resize(Client *c, int x, int y, int w, int h, Bool interact); static void resizeclient(Client *c, int x, int y, int w, int h); static void resizemouse(const Arg *arg); @@ -214,6 +217,7 @@ static Bool sendevent(Client *c, Atom proto); static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); +static void setfullscreen(Client *c, Bool fullscreen); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); @@ -237,6 +241,7 @@ static void updatebars(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); +static void updatewindowtype(Client *c); static void updatetitle(Client *c); static void updatewmhints(Client *c); static void view(const Arg *arg); @@ -267,6 +272,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { [KeyPress] = keypress, [MappingNotify] = mappingnotify, [MapRequest] = maprequest, + [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, [UnmapNotify] = unmapnotify }; @@ -338,14 +344,14 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { *y = 0; } else { - if(*x > m->mx + m->mw) - *x = m->mx + m->mw - WIDTH(c); - if(*y > m->my + m->mh) - *y = m->my + m->mh - HEIGHT(c); - if(*x + *w + 2 * c->bw < m->mx) - *x = m->mx; - if(*y + *h + 2 * c->bw < m->my) - *y = m->my; + if(*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if(*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if(*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if(*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; } if(*h < bh) *h = bh; @@ -391,9 +397,10 @@ arrange(Monitor *m) { showhide(m->stack); else for(m = mons; m; m = m->next) showhide(m->stack); - if(m) + if(m) { arrangemon(m); - else for(m = mons; m; m = m->next) + restack(m); + } else for(m = mons; m; m = m->next) arrangemon(m); } @@ -402,7 +409,6 @@ arrangemon(Monitor *m) { strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); if(m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); - restack(m); } void @@ -529,31 +535,10 @@ clientmessage(XEvent *e) { if(!c) return; - if(cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen]) { - if(cme->data.l[0] && !c->isfullscreen) { - XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32, - PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); - c->isfullscreen = True; - c->oldstate = c->isfloating; - c->oldbw = c->bw; - c->bw = 0; - c->isfloating = True; - resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); - XRaiseWindow(dpy, c->win); - } - else { - XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32, - PropModeReplace, (unsigned char*)0, 0); - c->isfullscreen = False; - c->isfloating = c->oldstate; - c->bw = c->oldbw; - c->x = c->oldx; - c->y = c->oldy; - c->w = c->oldw; - c->h = c->oldh; - resizeclient(c, c->x, c->y, c->w, c->h); - arrange(c->mon); - } + if(cme->message_type == netatom[NetWMState]) { + if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); } else if(cme->message_type == netatom[NetActiveWindow]) { if(!ISVISIBLE(c)) { @@ -926,6 +911,21 @@ focusstack(const Arg *arg) { } } +Atom +getatomprop(Client *c, Atom prop) { + int di; + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; + + if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + XFree(p); + } + return atom; +} + unsigned long getcolor(const char *colstr) { Colormap cmap = DefaultColormap(dpy, screen); @@ -1131,27 +1131,22 @@ manage(Window w, XWindowAttributes *wa) { c->w = c->oldw = wa->width; c->h = c->oldh = wa->height; c->oldbw = wa->border_width; - if(c->w == c->mon->mw && c->h == c->mon->mh) { - c->isfloating = True; // regression with flash, XXXX - c->x = c->mon->mx; - c->y = c->mon->my; - c->bw = 0; - } - else { - if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw) - c->x = c->mon->mx + c->mon->mw - WIDTH(c); - if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh) - c->y = c->mon->my + c->mon->mh - HEIGHT(c); - c->x = MAX(c->x, c->mon->mx); - /* only fix client y-offset, if the client center might cover the bar */ - c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx) - && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); - c->bw = borderpx; - } + + if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + c->y = c->mon->my + c->mon->mh - HEIGHT(c); + c->x = MAX(c->x, c->mon->mx); + /* only fix client y-offset, if the client center might cover the bar */ + c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); XSetWindowBorder(dpy, w, dc.norm[ColBorder]); configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); updatesizehints(c); updatewmhints(c); XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); @@ -1209,6 +1204,22 @@ monocle(Monitor *m) { } void +motionnotify(XEvent *e) { + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if(ev->window != root) + return; + if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, True); + selmon = m; + focus(NULL); + } + mon = m; +} + +void movemouse(const Arg *arg) { int x, y, ocx, ocy, nx, ny; Client *c; @@ -1256,7 +1267,7 @@ movemouse(const Arg *arg) { } } while(ev.type != ButtonRelease); XUngrabPointer(dpy, CurrentTime); - if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { + if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { sendmon(c, m); selmon = m; focus(NULL); @@ -1308,24 +1319,29 @@ propertynotify(XEvent *e) { if(c == c->mon->sel) drawbar(c->mon); } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); } } -Monitor * -ptrtomon(int x, int y) { - Monitor *m; - - for(m = mons; m; m = m->next) - if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh)) - return m; - return selmon; -} - void quit(const Arg *arg) { running = False; } +Monitor * +recttomon(int x, int y, int w, int h) { + Monitor *m, *r = selmon; + int a, area = 0; + + for(m = mons; m; m = m->next) + if((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + void resize(Client *c, int x, int y, int w, int h, Bool interact) { if(applysizehints(c, &x, &y, &w, &h, interact)) @@ -1389,7 +1405,7 @@ resizemouse(const Arg *arg) { XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); XUngrabPointer(dpy, CurrentTime); while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); - if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { + if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { sendmon(c, m); selmon = m; focus(NULL); @@ -1511,6 +1527,34 @@ setfocus(Client *c) { } void +setfullscreen(Client *c, Bool fullscreen) { + if(fullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = True; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; + c->isfloating = True; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } + else { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = False; + c->isfloating = c->oldstate; + c->bw = c->oldbw; + c->x = c->oldx; + c->y = c->oldy; + c->w = c->oldw; + c->h = c->oldh; + resizeclient(c, c->x, c->y, c->w, c->h); + arrange(c->mon); + } +} + +void setlayout(const Arg *arg) { if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) selmon->sellt ^= 1; @@ -1562,6 +1606,8 @@ setup(void) { netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); /* init cursors */ cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); @@ -1586,9 +1632,8 @@ setup(void) { PropModeReplace, (unsigned char *) netatom, NetLast); /* select for events */ wa.cursor = cursor[CurNormal]; - wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask - |EnterWindowMask|LeaveWindowMask|StructureNotifyMask - |PropertyChangeMask; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask + |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); XSelectInput(dpy, root, wa.event_mask); grabkeys(); @@ -1783,6 +1828,8 @@ updatebars(void) { .event_mask = ButtonPressMask|ExposureMask }; for(m = mons; m; m = m->next) { + if (m->barwin) + continue; m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); @@ -1967,6 +2014,18 @@ updatestatus(void) { } void +updatewindowtype(Client *c) { + Atom state = getatomprop(c, netatom[NetWMState]); + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if(state == netatom[NetWMFullscreen]) + setfullscreen(c, True); + + if(wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = True; +} + +void updatewmhints(Client *c) { XWMHints *wmh; @@ -2015,7 +2074,7 @@ wintomon(Window w) { Monitor *m; if(w == root && getrootptr(&x, &y)) - return ptrtomon(x, y); + return recttomon(x, y, 1, 1); for(m = mons; m; m = m->next) if(w == m->barwin) return m; @@ -2073,7 +2132,7 @@ zoom(const Arg *arg) { int main(int argc, char *argv[]) { if(argc == 2 && !strcmp("-v", argv[1])) - die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n"); + die("dwm-"VERSION", © 2006-2012 dwm engineers, see LICENSE for details\n"); else if(argc != 1) die("usage: dwm [-v]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())