Xinqi Bao's Git
e7804dc389796f195c306db8ef96e32acbc3ae36
   1 /* See LICENSE file for copyright and license details. 
   3  * dynamic window manager is designed like any other X client as well. It is 
   4  * driven through handling X events. In contrast to other X clients, a window 
   5  * manager selects for SubstructureRedirectMask on the root window, to receive 
   6  * events about window (dis-)appearance.  Only one X connection at a time is 
   7  * allowed to select for this event mask. 
   9  * Calls to fetch an X event from the event queue are blocking.  Due reading 
  10  * status text from standard input, a select()-driven main loop has been 
  11  * implemented which selects for reads on the X connection and STDIN_FILENO to 
  12  * handle all data smoothly. The event handlers of dwm are organized in an 
  13  * array which is accessed whenever a new event has been fetched. This allows 
  14  * event dispatching in O(1) time. 
  16  * Each child of the root window is called a client, except windows which have 
  17  * set the override_redirect flag.  Clients are organized in a global 
  18  * doubly-linked client list, the focus history is remembered through a global 
  19  * stack list. Each client contains a bit array to indicate the tags of a 
  22  * Keys and tagging rules are organized as arrays and defined in config.h. 
  24  * To understand everything else, start reading main(). 
  33 #include <sys/select.h> 
  34 #include <sys/types.h> 
  36 #include <X11/cursorfont.h> 
  37 #include <X11/keysym.h> 
  38 #include <X11/Xatom.h> 
  40 #include <X11/Xproto.h> 
  41 #include <X11/Xutil.h> 
  43 #include <X11/extensions/Xinerama.h> 
  47 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask) 
  48 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask)) 
  49 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) 
  50 #define ISVISIBLE(x)            (x->tags & tagset[seltags]) 
  51 #define LENGTH(x)               (sizeof x / sizeof x[0]) 
  52 #define MAX(a, b)               ((a) > (b) ? (a) : (b)) 
  53 #define MIN(a, b)               ((a) < (b) ? (a) : (b)) 
  55 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask) 
  56 #define NOBORDER(x)             ((x) - 2 * c->bw) 
  57 #define TAGMASK                 ((int)((1LL << LENGTH(tags)) - 1)) 
  58 #define TEXTW(x)                (textnw(x, strlen(x)) + dc.font.height) 
  61 enum { CurNormal
, CurResize
, CurMove
, CurLast 
};        /* cursor */ 
  62 enum { ColBorder
, ColFG
, ColBG
, ColLast 
};              /* color */ 
  63 enum { NetSupported
, NetWMName
, NetLast 
};              /* EWMH atoms */ 
  64 enum { WMProtocols
, WMDelete
, WMState
, WMLast 
};        /* default atoms */ 
  65 enum { ClkTagBar
, ClkLtSymbol
, ClkStatusText
, ClkWinTitle
, 
  66        ClkClientWin
, ClkRootWin
, ClkLast 
};             /* clicks */ 
  79         void (*func
)(const Arg 
*arg
); 
  83 typedef struct Client Client
; 
  88         int basew
, baseh
, incw
, inch
, maxw
, maxh
, minw
, minh
; 
  91         Bool isfixed
, isfloating
, isurgent
; 
  99         unsigned long norm
[ColLast
]; 
 100         unsigned long sel
[ColLast
]; 
 110 } DC
; /* draw context */ 
 115         void (*func
)(const Arg 
*); 
 121         void (*arrange
)(void); 
 126         const char *instance
; 
 132 /* function declarations */ 
 133 static void applyrules(Client 
*c
); 
 134 static void arrange(void); 
 135 static void attach(Client 
*c
); 
 136 static void attachstack(Client 
*c
); 
 137 static void buttonpress(XEvent 
*e
); 
 138 static void checkotherwm(void); 
 139 static void cleanup(void); 
 140 static void clearurgent(void); 
 141 static void configure(Client 
*c
); 
 142 static void configurenotify(XEvent 
*e
); 
 143 static void configurerequest(XEvent 
*e
); 
 144 static void destroynotify(XEvent 
*e
); 
 145 static void detach(Client 
*c
); 
 146 static void detachstack(Client 
*c
); 
 147 static void die(const char *errstr
, ...); 
 148 static void drawbar(void); 
 149 static void drawsquare(Bool filled
, Bool empty
, Bool invert
, unsigned long col
[ColLast
]); 
 150 static void drawtext(const char *text
, unsigned long col
[ColLast
], Bool invert
); 
 151 static void enternotify(XEvent 
*e
); 
 152 static void expose(XEvent 
*e
); 
 153 static void focus(Client 
*c
); 
 154 static void focusin(XEvent 
*e
); 
 155 static void focusstack(const Arg 
*arg
); 
 156 static Client 
*getclient(Window w
); 
 157 static unsigned long getcolor(const char *colstr
); 
 158 static long getstate(Window w
); 
 159 static Bool 
gettextprop(Window w
, Atom atom
, char *text
, unsigned int size
); 
 160 static void grabbuttons(Client 
*c
, Bool focused
); 
 161 static void grabkeys(void); 
 162 static void initfont(const char *fontstr
); 
 163 static Bool 
isprotodel(Client 
*c
); 
 164 static void keypress(XEvent 
*e
); 
 165 static void killclient(const Arg 
*arg
); 
 166 static void manage(Window w
, XWindowAttributes 
*wa
); 
 167 static void mappingnotify(XEvent 
*e
); 
 168 static void maprequest(XEvent 
*e
); 
 169 static void monocle(void); 
 170 static void movemouse(const Arg 
*arg
); 
 171 static Client 
*nexttiled(Client 
*c
); 
 172 static void propertynotify(XEvent 
*e
); 
 173 static void quit(const Arg 
*arg
); 
 174 static void resize(Client 
*c
, int x
, int y
, int w
, int h
, Bool sizehints
); 
 175 static void resizemouse(const Arg 
*arg
); 
 176 static void restack(void); 
 177 static void run(void); 
 178 static void scan(void); 
 179 static void setclientstate(Client 
*c
, long state
); 
 180 static void setlayout(const Arg 
*arg
); 
 181 static void setmfact(const Arg 
*arg
); 
 182 static void setup(void); 
 183 static void spawn(const Arg 
*arg
); 
 184 static void tag(const Arg 
*arg
); 
 185 static int textnw(const char *text
, unsigned int len
); 
 186 static void tile(void); 
 187 static void togglebar(const Arg 
*arg
); 
 188 static void togglefloating(const Arg 
*arg
); 
 189 static void toggletag(const Arg 
*arg
); 
 190 static void toggleview(const Arg 
*arg
); 
 191 static void unmanage(Client 
*c
); 
 192 static void unmapnotify(XEvent 
*e
); 
 193 static void updatebar(void); 
 194 static void updategeom(void); 
 195 static void updatenumlockmask(void); 
 196 static void updatesizehints(Client 
*c
); 
 197 static void updatetitle(Client 
*c
); 
 198 static void updatewmhints(Client 
*c
); 
 199 static void view(const Arg 
*arg
); 
 200 static int xerror(Display 
*dpy
, XErrorEvent 
*ee
); 
 201 static int xerrordummy(Display 
*dpy
, XErrorEvent 
*ee
); 
 202 static int xerrorstart(Display 
*dpy
, XErrorEvent 
*ee
); 
 203 static void zoom(const Arg 
*arg
); 
 206 static char stext
[256]; 
 208 static int sx
, sy
, sw
, sh
; /* X display screen geometry x, y, width, height */  
 209 static int by
, bh
, blw
;    /* bar geometry y, height and layout symbol width */ 
 210 static int wx
, wy
, ww
, wh
; /* window area geometry x, y, width, height, bar excluded */ 
 211 static unsigned int seltags 
= 0, sellt 
= 0; 
 212 static int (*xerrorxlib
)(Display 
*, XErrorEvent 
*); 
 213 static unsigned int numlockmask 
= 0; 
 214 static void (*handler
[LASTEvent
]) (XEvent 
*) = { 
 215         [ButtonPress
] = buttonpress
, 
 216         [ConfigureRequest
] = configurerequest
, 
 217         [ConfigureNotify
] = configurenotify
, 
 218         [DestroyNotify
] = destroynotify
, 
 219         [EnterNotify
] = enternotify
, 
 222         [KeyPress
] = keypress
, 
 223         [MappingNotify
] = mappingnotify
, 
 224         [MapRequest
] = maprequest
, 
 225         [PropertyNotify
] = propertynotify
, 
 226         [UnmapNotify
] = unmapnotify
 
 228 static Atom wmatom
[WMLast
], netatom
[NetLast
]; 
 230 static Bool running 
= True
; 
 231 static Client 
*clients 
= NULL
; 
 232 static Client 
*sel 
= NULL
; 
 233 static Client 
*stack 
= NULL
; 
 234 static Cursor cursor
[CurLast
]; 
 237 static Layout 
*lt
[] = { NULL
, NULL 
}; 
 238 static Window root
, barwin
; 
 239 /* configuration, allows nested code to access above variables */ 
 242 /* compile-time check if all tags fit into an unsigned int bit array. */ 
 243 struct NumTags 
{ char limitexceeded
[sizeof(unsigned int) * 8 < LENGTH(tags
) ? -1 : 1]; }; 
 245 /* function implementations */ 
 247 applyrules(Client 
*c
) { 
 250         XClassHint ch 
= { 0 }; 
 253         if(XGetClassHint(dpy
, c
->win
, &ch
)) { 
 254                 for(i 
= 0; i 
< LENGTH(rules
); i
++) { 
 256                         if((!r
->title 
|| strstr(c
->name
, r
->title
)) 
 257                         && (!r
->class || (ch
.res_class 
&& strstr(ch
.res_class
, r
->class))) 
 258                         && (!r
->instance 
|| (ch
.res_name 
&& strstr(ch
.res_name
, r
->instance
)))) { 
 259                                 c
->isfloating 
= r
->isfloating
; 
 260                                 c
->tags 
|= r
->tags 
& TAGMASK
; 
 269                 c
->tags 
= tagset
[seltags
]; 
 276         for(c 
= clients
; c
; c 
= c
->next
) 
 278                         XMoveWindow(dpy
, c
->win
, c
->x
, c
->y
); 
 279                         if(!lt
[sellt
]->arrange 
|| c
->isfloating
) 
 280                                 resize(c
, c
->x
, c
->y
, c
->w
, c
->h
, True
); 
 283                         XMoveWindow(dpy
, c
->win
, c
->x 
+ 2 * sw
, c
->y
); 
 287         if(lt
[sellt
]->arrange
) 
 288                 lt
[sellt
]->arrange(); 
 299 attachstack(Client 
*c
) { 
 305 buttonpress(XEvent 
*e
) { 
 306         unsigned int i
, x
, click
; 
 309         XButtonPressedEvent 
*ev 
= &e
->xbutton
; 
 312         if(ev
->window 
== barwin
) { 
 314                 do x 
+= TEXTW(tags
[i
]); while(ev
->x 
>= x 
&& ++i 
< LENGTH(tags
)); 
 315                 if(i 
< LENGTH(tags
)) { 
 319                 else if(ev
->x 
< x 
+ blw
) 
 321                 else if(ev
->x 
> wx 
+ ww 
- TEXTW(stext
)) 
 322                         click 
= ClkStatusText
; 
 326         else if((c 
= getclient(ev
->window
))) { 
 328                 click 
= ClkClientWin
; 
 331         for(i 
= 0; i 
< LENGTH(buttons
); i
++) 
 332                 if(click 
== buttons
[i
].click 
&& buttons
[i
].func 
&& buttons
[i
].button 
== ev
->button
 
 333                    && CLEANMASK(buttons
[i
].mask
) == CLEANMASK(ev
->state
)) 
 334                         buttons
[i
].func(click 
== ClkTagBar 
&& buttons
[i
].arg
.i 
== 0 ? &arg 
: &buttons
[i
].arg
); 
 340         xerrorxlib 
= XSetErrorHandler(xerrorstart
); 
 342         /* this causes an error if some other window manager is running */ 
 343         XSelectInput(dpy
, DefaultRootWindow(dpy
), SubstructureRedirectMask
); 
 346                 die("dwm: another window manager is already running\n"); 
 347         XSetErrorHandler(xerror
); 
 354         Layout foo 
= { "", NULL 
}; 
 362                 XFreeFontSet(dpy
, dc
.font
.set
); 
 364                 XFreeFont(dpy
, dc
.font
.xfont
); 
 365         XUngrabKey(dpy
, AnyKey
, AnyModifier
, root
); 
 366         XFreePixmap(dpy
, dc
.drawable
); 
 368         XFreeCursor(dpy
, cursor
[CurNormal
]); 
 369         XFreeCursor(dpy
, cursor
[CurResize
]); 
 370         XFreeCursor(dpy
, cursor
[CurMove
]); 
 371         XDestroyWindow(dpy
, barwin
); 
 373         XSetInputFocus(dpy
, PointerRoot
, RevertToPointerRoot
, CurrentTime
); 
 381         for(c 
= clients
; c
; c 
= c
->next
) 
 382                 if(ISVISIBLE(c
) && c
->isurgent
) { 
 384                         if (!(wmh 
= XGetWMHints(dpy
, c
->win
))) 
 387                         wmh
->flags 
&= ~XUrgencyHint
; 
 388                         XSetWMHints(dpy
, c
->win
, wmh
); 
 394 configure(Client 
*c
) { 
 397         ce
.type 
= ConfigureNotify
; 
 405         ce
.border_width 
= c
->bw
; 
 407         ce
.override_redirect 
= False
; 
 408         XSendEvent(dpy
, c
->win
, False
, StructureNotifyMask
, (XEvent 
*)&ce
); 
 412 configurenotify(XEvent 
*e
) { 
 413         XConfigureEvent 
*ev 
= &e
->xconfigure
; 
 415         if(ev
->window 
== root 
&& (ev
->width 
!= sw 
|| ev
->height 
!= sh
)) { 
 425 configurerequest(XEvent 
*e
) { 
 427         XConfigureRequestEvent 
*ev 
= &e
->xconfigurerequest
; 
 430         if((c 
= getclient(ev
->window
))) { 
 431                 if(ev
->value_mask 
& CWBorderWidth
) 
 432                         c
->bw 
= ev
->border_width
; 
 433                 else if(c
->isfloating 
|| !lt
[sellt
]->arrange
) { 
 434                         if(ev
->value_mask 
& CWX
) 
 436                         if(ev
->value_mask 
& CWY
) 
 438                         if(ev
->value_mask 
& CWWidth
) 
 440                         if(ev
->value_mask 
& CWHeight
) 
 442                         if((c
->x 
- sx 
+ c
->w
) > sw 
&& c
->isfloating
) 
 443                                 c
->x 
= sx 
+ (sw 
/ 2 - c
->w 
/ 2); /* center in x direction */ 
 444                         if((c
->y 
- sy 
+ c
->h
) > sh 
&& c
->isfloating
) 
 445                                 c
->y 
= sy 
+ (sh 
/ 2 - c
->h 
/ 2); /* center in y direction */ 
 446                         if((ev
->value_mask 
& (CWX
|CWY
)) && !(ev
->value_mask 
& (CWWidth
|CWHeight
))) 
 449                                 XMoveResizeWindow(dpy
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
); 
 457                 wc
.width 
= ev
->width
; 
 458                 wc
.height 
= ev
->height
; 
 459                 wc
.border_width 
= ev
->border_width
; 
 460                 wc
.sibling 
= ev
->above
; 
 461                 wc
.stack_mode 
= ev
->detail
; 
 462                 XConfigureWindow(dpy
, ev
->window
, ev
->value_mask
, &wc
); 
 468 destroynotify(XEvent 
*e
) { 
 470         XDestroyWindowEvent 
*ev 
= &e
->xdestroywindow
; 
 472         if((c 
= getclient(ev
->window
))) 
 480         for(tc 
= &clients
; *tc 
&& *tc 
!= c
; tc 
= &(*tc
)->next
); 
 485 detachstack(Client 
*c
) { 
 488         for(tc 
= &stack
; *tc 
&& *tc 
!= c
; tc 
= &(*tc
)->snext
); 
 493 die(const char *errstr
, ...) { 
 496         va_start(ap
, errstr
); 
 497         vfprintf(stderr
, errstr
, ap
); 
 505         unsigned int i
, occ 
= 0, urg 
= 0; 
 509         for(c 
= clients
; c
; c 
= c
->next
) { 
 516         for(i 
= 0; i 
< LENGTH(tags
); i
++) { 
 517                 dc
.w 
= TEXTW(tags
[i
]); 
 518                 col 
= tagset
[seltags
] & 1 << i 
? dc
.sel 
: dc
.norm
; 
 519                 drawtext(tags
[i
], col
, urg 
& 1 << i
); 
 520                 drawsquare(sel 
&& sel
->tags 
& 1 << i
, occ 
& 1 << i
, urg 
& 1 << i
, col
); 
 525                 drawtext(lt
[sellt
]->symbol
, dc
.norm
, False
); 
 536         drawtext(stext
, dc
.norm
, False
); 
 537         if((dc
.w 
= dc
.x 
- x
) > bh
) { 
 540                         drawtext(sel
->name
, dc
.sel
, False
); 
 541                         drawsquare(sel
->isfixed
, sel
->isfloating
, False
, dc
.sel
); 
 544                         drawtext(NULL
, dc
.norm
, False
); 
 546         XCopyArea(dpy
, dc
.drawable
, barwin
, dc
.gc
, 0, 0, ww
, bh
, 0, 0); 
 551 drawsquare(Bool filled
, Bool empty
, Bool invert
, unsigned long col
[ColLast
]) { 
 554         XRectangle r 
= { dc
.x
, dc
.y
, dc
.w
, dc
.h 
}; 
 556         gcv
.foreground 
= col
[invert 
? ColBG 
: ColFG
]; 
 557         XChangeGC(dpy
, dc
.gc
, GCForeground
, &gcv
); 
 558         x 
= (dc
.font
.ascent 
+ dc
.font
.descent 
+ 2) / 4; 
 562                 r
.width 
= r
.height 
= x 
+ 1; 
 563                 XFillRectangles(dpy
, dc
.drawable
, dc
.gc
, &r
, 1); 
 566                 r
.width 
= r
.height 
= x
; 
 567                 XDrawRectangles(dpy
, dc
.drawable
, dc
.gc
, &r
, 1); 
 572 drawtext(const char *text
, unsigned long col
[ColLast
], Bool invert
) { 
 574         int i
, x
, y
, h
, len
, olen
; 
 575         XRectangle r 
= { dc
.x
, dc
.y
, dc
.w
, dc
.h 
}; 
 577         XSetForeground(dpy
, dc
.gc
, col
[invert 
? ColFG 
: ColBG
]); 
 578         XFillRectangles(dpy
, dc
.drawable
, dc
.gc
, &r
, 1); 
 582         h 
= dc
.font
.ascent 
+ dc
.font
.descent
; 
 583         y 
= dc
.y 
+ (dc
.h 
/ 2) - (h 
/ 2) + dc
.font
.ascent
; 
 585         /* shorten text if necessary */ 
 586         for(len 
= MIN(olen
, sizeof buf
); len 
&& textnw(text
, len
) > dc
.w 
- h
; len
--); 
 589         memcpy(buf
, text
, len
); 
 591                 for(i 
= len
; i 
&& i 
> len 
- 3; buf
[--i
] = '.'); 
 592         XSetForeground(dpy
, dc
.gc
, col
[invert 
? ColBG 
: ColFG
]); 
 594                 XmbDrawString(dpy
, dc
.drawable
, dc
.font
.set
, dc
.gc
, x
, y
, buf
, len
); 
 596                 XDrawString(dpy
, dc
.drawable
, dc
.gc
, x
, y
, buf
, len
); 
 600 enternotify(XEvent 
*e
) { 
 602         XCrossingEvent 
*ev 
= &e
->xcrossing
; 
 604         if((ev
->mode 
!= NotifyNormal 
|| ev
->detail 
== NotifyInferior
) && ev
->window 
!= root
) 
 606         if((c 
= getclient(ev
->window
))) 
 614         XExposeEvent 
*ev 
= &e
->xexpose
; 
 616         if(ev
->count 
== 0 && (ev
->window 
== barwin
)) 
 622         if(!c 
|| !ISVISIBLE(c
)) 
 623                 for(c 
= stack
; c 
&& !ISVISIBLE(c
); c 
= c
->snext
); 
 624         if(sel 
&& sel 
!= c
) { 
 625                 grabbuttons(sel
, False
); 
 626                 XSetWindowBorder(dpy
, sel
->win
, dc
.norm
[ColBorder
]); 
 631                 grabbuttons(c
, True
); 
 632                 XSetWindowBorder(dpy
, c
->win
, dc
.sel
[ColBorder
]); 
 633                 XSetInputFocus(dpy
, c
->win
, RevertToPointerRoot
, CurrentTime
); 
 636                 XSetInputFocus(dpy
, root
, RevertToPointerRoot
, CurrentTime
); 
 642 focusin(XEvent 
*e
) { /* there are some broken focus acquiring clients */ 
 643         XFocusChangeEvent 
*ev 
= &e
->xfocus
; 
 645         if(sel 
&& ev
->window 
!= sel
->win
) 
 646                 XSetInputFocus(dpy
, sel
->win
, RevertToPointerRoot
, CurrentTime
); 
 650 focusstack(const Arg 
*arg
) { 
 651         Client 
*c 
= NULL
, *i
; 
 656                 for(c 
= sel
->next
; c 
&& !ISVISIBLE(c
); c 
= c
->next
); 
 658                         for(c 
= clients
; c 
&& !ISVISIBLE(c
); c 
= c
->next
); 
 661                 for(i 
= clients
; i 
!= sel
; i 
= i
->next
) 
 665                         for(; i
; i 
= i
->next
) 
 676 getclient(Window w
) { 
 679         for(c 
= clients
; c 
&& c
->win 
!= w
; c 
= c
->next
); 
 684 getcolor(const char *colstr
) { 
 685         Colormap cmap 
= DefaultColormap(dpy
, screen
); 
 688         if(!XAllocNamedColor(dpy
, cmap
, colstr
, &color
, &color
)) 
 689                 die("error, cannot allocate color '%s'\n", colstr
); 
 697         unsigned char *p 
= NULL
; 
 698         unsigned long n
, extra
; 
 701         status 
= XGetWindowProperty(dpy
, w
, wmatom
[WMState
], 0L, 2L, False
, wmatom
[WMState
], 
 702                         &real
, &format
, &n
, &extra
, (unsigned char **)&p
); 
 703         if(status 
!= Success
) 
 712 gettextprop(Window w
, Atom atom
, char *text
, unsigned int size
) { 
 717         if(!text 
|| size 
== 0) 
 720         XGetTextProperty(dpy
, w
, &name
, atom
); 
 723         if(name
.encoding 
== XA_STRING
) 
 724                 strncpy(text
, (char *)name
.value
, size 
- 1); 
 726                 if(XmbTextPropertyToTextList(dpy
, &name
, &list
, &n
) >= Success
 
 728                         strncpy(text
, *list
, size 
- 1); 
 729                         XFreeStringList(list
); 
 732         text
[size 
- 1] = '\0'; 
 738 grabbuttons(Client 
*c
, Bool focused
) { 
 742                 unsigned int modifiers
[] = { 0, LockMask
, numlockmask
, numlockmask
|LockMask 
}; 
 743                 XUngrabButton(dpy
, AnyButton
, AnyModifier
, c
->win
); 
 745                         for(i 
= 0; i 
< LENGTH(buttons
); i
++) 
 746                                 if(buttons
[i
].click 
== ClkClientWin
) 
 747                                         for(j 
= 0; j 
< LENGTH(modifiers
); j
++) 
 748                                                 XGrabButton(dpy
, buttons
[i
].button
, buttons
[i
].mask 
| modifiers
[j
], c
->win
, False
, BUTTONMASK
, GrabModeAsync
, GrabModeSync
, None
, None
); 
 750                         XGrabButton(dpy
, AnyButton
, AnyModifier
, c
->win
, False
, 
 751                                     BUTTONMASK
, GrabModeAsync
, GrabModeSync
, None
, None
); 
 760                 unsigned int modifiers
[] = { 0, LockMask
, numlockmask
, numlockmask
|LockMask 
}; 
 763                 XUngrabKey(dpy
, AnyKey
, AnyModifier
, root
); 
 764                 for(i 
= 0; i 
< LENGTH(keys
); i
++) { 
 765                         if((code 
= XKeysymToKeycode(dpy
, keys
[i
].keysym
))) 
 766                                 for(j 
= 0; j 
< LENGTH(modifiers
); j
++) 
 767                                         XGrabKey(dpy
, code
, keys
[i
].mod 
| modifiers
[j
], root
, 
 768                                                  True
, GrabModeAsync
, GrabModeAsync
); 
 774 initfont(const char *fontstr
) { 
 775         char *def
, **missing
; 
 779         dc
.font
.set 
= XCreateFontSet(dpy
, fontstr
, &missing
, &n
, &def
); 
 782                         fprintf(stderr
, "dwm: missing fontset: %s\n", missing
[n
]); 
 783                 XFreeStringList(missing
); 
 786                 XFontSetExtents 
*font_extents
; 
 787                 XFontStruct 
**xfonts
; 
 789                 dc
.font
.ascent 
= dc
.font
.descent 
= 0; 
 790                 font_extents 
= XExtentsOfFontSet(dc
.font
.set
); 
 791                 n 
= XFontsOfFontSet(dc
.font
.set
, &xfonts
, &font_names
); 
 792                 for(i 
= 0, dc
.font
.ascent 
= 0, dc
.font
.descent 
= 0; i 
< n
; i
++) { 
 793                         dc
.font
.ascent 
= MAX(dc
.font
.ascent
, (*xfonts
)->ascent
); 
 794                         dc
.font
.descent 
= MAX(dc
.font
.descent
,(*xfonts
)->descent
); 
 799                 if(!(dc
.font
.xfont 
= XLoadQueryFont(dpy
, fontstr
)) 
 800                 && !(dc
.font
.xfont 
= XLoadQueryFont(dpy
, "fixed"))) 
 801                         die("error, cannot load font: '%s'\n", fontstr
); 
 802                 dc
.font
.ascent 
= dc
.font
.xfont
->ascent
; 
 803                 dc
.font
.descent 
= dc
.font
.xfont
->descent
; 
 805         dc
.font
.height 
= dc
.font
.ascent 
+ dc
.font
.descent
; 
 809 isprotodel(Client 
*c
) { 
 814         if(XGetWMProtocols(dpy
, c
->win
, &protocols
, &n
)) { 
 815                 for(i 
= 0; !ret 
&& i 
< n
; i
++) 
 816                         if(protocols
[i
] == wmatom
[WMDelete
]) 
 824 keypress(XEvent 
*e
) { 
 830         keysym 
= XKeycodeToKeysym(dpy
, (KeyCode
)ev
->keycode
, 0); 
 831         for(i 
= 0; i 
< LENGTH(keys
); i
++) 
 832                 if(keysym 
== keys
[i
].keysym
 
 833                    && CLEANMASK(keys
[i
].mod
) == CLEANMASK(ev
->state
) 
 835                         keys
[i
].func(&(keys
[i
].arg
)); 
 839 killclient(const Arg 
*arg
) { 
 844         if(isprotodel(sel
)) { 
 845                 ev
.type 
= ClientMessage
; 
 846                 ev
.xclient
.window 
= sel
->win
; 
 847                 ev
.xclient
.message_type 
= wmatom
[WMProtocols
]; 
 848                 ev
.xclient
.format 
= 32; 
 849                 ev
.xclient
.data
.l
[0] = wmatom
[WMDelete
]; 
 850                 ev
.xclient
.data
.l
[1] = CurrentTime
; 
 851                 XSendEvent(dpy
, sel
->win
, False
, NoEventMask
, &ev
); 
 854                 XKillClient(dpy
, sel
->win
); 
 858 manage(Window w
, XWindowAttributes 
*wa
) { 
 859         Client 
*c
, *t 
= NULL
; 
 863         if(!(c 
= calloc(1, sizeof(Client
)))) 
 864                 die("fatal: could not calloc() %u bytes\n", sizeof(Client
)); 
 872         c
->oldbw 
= wa
->border_width
; 
 873         if(c
->w 
== sw 
&& c
->h 
== sh
) { 
 879                 if(c
->x 
+ c
->w 
+ 2 * c
->bw 
> sx 
+ sw
) 
 880                         c
->x 
= sx 
+ sw 
- NOBORDER(c
->w
); 
 881                 if(c
->y 
+ c
->h 
+ 2 * c
->bw 
> sy 
+ sh
) 
 882                         c
->y 
= sy 
+ sh 
- NOBORDER(c
->h
); 
 883                 c
->x 
= MAX(c
->x
, sx
); 
 884                 /* only fix client y-offset, if the client center might cover the bar */ 
 885                 c
->y 
= MAX(c
->y
, ((by 
== 0) && (c
->x 
+ (c
->w 
/ 2) >= wx
) && (c
->x 
+ (c
->w 
/ 2) < wx 
+ ww
)) ? bh 
: sy
); 
 889         wc
.border_width 
= c
->bw
; 
 890         XConfigureWindow(dpy
, w
, CWBorderWidth
, &wc
); 
 891         XSetWindowBorder(dpy
, w
, dc
.norm
[ColBorder
]); 
 892         configure(c
); /* propagates border_width, if size doesn't change */ 
 894         XSelectInput(dpy
, w
, EnterWindowMask
|FocusChangeMask
|PropertyChangeMask
|StructureNotifyMask
); 
 895         grabbuttons(c
, False
); 
 897         if(XGetTransientForHint(dpy
, w
, &trans
)) 
 898                 t 
= getclient(trans
); 
 904                 c
->isfloating 
= trans 
!= None 
|| c
->isfixed
; 
 906                 XRaiseWindow(dpy
, c
->win
); 
 909         XMoveResizeWindow(dpy
, c
->win
, c
->x 
+ 2 * sw
, c
->y
, c
->w
, c
->h
); /* some windows require this */ 
 910         XMapWindow(dpy
, c
->win
); 
 911         setclientstate(c
, NormalState
); 
 916 mappingnotify(XEvent 
*e
) { 
 917         XMappingEvent 
*ev 
= &e
->xmapping
; 
 919         XRefreshKeyboardMapping(ev
); 
 920         if(ev
->request 
== MappingKeyboard
) 
 925 maprequest(XEvent 
*e
) { 
 926         static XWindowAttributes wa
; 
 927         XMapRequestEvent 
*ev 
= &e
->xmaprequest
; 
 929         if(!XGetWindowAttributes(dpy
, ev
->window
, &wa
)) 
 931         if(wa
.override_redirect
) 
 933         if(!getclient(ev
->window
)) 
 934                 manage(ev
->window
, &wa
); 
 941         for(c 
= nexttiled(clients
); c
; c 
= nexttiled(c
->next
)) 
 942                 resize(c
, wx
, wy
, NOBORDER(ww
), NOBORDER(wh
), resizehints
); 
 946 movemouse(const Arg 
*arg
) { 
 947         int x
, y
, ocx
, ocy
, di
, nx
, ny
; 
 958         if(XGrabPointer(dpy
, root
, False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
, 
 959         None
, cursor
[CurMove
], CurrentTime
) != GrabSuccess
) 
 961         XQueryPointer(dpy
, root
, &dummy
, &dummy
, &x
, &y
, &di
, &di
, &dui
); 
 963                 XMaskEvent(dpy
, MOUSEMASK
|ExposureMask
|SubstructureRedirectMask
, &ev
); 
 965                 case ConfigureRequest
: 
 968                         handler
[ev
.type
](&ev
); 
 972                         nx 
= ocx 
+ (ev
.xmotion
.x 
- x
); 
 973                         ny 
= ocy 
+ (ev
.xmotion
.y 
- y
); 
 974                         if(snap 
&& nx 
>= wx 
&& nx 
<= wx 
+ ww
 
 975                                 && ny 
>= wy 
&& ny 
<= wy 
+ wh
) { 
 976                                 if(abs(wx 
- nx
) < snap
) 
 978                                 else if(abs((wx 
+ ww
) - (nx 
+ c
->w 
+ 2 * c
->bw
)) < snap
) 
 979                                         nx 
= wx 
+ ww 
- NOBORDER(c
->w
); 
 980                                 if(abs(wy 
- ny
) < snap
) 
 982                                 else if(abs((wy 
+ wh
) - (ny 
+ c
->h 
+ 2 * c
->bw
)) < snap
) 
 983                                         ny 
= wy 
+ wh 
- NOBORDER(c
->h
); 
 984                                 if(!c
->isfloating 
&& lt
[sellt
]->arrange 
&& (abs(nx 
- c
->x
) > snap 
|| abs(ny 
- c
->y
) > snap
)) 
 985                                         togglefloating(NULL
); 
 987                         if(!lt
[sellt
]->arrange 
|| c
->isfloating
) 
 988                                 resize(c
, nx
, ny
, c
->w
, c
->h
, False
); 
 992         while(ev
.type 
!= ButtonRelease
); 
 993         XUngrabPointer(dpy
, CurrentTime
); 
 997 nexttiled(Client 
*c
) { 
 998         for(; c 
&& (c
->isfloating 
|| !ISVISIBLE(c
)); c 
= c
->next
); 
1003 propertynotify(XEvent 
*e
) { 
1006         XPropertyEvent 
*ev 
= &e
->xproperty
; 
1008         if(ev
->state 
== PropertyDelete
) 
1009                 return; /* ignore */ 
1010         if((c 
= getclient(ev
->window
))) { 
1013                 case XA_WM_TRANSIENT_FOR
: 
1014                         XGetTransientForHint(dpy
, c
->win
, &trans
); 
1015                         if(!c
->isfloating 
&& (c
->isfloating 
= (getclient(trans
) != NULL
))) 
1018                 case XA_WM_NORMAL_HINTS
: 
1026                 if(ev
->atom 
== XA_WM_NAME 
|| ev
->atom 
== netatom
[NetWMName
]) { 
1035 quit(const Arg 
*arg
) { 
1036         readin 
= running 
= False
; 
1040 resize(Client 
*c
, int x
, int y
, int w
, int h
, Bool sizehints
) { 
1044                 /* see last two sentences in ICCCM 4.1.2.3 */ 
1045                 Bool baseismin 
= c
->basew 
== c
->minw 
&& c
->baseh 
== c
->minh
; 
1047                 /* set minimum possible */ 
1051                 if(!baseismin
) { /* temporarily remove base dimensions */ 
1056                 /* adjust for aspect limits */ 
1057                 if(c
->mina 
> 0 && c
->maxa 
> 0) { 
1058                         if(c
->maxa 
< (float)w 
/ h
) 
1060                         else if(c
->mina 
< (float)h 
/ w
) 
1064                 if(baseismin
) { /* increment calculation requires this */ 
1069                 /* adjust for increment value */ 
1075                 /* restore base dimensions */ 
1079                 w 
= MAX(w
, c
->minw
); 
1080                 h 
= MAX(h
, c
->minh
); 
1083                         w 
= MIN(w
, c
->maxw
); 
1086                         h 
= MIN(h
, c
->maxh
); 
1088         if(w 
<= 0 || h 
<= 0) 
1091                 x 
= sw 
- NOBORDER(w
); 
1093                 y 
= sh 
- NOBORDER(h
); 
1094         if(x 
+ w 
+ 2 * c
->bw 
< sx
) 
1096         if(y 
+ h 
+ 2 * c
->bw 
< sy
) 
1102         if(c
->x 
!= x 
|| c
->y 
!= y 
|| c
->w 
!= w 
|| c
->h 
!= h
) { 
1105                 c
->w 
= wc
.width 
= w
; 
1106                 c
->h 
= wc
.height 
= h
; 
1107                 wc
.border_width 
= c
->bw
; 
1108                 XConfigureWindow(dpy
, c
->win
, 
1109                                 CWX
|CWY
|CWWidth
|CWHeight
|CWBorderWidth
, &wc
); 
1116 resizemouse(const Arg 
*arg
) { 
1127         if(XGrabPointer(dpy
, root
, False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
, 
1128         None
, cursor
[CurResize
], CurrentTime
) != GrabSuccess
) 
1130         XWarpPointer(dpy
, None
, c
->win
, 0, 0, 0, 0, c
->w 
+ c
->bw 
- 1, c
->h 
+ c
->bw 
- 1); 
1132                 XMaskEvent(dpy
, MOUSEMASK
|ExposureMask
|SubstructureRedirectMask
, &ev
); 
1134                 case ConfigureRequest
: 
1137                         handler
[ev
.type
](&ev
); 
1141                         nw 
= MAX(ev
.xmotion
.x 
- NOBORDER(ocx
) + 1, 1); 
1142                         nh 
= MAX(ev
.xmotion
.y 
- NOBORDER(ocy
) + 1, 1); 
1144                         if(snap 
&& nw 
>= wx 
&& nw 
<= wx 
+ ww
 
1145                                 && nh 
>= wy 
&& nh 
<= wy 
+ wh
) { 
1146                                 if(!c
->isfloating 
&& lt
[sellt
]->arrange
 
1147                                    && (abs(nw 
- c
->w
) > snap 
|| abs(nh 
- c
->h
) > snap
)) 
1148                                         togglefloating(NULL
); 
1150                         if(!lt
[sellt
]->arrange 
|| c
->isfloating
) 
1151                                 resize(c
, c
->x
, c
->y
, nw
, nh
, True
); 
1155         while(ev
.type 
!= ButtonRelease
); 
1156         XWarpPointer(dpy
, None
, c
->win
, 0, 0, 0, 0, c
->w 
+ c
->bw 
- 1, c
->h 
+ c
->bw 
- 1); 
1157         XUngrabPointer(dpy
, CurrentTime
); 
1158         while(XCheckMaskEvent(dpy
, EnterWindowMask
, &ev
)); 
1170         if(sel
->isfloating 
|| !lt
[sellt
]->arrange
) 
1171                 XRaiseWindow(dpy
, sel
->win
); 
1172         if(lt
[sellt
]->arrange
) { 
1173                 wc
.stack_mode 
= Below
; 
1174                 wc
.sibling 
= barwin
; 
1175                 for(c 
= stack
; c
; c 
= c
->snext
) 
1176                         if(!c
->isfloating 
&& ISVISIBLE(c
)) { 
1177                                 XConfigureWindow(dpy
, c
->win
, CWSibling
|CWStackMode
, &wc
); 
1178                                 wc
.sibling 
= c
->win
; 
1182         while(XCheckMaskEvent(dpy
, EnterWindowMask
, &ev
)); 
1188         char sbuf
[sizeof stext
]; 
1191         unsigned int len
, offset
; 
1194         /* main event loop, also reads status text from stdin */ 
1196         xfd 
= ConnectionNumber(dpy
); 
1198         len 
= sizeof stext 
- 1; 
1199         sbuf
[len
] = stext
[len
] = '\0'; /* 0-terminator is never touched */ 
1203                         FD_SET(STDIN_FILENO
, &rd
); 
1205                 if(select(xfd 
+ 1, &rd
, NULL
, NULL
, NULL
) == -1) { 
1208                         die("select failed\n"); 
1210                 if(FD_ISSET(STDIN_FILENO
, &rd
)) { 
1211                         switch((r 
= read(STDIN_FILENO
, sbuf 
+ offset
, len 
- offset
))) { 
1213                                 strncpy(stext
, strerror(errno
), len
); 
1217                                 strncpy(stext
, "EOF", 4); 
1221                                 for(p 
= sbuf 
+ offset
; r 
> 0; p
++, r
--, offset
++) 
1222                                         if(*p 
== '\n' || *p 
== '\0') { 
1224                                                 strncpy(stext
, sbuf
, len
); 
1225                                                 p 
+= r 
- 1; /* p is sbuf + offset + r - 1 */ 
1226                                                 for(r 
= 0; *(p 
- r
) && *(p 
- r
) != '\n'; r
++); 
1229                                                         memmove(sbuf
, p 
- r 
+ 1, r
); 
1236                 while(XPending(dpy
)) { 
1237                         XNextEvent(dpy
, &ev
); 
1238                         if(handler
[ev
.type
]) 
1239                                 (handler
[ev
.type
])(&ev
); /* call handler */ 
1246         unsigned int i
, num
; 
1247         Window d1
, d2
, *wins 
= NULL
; 
1248         XWindowAttributes wa
; 
1250         if(XQueryTree(dpy
, root
, &d1
, &d2
, &wins
, &num
)) { 
1251                 for(i 
= 0; i 
< num
; i
++) { 
1252                         if(!XGetWindowAttributes(dpy
, wins
[i
], &wa
) 
1253                         || wa
.override_redirect 
|| XGetTransientForHint(dpy
, wins
[i
], &d1
)) 
1255                         if(wa
.map_state 
== IsViewable 
|| getstate(wins
[i
]) == IconicState
) 
1256                                 manage(wins
[i
], &wa
); 
1258                 for(i 
= 0; i 
< num
; i
++) { /* now the transients */ 
1259                         if(!XGetWindowAttributes(dpy
, wins
[i
], &wa
)) 
1261                         if(XGetTransientForHint(dpy
, wins
[i
], &d1
) 
1262                         && (wa
.map_state 
== IsViewable 
|| getstate(wins
[i
]) == IconicState
)) 
1263                                 manage(wins
[i
], &wa
); 
1271 setclientstate(Client 
*c
, long state
) { 
1272         long data
[] = {state
, None
}; 
1274         XChangeProperty(dpy
, c
->win
, wmatom
[WMState
], wmatom
[WMState
], 32, 
1275                         PropModeReplace
, (unsigned char *)data
, 2); 
1279 setlayout(const Arg 
*arg
) { 
1280         if(!arg 
|| !arg
->v 
|| arg
->v 
!= lt
[sellt
]) 
1283                 lt
[sellt
] = (Layout 
*)arg
->v
; 
1290 /* arg > 1.0 will set mfact absolutly */ 
1292 setmfact(const Arg 
*arg
) { 
1295         if(!arg 
|| !lt
[sellt
]->arrange
) 
1297         f 
= arg
->f 
< 1.0 ? arg
->f 
+ mfact 
: arg
->f 
- 1.0; 
1298         if(f 
< 0.1 || f 
> 0.9) 
1308         XSetWindowAttributes wa
; 
1311         screen 
= DefaultScreen(dpy
); 
1312         root 
= RootWindow(dpy
, screen
); 
1316         sw 
= DisplayWidth(dpy
, screen
); 
1317         sh 
= DisplayHeight(dpy
, screen
); 
1318         bh 
= dc
.h 
= dc
.font
.height 
+ 2; 
1319         lt
[0] = &layouts
[0]; 
1320         lt
[1] = &layouts
[1 % LENGTH(layouts
)]; 
1324         wmatom
[WMProtocols
] = XInternAtom(dpy
, "WM_PROTOCOLS", False
); 
1325         wmatom
[WMDelete
] = XInternAtom(dpy
, "WM_DELETE_WINDOW", False
); 
1326         wmatom
[WMState
] = XInternAtom(dpy
, "WM_STATE", False
); 
1327         netatom
[NetSupported
] = XInternAtom(dpy
, "_NET_SUPPORTED", False
); 
1328         netatom
[NetWMName
] = XInternAtom(dpy
, "_NET_WM_NAME", False
); 
1331         wa
.cursor 
= cursor
[CurNormal
] = XCreateFontCursor(dpy
, XC_left_ptr
); 
1332         cursor
[CurResize
] = XCreateFontCursor(dpy
, XC_sizing
); 
1333         cursor
[CurMove
] = XCreateFontCursor(dpy
, XC_fleur
); 
1335         /* init appearance */ 
1336         dc
.norm
[ColBorder
] = getcolor(normbordercolor
); 
1337         dc
.norm
[ColBG
] = getcolor(normbgcolor
); 
1338         dc
.norm
[ColFG
] = getcolor(normfgcolor
); 
1339         dc
.sel
[ColBorder
] = getcolor(selbordercolor
); 
1340         dc
.sel
[ColBG
] = getcolor(selbgcolor
); 
1341         dc
.sel
[ColFG
] = getcolor(selfgcolor
); 
1342         dc
.drawable 
= XCreatePixmap(dpy
, root
, DisplayWidth(dpy
, screen
), bh
, DefaultDepth(dpy
, screen
)); 
1343         dc
.gc 
= XCreateGC(dpy
, root
, 0, 0); 
1344         XSetLineAttributes(dpy
, dc
.gc
, 1, LineSolid
, CapButt
, JoinMiter
); 
1346                 XSetFont(dpy
, dc
.gc
, dc
.font
.xfont
->fid
); 
1349         for(blw 
= i 
= 0; LENGTH(layouts
) > 1 && i 
< LENGTH(layouts
); i
++) { 
1350                 w 
= TEXTW(layouts
[i
].symbol
); 
1354         wa
.override_redirect 
= 1; 
1355         wa
.background_pixmap 
= ParentRelative
; 
1356         wa
.event_mask 
= ButtonPressMask
|ExposureMask
; 
1358         barwin 
= XCreateWindow(dpy
, root
, wx
, by
, ww
, bh
, 0, DefaultDepth(dpy
, screen
), 
1359                         CopyFromParent
, DefaultVisual(dpy
, screen
), 
1360                         CWOverrideRedirect
|CWBackPixmap
|CWEventMask
, &wa
); 
1361         XDefineCursor(dpy
, barwin
, cursor
[CurNormal
]); 
1362         XMapRaised(dpy
, barwin
); 
1363         strcpy(stext
, "dwm-"VERSION
); 
1366         /* EWMH support per view */ 
1367         XChangeProperty(dpy
, root
, netatom
[NetSupported
], XA_ATOM
, 32, 
1368                         PropModeReplace
, (unsigned char *) netatom
, NetLast
); 
1370         /* select for events */ 
1371         wa
.event_mask 
= SubstructureRedirectMask
|SubstructureNotifyMask
|ButtonPressMask
 
1372                         |EnterWindowMask
|LeaveWindowMask
|StructureNotifyMask
; 
1373         XChangeWindowAttributes(dpy
, root
, CWEventMask
|CWCursor
, &wa
); 
1374         XSelectInput(dpy
, root
, wa
.event_mask
); 
1380 spawn(const Arg 
*arg
) { 
1381         /* The double-fork construct avoids zombie processes and keeps the code 
1382          * clean from stupid signal handlers. */ 
1386                                 close(ConnectionNumber(dpy
)); 
1388                         execvp(((char **)arg
->v
)[0], (char **)arg
->v
); 
1389                         fprintf(stderr
, "dwm: execvp %s", ((char **)arg
->v
)[0]); 
1398 tag(const Arg 
*arg
) { 
1399         if(sel 
&& arg
->ui 
& TAGMASK
) { 
1400                 sel
->tags 
= arg
->ui 
& TAGMASK
; 
1406 textnw(const char *text
, unsigned int len
) { 
1410                 XmbTextExtents(dc
.font
.set
, text
, len
, NULL
, &r
); 
1413         return XTextWidth(dc
.font
.xfont
, text
, len
); 
1422         for(n 
= 0, c 
= nexttiled(clients
); c
; c 
= nexttiled(c
->next
), n
++); 
1427         c 
= nexttiled(clients
); 
1429         resize(c
, wx
, wy
, NOBORDER(n 
== 1 ? ww 
: mw
), NOBORDER(wh
), resizehints
); 
1435         x 
= (wx 
+ mw 
> c
->x 
+ c
->w
) ? c
->x 
+ c
->w 
+ 2 * c
->bw 
: wx 
+ mw
; 
1437         w 
= (wx 
+ mw 
> c
->x 
+ c
->w
) ? wx 
+ ww 
- x 
: ww 
- mw
; 
1442         for(i 
= 0, c 
= nexttiled(c
->next
); c
; c 
= nexttiled(c
->next
), i
++) { 
1443                 resize(c
, x
, y
, NOBORDER(w
), /* remainder */ ((i 
+ 1 == n
) 
1444                        ? NOBORDER(wy 
+ wh
) - y 
: h
), resizehints
); 
1446                         y 
= c
->y 
+ c
->h 
+ 2 * c
->bw
; 
1451 togglebar(const Arg 
*arg
) { 
1459 togglefloating(const Arg 
*arg
) { 
1462         sel
->isfloating 
= !sel
->isfloating 
|| sel
->isfixed
; 
1464                 resize(sel
, sel
->x
, sel
->y
, sel
->w
, sel
->h
, True
); 
1469 toggletag(const Arg 
*arg
) { 
1475         mask 
= sel
->tags 
^ (arg
->ui 
& TAGMASK
); 
1483 toggleview(const Arg 
*arg
) { 
1484         unsigned int mask 
= tagset
[seltags
] ^ (arg
->ui 
& TAGMASK
); 
1487                 tagset
[seltags
] = mask
; 
1494 unmanage(Client 
*c
) { 
1497         wc
.border_width 
= c
->oldbw
; 
1498         /* The server grab construct avoids race conditions. */ 
1500         XSetErrorHandler(xerrordummy
); 
1501         XConfigureWindow(dpy
, c
->win
, CWBorderWidth
, &wc
); /* restore border */ 
1506         XUngrabButton(dpy
, AnyButton
, AnyModifier
, c
->win
); 
1507         setclientstate(c
, WithdrawnState
); 
1510         XSetErrorHandler(xerror
); 
1516 unmapnotify(XEvent 
*e
) { 
1518         XUnmapEvent 
*ev 
= &e
->xunmap
; 
1520         if((c 
= getclient(ev
->window
))) 
1526         if(dc
.drawable 
!= 0) 
1527                 XFreePixmap(dpy
, dc
.drawable
); 
1528         dc
.drawable 
= XCreatePixmap(dpy
, root
, ww
, bh
, DefaultDepth(dpy
, screen
)); 
1529         XMoveResizeWindow(dpy
, barwin
, wx
, by
, ww
, bh
); 
1536         XineramaScreenInfo 
*info 
= NULL
; 
1538         /* window area geometry */ 
1539         if(XineramaIsActive(dpy
) && (info 
= XineramaQueryScreens(dpy
, &n
))) {  
1544                         if(XQueryPointer(dpy
, root
, &dummy
, &dummy
, &x
, &y
, &di
, &di
, &dui
)) 
1545                                 for(i 
= 0; i 
< n
; i
++) 
1546                                         if(INRECT(x
, y
, info
[i
].x_org
, info
[i
].y_org
, info
[i
].width
, info
[i
].height
)) 
1550                 wy 
= showbar 
&& topbar 
?  info
[i
].y_org 
+ bh 
: info
[i
].y_org
; 
1552                 wh 
= showbar 
? info
[i
].height 
- bh 
: info
[i
].height
; 
1559                 wy 
= showbar 
&& topbar 
? sy 
+ bh 
: sy
; 
1561                 wh 
= showbar 
? sh 
- bh 
: sh
; 
1565         by 
= showbar 
? (topbar 
? wy 
- bh 
: wy 
+ wh
) : -bh
; 
1569 updatenumlockmask(void) { 
1571         XModifierKeymap 
*modmap
; 
1574         modmap 
= XGetModifierMapping(dpy
); 
1575         for(i 
= 0; i 
< 8; i
++) 
1576                 for(j 
= 0; j 
< modmap
->max_keypermod
; j
++) 
1577                         if(modmap
->modifiermap
[i 
* modmap
->max_keypermod 
+ j
] == XKeysymToKeycode(dpy
, XK_Num_Lock
)) 
1578                                 numlockmask 
= (1 << i
); 
1579         XFreeModifiermap(modmap
); 
1583 updatesizehints(Client 
*c
) { 
1587         XGetWMNormalHints(dpy
, c
->win
, &size
, &msize
); 
1588         if(size
.flags 
& PBaseSize
) { 
1589                 c
->basew 
= size
.base_width
; 
1590                 c
->baseh 
= size
.base_height
; 
1592         else if(size
.flags 
& PMinSize
) { 
1593                 c
->basew 
= size
.min_width
; 
1594                 c
->baseh 
= size
.min_height
; 
1597                 c
->basew 
= c
->baseh 
= 0; 
1598         if(size
.flags 
& PResizeInc
) { 
1599                 c
->incw 
= size
.width_inc
; 
1600                 c
->inch 
= size
.height_inc
; 
1603                 c
->incw 
= c
->inch 
= 0; 
1604         if(size
.flags 
& PMaxSize
) { 
1605                 c
->maxw 
= size
.max_width
; 
1606                 c
->maxh 
= size
.max_height
; 
1609                 c
->maxw 
= c
->maxh 
= 0; 
1610         if(size
.flags 
& PMinSize
) { 
1611                 c
->minw 
= size
.min_width
; 
1612                 c
->minh 
= size
.min_height
; 
1614         else if(size
.flags 
& PBaseSize
) { 
1615                 c
->minw 
= size
.base_width
; 
1616                 c
->minh 
= size
.base_height
; 
1619                 c
->minw 
= c
->minh 
= 0; 
1620         if(size
.flags 
& PAspect
) { 
1621                 c
->mina 
= (float)size
.min_aspect
.y 
/ (float)size
.min_aspect
.x
; 
1622                 c
->maxa 
= (float)size
.max_aspect
.x 
/ (float)size
.max_aspect
.y
; 
1625                 c
->maxa 
= c
->mina 
= 0.0; 
1626         c
->isfixed 
= (c
->maxw 
&& c
->minw 
&& c
->maxh 
&& c
->minh
 
1627                      && c
->maxw 
== c
->minw 
&& c
->maxh 
== c
->minh
); 
1631 updatetitle(Client 
*c
) { 
1632         if(!gettextprop(c
->win
, netatom
[NetWMName
], c
->name
, sizeof c
->name
)) 
1633                 gettextprop(c
->win
, XA_WM_NAME
, c
->name
, sizeof c
->name
); 
1637 updatewmhints(Client 
*c
) { 
1640         if((wmh 
= XGetWMHints(dpy
, c
->win
))) { 
1641                 if(ISVISIBLE(c
) && wmh
->flags 
& XUrgencyHint
) { 
1642                         wmh
->flags 
&= ~XUrgencyHint
; 
1643                         XSetWMHints(dpy
, c
->win
, wmh
); 
1646                         c
->isurgent 
= (wmh
->flags 
& XUrgencyHint
) ? True 
: False
; 
1653 view(const Arg 
*arg
) { 
1654         if((arg
->ui 
& TAGMASK
) == tagset
[seltags
]) 
1656         seltags 
^= 1; /* toggle sel tagset */ 
1657         if(arg
->ui 
& TAGMASK
) 
1658                 tagset
[seltags
] = arg
->ui 
& TAGMASK
; 
1663 /* There's no way to check accesses to destroyed windows, thus those cases are 
1664  * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs 
1665  * default error handler, which may call exit.  */ 
1667 xerror(Display 
*dpy
, XErrorEvent 
*ee
) { 
1668         if(ee
->error_code 
== BadWindow
 
1669         || (ee
->request_code 
== X_SetInputFocus 
&& ee
->error_code 
== BadMatch
) 
1670         || (ee
->request_code 
== X_PolyText8 
&& ee
->error_code 
== BadDrawable
) 
1671         || (ee
->request_code 
== X_PolyFillRectangle 
&& ee
->error_code 
== BadDrawable
) 
1672         || (ee
->request_code 
== X_PolySegment 
&& ee
->error_code 
== BadDrawable
) 
1673         || (ee
->request_code 
== X_ConfigureWindow 
&& ee
->error_code 
== BadMatch
) 
1674         || (ee
->request_code 
== X_GrabButton 
&& ee
->error_code 
== BadAccess
) 
1675         || (ee
->request_code 
== X_GrabKey 
&& ee
->error_code 
== BadAccess
) 
1676         || (ee
->request_code 
== X_CopyArea 
&& ee
->error_code 
== BadDrawable
)) 
1678         fprintf(stderr
, "dwm: fatal error: request code=%d, error code=%d\n", 
1679                         ee
->request_code
, ee
->error_code
); 
1680         return xerrorxlib(dpy
, ee
); /* may call exit */ 
1684 xerrordummy(Display 
*dpy
, XErrorEvent 
*ee
) { 
1688 /* Startup Error handler to check if another window manager 
1689  * is already running. */ 
1691 xerrorstart(Display 
*dpy
, XErrorEvent 
*ee
) { 
1697 zoom(const Arg 
*arg
) { 
1700         if(!lt
[sellt
]->arrange 
|| lt
[sellt
]->arrange 
== monocle 
|| (sel 
&& sel
->isfloating
)) 
1702         if(c 
== nexttiled(clients
)) 
1703                 if(!c 
|| !(c 
= nexttiled(c
->next
))) 
1712 main(int argc
, char *argv
[]) { 
1713         if(argc 
== 2 && !strcmp("-v", argv
[1])) 
1714                 die("dwm-"VERSION
", © 2006-2008 dwm engineers, see LICENSE for details\n"); 
1716                 die("usage: dwm [-v]\n"); 
1718         if(!setlocale(LC_CTYPE
, "") || !XSupportsLocale()) 
1719                 fprintf(stderr
, "warning: no locale support\n"); 
1721         if(!(dpy 
= XOpenDisplay(0))) 
1722                 die("dwm: cannot open display\n");