Xinqi Bao's Git
d3169be9384efd66ea5fb32800909e4ea5cfd384
   1 #define XINULATOR /* debug, simulates dual head */ 
   2 /* See LICENSE file for copyright and license details. 
   4  * dynamic window manager is designed like any other X client as well. It is 
   5  * driven through handling X events. In contrast to other X clients, a window 
   6  * manager selects for SubstructureRedirectMask on the root window, to receive 
   7  * events about window (dis-)appearance.  Only one X connection at a time is 
   8  * allowed to select for this event mask. 
  10  * The event handlers of dwm are organized in an array which is accessed 
  11  * whenever a new event has been fetched. This allows event dispatching 
  14  * Each child of the root window is called a client, except windows which have 
  15  * set the override_redirect flag.  Clients are organized in a global 
  16  * linked client list, the focus history is remembered through a global 
  17  * stack list. Each client contains a bit array to indicate the tags of a 
  20  * Keys and tagging rules are organized as arrays and defined in config.h. 
  22  * To understand everything else, start reading main(). 
  32 #include <sys/types.h> 
  34 #include <X11/cursorfont.h> 
  35 #include <X11/keysym.h> 
  36 #include <X11/Xatom.h> 
  38 #include <X11/Xproto.h> 
  39 #include <X11/Xutil.h> 
  41 #include <X11/extensions/Xinerama.h> 
  45 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask) 
  46 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask)) 
  47 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) 
  48 #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags])) 
  49 #define LENGTH(X)               (sizeof X / sizeof X[0]) 
  50 #define MAX(A, B)               ((A) > (B) ? (A) : (B)) 
  51 #define MIN(A, B)               ((A) < (B) ? (A) : (B)) 
  52 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask) 
  53 #define WIDTH(X)                ((X)->w + 2 * (X)->bw) 
  54 #define HEIGHT(X)               ((X)->h + 2 * (X)->bw) 
  55 #define TAGMASK                 ((int)((1LL << LENGTH(tags)) - 1)) 
  56 #define TEXTW(X)                (textnw(X, strlen(X)) + dc.font.height) 
  59 enum { CurNormal
, CurResize
, CurMove
, CurLast 
};        /* cursor */ 
  60 enum { ColBorder
, ColFG
, ColBG
, ColLast 
};              /* color */ 
  61 enum { NetSupported
, NetWMName
, NetLast 
};              /* EWMH atoms */ 
  62 enum { WMProtocols
, WMDelete
, WMState
, WMLast 
};        /* default atoms */ 
  63 enum { ClkTagBar
, ClkLtSymbol
, ClkStatusText
, ClkWinTitle
, 
  64        ClkClientWin
, ClkRootWin
, ClkLast 
};             /* clicks */ 
  77         void (*func
)(const Arg 
*arg
); 
  81 typedef struct Monitor Monitor
; 
  82 typedef struct Client Client
; 
  87         int basew
, baseh
, incw
, inch
, maxw
, maxh
, minw
, minh
; 
  90         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
)(Monitor 
*); 
 127         int by
, btx
;          /* bar geometry */ 
 128         int my
, mh
;           /* vertical screen size*/ 
 129         int wx
, wy
, ww
, wh
;   /* window area  */ 
 130         unsigned int seltags
; 
 132         unsigned int tagset
[2]; 
 144         const char *instance
; 
 150 /* function declarations */ 
 151 static void applyrules(Client 
*c
); 
 152 static Bool 
applysizehints(Client 
*c
, int *x
, int *y
, int *w
, int *h
); 
 153 static void arrange(void); 
 154 static void attach(Client 
*c
); 
 155 static void attachstack(Client 
*c
); 
 156 static void buttonpress(XEvent 
*e
); 
 157 static void checkotherwm(void); 
 158 static void cleanup(void); 
 159 static void cleanupmons(void); 
 160 static void clearurgent(Client 
*c
); 
 161 static void configure(Client 
*c
); 
 162 static void configurenotify(XEvent 
*e
); 
 163 static void configurerequest(XEvent 
*e
); 
 164 static void destroynotify(XEvent 
*e
); 
 165 static void detach(Client 
*c
); 
 166 static void detachstack(Client 
*c
); 
 167 static void die(const char *errstr
, ...); 
 168 static void drawbar(Monitor 
*m
); 
 169 static void drawbars(); 
 170 static void drawsquare(Bool filled
, Bool empty
, Bool invert
, unsigned long col
[ColLast
]); 
 171 static void drawtext(const char *text
, unsigned long col
[ColLast
], Bool invert
); 
 172 static void enternotify(XEvent 
*e
); 
 173 static void expose(XEvent 
*e
); 
 174 static void focus(Client 
*c
); 
 175 static void focusin(XEvent 
*e
); 
 176 static void focusstack(const Arg 
*arg
); 
 177 static Client 
*getclient(Window w
); 
 178 static unsigned long getcolor(const char *colstr
); 
 179 static long getstate(Window w
); 
 180 static Bool 
gettextprop(Window w
, Atom atom
, char *text
, unsigned int size
); 
 181 static void grabbuttons(Client 
*c
, Bool focused
); 
 182 static void grabkeys(void); 
 183 static void initfont(const char *fontstr
); 
 184 static Bool 
isprotodel(Client 
*c
); 
 185 static void keypress(XEvent 
*e
); 
 186 static void killclient(const Arg 
*arg
); 
 187 static void manage(Window w
, XWindowAttributes 
*wa
); 
 188 static void mappingnotify(XEvent 
*e
); 
 189 static void maprequest(XEvent 
*e
); 
 190 static void monocle(Monitor 
*m
); 
 191 static void movemouse(const Arg 
*arg
); 
 192 static Client 
*nexttiled(Client 
*c
); 
 193 static void propertynotify(XEvent 
*e
); 
 194 static void quit(const Arg 
*arg
); 
 195 static void resize(Client 
*c
, int x
, int y
, int w
, int h
); 
 196 static void resizemouse(const Arg 
*arg
); 
 197 static void restack(Monitor 
*m
); 
 198 static void run(void); 
 199 static void scan(void); 
 200 static void setclientstate(Client 
*c
, long state
); 
 201 static void setlayout(const Arg 
*arg
); 
 202 static void setmfact(const Arg 
*arg
); 
 203 static void setup(void); 
 204 static void showhide(Client 
*c
); 
 205 static void sigchld(int signal
); 
 206 static void spawn(const Arg 
*arg
); 
 207 static void tag(const Arg 
*arg
); 
 208 static int textnw(const char *text
, unsigned int len
); 
 209 static void tile(Monitor 
*); 
 210 static void togglebar(const Arg 
*arg
); 
 211 static void togglefloating(const Arg 
*arg
); 
 212 static void toggletag(const Arg 
*arg
); 
 213 static void toggleview(const Arg 
*arg
); 
 214 static void unfocus(Client 
*c
); 
 215 static void unmanage(Client 
*c
); 
 216 static void unmapnotify(XEvent 
*e
); 
 217 static void updategeom(void); 
 218 static void updatebarpos(Monitor 
*m
); 
 219 static void updatebars(void); 
 220 static void updatenumlockmask(void); 
 221 static void updatesizehints(Client 
*c
); 
 222 static void updatestatus(void); 
 223 static void updatetitle(Client 
*c
); 
 224 static void updatewmhints(Client 
*c
); 
 225 static void view(const Arg 
*arg
); 
 226 static int xerror(Display 
*dpy
, XErrorEvent 
*ee
); 
 227 static int xerrordummy(Display 
*dpy
, XErrorEvent 
*ee
); 
 228 static int xerrorstart(Display 
*dpy
, XErrorEvent 
*ee
); 
 229 static void zoom(const Arg 
*arg
); 
 231 static void focusmon(const Arg 
*arg
); 
 232 static void tagmon(const Arg 
*arg
); 
 233 #endif /* XINERAMA */ 
 236 static char stext
[256]; 
 238 static int sx
, sy
, sw
, sh
;   /* X display screen geometry x, y, width, height */ 
 239 static int bh
, blw 
= 0;      /* bar geometry */ 
 240 static int (*xerrorxlib
)(Display 
*, XErrorEvent 
*); 
 241 static unsigned int numlockmask 
= 0; 
 242 static void (*handler
[LASTEvent
]) (XEvent 
*) = { 
 243         [ButtonPress
] = buttonpress
, 
 244         [ConfigureRequest
] = configurerequest
, 
 245         [ConfigureNotify
] = configurenotify
, 
 246         [DestroyNotify
] = destroynotify
, 
 247         [EnterNotify
] = enternotify
, 
 250         [KeyPress
] = keypress
, 
 251         [MappingNotify
] = mappingnotify
, 
 252         [MapRequest
] = maprequest
, 
 253         [PropertyNotify
] = propertynotify
, 
 254         [UnmapNotify
] = unmapnotify
 
 256 static Atom wmatom
[WMLast
], netatom
[NetLast
]; 
 258 static Bool running 
= True
; 
 259 static Cursor cursor
[CurLast
]; 
 262 static Layout 
*lt
[] = { NULL
, NULL 
}; 
 263 static Monitor 
*mons 
= NULL
, *selmon 
= NULL
; 
 265 /* configuration, allows nested code to access above variables */ 
 268 /* compile-time check if all tags fit into an unsigned int bit array. */ 
 269 struct NumTags 
{ char limitexceeded
[sizeof(unsigned int) * 8 < LENGTH(tags
) ? -1 : 1]; }; 
 271 /* function implementations */ 
 273 applyrules(Client 
*c
) { 
 276         XClassHint ch 
= { 0 }; 
 279         c
->isfloating 
= c
->tags 
= 0; 
 280         if(XGetClassHint(dpy
, c
->win
, &ch
)) { 
 281                 for(i 
= 0; i 
< LENGTH(rules
); i
++) { 
 283                         if((!r
->title 
|| strstr(c
->name
, r
->title
)) 
 284                         && (!r
->class || (ch
.res_class 
&& strstr(ch
.res_class
, r
->class))) 
 285                         && (!r
->instance 
|| (ch
.res_name 
&& strstr(ch
.res_name
, r
->instance
)))) { 
 286                                 c
->isfloating 
= r
->isfloating
; 
 295         c
->tags 
= c
->tags 
& TAGMASK 
? c
->tags 
& TAGMASK 
: c
->mon
->tagset
[c
->mon
->seltags
]; 
 299 applysizehints(Client 
*c
, int *x
, int *y
, int *w
, int *h
) { 
 302         /* set minimum possible */ 
 310         if(*x 
+ *w 
+ 2 * c
->bw 
< sx
) 
 312         if(*y 
+ *h 
+ 2 * c
->bw 
< sy
) 
 319         if(resizehints 
|| c
->isfloating
) { 
 320                 /* see last two sentences in ICCCM 4.1.2.3 */ 
 321                 baseismin 
= c
->basew 
== c
->minw 
&& c
->baseh 
== c
->minh
; 
 323                 if(!baseismin
) { /* temporarily remove base dimensions */ 
 328                 /* adjust for aspect limits */ 
 329                 if(c
->mina 
> 0 && c
->maxa 
> 0) { 
 330                         if(c
->maxa 
< (float)*w 
/ *h
) 
 332                         else if(c
->mina 
< (float)*h 
/ *w
) 
 336                 if(baseismin
) { /* increment calculation requires this */ 
 341                 /* adjust for increment value */ 
 347                 /* restore base dimensions */ 
 351                 *w 
= MAX(*w
, c
->minw
); 
 352                 *h 
= MAX(*h
, c
->minh
); 
 355                         *w 
= MIN(*w
, c
->maxw
); 
 358                         *h 
= MIN(*h
, c
->maxh
); 
 360         return *x 
!= c
->x 
|| *y 
!= c
->y 
|| *w 
!= c
->w 
|| *h 
!= c
->h
; 
 367         /* optimise two loops into one, check focus(NULL) */ 
 368         for(m 
= mons
; m
; m 
= m
->next
) 
 371         for(m 
= mons
; m
; m 
= m
->next
) { 
 372                 if(lt
[m
->sellt
]->arrange
) 
 373                         lt
[m
->sellt
]->arrange(m
); 
 380         c
->next 
= c
->mon
->clients
; 
 385 attachstack(Client 
*c
) { 
 386         c
->snext 
= c
->mon
->stack
; 
 391 buttonpress(XEvent 
*e
) { 
 392         unsigned int i
, x
, click
; 
 396         XButtonPressedEvent 
*ev 
= &e
->xbutton
; 
 399         /* focus monitor if necessary */ 
 400         for(m 
= mons
; m
; m 
= m
->next
) 
 401                 if(ev
->window 
== m
->barwin
) { 
 404                                         focus(selmon
->stack
); 
 412         if(ev
->window 
== selmon
->barwin 
&& ev
->x 
>= selmon
->btx
) { 
 417                 while(ev
->x 
>= x 
&& ++i 
< LENGTH(tags
)); 
 418                 if(i 
< LENGTH(tags
)) { 
 422                 else if(ev
->x 
< x 
+ blw
) 
 424                 else if(ev
->x 
> selmon
->wx 
+ selmon
->ww 
- TEXTW(stext
)) 
 425                         click 
= ClkStatusText
; 
 429         else if((c 
= getclient(ev
->window
))) { 
 431                 click 
= ClkClientWin
; 
 434         for(i 
= 0; i 
< LENGTH(buttons
); i
++) 
 435                 if(click 
== buttons
[i
].click 
&& buttons
[i
].func 
&& buttons
[i
].button 
== ev
->button
 
 436                    && CLEANMASK(buttons
[i
].mask
) == CLEANMASK(ev
->state
)) 
 437                         buttons
[i
].func(click 
== ClkTagBar 
&& buttons
[i
].arg
.i 
== 0 ? &arg 
: &buttons
[i
].arg
); 
 443         xerrorxlib 
= XSetErrorHandler(xerrorstart
); 
 445         /* this causes an error if some other window manager is running */ 
 446         XSelectInput(dpy
, DefaultRootWindow(dpy
), SubstructureRedirectMask
); 
 449                 die("dwm: another window manager is already running\n"); 
 450         XSetErrorHandler(xerror
); 
 457         Layout foo 
= { "", NULL 
}; 
 461         lt
[selmon
->sellt
] = &foo
; 
 463         /* TODO: consider simplifying cleanup code of the stack, perhaps do that in cleanmons() ? */ 
 464         for(m 
= mons
; m
; m 
= m
->next
) 
 468                 XFreeFontSet(dpy
, dc
.font
.set
); 
 470                 XFreeFont(dpy
, dc
.font
.xfont
); 
 471         XUngrabKey(dpy
, AnyKey
, AnyModifier
, root
); 
 472         XFreePixmap(dpy
, dc
.drawable
); 
 474         XFreeCursor(dpy
, cursor
[CurNormal
]); 
 475         XFreeCursor(dpy
, cursor
[CurResize
]); 
 476         XFreeCursor(dpy
, cursor
[CurMove
]); 
 479         XSetInputFocus(dpy
, PointerRoot
, RevertToPointerRoot
, CurrentTime
); 
 488                 XUnmapWindow(dpy
, mons
->barwin
); 
 489                 XDestroyWindow(dpy
, mons
->barwin
); 
 496 clearurgent(Client 
*c
) { 
 500         if(!(wmh 
= XGetWMHints(dpy
, c
->win
))) 
 502         wmh
->flags 
&= ~XUrgencyHint
; 
 503         XSetWMHints(dpy
, c
->win
, wmh
); 
 508 configure(Client 
*c
) { 
 511         ce
.type 
= ConfigureNotify
; 
 519         ce
.border_width 
= c
->bw
; 
 521         ce
.override_redirect 
= False
; 
 522         XSendEvent(dpy
, c
->win
, False
, StructureNotifyMask
, (XEvent 
*)&ce
); 
 526 configurenotify(XEvent 
*e
) { 
 528         XConfigureEvent 
*ev 
= &e
->xconfigure
; 
 530         if(ev
->window 
== root 
&& (ev
->width 
!= sw 
|| ev
->height 
!= sh
)) { 
 535                         XFreePixmap(dpy
, dc
.drawable
); 
 536                 dc
.drawable 
= XCreatePixmap(dpy
, root
, sw
, bh
, DefaultDepth(dpy
, screen
)); 
 538                 for(m 
= mons
; m
; m 
= m
->next
) 
 539                         XMoveResizeWindow(dpy
, m
->barwin
, m
->wx
, m
->by
, m
->ww
, bh
); 
 545 configurerequest(XEvent 
*e
) { 
 547         XConfigureRequestEvent 
*ev 
= &e
->xconfigurerequest
; 
 550         if((c 
= getclient(ev
->window
))) { 
 551                 if(ev
->value_mask 
& CWBorderWidth
) 
 552                         c
->bw 
= ev
->border_width
; 
 553                 else if(c
->isfloating 
|| !lt
[selmon
->sellt
]->arrange
) { 
 554                         if(ev
->value_mask 
& CWX
) 
 556                         if(ev
->value_mask 
& CWY
) 
 558                         if(ev
->value_mask 
& CWWidth
) 
 560                         if(ev
->value_mask 
& CWHeight
) 
 562                         if((c
->x 
- sx 
+ c
->w
) > sw 
&& c
->isfloating
) 
 563                                 c
->x 
= sx 
+ (sw 
/ 2 - c
->w 
/ 2); /* center in x direction */ 
 564                         if((c
->y 
- sy 
+ c
->h
) > sh 
&& c
->isfloating
) 
 565                                 c
->y 
= sy 
+ (sh 
/ 2 - c
->h 
/ 2); /* center in y direction */ 
 566                         if((ev
->value_mask 
& (CWX
|CWY
)) && !(ev
->value_mask 
& (CWWidth
|CWHeight
))) 
 569                                 XMoveResizeWindow(dpy
, c
->win
, c
->x
, c
->y
, c
->w
, c
->h
); 
 577                 wc
.width 
= ev
->width
; 
 578                 wc
.height 
= ev
->height
; 
 579                 wc
.border_width 
= ev
->border_width
; 
 580                 wc
.sibling 
= ev
->above
; 
 581                 wc
.stack_mode 
= ev
->detail
; 
 582                 XConfigureWindow(dpy
, ev
->window
, ev
->value_mask
, &wc
); 
 588 destroynotify(XEvent 
*e
) { 
 590         XDestroyWindowEvent 
*ev 
= &e
->xdestroywindow
; 
 592         if((c 
= getclient(ev
->window
))) 
 600         for(tc 
= &c
->mon
->clients
; *tc 
&& *tc 
!= c
; tc 
= &(*tc
)->next
); 
 605 detachstack(Client 
*c
) { 
 608         for(tc 
= &c
->mon
->stack
; *tc 
&& *tc 
!= c
; tc 
= &(*tc
)->snext
); 
 613 die(const char *errstr
, ...) { 
 616         va_start(ap
, errstr
); 
 617         vfprintf(stderr
, errstr
, ap
); 
 623 drawbar(Monitor 
*m
) { 
 625         unsigned int i
, occ 
= 0, urg 
= 0; 
 629         for(c 
= m
->clients
; c
; c 
= c
->next
) { 
 639                 buf
[0] = m
->screen_number 
+ '0'; 
 642                 drawtext(buf
, selmon 
== m 
? dc
.sel 
: dc
.norm
, True
); 
 645 #endif /* XINERAMA */ 
 647         for(i 
= 0; i 
< LENGTH(tags
); i
++) { 
 648                 dc
.w 
= TEXTW(tags
[i
]); 
 649                 col 
= m
->tagset
[m
->seltags
] & 1 << i 
? dc
.sel 
: dc
.norm
; 
 650                 drawtext(tags
[i
], col
, urg 
& 1 << i
); 
 651                 drawsquare(m 
== selmon 
&& selmon
->sel 
&& selmon
->sel
->tags 
& 1 << i
, 
 652                            occ 
& 1 << i
, urg 
& 1 << i
, col
); 
 657                 drawtext(lt
[m
->sellt
]->symbol
, dc
.norm
, False
); 
 662         if(m 
== selmon
) { /* status is only drawn on selected monitor */ 
 669                 drawtext(stext
, dc
.norm
, False
); 
 674         if((dc
.w 
= dc
.x 
- x
) > bh
) { 
 677                         col 
= m 
== selmon 
? dc
.sel 
: dc
.norm
; 
 678                         drawtext(m
->sel
->name
, col
, False
); 
 679                         drawsquare(m
->sel
->isfixed
, m
->sel
->isfloating
, False
, col
); 
 682                         drawtext(NULL
, dc
.norm
, False
); 
 684         XCopyArea(dpy
, dc
.drawable
, m
->barwin
, dc
.gc
, 0, 0, m
->ww
, bh
, 0, 0); 
 692         for(m 
= mons
; m
; m 
= m
->next
) 
 697 drawsquare(Bool filled
, Bool empty
, Bool invert
, unsigned long col
[ColLast
]) { 
 700         XRectangle r 
= { dc
.x
, dc
.y
, dc
.w
, dc
.h 
}; 
 702         gcv
.foreground 
= col
[invert 
? ColBG 
: ColFG
]; 
 703         XChangeGC(dpy
, dc
.gc
, GCForeground
, &gcv
); 
 704         x 
= (dc
.font
.ascent 
+ dc
.font
.descent 
+ 2) / 4; 
 708                 r
.width 
= r
.height 
= x 
+ 1; 
 709                 XFillRectangles(dpy
, dc
.drawable
, dc
.gc
, &r
, 1); 
 712                 r
.width 
= r
.height 
= x
; 
 713                 XDrawRectangles(dpy
, dc
.drawable
, dc
.gc
, &r
, 1); 
 718 drawtext(const char *text
, unsigned long col
[ColLast
], Bool invert
) { 
 720         int i
, x
, y
, h
, len
, olen
; 
 721         XRectangle r 
= { dc
.x
, dc
.y
, dc
.w
, dc
.h 
}; 
 723         XSetForeground(dpy
, dc
.gc
, col
[invert 
? ColFG 
: ColBG
]); 
 724         XFillRectangles(dpy
, dc
.drawable
, dc
.gc
, &r
, 1); 
 728         h 
= dc
.font
.ascent 
+ dc
.font
.descent
; 
 729         y 
= dc
.y 
+ (dc
.h 
/ 2) - (h 
/ 2) + dc
.font
.ascent
; 
 731         /* shorten text if necessary */ 
 732         for(len 
= MIN(olen
, sizeof buf
); len 
&& textnw(text
, len
) > dc
.w 
- h
; len
--); 
 735         memcpy(buf
, text
, len
); 
 737                 for(i 
= len
; i 
&& i 
> len 
- 3; buf
[--i
] = '.'); 
 738         XSetForeground(dpy
, dc
.gc
, col
[invert 
? ColBG 
: ColFG
]); 
 740                 XmbDrawString(dpy
, dc
.drawable
, dc
.font
.set
, dc
.gc
, x
, y
, buf
, len
); 
 742                 XDrawString(dpy
, dc
.drawable
, dc
.gc
, x
, y
, buf
, len
); 
 746 enternotify(XEvent 
*e
) { 
 748         XCrossingEvent 
*ev 
= &e
->xcrossing
; 
 750         if((ev
->mode 
!= NotifyNormal 
|| ev
->detail 
== NotifyInferior
) && ev
->window 
!= root
) 
 752         if((c 
= getclient(ev
->window
))) 
 761         XExposeEvent 
*ev 
= &e
->xexpose
; 
 764                 for(m 
= mons
; m
; m 
= m
->next
) 
 765                         if(ev
->window 
== m
->barwin
) { 
 773         if(!c 
|| !ISVISIBLE(c
)) 
 774                 for(c 
= selmon
->stack
; c 
&& !ISVISIBLE(c
); c 
= c
->snext
); 
 776                 unfocus(selmon
->sel
); 
 784                 grabbuttons(c
, True
); 
 785                 XSetWindowBorder(dpy
, c
->win
, dc
.sel
[ColBorder
]); 
 786                 XSetInputFocus(dpy
, c
->win
, RevertToPointerRoot
, CurrentTime
); 
 789                 XSetInputFocus(dpy
, root
, RevertToPointerRoot
, CurrentTime
); 
 795 focusin(XEvent 
*e
) { /* there are some broken focus acquiring clients */ 
 796         XFocusChangeEvent 
*ev 
= &e
->xfocus
; 
 798         if(selmon
->sel 
&& ev
->window 
!= selmon
->sel
->win
) 
 799                 XSetInputFocus(dpy
, selmon
->sel
->win
, RevertToPointerRoot
, CurrentTime
); 
 804 focusmon(const Arg 
*arg
) { 
 808         for(i 
= 0, m 
= mons
; m
; m 
= m
->next
, i
++) 
 813                                 unfocus(selmon
->stack
); 
 821 #endif /* XINERAMA */ 
 824 focusstack(const Arg 
*arg
) { 
 825         Client 
*c 
= NULL
, *i
; 
 830                 for(c 
= selmon
->sel
->next
; c 
&& !ISVISIBLE(c
); c 
= c
->next
); 
 832                         for(c 
= selmon
->clients
; c 
&& !ISVISIBLE(c
); c 
= c
->next
); 
 835                 for(i 
= selmon
->clients
; i 
!= selmon
->sel
; i 
= i
->next
) 
 839                         for(; i
; i 
= i
->next
) 
 850 getclient(Window w
) { 
 854         for(m 
= mons
; m
; m 
= m
->next
) 
 855                 for(c 
= m
->clients
; c
; c 
= c
->next
) 
 862 getcolor(const char *colstr
) { 
 863         Colormap cmap 
= DefaultColormap(dpy
, screen
); 
 866         if(!XAllocNamedColor(dpy
, cmap
, colstr
, &color
, &color
)) 
 867                 die("error, cannot allocate color '%s'\n", colstr
); 
 875         unsigned char *p 
= NULL
; 
 876         unsigned long n
, extra
; 
 879         status 
= XGetWindowProperty(dpy
, w
, wmatom
[WMState
], 0L, 2L, False
, wmatom
[WMState
], 
 880                         &real
, &format
, &n
, &extra
, (unsigned char **)&p
); 
 881         if(status 
!= Success
) 
 890 gettextprop(Window w
, Atom atom
, char *text
, unsigned int size
) { 
 895         if(!text 
|| size 
== 0) 
 898         XGetTextProperty(dpy
, w
, &name
, atom
); 
 901         if(name
.encoding 
== XA_STRING
) 
 902                 strncpy(text
, (char *)name
.value
, size 
- 1); 
 904                 if(XmbTextPropertyToTextList(dpy
, &name
, &list
, &n
) >= Success
 
 906                         strncpy(text
, *list
, size 
- 1); 
 907                         XFreeStringList(list
); 
 910         text
[size 
- 1] = '\0'; 
 916 grabbuttons(Client 
*c
, Bool focused
) { 
 920                 unsigned int modifiers
[] = { 0, LockMask
, numlockmask
, numlockmask
|LockMask 
}; 
 921                 XUngrabButton(dpy
, AnyButton
, AnyModifier
, c
->win
); 
 923                         for(i 
= 0; i 
< LENGTH(buttons
); i
++) 
 924                                 if(buttons
[i
].click 
== ClkClientWin
) 
 925                                         for(j 
= 0; j 
< LENGTH(modifiers
); j
++) 
 926                                                 XGrabButton(dpy
, buttons
[i
].button
, 
 927                                                             buttons
[i
].mask 
| modifiers
[j
], 
 928                                                             c
->win
, False
, BUTTONMASK
, 
 929                                                             GrabModeAsync
, GrabModeSync
, None
, None
); 
 931                         XGrabButton(dpy
, AnyButton
, AnyModifier
, c
->win
, False
, 
 932                                     BUTTONMASK
, GrabModeAsync
, GrabModeSync
, None
, None
); 
 941                 unsigned int modifiers
[] = { 0, LockMask
, numlockmask
, numlockmask
|LockMask 
}; 
 944                 XUngrabKey(dpy
, AnyKey
, AnyModifier
, root
); 
 945                 for(i 
= 0; i 
< LENGTH(keys
); i
++) { 
 946                         if((code 
= XKeysymToKeycode(dpy
, keys
[i
].keysym
))) 
 947                                 for(j 
= 0; j 
< LENGTH(modifiers
); j
++) 
 948                                         XGrabKey(dpy
, code
, keys
[i
].mod 
| modifiers
[j
], root
, 
 949                                                  True
, GrabModeAsync
, GrabModeAsync
); 
 955 initfont(const char *fontstr
) { 
 956         char *def
, **missing
; 
 960         dc
.font
.set 
= XCreateFontSet(dpy
, fontstr
, &missing
, &n
, &def
); 
 963                         fprintf(stderr
, "dwm: missing fontset: %s\n", missing
[n
]); 
 964                 XFreeStringList(missing
); 
 967                 XFontSetExtents 
*font_extents
; 
 968                 XFontStruct 
**xfonts
; 
 970                 dc
.font
.ascent 
= dc
.font
.descent 
= 0; 
 971                 font_extents 
= XExtentsOfFontSet(dc
.font
.set
); 
 972                 n 
= XFontsOfFontSet(dc
.font
.set
, &xfonts
, &font_names
); 
 973                 for(i 
= 0, dc
.font
.ascent 
= 0, dc
.font
.descent 
= 0; i 
< n
; i
++) { 
 974                         dc
.font
.ascent 
= MAX(dc
.font
.ascent
, (*xfonts
)->ascent
); 
 975                         dc
.font
.descent 
= MAX(dc
.font
.descent
,(*xfonts
)->descent
); 
 980                 if(!(dc
.font
.xfont 
= XLoadQueryFont(dpy
, fontstr
)) 
 981                 && !(dc
.font
.xfont 
= XLoadQueryFont(dpy
, "fixed"))) 
 982                         die("error, cannot load font: '%s'\n", fontstr
); 
 983                 dc
.font
.ascent 
= dc
.font
.xfont
->ascent
; 
 984                 dc
.font
.descent 
= dc
.font
.xfont
->descent
; 
 986         dc
.font
.height 
= dc
.font
.ascent 
+ dc
.font
.descent
; 
 990 isprotodel(Client 
*c
) { 
 995         if(XGetWMProtocols(dpy
, c
->win
, &protocols
, &n
)) { 
 996                 for(i 
= 0; !ret 
&& i 
< n
; i
++) 
 997                         if(protocols
[i
] == wmatom
[WMDelete
]) 
1005 keypress(XEvent 
*e
) { 
1011         keysym 
= XKeycodeToKeysym(dpy
, (KeyCode
)ev
->keycode
, 0); 
1012         for(i 
= 0; i 
< LENGTH(keys
); i
++) 
1013                 if(keysym 
== keys
[i
].keysym
 
1014                    && CLEANMASK(keys
[i
].mod
) == CLEANMASK(ev
->state
) 
1016                         keys
[i
].func(&(keys
[i
].arg
)); 
1020 killclient(const Arg 
*arg
) { 
1025         if(isprotodel(selmon
->sel
)) { 
1026                 ev
.type 
= ClientMessage
; 
1027                 ev
.xclient
.window 
= selmon
->sel
->win
; 
1028                 ev
.xclient
.message_type 
= wmatom
[WMProtocols
]; 
1029                 ev
.xclient
.format 
= 32; 
1030                 ev
.xclient
.data
.l
[0] = wmatom
[WMDelete
]; 
1031                 ev
.xclient
.data
.l
[1] = CurrentTime
; 
1032                 XSendEvent(dpy
, selmon
->sel
->win
, False
, NoEventMask
, &ev
); 
1035                 XKillClient(dpy
, selmon
->sel
->win
); 
1039 manage(Window w
, XWindowAttributes 
*wa
) { 
1041         Client 
*c
, *t 
= NULL
; 
1042         Window trans 
= None
; 
1045         if(!(c 
= malloc(sizeof(Client
)))) 
1046                 die("fatal: could not malloc() %u bytes\n", sizeof(Client
)); 
1056         c
->oldbw 
= wa
->border_width
; 
1057         if(c
->w 
== sw 
&& c
->h 
== sh
) { 
1063                 if(c
->x 
+ WIDTH(c
) > sx 
+ sw
) 
1064                         c
->x 
= sx 
+ sw 
- WIDTH(c
); 
1065                 if(c
->y 
+ HEIGHT(c
) > sy 
+ sh
) 
1066                         c
->y 
= sy 
+ sh 
- HEIGHT(c
); 
1067                 c
->x 
= MAX(c
->x
, sx
); 
1068                 /* only fix client y-offset, if the client center might cover the bar */ 
1069                 c
->y 
= MAX(c
->y
, ((c
->mon
->by 
== 0) && (c
->x 
+ (c
->w 
/ 2) >= c
->mon
->wx
) 
1070                            && (c
->x 
+ (c
->w 
/ 2) < c
->mon
->wx 
+ c
->mon
->ww
)) ? bh 
: sy
); 
1074         wc
.border_width 
= c
->bw
; 
1075         XConfigureWindow(dpy
, w
, CWBorderWidth
, &wc
); 
1076         XSetWindowBorder(dpy
, w
, dc
.norm
[ColBorder
]); 
1077         configure(c
); /* propagates border_width, if size doesn't change */ 
1079         XSelectInput(dpy
, w
, EnterWindowMask
|FocusChangeMask
|PropertyChangeMask
|StructureNotifyMask
); 
1080         grabbuttons(c
, False
); 
1082         if(XGetTransientForHint(dpy
, w
, &trans
)) 
1083                 t 
= getclient(trans
); 
1089                 c
->isfloating 
= trans 
!= None 
|| c
->isfixed
; 
1091                 XRaiseWindow(dpy
, c
->win
); 
1094         XMoveResizeWindow(dpy
, c
->win
, c
->x 
+ 2 * sw
, c
->y
, c
->w
, c
->h
); /* some windows require this */ 
1095         XMapWindow(dpy
, c
->win
); 
1096         setclientstate(c
, NormalState
); 
1101 mappingnotify(XEvent 
*e
) { 
1102         XMappingEvent 
*ev 
= &e
->xmapping
; 
1104         XRefreshKeyboardMapping(ev
); 
1105         if(ev
->request 
== MappingKeyboard
) 
1110 maprequest(XEvent 
*e
) { 
1111         static XWindowAttributes wa
; 
1112         XMapRequestEvent 
*ev 
= &e
->xmaprequest
; 
1114         if(!XGetWindowAttributes(dpy
, ev
->window
, &wa
)) 
1116         if(wa
.override_redirect
) 
1118         if(!getclient(ev
->window
)) 
1119                 manage(ev
->window
, &wa
); 
1123 monocle(Monitor 
*m
) { 
1126         for(c 
= nexttiled(m
->clients
); c
; c 
= nexttiled(c
->next
)) 
1127                 resize(c
, m
->wx
, m
->wy
, m
->ww 
- 2 * c
->bw
, m
->wh 
- 2 * c
->bw
); 
1131 movemouse(const Arg 
*arg
) { 
1132         int x
, y
, ocx
, ocy
, di
, nx
, ny
; 
1138         if(!(c 
= selmon
->sel
)) 
1143         if(XGrabPointer(dpy
, root
, False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
, 
1144         None
, cursor
[CurMove
], CurrentTime
) != GrabSuccess
) 
1146         XQueryPointer(dpy
, root
, &dummy
, &dummy
, &x
, &y
, &di
, &di
, &dui
); 
1148                 XMaskEvent(dpy
, MOUSEMASK
|ExposureMask
|SubstructureRedirectMask
, &ev
); 
1150                 case ConfigureRequest
: 
1153                         handler
[ev
.type
](&ev
); 
1156                         nx 
= ocx 
+ (ev
.xmotion
.x 
- x
); 
1157                         ny 
= ocy 
+ (ev
.xmotion
.y 
- y
); 
1158                         if(snap 
&& nx 
>= selmon
->wx 
&& nx 
<= selmon
->wx 
+ selmon
->ww
 
1159                                 && ny 
>= selmon
->wy 
&& ny 
<= selmon
->wy 
+ selmon
->wh
) { 
1160                                 if(abs(selmon
->wx 
- nx
) < snap
) 
1162                                 else if(abs((selmon
->wx 
+ selmon
->ww
) - (nx 
+ WIDTH(c
))) < snap
) 
1163                                         nx 
= selmon
->wx 
+ selmon
->ww 
- WIDTH(c
); 
1164                                 if(abs(selmon
->wy 
- ny
) < snap
) 
1166                                 else if(abs((selmon
->wy 
+ selmon
->wh
) - (ny 
+ HEIGHT(c
))) < snap
) 
1167                                         ny 
= selmon
->wy 
+ selmon
->wh 
- HEIGHT(c
); 
1168                                 if(!c
->isfloating 
&& lt
[selmon
->sellt
]->arrange
 
1169                                                   && (abs(nx 
- c
->x
) > snap 
|| abs(ny 
- c
->y
) > snap
)) 
1170                                         togglefloating(NULL
); 
1172                         if(!lt
[selmon
->sellt
]->arrange 
|| c
->isfloating
) 
1173                                 resize(c
, nx
, ny
, c
->w
, c
->h
); 
1177         while(ev
.type 
!= ButtonRelease
); 
1178         XUngrabPointer(dpy
, CurrentTime
); 
1182 nexttiled(Client 
*c
) { 
1183         for(; c 
&& (c
->isfloating 
|| !ISVISIBLE(c
)); c 
= c
->next
); 
1188 propertynotify(XEvent 
*e
) { 
1191         XPropertyEvent 
*ev 
= &e
->xproperty
; 
1193         if((ev
->window 
== root
) && (ev
->atom 
== XA_WM_NAME
)) 
1195         else if(ev
->state 
== PropertyDelete
) 
1196                 return; /* ignore */ 
1197         else if((c 
= getclient(ev
->window
))) { 
1200                 case XA_WM_TRANSIENT_FOR
: 
1201                         XGetTransientForHint(dpy
, c
->win
, &trans
); 
1202                         if(!c
->isfloating 
&& (c
->isfloating 
= (getclient(trans
) != NULL
))) 
1205                 case XA_WM_NORMAL_HINTS
: 
1213                 if(ev
->atom 
== XA_WM_NAME 
|| ev
->atom 
== netatom
[NetWMName
]) { 
1215                         if(c 
== selmon
->sel
) 
1222 quit(const Arg 
*arg
) { 
1227 resize(Client 
*c
, int x
, int y
, int w
, int h
) { 
1230         if(applysizehints(c
, &x
, &y
, &w
, &h
)) { 
1233                 c
->w 
= wc
.width 
= w
; 
1234                 c
->h 
= wc
.height 
= h
; 
1235                 wc
.border_width 
= c
->bw
; 
1236                 XConfigureWindow(dpy
, c
->win
, CWX
|CWY
|CWWidth
|CWHeight
|CWBorderWidth
, &wc
); 
1243 resizemouse(const Arg 
*arg
) { 
1249         if(!(c 
= selmon
->sel
)) 
1254         if(XGrabPointer(dpy
, root
, False
, MOUSEMASK
, GrabModeAsync
, GrabModeAsync
, 
1255         None
, cursor
[CurResize
], CurrentTime
) != GrabSuccess
) 
1257         XWarpPointer(dpy
, None
, c
->win
, 0, 0, 0, 0, c
->w 
+ c
->bw 
- 1, c
->h 
+ c
->bw 
- 1); 
1259                 XMaskEvent(dpy
, MOUSEMASK
|ExposureMask
|SubstructureRedirectMask
, &ev
); 
1261                 case ConfigureRequest
: 
1264                         handler
[ev
.type
](&ev
); 
1267                         nw 
= MAX(ev
.xmotion
.x 
- ocx 
- 2 * c
->bw 
+ 1, 1); 
1268                         nh 
= MAX(ev
.xmotion
.y 
- ocy 
- 2 * c
->bw 
+ 1, 1); 
1270                         if(snap 
&& nw 
>= selmon
->wx 
&& nw 
<= selmon
->wx 
+ selmon
->ww
 
1271                                 && nh 
>= selmon
->wy 
&& nh 
<= selmon
->wy 
+ selmon
->wh
) { 
1272                                 if(!c
->isfloating 
&& lt
[selmon
->sellt
]->arrange
 
1273                                    && (abs(nw 
- c
->w
) > snap 
|| abs(nh 
- c
->h
) > snap
)) 
1274                                         togglefloating(NULL
); 
1276                         if(!lt
[selmon
->sellt
]->arrange 
|| c
->isfloating
) 
1277                                 resize(c
, c
->x
, c
->y
, nw
, nh
); 
1281         while(ev
.type 
!= ButtonRelease
); 
1282         XWarpPointer(dpy
, None
, c
->win
, 0, 0, 0, 0, c
->w 
+ c
->bw 
- 1, c
->h 
+ c
->bw 
- 1); 
1283         XUngrabPointer(dpy
, CurrentTime
); 
1284         while(XCheckMaskEvent(dpy
, EnterWindowMask
, &ev
)); 
1288 restack(Monitor 
*m
) { 
1296         if(m
->sel
->isfloating 
|| !lt
[m
->sellt
]->arrange
) 
1297                 XRaiseWindow(dpy
, m
->sel
->win
); 
1298         if(lt
[m
->sellt
]->arrange
) { 
1299                 wc
.stack_mode 
= Below
; 
1300                 wc
.sibling 
= m
->barwin
; 
1301                 for(c 
= m
->stack
; c
; c 
= c
->snext
) 
1302                         if(!c
->isfloating 
&& ISVISIBLE(c
)) { 
1303                                 XConfigureWindow(dpy
, c
->win
, CWSibling
|CWStackMode
, &wc
); 
1304                                 wc
.sibling 
= c
->win
; 
1308         while(XCheckMaskEvent(dpy
, EnterWindowMask
, &ev
)); 
1315         /* main event loop */ 
1317         while(running 
&& !XNextEvent(dpy
, &ev
)) { 
1318                 if(handler
[ev
.type
]) 
1319                         (handler
[ev
.type
])(&ev
); /* call handler */ 
1325         unsigned int i
, num
; 
1326         Window d1
, d2
, *wins 
= NULL
; 
1327         XWindowAttributes wa
; 
1329         if(XQueryTree(dpy
, root
, &d1
, &d2
, &wins
, &num
)) { 
1330                 for(i 
= 0; i 
< num
; i
++) { 
1331                         if(!XGetWindowAttributes(dpy
, wins
[i
], &wa
) 
1332                         || wa
.override_redirect 
|| XGetTransientForHint(dpy
, wins
[i
], &d1
)) 
1334                         if(wa
.map_state 
== IsViewable 
|| getstate(wins
[i
]) == IconicState
) 
1335                                 manage(wins
[i
], &wa
); 
1337                 for(i 
= 0; i 
< num
; i
++) { /* now the transients */ 
1338                         if(!XGetWindowAttributes(dpy
, wins
[i
], &wa
)) 
1340                         if(XGetTransientForHint(dpy
, wins
[i
], &d1
) 
1341                         && (wa
.map_state 
== IsViewable 
|| getstate(wins
[i
]) == IconicState
)) 
1342                                 manage(wins
[i
], &wa
); 
1350 setclientstate(Client 
*c
, long state
) { 
1351         long data
[] = {state
, None
}; 
1353         XChangeProperty(dpy
, c
->win
, wmatom
[WMState
], wmatom
[WMState
], 32, 
1354                         PropModeReplace
, (unsigned char *)data
, 2); 
1358 setlayout(const Arg 
*arg
) { 
1359         if(!arg 
|| !arg
->v 
|| arg
->v 
!= lt
[selmon
->sellt
]) 
1362                 lt
[selmon
->sellt
] = (Layout 
*)arg
->v
; 
1369 /* arg > 1.0 will set mfact absolutly */ 
1371 setmfact(const Arg 
*arg
) { 
1374         if(!arg 
|| !lt
[selmon
->sellt
]->arrange
) 
1376         f 
= arg
->f 
< 1.0 ? arg
->f 
+ selmon
->mfact 
: arg
->f 
- 1.0; 
1377         if(f 
< 0.1 || f 
> 0.9) 
1387         XSetWindowAttributes wa
; 
1390         screen 
= DefaultScreen(dpy
); 
1391         root 
= RootWindow(dpy
, screen
); 
1395         sw 
= DisplayWidth(dpy
, screen
); 
1396         sh 
= DisplayHeight(dpy
, screen
); 
1397         bh 
= dc
.h 
= dc
.font
.height 
+ 2; 
1398         lt
[0] = &layouts
[0]; 
1399         lt
[1] = &layouts
[1 % LENGTH(layouts
)]; 
1403         wmatom
[WMProtocols
] = XInternAtom(dpy
, "WM_PROTOCOLS", False
); 
1404         wmatom
[WMDelete
] = XInternAtom(dpy
, "WM_DELETE_WINDOW", False
); 
1405         wmatom
[WMState
] = XInternAtom(dpy
, "WM_STATE", False
); 
1406         netatom
[NetSupported
] = XInternAtom(dpy
, "_NET_SUPPORTED", False
); 
1407         netatom
[NetWMName
] = XInternAtom(dpy
, "_NET_WM_NAME", False
); 
1410         cursor
[CurNormal
] = XCreateFontCursor(dpy
, XC_left_ptr
); 
1411         cursor
[CurResize
] = XCreateFontCursor(dpy
, XC_sizing
); 
1412         cursor
[CurMove
] = XCreateFontCursor(dpy
, XC_fleur
); 
1414         /* init appearance */ 
1415         dc
.norm
[ColBorder
] = getcolor(normbordercolor
); 
1416         dc
.norm
[ColBG
] = getcolor(normbgcolor
); 
1417         dc
.norm
[ColFG
] = getcolor(normfgcolor
); 
1418         dc
.sel
[ColBorder
] = getcolor(selbordercolor
); 
1419         dc
.sel
[ColBG
] = getcolor(selbgcolor
); 
1420         dc
.sel
[ColFG
] = getcolor(selfgcolor
); 
1421         dc
.drawable 
= XCreatePixmap(dpy
, root
, DisplayWidth(dpy
, screen
), bh
, DefaultDepth(dpy
, screen
)); 
1422         dc
.gc 
= XCreateGC(dpy
, root
, 0, NULL
); 
1423         XSetLineAttributes(dpy
, dc
.gc
, 1, LineSolid
, CapButt
, JoinMiter
); 
1425                 XSetFont(dpy
, dc
.gc
, dc
.font
.xfont
->fid
); 
1428         for(blw 
= i 
= 0; LENGTH(layouts
) > 1 && i 
< LENGTH(layouts
); i
++) { 
1429                 w 
= TEXTW(layouts
[i
].symbol
); 
1435         /* EWMH support per view */ 
1436         XChangeProperty(dpy
, root
, netatom
[NetSupported
], XA_ATOM
, 32, 
1437                         PropModeReplace
, (unsigned char *) netatom
, NetLast
); 
1439         /* select for events */ 
1440         wa
.cursor 
= cursor
[CurNormal
]; 
1441         wa
.event_mask 
= SubstructureRedirectMask
|SubstructureNotifyMask
|ButtonPressMask
 
1442                         |EnterWindowMask
|LeaveWindowMask
|StructureNotifyMask
 
1443                         |PropertyChangeMask
; 
1444         XChangeWindowAttributes(dpy
, root
, CWEventMask
|CWCursor
, &wa
); 
1445         XSelectInput(dpy
, root
, wa
.event_mask
); 
1451 showhide(Client 
*c
) { 
1454         if(ISVISIBLE(c
)) { /* show clients top down */ 
1455                 XMoveWindow(dpy
, c
->win
, c
->x
, c
->y
); 
1456                 if(!lt
[c
->mon
->sellt
]->arrange 
|| c
->isfloating
) 
1457                         resize(c
, c
->x
, c
->y
, c
->w
, c
->h
); 
1460         else { /* hide clients bottom up */ 
1462                 XMoveWindow(dpy
, c
->win
, c
->x 
+ 2 * sw
, c
->y
); 
1468 sigchld(int signal
) { 
1469         while(0 < waitpid(-1, NULL
, WNOHANG
)); 
1473 spawn(const Arg 
*arg
) { 
1474         signal(SIGCHLD
, sigchld
); 
1477                         close(ConnectionNumber(dpy
)); 
1479                 execvp(((char **)arg
->v
)[0], (char **)arg
->v
); 
1480                 fprintf(stderr
, "dwm: execvp %s", ((char **)arg
->v
)[0]); 
1487 tag(const Arg 
*arg
) { 
1488         if(selmon
->sel 
&& arg
->ui 
& TAGMASK
) { 
1489                 selmon
->sel
->tags 
= arg
->ui 
& TAGMASK
; 
1496 tagmon(const Arg 
*arg
) { 
1501         if(!(c 
= selmon
->sel
)) 
1503         for(i 
= 0, m 
= mons
; m
; m 
= m
->next
, i
++) 
1510                         selmon
->sel 
= selmon
->stack
; 
1516 #endif /* XINERAMA */ 
1519 textnw(const char *text
, unsigned int len
) { 
1523                 XmbTextExtents(dc
.font
.set
, text
, len
, NULL
, &r
); 
1526         return XTextWidth(dc
.font
.xfont
, text
, len
); 
1535         for(n 
= 0, c 
= nexttiled(m
->clients
); c
; c 
= nexttiled(c
->next
), n
++); 
1540         c 
= nexttiled(m
->clients
); 
1541         mw 
= m
->mfact 
* m
->ww
; 
1542         resize(c
, m
->wx
, m
->wy
, (n 
== 1 ? m
->ww 
: mw
) - 2 * c
->bw
, m
->wh 
- 2 * c
->bw
); 
1548         x 
= (m
->wx 
+ mw 
> c
->x 
+ c
->w
) ? c
->x 
+ c
->w 
+ 2 * c
->bw 
: m
->wx 
+ mw
; 
1550         w 
= (m
->wx 
+ mw 
> c
->x 
+ c
->w
) ? m
->wx 
+ m
->ww 
- x 
: m
->ww 
- mw
; 
1555         for(i 
= 0, c 
= nexttiled(c
->next
); c
; c 
= nexttiled(c
->next
), i
++) { 
1556                 resize(c
, x
, y
, w 
- 2 * c
->bw
, /* remainder */ ((i 
+ 1 == n
) 
1557                        ? m
->wy 
+ m
->wh 
- y 
- 2 * c
->bw 
: h 
- 2 * c
->bw
)); 
1559                         y 
= c
->y 
+ HEIGHT(c
); 
1564 togglebar(const Arg 
*arg
) { 
1565         selmon
->showbar 
= !selmon
->showbar
; 
1566         updatebarpos(selmon
); 
1567         XMoveResizeWindow(dpy
, selmon
->barwin
, selmon
->wx
, selmon
->by
, selmon
->ww
, bh
); 
1572 togglefloating(const Arg 
*arg
) { 
1575         selmon
->sel
->isfloating 
= !selmon
->sel
->isfloating 
|| selmon
->sel
->isfixed
; 
1576         if(selmon
->sel
->isfloating
) 
1577                 resize(selmon
->sel
, selmon
->sel
->x
, selmon
->sel
->y
, selmon
->sel
->w
, selmon
->sel
->h
); 
1582 toggletag(const Arg 
*arg
) { 
1588         mask 
= selmon
->sel
->tags 
^ (arg
->ui 
& TAGMASK
); 
1590                 selmon
->sel
->tags 
= mask
; 
1596 toggleview(const Arg 
*arg
) { 
1597         unsigned int mask 
= selmon
->tagset
[selmon
->seltags
] ^ (arg
->ui 
& TAGMASK
); 
1600                 selmon
->tagset
[selmon
->seltags
] = mask
; 
1606 unfocus(Client 
*c
) { 
1609         grabbuttons(c
, False
); 
1610         XSetWindowBorder(dpy
, c
->win
, dc
.norm
[ColBorder
]); 
1614 unmanage(Client 
*c
) { 
1617         wc
.border_width 
= c
->oldbw
; 
1618         /* The server grab construct avoids race conditions. */ 
1620         XSetErrorHandler(xerrordummy
); 
1621         XConfigureWindow(dpy
, c
->win
, CWBorderWidth
, &wc
); /* restore border */ 
1624         if(c
->mon
->sel 
== c
) { 
1625                 c
->mon
->sel 
= c
->mon
->stack
; 
1628         XUngrabButton(dpy
, AnyButton
, AnyModifier
, c
->win
); 
1629         setclientstate(c
, WithdrawnState
); 
1632         XSetErrorHandler(xerror
); 
1638 unmapnotify(XEvent 
*e
) { 
1640         XUnmapEvent 
*ev 
= &e
->xunmap
; 
1642         if((c 
= getclient(ev
->window
))) 
1649         XSetWindowAttributes wa
; 
1651         wa
.override_redirect 
= True
; 
1652         wa
.background_pixmap 
= ParentRelative
; 
1653         wa
.event_mask 
= ButtonPressMask
|ExposureMask
; 
1655         for(m 
= mons
; m
; m 
= m
->next
) { 
1656                 m
->barwin 
= XCreateWindow(dpy
, root
, m
->wx
, m
->by
, m
->ww
, bh
, 0, DefaultDepth(dpy
, screen
), 
1658                                           CopyFromParent
, DefaultVisual(dpy
, screen
), 
1659                                           CWOverrideRedirect
|CWBackPixmap
|CWEventMask
, &wa
); 
1660                 XDefineCursor(dpy
, m
->barwin
, cursor
[CurNormal
]); 
1661                 XMapRaised(dpy
, m
->barwin
); 
1666 updatebarpos(Monitor 
*m
) { 
1671                 m
->by 
= m
->topbar 
? m
->wy 
: m
->wy 
+ m
->wh
; 
1672                 m
->wy 
= m
->topbar 
? m
->wy 
+ bh 
: m
->wy
; 
1680         int i
, di
, n 
= 1, x
, y
; 
1683         Monitor 
*newmons 
= NULL
, *m
, *tm
; 
1688 #elif defined(XINERAMA) 
1689         XineramaScreenInfo 
*info 
= NULL
; 
1691         if(XineramaIsActive(dpy
)) 
1692                 info 
= XineramaQueryScreens(dpy
, &n
); 
1694         /* allocate monitor(s) for the new geometry setup */ 
1695         for(i 
= 0; i 
< n
; i
++) { 
1696                 m 
= (Monitor 
*)malloc(sizeof(Monitor
)); 
1701         /* initialise monitor(s) */ 
1705                 m
->screen_number 
= 0; 
1709                 m
->mh 
= m
->wh 
= sh 
/ 2; 
1711                 m
->screen_number 
= 1; 
1713                 m
->my 
= m
->wy 
= sy 
+ sh 
/ 2; 
1715                 m
->mh 
= m
->wh 
= sh 
/ 2; 
1718 #elif defined(XINERAMA) 
1719         if(XineramaIsActive(dpy
)) { 
1720                 for(i 
= 0, m 
= newmons
; m
; m 
= m
->next
, i
++) { 
1721                         m
->screen_number 
= info
[i
].screen_number
; 
1722                         m
->wx 
= info
[i
].x_org
; 
1723                         m
->my 
= m
->wy 
= info
[i
].y_org
; 
1724                         m
->ww 
= info
[i
].width
; 
1725                         m
->mh 
= m
->wh 
= info
[i
].height
; 
1731         /* default monitor setup */ 
1733                 m
->screen_number 
= 0; 
1740         /* bar geometry setup */ 
1741         for(m 
= newmons
; m
; m 
= m
->next
) { 
1742                 /* TODO: consider removing the following values from config.h */ 
1748                 m
->tagset
[0] = m
->tagset
[1] = 1; 
1750                 m
->showbar 
= showbar
; 
1755         /* reassign left over clients of disappeared monitors */ 
1756         for(tm 
= mons
; tm
; tm 
= tm
->next
) 
1757                 while(tm
->clients
) { 
1759                         tm
->clients 
= c
->next
; 
1766         /* select focused monitor */ 
1768         if(XQueryPointer(dpy
, root
, &dummy
, &dummy
, &x
, &y
, &di
, &di
, &dui
))  
1769                 for(m 
= newmons
; m
; m 
= m
->next
) 
1770                         if(INRECT(x
, y
, m
->wx
, m
->wy
, m
->ww
, m
->wh
)) { 
1775         /* final assignment of new monitors */ 
1781 updatenumlockmask(void) { 
1783         XModifierKeymap 
*modmap
; 
1786         modmap 
= XGetModifierMapping(dpy
); 
1787         for(i 
= 0; i 
< 8; i
++) 
1788                 for(j 
= 0; j 
< modmap
->max_keypermod
; j
++) 
1789                         if(modmap
->modifiermap
[i 
* modmap
->max_keypermod 
+ j
] 
1790                            == XKeysymToKeycode(dpy
, XK_Num_Lock
)) 
1791                                 numlockmask 
= (1 << i
); 
1792         XFreeModifiermap(modmap
); 
1796 updatesizehints(Client 
*c
) { 
1800         if(!XGetWMNormalHints(dpy
, c
->win
, &size
, &msize
)) 
1801                 /* size is uninitialized, ensure that size.flags aren't used */ 
1803         if(size
.flags 
& PBaseSize
) { 
1804                 c
->basew 
= size
.base_width
; 
1805                 c
->baseh 
= size
.base_height
; 
1807         else if(size
.flags 
& PMinSize
) { 
1808                 c
->basew 
= size
.min_width
; 
1809                 c
->baseh 
= size
.min_height
; 
1812                 c
->basew 
= c
->baseh 
= 0; 
1813         if(size
.flags 
& PResizeInc
) { 
1814                 c
->incw 
= size
.width_inc
; 
1815                 c
->inch 
= size
.height_inc
; 
1818                 c
->incw 
= c
->inch 
= 0; 
1819         if(size
.flags 
& PMaxSize
) { 
1820                 c
->maxw 
= size
.max_width
; 
1821                 c
->maxh 
= size
.max_height
; 
1824                 c
->maxw 
= c
->maxh 
= 0; 
1825         if(size
.flags 
& PMinSize
) { 
1826                 c
->minw 
= size
.min_width
; 
1827                 c
->minh 
= size
.min_height
; 
1829         else if(size
.flags 
& PBaseSize
) { 
1830                 c
->minw 
= size
.base_width
; 
1831                 c
->minh 
= size
.base_height
; 
1834                 c
->minw 
= c
->minh 
= 0; 
1835         if(size
.flags 
& PAspect
) { 
1836                 c
->mina 
= (float)size
.min_aspect
.y 
/ (float)size
.min_aspect
.x
; 
1837                 c
->maxa 
= (float)size
.max_aspect
.x 
/ (float)size
.max_aspect
.y
; 
1840                 c
->maxa 
= c
->mina 
= 0.0; 
1841         c
->isfixed 
= (c
->maxw 
&& c
->minw 
&& c
->maxh 
&& c
->minh
 
1842                      && c
->maxw 
== c
->minw 
&& c
->maxh 
== c
->minh
); 
1846 updatetitle(Client 
*c
) { 
1847         if(!gettextprop(c
->win
, netatom
[NetWMName
], c
->name
, sizeof c
->name
)) 
1848                 gettextprop(c
->win
, XA_WM_NAME
, c
->name
, sizeof c
->name
); 
1853         if(!gettextprop(root
, XA_WM_NAME
, stext
, sizeof(stext
))) 
1854                 strcpy(stext
, "dwm-"VERSION
); 
1859 updatewmhints(Client 
*c
) { 
1862         if((wmh 
= XGetWMHints(dpy
, c
->win
))) { 
1863                 if(c 
== selmon
->sel 
&& wmh
->flags 
& XUrgencyHint
) { 
1864                         wmh
->flags 
&= ~XUrgencyHint
; 
1865                         XSetWMHints(dpy
, c
->win
, wmh
); 
1868                         c
->isurgent 
= (wmh
->flags 
& XUrgencyHint
) ? True 
: False
; 
1875 view(const Arg 
*arg
) { 
1876         if((arg
->ui 
& TAGMASK
) == selmon
->tagset
[selmon
->seltags
]) 
1878         selmon
->seltags 
^= 1; /* toggle sel tagset */ 
1879         if(arg
->ui 
& TAGMASK
) 
1880                 selmon
->tagset
[selmon
->seltags
] = arg
->ui 
& TAGMASK
; 
1884 /* There's no way to check accesses to destroyed windows, thus those cases are 
1885  * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs 
1886  * default error handler, which may call exit.  */ 
1888 xerror(Display 
*dpy
, XErrorEvent 
*ee
) { 
1889         if(ee
->error_code 
== BadWindow
 
1890         || (ee
->request_code 
== X_SetInputFocus 
&& ee
->error_code 
== BadMatch
) 
1891         || (ee
->request_code 
== X_PolyText8 
&& ee
->error_code 
== BadDrawable
) 
1892         || (ee
->request_code 
== X_PolyFillRectangle 
&& ee
->error_code 
== BadDrawable
) 
1893         || (ee
->request_code 
== X_PolySegment 
&& ee
->error_code 
== BadDrawable
) 
1894         || (ee
->request_code 
== X_ConfigureWindow 
&& ee
->error_code 
== BadMatch
) 
1895         || (ee
->request_code 
== X_GrabButton 
&& ee
->error_code 
== BadAccess
) 
1896         || (ee
->request_code 
== X_GrabKey 
&& ee
->error_code 
== BadAccess
) 
1897         || (ee
->request_code 
== X_CopyArea 
&& ee
->error_code 
== BadDrawable
)) 
1899         fprintf(stderr
, "dwm: fatal error: request code=%d, error code=%d\n", 
1900                         ee
->request_code
, ee
->error_code
); 
1901         return xerrorxlib(dpy
, ee
); /* may call exit */ 
1905 xerrordummy(Display 
*dpy
, XErrorEvent 
*ee
) { 
1909 /* Startup Error handler to check if another window manager 
1910  * is already running. */ 
1912 xerrorstart(Display 
*dpy
, XErrorEvent 
*ee
) { 
1918 zoom(const Arg 
*arg
) { 
1919         Client 
*c 
= selmon
->sel
; 
1921         if(!lt
[selmon
->sellt
]->arrange 
|| lt
[selmon
->sellt
]->arrange 
== monocle 
|| (selmon
->sel 
&& selmon
->sel
->isfloating
)) 
1923         if(c 
== nexttiled(selmon
->clients
)) 
1924                 if(!c 
|| !(c 
= nexttiled(c
->next
))) 
1933 main(int argc
, char *argv
[]) { 
1934         if(argc 
== 2 && !strcmp("-v", argv
[1])) 
1935                 die("dwm-"VERSION
", © 2006-2009 dwm engineers, see LICENSE for details\n"); 
1937                 die("usage: dwm [-v]\n"); 
1939         if(!setlocale(LC_CTYPE
, "") || !XSupportsLocale()) 
1940                 fputs("warning: no locale support\n", stderr
); 
1942         if(!(dpy 
= XOpenDisplay(NULL
))) 
1943                 die("dwm: cannot open display\n");