2024-05-10 20:01:34 +00:00
/* See LICENSE file for copyright and license details.
*
* dynamic window manager is designed like any other X client as well . It is
* driven through handling X events . In contrast to other X clients , a window
* manager selects for SubstructureRedirectMask on the root window , to receive
* events about window ( dis - ) appearance . Only one X connection at a time is
* allowed to select for this event mask .
*
* The event handlers of dwm are organized in an array which is accessed
* whenever a new event has been fetched . This allows event dispatching
* in O ( 1 ) time .
*
* Each child of the root window is called a client , except windows which have
* set the override_redirect flag . Clients are organized in a linked client
* list on each monitor , the focus history is remembered through a stack list
* on each monitor . Each client contains a bit array to indicate the tags of a
* client .
*
* Keys and tagging rules are organized as arrays and defined in config . h .
*
* To understand everything else , start reading main ( ) .
*/
# include <errno.h>
# include <locale.h>
# include <signal.h>
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <X11/cursorfont.h>
# include <X11/keysym.h>
# include <X11/Xatom.h>
# include <X11/Xlib.h>
# include <X11/Xproto.h>
# include <X11/Xutil.h>
# ifdef XINERAMA
# include <X11/extensions/Xinerama.h>
# endif /* XINERAMA */
# include <X11/Xft/Xft.h>
2024-05-11 04:43:32 +00:00
# include <X11/Xlib-xcb.h>
# include <xcb/res.h>
# ifdef __OpenBSD__
# include <sys/sysctl.h>
# include <kvm.h>
# endif /* __OpenBSD */
2024-05-10 20:01:34 +00:00
# include "drw.h"
# include "util.h"
/* macros */
# define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
# define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
# define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX ( 0 , MIN ( ( y ) + ( h ) , ( m ) - > wy + ( m ) - > wh ) - MAX ( ( y ) , ( m ) - > wy ) ) )
# define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
2024-05-11 04:25:35 +00:00
# define HIDDEN(C) ((getstate(C->win) == IconicState))
2024-05-10 20:01:34 +00:00
# define LENGTH(X) (sizeof X / sizeof X[0])
# define MOUSEMASK (BUTTONMASK|PointerMotionMask)
# define WIDTH(X) ((X)->w + 2 * (X)->bw)
# define HEIGHT(X) ((X)->h + 2 * (X)->bw)
# define TAGMASK ((1 << LENGTH(tags)) - 1)
# define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
2024-05-10 22:23:16 +00:00
# define OPAQUE 0xffU
2024-05-10 20:01:34 +00:00
/* enums */
enum { CurNormal , CurResize , CurMove , CurLast } ; /* cursor */
2024-05-11 04:25:35 +00:00
enum { SchemeNorm , SchemeSel , SchemeHid } ; /* color schemes */
2024-05-10 20:01:34 +00:00
enum { NetSupported , NetWMName , NetWMState , NetWMCheck ,
NetWMFullscreen , NetActiveWindow , NetWMWindowType ,
2024-05-11 01:22:05 +00:00
NetWMWindowTypeDialog , NetClientList , NetClientInfo , NetLast } ; /* EWMH atoms */
2024-05-10 20:01:34 +00:00
enum { WMProtocols , WMDelete , WMState , WMTakeFocus , WMLast } ; /* default atoms */
enum { ClkTagBar , ClkLtSymbol , ClkStatusText , ClkWinTitle ,
2024-05-10 21:47:45 +00:00
ClkExBarLeftStatus , ClkExBarMiddle , ClkExBarRightStatus ,
2024-05-11 05:55:46 +00:00
ClkClientWin , ClkRootWin , ClkFollowSymbol , ClkLast } ; /* clicks */
2024-05-10 20:01:34 +00:00
typedef union {
int i ;
unsigned int ui ;
float f ;
const void * v ;
} Arg ;
typedef struct {
unsigned int click ;
unsigned int mask ;
unsigned int button ;
void ( * func ) ( const Arg * arg ) ;
const Arg arg ;
} Button ;
typedef struct Monitor Monitor ;
typedef struct Client Client ;
struct Client {
char name [ 256 ] ;
float mina , maxa ;
int x , y , w , h ;
2024-05-11 02:51:27 +00:00
int sfx , sfy , sfw , sfh ; /* stored float geometry, used on mode revert */
2024-05-10 20:01:34 +00:00
int oldx , oldy , oldw , oldh ;
int basew , baseh , incw , inch , maxw , maxh , minw , minh , hintsvalid ;
int bw , oldbw ;
unsigned int tags ;
2024-05-11 04:43:32 +00:00
int isfixed , isfloating , isurgent , neverfocus , oldstate , isfullscreen , isterminal , noswallow ;
pid_t pid ;
2024-05-10 20:01:34 +00:00
Client * next ;
Client * snext ;
2024-05-11 04:43:32 +00:00
Client * swallowing ;
2024-05-10 20:01:34 +00:00
Monitor * mon ;
Window win ;
} ;
typedef struct {
unsigned int mod ;
KeySym keysym ;
void ( * func ) ( const Arg * ) ;
const Arg arg ;
} Key ;
typedef struct {
const char * symbol ;
void ( * arrange ) ( Monitor * ) ;
} Layout ;
2024-05-11 01:37:08 +00:00
typedef struct Pertag Pertag ;
2024-05-10 20:01:34 +00:00
struct Monitor {
char ltsymbol [ 16 ] ;
float mfact ;
int nmaster ;
int num ;
int by ; /* bar geometry */
2024-05-10 21:47:45 +00:00
int eby ; /* extra bar geometry */
2024-05-11 04:25:35 +00:00
int btw ; /* width of tasks portion of bar */
int bt ; /* number of tasks */
2024-05-10 20:01:34 +00:00
int mx , my , mw , mh ; /* screen size */
int wx , wy , ww , wh ; /* window area */
unsigned int seltags ;
unsigned int sellt ;
unsigned int tagset [ 2 ] ;
int showbar ;
int topbar ;
2024-05-11 04:25:35 +00:00
int hidsel ;
2024-05-10 21:47:45 +00:00
int extrabar ;
2024-05-10 20:01:34 +00:00
Client * clients ;
Client * sel ;
Client * stack ;
Monitor * next ;
Window barwin ;
2024-05-10 21:47:45 +00:00
Window extrabarwin ;
2024-05-10 20:01:34 +00:00
const Layout * lt [ 2 ] ;
2024-05-11 01:37:08 +00:00
Pertag * pertag ;
2024-05-10 20:01:34 +00:00
} ;
typedef struct {
const char * class ;
const char * instance ;
const char * title ;
unsigned int tags ;
int isfloating ;
2024-05-11 04:43:32 +00:00
int isterminal ;
int noswallow ;
2024-05-10 20:01:34 +00:00
int monitor ;
} Rule ;
2024-05-22 14:05:25 +00:00
typedef struct {
const char * * command ;
const char * name ;
} Launcher ;
2024-05-10 20:01:34 +00:00
/* function declarations */
static void applyrules ( Client * c ) ;
static int applysizehints ( Client * c , int * x , int * y , int * w , int * h , int interact ) ;
static void arrange ( Monitor * m ) ;
static void arrangemon ( Monitor * m ) ;
static void attach ( Client * c ) ;
2024-05-10 22:38:38 +00:00
static void attachbottom ( Client * c ) ;
2024-05-10 20:01:34 +00:00
static void attachstack ( Client * c ) ;
static void buttonpress ( XEvent * e ) ;
static void checkotherwm ( void ) ;
static void cleanup ( void ) ;
static void cleanupmon ( Monitor * mon ) ;
static void clientmessage ( XEvent * e ) ;
static void configure ( Client * c ) ;
static void configurenotify ( XEvent * e ) ;
static void configurerequest ( XEvent * e ) ;
static Monitor * createmon ( void ) ;
static void destroynotify ( XEvent * e ) ;
static void detach ( Client * c ) ;
static void detachstack ( Client * c ) ;
static Monitor * dirtomon ( int dir ) ;
static void drawbar ( Monitor * m ) ;
static void drawbars ( void ) ;
static void enternotify ( XEvent * e ) ;
static void expose ( XEvent * e ) ;
2024-05-11 12:22:34 +00:00
static Client * findbefore ( Client * c ) ;
2024-05-10 20:01:34 +00:00
static void focus ( Client * c ) ;
static void focusin ( XEvent * e ) ;
static void focusmon ( const Arg * arg ) ;
2024-05-11 04:25:35 +00:00
static void focusstackvis ( const Arg * arg ) ;
static void focusstackhid ( const Arg * arg ) ;
static void focusstack ( int inc , int vis ) ;
2024-05-10 20:01:34 +00:00
static Atom getatomprop ( Client * c , Atom prop ) ;
static int getrootptr ( int * x , int * y ) ;
static long getstate ( Window w ) ;
static int gettextprop ( Window w , Atom atom , char * text , unsigned int size ) ;
static void grabbuttons ( Client * c , int focused ) ;
static void grabkeys ( void ) ;
2024-05-11 04:25:35 +00:00
static void hide ( const Arg * arg ) ;
static void hidewin ( Client * c ) ;
2024-05-10 20:01:34 +00:00
static void incnmaster ( const Arg * arg ) ;
static void keypress ( XEvent * e ) ;
static void killclient ( const Arg * arg ) ;
static void manage ( Window w , XWindowAttributes * wa ) ;
static void mappingnotify ( XEvent * e ) ;
static void maprequest ( XEvent * e ) ;
static void monocle ( Monitor * m ) ;
static void motionnotify ( XEvent * e ) ;
static void movemouse ( const Arg * arg ) ;
2024-05-23 23:42:15 +00:00
static void movestack ( const Arg * arg ) ;
2024-05-10 20:01:34 +00:00
static Client * nexttiled ( Client * c ) ;
static void pop ( Client * c ) ;
static void propertynotify ( XEvent * e ) ;
static void quit ( const Arg * arg ) ;
static Monitor * recttomon ( int x , int y , int w , int h ) ;
2024-05-25 00:43:21 +00:00
static void reorganizetags ( const Arg * arg ) ;
2024-05-23 23:37:03 +00:00
static void resetlayout ( const Arg * arg ) ;
2024-05-10 20:01:34 +00:00
static void resize ( Client * c , int x , int y , int w , int h , int interact ) ;
static void resizeclient ( Client * c , int x , int y , int w , int h ) ;
static void resizemouse ( const Arg * arg ) ;
static void restack ( Monitor * m ) ;
static void run ( void ) ;
static void scan ( void ) ;
static int sendevent ( Client * c , Atom proto ) ;
static void sendmon ( Client * c , Monitor * m ) ;
static void setclientstate ( Client * c , long state ) ;
2024-05-11 01:22:05 +00:00
static void setclienttagprop ( Client * c ) ;
2024-05-10 20:01:34 +00:00
static void setfocus ( Client * c ) ;
static void setfullscreen ( Client * c , int fullscreen ) ;
static void setlayout ( const Arg * arg ) ;
static void setmfact ( const Arg * arg ) ;
static void setup ( void ) ;
static void seturgent ( Client * c , int urg ) ;
2024-05-11 04:25:35 +00:00
static void show ( const Arg * arg ) ;
static void showall ( const Arg * arg ) ;
static void showwin ( Client * c ) ;
2024-05-10 20:01:34 +00:00
static void showhide ( Client * c ) ;
2024-05-11 01:05:59 +00:00
static void sighup ( int unused ) ;
static void sigterm ( int unused ) ;
2024-05-10 20:01:34 +00:00
static void spawn ( const Arg * arg ) ;
static void tag ( const Arg * arg ) ;
static void tagmon ( const Arg * arg ) ;
static void tile ( Monitor * m ) ;
static void togglebar ( const Arg * arg ) ;
2024-05-19 04:37:47 +00:00
static void togglefullscr ( const Arg * arg ) ;
2024-05-10 21:47:45 +00:00
static void toggleextrabar ( const Arg * arg ) ;
2024-05-10 20:01:34 +00:00
static void togglefloating ( const Arg * arg ) ;
2024-05-11 05:55:46 +00:00
static void togglefollow ( const Arg * arg ) ;
2024-05-10 20:01:34 +00:00
static void toggletag ( const Arg * arg ) ;
static void toggleview ( const Arg * arg ) ;
2024-05-11 04:25:35 +00:00
static void togglewin ( const Arg * arg ) ;
2024-05-10 20:01:34 +00:00
static void unfocus ( Client * c , int setfocus ) ;
static void unmanage ( Client * c , int destroyed ) ;
static void unmapnotify ( XEvent * e ) ;
static void updatebarpos ( Monitor * m ) ;
static void updatebars ( void ) ;
static void updateclientlist ( void ) ;
static int updategeom ( void ) ;
static void updatenumlockmask ( void ) ;
static void updatesizehints ( Client * c ) ;
static void updatestatus ( void ) ;
static void updatetitle ( Client * c ) ;
static void updatewindowtype ( Client * c ) ;
static void updatewmhints ( Client * c ) ;
static void view ( const Arg * arg ) ;
2024-05-25 01:36:09 +00:00
static void window_set_state ( Display * dpy , Window win , long state ) ;
static void window_map ( Display * dpy , Client * c , int deiconify ) ;
static void window_unmap ( Display * dpy , Window win , Window root , int iconify ) ;
2024-05-10 20:01:34 +00:00
static Client * wintoclient ( Window w ) ;
static Monitor * wintomon ( Window w ) ;
static int xerror ( Display * dpy , XErrorEvent * ee ) ;
static int xerrordummy ( Display * dpy , XErrorEvent * ee ) ;
static int xerrorstart ( Display * dpy , XErrorEvent * ee ) ;
2024-05-10 22:23:16 +00:00
static void xinitvisual ( ) ;
2024-05-10 20:01:34 +00:00
static void zoom ( const Arg * arg ) ;
2024-05-20 22:10:54 +00:00
static void swaptags ( const Arg * arg ) ;
2024-05-20 22:06:37 +00:00
static void autostart_exec ( void ) ;
2024-05-10 20:01:34 +00:00
2024-05-11 04:43:32 +00:00
static pid_t getparentprocess ( pid_t p ) ;
static int isdescprocess ( pid_t p , pid_t c ) ;
static Client * swallowingclient ( Window w ) ;
static Client * termforwin ( const Client * c ) ;
static pid_t winpid ( Window w ) ;
2024-05-10 20:01:34 +00:00
/* variables */
2024-05-11 12:22:34 +00:00
static Client * prevzoom = NULL ;
2024-05-10 20:01:34 +00:00
static const char broken [ ] = " broken " ;
static char stext [ 256 ] ;
2024-05-22 14:05:25 +00:00
static char estext [ 256 ] ;
2024-05-17 03:26:11 +00:00
static char wfsymbol [ 2 ] ;
2024-05-10 20:01:34 +00:00
static int screen ;
static int sw , sh ; /* X display screen geometry width, height */
static int bh ; /* bar height */
static int lrpad ; /* sum of left and right padding for text */
2024-05-19 05:32:12 +00:00
static int vp ; /* vertical padding for bar */
static int sp ; /* side padding for bar */
2024-05-10 20:01:34 +00:00
static int ( * xerrorxlib ) ( Display * , XErrorEvent * ) ;
static unsigned int numlockmask = 0 ;
static void ( * handler [ LASTEvent ] ) ( XEvent * ) = {
[ ButtonPress ] = buttonpress ,
[ ClientMessage ] = clientmessage ,
[ ConfigureRequest ] = configurerequest ,
[ ConfigureNotify ] = configurenotify ,
[ DestroyNotify ] = destroynotify ,
[ EnterNotify ] = enternotify ,
[ Expose ] = expose ,
[ FocusIn ] = focusin ,
[ KeyPress ] = keypress ,
[ MappingNotify ] = mappingnotify ,
[ MapRequest ] = maprequest ,
[ MotionNotify ] = motionnotify ,
[ PropertyNotify ] = propertynotify ,
[ UnmapNotify ] = unmapnotify
} ;
static Atom wmatom [ WMLast ] , netatom [ NetLast ] ;
2024-05-11 01:05:59 +00:00
static int restart = 0 ;
2024-05-10 20:01:34 +00:00
static int running = 1 ;
static Cur * cursor [ CurLast ] ;
static Clr * * scheme ;
static Display * dpy ;
static Drw * drw ;
static Monitor * mons , * selmon ;
static Window root , wmcheckwin ;
2024-05-10 22:23:16 +00:00
static int useargb = 0 ;
static Visual * visual ;
static int depth ;
static Colormap cmap ;
2024-05-11 04:43:32 +00:00
static xcb_connection_t * xcon ;
2024-05-10 20:01:34 +00:00
/* configuration, allows nested code to access above variables */
# include "config.h"
2024-05-11 01:37:08 +00:00
struct Pertag {
unsigned int curtag , prevtag ; /* current and previous tag */
int nmasters [ LENGTH ( tags ) + 1 ] ; /* number of windows in master area */
float mfacts [ LENGTH ( tags ) + 1 ] ; /* mfacts per tag */
unsigned int sellts [ LENGTH ( tags ) + 1 ] ; /* selected layouts */
const Layout * ltidxs [ LENGTH ( tags ) + 1 ] [ 2 ] ; /* matrix of tags and layouts indexes */
int showbars [ LENGTH ( tags ) + 1 ] ; /* display bar for the current tag */
} ;
2024-05-10 20:01:34 +00:00
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded [ LENGTH ( tags ) > 31 ? - 1 : 1 ] ; } ;
2024-05-20 22:06:37 +00:00
/* dwm will keep pid's of processes from autostart array and kill them at quit */
static pid_t * autostart_pids ;
static size_t autostart_len ;
/* execute command from autostart array */
static void
autostart_exec ( ) {
const char * const * p ;
size_t i = 0 ;
/* count entries */
for ( p = autostart ; * p ; autostart_len + + , p + + )
while ( * + + p ) ;
autostart_pids = malloc ( autostart_len * sizeof ( pid_t ) ) ;
for ( p = autostart ; * p ; i + + , p + + ) {
if ( ( autostart_pids [ i ] = fork ( ) ) = = 0 ) {
setsid ( ) ;
execvp ( * p , ( char * const * ) p ) ;
fprintf ( stderr , " dwm: execvp %s \n " , * p ) ;
perror ( " failed " ) ;
_exit ( EXIT_FAILURE ) ;
}
/* skip arguments */
while ( * + + p ) ;
}
}
2024-05-10 20:01:34 +00:00
/* function implementations */
void
applyrules ( Client * c )
{
const char * class , * instance ;
unsigned int i ;
const Rule * r ;
Monitor * m ;
XClassHint ch = { NULL , NULL } ;
/* rule matching */
c - > isfloating = 0 ;
c - > tags = 0 ;
XGetClassHint ( dpy , c - > win , & ch ) ;
class = ch . res_class ? ch . res_class : broken ;
instance = ch . res_name ? ch . res_name : broken ;
for ( i = 0 ; i < LENGTH ( rules ) ; i + + ) {
r = & rules [ i ] ;
if ( ( ! r - > title | | strstr ( c - > name , r - > title ) )
& & ( ! r - > class | | strstr ( class , r - > class ) )
& & ( ! r - > instance | | strstr ( instance , r - > instance ) ) )
{
2024-05-11 04:43:32 +00:00
c - > isterminal = r - > isterminal ;
c - > noswallow = r - > noswallow ;
2024-05-10 20:01:34 +00:00
c - > isfloating = r - > isfloating ;
c - > tags | = r - > tags ;
for ( m = mons ; m & & m - > num ! = r - > monitor ; m = m - > next ) ;
if ( m )
c - > mon = m ;
}
}
if ( ch . res_class )
XFree ( ch . res_class ) ;
if ( ch . res_name )
XFree ( ch . res_name ) ;
c - > tags = c - > tags & TAGMASK ? c - > tags & TAGMASK : c - > mon - > tagset [ c - > mon - > seltags ] ;
}
int
applysizehints ( Client * c , int * x , int * y , int * w , int * h , int interact )
{
int baseismin ;
Monitor * m = c - > mon ;
/* set minimum possible */
* w = MAX ( 1 , * w ) ;
* h = MAX ( 1 , * h ) ;
if ( interact ) {
if ( * x > sw )
* x = sw - WIDTH ( c ) ;
if ( * y > sh )
* y = sh - HEIGHT ( c ) ;
if ( * x + * w + 2 * c - > bw < 0 )
* x = 0 ;
if ( * y + * h + 2 * c - > bw < 0 )
* y = 0 ;
} else {
if ( * x > = m - > wx + m - > ww )
* x = m - > wx + m - > ww - WIDTH ( c ) ;
if ( * y > = m - > wy + m - > wh )
* y = m - > wy + m - > wh - HEIGHT ( c ) ;
if ( * x + * w + 2 * c - > bw < = m - > wx )
* x = m - > wx ;
if ( * y + * h + 2 * c - > bw < = m - > wy )
* y = m - > wy ;
}
if ( * h < bh )
* h = bh ;
if ( * w < bh )
* w = bh ;
if ( resizehints | | c - > isfloating | | ! c - > mon - > lt [ c - > mon - > sellt ] - > arrange ) {
if ( ! c - > hintsvalid )
updatesizehints ( c ) ;
/* see last two sentences in ICCCM 4.1.2.3 */
baseismin = c - > basew = = c - > minw & & c - > baseh = = c - > minh ;
if ( ! baseismin ) { /* temporarily remove base dimensions */
* w - = c - > basew ;
* h - = c - > baseh ;
}
/* adjust for aspect limits */
if ( c - > mina > 0 & & c - > maxa > 0 ) {
if ( c - > maxa < ( float ) * w / * h )
* w = * h * c - > maxa + 0.5 ;
else if ( c - > mina < ( float ) * h / * w )
* h = * w * c - > mina + 0.5 ;
}
if ( baseismin ) { /* increment calculation requires this */
* w - = c - > basew ;
* h - = c - > baseh ;
}
/* adjust for increment value */
if ( c - > incw )
* w - = * w % c - > incw ;
if ( c - > inch )
* h - = * h % c - > inch ;
/* restore base dimensions */
* w = MAX ( * w + c - > basew , c - > minw ) ;
* h = MAX ( * h + c - > baseh , c - > minh ) ;
if ( c - > maxw )
* w = MIN ( * w , c - > maxw ) ;
if ( c - > maxh )
* h = MIN ( * h , c - > maxh ) ;
}
return * x ! = c - > x | | * y ! = c - > y | | * w ! = c - > w | | * h ! = c - > h ;
}
void
arrange ( Monitor * m )
{
if ( m )
showhide ( m - > stack ) ;
else for ( m = mons ; m ; m = m - > next )
showhide ( m - > stack ) ;
if ( m ) {
arrangemon ( m ) ;
restack ( m ) ;
} else for ( m = mons ; m ; m = m - > next )
arrangemon ( m ) ;
}
void
arrangemon ( Monitor * m )
{
strncpy ( m - > ltsymbol , m - > lt [ m - > sellt ] - > symbol , sizeof m - > ltsymbol ) ;
if ( m - > lt [ m - > sellt ] - > arrange )
m - > lt [ m - > sellt ] - > arrange ( m ) ;
}
void
attach ( Client * c )
{
c - > next = c - > mon - > clients ;
c - > mon - > clients = c ;
}
2024-05-10 22:38:38 +00:00
void
attachbottom ( Client * c )
{
Client * * tc ;
c - > next = NULL ;
for ( tc = & c - > mon - > clients ; * tc ; tc = & ( * tc ) - > next ) ;
* tc = c ;
}
2024-05-10 20:01:34 +00:00
void
attachstack ( Client * c )
{
c - > snext = c - > mon - > stack ;
c - > mon - > stack = c ;
}
2024-05-11 04:43:32 +00:00
void
swallow ( Client * p , Client * c )
{
if ( c - > noswallow | | c - > isterminal )
return ;
if ( c - > noswallow & & ! swallowfloating & & c - > isfloating )
return ;
detach ( c ) ;
detachstack ( c ) ;
setclientstate ( c , WithdrawnState ) ;
XUnmapWindow ( dpy , p - > win ) ;
p - > swallowing = c ;
c - > mon = p - > mon ;
Window w = p - > win ;
p - > win = c - > win ;
c - > win = w ;
updatetitle ( p ) ;
XMoveResizeWindow ( dpy , p - > win , p - > x , p - > y , p - > w , p - > h ) ;
arrange ( p - > mon ) ;
configure ( p ) ;
updateclientlist ( ) ;
}
void
unswallow ( Client * c )
{
c - > win = c - > swallowing - > win ;
free ( c - > swallowing ) ;
c - > swallowing = NULL ;
/* unfullscreen the client */
setfullscreen ( c , 0 ) ;
updatetitle ( c ) ;
arrange ( c - > mon ) ;
XMapWindow ( dpy , c - > win ) ;
XMoveResizeWindow ( dpy , c - > win , c - > x , c - > y , c - > w , c - > h ) ;
setclientstate ( c , NormalState ) ;
focus ( NULL ) ;
arrange ( c - > mon ) ;
}
2024-05-10 20:01:34 +00:00
void
buttonpress ( XEvent * e )
{
unsigned int i , x , click ;
Arg arg = { 0 } ;
Client * c ;
Monitor * m ;
XButtonPressedEvent * ev = & e - > xbutton ;
click = ClkRootWin ;
/* focus monitor if necessary */
if ( ( m = wintomon ( ev - > window ) ) & & m ! = selmon ) {
unfocus ( selmon - > sel , 1 ) ;
selmon = m ;
focus ( NULL ) ;
}
if ( ev - > window = = selmon - > barwin ) {
i = x = 0 ;
2024-05-25 00:50:40 +00:00
unsigned int occ = 0 ;
for ( c = m - > clients ; c ; c = c - > next )
occ | = c - > tags = = TAGMASK ? 0 : c - > tags ;
do {
/* Do not reserve space for vacant tags */
if ( ! ( occ & 1 < < i | | m - > tagset [ m - > seltags ] & 1 < < i ) )
continue ;
2024-05-10 20:01:34 +00:00
x + = TEXTW ( tags [ i ] ) ;
2024-05-25 00:50:40 +00:00
} while ( ev - > x > = x & & + + i < LENGTH ( tags ) ) ;
2024-05-10 20:01:34 +00:00
if ( i < LENGTH ( tags ) ) {
click = ClkTagBar ;
arg . ui = 1 < < i ;
2024-05-11 05:55:46 +00:00
} else if ( ev - > x < ( x = ( x + TEXTW ( selmon - > ltsymbol ) ) ) )
2024-05-10 20:01:34 +00:00
click = ClkLtSymbol ;
2024-05-17 03:26:11 +00:00
else if ( ev - > x < x + TEXTW ( wfsymbol ) )
2024-05-11 05:55:46 +00:00
click = ClkFollowSymbol ;
2024-05-11 04:25:35 +00:00
/* 2px right padding */
else if ( ev - > x > selmon - > ww - TEXTW ( stext ) + lrpad - 2 )
2024-05-10 20:01:34 +00:00
click = ClkStatusText ;
2024-05-11 04:25:35 +00:00
else {
x + = TEXTW ( selmon - > ltsymbol ) ;
c = m - > clients ;
if ( c ) {
do {
if ( ! ISVISIBLE ( c ) )
continue ;
else
x + = ( 1.0 / ( double ) m - > bt ) * m - > btw ;
} while ( ev - > x > x & & ( c = c - > next ) ) ;
click = ClkWinTitle ;
arg . v = c ;
}
}
2024-05-22 14:05:25 +00:00
} else if ( ev - > window = = selmon - > extrabarwin ) {
i = x = 0 ;
for ( i = 0 ; i < LENGTH ( launchers ) ; i + + ) {
x + = TEXTW ( launchers [ i ] . name ) ;
if ( ev - > x < x ) {
Arg a ;
a . v = launchers [ i ] . command ;
spawn ( & a ) ;
return ;
} else if ( ev - > x > selmon - > ww - TEXTW ( estext ) )
click = ClkStatusText ;
}
2024-05-10 20:01:34 +00:00
} else if ( ( c = wintoclient ( ev - > window ) ) ) {
focus ( c ) ;
restack ( selmon ) ;
XAllowEvents ( dpy , ReplayPointer , CurrentTime ) ;
click = ClkClientWin ;
}
for ( i = 0 ; i < LENGTH ( buttons ) ; i + + )
if ( click = = buttons [ i ] . click & & buttons [ i ] . func & & buttons [ i ] . button = = ev - > button
& & CLEANMASK ( buttons [ i ] . mask ) = = CLEANMASK ( ev - > state ) )
2024-05-11 04:25:35 +00:00
buttons [ i ] . func ( ( click = = ClkTagBar | | click = = ClkWinTitle ) & & buttons [ i ] . arg . i = = 0 ? & arg : & buttons [ i ] . arg ) ;
2024-05-10 20:01:34 +00:00
}
void
checkotherwm ( void )
{
xerrorxlib = XSetErrorHandler ( xerrorstart ) ;
/* this causes an error if some other window manager is running */
XSelectInput ( dpy , DefaultRootWindow ( dpy ) , SubstructureRedirectMask ) ;
XSync ( dpy , False ) ;
XSetErrorHandler ( xerror ) ;
XSync ( dpy , False ) ;
}
void
cleanup ( void )
{
Arg a = { . ui = ~ 0 } ;
Layout foo = { " " , NULL } ;
Monitor * m ;
size_t i ;
view ( & a ) ;
selmon - > lt [ selmon - > sellt ] = & foo ;
for ( m = mons ; m ; m = m - > next )
while ( m - > stack )
unmanage ( m - > stack , 0 ) ;
XUngrabKey ( dpy , AnyKey , AnyModifier , root ) ;
while ( mons )
cleanupmon ( mons ) ;
for ( i = 0 ; i < CurLast ; i + + )
drw_cur_free ( drw , cursor [ i ] ) ;
for ( i = 0 ; i < LENGTH ( colors ) ; i + + )
free ( scheme [ i ] ) ;
free ( scheme ) ;
XDestroyWindow ( dpy , wmcheckwin ) ;
drw_free ( drw ) ;
XSync ( dpy , False ) ;
XSetInputFocus ( dpy , PointerRoot , RevertToPointerRoot , CurrentTime ) ;
XDeleteProperty ( dpy , root , netatom [ NetActiveWindow ] ) ;
}
void
cleanupmon ( Monitor * mon )
{
Monitor * m ;
if ( mon = = mons )
mons = mons - > next ;
else {
for ( m = mons ; m & & m - > next ! = mon ; m = m - > next ) ;
m - > next = mon - > next ;
}
XUnmapWindow ( dpy , mon - > barwin ) ;
2024-05-10 21:47:45 +00:00
XUnmapWindow ( dpy , mon - > extrabarwin ) ;
2024-05-10 20:01:34 +00:00
XDestroyWindow ( dpy , mon - > barwin ) ;
2024-05-10 21:47:45 +00:00
XDestroyWindow ( dpy , mon - > extrabarwin ) ;
2024-05-10 20:01:34 +00:00
free ( mon ) ;
}
void
clientmessage ( XEvent * e )
{
XClientMessageEvent * cme = & e - > xclient ;
Client * c = wintoclient ( cme - > window ) ;
if ( ! c )
return ;
if ( cme - > message_type = = netatom [ NetWMState ] ) {
if ( cme - > data . l [ 1 ] = = netatom [ NetWMFullscreen ]
| | cme - > data . l [ 2 ] = = netatom [ NetWMFullscreen ] )
setfullscreen ( c , ( cme - > data . l [ 0 ] = = 1 /* _NET_WM_STATE_ADD */
| | ( cme - > data . l [ 0 ] = = 2 /* _NET_WM_STATE_TOGGLE */ & & ! c - > isfullscreen ) ) ) ;
} else if ( cme - > message_type = = netatom [ NetActiveWindow ] ) {
if ( c ! = selmon - > sel & & ! c - > isurgent )
seturgent ( c , 1 ) ;
}
}
void
configure ( Client * c )
{
XConfigureEvent ce ;
ce . type = ConfigureNotify ;
ce . display = dpy ;
ce . event = c - > win ;
ce . window = c - > win ;
ce . x = c - > x ;
ce . y = c - > y ;
ce . width = c - > w ;
ce . height = c - > h ;
ce . border_width = c - > bw ;
ce . above = None ;
ce . override_redirect = False ;
XSendEvent ( dpy , c - > win , False , StructureNotifyMask , ( XEvent * ) & ce ) ;
}
void
configurenotify ( XEvent * e )
{
Monitor * m ;
Client * c ;
XConfigureEvent * ev = & e - > xconfigure ;
int dirty ;
/* TODO: updategeom handling sucks, needs to be simplified */
if ( ev - > window = = root ) {
dirty = ( sw ! = ev - > width | | sh ! = ev - > height ) ;
sw = ev - > width ;
sh = ev - > height ;
if ( updategeom ( ) | | dirty ) {
drw_resize ( drw , sw , bh ) ;
updatebars ( ) ;
for ( m = mons ; m ; m = m - > next ) {
for ( c = m - > clients ; c ; c = c - > next )
if ( c - > isfullscreen )
resizeclient ( c , m - > mx , m - > my , m - > mw , m - > mh ) ;
2024-05-19 05:32:12 +00:00
XMoveResizeWindow ( dpy , m - > barwin , m - > wx + sp , m - > by + vp , m - > ww - 2 * sp , bh ) ;
XMoveResizeWindow ( dpy , m - > extrabarwin , m - > wx + sp , m - > eby - vp , m - > ww - 2 * sp , bh ) ;
2024-05-10 20:01:34 +00:00
}
focus ( NULL ) ;
arrange ( NULL ) ;
}
}
}
void
configurerequest ( XEvent * e )
{
Client * c ;
Monitor * m ;
XConfigureRequestEvent * ev = & e - > xconfigurerequest ;
XWindowChanges wc ;
if ( ( c = wintoclient ( ev - > window ) ) ) {
if ( ev - > value_mask & CWBorderWidth )
c - > bw = ev - > border_width ;
else if ( c - > isfloating | | ! selmon - > lt [ selmon - > sellt ] - > arrange ) {
m = c - > mon ;
if ( ev - > value_mask & CWX ) {
c - > oldx = c - > x ;
c - > x = m - > mx + ev - > x ;
}
if ( ev - > value_mask & CWY ) {
c - > oldy = c - > y ;
c - > y = m - > my + ev - > y ;
}
if ( ev - > value_mask & CWWidth ) {
c - > oldw = c - > w ;
c - > w = ev - > width ;
}
if ( ev - > value_mask & CWHeight ) {
c - > oldh = c - > h ;
c - > h = ev - > height ;
}
if ( ( c - > x + c - > w ) > m - > mx + m - > mw & & c - > isfloating )
c - > x = m - > mx + ( m - > mw / 2 - WIDTH ( c ) / 2 ) ; /* center in x direction */
if ( ( c - > y + c - > h ) > m - > my + m - > mh & & c - > isfloating )
c - > y = m - > my + ( m - > mh / 2 - HEIGHT ( c ) / 2 ) ; /* center in y direction */
if ( ( ev - > value_mask & ( CWX | CWY ) ) & & ! ( ev - > value_mask & ( CWWidth | CWHeight ) ) )
configure ( c ) ;
if ( ISVISIBLE ( c ) )
XMoveResizeWindow ( dpy , c - > win , c - > x , c - > y , c - > w , c - > h ) ;
} else
configure ( c ) ;
} else {
wc . x = ev - > x ;
wc . y = ev - > y ;
wc . width = ev - > width ;
wc . height = ev - > height ;
wc . border_width = ev - > border_width ;
wc . sibling = ev - > above ;
wc . stack_mode = ev - > detail ;
XConfigureWindow ( dpy , ev - > window , ev - > value_mask , & wc ) ;
}
XSync ( dpy , False ) ;
}
Monitor *
createmon ( void )
{
Monitor * m ;
2024-05-11 01:37:08 +00:00
unsigned int i ;
2024-05-10 20:01:34 +00:00
m = ecalloc ( 1 , sizeof ( Monitor ) ) ;
m - > tagset [ 0 ] = m - > tagset [ 1 ] = 1 ;
m - > mfact = mfact ;
m - > nmaster = nmaster ;
m - > showbar = showbar ;
m - > topbar = topbar ;
2024-05-10 21:47:45 +00:00
m - > extrabar = extrabar ;
2024-05-10 20:01:34 +00:00
m - > lt [ 0 ] = & layouts [ 0 ] ;
m - > lt [ 1 ] = & layouts [ 1 % LENGTH ( layouts ) ] ;
strncpy ( m - > ltsymbol , layouts [ 0 ] . symbol , sizeof m - > ltsymbol ) ;
2024-05-11 01:37:08 +00:00
m - > pertag = ecalloc ( 1 , sizeof ( Pertag ) ) ;
m - > pertag - > curtag = m - > pertag - > prevtag = 1 ;
for ( i = 0 ; i < = LENGTH ( tags ) ; i + + ) {
m - > pertag - > nmasters [ i ] = m - > nmaster ;
m - > pertag - > mfacts [ i ] = m - > mfact ;
m - > pertag - > ltidxs [ i ] [ 0 ] = m - > lt [ 0 ] ;
m - > pertag - > ltidxs [ i ] [ 1 ] = m - > lt [ 1 ] ;
m - > pertag - > sellts [ i ] = m - > sellt ;
m - > pertag - > showbars [ i ] = m - > showbar ;
}
2024-05-17 03:26:11 +00:00
wfsymbol [ 0 ] = WFDEFAULT ;
wfsymbol [ 1 ] = ' \0 ' ;
2024-05-10 20:01:34 +00:00
return m ;
}
void
destroynotify ( XEvent * e )
{
Client * c ;
XDestroyWindowEvent * ev = & e - > xdestroywindow ;
if ( ( c = wintoclient ( ev - > window ) ) )
unmanage ( c , 1 ) ;
2024-05-11 04:43:32 +00:00
else if ( ( c = swallowingclient ( ev - > window ) ) )
unmanage ( c - > swallowing , 1 ) ;
2024-05-10 20:01:34 +00:00
}
void
detach ( Client * c )
{
Client * * tc ;
for ( tc = & c - > mon - > clients ; * tc & & * tc ! = c ; tc = & ( * tc ) - > next ) ;
* tc = c - > next ;
}
void
detachstack ( Client * c )
{
Client * * tc , * t ;
for ( tc = & c - > mon - > stack ; * tc & & * tc ! = c ; tc = & ( * tc ) - > snext ) ;
* tc = c - > snext ;
if ( c = = c - > mon - > sel ) {
for ( t = c - > mon - > stack ; t & & ! ISVISIBLE ( t ) ; t = t - > snext ) ;
c - > mon - > sel = t ;
}
}
Monitor *
dirtomon ( int dir )
{
Monitor * m = NULL ;
if ( dir > 0 ) {
if ( ! ( m = selmon - > next ) )
m = mons ;
} else if ( selmon = = mons )
for ( m = mons ; m - > next ; m = m - > next ) ;
else
for ( m = mons ; m - > next ! = selmon ; m = m - > next ) ;
return m ;
}
void
drawbar ( Monitor * m )
{
2024-05-11 04:25:35 +00:00
int x , w , tw = 0 , etwl = 0 , etwr = 0 , n = 0 , scm ;
2024-05-10 20:01:34 +00:00
int boxs = drw - > fonts - > h / 9 ;
int boxw = drw - > fonts - > h / 6 + 2 ;
unsigned int i , occ = 0 , urg = 0 ;
2024-05-19 03:43:14 +00:00
int mid ;
2024-05-10 20:01:34 +00:00
Client * c ;
if ( ! m - > showbar )
return ;
/* draw status first so it can be overdrawn by tags later */
2024-05-11 01:40:10 +00:00
drw_setscheme ( drw , scheme [ SchemeNorm ] ) ;
tw = TEXTW ( stext ) - lrpad + 2 ; /* 2px right padding */
2024-05-19 05:32:12 +00:00
drw_text ( drw , m - > ww - tw - 2 * sp , 0 , tw , bh , 0 , stext , 0 ) ;
2024-05-10 20:01:34 +00:00
for ( c = m - > clients ; c ; c = c - > next ) {
2024-05-11 04:25:35 +00:00
if ( ISVISIBLE ( c ) )
n + + ;
2024-05-25 00:50:40 +00:00
occ | = c - > tags = = TAGMASK ? 0 : c - > tags ;
2024-05-10 20:01:34 +00:00
if ( c - > isurgent )
urg | = c - > tags ;
}
x = 0 ;
for ( i = 0 ; i < LENGTH ( tags ) ; i + + ) {
2024-05-25 00:50:40 +00:00
/* Do not draw vacant tags */
if ( ! ( occ & 1 < < i | | m - > tagset [ m - > seltags ] & 1 < < i ) )
continue ;
2024-05-10 20:01:34 +00:00
w = TEXTW ( tags [ i ] ) ;
2024-05-19 01:53:46 +00:00
drw_setscheme ( drw , scheme [ m - > tagset [ m - > seltags ] & 1 < < i ? SchemeNorm : SchemeNorm ] ) ;
2024-05-10 20:01:34 +00:00
drw_text ( drw , x , 0 , w , bh , lrpad / 2 , tags [ i ] , urg & 1 < < i ) ;
2024-05-19 03:43:14 +00:00
if ( ulineall | | m - > tagset [ m - > seltags ] & 1 < < i ) { /* if there are conflicts, just move these lines directly underneath both 'drw_setscheme' and 'drw_text' :) */
if ( m = = selmon )
drw_setscheme ( drw , scheme [ SchemeHid ] ) ;
drw_rect ( drw , x + w * 0.0675 , bh - ulinestroke - ulinevoffset , w * 0.875 , ulinestroke , 1 , 0 ) ;
} else if ( occ & 1 < < i ) {
drw_setscheme ( drw , scheme [ SchemeNorm ] ) ;
if ( urg )
drw_rect ( drw , x + boxs , boxs , boxw , boxw , m = = selmon & & selmon - > sel & & selmon - > sel - > tags & 1 < < i , 1 ) ;
else
drw_rect ( drw , x + w * 0.375 , bh - ulinestroke - ulinevoffset , w * 0.25 , ulinestroke , 1 , 0 ) ;
}
2024-05-10 20:01:34 +00:00
x + = w ;
}
w = TEXTW ( m - > ltsymbol ) ;
2024-05-19 06:53:02 +00:00
drw_setscheme ( drw , scheme [ SchemeSel ] ) ;
2024-05-10 20:01:34 +00:00
x = drw_text ( drw , x , 0 , w , bh , lrpad / 2 , m - > ltsymbol , 0 ) ;
2024-05-17 03:26:11 +00:00
w = TEXTW ( wfsymbol ) ;
x = drw_text ( drw , x , 0 , w , bh , lrpad / 2 , wfsymbol , 0 ) ;
2024-05-11 05:55:46 +00:00
2024-05-10 20:01:34 +00:00
if ( ( w = m - > ww - tw - x ) > bh ) {
2024-05-11 04:25:35 +00:00
if ( n > 0 ) {
int remainder = w % n ;
int tabw = ( 1.0 / ( double ) n ) * w + 1 ;
for ( c = m - > clients ; c ; c = c - > next ) {
if ( ! ISVISIBLE ( c ) )
continue ;
2024-05-19 03:43:14 +00:00
if ( HIDDEN ( c ) )
2024-05-11 04:25:35 +00:00
scm = SchemeHid ;
else
scm = SchemeNorm ;
drw_setscheme ( drw , scheme [ scm ] ) ;
if ( remainder > = 0 ) {
if ( remainder = = 0 ) {
tabw - - ;
}
remainder - - ;
}
2024-05-19 03:43:14 +00:00
mid = ( tabw - ( int ) TEXTW ( c - > name ) ) / 2 ;
mid = mid > = lrpad / 2 ? mid : lrpad / 2 ;
2024-05-19 05:32:12 +00:00
drw_text ( drw , x , 0 , tabw - 2 * sp , bh , mid , c - > name , 0 ) ;
2024-05-19 03:43:14 +00:00
if ( ! HIDDEN ( c ) ) {
if ( m - > sel = = c ) {
if ( m = = selmon )
drw_setscheme ( drw , scheme [ SchemeHid ] ) ;
drw_rect ( drw , x + tabw * 0.0675 , bh - ulinestroke - ulinevoffset , tabw * 0.875 - ulinepad * 2 , ulinestroke , 1 , 0 ) ;
} else {
drw_rect ( drw , x + tabw * 0.375 , bh - ulinestroke - ulinevoffset , tabw * 0.25 - ulinepad * 2 , ulinestroke , 1 , 0 ) ;
}
}
2024-05-11 04:25:35 +00:00
x + = tabw ;
}
2024-05-10 20:01:34 +00:00
} else {
drw_setscheme ( drw , scheme [ SchemeNorm ] ) ;
2024-05-19 05:32:12 +00:00
drw_rect ( drw , x , 0 , w - 2 * sp , bh , 1 , 1 ) ;
2024-05-10 20:01:34 +00:00
}
}
2024-05-11 04:25:35 +00:00
m - > bt = n ;
m - > btw = w ;
2024-05-10 20:01:34 +00:00
drw_map ( drw , m - > barwin , 0 , 0 , m - > ww , bh ) ;
2024-05-10 21:47:45 +00:00
2024-05-11 01:40:10 +00:00
drw_setscheme ( drw , scheme [ SchemeNorm ] ) ;
/* clear default bar draw buffer by drawing a blank rectangle */
drw_rect ( drw , 0 , 0 , m - > ww , bh , 1 , 1 ) ;
2024-05-22 14:05:25 +00:00
w = TEXTW ( estext ) - lrpad + 2 ; /* 2px right padding */
drw_text ( drw , m - > ww - w - 2 * sp , 0 , w , bh , 0 , estext , 0 ) ;
x = 0 ;
for ( i = 0 ; i < LENGTH ( launchers ) ; i + + )
{
w = TEXTW ( launchers [ i ] . name ) ;
drw_text ( drw , x , 0 , w , bh , lrpad / 2 , launchers [ i ] . name , 0 ) ;
x + = w ;
}
2024-05-11 01:40:10 +00:00
drw_map ( drw , m - > extrabarwin , 0 , 0 , m - > ww , bh ) ;
2024-05-10 20:01:34 +00:00
}
void
drawbars ( void )
{
Monitor * m ;
for ( m = mons ; m ; m = m - > next )
drawbar ( m ) ;
}
void
enternotify ( XEvent * e )
{
Client * c ;
Monitor * m ;
XCrossingEvent * ev = & e - > xcrossing ;
if ( ( ev - > mode ! = NotifyNormal | | ev - > detail = = NotifyInferior ) & & ev - > window ! = root )
return ;
c = wintoclient ( ev - > window ) ;
m = c ? c - > mon : wintomon ( ev - > window ) ;
if ( m ! = selmon ) {
unfocus ( selmon - > sel , 1 ) ;
selmon = m ;
} else if ( ! c | | c = = selmon - > sel )
return ;
focus ( c ) ;
}
void
expose ( XEvent * e )
{
Monitor * m ;
XExposeEvent * ev = & e - > xexpose ;
if ( ev - > count = = 0 & & ( m = wintomon ( ev - > window ) ) )
drawbar ( m ) ;
}
2024-05-11 12:22:34 +00:00
Client *
findbefore ( Client * c )
{
Client * tmp ;
if ( c = = selmon - > clients )
return NULL ;
for ( tmp = selmon - > clients ; tmp & & tmp - > next ! = c ; tmp = tmp - > next ) ;
return tmp ;
}
2024-05-10 20:01:34 +00:00
void
focus ( Client * c )
{
if ( ! c | | ! ISVISIBLE ( c ) )
2024-05-11 04:25:35 +00:00
for ( c = selmon - > stack ; c & & ( ! ISVISIBLE ( c ) | | HIDDEN ( c ) ) ; c = c - > snext ) ;
if ( selmon - > sel & & selmon - > sel ! = c ) {
2024-05-10 20:01:34 +00:00
unfocus ( selmon - > sel , 0 ) ;
2024-05-11 04:25:35 +00:00
if ( selmon - > hidsel ) {
hidewin ( selmon - > sel ) ;
if ( c )
arrange ( c - > mon ) ;
selmon - > hidsel = 0 ;
}
}
2024-05-10 20:01:34 +00:00
if ( c ) {
if ( c - > mon ! = selmon )
selmon = c - > mon ;
if ( c - > isurgent )
seturgent ( c , 0 ) ;
detachstack ( c ) ;
attachstack ( c ) ;
grabbuttons ( c , 1 ) ;
2024-05-23 03:33:28 +00:00
XSetWindowBorder ( dpy , c - > win , scheme [ SchemeSel ] [ ColBorder ] . pixel ) ;
2024-05-10 20:01:34 +00:00
setfocus ( c ) ;
} else {
XSetInputFocus ( dpy , root , RevertToPointerRoot , CurrentTime ) ;
XDeleteProperty ( dpy , root , netatom [ NetActiveWindow ] ) ;
}
selmon - > sel = c ;
drawbars ( ) ;
}
/* there are some broken focus acquiring clients needing extra handling */
void
focusin ( XEvent * e )
{
XFocusChangeEvent * ev = & e - > xfocus ;
if ( selmon - > sel & & ev - > window ! = selmon - > sel - > win )
setfocus ( selmon - > sel ) ;
}
void
focusmon ( const Arg * arg )
{
Monitor * m ;
if ( ! mons - > next )
return ;
if ( ( m = dirtomon ( arg - > i ) ) = = selmon )
return ;
unfocus ( selmon - > sel , 0 ) ;
selmon = m ;
focus ( NULL ) ;
2024-05-17 02:56:17 +00:00
if ( selmon - > sel )
XWarpPointer ( dpy , None , selmon - > sel - > win , 0 , 0 , 0 , 0 , selmon - > sel - > w / 2 , selmon - > sel - > h / 2 ) ;
2024-05-10 20:01:34 +00:00
}
void
2024-05-11 04:25:35 +00:00
focusstackvis ( const Arg * arg ) {
focusstack ( arg - > i , 0 ) ;
}
void
focusstackhid ( const Arg * arg ) {
focusstack ( arg - > i , 1 ) ;
}
void
focusstack ( int inc , int hid )
2024-05-10 20:01:34 +00:00
{
Client * c = NULL , * i ;
2024-05-11 04:25:35 +00:00
// if no client selected AND exclude hidden client; if client selected but fullscreened
if ( ( ! selmon - > sel & & ! hid ) | | ( selmon - > sel & & selmon - > sel - > isfullscreen & & lockfullscreen ) )
return ;
if ( ! selmon - > clients )
2024-05-10 20:01:34 +00:00
return ;
2024-05-11 04:25:35 +00:00
if ( inc > 0 ) {
if ( selmon - > sel )
for ( c = selmon - > sel - > next ;
c & & ( ! ISVISIBLE ( c ) | | ( ! hid & & HIDDEN ( c ) ) ) ;
c = c - > next ) ;
2024-05-10 20:01:34 +00:00
if ( ! c )
2024-05-11 04:25:35 +00:00
for ( c = selmon - > clients ;
c & & ( ! ISVISIBLE ( c ) | | ( ! hid & & HIDDEN ( c ) ) ) ;
c = c - > next ) ;
2024-05-10 20:01:34 +00:00
} else {
2024-05-11 04:25:35 +00:00
if ( selmon - > sel ) {
for ( i = selmon - > clients ; i ! = selmon - > sel ; i = i - > next )
if ( ISVISIBLE ( i ) & & ! ( ! hid & & HIDDEN ( i ) ) )
c = i ;
} else
c = selmon - > clients ;
2024-05-10 20:01:34 +00:00
if ( ! c )
for ( ; i ; i = i - > next )
2024-05-11 04:25:35 +00:00
if ( ISVISIBLE ( i ) & & ! ( ! hid & & HIDDEN ( i ) ) )
2024-05-10 20:01:34 +00:00
c = i ;
}
if ( c ) {
focus ( c ) ;
restack ( selmon ) ;
2024-05-11 04:25:35 +00:00
if ( HIDDEN ( c ) ) {
showwin ( c ) ;
c - > mon - > hidsel = 1 ;
}
2024-05-17 02:56:17 +00:00
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w / 2 , c - > h / 2 ) ;
2024-05-10 20:01:34 +00:00
}
}
Atom
getatomprop ( Client * c , Atom prop )
{
int di ;
unsigned long dl ;
unsigned char * p = NULL ;
Atom da , atom = None ;
if ( XGetWindowProperty ( dpy , c - > win , prop , 0L , sizeof atom , False , XA_ATOM ,
& da , & di , & dl , & dl , & p ) = = Success & & p ) {
atom = * ( Atom * ) p ;
XFree ( p ) ;
}
return atom ;
}
int
getrootptr ( int * x , int * y )
{
int di ;
unsigned int dui ;
Window dummy ;
return XQueryPointer ( dpy , root , & dummy , & dummy , x , y , & di , & di , & dui ) ;
}
long
getstate ( Window w )
{
int format ;
long result = - 1 ;
unsigned char * p = NULL ;
unsigned long n , extra ;
Atom real ;
if ( XGetWindowProperty ( dpy , w , wmatom [ WMState ] , 0L , 2L , False , wmatom [ WMState ] ,
& real , & format , & n , & extra , ( unsigned char * * ) & p ) ! = Success )
return - 1 ;
if ( n ! = 0 )
result = * p ;
XFree ( p ) ;
return result ;
}
int
gettextprop ( Window w , Atom atom , char * text , unsigned int size )
{
char * * list = NULL ;
int n ;
XTextProperty name ;
if ( ! text | | size = = 0 )
return 0 ;
text [ 0 ] = ' \0 ' ;
if ( ! XGetTextProperty ( dpy , w , & name , atom ) | | ! name . nitems )
return 0 ;
if ( name . encoding = = XA_STRING ) {
strncpy ( text , ( char * ) name . value , size - 1 ) ;
} else if ( XmbTextPropertyToTextList ( dpy , & name , & list , & n ) > = Success & & n > 0 & & * list ) {
strncpy ( text , * list , size - 1 ) ;
XFreeStringList ( list ) ;
}
text [ size - 1 ] = ' \0 ' ;
XFree ( name . value ) ;
return 1 ;
}
void
grabbuttons ( Client * c , int focused )
{
updatenumlockmask ( ) ;
{
unsigned int i , j ;
unsigned int modifiers [ ] = { 0 , LockMask , numlockmask , numlockmask | LockMask } ;
XUngrabButton ( dpy , AnyButton , AnyModifier , c - > win ) ;
if ( ! focused )
XGrabButton ( dpy , AnyButton , AnyModifier , c - > win , False ,
BUTTONMASK , GrabModeSync , GrabModeSync , None , None ) ;
for ( i = 0 ; i < LENGTH ( buttons ) ; i + + )
if ( buttons [ i ] . click = = ClkClientWin )
for ( j = 0 ; j < LENGTH ( modifiers ) ; j + + )
XGrabButton ( dpy , buttons [ i ] . button ,
buttons [ i ] . mask | modifiers [ j ] ,
c - > win , False , BUTTONMASK ,
GrabModeAsync , GrabModeSync , None , None ) ;
}
}
void
grabkeys ( void )
{
updatenumlockmask ( ) ;
{
unsigned int i , j , k ;
unsigned int modifiers [ ] = { 0 , LockMask , numlockmask , numlockmask | LockMask } ;
int start , end , skip ;
KeySym * syms ;
XUngrabKey ( dpy , AnyKey , AnyModifier , root ) ;
XDisplayKeycodes ( dpy , & start , & end ) ;
syms = XGetKeyboardMapping ( dpy , start , end - start + 1 , & skip ) ;
if ( ! syms )
return ;
for ( k = start ; k < = end ; k + + )
for ( i = 0 ; i < LENGTH ( keys ) ; i + + )
/* skip modifier codes, we do that ourselves */
if ( keys [ i ] . keysym = = syms [ ( k - start ) * skip ] )
for ( j = 0 ; j < LENGTH ( modifiers ) ; j + + )
XGrabKey ( dpy , k ,
keys [ i ] . mod | modifiers [ j ] ,
root , True ,
GrabModeAsync , GrabModeAsync ) ;
XFree ( syms ) ;
}
}
2024-05-11 04:25:35 +00:00
void
hide ( const Arg * arg )
{
hidewin ( selmon - > sel ) ;
focus ( NULL ) ;
arrange ( selmon ) ;
}
void
hidewin ( Client * c ) {
if ( ! c | | HIDDEN ( c ) )
return ;
Window w = c - > win ;
static XWindowAttributes ra , ca ;
// more or less taken directly from blackbox's hide() function
XGrabServer ( dpy ) ;
XGetWindowAttributes ( dpy , root , & ra ) ;
XGetWindowAttributes ( dpy , w , & ca ) ;
// prevent UnmapNotify events
XSelectInput ( dpy , root , ra . your_event_mask & ~ SubstructureNotifyMask ) ;
XSelectInput ( dpy , w , ca . your_event_mask & ~ StructureNotifyMask ) ;
XUnmapWindow ( dpy , w ) ;
setclientstate ( c , IconicState ) ;
XSelectInput ( dpy , root , ra . your_event_mask ) ;
XSelectInput ( dpy , w , ca . your_event_mask ) ;
XUngrabServer ( dpy ) ;
}
2024-05-10 20:01:34 +00:00
void
incnmaster ( const Arg * arg )
{
2024-05-11 01:37:08 +00:00
unsigned int i ;
2024-05-10 20:01:34 +00:00
selmon - > nmaster = MAX ( selmon - > nmaster + arg - > i , 0 ) ;
2024-05-11 01:37:08 +00:00
for ( i = 0 ; i < LENGTH ( tags ) ; + + i )
if ( selmon - > tagset [ selmon - > seltags ] & 1 < < i )
selmon - > pertag - > nmasters [ i + 1 ] = selmon - > nmaster ;
if ( selmon - > pertag - > curtag = = 0 )
{
selmon - > pertag - > nmasters [ 0 ] = selmon - > nmaster ;
}
2024-05-10 20:01:34 +00:00
arrange ( selmon ) ;
}
# ifdef XINERAMA
static int
isuniquegeom ( XineramaScreenInfo * unique , size_t n , XineramaScreenInfo * info )
{
while ( n - - )
if ( unique [ n ] . x_org = = info - > x_org & & unique [ n ] . y_org = = info - > y_org
& & unique [ n ] . width = = info - > width & & unique [ n ] . height = = info - > height )
return 0 ;
return 1 ;
}
# endif /* XINERAMA */
void
keypress ( XEvent * e )
{
unsigned int i ;
KeySym keysym ;
XKeyEvent * ev ;
ev = & e - > xkey ;
keysym = XKeycodeToKeysym ( dpy , ( KeyCode ) ev - > keycode , 0 ) ;
for ( i = 0 ; i < LENGTH ( keys ) ; i + + )
if ( keysym = = keys [ i ] . keysym
& & CLEANMASK ( keys [ i ] . mod ) = = CLEANMASK ( ev - > state )
& & keys [ i ] . func )
keys [ i ] . func ( & ( keys [ i ] . arg ) ) ;
}
void
killclient ( const Arg * arg )
{
if ( ! selmon - > sel )
return ;
if ( ! sendevent ( selmon - > sel , wmatom [ WMDelete ] ) ) {
XGrabServer ( dpy ) ;
XSetErrorHandler ( xerrordummy ) ;
XSetCloseDownMode ( dpy , DestroyAll ) ;
XKillClient ( dpy , selmon - > sel - > win ) ;
XSync ( dpy , False ) ;
XSetErrorHandler ( xerror ) ;
XUngrabServer ( dpy ) ;
}
}
void
manage ( Window w , XWindowAttributes * wa )
{
2024-05-11 04:43:32 +00:00
Client * c , * t = NULL , * term = NULL ;
2024-05-10 20:01:34 +00:00
Window trans = None ;
XWindowChanges wc ;
c = ecalloc ( 1 , sizeof ( Client ) ) ;
c - > win = w ;
2024-05-11 04:43:32 +00:00
c - > pid = winpid ( w ) ;
2024-05-10 20:01:34 +00:00
/* geometry */
c - > x = c - > oldx = wa - > x ;
c - > y = c - > oldy = wa - > y ;
c - > w = c - > oldw = wa - > width ;
c - > h = c - > oldh = wa - > height ;
c - > oldbw = wa - > border_width ;
updatetitle ( c ) ;
if ( XGetTransientForHint ( dpy , w , & trans ) & & ( t = wintoclient ( trans ) ) ) {
c - > mon = t - > mon ;
c - > tags = t - > tags ;
} else {
c - > mon = selmon ;
applyrules ( c ) ;
2024-05-11 04:43:32 +00:00
term = termforwin ( c ) ;
2024-05-10 20:01:34 +00:00
}
if ( c - > x + WIDTH ( c ) > c - > mon - > wx + c - > mon - > ww )
c - > x = c - > mon - > wx + c - > mon - > ww - WIDTH ( c ) ;
if ( c - > y + HEIGHT ( c ) > c - > mon - > wy + c - > mon - > wh )
c - > y = c - > mon - > wy + c - > mon - > wh - HEIGHT ( c ) ;
c - > x = MAX ( c - > x , c - > mon - > wx ) ;
c - > y = MAX ( c - > y , c - > mon - > wy ) ;
c - > bw = borderpx ;
wc . border_width = c - > bw ;
XConfigureWindow ( dpy , w , CWBorderWidth , & wc ) ;
XSetWindowBorder ( dpy , w , scheme [ SchemeNorm ] [ ColBorder ] . pixel ) ;
configure ( c ) ; /* propagates border_width, if size doesn't change */
updatewindowtype ( c ) ;
updatesizehints ( c ) ;
updatewmhints ( c ) ;
2024-05-11 02:51:27 +00:00
c - > sfx = c - > x ;
c - > sfy = c - > y ;
c - > sfw = c - > w ;
c - > sfh = c - > h ;
2024-05-11 01:22:05 +00:00
{
int format ;
unsigned long * data , n , extra ;
Monitor * m ;
Atom atom ;
if ( XGetWindowProperty ( dpy , c - > win , netatom [ NetClientInfo ] , 0L , 2L , False , XA_CARDINAL ,
& atom , & format , & n , & extra , ( unsigned char * * ) & data ) = = Success & & n = = 2 ) {
c - > tags = * data ;
for ( m = mons ; m ; m = m - > next ) {
if ( m - > num = = * ( data + 1 ) ) {
c - > mon = m ;
break ;
}
}
}
if ( n > 0 )
XFree ( data ) ;
}
setclienttagprop ( c ) ;
2024-05-21 03:31:08 +00:00
c - > x = c - > mon - > mx + ( c - > mon - > mw - WIDTH ( c ) ) / 2 ;
c - > y = c - > mon - > my + ( c - > mon - > mh - HEIGHT ( c ) ) / 2 ;
2024-05-10 20:01:34 +00:00
XSelectInput ( dpy , w , EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask ) ;
grabbuttons ( c , 0 ) ;
if ( ! c - > isfloating )
c - > isfloating = c - > oldstate = trans ! = None | | c - > isfixed ;
if ( c - > isfloating )
XRaiseWindow ( dpy , c - > win ) ;
2024-05-10 22:38:38 +00:00
attachbottom ( c ) ;
2024-05-10 20:01:34 +00:00
attachstack ( c ) ;
XChangeProperty ( dpy , root , netatom [ NetClientList ] , XA_WINDOW , 32 , PropModeAppend ,
( unsigned char * ) & ( c - > win ) , 1 ) ;
XMoveResizeWindow ( dpy , c - > win , c - > x + 2 * sw , c - > y , c - > w , c - > h ) ; /* some windows require this */
2024-05-11 04:25:35 +00:00
if ( ! HIDDEN ( c ) )
setclientstate ( c , NormalState ) ;
2024-05-21 04:28:01 +00:00
if ( selmon - > sel & & selmon - > sel - > isfullscreen )
setfullscreen ( selmon - > sel , 0 ) ;
2024-05-10 20:01:34 +00:00
if ( c - > mon = = selmon )
unfocus ( selmon - > sel , 0 ) ;
c - > mon - > sel = c ;
arrange ( c - > mon ) ;
2024-05-17 02:56:17 +00:00
if ( ! HIDDEN ( c ) ) {
2024-05-11 04:25:35 +00:00
XMapWindow ( dpy , c - > win ) ;
2024-05-17 02:56:17 +00:00
if ( c & & c - > mon = = selmon )
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w / 2 , c - > h / 2 ) ;
}
2024-05-11 04:43:32 +00:00
if ( term )
swallow ( term , c ) ;
2024-05-10 20:01:34 +00:00
focus ( NULL ) ;
}
void
mappingnotify ( XEvent * e )
{
XMappingEvent * ev = & e - > xmapping ;
XRefreshKeyboardMapping ( ev ) ;
if ( ev - > request = = MappingKeyboard )
grabkeys ( ) ;
}
void
maprequest ( XEvent * e )
{
static XWindowAttributes wa ;
XMapRequestEvent * ev = & e - > xmaprequest ;
if ( ! XGetWindowAttributes ( dpy , ev - > window , & wa ) | | wa . override_redirect )
return ;
if ( ! wintoclient ( ev - > window ) )
manage ( ev - > window , & wa ) ;
}
void
monocle ( Monitor * m )
{
unsigned int n = 0 ;
Client * c ;
for ( c = m - > clients ; c ; c = c - > next )
if ( ISVISIBLE ( c ) )
n + + ;
if ( n > 0 ) /* override layout symbol */
snprintf ( m - > ltsymbol , sizeof m - > ltsymbol , " [%d] " , n ) ;
for ( c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) )
2024-05-19 06:44:26 +00:00
resize ( c , m - > wx + gappx , m - > wy + gappx , m - > ww - 2 * c - > bw - 2 * gappx , m - > wh - 2 * c - > bw - 2 * gappx , 0 ) ;
2024-05-10 20:01:34 +00:00
}
void
motionnotify ( XEvent * e )
{
static Monitor * mon = NULL ;
Monitor * m ;
XMotionEvent * ev = & e - > xmotion ;
if ( ev - > window ! = root )
return ;
if ( ( m = recttomon ( ev - > x_root , ev - > y_root , 1 , 1 ) ) ! = mon & & mon ) {
unfocus ( selmon - > sel , 1 ) ;
selmon = m ;
focus ( NULL ) ;
}
mon = m ;
}
void
movemouse ( const Arg * arg )
{
int x , y , ocx , ocy , nx , ny ;
Client * c ;
Monitor * m ;
XEvent ev ;
Time lasttime = 0 ;
if ( ! ( c = selmon - > sel ) )
return ;
if ( c - > isfullscreen ) /* no support moving fullscreen windows by mouse */
return ;
restack ( selmon ) ;
ocx = c - > x ;
ocy = c - > y ;
if ( XGrabPointer ( dpy , root , False , MOUSEMASK , GrabModeAsync , GrabModeAsync ,
None , cursor [ CurMove ] - > cursor , CurrentTime ) ! = GrabSuccess )
return ;
if ( ! getrootptr ( & x , & y ) )
return ;
do {
XMaskEvent ( dpy , MOUSEMASK | ExposureMask | SubstructureRedirectMask , & ev ) ;
switch ( ev . type ) {
case ConfigureRequest :
case Expose :
case MapRequest :
handler [ ev . type ] ( & ev ) ;
break ;
case MotionNotify :
if ( ( ev . xmotion . time - lasttime ) < = ( 1000 / 60 ) )
continue ;
lasttime = ev . xmotion . time ;
nx = ocx + ( ev . xmotion . x - x ) ;
ny = ocy + ( ev . xmotion . y - y ) ;
if ( abs ( selmon - > wx - nx ) < snap )
nx = selmon - > wx ;
else if ( abs ( ( selmon - > wx + selmon - > ww ) - ( nx + WIDTH ( c ) ) ) < snap )
nx = selmon - > wx + selmon - > ww - WIDTH ( c ) ;
if ( abs ( selmon - > wy - ny ) < snap )
ny = selmon - > wy ;
else if ( abs ( ( selmon - > wy + selmon - > wh ) - ( ny + HEIGHT ( c ) ) ) < snap )
ny = selmon - > wy + selmon - > wh - HEIGHT ( c ) ;
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | c - > isfloating )
resize ( c , nx , ny , c - > w , c - > h , 1 ) ;
2024-05-11 05:42:15 +00:00
else if ( selmon - > lt [ selmon - > sellt ] - > arrange | | ! c - > isfloating ) {
if ( ( m = recttomon ( ev . xmotion . x_root , ev . xmotion . y_root , 1 , 1 ) ) ! = selmon ) {
sendmon ( c , m ) ;
selmon = m ;
focus ( NULL ) ;
}
Client * cc = c - > mon - > clients ;
while ( 1 ) {
if ( cc = = 0 ) break ;
if (
cc ! = c & & ! cc - > isfloating & & ISVISIBLE ( cc ) & &
ev . xmotion . x_root > cc - > x & &
ev . xmotion . x_root < cc - > x + cc - > w & &
ev . xmotion . y_root > cc - > y & &
ev . xmotion . y_root < cc - > y + cc - > h ) {
break ;
}
cc = cc - > next ;
}
if ( cc ) {
Client * cl1 , * cl2 , ocl1 ;
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange ) return ;
cl1 = c ;
cl2 = cc ;
ocl1 = * cl1 ;
strcpy ( cl1 - > name , cl2 - > name ) ;
cl1 - > win = cl2 - > win ;
cl1 - > x = cl2 - > x ;
cl1 - > y = cl2 - > y ;
cl1 - > w = cl2 - > w ;
cl1 - > h = cl2 - > h ;
cl2 - > win = ocl1 . win ;
strcpy ( cl2 - > name , ocl1 . name ) ;
cl2 - > x = ocl1 . x ;
cl2 - > y = ocl1 . y ;
cl2 - > w = ocl1 . w ;
cl2 - > h = ocl1 . h ;
selmon - > sel = cl2 ;
c = cc ;
focus ( c ) ;
arrange ( cl1 - > mon ) ;
}
}
2024-05-10 20:01:34 +00:00
break ;
}
} while ( ev . type ! = ButtonRelease ) ;
XUngrabPointer ( dpy , CurrentTime ) ;
if ( ( m = recttomon ( c - > x , c - > y , c - > w , c - > h ) ) ! = selmon ) {
sendmon ( c , m ) ;
selmon = m ;
focus ( NULL ) ;
}
}
Client *
nexttiled ( Client * c )
{
2024-05-11 04:25:35 +00:00
for ( ; c & & ( c - > isfloating | | ! ISVISIBLE ( c ) | | HIDDEN ( c ) ) ; c = c - > next ) ;
2024-05-10 20:01:34 +00:00
return c ;
}
2024-05-23 23:42:15 +00:00
void
movestack ( const Arg * arg ) {
Client * c = NULL , * p = NULL , * pc = NULL , * i ;
if ( arg - > i > 0 ) {
/* find the client after selmon->sel */
for ( c = selmon - > sel - > next ; c & & ( ! ISVISIBLE ( c ) | | c - > isfloating ) ; c = c - > next ) ;
if ( ! c )
for ( c = selmon - > clients ; c & & ( ! ISVISIBLE ( c ) | | c - > isfloating ) ; c = c - > next ) ;
}
else {
/* find the client before selmon->sel */
for ( i = selmon - > clients ; i ! = selmon - > sel ; i = i - > next )
if ( ISVISIBLE ( i ) & & ! i - > isfloating )
c = i ;
if ( ! c )
for ( ; i ; i = i - > next )
if ( ISVISIBLE ( i ) & & ! i - > isfloating )
c = i ;
}
/* find the client before selmon->sel and c */
for ( i = selmon - > clients ; i & & ( ! p | | ! pc ) ; i = i - > next ) {
if ( i - > next = = selmon - > sel )
p = i ;
if ( i - > next = = c )
pc = i ;
}
/* swap c and selmon->sel selmon->clients in the selmon->clients list */
if ( c & & c ! = selmon - > sel ) {
Client * temp = selmon - > sel - > next = = c ? selmon - > sel : selmon - > sel - > next ;
selmon - > sel - > next = c - > next = = selmon - > sel ? c : c - > next ;
c - > next = temp ;
if ( p & & p ! = c )
p - > next = c ;
if ( pc & & pc ! = selmon - > sel )
pc - > next = selmon - > sel ;
if ( selmon - > sel = = selmon - > clients )
selmon - > clients = c ;
else if ( c = = selmon - > clients )
selmon - > clients = selmon - > sel ;
arrange ( selmon ) ;
}
}
2024-05-10 20:01:34 +00:00
void
pop ( Client * c )
{
detach ( c ) ;
attach ( c ) ;
focus ( c ) ;
arrange ( c - > mon ) ;
}
void
propertynotify ( XEvent * e )
{
Client * c ;
Window trans ;
XPropertyEvent * ev = & e - > xproperty ;
if ( ( ev - > window = = root ) & & ( ev - > atom = = XA_WM_NAME ) )
updatestatus ( ) ;
else if ( ev - > state = = PropertyDelete )
return ; /* ignore */
else if ( ( c = wintoclient ( ev - > window ) ) ) {
switch ( ev - > atom ) {
default : break ;
case XA_WM_TRANSIENT_FOR :
if ( ! c - > isfloating & & ( XGetTransientForHint ( dpy , c - > win , & trans ) ) & &
( c - > isfloating = ( wintoclient ( trans ) ) ! = NULL ) )
arrange ( c - > mon ) ;
break ;
case XA_WM_NORMAL_HINTS :
c - > hintsvalid = 0 ;
break ;
case XA_WM_HINTS :
updatewmhints ( c ) ;
drawbars ( ) ;
break ;
}
if ( ev - > atom = = XA_WM_NAME | | ev - > atom = = netatom [ NetWMName ] ) {
updatetitle ( c ) ;
if ( c = = c - > mon - > sel )
drawbar ( c - > mon ) ;
}
if ( ev - > atom = = netatom [ NetWMWindowType ] )
updatewindowtype ( c ) ;
}
}
void
quit ( const Arg * arg )
{
2024-05-11 04:25:35 +00:00
// fix: reloading dwm keeps all the hidden clients hidden
Monitor * m ;
Client * c ;
2024-05-20 22:06:37 +00:00
size_t i ;
/* kill child processes */
for ( i = 0 ; i < autostart_len ; i + + ) {
if ( 0 < autostart_pids [ i ] ) {
kill ( autostart_pids [ i ] , SIGTERM ) ;
waitpid ( autostart_pids [ i ] , NULL , 0 ) ;
}
}
2024-05-11 04:25:35 +00:00
for ( m = mons ; m ; m = m - > next ) {
if ( m ) {
for ( c = m - > stack ; c ; c = c - > next )
if ( c & & HIDDEN ( c ) ) showwin ( c ) ;
}
}
2024-05-11 01:05:59 +00:00
if ( arg - > i ) restart = 1 ;
2024-05-10 20:01:34 +00:00
running = 0 ;
}
Monitor *
recttomon ( int x , int y , int w , int h )
{
Monitor * m , * r = selmon ;
int a , area = 0 ;
for ( m = mons ; m ; m = m - > next )
if ( ( a = INTERSECT ( x , y , w , h , m ) ) > area ) {
area = a ;
r = m ;
}
return r ;
}
2024-05-23 23:37:03 +00:00
void
resetlayout ( const Arg * arg )
{
Arg default_layout = { . v = & layouts [ 0 ] } ;
Arg default_mfact = { . f = mfact + 1 } ;
setlayout ( & default_layout ) ;
setmfact ( & default_mfact ) ;
2024-05-23 23:38:10 +00:00
selmon - > nmaster = selmon - > pertag - > nmasters [ selmon - > pertag - > curtag ] = nmaster ;
arrange ( selmon ) ;
2024-05-25 00:43:21 +00:00
reorganizetags ( 0 ) ;
}
void
reorganizetags ( const Arg * arg ) {
Client * c ;
unsigned int occ , unocc , i ;
unsigned int tagdest [ LENGTH ( tags ) ] ;
occ = 0 ;
for ( c = selmon - > clients ; c ; c = c - > next )
occ | = ( 1 < < ( ffs ( c - > tags ) - 1 ) ) ;
unocc = 0 ;
for ( i = 0 ; i < LENGTH ( tags ) ; + + i ) {
while ( unocc < i & & ( occ & ( 1 < < unocc ) ) )
unocc + + ;
if ( occ & ( 1 < < i ) ) {
tagdest [ i ] = unocc ;
occ & = ~ ( 1 < < i ) ;
occ | = 1 < < unocc ;
}
}
for ( c = selmon - > clients ; c ; c = c - > next )
c - > tags = 1 < < tagdest [ ffs ( c - > tags ) - 1 ] ;
if ( selmon - > sel )
selmon - > tagset [ selmon - > seltags ] = selmon - > sel - > tags ;
arrange ( selmon ) ;
2024-05-23 23:37:03 +00:00
}
2024-05-10 20:01:34 +00:00
void
resize ( Client * c , int x , int y , int w , int h , int interact )
{
if ( applysizehints ( c , & x , & y , & w , & h , interact ) )
resizeclient ( c , x , y , w , h ) ;
}
void
resizeclient ( Client * c , int x , int y , int w , int h )
{
XWindowChanges wc ;
2024-05-23 03:33:28 +00:00
unsigned int n ;
Client * nbc ;
2024-05-10 20:01:34 +00:00
c - > oldx = c - > x ; c - > x = wc . x = x ;
c - > oldy = c - > y ; c - > y = wc . y = y ;
c - > oldw = c - > w ; c - > w = wc . width = w ;
c - > oldh = c - > h ; c - > h = wc . height = h ;
wc . border_width = c - > bw ;
2024-05-23 03:33:28 +00:00
2024-05-23 23:37:03 +00:00
if ( ( nexttiled ( c - > mon - > clients ) = = c ) & & ! ( nexttiled ( c - > next ) ) )
resetlayout ( NULL ) ;
2024-05-23 03:33:28 +00:00
for ( n = 0 , nbc = nexttiled ( c - > mon - > clients ) ; nbc ; nbc = nexttiled ( nbc - > next ) , n + + ) ;
if ( c - > isfloating | | c - > mon - > lt [ c - > mon - > sellt ] - > arrange = = NULL ) {
} else {
if ( c - > mon - > lt [ c - > mon - > sellt ] - > arrange = = monocle | | n = = 1 ) {
wc . border_width = 0 ;
c - > w = wc . width + = c - > bw * 2 ;
c - > h = wc . height + = c - > bw * 2 ;
}
2024-05-19 06:36:11 +00:00
}
2024-05-23 03:33:28 +00:00
2024-05-10 20:01:34 +00:00
XConfigureWindow ( dpy , c - > win , CWX | CWY | CWWidth | CWHeight | CWBorderWidth , & wc ) ;
configure ( c ) ;
XSync ( dpy , False ) ;
}
void
resizemouse ( const Arg * arg )
{
int ocx , ocy , nw , nh ;
2024-05-17 20:11:18 +00:00
int ocx2 , ocy2 , nx , ny ;
2024-05-15 20:08:05 +00:00
unsigned int i ;
2024-05-10 20:01:34 +00:00
Client * c ;
Monitor * m ;
XEvent ev ;
2024-05-17 20:11:18 +00:00
int horizcorner , vertcorner ;
int di ;
unsigned int dui ;
Window dummy ;
2024-05-10 20:01:34 +00:00
Time lasttime = 0 ;
if ( ! ( c = selmon - > sel ) )
return ;
if ( c - > isfullscreen ) /* no support resizing fullscreen windows by mouse */
return ;
restack ( selmon ) ;
ocx = c - > x ;
ocy = c - > y ;
2024-05-17 20:11:18 +00:00
ocx2 = c - > x + c - > w ;
ocy2 = c - > y + c - > h ;
2024-05-10 20:01:34 +00:00
if ( XGrabPointer ( dpy , root , False , MOUSEMASK , GrabModeAsync , GrabModeAsync ,
None , cursor [ CurResize ] - > cursor , CurrentTime ) ! = GrabSuccess )
return ;
2024-05-11 15:13:46 +00:00
if ( c - > isfloating | | NULL = = c - > mon - > lt [ c - > mon - > sellt ] - > arrange ) {
2024-05-17 20:30:59 +00:00
if ( ! XQueryPointer ( dpy , c - > win , & dummy , & dummy , & di , & di , & nx , & ny , & dui ) )
return ;
horizcorner = nx < c - > w / 2 ;
vertcorner = ny < c - > h / 2 ;
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 ,
2024-05-17 20:11:18 +00:00
horizcorner ? ( - c - > bw ) : ( c - > w + c - > bw - 1 ) ,
vertcorner ? ( - c - > bw ) : ( c - > h + c - > bw - 1 ) ) ;
2024-05-11 15:13:46 +00:00
} else {
XWarpPointer ( dpy , None , root , 0 , 0 , 0 , 0 ,
selmon - > mx + ( selmon - > ww * selmon - > mfact ) ,
selmon - > my + ( selmon - > wh / 2 )
) ;
}
2024-05-10 20:01:34 +00:00
do {
XMaskEvent ( dpy , MOUSEMASK | ExposureMask | SubstructureRedirectMask , & ev ) ;
switch ( ev . type ) {
case ConfigureRequest :
case Expose :
case MapRequest :
handler [ ev . type ] ( & ev ) ;
break ;
case MotionNotify :
if ( ( ev . xmotion . time - lasttime ) < = ( 1000 / 60 ) )
continue ;
lasttime = ev . xmotion . time ;
2024-05-17 20:11:18 +00:00
nx = horizcorner ? ev . xmotion . x : c - > x ;
ny = vertcorner ? ev . xmotion . y : c - > y ;
nw = MAX ( horizcorner ? ( ocx2 - nx ) : ( ev . xmotion . x - ocx - 2 * c - > bw + 1 ) , 1 ) ;
nh = MAX ( vertcorner ? ( ocy2 - ny ) : ( ev . xmotion . y - ocy - 2 * c - > bw + 1 ) , 1 ) ;
2024-05-11 15:13:46 +00:00
2024-05-10 20:01:34 +00:00
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | c - > isfloating )
2024-05-17 20:11:18 +00:00
resize ( c , nx , ny , nw , nh , 1 ) ;
2024-05-17 20:30:59 +00:00
/* >>>>>>HEAD */
2024-05-15 10:33:30 +00:00
else {
selmon - > mfact = ( double ) ( ev . xmotion . x_root - selmon - > mx ) / ( double ) selmon - > ww ;
2024-05-15 20:08:05 +00:00
for ( i = 0 ; i < LENGTH ( tags ) ; + + i )
if ( selmon - > tagset [ selmon - > seltags ] & 1 < < i )
selmon - > pertag - > mfacts [ i + 1 ] = selmon - > mfact ;
if ( selmon - > pertag - > curtag = = 0 )
selmon - > pertag - > mfacts [ 0 ] = selmon - > mfact ;
2024-05-15 10:33:30 +00:00
arrange ( selmon ) ;
}
2024-05-17 20:30:59 +00:00
/* ======= */
/* if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww */
/* && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) */
/* { */
/* if (!c->isfloating && selmon->lt[selmon->sellt]->arrange */
/* && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) */
/* togglefloating(NULL); */
/* } */
/* */
/* >>>>>>> corners */
2024-05-10 20:01:34 +00:00
break ;
}
2024-05-17 20:30:59 +00:00
}
while ( ev . type ! = ButtonRelease ) ;
2024-05-11 15:13:46 +00:00
if ( c - > isfloating | | NULL = = c - > mon - > lt [ c - > mon - > sellt ] - > arrange ) {
2024-05-17 20:30:59 +00:00
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 ,
horizcorner ? ( - c - > bw ) : ( c - > w + c - > bw - 1 ) ,
vertcorner ? ( - c - > bw ) : ( c - > h + c - > bw - 1 ) ) ;
2024-05-11 15:13:46 +00:00
} else {
XWarpPointer ( dpy , None , root , 0 , 0 , 0 , 0 ,
selmon - > mx + ( selmon - > ww * selmon - > mfact ) ,
2024-05-17 20:30:59 +00:00
selmon - > my + ( selmon - > wh / 2 ) ) ;
2024-05-11 15:13:46 +00:00
}
2024-05-10 20:01:34 +00:00
XUngrabPointer ( dpy , CurrentTime ) ;
while ( XCheckMaskEvent ( dpy , EnterWindowMask , & ev ) ) ;
if ( ( m = recttomon ( c - > x , c - > y , c - > w , c - > h ) ) ! = selmon ) {
sendmon ( c , m ) ;
selmon = m ;
focus ( NULL ) ;
}
}
void
restack ( Monitor * m )
{
Client * c ;
XEvent ev ;
XWindowChanges wc ;
drawbar ( m ) ;
if ( ! m - > sel )
return ;
if ( m - > sel - > isfloating | | ! m - > lt [ m - > sellt ] - > arrange )
XRaiseWindow ( dpy , m - > sel - > win ) ;
if ( m - > lt [ m - > sellt ] - > arrange ) {
wc . stack_mode = Below ;
wc . sibling = m - > barwin ;
for ( c = m - > stack ; c ; c = c - > snext )
if ( ! c - > isfloating & & ISVISIBLE ( c ) ) {
XConfigureWindow ( dpy , c - > win , CWSibling | CWStackMode , & wc ) ;
wc . sibling = c - > win ;
}
}
XSync ( dpy , False ) ;
while ( XCheckMaskEvent ( dpy , EnterWindowMask , & ev ) ) ;
}
void
run ( void )
{
XEvent ev ;
/* main event loop */
XSync ( dpy , False ) ;
while ( running & & ! XNextEvent ( dpy , & ev ) )
if ( handler [ ev . type ] )
handler [ ev . type ] ( & ev ) ; /* call handler */
}
void
scan ( void )
{
unsigned int i , num ;
Window d1 , d2 , * wins = NULL ;
XWindowAttributes wa ;
if ( XQueryTree ( dpy , root , & d1 , & d2 , & wins , & num ) ) {
for ( i = 0 ; i < num ; i + + ) {
if ( ! XGetWindowAttributes ( dpy , wins [ i ] , & wa )
| | wa . override_redirect | | XGetTransientForHint ( dpy , wins [ i ] , & d1 ) )
continue ;
if ( wa . map_state = = IsViewable | | getstate ( wins [ i ] ) = = IconicState )
manage ( wins [ i ] , & wa ) ;
}
for ( i = 0 ; i < num ; i + + ) { /* now the transients */
if ( ! XGetWindowAttributes ( dpy , wins [ i ] , & wa ) )
continue ;
if ( XGetTransientForHint ( dpy , wins [ i ] , & d1 )
& & ( wa . map_state = = IsViewable | | getstate ( wins [ i ] ) = = IconicState ) )
manage ( wins [ i ] , & wa ) ;
}
if ( wins )
XFree ( wins ) ;
}
}
void
sendmon ( Client * c , Monitor * m )
{
if ( c - > mon = = m )
return ;
unfocus ( c , 1 ) ;
detach ( c ) ;
detachstack ( c ) ;
c - > mon = m ;
c - > tags = m - > tagset [ m - > seltags ] ; /* assign tags of target monitor */
2024-05-10 22:38:38 +00:00
attachbottom ( c ) ;
2024-05-19 04:34:11 +00:00
c - > x = c - > mon - > mx + ( c - > mon - > mw - WIDTH ( c ) ) / 2 ;
c - > y = c - > mon - > my + ( c - > mon - > mh - HEIGHT ( c ) ) / 2 ;
2024-05-10 20:01:34 +00:00
attachstack ( c ) ;
2024-05-11 01:22:05 +00:00
setclienttagprop ( c ) ;
2024-05-10 20:01:34 +00:00
focus ( NULL ) ;
arrange ( NULL ) ;
}
void
setclientstate ( Client * c , long state )
{
long data [ ] = { state , None } ;
XChangeProperty ( dpy , c - > win , wmatom [ WMState ] , wmatom [ WMState ] , 32 ,
PropModeReplace , ( unsigned char * ) data , 2 ) ;
}
int
sendevent ( Client * c , Atom proto )
{
int n ;
Atom * protocols ;
int exists = 0 ;
XEvent ev ;
if ( XGetWMProtocols ( dpy , c - > win , & protocols , & n ) ) {
while ( ! exists & & n - - )
exists = protocols [ n ] = = proto ;
XFree ( protocols ) ;
}
if ( exists ) {
ev . type = ClientMessage ;
ev . xclient . window = c - > win ;
ev . xclient . message_type = wmatom [ WMProtocols ] ;
ev . xclient . format = 32 ;
ev . xclient . data . l [ 0 ] = proto ;
ev . xclient . data . l [ 1 ] = CurrentTime ;
XSendEvent ( dpy , c - > win , False , NoEventMask , & ev ) ;
}
return exists ;
}
void
setfocus ( Client * c )
{
if ( ! c - > neverfocus ) {
XSetInputFocus ( dpy , c - > win , RevertToPointerRoot , CurrentTime ) ;
XChangeProperty ( dpy , root , netatom [ NetActiveWindow ] ,
XA_WINDOW , 32 , PropModeReplace ,
( unsigned char * ) & ( c - > win ) , 1 ) ;
}
sendevent ( c , wmatom [ WMTakeFocus ] ) ;
}
void
setfullscreen ( Client * c , int fullscreen )
{
if ( fullscreen & & ! c - > isfullscreen ) {
XChangeProperty ( dpy , c - > win , netatom [ NetWMState ] , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) & netatom [ NetWMFullscreen ] , 1 ) ;
c - > isfullscreen = 1 ;
c - > oldstate = c - > isfloating ;
c - > oldbw = c - > bw ;
c - > bw = 0 ;
c - > isfloating = 1 ;
resizeclient ( c , c - > mon - > mx , c - > mon - > my , c - > mon - > mw , c - > mon - > mh ) ;
XRaiseWindow ( dpy , c - > win ) ;
} else if ( ! fullscreen & & c - > isfullscreen ) {
XChangeProperty ( dpy , c - > win , netatom [ NetWMState ] , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) 0 , 0 ) ;
c - > isfullscreen = 0 ;
c - > isfloating = c - > oldstate ;
c - > bw = c - > oldbw ;
c - > x = c - > oldx ;
c - > y = c - > oldy ;
c - > w = c - > oldw ;
c - > h = c - > oldh ;
resizeclient ( c , c - > x , c - > y , c - > w , c - > h ) ;
arrange ( c - > mon ) ;
}
}
void
setlayout ( const Arg * arg )
{
2024-05-11 01:37:08 +00:00
unsigned int i ;
2024-05-10 20:01:34 +00:00
if ( ! arg | | ! arg - > v | | arg - > v ! = selmon - > lt [ selmon - > sellt ] )
selmon - > sellt ^ = 1 ;
if ( arg & & arg - > v )
selmon - > lt [ selmon - > sellt ] = ( Layout * ) arg - > v ;
strncpy ( selmon - > ltsymbol , selmon - > lt [ selmon - > sellt ] - > symbol , sizeof selmon - > ltsymbol ) ;
2024-05-11 01:37:08 +00:00
for ( i = 0 ; i < LENGTH ( tags ) ; + + i )
if ( selmon - > tagset [ selmon - > seltags ] & 1 < < i )
{
selmon - > pertag - > ltidxs [ i + 1 ] [ selmon - > sellt ] = selmon - > lt [ selmon - > sellt ] ;
selmon - > pertag - > sellts [ i + 1 ] = selmon - > sellt ;
}
if ( selmon - > pertag - > curtag = = 0 )
{
selmon - > pertag - > ltidxs [ 0 ] [ selmon - > sellt ] = selmon - > lt [ selmon - > sellt ] ;
selmon - > pertag - > sellts [ 0 ] = selmon - > sellt ;
}
2024-05-10 20:01:34 +00:00
if ( selmon - > sel )
arrange ( selmon ) ;
else
drawbar ( selmon ) ;
}
/* arg > 1.0 will set mfact absolutely */
void
setmfact ( const Arg * arg )
{
float f ;
2024-05-11 01:37:08 +00:00
unsigned int i ;
2024-05-10 20:01:34 +00:00
if ( ! arg | | ! selmon - > lt [ selmon - > sellt ] - > arrange )
return ;
f = arg - > f < 1.0 ? arg - > f + selmon - > mfact : arg - > f - 1.0 ;
2024-05-11 01:37:08 +00:00
if ( arg - > f = = 0.0 )
f = mfact ;
2024-05-10 20:01:34 +00:00
if ( f < 0.05 | | f > 0.95 )
return ;
selmon - > mfact = f ;
2024-05-11 01:37:08 +00:00
for ( i = 0 ; i < LENGTH ( tags ) ; + + i )
if ( selmon - > tagset [ selmon - > seltags ] & 1 < < i )
selmon - > pertag - > mfacts [ i + 1 ] = f ;
if ( selmon - > pertag - > curtag = = 0 )
{
selmon - > pertag - > mfacts [ 0 ] = f ;
}
2024-05-10 20:01:34 +00:00
arrange ( selmon ) ;
}
void
setup ( void )
{
int i ;
2024-05-20 22:06:37 +00:00
pid_t pid ;
2024-05-10 20:01:34 +00:00
XSetWindowAttributes wa ;
Atom utf8string ;
struct sigaction sa ;
/* do not transform children into zombies when they terminate */
sigemptyset ( & sa . sa_mask ) ;
sa . sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART ;
sa . sa_handler = SIG_IGN ;
sigaction ( SIGCHLD , & sa , NULL ) ;
/* clean up any zombies (inherited from .xinitrc etc) immediately */
2024-05-20 22:06:37 +00:00
while ( ( pid = waitpid ( - 1 , NULL , WNOHANG ) ) > 0 ) {
pid_t * p , * lim ;
if ( ! ( p = autostart_pids ) )
continue ;
lim = & p [ autostart_len ] ;
for ( ; p < lim ; p + + ) {
if ( * p = = pid ) {
* p = - 1 ;
break ;
}
}
}
2024-05-10 20:01:34 +00:00
2024-05-11 01:05:59 +00:00
signal ( SIGHUP , sighup ) ;
signal ( SIGTERM , sigterm ) ;
2024-05-10 20:01:34 +00:00
/* init screen */
screen = DefaultScreen ( dpy ) ;
sw = DisplayWidth ( dpy , screen ) ;
sh = DisplayHeight ( dpy , screen ) ;
root = RootWindow ( dpy , screen ) ;
2024-05-10 22:23:16 +00:00
xinitvisual ( ) ;
drw = drw_create ( dpy , screen , root , sw , sh , visual , depth , cmap ) ;
2024-05-10 20:01:34 +00:00
if ( ! drw_fontset_create ( drw , fonts , LENGTH ( fonts ) ) )
die ( " no fonts could be loaded. " ) ;
lrpad = drw - > fonts - > h ;
2024-05-11 03:03:03 +00:00
bh = drw - > fonts - > h + user_bh ;
2024-05-19 05:32:12 +00:00
sp = sidepad ;
vp = ( topbar = = 1 ) ? vertpad : - vertpad ;
2024-05-10 20:01:34 +00:00
updategeom ( ) ;
/* init atoms */
utf8string = XInternAtom ( dpy , " UTF8_STRING " , False ) ;
wmatom [ WMProtocols ] = XInternAtom ( dpy , " WM_PROTOCOLS " , False ) ;
wmatom [ WMDelete ] = XInternAtom ( dpy , " WM_DELETE_WINDOW " , False ) ;
wmatom [ WMState ] = XInternAtom ( dpy , " WM_STATE " , False ) ;
wmatom [ WMTakeFocus ] = XInternAtom ( dpy , " WM_TAKE_FOCUS " , False ) ;
netatom [ NetActiveWindow ] = XInternAtom ( dpy , " _NET_ACTIVE_WINDOW " , False ) ;
netatom [ NetSupported ] = XInternAtom ( dpy , " _NET_SUPPORTED " , False ) ;
netatom [ NetWMName ] = XInternAtom ( dpy , " _NET_WM_NAME " , False ) ;
netatom [ NetWMState ] = XInternAtom ( dpy , " _NET_WM_STATE " , False ) ;
netatom [ NetWMCheck ] = XInternAtom ( dpy , " _NET_SUPPORTING_WM_CHECK " , False ) ;
netatom [ NetWMFullscreen ] = XInternAtom ( dpy , " _NET_WM_STATE_FULLSCREEN " , False ) ;
netatom [ NetWMWindowType ] = XInternAtom ( dpy , " _NET_WM_WINDOW_TYPE " , False ) ;
netatom [ NetWMWindowTypeDialog ] = XInternAtom ( dpy , " _NET_WM_WINDOW_TYPE_DIALOG " , False ) ;
netatom [ NetClientList ] = XInternAtom ( dpy , " _NET_CLIENT_LIST " , False ) ;
2024-05-11 01:22:05 +00:00
netatom [ NetClientInfo ] = XInternAtom ( dpy , " _NET_CLIENT_INFO " , False ) ;
2024-05-10 20:01:34 +00:00
/* init cursors */
cursor [ CurNormal ] = drw_cur_create ( drw , XC_left_ptr ) ;
cursor [ CurResize ] = drw_cur_create ( drw , XC_sizing ) ;
cursor [ CurMove ] = drw_cur_create ( drw , XC_fleur ) ;
/* init appearance */
scheme = ecalloc ( LENGTH ( colors ) , sizeof ( Clr * ) ) ;
for ( i = 0 ; i < LENGTH ( colors ) ; i + + )
2024-05-10 22:23:16 +00:00
scheme [ i ] = drw_scm_create ( drw , colors [ i ] , alphas [ i ] , 3 ) ;
2024-05-10 20:01:34 +00:00
/* init bars */
updatebars ( ) ;
updatestatus ( ) ;
/* supporting window for NetWMCheck */
wmcheckwin = XCreateSimpleWindow ( dpy , root , 0 , 0 , 1 , 1 , 0 , 0 , 0 ) ;
XChangeProperty ( dpy , wmcheckwin , netatom [ NetWMCheck ] , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) & wmcheckwin , 1 ) ;
XChangeProperty ( dpy , wmcheckwin , netatom [ NetWMName ] , utf8string , 8 ,
PropModeReplace , ( unsigned char * ) " dwm " , 3 ) ;
XChangeProperty ( dpy , root , netatom [ NetWMCheck ] , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) & wmcheckwin , 1 ) ;
/* EWMH support per view */
XChangeProperty ( dpy , root , netatom [ NetSupported ] , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) netatom , NetLast ) ;
XDeleteProperty ( dpy , root , netatom [ NetClientList ] ) ;
2024-05-11 01:22:05 +00:00
XDeleteProperty ( dpy , root , netatom [ NetClientInfo ] ) ;
2024-05-10 20:01:34 +00:00
/* select events */
wa . cursor = cursor [ CurNormal ] - > cursor ;
wa . event_mask = SubstructureRedirectMask | SubstructureNotifyMask
| ButtonPressMask | PointerMotionMask | EnterWindowMask
| LeaveWindowMask | StructureNotifyMask | PropertyChangeMask ;
XChangeWindowAttributes ( dpy , root , CWEventMask | CWCursor , & wa ) ;
XSelectInput ( dpy , root , wa . event_mask ) ;
grabkeys ( ) ;
focus ( NULL ) ;
}
void
seturgent ( Client * c , int urg )
{
XWMHints * wmh ;
c - > isurgent = urg ;
if ( ! ( wmh = XGetWMHints ( dpy , c - > win ) ) )
return ;
wmh - > flags = urg ? ( wmh - > flags | XUrgencyHint ) : ( wmh - > flags & ~ XUrgencyHint ) ;
XSetWMHints ( dpy , c - > win , wmh ) ;
XFree ( wmh ) ;
}
2024-05-11 04:25:35 +00:00
void
show ( const Arg * arg )
{
if ( selmon - > hidsel )
selmon - > hidsel = 0 ;
showwin ( selmon - > sel ) ;
}
void
showall ( const Arg * arg )
{
Client * c = NULL ;
selmon - > hidsel = 0 ;
for ( c = selmon - > clients ; c ; c = c - > next ) {
if ( ISVISIBLE ( c ) )
showwin ( c ) ;
}
if ( ! selmon - > sel ) {
for ( c = selmon - > clients ; c & & ! ISVISIBLE ( c ) ; c = c - > next ) ;
if ( c )
focus ( c ) ;
}
restack ( selmon ) ;
}
void
showwin ( Client * c )
{
if ( ! c | | ! HIDDEN ( c ) )
return ;
XMapWindow ( dpy , c - > win ) ;
setclientstate ( c , NormalState ) ;
arrange ( c - > mon ) ;
}
2024-05-10 20:01:34 +00:00
void
showhide ( Client * c )
{
if ( ! c )
return ;
if ( ISVISIBLE ( c ) ) {
/* show clients top down */
2024-05-25 01:36:09 +00:00
window_map ( dpy , c , 1 ) ;
2024-05-10 20:01:34 +00:00
showhide ( c - > snext ) ;
} else {
/* hide clients bottom up */
showhide ( c - > snext ) ;
2024-05-25 01:36:09 +00:00
window_unmap ( dpy , c - > win , root , 1 ) ;
2024-05-10 20:01:34 +00:00
}
}
2024-05-11 01:05:59 +00:00
void
sighup ( int unused )
{
Arg a = { . i = 1 } ;
quit ( & a ) ;
}
void
sigterm ( int unused )
{
Arg a = { . i = 0 } ;
quit ( & a ) ;
}
2024-05-10 20:01:34 +00:00
void
spawn ( const Arg * arg )
{
struct sigaction sa ;
if ( arg - > v = = dmenucmd )
dmenumon [ 0 ] = ' 0 ' + selmon - > num ;
if ( fork ( ) = = 0 ) {
if ( dpy )
close ( ConnectionNumber ( dpy ) ) ;
setsid ( ) ;
sigemptyset ( & sa . sa_mask ) ;
sa . sa_flags = 0 ;
sa . sa_handler = SIG_DFL ;
sigaction ( SIGCHLD , & sa , NULL ) ;
execvp ( ( ( char * * ) arg - > v ) [ 0 ] , ( char * * ) arg - > v ) ;
die ( " dwm: execvp '%s' failed: " , ( ( char * * ) arg - > v ) [ 0 ] ) ;
}
}
2024-05-11 01:22:05 +00:00
void
setclienttagprop ( Client * c )
{
long data [ ] = { ( long ) c - > tags , ( long ) c - > mon - > num } ;
XChangeProperty ( dpy , c - > win , netatom [ NetClientInfo ] , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) data , 2 ) ;
}
2024-05-10 20:01:34 +00:00
void
tag ( const Arg * arg )
{
2024-05-11 01:22:05 +00:00
Client * c ;
2024-05-10 20:01:34 +00:00
if ( selmon - > sel & & arg - > ui & TAGMASK ) {
2024-05-11 01:22:05 +00:00
c = selmon - > sel ;
2024-05-10 20:01:34 +00:00
selmon - > sel - > tags = arg - > ui & TAGMASK ;
2024-05-11 01:22:05 +00:00
setclienttagprop ( c ) ;
2024-05-10 20:01:34 +00:00
focus ( NULL ) ;
arrange ( selmon ) ;
}
2024-05-17 03:26:11 +00:00
if ( wfsymbol [ 0 ] = = WFACTIVE )
2024-05-11 05:55:46 +00:00
view ( arg ) ;
2024-05-10 20:01:34 +00:00
}
void
tagmon ( const Arg * arg )
{
if ( ! selmon - > sel | | ! mons - > next )
return ;
sendmon ( selmon - > sel , dirtomon ( arg - > i ) ) ;
2024-05-17 03:26:11 +00:00
if ( wfsymbol [ 0 ] = = WFACTIVE )
2024-05-11 05:55:46 +00:00
focusmon ( arg ) ;
2024-05-10 20:01:34 +00:00
}
void
tile ( Monitor * m )
{
2024-05-19 06:30:54 +00:00
unsigned int i , n , h , mw , my , ty , ns ;
2024-05-10 20:01:34 +00:00
Client * c ;
for ( n = 0 , c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) , n + + ) ;
if ( n = = 0 )
return ;
2024-05-19 06:30:54 +00:00
if ( n > m - > nmaster ) {
2024-05-10 20:01:34 +00:00
mw = m - > nmaster ? m - > ww * m - > mfact : 0 ;
2024-05-19 06:30:54 +00:00
ns = m - > nmaster > 0 ? 2 : 1 ;
} else {
2024-05-10 20:01:34 +00:00
mw = m - > ww ;
2024-05-19 06:30:54 +00:00
ns = 1 ;
}
for ( i = 0 , my = ty = gappx , c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) , i + + )
2024-05-10 20:01:34 +00:00
if ( i < m - > nmaster ) {
2024-05-19 06:30:54 +00:00
h = ( m - > wh - my ) / ( MIN ( n , m - > nmaster ) - i ) - gappx ;
resize ( c , m - > wx + gappx , m - > wy + my , mw - ( 2 * c - > bw ) - gappx * ( 5 - ns ) / 2 , h - ( 2 * c - > bw ) , False ) ;
2024-05-10 20:01:34 +00:00
if ( my + HEIGHT ( c ) < m - > wh )
2024-05-19 06:30:54 +00:00
my + = HEIGHT ( c ) + gappx ;
2024-05-10 20:01:34 +00:00
} else {
2024-05-19 06:30:54 +00:00
h = ( m - > wh - ty ) / ( n - i ) - gappx ;
resize ( c , m - > wx + mw + gappx / ns , m - > wy + ty , m - > ww - mw - ( 2 * c - > bw ) - gappx * ( 5 - ns ) / 2 , h - ( 2 * c - > bw ) , False ) ;
2024-05-10 20:01:34 +00:00
if ( ty + HEIGHT ( c ) < m - > wh )
2024-05-19 06:30:54 +00:00
ty + = HEIGHT ( c ) + gappx ;
2024-05-10 20:01:34 +00:00
}
}
void
togglebar ( const Arg * arg )
{
2024-05-11 01:37:08 +00:00
unsigned int i ;
2024-05-10 20:01:34 +00:00
selmon - > showbar = ! selmon - > showbar ;
2024-05-11 01:37:08 +00:00
for ( i = 0 ; i < LENGTH ( tags ) ; + + i )
if ( selmon - > tagset [ selmon - > seltags ] & 1 < < i )
selmon - > pertag - > showbars [ i + 1 ] = selmon - > showbar ;
if ( selmon - > pertag - > curtag = = 0 )
{
selmon - > pertag - > showbars [ 0 ] = selmon - > showbar ;
}
2024-05-10 20:01:34 +00:00
updatebarpos ( selmon ) ;
2024-05-19 05:32:12 +00:00
XMoveResizeWindow ( dpy , selmon - > barwin , selmon - > wx + sp , selmon - > by + vp , selmon - > ww - 2 * sp , bh ) ;
2024-05-10 20:01:34 +00:00
arrange ( selmon ) ;
}
2024-05-10 21:47:45 +00:00
void
toggleextrabar ( const Arg * arg )
{
selmon - > extrabar = ! selmon - > extrabar ;
updatebarpos ( selmon ) ;
2024-06-04 03:49:53 +00:00
XMoveResizeWindow ( dpy , selmon - > extrabarwin , selmon - > wx + sp , selmon - > eby - vp , selmon - > ww - 2 * sp , bh ) ;
2024-05-10 21:47:45 +00:00
arrange ( selmon ) ;
}
2024-05-11 05:55:46 +00:00
void
togglefollow ( const Arg * arg )
{
2024-05-17 03:26:11 +00:00
wfsymbol [ 0 ] = ( wfsymbol [ 0 ] = = WFACTIVE ) ? WFINACTIVE : WFACTIVE ;
2024-05-11 05:55:46 +00:00
drawbars ( ) ;
}
2024-05-10 20:01:34 +00:00
void
togglefloating ( const Arg * arg )
{
if ( ! selmon - > sel )
return ;
if ( selmon - > sel - > isfullscreen ) /* no support for fullscreen windows */
return ;
selmon - > sel - > isfloating = ! selmon - > sel - > isfloating | | selmon - > sel - > isfixed ;
if ( selmon - > sel - > isfloating )
2024-05-11 02:51:27 +00:00
/* restore last known float dimensions */
resize ( selmon - > sel , selmon - > sel - > sfx , selmon - > sel - > sfy ,
selmon - > sel - > sfw , selmon - > sel - > sfh , False ) ;
else {
/* save last known float dimensions */
selmon - > sel - > sfx = selmon - > sel - > x ;
selmon - > sel - > sfy = selmon - > sel - > y ;
selmon - > sel - > sfw = selmon - > sel - > w ;
selmon - > sel - > sfh = selmon - > sel - > h ;
}
2024-05-11 02:05:01 +00:00
selmon - > sel - > x = selmon - > sel - > mon - > mx + ( selmon - > sel - > mon - > mw - WIDTH ( selmon - > sel ) ) / 2 ;
selmon - > sel - > y = selmon - > sel - > mon - > my + ( selmon - > sel - > mon - > mh - HEIGHT ( selmon - > sel ) ) / 2 ;
2024-05-10 20:01:34 +00:00
arrange ( selmon ) ;
}
2024-05-19 04:37:47 +00:00
void
togglefullscr ( const Arg * arg )
{
if ( selmon - > sel )
setfullscreen ( selmon - > sel , ! selmon - > sel - > isfullscreen ) ;
}
2024-05-10 20:01:34 +00:00
void
toggletag ( const Arg * arg )
{
unsigned int newtags ;
if ( ! selmon - > sel )
return ;
newtags = selmon - > sel - > tags ^ ( arg - > ui & TAGMASK ) ;
if ( newtags ) {
selmon - > sel - > tags = newtags ;
2024-05-11 01:22:05 +00:00
setclienttagprop ( selmon - > sel ) ;
2024-05-10 20:01:34 +00:00
focus ( NULL ) ;
arrange ( selmon ) ;
}
}
void
toggleview ( const Arg * arg )
{
unsigned int newtagset = selmon - > tagset [ selmon - > seltags ] ^ ( arg - > ui & TAGMASK ) ;
2024-05-11 01:37:08 +00:00
int i ;
2024-05-10 20:01:34 +00:00
if ( newtagset ) {
selmon - > tagset [ selmon - > seltags ] = newtagset ;
2024-05-11 01:37:08 +00:00
if ( newtagset = = ~ 0 ) {
selmon - > pertag - > prevtag = selmon - > pertag - > curtag ;
selmon - > pertag - > curtag = 0 ;
}
/* test if the user did not select the same tag */
if ( ! ( newtagset & 1 < < ( selmon - > pertag - > curtag - 1 ) ) ) {
selmon - > pertag - > prevtag = selmon - > pertag - > curtag ;
for ( i = 0 ; ! ( newtagset & 1 < < i ) ; i + + ) ;
selmon - > pertag - > curtag = i + 1 ;
}
/* apply settings for this view */
selmon - > nmaster = selmon - > pertag - > nmasters [ selmon - > pertag - > curtag ] ;
selmon - > mfact = selmon - > pertag - > mfacts [ selmon - > pertag - > curtag ] ;
selmon - > sellt = selmon - > pertag - > sellts [ selmon - > pertag - > curtag ] ;
selmon - > lt [ selmon - > sellt ] = selmon - > pertag - > ltidxs [ selmon - > pertag - > curtag ] [ selmon - > sellt ] ;
selmon - > lt [ selmon - > sellt ^ 1 ] = selmon - > pertag - > ltidxs [ selmon - > pertag - > curtag ] [ selmon - > sellt ^ 1 ] ;
if ( selmon - > showbar ! = selmon - > pertag - > showbars [ selmon - > pertag - > curtag ] )
togglebar ( NULL ) ;
2024-05-10 20:01:34 +00:00
focus ( NULL ) ;
arrange ( selmon ) ;
}
}
2024-05-11 04:25:35 +00:00
void
togglewin ( const Arg * arg )
{
Client * c = ( Client * ) arg - > v ;
if ( c = = selmon - > sel ) {
hidewin ( c ) ;
focus ( NULL ) ;
arrange ( c - > mon ) ;
} else {
if ( HIDDEN ( c ) )
showwin ( c ) ;
focus ( c ) ;
restack ( selmon ) ;
2024-05-17 02:56:17 +00:00
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w / 2 , c - > h / 2 ) ;
2024-05-11 04:25:35 +00:00
}
}
2024-05-10 20:01:34 +00:00
void
unfocus ( Client * c , int setfocus )
{
if ( ! c )
return ;
grabbuttons ( c , 0 ) ;
XSetWindowBorder ( dpy , c - > win , scheme [ SchemeNorm ] [ ColBorder ] . pixel ) ;
if ( setfocus ) {
XSetInputFocus ( dpy , root , RevertToPointerRoot , CurrentTime ) ;
XDeleteProperty ( dpy , root , netatom [ NetActiveWindow ] ) ;
}
}
void
unmanage ( Client * c , int destroyed )
{
Monitor * m = c - > mon ;
XWindowChanges wc ;
2024-05-11 04:43:32 +00:00
if ( c - > swallowing ) {
unswallow ( c ) ;
return ;
}
Client * s = swallowingclient ( c - > win ) ;
if ( s ) {
free ( s - > swallowing ) ;
s - > swallowing = NULL ;
arrange ( m ) ;
focus ( NULL ) ;
return ;
}
2024-05-10 20:01:34 +00:00
detach ( c ) ;
detachstack ( c ) ;
if ( ! destroyed ) {
wc . border_width = c - > oldbw ;
XGrabServer ( dpy ) ; /* avoid race conditions */
XSetErrorHandler ( xerrordummy ) ;
XSelectInput ( dpy , c - > win , NoEventMask ) ;
XConfigureWindow ( dpy , c - > win , CWBorderWidth , & wc ) ; /* restore border */
XUngrabButton ( dpy , AnyButton , AnyModifier , c - > win ) ;
setclientstate ( c , WithdrawnState ) ;
XSync ( dpy , False ) ;
XSetErrorHandler ( xerror ) ;
XUngrabServer ( dpy ) ;
}
free ( c ) ;
2024-05-11 04:43:32 +00:00
if ( ! s ) {
arrange ( m ) ;
focus ( NULL ) ;
updateclientlist ( ) ;
2024-05-17 02:56:17 +00:00
if ( m = = selmon & & m - > sel )
XWarpPointer ( dpy , None , m - > sel - > win , 0 , 0 , 0 , 0 ,
m - > sel - > w / 2 , m - > sel - > h / 2 ) ;
2024-05-11 04:43:32 +00:00
}
2024-05-10 20:01:34 +00:00
}
void
unmapnotify ( XEvent * e )
{
Client * c ;
XUnmapEvent * ev = & e - > xunmap ;
if ( ( c = wintoclient ( ev - > window ) ) ) {
if ( ev - > send_event )
setclientstate ( c , WithdrawnState ) ;
else
unmanage ( c , 0 ) ;
}
}
void
updatebars ( void )
{
Monitor * m ;
XSetWindowAttributes wa = {
. override_redirect = True ,
2024-05-10 22:23:16 +00:00
. background_pixel = 0 ,
. border_pixel = 0 ,
. colormap = cmap ,
2024-05-10 20:01:34 +00:00
. event_mask = ButtonPressMask | ExposureMask
} ;
XClassHint ch = { " dwm " , " dwm " } ;
for ( m = mons ; m ; m = m - > next ) {
2024-05-10 21:47:45 +00:00
if ( ! m - > barwin ) {
2024-05-19 05:32:12 +00:00
m - > barwin = XCreateWindow ( dpy , root , m - > wx + sp , m - > by + vp , m - > ww - 2 * sp , bh , 0 , depth ,
2024-05-10 22:23:16 +00:00
InputOutput , visual ,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask , & wa ) ;
2024-05-10 21:47:45 +00:00
XDefineCursor ( dpy , m - > barwin , cursor [ CurNormal ] - > cursor ) ;
XMapRaised ( dpy , m - > barwin ) ;
XSetClassHint ( dpy , m - > barwin , & ch ) ;
}
if ( ! m - > extrabarwin ) {
2024-05-19 05:32:12 +00:00
m - > extrabarwin = XCreateWindow ( dpy , root , m - > wx + sp , m - > eby - vp , m - > ww - 2 * sp , bh , 0 , depth ,
2024-05-10 22:23:16 +00:00
InputOutput , visual ,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask , & wa ) ;
2024-05-10 21:47:45 +00:00
XDefineCursor ( dpy , m - > extrabarwin , cursor [ CurNormal ] - > cursor ) ;
XMapRaised ( dpy , m - > extrabarwin ) ;
XSetClassHint ( dpy , m - > extrabarwin , & ch ) ;
}
2024-05-10 20:01:34 +00:00
}
}
void
updatebarpos ( Monitor * m )
{
m - > wy = m - > my ;
m - > wh = m - > mh ;
if ( m - > showbar ) {
2024-05-19 05:32:12 +00:00
m - > wh = m - > wh - vertpad - bh ;
m - > by = m - > topbar ? m - > wy : m - > wy + m - > wh + vertpad ;
m - > wy = m - > topbar ? m - > wy + bh + vp : m - > wy ;
2024-05-10 20:01:34 +00:00
} else
2024-05-19 05:32:12 +00:00
m - > by = - bh - vp ;
2024-05-10 21:47:45 +00:00
if ( m - > extrabar ) {
2024-05-19 05:32:12 +00:00
m - > wh = m - > wh - vertpad - bh ;
m - > eby = ! m - > topbar ? m - > wy : m - > wy + m - > wh + vertpad ;
m - > wy = ! m - > topbar ? m - > wy + bh + vp : m - > wy ;
2024-05-10 21:47:45 +00:00
} else
2024-05-19 05:32:12 +00:00
m - > eby = - bh - vp ;
2024-05-10 20:01:34 +00:00
}
void
updateclientlist ( )
{
Client * c ;
Monitor * m ;
XDeleteProperty ( dpy , root , netatom [ NetClientList ] ) ;
for ( m = mons ; m ; m = m - > next )
for ( c = m - > clients ; c ; c = c - > next )
XChangeProperty ( dpy , root , netatom [ NetClientList ] ,
XA_WINDOW , 32 , PropModeAppend ,
( unsigned char * ) & ( c - > win ) , 1 ) ;
}
int
updategeom ( void )
{
int dirty = 0 ;
# ifdef XINERAMA
if ( XineramaIsActive ( dpy ) ) {
int i , j , n , nn ;
Client * c ;
Monitor * m ;
XineramaScreenInfo * info = XineramaQueryScreens ( dpy , & nn ) ;
XineramaScreenInfo * unique = NULL ;
for ( n = 0 , m = mons ; m ; m = m - > next , n + + ) ;
/* only consider unique geometries as separate screens */
unique = ecalloc ( nn , sizeof ( XineramaScreenInfo ) ) ;
for ( i = 0 , j = 0 ; i < nn ; i + + )
if ( isuniquegeom ( unique , j , & info [ i ] ) )
memcpy ( & unique [ j + + ] , & info [ i ] , sizeof ( XineramaScreenInfo ) ) ;
XFree ( info ) ;
nn = j ;
/* new monitors if nn > n */
for ( i = n ; i < nn ; i + + ) {
for ( m = mons ; m & & m - > next ; m = m - > next ) ;
if ( m )
m - > next = createmon ( ) ;
else
mons = createmon ( ) ;
}
for ( i = 0 , m = mons ; i < nn & & m ; m = m - > next , i + + )
if ( i > = n
| | unique [ i ] . x_org ! = m - > mx | | unique [ i ] . y_org ! = m - > my
| | unique [ i ] . width ! = m - > mw | | unique [ i ] . height ! = m - > mh )
{
dirty = 1 ;
m - > num = i ;
m - > mx = m - > wx = unique [ i ] . x_org ;
m - > my = m - > wy = unique [ i ] . y_org ;
m - > mw = m - > ww = unique [ i ] . width ;
m - > mh = m - > wh = unique [ i ] . height ;
updatebarpos ( m ) ;
}
/* removed monitors if n > nn */
for ( i = nn ; i < n ; i + + ) {
for ( m = mons ; m & & m - > next ; m = m - > next ) ;
while ( ( c = m - > clients ) ) {
dirty = 1 ;
m - > clients = c - > next ;
detachstack ( c ) ;
c - > mon = mons ;
2024-05-10 22:38:38 +00:00
attachbottom ( c ) ;
2024-05-10 20:01:34 +00:00
attachstack ( c ) ;
}
if ( m = = selmon )
selmon = mons ;
cleanupmon ( m ) ;
}
free ( unique ) ;
} else
# endif /* XINERAMA */
{ /* default monitor setup */
if ( ! mons )
mons = createmon ( ) ;
if ( mons - > mw ! = sw | | mons - > mh ! = sh ) {
dirty = 1 ;
mons - > mw = mons - > ww = sw ;
mons - > mh = mons - > wh = sh ;
updatebarpos ( mons ) ;
}
}
if ( dirty ) {
selmon = mons ;
selmon = wintomon ( root ) ;
}
return dirty ;
}
void
updatenumlockmask ( void )
{
unsigned int i , j ;
XModifierKeymap * modmap ;
numlockmask = 0 ;
modmap = XGetModifierMapping ( dpy ) ;
for ( i = 0 ; i < 8 ; i + + )
for ( j = 0 ; j < modmap - > max_keypermod ; j + + )
if ( modmap - > modifiermap [ i * modmap - > max_keypermod + j ]
= = XKeysymToKeycode ( dpy , XK_Num_Lock ) )
numlockmask = ( 1 < < i ) ;
XFreeModifiermap ( modmap ) ;
}
void
updatesizehints ( Client * c )
{
long msize ;
XSizeHints size ;
if ( ! XGetWMNormalHints ( dpy , c - > win , & size , & msize ) )
/* size is uninitialized, ensure that size.flags aren't used */
size . flags = PSize ;
if ( size . flags & PBaseSize ) {
c - > basew = size . base_width ;
c - > baseh = size . base_height ;
} else if ( size . flags & PMinSize ) {
c - > basew = size . min_width ;
c - > baseh = size . min_height ;
} else
c - > basew = c - > baseh = 0 ;
if ( size . flags & PResizeInc ) {
c - > incw = size . width_inc ;
c - > inch = size . height_inc ;
} else
c - > incw = c - > inch = 0 ;
if ( size . flags & PMaxSize ) {
c - > maxw = size . max_width ;
c - > maxh = size . max_height ;
} else
c - > maxw = c - > maxh = 0 ;
if ( size . flags & PMinSize ) {
c - > minw = size . min_width ;
c - > minh = size . min_height ;
} else if ( size . flags & PBaseSize ) {
c - > minw = size . base_width ;
c - > minh = size . base_height ;
} else
c - > minw = c - > minh = 0 ;
if ( size . flags & PAspect ) {
c - > mina = ( float ) size . min_aspect . y / size . min_aspect . x ;
c - > maxa = ( float ) size . max_aspect . x / size . max_aspect . y ;
} else
c - > maxa = c - > mina = 0.0 ;
c - > isfixed = ( c - > maxw & & c - > maxh & & c - > maxw = = c - > minw & & c - > maxh = = c - > minh ) ;
c - > hintsvalid = 1 ;
}
void
updatestatus ( void )
{
2024-05-11 01:40:10 +00:00
Monitor * m ;
2024-05-10 21:47:45 +00:00
char text [ 768 ] ;
if ( ! gettextprop ( root , XA_WM_NAME , text , sizeof ( text ) ) ) {
2024-05-10 20:01:34 +00:00
strcpy ( stext , " dwm- " VERSION ) ;
2024-05-22 14:05:25 +00:00
estext [ 0 ] = ' \0 ' ;
2024-05-10 21:47:45 +00:00
} else {
2024-05-22 14:05:25 +00:00
char * s = strchr ( text , statussep ) ;
if ( s ) {
* s = ' \0 ' ; s + + ;
strncpy ( estext , s , sizeof ( estext ) - 1 ) ;
2024-05-10 21:47:45 +00:00
} else
2024-05-22 14:05:25 +00:00
estext [ 0 ] = ' \0 ' ;
2024-05-10 21:47:45 +00:00
strncpy ( stext , text , sizeof ( stext ) - 1 ) ;
}
2024-05-11 01:40:10 +00:00
for ( m = mons ; m ; m = m - > next )
drawbar ( m ) ;
2024-05-10 20:01:34 +00:00
}
void
updatetitle ( Client * c )
{
if ( ! gettextprop ( c - > win , netatom [ NetWMName ] , c - > name , sizeof c - > name ) )
gettextprop ( c - > win , XA_WM_NAME , c - > name , sizeof c - > name ) ;
if ( c - > name [ 0 ] = = ' \0 ' ) /* hack to mark broken clients */
strcpy ( c - > name , broken ) ;
}
void
updatewindowtype ( Client * c )
{
Atom state = getatomprop ( c , netatom [ NetWMState ] ) ;
Atom wtype = getatomprop ( c , netatom [ NetWMWindowType ] ) ;
if ( state = = netatom [ NetWMFullscreen ] )
setfullscreen ( c , 1 ) ;
if ( wtype = = netatom [ NetWMWindowTypeDialog ] )
c - > isfloating = 1 ;
}
void
updatewmhints ( Client * c )
{
XWMHints * wmh ;
if ( ( wmh = XGetWMHints ( dpy , c - > win ) ) ) {
if ( c = = selmon - > sel & & wmh - > flags & XUrgencyHint ) {
wmh - > flags & = ~ XUrgencyHint ;
XSetWMHints ( dpy , c - > win , wmh ) ;
} else
c - > isurgent = ( wmh - > flags & XUrgencyHint ) ? 1 : 0 ;
if ( wmh - > flags & InputHint )
c - > neverfocus = ! wmh - > input ;
else
c - > neverfocus = 0 ;
XFree ( wmh ) ;
}
}
2024-05-25 01:36:09 +00:00
void
window_set_state ( Display * dpy , Window win , long state )
{
long data [ ] = { state , None } ;
XChangeProperty ( dpy , win , wmatom [ WMState ] , wmatom [ WMState ] , 32 ,
PropModeReplace , ( unsigned char * ) data , 2 ) ;
}
void
window_map ( Display * dpy , Client * c , int deiconify )
{
Window win = c - > win ;
if ( deiconify )
window_set_state ( dpy , win , NormalState ) ;
XMoveResizeWindow ( dpy , c - > win , c - > x , c - > y , c - > w , c - > h ) ;
XSetInputFocus ( dpy , win , RevertToPointerRoot , CurrentTime ) ;
XMapWindow ( dpy , win ) ;
}
void
window_unmap ( Display * dpy , Window win , Window root , int iconify )
{
static XWindowAttributes ca , ra ;
XGrabServer ( dpy ) ;
XGetWindowAttributes ( dpy , root , & ra ) ;
XGetWindowAttributes ( dpy , win , & ca ) ;
/* Prevent UnmapNotify events */
XSelectInput ( dpy , root , ra . your_event_mask & ~ SubstructureNotifyMask ) ;
XSelectInput ( dpy , win , ca . your_event_mask & ~ StructureNotifyMask ) ;
XUnmapWindow ( dpy , win ) ;
if ( iconify )
window_set_state ( dpy , win , IconicState ) ;
XSelectInput ( dpy , root , ra . your_event_mask ) ;
XSelectInput ( dpy , win , ca . your_event_mask ) ;
XUngrabServer ( dpy ) ;
}
2024-05-10 20:01:34 +00:00
void
view ( const Arg * arg )
{
2024-05-11 01:37:08 +00:00
int i ;
unsigned int tmptag ;
2024-05-10 20:01:34 +00:00
if ( ( arg - > ui & TAGMASK ) = = selmon - > tagset [ selmon - > seltags ] )
return ;
selmon - > seltags ^ = 1 ; /* toggle sel tagset */
2024-05-11 01:37:08 +00:00
if ( arg - > ui & TAGMASK ) {
2024-05-10 20:01:34 +00:00
selmon - > tagset [ selmon - > seltags ] = arg - > ui & TAGMASK ;
2024-05-11 01:37:08 +00:00
selmon - > pertag - > prevtag = selmon - > pertag - > curtag ;
if ( arg - > ui = = ~ 0 )
selmon - > pertag - > curtag = 0 ;
else {
for ( i = 0 ; ! ( arg - > ui & 1 < < i ) ; i + + ) ;
selmon - > pertag - > curtag = i + 1 ;
}
} else {
tmptag = selmon - > pertag - > prevtag ;
selmon - > pertag - > prevtag = selmon - > pertag - > curtag ;
selmon - > pertag - > curtag = tmptag ;
}
selmon - > nmaster = selmon - > pertag - > nmasters [ selmon - > pertag - > curtag ] ;
selmon - > mfact = selmon - > pertag - > mfacts [ selmon - > pertag - > curtag ] ;
selmon - > sellt = selmon - > pertag - > sellts [ selmon - > pertag - > curtag ] ;
selmon - > lt [ selmon - > sellt ] = selmon - > pertag - > ltidxs [ selmon - > pertag - > curtag ] [ selmon - > sellt ] ;
selmon - > lt [ selmon - > sellt ^ 1 ] = selmon - > pertag - > ltidxs [ selmon - > pertag - > curtag ] [ selmon - > sellt ^ 1 ] ;
if ( selmon - > showbar ! = selmon - > pertag - > showbars [ selmon - > pertag - > curtag ] )
togglebar ( NULL ) ;
2024-05-10 20:01:34 +00:00
focus ( NULL ) ;
arrange ( selmon ) ;
}
2024-05-11 04:43:32 +00:00
pid_t
winpid ( Window w )
{
pid_t result = 0 ;
# ifdef __linux__
xcb_res_client_id_spec_t spec = { 0 } ;
spec . client = w ;
spec . mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID ;
xcb_generic_error_t * e = NULL ;
xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids ( xcon , 1 , & spec ) ;
xcb_res_query_client_ids_reply_t * r = xcb_res_query_client_ids_reply ( xcon , c , & e ) ;
if ( ! r )
return ( pid_t ) 0 ;
xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator ( r ) ;
for ( ; i . rem ; xcb_res_client_id_value_next ( & i ) ) {
spec = i . data - > spec ;
if ( spec . mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID ) {
uint32_t * t = xcb_res_client_id_value_value ( i . data ) ;
result = * t ;
break ;
}
}
free ( r ) ;
if ( result = = ( pid_t ) - 1 )
result = 0 ;
# endif /* __linux__ */
# ifdef __OpenBSD__
Atom type ;
int format ;
unsigned long len , bytes ;
unsigned char * prop ;
pid_t ret ;
if ( XGetWindowProperty ( dpy , w , XInternAtom ( dpy , " _NET_WM_PID " , 0 ) , 0 , 1 , False , AnyPropertyType , & type , & format , & len , & bytes , & prop ) ! = Success | | ! prop )
return 0 ;
ret = * ( pid_t * ) prop ;
XFree ( prop ) ;
result = ret ;
# endif /* __OpenBSD__ */
return result ;
}
pid_t
getparentprocess ( pid_t p )
{
unsigned int v = 0 ;
# ifdef __linux__
FILE * f ;
char buf [ 256 ] ;
snprintf ( buf , sizeof ( buf ) - 1 , " /proc/%u/stat " , ( unsigned ) p ) ;
if ( ! ( f = fopen ( buf , " r " ) ) )
return 0 ;
fscanf ( f , " %*u %*s %*c %u " , & v ) ;
fclose ( f ) ;
# endif /* __linux__*/
# ifdef __OpenBSD__
int n ;
kvm_t * kd ;
struct kinfo_proc * kp ;
kd = kvm_openfiles ( NULL , NULL , NULL , KVM_NO_FILES , NULL ) ;
if ( ! kd )
return 0 ;
kp = kvm_getprocs ( kd , KERN_PROC_PID , p , sizeof ( * kp ) , & n ) ;
v = kp - > p_ppid ;
# endif /* __OpenBSD__ */
return ( pid_t ) v ;
}
int
isdescprocess ( pid_t p , pid_t c )
{
while ( p ! = c & & c ! = 0 )
c = getparentprocess ( c ) ;
return ( int ) c ;
}
Client *
termforwin ( const Client * w )
{
Client * c ;
Monitor * m ;
if ( ! w - > pid | | w - > isterminal )
return NULL ;
for ( m = mons ; m ; m = m - > next ) {
for ( c = m - > clients ; c ; c = c - > next ) {
if ( c - > isterminal & & ! c - > swallowing & & c - > pid & & isdescprocess ( c - > pid , w - > pid ) )
return c ;
}
}
return NULL ;
}
Client *
swallowingclient ( Window w )
{
Client * c ;
Monitor * m ;
for ( m = mons ; m ; m = m - > next ) {
for ( c = m - > clients ; c ; c = c - > next ) {
if ( c - > swallowing & & c - > swallowing - > win = = w )
return c ;
}
}
return NULL ;
}
2024-05-10 20:01:34 +00:00
Client *
wintoclient ( Window w )
{
Client * c ;
Monitor * m ;
for ( m = mons ; m ; m = m - > next )
for ( c = m - > clients ; c ; c = c - > next )
if ( c - > win = = w )
return c ;
return NULL ;
}
Monitor *
wintomon ( Window w )
{
int x , y ;
Client * c ;
Monitor * m ;
if ( w = = root & & getrootptr ( & x , & y ) )
return recttomon ( x , y , 1 , 1 ) ;
for ( m = mons ; m ; m = m - > next )
2024-05-10 21:47:45 +00:00
if ( w = = m - > barwin | | w = = m - > extrabarwin )
2024-05-10 20:01:34 +00:00
return m ;
if ( ( c = wintoclient ( w ) ) )
return c - > mon ;
return selmon ;
}
/* There's no way to check accesses to destroyed windows, thus those cases are
* ignored ( especially on UnmapNotify ' s ) . Other types of errors call Xlibs
* default error handler , which may call exit . */
int
xerror ( Display * dpy , XErrorEvent * ee )
{
if ( ee - > error_code = = BadWindow
| | ( ee - > request_code = = X_SetInputFocus & & ee - > error_code = = BadMatch )
| | ( ee - > request_code = = X_PolyText8 & & ee - > error_code = = BadDrawable )
| | ( ee - > request_code = = X_PolyFillRectangle & & ee - > error_code = = BadDrawable )
| | ( ee - > request_code = = X_PolySegment & & ee - > error_code = = BadDrawable )
| | ( ee - > request_code = = X_ConfigureWindow & & ee - > error_code = = BadMatch )
| | ( ee - > request_code = = X_GrabButton & & ee - > error_code = = BadAccess )
| | ( ee - > request_code = = X_GrabKey & & ee - > error_code = = BadAccess )
| | ( ee - > request_code = = X_CopyArea & & ee - > error_code = = BadDrawable ) )
return 0 ;
fprintf ( stderr , " dwm: fatal error: request code=%d, error code=%d \n " ,
ee - > request_code , ee - > error_code ) ;
return xerrorxlib ( dpy , ee ) ; /* may call exit */
}
int
xerrordummy ( Display * dpy , XErrorEvent * ee )
{
return 0 ;
}
/* Startup Error handler to check if another window manager
* is already running . */
int
xerrorstart ( Display * dpy , XErrorEvent * ee )
{
die ( " dwm: another window manager is already running " ) ;
return - 1 ;
}
2024-05-10 22:23:16 +00:00
void
xinitvisual ( )
{
XVisualInfo * infos ;
XRenderPictFormat * fmt ;
int nitems ;
int i ;
XVisualInfo tpl = {
. screen = screen ,
. depth = 32 ,
. class = TrueColor
} ;
long masks = VisualScreenMask | VisualDepthMask | VisualClassMask ;
infos = XGetVisualInfo ( dpy , masks , & tpl , & nitems ) ;
visual = NULL ;
for ( i = 0 ; i < nitems ; i + + ) {
fmt = XRenderFindVisualFormat ( dpy , infos [ i ] . visual ) ;
if ( fmt - > type = = PictTypeDirect & & fmt - > direct . alphaMask ) {
visual = infos [ i ] . visual ;
depth = infos [ i ] . depth ;
cmap = XCreateColormap ( dpy , root , visual , AllocNone ) ;
useargb = 1 ;
break ;
}
}
XFree ( infos ) ;
if ( ! visual ) {
visual = DefaultVisual ( dpy , screen ) ;
depth = DefaultDepth ( dpy , screen ) ;
cmap = DefaultColormap ( dpy , screen ) ;
}
}
2024-05-10 20:01:34 +00:00
void
zoom ( const Arg * arg )
{
Client * c = selmon - > sel ;
2024-05-11 12:22:34 +00:00
Client * at = NULL , * cold , * cprevious = NULL ;
2024-05-10 20:01:34 +00:00
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | ! c | | c - > isfloating )
return ;
2024-05-11 12:22:34 +00:00
if ( c = = nexttiled ( selmon - > clients ) ) {
at = findbefore ( prevzoom ) ;
if ( at )
cprevious = nexttiled ( at - > next ) ;
if ( ! cprevious | | cprevious ! = prevzoom ) {
prevzoom = NULL ;
if ( ! c | | ! ( c = nexttiled ( c - > next ) ) )
return ;
} else
c = cprevious ;
}
cold = nexttiled ( selmon - > clients ) ;
if ( c ! = cold & & ! at )
at = findbefore ( c ) ;
detach ( c ) ;
attach ( c ) ;
/* swap windows instead of pushing the previous one down */
if ( c ! = cold & & at ) {
prevzoom = cold ;
if ( cold & & at ! = cold ) {
detach ( cold ) ;
cold - > next = at - > next ;
at - > next = cold ;
}
}
focus ( c ) ;
arrange ( c - > mon ) ;
2024-05-10 20:01:34 +00:00
}
2024-05-20 22:10:54 +00:00
void
swaptags ( const Arg * arg )
{
unsigned int newtag = arg - > ui & TAGMASK ;
unsigned int curtag = selmon - > tagset [ selmon - > seltags ] ;
if ( newtag = = curtag | | ! curtag | | ( curtag & ( curtag - 1 ) ) )
return ;
for ( Client * c = selmon - > clients ; c ! = NULL ; c = c - > next ) {
if ( ( c - > tags & newtag ) | | ( c - > tags & curtag ) )
c - > tags ^ = curtag ^ newtag ;
if ( ! c - > tags ) c - > tags = newtag ;
}
selmon - > tagset [ selmon - > seltags ] = newtag ;
focus ( NULL ) ;
arrange ( selmon ) ;
}
2024-05-10 20:01:34 +00:00
int
main ( int argc , char * argv [ ] )
{
if ( argc = = 2 & & ! strcmp ( " -v " , argv [ 1 ] ) )
die ( " dwm- " VERSION ) ;
else if ( argc ! = 1 )
die ( " usage: dwm [-v] " ) ;
if ( ! setlocale ( LC_CTYPE , " " ) | | ! XSupportsLocale ( ) )
fputs ( " warning: no locale support \n " , stderr ) ;
if ( ! ( dpy = XOpenDisplay ( NULL ) ) )
die ( " dwm: cannot open display " ) ;
2024-05-11 04:43:32 +00:00
if ( ! ( xcon = XGetXCBConnection ( dpy ) ) )
die ( " dwm: cannot get xcb connection \n " ) ;
2024-05-10 20:01:34 +00:00
checkotherwm ( ) ;
2024-05-20 22:06:37 +00:00
autostart_exec ( ) ;
2024-05-10 20:01:34 +00:00
setup ( ) ;
# ifdef __OpenBSD__
2024-05-11 04:43:32 +00:00
if ( pledge ( " stdio rpath proc exec ps " , NULL ) = = - 1 )
2024-05-10 20:01:34 +00:00
die ( " pledge " ) ;
# endif /* __OpenBSD__ */
scan ( ) ;
run ( ) ;
2024-05-11 01:05:59 +00:00
if ( restart ) execvp ( argv [ 0 ] , argv ) ;
2024-05-10 20:01:34 +00:00
cleanup ( ) ;
XCloseDisplay ( dpy ) ;
return EXIT_SUCCESS ;
}