2022-10-03 21:57:15 +02:00
/* See LICENSE file for copyright and license details. */
2022-08-21 11:53:18 +02:00
# include <assert.h>
# 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 <limits.h>
2022-10-11 18:08:16 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
# include <stdint.h>
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
# include <sys/types.h>
# include <sys/wait.h>
2022-08-26 11:41:11 +02:00
# include "toggle.h"
# if USEIPC
# include <sys/epoll.h>
# endif
2022-08-21 11:53:18 +02:00
# include <X11/cursorfont.h>
# include <X11/keysym.h>
# include <X11/Xatom.h>
# include <X11/Xlib.h>
# include <X11/Xproto.h>
# include <X11/Xutil.h>
2022-10-05 19:57:18 +02:00
# if USEXRESOURCES
2022-08-21 11:53:18 +02:00
# include <X11/Xresource.h>
2022-10-05 19:57:18 +02:00
# endif
# if USEROUNDCORNERS
2022-08-21 11:53:18 +02:00
# include <X11/extensions/shape.h>
2022-10-05 19:57:18 +02:00
# endif
2022-08-21 11:53:18 +02:00
# ifdef XINERAMA
# include <X11/extensions/Xinerama.h>
# endif /* XINERAMA */
# include <X11/Xft/Xft.h>
2022-09-03 17:44:49 +02:00
# if USEIMLIB2
2022-08-21 11:53:18 +02:00
# include <Imlib2.h>
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
# include <X11/Xlib-xcb.h>
# include <xcb/res.h>
# ifdef __OpenBSD__
# include <sys/sysctl.h>
# include <kvm.h>
# endif /* __OpenBSD */
# 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)->mw) - MAX((x),(m)->mx)) \
* MAX ( 0 , MIN ( ( y ) + ( h ) , ( m ) - > wy + ( m ) - > mh ) - MAX ( ( y ) , ( m ) - > my ) ) )
# define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \
* MAX ( 0 , MIN ( ( y ) + ( h ) , ( z ) - > y + ( z ) - > h ) - MAX ( ( y ) , ( z ) - > y ) ) )
# define HIDDEN(C) ((getstate(C->win) == IconicState))
# define ISVISIBLEONTAG(C, T) ((C->tags & T))
# define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
# 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 TAGSLENGTH (LENGTH(tags))
# define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
# define RIGHTOF(a,b) (a.y_org > b.y_org) || \
( ( a . y_org = = b . y_org ) & & ( a . x_org > b . x_org ) )
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
# define SYSTEM_TRAY_REQUEST_DOCK 0
/* XEMBED messages */
# define XEMBED_EMBEDDED_NOTIFY 0
# define XEMBED_WINDOW_ACTIVATE 1
# define XEMBED_FOCUS_IN 4
# define XEMBED_MODALITY_ON 10
# define XEMBED_MAPPED (1 << 0)
# define XEMBED_WINDOW_ACTIVATE 1
# define XEMBED_WINDOW_DEACTIVATE 2
# define VERSION_MAJOR 0
# define VERSION_MINOR 0
# define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
# endif
2022-08-21 11:53:18 +02:00
# define OPAQUE 0xffU
# define TRANSPARENT 0
# define MWM_HINTS_FLAGS_FIELD 0
# define MWM_HINTS_DECORATIONS_FIELD 2
# define MWM_HINTS_DECORATIONS (1 << 1)
# define MWM_DECOR_ALL (1 << 0)
# define MWM_DECOR_BORDER (1 << 1)
# define MWM_DECOR_TITLE (1 << 3)
/* enums */
2022-10-11 14:01:22 +02:00
enum { CurNormal , CurResize , CurMove , CurResizeHorzArrow , CurResizeVertArrow , CurLast } ; /* cursor */
2022-08-21 11:53:18 +02:00
/* color schemes */
enum { SchemeNormBorder ,
SchemeSelBorder ,
SchemeTags ,
SchemeBar ,
2022-10-01 17:29:31 +02:00
SchemeHiddenTitle ,
2022-08-21 11:53:18 +02:00
SchemeLayout ,
SchemeNormTitle ,
SchemeSelTitle ,
SchemeStatus ,
2022-10-06 08:22:06 +02:00
SchemeSystray ,
2022-08-21 11:53:18 +02:00
} ;
2022-09-03 17:05:20 +02:00
enum { NetSupported , NetWMName ,
# if USEWINICON
NetWMIcon ,
# endif
NetWMState , NetWMCheck ,
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
NetSystemTray , NetSystemTrayOP , NetSystemTrayOrientation , NetSystemTrayOrientationHorz ,
# endif
2022-08-21 11:53:18 +02:00
NetWMFullscreen , NetActiveWindow , NetWMWindowType , NetWMWindowTypeDesktop ,
2022-09-03 18:07:51 +02:00
NetWMWindowTypeDialog , NetClientList , NetDesktopNames , NetDesktopViewport , NetNumberOfDesktops , NetCurrentDesktop ,
# if USEFADE
NetWMWindowsOpacity ,
# endif
NetClientListStacking , NetClientInfo , NetLast } ; /* EWMH atoms */
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
enum { Manager , Xembed , XembedInfo , XLast } ; /* Xembed atoms */
# endif
2022-08-21 11:53:18 +02:00
enum { WMClass , WMProtocols , WMDelete , WMState , WMTakeFocus , WMLast } ; /* default atoms */
2022-08-21 16:05:53 +02:00
enum { DWMTags , DWMLast } ;
2022-08-21 11:53:18 +02:00
enum { ClkTagBar , ClkLtSymbol , ClkStatusText , ClkWinTitle ,
ClkClientWin , ClkRootWin , ClkLast } ; /* clicks */
2022-08-26 11:41:11 +02:00
# if USEIPC
typedef struct TagState TagState ;
struct TagState {
int selected ;
int occupied ;
int urgent ;
} ;
typedef struct ClientState ClientState ;
struct ClientState {
int isfixed , isfloating , isurgent , neverfocus , oldstate , isfullscreen ;
} ;
# endif
2022-08-21 11:53:18 +02:00
typedef union {
2022-10-11 18:19:35 +02:00
# if USEIPC
long i ;
unsigned long ui ;
# else
2022-08-26 11:41:11 +02:00
long i ;
unsigned long ui ;
2022-10-11 18:19:35 +02:00
# endif
2022-08-21 11:53:18 +02:00
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 ;
float cfact ;
int x , y , w , h ;
int sfx , sfy , sfw , sfh ; /* stored float geometry, used on mode revert */
int oldx , oldy , oldw , oldh ;
int basew , baseh , incw , inch , maxw , maxh , minw , minh ;
2022-09-10 23:49:22 +02:00
int hintsvalid ; /* https://git.suckless.org/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.html */
2022-08-21 11:53:18 +02:00
int bw , oldbw ;
unsigned int tags ;
int isfixed , ispermanent , isfloating , isurgent , neverfocus , oldstate , isfullscreen , ignoretransient , issticky , isterminal , noswallow , needresize ;
pid_t pid ;
char scratchkey ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
unsigned int icw , ich ; Picture icon ;
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
int issteam ;
int beingmoved ;
Client * next ;
Client * snext ;
Client * swallowing ;
Monitor * mon ;
Window win ;
2022-08-26 11:41:11 +02:00
# if USEIPC
ClientState prevstate ;
# endif
2022-08-21 11:53:18 +02:00
} ;
typedef struct {
unsigned int mod ;
KeySym chain ;
KeySym keysym ;
void ( * func ) ( const Arg * ) ;
const Arg arg ;
} Key ;
typedef struct {
unsigned int signum ;
void ( * func ) ( const Arg * ) ;
const Arg arg ;
} Signal ;
typedef struct {
const char * symbol ;
void ( * arrange ) ( Monitor * ) ;
} Layout ;
typedef struct Pertag Pertag ;
struct Monitor {
char ltsymbol [ 16 ] ;
2022-08-26 11:41:11 +02:00
# if USEIPC
char lastltsymbol [ 16 ] ;
# endif
2022-08-21 11:53:18 +02:00
float mfact ;
2022-08-28 21:54:47 +02:00
float cfact ;
2022-08-21 11:53:18 +02:00
int nmaster ;
int num ;
int by , bh ; /* bar geometry */
int tx , tw ; /* bar tray geometry */
int btw ;
int bt ;
int mx , my , mw , mh ; /* screen size */
int wx , wy , ww , wh ; /* window area */
int gappih ; /* horizontal gap between windows */
int gappiv ; /* vertical gap between windows */
int gappoh ; /* horizontal outer gaps */
int gappov ; /* vertical outer gaps */
unsigned int seltags ;
unsigned int sellt ;
unsigned int tagset [ 2 ] ;
2022-08-26 11:41:11 +02:00
# if USEIPC
TagState tagstate ;
# endif
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
int previewshow ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
int showbar ;
int barposition ;
int hidsel ;
2022-09-14 17:46:09 +02:00
int isreset ;
2022-10-06 11:39:35 +02:00
int allowwarp ;
2022-08-21 11:53:18 +02:00
Client * clients ;
Client * sel ;
2022-08-26 11:41:11 +02:00
# if USEIPC
Client * lastsel ;
# endif
2022-08-21 11:53:18 +02:00
Client * stack ;
2022-09-11 14:16:14 +02:00
Client * tagmarked [ 32 ] ;
2022-08-21 11:53:18 +02:00
Monitor * next ;
Window barwin ;
Window traywin ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
Window tagwin ;
Pixmap * tagmap ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
const Layout * lt [ 2 ] ;
2022-08-26 11:41:11 +02:00
# if USEIPC
const Layout * lastlt ;
# endif
2022-08-21 11:53:18 +02:00
Pertag * pertag ;
} ;
/* Order of the rules */
typedef struct {
const char * class ;
const char * instance ;
const char * title ;
unsigned int tags ;
int isfloating ;
int ispermanent ;
int isterminal ;
int noswallow ;
int monitor ;
int unmanaged ;
int ignoretransient ;
const char scratchkey ;
} Rule ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
typedef struct Systray Systray ;
struct Systray {
Window win ;
Client * icons ;
} ;
# endif
2022-08-21 11:53:18 +02:00
typedef struct {
const char * cmd ;
int id ;
} StatusCmd ;
/* Xresources preferences */
enum resource_type {
STRING = 0 ,
INTEGER = 1 ,
FLOAT = 2
} ;
typedef struct {
char * name ;
enum resource_type type ;
void * dst ;
} ResourcePref ;
/* function declarations */
static void applyrules ( Client * c ) ;
2022-09-03 19:08:07 +02:00
# if LAYOUT_CM
2022-08-21 11:53:18 +02:00
static void centeredmaster ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
# if LAYOUT_CFM
2022-08-21 11:53:18 +02:00
static void centeredfloatingmaster ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
# if LAYOUT_TW
2022-08-21 11:53:18 +02:00
static void tilewide ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void getgaps ( Monitor * m , int * oh , int * ov , int * ih , int * iv , unsigned int * nc ) ;
static void getfacts ( Monitor * m , int msize , int ssize , float * mf , float * sf , int * mr , int * sr ) ;
2022-09-03 19:08:07 +02:00
# if LAYOUT_STAIRS
2022-08-21 11:53:18 +02:00
static void stairs ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
static int applysizehints ( Client * c , int * x , int * y , int * w , int * h , int interact ) ;
static void inplacerotate ( const Arg * arg ) ;
2022-08-21 16:05:53 +02:00
static void settagsatom ( Window w , unsigned int tags ) ;
2022-08-21 11:53:18 +02:00
static void togglesticky ( const Arg * arg ) ;
static void previewtag ( const Arg * arg ) ;
static void setcurrentdesktop ( void ) ;
static void setdesktopnames ( void ) ;
static void setnumdesktops ( void ) ;
static void setviewport ( void ) ;
static void arrange ( Monitor * m ) ;
static void arrangemon ( Monitor * m ) ;
2022-09-11 14:06:29 +02:00
static void moveresizeaspect ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void attach ( Client * c ) ;
static void attachabove ( Client * c ) ;
static void attachaside ( Client * c ) ;
static void attachbelow ( Client * c ) ;
static void attachbottom ( Client * c ) ;
static void attachtop ( Client * c ) ;
static void attachstack ( Client * c ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void buttonpress ( XEvent * e ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
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 void copyvalidchars ( char * text , char * rawtext ) ;
static void autostart_exec ( void ) ;
static void moveresize ( const Arg * arg ) ;
static void moveresizeedge ( const Arg * arg ) ;
static Monitor * createmon ( void ) ;
2022-09-03 19:08:07 +02:00
# if LAYOUT_DECK
2022-08-21 11:53:18 +02:00
static void deck ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void cyclelayout ( const Arg * arg ) ;
static void destroynotify ( XEvent * e ) ;
static void detach ( Client * c ) ;
static void detachstack ( Client * c ) ;
static Monitor * dirtomon ( int dir ) ;
2022-10-11 14:01:22 +02:00
# if USEMOUSE
static void dragmfact ( const Arg * arg ) ;
# endif
2022-08-21 11:53:18 +02:00
static void drawbar ( Monitor * m ) ;
static void drawbars ( void ) ;
2022-09-17 00:11:05 +02:00
# if USEROUNDCORNERS
2022-08-21 11:53:18 +02:00
static void drawroundedcorners ( Client * c ) ;
2022-09-17 00:11:05 +02:00
# endif
2022-08-21 11:53:18 +02:00
static int drawstatusbar ( Monitor * m , int bh , char * text ) ;
2022-10-08 00:41:15 +02:00
static int statuslength ( char * stext ) ;
static int textlength ( char * stext ) ;
2022-08-21 11:53:18 +02:00
static void enternotify ( XEvent * e ) ;
static void expose ( XEvent * e ) ;
static void focus ( Client * c ) ;
static void focusin ( XEvent * e ) ;
2022-09-11 14:16:14 +02:00
static void focusmaster ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void focusmon ( const Arg * arg ) ;
2022-08-23 21:48:34 +02:00
static void focusstack ( int inc , int vis ) ;
2022-08-21 11:53:18 +02:00
static void focusstackvis ( const Arg * arg ) ;
static void focusstackhid ( const Arg * arg ) ;
static Atom getatomprop ( Client * c , Atom prop ) ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
static Picture geticonprop ( Window w , unsigned int * icw , unsigned int * ich ) ;
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
static int getrootptr ( int * x , int * y ) ;
static long getstate ( Window w ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
static unsigned int getsystraywidth ( ) ;
static void removesystrayicon ( Client * i ) ;
static void resizebarwin ( Monitor * m ) ;
static void resizerequest ( XEvent * e ) ;
static Monitor * systraytomon ( Monitor * m ) ;
static void updatesystray ( void ) ;
static void updatesystrayicongeom ( Client * i , int w , int h ) ;
static void updatesystrayiconstate ( Client * i , XPropertyEvent * ev ) ;
static Client * wintosystrayicon ( Window w ) ;
static int sendevent ( Window w , Atom proto , int m , long d0 , long d1 , long d2 , long d3 , long d4 ) ;
static void togglesystray ( ) ;
# else
static int sendevent ( Client * c , Atom proto ) ;
# endif
2022-08-21 11:53:18 +02:00
static int gettextprop ( Window w , Atom atom , char * text , unsigned int size ) ;
static void grabbuttons ( Client * c , int focused ) ;
2022-08-23 21:48:34 +02:00
static void hide ( const Arg * arg ) ;
static void hidewin ( Client * c ) ;
2022-08-21 11:53:18 +02:00
static void incnmaster ( const Arg * arg ) ;
2022-08-26 11:41:11 +02:00
# if USEIPC
static int handlexevent ( struct epoll_event * ev ) ;
# endif
2022-08-21 11:53:18 +02:00
static void keypress ( XEvent * e ) ;
2022-10-14 16:14:45 +02:00
static int getsignal ( void ) ;
2022-08-21 11:53:18 +02:00
static void killclient ( const Arg * arg ) ;
2022-08-26 19:12:10 +02:00
static void killunsel ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void layoutmenu ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void manage ( Window w , XWindowAttributes * wa ) ;
static void managealtbar ( Window win , XWindowAttributes * wa ) ;
static void managetray ( Window win , XWindowAttributes * wa ) ;
static void mappingnotify ( XEvent * e ) ;
static void maprequest ( XEvent * e ) ;
2022-09-03 19:08:07 +02:00
# if LAYOUT_MONOCLE
2022-08-21 11:53:18 +02:00
static void monocle ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void motionnotify ( XEvent * e ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void movemouse ( const Arg * arg ) ;
static void moveorplace ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static Client * nexttagged ( Client * c ) ;
static Client * nexttiled ( Client * c ) ;
2022-10-11 17:11:31 +02:00
static unsigned int nexttag ( void ) ;
2022-10-14 15:56:42 +02:00
static unsigned int nexttag_skip_vacant ( void ) ;
2022-10-11 17:11:31 +02:00
static unsigned int prevtag ( void ) ;
2022-10-14 15:56:42 +02:00
static unsigned int prevtag_skip_vacant ( void ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void placemouse ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-09-03 18:07:51 +02:00
# if USEFADE
2022-08-21 11:53:18 +02:00
static void opacity ( Client * c , double opacity ) ;
2022-09-03 18:07:51 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void pop ( Client * ) ;
static void propertynotify ( XEvent * e ) ;
static void quit ( const Arg * arg ) ;
static Client * recttoclient ( int x , int y , int w , int h ) ;
static Monitor * recttomon ( int x , int y , int w , int h ) ;
2022-09-21 15:50:53 +02:00
static void resetnmaster ( const Arg * arg ) ;
2022-10-11 17:11:31 +02:00
static void reset_mfact ( const Arg * arg ) ;
2022-09-14 18:01:06 +02:00
static void reset_layout ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void reorganizetags ( const Arg * arg ) ;
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 ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void resizemouse ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void restack ( Monitor * m ) ;
static void run ( void ) ;
static void scantray ( void ) ;
static void scan ( void ) ;
2022-10-06 09:58:29 +02:00
/* scratchpad functions */
static void scratchpad_hide ( ) ;
static _Bool scratchpad_last_showed_is_killed ( void ) ;
static void scratchpad_remove ( ) ;
static void scratchpad_show ( ) ;
static void scratchpad_show_client ( Client * c ) ;
static void scratchpad_show_first ( void ) ;
/* */
2022-08-21 11:53:18 +02:00
static void sendmon ( Client * c , Monitor * m ) ;
static void setclientstate ( Client * c , long state ) ;
static void setclienttagprop ( Client * c ) ;
static void setfocus ( Client * c ) ;
static void setfullscreen ( Client * c , int fullscreen ) ;
static void setgaps ( int oh , int ov , int ih , int iv ) ;
static void incrgaps ( const Arg * arg ) ;
static void incrigaps ( const Arg * arg ) ;
static void incrogaps ( const Arg * arg ) ;
static void togglegaps ( const Arg * arg ) ;
static void defaultgaps ( const Arg * arg ) ;
static void setlayout ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-28 01:47:41 +02:00
static void dragcfact ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-26 11:41:11 +02:00
# if USEIPC
static void setlayoutsafe ( const Arg * arg ) ;
# endif
2022-08-21 11:53:18 +02:00
static void setcfact ( const Arg * arg ) ;
static void setmfact ( const Arg * arg ) ;
static void setup ( void ) ;
2022-08-26 11:41:11 +02:00
# if USEIPC
static void setupepoll ( void ) ;
# endif
2022-08-21 11:53:18 +02:00
static void seturgent ( Client * c , int urg ) ;
2022-08-23 21:48:34 +02:00
static void show ( const Arg * arg ) ;
2022-10-05 19:05:16 +02:00
static void showall ( const Arg * arg ) ;
static void hideall ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void showwin ( Client * c ) ;
static void showhide ( Client * c ) ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
static void showtagpreview ( unsigned int i ) ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void sigchld ( int unused ) ;
# ifdef XINERAMA
static void sortscreens ( XineramaScreenInfo * screens , int n ) ;
# endif
static void sighup ( int unused ) ;
static void sigterm ( int unused ) ;
static void spawn ( const Arg * arg ) ;
static void spawnbar ( ) ;
static void unmanagealtbar ( Window w ) ;
static void unmanagetray ( Window w ) ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-09-09 10:07:24 +02:00
static void takepreview ( void ) ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void tagmon ( const Arg * arg ) ;
2022-09-03 19:08:07 +02:00
# if LAYOUT_TILE
2022-09-11 00:29:45 +02:00
static void tile ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-10-14 14:39:55 +02:00
# if LAYOUT_DECK
static void deck ( Monitor * m ) ;
# endif
2022-10-11 17:11:31 +02:00
# if LAYOUT_EMPTY
static void empty ( Monitor * m ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void togglebar ( const Arg * arg ) ;
static void togglefloating ( const Arg * arg ) ;
static void toggleopacity ( const Arg * arg ) ;
static void togglefullscr ( const Arg * arg ) ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
static void freeicon ( Client * c ) ;
2022-09-03 17:05:20 +02:00
# endif
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void togglewin ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void unfocus ( Client * c , int setfocus ) ;
static void unmanage ( Client * c , int destroyed ) ;
static void unmapnotify ( XEvent * e ) ;
static void updatecurrentdesktop ( void ) ;
static void updatebarpos ( Monitor * m ) ;
static void updatebars ( void ) ;
static void updateclientlist ( void ) ;
static int updategeom ( void ) ;
static void updatemotifhints ( Client * c ) ;
static void updatenumlockmask ( void ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static void resizemouse ( const Arg * arg ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void updatesizehints ( Client * c ) ;
static void updatestatus ( void ) ;
static void updaterules ( Client * c ) ;
static void updatetitle ( Client * c ) ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
static void updatepreview ( void ) ;
# endif
2022-08-21 11:53:18 +02:00
static void updateicon ( Client * c ) ;
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
static void updatewindowtype ( Client * c ) ;
static void updatewmhints ( Client * c ) ;
2022-09-17 18:20:59 +02:00
static void toggleview ( const Arg * arg ) ;
static void tag ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void view ( const Arg * arg ) ;
static void viewtoleft ( const Arg * arg ) ;
static void viewtoright ( const Arg * arg ) ;
2022-10-14 15:56:42 +02:00
static void viewtoleft_vacant ( const Arg * arg ) ;
static void viewtoright_vacant ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void warp ( const Client * c ) ;
static Client * wintoclient ( Window w ) ;
static Monitor * wintomon ( Window w ) ;
static int wmclasscontains ( Window win , const char * class , const char * name ) ;
static int xerror ( Display * dpy , XErrorEvent * ee ) ;
static int xerrordummy ( Display * dpy , XErrorEvent * ee ) ;
static int xerrorstart ( Display * dpy , XErrorEvent * ee ) ;
static void xinitvisual ( ) ;
static void zoom ( const Arg * arg ) ;
2022-10-05 13:42:45 +02:00
# if USEXRESOURCES
2022-08-21 11:53:18 +02:00
static void load_xresources ( void ) ;
2022-10-03 16:49:24 +02:00
static void reloadcolors ( const Arg * arg ) ;
2022-08-21 11:53:18 +02:00
static void resource_load ( XrmDatabase db , char * name , enum resource_type rtype , void * dst ) ;
2022-10-05 13:42:45 +02:00
# endif
2022-08-21 11:53:18 +02: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 ) ;
/* variables */
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
static Systray * systray = NULL ;
# endif
2022-10-06 09:52:35 +02:00
static const char notitle [ ] = " " ; /* Title when none can be grabbed. */
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-10-06 09:52:35 +02:00
static const char * layoutcmd = " speedwm-utils layout " ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static char stext [ 1024 ] ;
static char rawstext [ 1024 ] ;
static int statusw ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static int statuscmdn ;
static char lastbutton [ ] = " - " ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
static int screen ;
static int tw , sh ; /* X display screen geometry width, height */
2022-09-10 23:45:37 +02:00
static int bh ; /* bar geometry */
// NOTE: Implemented https://git.suckless.org/dwm/commit/5799dd1fca6576b662d299e210cd5933b29d502d.html
2022-08-21 11:53:18 +02:00
static int unmanaged = 0 ; /* whether the window manager should manage the new window or not */
static int lrpad ; /* sum of left and right padding for text */
static int vp ; /* vertical padding for bar */
static int sp ; /* side padding for bar */
static int ( * xerrorxlib ) ( Display * , XErrorEvent * ) ;
static unsigned int numlockmask = 0 ;
static void ( * handler [ LASTEvent ] ) ( XEvent * ) = {
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
[ ButtonPress ] = buttonpress ,
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
[ ClientMessage ] = clientmessage ,
[ ConfigureRequest ] = configurerequest ,
[ ConfigureNotify ] = configurenotify ,
[ DestroyNotify ] = destroynotify ,
[ EnterNotify ] = enternotify ,
[ Expose ] = expose ,
[ FocusIn ] = focusin ,
[ KeyPress ] = keypress ,
[ MappingNotify ] = mappingnotify ,
[ MapRequest ] = maprequest ,
[ MotionNotify ] = motionnotify ,
[ PropertyNotify ] = propertynotify ,
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
[ ResizeRequest ] = resizerequest ,
# endif
2022-08-21 11:53:18 +02:00
[ UnmapNotify ] = unmapnotify
} ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
static Atom wmatom [ WMLast ] , netatom [ NetLast ] , xatom [ XLast ] , dwmatom [ DWMLast ] , motifatom ;
# else
2022-08-21 16:05:53 +02:00
static Atom wmatom [ WMLast ] , netatom [ NetLast ] , dwmatom [ DWMLast ] , motifatom ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-26 11:41:11 +02:00
# if USEIPC
static int epoll_fd ;
static int dpy_fd ;
# endif
2022-08-21 11:53:18 +02:00
static int running = 1 ;
static int restart = 0 ;
static Cur * cursor [ CurLast ] ;
static Clr * * scheme ;
static Clr * * tagscheme ;
static Display * dpy ;
static Drw * drw ;
static Monitor * mons , * selmon ;
2022-08-26 11:41:11 +02:00
# if USEIPC
static Monitor * lastselmon ; /* IPC */
# endif
2022-08-25 18:53:04 +02:00
2022-08-21 11:53:18 +02:00
static Window root , wmcheckwin ;
2022-08-25 18:53:04 +02:00
2022-08-21 11:53:18 +02:00
static KeySym keychain = - 1 ;
/* scratchpad */
# define SCRATCHPAD_MASK (1u << sizeof tags / sizeof * tags)
static Client * scratchpad_last_showed = NULL ;
static int useargb = 0 ;
static Visual * visual ;
static int depth ;
static Colormap cmap ;
static xcb_connection_t * xcon ;
# define FORCE_VSPLIT forcevsplit
2022-08-26 11:41:11 +02:00
# if USEIPC
# include "toggle/ipc.c"
# endif
2022-09-11 01:44:40 +02:00
/* Media controls */
# if USEMEDIA
2022-08-21 11:53:18 +02:00
# include <X11/XF86keysym.h> /* Enable multimedia button support */
2022-09-11 01:44:40 +02:00
# endif
/* Configuration */
2022-10-11 17:11:31 +02:00
# include "actions.h" /* include #defines */
2022-08-21 11:53:18 +02:00
# include "options.h" /* Include options */
2022-09-11 14:20:26 +02:00
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
static int systraypinningfailfirst = 1 ;
# endif
2022-09-11 14:20:26 +02:00
/* Shell command */
# define RCMD(cmd) {.v = (const char*[]){ shell, "-c", cmd, NULL } },
2022-10-09 14:05:11 +02:00
# define cmd( cmd ) {.v = (const char*[]){ shell, "-c", cmd, NULL } },
2022-09-17 18:20:59 +02:00
# define SESSION_FILE " / tmp / speedwm-session"
2022-09-11 14:20:26 +02:00
2022-09-14 17:30:08 +02:00
/* Modifiers */
# define CONTROL ControlMask
# define SHIFT ShiftMask
2022-09-17 00:45:58 +02:00
# define ALT Mod1Mask
# define ALTR Mod3Mask
# define SUPER Mod4Mask
2022-10-06 14:09:30 +02:00
# define SUPERR Mod5Mask
2022-09-14 17:30:08 +02:00
2022-09-11 14:20:26 +02:00
/* Rest of the headers */
2022-08-21 11:53:18 +02:00
# include "layouts.c" /* Enable patched layouts */
# include "autostart.h" /* Add autostart support */
# include "colors.h" /* Include colors */
# include "rules.h" /* Include rules */
# include "layouts.h" /* Include layout list */
2022-10-05 13:42:45 +02:00
# if USEXRESOURCES
2022-08-21 11:53:18 +02:00
# include "xresources.h" /* Include .Xresources/Pywal support */
2022-10-05 13:42:45 +02:00
# endif
2022-08-21 11:53:18 +02:00
# include "keybinds.h" /* Include keybinds */
2022-09-11 14:20:26 +02:00
/* IPC support */
2022-08-26 11:41:11 +02:00
# if USEIPC
2022-09-10 13:44:11 +02:00
# include "ipc.h" /* Include IPC */
2022-08-26 11:41:11 +02:00
# include "toggle/ipc-cli.c"
# include "toggle/ipc-yajl.c"
# endif
2022-09-11 14:20:26 +02:00
/* Mouse support */
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
static const char * statuscmd [ ] = { shell , " -c " , NULL , NULL } ;
# include "mouse.h" /* Include mouse support */
2022-10-08 18:07:28 +02:00
# include "statusbar.h" /* Include mouse statuscmd support */
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
2022-10-14 16:14:45 +02:00
# include "signal.h" /* Include signal support */
2022-08-21 11:53:18 +02:00
unsigned int tagw [ LENGTH ( tags ) ] ;
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 */
2022-10-04 19:42:53 +02:00
unsigned int gaps [ LENGTH ( tags ) + 1 ] ;
2022-08-21 11:53:18 +02:00
} ;
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded [ LENGTH ( tags ) > 31 ? - 1 : 1 ] ; } ;
/* speedwm 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 ) ;
2022-09-11 00:41:06 +02:00
die ( " speedwm: execvp %s \n " , * p ) ;
2022-08-21 11:53:18 +02:00
}
/* skip arguments */
while ( * + + p ) ;
}
}
/* 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 ;
c - > scratchkey = 0 ;
XGetClassHint ( dpy , c - > win , & ch ) ;
2022-10-06 09:52:35 +02:00
class = ch . res_class ? ch . res_class : notitle ;
instance = ch . res_name ? ch . res_name : notitle ;
2022-08-21 11:53:18 +02:00
if ( strstr ( class , " Steam " ) | | strstr ( class , " steam_app_ " ) )
c - > issteam = 1 ;
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 ) ) )
{
c - > isterminal = r - > isterminal ;
c - > noswallow = r - > noswallow ;
c - > isfloating = r - > isfloating ;
c - > ignoretransient = r - > ignoretransient ;
c - > ispermanent = r - > ispermanent ;
c - > tags | = r - > tags ;
unmanaged = r - > unmanaged ;
c - > scratchkey = r - > scratchkey ;
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 ) ;
if ( c - > tags & TAGMASK ) c - > tags = c - > tags & TAGMASK ;
else if ( c - > mon - > tagset [ c - > mon - > seltags ] ) c - > tags = c - > mon - > tagset [ c - > mon - > seltags ] ;
else c - > tags = 1 ;
if ( c - > tags ! = SCRATCHPAD_MASK )
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 > tw )
* x = tw - 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 ) {
2022-09-10 23:49:22 +02:00
if ( ! c - > hintsvalid )
updatesizehints ( c ) ;
2022-08-21 11:53:18 +02:00
/* 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 )
{
memcpy ( m - > ltsymbol , m - > lt [ m - > sellt ] - > symbol , sizeof ( m - > ltsymbol ) ) ;
if ( m - > lt [ m - > sellt ] - > arrange ) {
m - > lt [ m - > sellt ] - > arrange ( m ) ;
}
2022-09-17 00:11:05 +02:00
# if USEROUNDCORNERS
2022-08-21 11:53:18 +02:00
if ( roundedcorners ) {
Client * c ;
for ( c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) )
drawroundedcorners ( c ) ;
}
2022-09-17 00:11:05 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
2022-09-11 14:06:29 +02:00
void
moveresizeaspect ( const Arg * arg ) {
Client * c ;
c = selmon - > sel ;
float ratio ;
int w , h , nw , nh ;
if ( ! c | | ! arg )
return ;
if ( selmon - > lt [ selmon - > sellt ] - > arrange & & ! c - > isfloating )
return ;
ratio = ( float ) c - > w / ( float ) c - > h ;
h = arg - > i ;
w = ( int ) ( ratio * h ) ;
nw = c - > w + w ;
nh = c - > h + h ;
XRaiseWindow ( dpy , c - > win ) ;
resize ( c , c - > x , c - > y , nw , nh , True ) ;
}
2022-08-21 11:53:18 +02:00
void
attach ( Client * c )
{
c - > next = c - > mon - > clients ;
c - > mon - > clients = c ;
}
void
attachabove ( Client * c )
{
if ( c - > mon - > sel = = NULL | | c - > mon - > sel = = c - > mon - > clients | | c - > mon - > sel - > isfloating ) {
attach ( c ) ;
return ;
}
Client * at ;
for ( at = c - > mon - > clients ; at - > next ! = c - > mon - > sel ; at = at - > next ) ;
c - > next = at - > next ;
at - > next = c ;
}
void
attachaside ( Client * c ) {
Client * at = nexttagged ( c ) ;
if ( ! at ) {
attach ( c ) ;
return ;
}
c - > next = at - > next ;
at - > next = c ;
}
void
attachbelow ( Client * c )
{
if ( c - > mon - > sel = = NULL | | c - > mon - > sel = = c | | c - > mon - > sel - > isfloating ) {
attach ( c ) ;
return ;
}
c - > next = c - > mon - > sel - > next ;
c - > mon - > sel - > next = c ;
}
void
attachbottom ( Client * c )
{
Client * below = c - > mon - > clients ;
for ( ; below & & below - > next ; below = below - > next ) ;
c - > next = NULL ;
if ( below )
below - > next = c ;
else
c - > mon - > clients = c ;
}
void
attachtop ( Client * c )
{
int n ;
Monitor * m = selmon ;
Client * below ;
for ( n = 1 , below = c - > mon - > clients ;
below & & below - > next & & ( below - > isfloating | | ! ISVISIBLEONTAG ( below , c - > tags ) | | n ! = m - > nmaster ) ;
n = below - > isfloating | | ! ISVISIBLEONTAG ( below , c - > tags ) ? n + 0 : n + 1 , below = below - > next ) ;
c - > next = NULL ;
if ( below ) {
c - > next = below - > next ;
below - > next = c ;
}
else
c - > mon - > clients = c ;
}
void
attachstack ( Client * c )
{
c - > snext = c - > mon - > stack ;
c - > mon - > stack = c ;
}
void
swallow ( Client * p , Client * c )
{
if ( c - > noswallow | | c - > isterminal )
return ;
if ( c - > noswallow & & ! swallowfloating & & c - > isfloating )
return ;
if ( ! swallowclients )
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 ) ;
}
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
void
buttonpress ( XEvent * e )
{
unsigned int i , x , click , occ ;
Arg arg = { 0 } ;
Client * c ;
Monitor * m ;
XButtonPressedEvent * ev = & e - > xbutton ;
* lastbutton = ' 0 ' + ev - > button ;
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 = occ = 0 ;
/* Bitmask of occupied tags */
for ( c = m - > clients ; c ; c = c - > next )
occ | = c - > tags ;
2022-08-27 19:50:19 +02:00
2022-10-01 22:24:19 +02:00
if ( layoutposition ) {
2022-09-10 23:45:37 +02:00
x + = TEXTW ( m - > ltsymbol ) ;
2022-10-01 22:24:19 +02:00
} if ( ev - > x < x & & layoutposition & & ! selmon - > isreset ) {
2022-08-27 19:50:19 +02:00
click = ClkLtSymbol ; // left layout
2022-08-21 11:53:18 +02:00
} else {
2022-08-27 19:50:19 +02:00
do {
2022-09-10 13:31:30 +02:00
if ( ! ( occ & 1 < < i | | m - > tagset [ m - > seltags ] & 1 < < i ) & & hideemptytags )
2022-08-21 11:53:18 +02:00
continue ;
2022-09-10 13:31:30 +02:00
if ( ! hidetags & & hideemptytags )
x + = TEXTW ( occ & 1 < < i ? usedtags [ i ] : tags [ i ] ) ;
else if ( ! hidetags & & ! hideemptytags )
2022-09-08 16:03:56 +02:00
x + = TEXTW ( occ & 1 < < i ? usedtags [ i ] : tags [ i ] ) ;
2022-08-21 11:53:18 +02:00
} while ( ev - > x > = x & & + + i < LENGTH ( tags ) ) ;
2022-09-08 16:03:56 +02:00
if ( i < LENGTH ( tags ) & & ! hidetags ) {
2022-08-21 11:53:18 +02:00
click = ClkTagBar ;
2022-10-03 01:36:47 +02:00
if ( ev - > button = = Button4 | | ev - > button = = Button5 ) {
arg . ui = selmon - > tagset [ selmon - > seltags ] ;
if ( ! ( arg . ui & ( ( 1 < < ( LENGTH ( tags ) - 1 ) ) + 1 ) ) ) {
arg . ui = ( ev - > button = = Button4 ) ? ( arg . ui > > 1 ) : ( arg . ui < < 1 ) ;
} else if ( arg . ui & 1 ) {
arg . ui = ( ev - > button = = Button4 ) ? arg . ui : ( arg . ui < < 1 ) ;
} else if ( arg . ui & ( 1 < < ( LENGTH ( tags ) - 1 ) ) ) {
arg . ui = ( ev - > button = = Button4 ) ? ( arg . ui > > 1 ) : arg . ui ;
}
} else
2022-08-21 11:53:18 +02:00
arg . ui = 1 < < i ;
2022-10-03 21:57:15 +02:00
# if USETAGPREVIEW
if ( selmon - > previewshow ) {
selmon - > previewshow = 0 ;
XUnmapWindow ( dpy , selmon - > tagwin ) ;
}
# endif
2022-10-01 22:24:19 +02:00
} else if ( ev - > x < x + TEXTW ( selmon - > ltsymbol ) & & ! layoutposition & & ! selmon - > isreset ) // right layout
2022-08-27 19:50:19 +02:00
click = ClkLtSymbol ; // right layout
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
else if ( ev - > x > selmon - > ww - statusw + lrpad - 2 - getsystraywidth ( ) & & ! hidestatus ) {
x = selmon - > ww - statusw + lrpad - 2 * sp - getsystraywidth ( ) - 2 ;
# else
2022-09-08 17:03:46 +02:00
else if ( ev - > x > selmon - > ww - statusw + lrpad - 2 & & ! hidestatus ) {
2022-10-02 15:34:11 +02:00
x = selmon - > ww - statusw + lrpad - 2 * sp - 2 ;
# endif
2022-08-21 11:53:18 +02:00
click = ClkStatusText ;
2022-08-27 21:49:51 +02:00
char * text = rawstext ;
int i = - 1 ;
char ch ;
statuscmdn = 0 ;
while ( text [ + + i ] ) {
if ( ( unsigned char ) text [ i ] < ' ' ) {
ch = text [ i ] ;
text [ i ] = ' \0 ' ;
2022-10-08 00:41:15 +02:00
x + = statuslength ( text ) ;
//x += TEXTW(text) - lrpad - 2;
2022-08-27 21:49:51 +02:00
text [ i ] = ch ;
text + = i + 1 ;
i = - 1 ;
if ( x > = ev - > x )
break ;
if ( ch < = LENGTH ( statuscmds ) )
statuscmdn = ch ;
}
2022-08-21 11:53:18 +02:00
}
} else {
2022-10-01 22:24:19 +02:00
if ( ! layoutposition ) {
2022-10-03 21:57:15 +02:00
x + = TEXTW ( m - > ltsymbol ) ; // Left layout does not need this
2022-08-28 21:54:47 +02:00
}
2022-09-08 16:03:56 +02:00
2022-10-11 17:11:31 +02:00
/* Don't click if title is hidden
* This is not required , but you won ' t be able to see what you ' re clicking so we might as well disable it */
2022-09-08 16:03:56 +02:00
if ( ! hidetitle ) {
2022-08-21 11:53:18 +02:00
c = m - > clients ;
if ( c ) {
do {
2022-08-27 21:49:51 +02:00
if ( ! c | | ! ISVISIBLE ( c ) )
2022-08-21 11:53:18 +02:00
continue ;
2022-08-27 21:49:51 +02:00
else
2022-08-28 21:54:47 +02:00
x + = ( 1.0 / ( double ) m - > bt ) * m - > btw ;
2022-08-27 21:49:51 +02:00
} while ( c & & ev - > x > x & & ( c = c - > next ) ) ;
2022-08-21 11:53:18 +02:00
click = ClkWinTitle ;
arg . v = c ;
}
2022-09-08 16:03:56 +02:00
}
2022-08-21 11:53:18 +02:00
}
}
} else if ( ( c = wintoclient ( ev - > window ) ) ) {
focus ( c ) ;
restack ( selmon ) ;
XAllowEvents ( dpy , ReplayPointer , CurrentTime ) ;
click = ClkClientWin ;
2022-08-27 19:50:19 +02:00
}
2022-08-21 11:53:18 +02:00
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 ) )
buttons [ i ] . func ( ( click = = ClkTagBar | | click = = ClkWinTitle ) & & buttons [ i ] . arg . i = = 0 ? & arg : & buttons [ i ] . arg ) ;
}
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02: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 ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( showsystray ) {
XUnmapWindow ( dpy , systray - > win ) ;
XDestroyWindow ( dpy , systray - > win ) ;
free ( systray ) ;
}
# endif
2022-08-21 11:53:18 +02:00
for ( i = 0 ; i < CurLast ; i + + )
drw_cur_free ( drw , cursor [ i ] ) ;
for ( i = 0 ; i < LENGTH ( colors ) + 1 ; i + + )
free ( scheme [ i ] ) ;
free ( scheme ) ;
2022-08-25 18:53:04 +02:00
if ( fullscreenhidebar )
XDestroyWindow ( dpy , wmcheckwin ) ;
2022-08-21 11:53:18 +02:00
drw_free ( drw ) ;
XSync ( dpy , False ) ;
XSetInputFocus ( dpy , PointerRoot , RevertToPointerRoot , CurrentTime ) ;
XDeleteProperty ( dpy , root , netatom [ NetActiveWindow ] ) ;
2022-08-26 11:41:11 +02:00
# if USEIPC
ipc_cleanup ( ) ;
if ( close ( epoll_fd ) < 0 ) {
fprintf ( stderr , " Failed to close epoll file descriptor \n " ) ;
}
# endif
2022-08-21 11:53:18 +02:00
}
void
cleanupmon ( Monitor * mon )
{
Monitor * m ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
size_t i ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
if ( mon = = mons )
mons = mons - > next ;
else {
for ( m = mons ; m & & m - > next ! = mon ; m = m - > next ) ;
m - > next = mon - > next ;
}
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
for ( i = 0 ; i < LENGTH ( tags ) ; i + + ) {
if ( mon - > tagmap [ i ] )
XFreePixmap ( dpy , mon - > tagmap [ i ] ) ;
free ( mon - > tagmap ) ;
2022-09-03 17:44:49 +02:00
2022-08-21 11:53:18 +02:00
if ( ! altbar ) {
XUnmapWindow ( dpy , mon - > tagwin ) ;
XDestroyWindow ( dpy , mon - > tagwin ) ;
}
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
free ( mon ) ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
}
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
void
clientmessage ( XEvent * e )
{
XClientMessageEvent * cme = & e - > xclient ;
Client * c = wintoclient ( cme - > window ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
XWindowAttributes wa ;
XSetWindowAttributes swa ;
if ( showsystray & & cme - > window = = systray - > win & & cme - > message_type = = netatom [ NetSystemTrayOP ] ) {
/* add systray icons */
if ( cme - > data . l [ 1 ] = = SYSTEM_TRAY_REQUEST_DOCK ) {
if ( ! ( c = ( Client * ) calloc ( 1 , sizeof ( Client ) ) ) )
die ( " fatal: could not malloc() %u bytes \n " , sizeof ( Client ) ) ;
if ( ! ( c - > win = cme - > data . l [ 2 ] ) ) {
free ( c ) ;
return ;
}
c - > mon = selmon ;
c - > next = systray - > icons ;
systray - > icons = c ;
if ( ! XGetWindowAttributes ( dpy , c - > win , & wa ) ) {
/* use sane defaults */
wa . width = bh ;
wa . height = bh ;
wa . border_width = 0 ;
}
c - > x = c - > oldx = c - > y = c - > oldy = 0 ;
c - > w = c - > oldw = wa . width ;
c - > h = c - > oldh = wa . height ;
c - > oldbw = wa . border_width ;
c - > bw = 0 ;
c - > isfloating = True ;
/* reuse tags field as mapped status */
c - > tags = 1 ;
updatesizehints ( c ) ;
updatesystrayicongeom ( c , wa . width , wa . height ) ;
XAddToSaveSet ( dpy , c - > win ) ;
XSelectInput ( dpy , c - > win , StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask ) ;
XReparentWindow ( dpy , c - > win , systray - > win , 0 , 0 ) ;
/* use parents background color */
swa . background_pixel = scheme [ SchemeBar ] [ ColBg ] . pixel ;
XChangeWindowAttributes ( dpy , c - > win , CWBackPixel , & swa ) ;
sendevent ( c - > win , netatom [ Xembed ] , StructureNotifyMask , CurrentTime , XEMBED_EMBEDDED_NOTIFY , 0 , systray - > win , XEMBED_EMBEDDED_VERSION ) ;
sendevent ( c - > win , netatom [ Xembed ] , StructureNotifyMask , CurrentTime , XEMBED_FOCUS_IN , 0 , systray - > win , XEMBED_EMBEDDED_VERSION ) ;
sendevent ( c - > win , netatom [ Xembed ] , StructureNotifyMask , CurrentTime , XEMBED_WINDOW_ACTIVATE , 0 , systray - > win , XEMBED_EMBEDDED_VERSION ) ;
sendevent ( c - > win , netatom [ Xembed ] , StructureNotifyMask , CurrentTime , XEMBED_MODALITY_ON , 0 , systray - > win , XEMBED_EMBEDDED_VERSION ) ;
XSync ( dpy , False ) ;
resizebarwin ( selmon ) ;
updatesystray ( ) ;
setclientstate ( c , NormalState ) ;
}
return ;
}
# endif
2022-08-21 11:53:18 +02:00
unsigned int i ;
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 ] ) {
for ( i = 0 ; i < LENGTH ( tags ) & & ! ( ( 1 < < i ) & c - > tags ) ; i + + ) ;
if ( i < LENGTH ( tags ) ) {
const Arg a = { . ui = 1 < < i } ;
selmon = c - > mon ;
view ( & a ) ;
focus ( c ) ;
restack ( selmon ) ;
}
}
}
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 ;
if ( ev - > window = = root ) {
dirty = ( tw ! = ev - > width | | sh ! = ev - > height ) ;
tw = ev - > width ;
sh = ev - > height ;
if ( updategeom ( ) | | dirty ) {
drw_resize ( drw , tw , 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 ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
resizebarwin ( m ) ;
# else
XMoveResizeWindow ( dpy , m - > barwin , m - > wx + sp , m - > by + vp , m - > ww - 2 * sp , bh ) ;
# endif
2022-08-21 11:53:18 +02:00
}
focus ( NULL ) ;
arrange ( NULL ) ;
}
}
}
2022-09-17 00:11:05 +02:00
# if USEROUNDCORNERS
2022-10-11 17:11:31 +02:00
void
drawroundedcorners ( Client * c )
2022-08-21 11:53:18 +02:00
{
2022-10-03 01:36:47 +02:00
Window w = c - > win ;
XWindowAttributes wa ;
XGetWindowAttributes ( dpy , w , & wa ) ;
2022-08-21 11:53:18 +02:00
2022-10-03 01:36:47 +02:00
if ( ! XGetWindowAttributes ( dpy , w , & wa ) )
return ;
int width = borderpx * 2 + wa . width ;
int height = borderpx * 2 + wa . height ;
2022-10-04 19:58:03 +02:00
int rad = cornerradius ;
2022-10-03 01:36:47 +02:00
int dia = 2 * rad ;
if ( width < dia | | height < dia )
return ;
2022-08-21 11:53:18 +02:00
2022-10-03 01:36:47 +02:00
Pixmap mask = XCreatePixmap ( dpy , w , width , height , 1 ) ;
if ( ! mask )
return ;
XGCValues xgcv ;
GC shape_gc = XCreateGC ( dpy , mask , 0 , & xgcv ) ;
if ( ! shape_gc ) {
2022-08-21 11:53:18 +02:00
XFreePixmap ( dpy , mask ) ;
return ;
}
XSetForeground ( dpy , shape_gc , 0 ) ;
2022-10-03 01:36:47 +02:00
XFillRectangle ( dpy , mask , shape_gc , 0 , 0 , width , height ) ;
2022-08-21 11:53:18 +02:00
XSetForeground ( dpy , shape_gc , 1 ) ;
XFillArc ( dpy , mask , shape_gc , 0 , 0 , dia , dia , 0 , 23040 ) ;
2022-10-03 01:36:47 +02:00
XFillArc ( dpy , mask , shape_gc , width - dia - 1 , 0 , dia , dia , 0 , 23040 ) ;
XFillArc ( dpy , mask , shape_gc , 0 , height - dia - 1 , dia , dia , 0 , 23040 ) ;
XFillArc ( dpy , mask , shape_gc , width - dia - 1 , height - dia - 1 , dia , dia , 0 , 23040 ) ;
XFillRectangle ( dpy , mask , shape_gc , rad , 0 , width - dia , height ) ;
XFillRectangle ( dpy , mask , shape_gc , 0 , rad , width , height - dia ) ;
XShapeCombineMask ( dpy , w , ShapeBounding , 0 - wa . border_width , 0 - wa . border_width , mask , ShapeSet ) ;
2022-08-21 11:53:18 +02:00
XFreePixmap ( dpy , mask ) ;
XFreeGC ( dpy , shape_gc ) ;
}
2022-09-17 00:11:05 +02:00
# endif
2022-08-21 11:53:18 +02:00
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 ( ! c - > issteam ) {
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 ) ;
2022-10-01 15:37:35 +02:00
else if ( autoresize )
2022-08-21 11:53:18 +02:00
c - > needresize = 1 ;
} 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 ) ;
}
void
copyvalidchars ( char * text , char * rawtext )
{
int i = - 1 , j = 0 ;
while ( rawtext [ + + i ] ) {
if ( ( unsigned char ) rawtext [ i ] > = ' ' ) {
text [ j + + ] = rawtext [ i ] ;
}
}
text [ j ] = ' \0 ' ;
}
Monitor *
createmon ( void )
{
Monitor * m ;
unsigned int i ;
m = ecalloc ( 1 , sizeof ( Monitor ) ) ;
m - > tagset [ 0 ] = m - > tagset [ 1 ] = startontag ? 1 : 0 ;
m - > mfact = mfact ;
m - > nmaster = nmaster ;
2022-09-20 16:53:23 +02:00
m - > showbar = ! hidebar ;
2022-08-21 11:53:18 +02:00
m - > barposition = barposition ;
m - > bh = bh ;
m - > gappih = gappih ;
m - > gappiv = gappiv ;
m - > gappoh = gappoh ;
m - > gappov = gappov ;
m - > lt [ 0 ] = & layouts [ 0 ] ;
m - > lt [ 1 ] = & layouts [ 1 % LENGTH ( layouts ) ] ;
strncpy ( m - > ltsymbol , layouts [ 0 ] . symbol , sizeof m - > ltsymbol ) ;
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 ;
}
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
m - > tagmap = ecalloc ( LENGTH ( tags ) , sizeof ( Pixmap ) ) ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
return m ;
}
void
cyclelayout ( const Arg * arg ) {
Layout * l ;
for ( l = ( Layout * ) layouts ; l ! = selmon - > lt [ selmon - > sellt ] ; l + + ) ;
if ( arg - > i > 0 ) {
if ( l - > symbol & & ( l + 1 ) - > symbol )
setlayout ( & ( ( Arg ) { . v = ( l + 1 ) } ) ) ;
else
setlayout ( & ( ( Arg ) { . v = layouts } ) ) ;
} else {
if ( l ! = layouts & & ( l - 1 ) - > symbol )
setlayout ( & ( ( Arg ) { . v = ( l - 1 ) } ) ) ;
else
setlayout ( & ( ( Arg ) { . v = & layouts [ LENGTH ( layouts ) - 2 ] } ) ) ;
}
}
void
destroynotify ( XEvent * e )
{
Client * c ;
Monitor * m ;
XDestroyWindowEvent * ev = & e - > xdestroywindow ;
if ( ( c = wintoclient ( ev - > window ) ) )
unmanage ( c , 1 ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
else if ( ( c = wintosystrayicon ( ev - > window ) ) ) {
removesystrayicon ( c ) ;
resizebarwin ( selmon ) ;
updatesystray ( ) ;
}
# endif
2022-08-21 11:53:18 +02:00
else if ( ( c = swallowingclient ( ev - > window ) ) )
unmanage ( c - > swallowing , 1 ) ;
if ( altbar & & ( m = wintomon ( ev - > window ) ) & & m - > barwin = = ev - > window )
unmanagealtbar ( ev - > window ) ;
else if ( altbar & & m - > traywin = = ev - > window )
unmanagetray ( ev - > window ) ;
}
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
void
layoutmenu ( const Arg * arg ) {
FILE * p ;
char c [ 3 ] ;
int i ;
2022-10-06 09:52:35 +02:00
if ( ! ( p = popen ( layoutcmd , " r " ) ) )
2022-08-21 11:53:18 +02:00
return ;
pclose ( p ) ;
i = atoi ( c ) ;
setlayout ( & ( ( Arg ) { . v = & layouts [ i ] } ) ) ;
}
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
void
detach ( Client * c )
{
Client * * tc ;
2022-09-11 14:16:14 +02:00
for ( int i = 1 ; i < LENGTH ( tags ) ; i + + )
if ( c = = c - > mon - > tagmarked [ i ] )
c - > mon - > tagmarked [ i ] = NULL ;
2022-08-21 11:53:18 +02:00
for ( tc = & c - > mon - > clients ; * tc & & * tc ! = c ; tc = & ( * tc ) - > next ) ;
* tc = c - > next ;
}
void
getfacts ( Monitor * m , int msize , int ssize , float * mf , float * sf , int * mr , int * sr )
{
unsigned int n ;
float mfacts , sfacts ;
int mtotal = 0 , stotal = 0 ;
Client * c ;
for ( n = 0 , c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) , n + + ) ;
mfacts = MIN ( n , m - > nmaster ) ;
sfacts = n - m - > nmaster ;
for ( n = 0 , c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) , n + + )
if ( n < m - > nmaster )
mtotal + = msize / mfacts ;
else
stotal + = ssize / sfacts ;
* mf = mfacts ; // total factor of master area
* sf = sfacts ; // total factor of stack area
* mr = msize - mtotal ; // the remainder (rest) of pixels after an even master split
* sr = ssize - stotal ; // the remainder (rest) of pixels after an even stack split
}
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 ;
}
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-28 01:47:41 +02:00
void
dragcfact ( const Arg * arg )
{
2022-10-11 14:01:22 +02:00
if ( ! mousecfact )
return ;
2022-08-28 01:47:41 +02:00
int prev_x , prev_y , dist_x , dist_y ;
float fact ;
Client * c ;
XEvent ev ;
Time lasttime = 0 ;
if ( ! ( c = selmon - > sel ) )
return ;
if ( c - > isfloating ) {
resizemouse ( arg ) ;
return ;
}
if ( c - > isfullscreen ) /* no support resizing fullscreen windows by mouse */
return ;
2022-08-28 02:33:33 +02:00
2022-08-28 01:47:41 +02:00
restack ( selmon ) ;
if ( XGrabPointer ( dpy , root , False , MOUSEMASK , GrabModeAsync , GrabModeAsync ,
None , cursor [ CurResize ] - > cursor , CurrentTime ) ! = GrabSuccess )
return ;
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w / 2 , c - > h / 2 ) ;
prev_x = prev_y = - 999999 ;
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 ;
if ( prev_x = = - 999999 ) {
prev_x = ev . xmotion . x_root ;
prev_y = ev . xmotion . y_root ;
}
dist_x = ev . xmotion . x - prev_x ;
dist_y = ev . xmotion . y - prev_y ;
if ( abs ( dist_x ) > abs ( dist_y ) ) {
fact = ( float ) 4.0 * dist_x / c - > mon - > ww ;
} else {
fact = ( float ) - 4.0 * dist_y / c - > mon - > wh ;
}
if ( fact )
setcfact ( & ( ( Arg ) { . f = fact } ) ) ;
prev_x = ev . xmotion . x ;
prev_y = ev . xmotion . y ;
break ;
}
} while ( ev . type ! = ButtonRelease ) ;
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w / 2 , c - > h / 2 ) ;
XUngrabPointer ( dpy , CurrentTime ) ;
while ( XCheckMaskEvent ( dpy , EnterWindowMask , & ev ) ) ;
}
2022-09-03 16:46:19 +02:00
# endif
2022-08-28 01:47:41 +02:00
2022-08-21 11:53:18 +02:00
Bool
isHexDigit ( char digit ) {
return ( digit > = ' 0 ' & & digit < = ' 9 ' ) | | ( digit > = ' A ' & & digit < = ' F ' ) | | ( digit > = ' a ' & & digit < = ' f ' ) ;
}
Bool
isHexColor ( char * hex ) {
return isHexDigit ( hex [ 1 ] ) & & isHexDigit ( hex [ 2 ] ) & & isHexDigit ( hex [ 3 ] ) & &
isHexDigit ( hex [ 4 ] ) & & isHexDigit ( hex [ 5 ] ) & & isHexDigit ( hex [ 6 ] ) & &
hex [ 0 ] = = ' # ' & & hex [ 7 ] = = ' \0 ' ;
}
void
readAndSetColor ( int clrIdx , char * txt ) {
char buf [ 8 ] ;
memcpy ( buf , txt , 7 ) ;
buf [ 7 ] = ' \0 ' ;
if ( isHexColor ( buf ) ) {
drw_clr_create ( drw , & drw - > scheme [ clrIdx ] , buf , alphas [ SchemeStatus ] [ ColBg ] ) ;
}
}
2022-10-08 00:41:15 +02:00
int
statuslength ( char * stext )
{
int ret , i = - 1 , j = 0 , w , len ;
short isCode = 0 ;
char * text ;
char * p ;
len = strlen ( stext ) + 1 ;
if ( ! ( text = ( char * ) malloc ( sizeof ( char ) * len ) ) )
die ( " malloc " ) ;
p = text ;
copyvalidchars ( text , stext ) ;
/* compute width of the status text */
w = 0 ;
i = - 1 ;
while ( text [ + + i ] ) {
if ( text [ i ] = = ' ^ ' ) {
if ( ! isCode ) {
isCode = 1 ;
text [ i ] = ' \0 ' ;
w + = TEXTW ( text ) - lrpad ;
text [ i ] = ' ^ ' ;
if ( text [ + + i ] = = ' f ' )
w + = atoi ( text + + + i ) ;
} else {
isCode = 0 ;
text = text + i + 1 ;
i = - 1 ;
}
}
}
if ( ! isCode )
w + = TEXTW ( text ) - lrpad ;
free ( p ) ;
return w ;
}
2022-08-21 11:53:18 +02:00
int
drawstatusbar ( Monitor * m , int bh , char * stext ) {
int ret , i , j , w , x , len ;
short isCode = 0 ;
char * text ;
char * p ;
2022-10-08 00:41:15 +02:00
len = strlen ( stext ) + 1 ;
2022-08-21 11:53:18 +02:00
if ( ! ( text = ( char * ) malloc ( sizeof ( char ) * len ) ) )
die ( " malloc " ) ;
p = text ;
2022-10-08 00:41:15 +02:00
copyvalidchars ( text , stext ) ;
2022-08-27 21:49:51 +02:00
2022-08-21 11:53:18 +02:00
i = - 1 , j = 0 ;
2022-10-08 00:41:15 +02:00
while ( stext [ + + i ] )
if ( ( unsigned char ) stext [ i ] > = ' ' )
text [ j + + ] = stext [ i ] ;
2022-08-21 11:53:18 +02:00
text [ j ] = ' \0 ' ;
2022-08-27 21:49:51 +02:00
2022-08-21 11:53:18 +02:00
/* compute width of the status text */
w = 0 ;
i = - 1 ;
while ( text [ + + i ] ) {
if ( text [ i ] = = ' ^ ' ) {
if ( ! isCode ) {
isCode = 1 ;
text [ i ] = ' \0 ' ;
w + = TEXTW ( text ) - lrpad ;
text [ i ] = ' ^ ' ;
if ( text [ + + i ] = = ' f ' )
w + = atoi ( text + + + i ) ;
} else {
isCode = 0 ;
text = text + i + 1 ;
i = - 1 ;
}
}
}
if ( ! isCode )
w + = TEXTW ( text ) - lrpad ;
else
isCode = 0 ;
text = p ;
w + = 2 ; /* 1px padding on both sides */
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
2022-10-07 21:58:30 +02:00
ret = x = m - > ww - w - 2 * sp - ( ( showsystray & & m = = systraytomon ( m ) ) ? getsystraywidth ( ) : 0 ) ;
2022-10-02 15:34:11 +02:00
# else
2022-08-21 11:53:18 +02:00
ret = x = m - > ww - w - 2 * sp ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
drw_setscheme ( drw , scheme [ LENGTH ( colors ) ] ) ;
drw - > scheme [ ColFg ] = scheme [ SchemeStatus ] [ ColFg ] ;
drw - > scheme [ ColBg ] = scheme [ SchemeStatus ] [ ColBg ] ;
drw_rect ( drw , x , 0 , w , bh , 1 , 1 ) ;
x + + ;
/* process status text */
i = - 1 ;
while ( text [ + + i ] ) {
if ( text [ i ] = = ' ^ ' & & ! isCode ) {
isCode = 1 ;
text [ i ] = ' \0 ' ;
w = TEXTW ( text ) - lrpad ;
drw_text ( drw , x , 0 , w , bh , 0 , text , 0 ) ;
x + = w ;
/* process code */
while ( text [ + + i ] ! = ' ^ ' ) {
if ( text [ i ] = = ' c ' ) {
readAndSetColor ( ColFg , ( char * ) text + i + 1 ) ;
i + = 7 ;
} else if ( text [ i ] = = ' b ' ) {
readAndSetColor ( ColBg , ( char * ) text + i + 1 ) ;
i + = 7 ;
} else if ( text [ i ] = = ' C ' ) {
int c = atoi ( text + + + i ) ;
drw_clr_create ( drw , & drw - > scheme [ ColFg ] , colstatus [ c ] , alphas [ SchemeStatus ] [ ColBg ] ) ;
} else if ( text [ i ] = = ' B ' ) {
int c = atoi ( text + + + i ) ;
drw_clr_create ( drw , & drw - > scheme [ ColBg ] , colstatus [ c ] , alphas [ SchemeStatus ] [ ColBg ] ) ;
} else if ( text [ i ] = = ' d ' ) {
drw - > scheme [ ColFg ] = scheme [ SchemeStatus ] [ ColFg ] ;
drw - > scheme [ ColBg ] = scheme [ SchemeStatus ] [ ColBg ] ;
} else if ( text [ i ] = = ' r ' ) {
int rx = atoi ( text + + + i ) ;
while ( text [ + + i ] ! = ' , ' ) ;
int ry = atoi ( text + + + i ) ;
while ( text [ + + i ] ! = ' , ' ) ;
int rw = atoi ( text + + + i ) ;
while ( text [ + + i ] ! = ' , ' ) ;
int rh = atoi ( text + + + i ) ;
drw_rect ( drw , rx + x , ry , rw , rh , 1 , 0 ) ;
} else if ( text [ i ] = = ' f ' ) {
x + = atoi ( text + + + i ) ;
}
}
text = text + i + 1 ;
i = - 1 ;
isCode = 0 ;
}
}
if ( ! isCode ) {
w = TEXTW ( text ) - lrpad ;
drw_text ( drw , x , 0 , w , bh , 0 , text , 0 ) ;
w = 0 ;
}
drw_setscheme ( drw , scheme [ SchemeStatus ] ) ;
free ( p ) ;
return ret ;
}
2022-10-11 14:01:22 +02:00
# if USEMOUSE
void
dragmfact ( const Arg * arg )
{
if ( ! mousemfact )
return ;
unsigned int n ;
int py , px ; // pointer coordinates
int ax , ay , aw , ah ; // area position, width and height
int center = 0 , horizontal = 0 , mirror = 0 , fixed = 0 ; // layout configuration
double fact ;
Monitor * m ;
XEvent ev ;
Time lasttime = 0 ;
m = selmon ;
int oh , ov , ih , iv ;
getgaps ( m , & oh , & ov , & ih , & iv , & n ) ;
ax = m - > wx ;
ay = m - > wy ;
ah = m - > wh ;
aw = m - > ww ;
if ( ! n )
return ;
# if LAYOUT_CM
else if ( m - > lt [ m - > sellt ] - > arrange = = & centeredmaster & & ( fixed | | n - m - > nmaster > 1 ) )
center = 1 ;
# endif
# if LAYOUT_CFM
else if ( m - > lt [ m - > sellt ] - > arrange = = & centeredfloatingmaster )
center = 1 ;
# endif
# if LAYOUT_BSTACK
else if ( m - > lt [ m - > sellt ] - > arrange = = & bstack )
horizontal = 1 ;
# endif
# if LAYOUT_BSTACKH
else if ( m - > lt [ m - > sellt ] - > arrange = = & bstackhoriz )
horizontal = 1 ;
# endif
/* do not allow mfact to be modified under certain conditions */
if ( ! m - > lt [ m - > sellt ] - > arrange // floating layout
| | ( ! fixed & & m - > nmaster & & n < = m - > nmaster ) // no master
# if LAYOUT_MONOCLE
| | m - > lt [ m - > sellt ] - > arrange = = & monocle
# endif
# if LAYOUT_GRID
| | m - > lt [ m - > sellt ] - > arrange = = & grid
# endif
# if LAYOUT_HGRID
| | m - > lt [ m - > sellt ] - > arrange = = & horizgrid
# endif
# if LAYOUT_DGRID
| | m - > lt [ m - > sellt ] - > arrange = = & dynamicgrid
# endif
# if LAYOUT_NGRID
| | m - > lt [ m - > sellt ] - > arrange = = & nrowgrid
# endif
)
return ;
ay + = oh ;
ax + = ov ;
aw - = 2 * ov ;
ah - = 2 * oh ;
if ( center ) {
if ( horizontal ) {
px = ax + aw / 2 ;
py = ay + ah / 2 + ( ah - 2 * ih ) * ( m - > mfact / 2.0 ) + ih / 2 ;
} else { // vertical split
px = ax + aw / 2 + ( aw - 2 * iv ) * m - > mfact / 2.0 + iv / 2 ;
py = ay + ah / 2 ;
}
} else if ( horizontal ) {
px = ax + aw / 2 ;
if ( mirror )
py = ay + ( ah - ih ) * ( 1.0 - m - > mfact ) + ih / 2 ;
else
py = ay + ( ( ah - ih ) * m - > mfact ) + ih / 2 ;
} else { // vertical split
if ( mirror )
px = ax + ( aw - iv ) * ( 1.0 - m - > mfact ) + iv / 2 ;
else
px = ax + ( ( aw - iv ) * m - > mfact ) + iv / 2 ;
py = ay + ah / 2 ;
}
if ( XGrabPointer ( dpy , root , False , MOUSEMASK , GrabModeAsync , GrabModeAsync ,
None , cursor [ horizontal ? CurResizeVertArrow : CurResizeHorzArrow ] - > cursor , CurrentTime ) ! = GrabSuccess )
return ;
XWarpPointer ( dpy , None , root , 0 , 0 , 0 , 0 , px , py ) ;
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 / 40 ) )
continue ;
if ( lasttime ! = 0 ) {
px = ev . xmotion . x ;
py = ev . xmotion . y ;
}
lasttime = ev . xmotion . time ;
if ( center )
if ( horizontal )
if ( py - ay > ah / 2 )
fact = ( double ) 1.0 - ( ay + ah - py - ih / 2 ) * 2 / ( double ) ( ah - 2 * ih ) ;
else
fact = ( double ) 1.0 - ( py - ay - ih / 2 ) * 2 / ( double ) ( ah - 2 * ih ) ;
else
if ( px - ax > aw / 2 )
fact = ( double ) 1.0 - ( ax + aw - px - iv / 2 ) * 2 / ( double ) ( aw - 2 * iv ) ;
else
fact = ( double ) 1.0 - ( px - ax - iv / 2 ) * 2 / ( double ) ( aw - 2 * iv ) ;
else
if ( horizontal )
fact = ( double ) ( py - ay - ih / 2 ) / ( double ) ( ah - ih ) ;
else
fact = ( double ) ( px - ax - iv / 2 ) / ( double ) ( aw - iv ) ;
if ( ! center & & mirror )
fact = 1.0 - fact ;
setmfact ( & ( ( Arg ) { . f = 1.0 + fact } ) ) ;
px = ev . xmotion . x ;
py = ev . xmotion . y ;
break ;
}
} while ( ev . type ! = ButtonRelease ) ;
XUngrabPointer ( dpy , CurrentTime ) ;
while ( XCheckMaskEvent ( dpy , EnterWindowMask , & ev ) ) ;
}
# endif
2022-08-21 11:53:18 +02:00
void
drawbar ( Monitor * m )
{
2022-08-28 21:54:47 +02:00
int x = 0 , w = 0 , tw = 0 , scm ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
int stw = 0 ;
# endif
2022-08-21 11:53:18 +02:00
int boxs = drw - > fonts - > h / 9 ;
int boxw = drw - > fonts - > h / 6 + 2 ;
2022-09-03 19:08:07 +02:00
unsigned int i , occ = 0 , urg = 0 , n = 0 ;
# if LAYOUT_MONOCLE
unsigned int s = 0 , a = 0 ;
# endif
2022-08-21 11:53:18 +02:00
const char * tagtext ;
Client * c ;
if ( ! m - > showbar )
return ;
if ( altbar )
return ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( showsystray & & m = = systraytomon ( m ) & & ! systrayonleft )
stw = getsystraywidth ( ) ;
# endif
2022-08-21 11:53:18 +02:00
/* draw status first so it can be overdrawn by tags later */
if ( m = = selmon | | 1 ) { /* status is only drawn on selected monitor */
char * text , * s , ch ;
if ( ! hidestatus ) {
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
tw = statusw = m - > ww - drawstatusbar ( m , bh , stext ) - getsystraywidth ( ) ;
# else
2022-08-21 11:53:18 +02:00
tw = statusw = m - > ww - drawstatusbar ( m , bh , stext ) ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
resizebarwin ( m ) ;
# endif
2022-08-21 11:53:18 +02:00
2022-10-03 21:57:15 +02:00
/* for statuscmd */
2022-08-21 11:53:18 +02:00
for ( text = s = stext ; * s ; s + + ) {
if ( ( unsigned char ) ( * s ) < ' ' ) {
ch = * s ;
* s = ' \0 ' ;
tw = TEXTW ( text ) - lrpad ;
x + = tw ;
* s = ch ;
text = s + 1 ;
}
}
}
for ( c = m - > clients ; c ; c = c - > next ) {
if ( ISVISIBLE ( c ) )
n + + ;
occ | = c - > tags ;
2022-09-08 16:03:56 +02:00
if ( c - > isurgent & & ! hidetags )
2022-08-21 11:53:18 +02:00
urg | = c - > tags ;
}
2022-08-27 21:49:51 +02:00
2022-10-01 22:24:19 +02:00
/* Draw the layout bar on the left if layoutposition = 1 */
2022-08-21 11:53:18 +02:00
/* If colorlayoutnorm = 0, draw using SchemeLayout */
2022-10-01 22:24:19 +02:00
if ( layoutposition & & ! hidelayout ) {
2022-09-10 23:45:37 +02:00
w = TEXTW ( m - > ltsymbol ) ;
2022-08-21 11:53:18 +02:00
drw_setscheme ( drw , scheme [ SchemeLayout ] ) ;
x = drw_text ( drw , x , 0 , w , bh , lrpad / 2 , m - > ltsymbol , 0 ) ;
}
2022-09-08 16:03:56 +02:00
if ( ! hidetags ) {
2022-08-21 11:53:18 +02:00
for ( i = 0 ; i < LENGTH ( tags ) ; i + + ) {
2022-09-10 13:31:30 +02:00
if ( ! ( occ & 1 < < i | | m - > tagset [ m - > seltags ] & 1 < < i ) & & hideemptytags )
2022-08-21 11:53:18 +02:00
continue ;
if ( ! hidetags ) {
2022-09-08 16:03:56 +02:00
tagtext = occ & 1 < < i ? usedtags [ i ] : tags [ i ] ;
2022-08-21 11:53:18 +02:00
w = TEXTW ( tagtext ) ;
drw_setscheme ( drw , ( m - > tagset [ m - > seltags ] & 1 < < i ? tagscheme [ i ] : scheme [ SchemeTags ] ) ) ;
drw_text ( drw , x , 0 , w , bh , lrpad / 2 , tagtext , urg & 1 < < i ) ;
if ( underlineall | | m - > tagset [ m - > seltags ] & 1 < < i )
if ( underline )
drw_rect ( drw , x + underlinepad , bh - underlinestroke - underlinevoffset , w - ( underlinepad * 2 ) , underlinestroke , 1 , 0 ) ;
2022-09-10 13:31:30 +02:00
2022-08-21 11:53:18 +02:00
x + = w ;
}
2022-09-08 16:03:56 +02:00
}
}
2022-08-21 11:53:18 +02:00
2022-09-03 19:08:07 +02:00
# if LAYOUT_MONOCLE
2022-08-21 11:53:18 +02:00
if ( monoclecount ) {
if ( m - > lt [ m - > sellt ] - > arrange = = monocle ) {
for ( c = nexttiled ( m - > clients ) , a = 0 , s = 0 ; c ; c = nexttiled ( c - > next ) , a + + )
if ( c = = m - > stack )
s = a + 1 ;
if ( ! s & & a )
s = 1 ;
snprintf ( m - > ltsymbol , sizeof m - > ltsymbol , monocleformat , s , a ) ;
}
}
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
2022-10-01 22:24:19 +02:00
/* Draw the layout bar on the right if layoutposition is not 0 */
2022-08-21 11:53:18 +02:00
/* If colorlayoutnorm = 0, draw using SchemeLayout */
2022-10-01 22:24:19 +02:00
if ( ! layoutposition & & ! hidelayout ) {
2022-09-10 23:45:37 +02:00
w = TEXTW ( m - > ltsymbol ) ;
2022-08-21 11:53:18 +02:00
drw_setscheme ( drw , scheme [ SchemeLayout ] ) ;
x = drw_text ( drw , x , 0 , w , bh , lrpad / 2 , m - > ltsymbol , 0 ) ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( ( w = m - > ww - tw - stw - x ) > bh ) {
# else
2022-08-21 11:53:18 +02:00
if ( ( w = m - > ww - tw - x ) > bh ) {
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02: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 ;
if ( m - > sel = = c )
scm = SchemeSelTitle ;
else if ( HIDDEN ( c ) )
2022-10-01 17:29:31 +02:00
scm = SchemeHiddenTitle ;
2022-08-21 11:53:18 +02:00
else
scm = SchemeNormTitle ;
drw_setscheme ( drw , scheme [ scm ] ) ;
if ( remainder > = 0 ) {
if ( remainder = = 0 ) {
tabw - - ;
}
remainder - - ;
}
if ( ! hidetitle ) {
2022-08-27 13:16:53 +02:00
if ( hideicon ) {
drw_text ( drw , x , 0 , tabw , bh , lrpad / 2 , c - > name , 0 ) ;
} else {
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-09-16 20:33:43 +02:00
drw_text ( drw , x , 0 , tabw , bh , lrpad / 2 + ( c - > icon ? c - > icw + iconspacing : 0 ) , c - > name , 0 ) ;
2022-08-27 13:16:53 +02:00
if ( c - > icon ) drw_pic ( drw , x + lrpad / 2 , ( bh - c - > ich ) / 2 , c - > icw , c - > ich , c - > icon ) ;
2022-09-03 17:05:20 +02:00
# else
drw_text ( drw , x , 0 , tabw , bh , lrpad / 2 , c - > name , 0 ) ;
# endif
2022-08-27 13:16:53 +02:00
}
2022-08-21 11:53:18 +02:00
}
2022-09-08 18:07:30 +02:00
// Draw sticky window indicator
2022-08-21 11:53:18 +02:00
if ( c - > issticky & & ! hidesticky ) {
drw_polygon ( drw , x + boxs , c - > isfloating ? boxs * 2 + boxw : boxs , stickyiconbb . x , stickyiconbb . y , boxw , boxw * stickyiconbb . y / stickyiconbb . x , stickyicon , LENGTH ( stickyicon ) , Nonconvex , c - > tags & c - > mon - > tagset [ c - > mon - > seltags ] ) ;
}
2022-09-08 18:07:30 +02:00
// Draw floating window indicator
2022-08-21 11:53:18 +02:00
if ( c - > isfloating & & ! hidefloating ) {
drw_rect ( drw , x + boxs , boxs , boxw , boxw , c - > isfixed , 0 ) ;
}
2022-09-08 18:07:30 +02:00
x + = tabw ;
2022-08-21 11:53:18 +02:00
}
} else {
drw_setscheme ( drw , scheme [ SchemeBar ] ) ;
drw_rect ( drw , x , 0 , w , bh , 1 , 1 ) ;
}
}
2022-09-08 18:07:30 +02:00
2022-08-21 11:53:18 +02:00
m - > bt = n ;
m - > btw = w ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
drw_map ( drw , m - > barwin , 0 , 0 , m - > ww - stw , bh ) ;
# else
2022-08-21 11:53:18 +02:00
drw_map ( drw , m - > barwin , 0 , 0 , m - > ww , bh ) ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
void
drawbars ( void )
{
Monitor * m ;
for ( m = mons ; m ; m = m - > next )
drawbar ( m ) ;
}
void
enternotify ( XEvent * e )
{
Client * c ;
Monitor * m ;
2022-10-07 21:58:30 +02:00
if ( clicktofocus )
return ;
2022-08-21 11:53:18 +02:00
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 ;
2022-10-07 21:58:30 +02:00
focus ( c ) ;
2022-08-21 11:53:18 +02:00
}
void
expose ( XEvent * e )
{
Monitor * m ;
XExposeEvent * ev = & e - > xexpose ;
2022-10-02 15:34:11 +02:00
if ( ev - > count = = 0 & & ( m = wintomon ( ev - > window ) ) ) {
2022-08-21 11:53:18 +02:00
drawbar ( m ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( m = = selmon )
updatesystray ( ) ;
# endif
}
2022-08-21 11:53:18 +02:00
}
void
focus ( Client * c )
{
2022-08-23 21:48:34 +02:00
if ( ! c | | ! ISVISIBLE ( c ) )
for ( c = selmon - > stack ; c & & ( ! ISVISIBLE ( c ) | | HIDDEN ( c ) ) ; c = c - > snext ) ;
if ( selmon - > sel & & selmon - > sel ! = c ) {
2022-08-21 11:53:18 +02:00
unfocus ( selmon - > sel , 0 ) ;
2022-08-23 21:48:34 +02:00
if ( selmon - > hidsel ) {
hidewin ( selmon - > sel ) ;
if ( c )
arrange ( c - > mon ) ;
selmon - > hidsel = 0 ;
}
}
2022-08-21 11:53:18 +02:00
if ( c ) {
if ( c - > mon ! = selmon )
selmon = c - > mon ;
2022-10-01 17:29:31 +02:00
if ( c - > isurgent & & urgentwindows )
2022-08-21 11:53:18 +02:00
seturgent ( c , 0 ) ;
detachstack ( c ) ;
attachstack ( c ) ;
grabbuttons ( c , 1 ) ;
XSetWindowBorder ( dpy , c - > win , scheme [ SchemeSelBorder ] [ ColBorder ] . pixel ) ;
setfocus ( c ) ;
2022-09-03 18:07:51 +02:00
# if USEFADE
2022-08-21 11:53:18 +02:00
opacity ( c , activeopacity ) ;
2022-09-03 18:07:51 +02:00
# endif
2022-08-21 11:53:18 +02:00
} else {
XSetInputFocus ( dpy , root , RevertToPointerRoot , CurrentTime ) ;
XDeleteProperty ( dpy , root , netatom [ NetActiveWindow ] ) ;
}
selmon - > sel = c ;
2022-09-03 19:08:07 +02:00
# if LAYOUT_MONOCLE
2022-08-21 11:53:18 +02:00
if ( selmon - > lt [ selmon - > sellt ] - > arrange = = monocle )
arrangemon ( selmon ) ;
2022-09-03 19:08:07 +02:00
# endif
2022-08-21 11:53:18 +02:00
drawbars ( ) ;
}
2022-10-06 09:52:35 +02:00
/* there are some notitle focus acquiring clients needing extra handling */
2022-08-21 11:53:18 +02:00
void
focusin ( XEvent * e )
{
XFocusChangeEvent * ev = & e - > xfocus ;
if ( selmon - > sel & & ev - > window ! = selmon - > sel - > win )
setfocus ( selmon - > sel ) ;
}
2022-09-11 14:16:14 +02:00
void
focusmaster ( const Arg * arg )
{
Client * master ;
if ( selmon - > nmaster > 1 )
return ;
if ( ! selmon - > sel | | ( selmon - > sel - > isfullscreen & & lockfullscreen ) )
return ;
master = nexttiled ( selmon - > clients ) ;
if ( ! master )
return ;
int i ;
for ( i = 0 ; ! ( selmon - > tagset [ selmon - > seltags ] & 1 < < i ) ; i + + ) ;
i + + ;
if ( selmon - > sel = = master ) {
if ( selmon - > tagmarked [ i ] & & ISVISIBLE ( selmon - > tagmarked [ i ] ) )
focus ( selmon - > tagmarked [ i ] ) ;
} else {
selmon - > tagmarked [ i ] = selmon - > sel ;
focus ( master ) ;
}
}
2022-08-21 11:53:18 +02:00
void
focusmon ( const Arg * arg )
{
Monitor * m ;
2022-10-06 11:39:35 +02:00
selmon - > allowwarp = 1 ; // Allow warp
2022-08-21 11:53:18 +02:00
if ( ! mons - > next )
return ;
if ( ( m = dirtomon ( arg - > i ) ) = = selmon )
return ;
unfocus ( selmon - > sel , 0 ) ;
selmon = m ;
focus ( NULL ) ;
2022-10-06 11:39:35 +02:00
if ( warpcursor )
warp ( selmon - > sel ) ;
selmon - > allowwarp = 0 ;
2022-08-21 11:53:18 +02:00
}
void
focusstackvis ( const Arg * arg )
{
focusstack ( arg - > i , 0 ) ;
}
void
focusstackhid ( const Arg * arg )
{
focusstack ( arg - > i , 1 ) ;
}
2022-08-23 22:04:27 +02:00
void
focusstack ( int inc , int hid )
{
Client * c = NULL , * i ;
2022-09-17 01:40:49 +02:00
if ( ( ! selmon - > sel & & ! hid ) | | ( selmon - > sel & & selmon - > sel - > isfullscreen & & lockfullscreen ) )
return ;
2022-08-25 17:14:06 +02:00
if ( ! selmon - > clients )
2022-08-23 22:04:27 +02:00
return ;
if ( inc > 0 ) {
if ( selmon - > sel )
for ( c = selmon - > sel - > next ;
c & & ( ! ISVISIBLE ( c ) | | ( ! hid & & HIDDEN ( c ) ) ) ;
c = c - > next ) ;
if ( ! c )
for ( c = selmon - > clients ;
c & & ( ! ISVISIBLE ( c ) | | ( ! hid & & HIDDEN ( c ) ) ) ;
c = c - > next ) ;
} else {
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 ;
if ( ! c )
for ( ; i ; i = i - > next )
2022-08-25 17:14:06 +02:00
if ( ISVISIBLE ( i ) & & ! ( ! hid & & HIDDEN ( i ) ) )
2022-08-23 22:04:27 +02:00
c = i ;
}
2022-10-06 11:39:35 +02:00
selmon - > allowwarp = 1 ;
2022-08-23 22:04:27 +02:00
if ( c ) {
focus ( c ) ;
restack ( selmon ) ;
2022-10-06 11:39:35 +02:00
selmon - > allowwarp = 0 ;
2022-08-21 11:53:18 +02:00
if ( HIDDEN ( c ) ) {
showwin ( c ) ;
c - > mon - > hidsel = 1 ;
}
}
}
2022-08-23 21:48:34 +02:00
2022-08-21 11:53:18 +02:00
Atom
getatomprop ( Client * c , Atom prop )
{
int di ;
unsigned long dl ;
unsigned char * p = NULL ;
Atom da , atom = None ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
Atom req = XA_ATOM ;
if ( prop = = xatom [ XembedInfo ] )
req = xatom [ XembedInfo ] ;
if ( XGetWindowProperty ( dpy , c - > win , prop , 0L , sizeof atom , False , req ,
# else
2022-08-21 11:53:18 +02:00
if ( XGetWindowProperty ( dpy , c - > win , prop , 0L , sizeof atom , False , XA_ATOM ,
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
& da , & di , & dl , & dl , & p ) = = Success & & p ) {
atom = * ( Atom * ) p ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( da = = xatom [ XembedInfo ] & & dl = = 2 )
atom = ( ( Atom * ) p ) [ 1 ] ;
# endif
2022-08-21 11:53:18 +02:00
XFree ( p ) ;
}
return atom ;
}
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
static uint32_t prealpha ( uint32_t p ) {
uint8_t a = p > > 24u ;
uint32_t rb = ( a * ( p & 0xFF00FFu ) ) > > 8u ;
uint32_t g = ( a * ( p & 0x00FF00u ) ) > > 8u ;
return ( rb & 0xFF00FFu ) | ( g & 0x00FF00u ) | ( a < < 24u ) ;
}
Picture
geticonprop ( Window win , unsigned int * picw , unsigned int * pich )
{
int format ;
unsigned long n , extra , * p = NULL ;
Atom real ;
if ( XGetWindowProperty ( dpy , win , netatom [ NetWMIcon ] , 0L , LONG_MAX , False , AnyPropertyType ,
& real , & format , & n , & extra , ( unsigned char * * ) & p ) ! = Success )
return None ;
if ( n = = 0 | | format ! = 32 ) { XFree ( p ) ; return None ; }
unsigned long * bstp = NULL ;
uint32_t w , h , sz ;
{
unsigned long * i ; const unsigned long * end = p + n ;
uint32_t bstd = UINT32_MAX , d , m ;
for ( i = p ; i < end - 1 ; i + = sz ) {
if ( ( w = * i + + ) > = 16384 | | ( h = * i + + ) > = 16384 ) { XFree ( p ) ; return None ; }
if ( ( sz = w * h ) > end - i ) break ;
2022-09-16 20:33:43 +02:00
if ( ( m = w > h ? w : h ) > = iconsize & & ( d = m - iconsize ) < bstd ) { bstd = d ; bstp = i ; }
2022-08-21 11:53:18 +02:00
}
if ( ! bstp ) {
for ( i = p ; i < end - 1 ; i + = sz ) {
if ( ( w = * i + + ) > = 16384 | | ( h = * i + + ) > = 16384 ) { XFree ( p ) ; return None ; }
if ( ( sz = w * h ) > end - i ) break ;
2022-09-16 20:33:43 +02:00
if ( ( d = iconsize - ( w > h ? w : h ) ) < bstd ) { bstd = d ; bstp = i ; }
2022-08-21 11:53:18 +02:00
}
}
if ( ! bstp ) { XFree ( p ) ; return None ; }
}
if ( ( w = * ( bstp - 2 ) ) = = 0 | | ( h = * ( bstp - 1 ) ) = = 0 ) { XFree ( p ) ; return None ; }
uint32_t icw , ich ;
if ( w < = h ) {
2022-09-16 20:33:43 +02:00
ich = iconsize ; icw = w * iconsize / h ;
2022-08-21 11:53:18 +02:00
if ( icw = = 0 ) icw = 1 ;
}
else {
2022-09-16 20:33:43 +02:00
icw = iconsize ; ich = h * iconsize / w ;
2022-08-21 11:53:18 +02:00
if ( ich = = 0 ) ich = 1 ;
}
* picw = icw ; * pich = ich ;
uint32_t i , * bstp32 = ( uint32_t * ) bstp ;
for ( sz = w * h , i = 0 ; i < sz ; + + i ) bstp32 [ i ] = prealpha ( bstp [ i ] ) ;
Picture ret = drw_picture_create_resized ( drw , ( char * ) bstp , w , h , icw , ich ) ;
XFree ( p ) ;
return ret ;
}
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
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 ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
unsigned int
getsystraywidth ( )
{
unsigned int w = 0 ;
Client * i ;
if ( showsystray )
for ( i = systray - > icons ; i ; w + = i - > w + systrayspacing , i = i - > next ) ;
return w ? w + systrayspacing : 1 ;
}
void
togglesystray ( )
{
if ( showsystray )
XUnmapWindow ( dpy , systray - > win ) ;
showsystray = ! showsystray ;
updatesystray ( ) ;
updatestatus ( ) ;
}
# endif
2022-08-21 11:53:18 +02:00
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 ;
2022-09-11 00:46:21 +02:00
if ( name . encoding = = XA_STRING ) {
2022-08-21 11:53:18 +02:00
strncpy ( text , ( char * ) name . value , size - 1 ) ;
2022-09-11 00:46:21 +02:00
} else if ( XmbTextPropertyToTextList ( dpy , & name , & list , & n ) > = Success & & n > 0 & & * list ) {
strncpy ( text , * list , size - 1 ) ;
XFreeStringList ( list ) ;
2022-08-21 11:53:18 +02:00
}
text [ size - 1 ] = ' \0 ' ;
XFree ( name . value ) ;
return 1 ;
}
void
grabbuttons ( Client * c , int focused )
{
updatenumlockmask ( ) ;
{
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
unsigned int i , j ;
unsigned int modifiers [ ] = { 0 , LockMask , numlockmask , numlockmask | LockMask } ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
XUngrabButton ( dpy , AnyButton , AnyModifier , c - > win ) ;
2022-08-25 19:51:43 +02:00
if ( ! focused )
XGrabButton ( dpy , AnyButton , AnyModifier , c - > win , False ,
BUTTONMASK , GrabModeSync , GrabModeSync , None , None ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
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 ) ;
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
}
void
grabkeys ( void )
{
updatenumlockmask ( ) ;
{
unsigned int i , j ;
unsigned int modifiers [ ] = { 0 , LockMask , numlockmask , numlockmask | LockMask } ;
KeyCode code ;
KeyCode chain ;
XUngrabKey ( dpy , AnyKey , AnyModifier , root ) ;
for ( i = 0 ; i < LENGTH ( keys ) ; i + + )
if ( ( code = XKeysymToKeycode ( dpy , keys [ i ] . keysym ) ) ) {
if ( keys [ i ] . chain ! = - 1 & &
( ( chain = XKeysymToKeycode ( dpy , keys [ i ] . chain ) ) ) )
code = chain ;
for ( j = 0 ; j < LENGTH ( modifiers ) ; j + + )
XGrabKey ( dpy , code , keys [ i ] . mod | modifiers [ j ] , root ,
True , GrabModeAsync , GrabModeAsync ) ;
}
}
}
2022-08-23 21:48:34 +02: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 ) ;
}
2022-08-26 11:41:11 +02:00
# if USEIPC
int
handlexevent ( struct epoll_event * ev )
{
if ( ev - > events & EPOLLIN ) {
XEvent ev ;
while ( running & & XPending ( dpy ) ) {
XNextEvent ( dpy , & ev ) ;
if ( handler [ ev . type ] ) {
handler [ ev . type ] ( & ev ) ; /* call handler */
ipc_send_events ( mons , & lastselmon , selmon ) ;
}
}
} else if ( ev - > events & EPOLLHUP ) {
return - 1 ;
}
return 0 ;
}
# endif
2022-08-21 11:53:18 +02:00
void
incnmaster ( const Arg * arg )
{
if ( i3nmaster ) {
selmon - > nmaster = selmon - > pertag - > nmasters [ selmon - > pertag - > curtag ] = ! selmon - > nmaster ;
} else {
selmon - > nmaster = selmon - > pertag - > nmasters [ selmon - > pertag - > curtag ] = MAX ( selmon - > nmaster + arg - > i , 0 ) ;
}
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 , j ;
KeySym keysym ;
XKeyEvent * ev ;
int current = 0 ;
unsigned int modifiers [ ] = { 0 , LockMask , numlockmask , numlockmask | LockMask } ;
ev = & e - > xkey ;
keysym = XKeycodeToKeysym ( dpy , ( KeyCode ) ev - > keycode , 0 ) ;
for ( i = 0 ; i < LENGTH ( keys ) ; i + + ) {
if ( keysym = = keys [ i ] . keysym & & keys [ i ] . chain = = - 1
& & CLEANMASK ( keys [ i ] . mod ) = = CLEANMASK ( ev - > state )
& & keys [ i ] . func )
keys [ i ] . func ( & ( keys [ i ] . arg ) ) ;
else if ( keysym = = keys [ i ] . chain & & keychain = = - 1
& & CLEANMASK ( keys [ i ] . mod ) = = CLEANMASK ( ev - > state )
& & keys [ i ] . func ) {
current = 1 ;
keychain = keysym ;
for ( j = 0 ; j < LENGTH ( modifiers ) ; j + + )
XGrabKey ( dpy , AnyKey , 0 | modifiers [ j ] , root ,
True , GrabModeAsync , GrabModeAsync ) ;
} else if ( ! current & & keysym = = keys [ i ] . keysym
& & keychain ! = - 1
& & keys [ i ] . chain = = keychain
& & keys [ i ] . func )
keys [ i ] . func ( & ( keys [ i ] . arg ) ) ;
}
if ( ! current ) {
keychain = - 1 ;
grabkeys ( ) ;
}
}
int
2022-10-14 16:14:45 +02:00
getsignal ( void )
2022-08-21 11:53:18 +02:00
{
2022-10-14 16:14:45 +02:00
char signal [ 256 ] ;
char indicator [ 9 ] = " #cmd: " ;
2022-08-21 11:53:18 +02:00
char str_signum [ 16 ] ;
2022-10-14 16:14:45 +02:00
char * prevstatus = rawstext ;
2022-08-21 11:53:18 +02:00
int i , v , signum ;
2022-10-14 16:14:45 +02:00
size_t len_signal , len_indicator = strlen ( indicator ) ;
2022-08-21 11:53:18 +02:00
2022-10-14 16:14:45 +02:00
/* Get root name property */
if ( gettextprop ( root , XA_WM_NAME , signal , sizeof ( signal ) ) ) {
len_signal = strlen ( signal ) ;
2022-08-21 11:53:18 +02:00
2022-10-14 16:14:45 +02:00
/* Check if this is indeed a fake signal */
if ( len_indicator > len_signal ? 0 : strncmp ( indicator , signal , len_indicator ) = = 0 ) {
memcpy ( str_signum , & signal [ len_indicator ] , len_signal - len_indicator ) ;
str_signum [ len_signal - len_indicator ] = ' \0 ' ;
2022-08-21 11:53:18 +02:00
2022-10-14 16:14:45 +02:00
/* Convert string value into managable integer */
2022-08-21 11:53:18 +02:00
for ( i = signum = 0 ; i < strlen ( str_signum ) ; i + + ) {
v = str_signum [ i ] - ' 0 ' ;
if ( v > = 0 & & v < = 9 ) {
signum = signum * 10 + v ;
}
}
2022-10-14 16:14:45 +02:00
/* Check if a signal was found, and if so handle it */
2022-08-21 11:53:18 +02:00
if ( signum )
for ( i = 0 ; i < LENGTH ( signals ) ; i + + )
if ( signum = = signals [ i ] . signum & & signals [ i ] . func )
signals [ i ] . func ( & ( signals [ i ] . arg ) ) ;
2022-10-14 16:14:45 +02:00
/* Set status bar to previous status */
strcpy ( prevstatus , stext ) ;
/* A fake signal was sent */
2022-08-21 11:53:18 +02:00
return 1 ;
}
}
// No fake signal was sent, so proceed with update
return 0 ;
}
void
setgaps ( int oh , int ov , int ih , int iv )
{
if ( oh < 0 ) oh = 0 ;
if ( ov < 0 ) ov = 0 ;
if ( ih < 0 ) ih = 0 ;
if ( iv < 0 ) iv = 0 ;
selmon - > gappoh = oh ;
selmon - > gappov = ov ;
selmon - > gappih = ih ;
selmon - > gappiv = iv ;
2022-10-04 19:42:53 +02:00
2022-08-21 11:53:18 +02:00
arrange ( selmon ) ;
}
void
getgaps ( Monitor * m , int * oh , int * ov , int * ih , int * iv , unsigned int * nc )
{
unsigned int n , oe , ie ;
2022-10-04 19:58:03 +02:00
oe = ie = enablegaps ;
2022-08-21 11:53:18 +02:00
Client * c ;
for ( n = 0 , c = nexttiled ( m - > clients ) ; c ; c = nexttiled ( c - > next ) , n + + ) ;
if ( smartgaps & & n = = 1 ) {
oe = smartgapsize ; // outer gaps disabled when only one client
}
* oh = m - > gappoh * oe ; // outer horizontal gap
* ov = m - > gappov * oe ; // outer vertical gap
* ih = m - > gappih * ie ; // inner horizontal gap
* iv = m - > gappiv * ie ; // inner vertical gap
* nc = n ; // number of clients
}
2022-08-23 21:48:34 +02:00
void
show ( const Arg * arg )
{
if ( selmon - > hidsel )
selmon - > hidsel = 0 ;
showwin ( selmon - > sel ) ;
}
2022-10-05 19:05:16 +02:00
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
hideall ( const Arg * arg )
{
Client * c = NULL ;
for ( c = selmon - > clients ; c ; c = c - > next ) {
hidewin ( c ) ;
hidewin ( selmon - > sel ) ;
}
restack ( selmon ) ;
}
2022-08-23 21:48:34 +02:00
void
showwin ( Client * c )
{
if ( ! c | | ! HIDDEN ( c ) )
return ;
XMapWindow ( dpy , c - > win ) ;
setclientstate ( c , NormalState ) ;
arrange ( c - > mon ) ;
}
void
showhide ( Client * c )
{
if ( ! c )
return ;
if ( ISVISIBLE ( c ) ) {
/* show clients top down */
XMoveWindow ( dpy , c - > win , c - > x , c - > y ) ;
2022-10-01 15:37:35 +02:00
if ( c - > needresize & & autoresize ) {
2022-08-23 21:48:34 +02:00
c - > needresize = 0 ;
XMoveResizeWindow ( dpy , c - > win , c - > x , c - > y , c - > w , c - > h ) ;
2022-10-01 15:37:35 +02:00
} else if ( autoresize ) {
2022-08-23 21:48:34 +02:00
XMoveWindow ( dpy , c - > win , c - > x , c - > y ) ;
}
2022-10-01 15:37:35 +02:00
2022-08-23 21:48:34 +02:00
if ( ( ! c - > mon - > lt [ c - > mon - > sellt ] - > arrange | | c - > isfloating ) & & ! c - > isfullscreen )
resize ( c , c - > x , c - > y , c - > w , c - > h , 0 ) ;
showhide ( c - > snext ) ;
} else {
/* hide clients bottom up */
showhide ( c - > snext ) ;
XMoveWindow ( dpy , c - > win , WIDTH ( c ) * - 2 , c - > y ) ;
}
}
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-23 21:48:34 +02:00
void
togglewin ( const Arg * arg )
{
Client * c = ( Client * ) arg - > v ;
2022-10-05 19:25:46 +02:00
if ( ! c )
return ;
2022-08-23 21:48:34 +02:00
if ( c = = selmon - > sel ) {
hidewin ( c ) ;
focus ( NULL ) ;
2022-08-23 22:29:29 +02:00
arrange ( selmon ) ;
2022-08-23 21:48:34 +02:00
} else {
if ( HIDDEN ( c ) )
showwin ( c ) ;
focus ( c ) ;
restack ( selmon ) ;
}
}
2022-09-03 16:46:19 +02:00
# endif
2022-08-23 21:48:34 +02:00
2022-08-21 11:53:18 +02:00
void
togglegaps ( const Arg * arg )
{
2022-10-04 19:58:03 +02:00
enablegaps = ! enablegaps ;
2022-08-21 11:53:18 +02:00
arrange ( selmon ) ;
}
void
defaultgaps ( const Arg * arg )
{
setgaps ( gappoh , gappov , gappih , gappiv ) ;
}
void
incrgaps ( const Arg * arg )
{
setgaps (
selmon - > gappoh + arg - > i ,
selmon - > gappov + arg - > i ,
selmon - > gappih + arg - > i ,
selmon - > gappiv + arg - > i
) ;
}
void
incrigaps ( const Arg * arg )
{
setgaps (
selmon - > gappoh ,
selmon - > gappov ,
selmon - > gappih + arg - > i ,
selmon - > gappiv + arg - > i
) ;
}
void
incrogaps ( const Arg * arg )
{
setgaps (
selmon - > gappoh + arg - > i ,
selmon - > gappov + arg - > i ,
selmon - > gappih ,
selmon - > gappiv
) ;
}
void
killclient ( const Arg * arg )
{
if ( ! selmon - > sel | | selmon - > sel - > ispermanent )
return ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( ! sendevent ( selmon - > sel - > win , wmatom [ WMDelete ] , NoEventMask , wmatom [ WMDelete ] , CurrentTime , 0 , 0 , 0 ) ) {
# else
2022-08-21 11:53:18 +02:00
if ( ! sendevent ( selmon - > sel , wmatom [ WMDelete ] ) ) {
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
XGrabServer ( dpy ) ;
XSetErrorHandler ( xerrordummy ) ;
XSetCloseDownMode ( dpy , DestroyAll ) ;
XKillClient ( dpy , selmon - > sel - > win ) ;
XSync ( dpy , False ) ;
XSetErrorHandler ( xerror ) ;
XUngrabServer ( dpy ) ;
}
}
2022-08-26 19:12:10 +02:00
void
killunsel ( const Arg * arg )
{
Client * i = NULL ;
if ( ! selmon - > sel )
return ;
for ( i = selmon - > clients ; i ; i = i - > next ) {
if ( ISVISIBLE ( i ) & & i ! = selmon - > sel ) {
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
2022-10-03 13:30:51 +02:00
if ( ! sendevent ( i - > win , wmatom [ WMDelete ] , NoEventMask , wmatom [ WMDelete ] , CurrentTime , 0 , 0 , 0 ) ) {
2022-10-02 15:34:11 +02:00
# else
if ( ! sendevent ( selmon - > sel , wmatom [ WMDelete ] ) ) {
# endif
2022-08-26 19:12:10 +02:00
XGrabServer ( dpy ) ;
XSetErrorHandler ( xerrordummy ) ;
XSetCloseDownMode ( dpy , DestroyAll ) ;
XKillClient ( dpy , i - > win ) ;
XSync ( dpy , False ) ;
XSetErrorHandler ( xerror ) ;
XUngrabServer ( dpy ) ;
}
}
}
}
2022-08-21 11:53:18 +02:00
void
manage ( Window w , XWindowAttributes * wa )
{
Client * c , * t = NULL , * term = NULL ;
Window trans = None ;
XWindowChanges wc ;
2022-08-21 16:05:53 +02:00
int format ;
unsigned int * ptags ;
unsigned long n , extra ;
Atom atom ;
2022-08-21 11:53:18 +02:00
c = ecalloc ( 1 , sizeof ( Client ) ) ;
c - > win = w ;
c - > pid = winpid ( w ) ;
if ( getatomprop ( c , netatom [ NetWMWindowType ] ) = = netatom [ NetWMWindowTypeDesktop ] ) {
XMapWindow ( dpy , c - > win ) ;
XLowerWindow ( dpy , c - > win ) ;
free ( c ) ;
return ;
}
/* 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 ;
c - > cfact = 1.0 ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
updateicon ( c ) ;
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
updatetitle ( c ) ;
if ( XGetTransientForHint ( dpy , w , & trans ) & & ( t = wintoclient ( trans ) ) ) {
c - > mon = t - > mon ;
c - > tags = t - > tags ;
} else {
c - > mon = selmon ;
applyrules ( c ) ;
term = termforwin ( c ) ;
2022-08-21 16:05:53 +02:00
if ( XGetWindowProperty ( dpy , c - > win , dwmatom [ DWMTags ] , 0L , 1L , False , XA_CARDINAL ,
& atom , & format , & n , & extra , ( unsigned char * * ) & ptags ) = = Success & & n = = 1 & & * ptags ! = 0 ) {
c - > tags = * ptags ;
XFree ( ptags ) ;
}
2022-08-21 11:53:18 +02:00
}
2022-08-21 16:05:53 +02:00
settagsatom ( c - > win , c - > tags ) ;
2022-08-21 11:53:18 +02:00
if ( unmanaged ) {
XMapWindow ( dpy , c - > win ) ;
if ( unmanaged = = 1 )
XRaiseWindow ( dpy , c - > win ) ;
else if ( unmanaged = = 2 )
XLowerWindow ( dpy , c - > win ) ;
free ( c ) ;
unmanaged = 0 ;
return ;
}
2022-09-11 00:50:07 +02: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 ) ;
2022-08-21 11:53:18 +02:00
c - > x = MAX ( c - > x , c - > mon - > mx ) ;
2022-09-11 00:48:45 +02:00
c - > y = MAX ( c - > y , c - > mon - > wy ) ;
2022-08-21 11:53:18 +02:00
c - > bw = borderpx ;
wc . border_width = c - > bw ;
XConfigureWindow ( dpy , w , CWBorderWidth , & wc ) ;
XSetWindowBorder ( dpy , w , scheme [ SchemeNormBorder ] [ ColBorder ] . pixel ) ;
configure ( c ) ; /* propagates border_width, if size doesn't change */
updatewindowtype ( c ) ;
2022-09-11 00:17:46 +02:00
updatesizehints ( c ) ;
2022-08-21 11:53:18 +02:00
updatewmhints ( c ) ;
{
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 ) ;
if ( savefloat )
{
c - > sfx = c - > x ;
c - > sfy = c - > y ;
c - > sfw = c - > w ;
c - > sfh = c - > h ;
}
if ( centerfloating )
{
c - > x = c - > mon - > mx + ( c - > mon - > mw - WIDTH ( c ) ) / 2 ;
c - > y = c - > mon - > my + ( c - > mon - > mh - HEIGHT ( c ) ) / 2 ;
}
updatemotifhints ( c ) ;
XSelectInput ( dpy , w , EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask ) ;
grabbuttons ( c , 0 ) ;
if ( ! c - > isfloating )
c - > isfloating = c - > oldstate = t | | c - > isfixed ;
if ( c - > isfloating )
XRaiseWindow ( dpy , c - > win ) ;
switch ( attachdirection ) {
case 1 :
attachabove ( c ) ;
break ;
case 2 :
attachaside ( c ) ;
break ;
case 3 :
attachbelow ( c ) ;
break ;
case 4 :
attachbottom ( c ) ;
break ;
case 5 :
attachtop ( c ) ;
break ;
default :
attach ( c ) ;
}
attachstack ( c ) ;
setclienttagprop ( c ) ;
XChangeProperty ( dpy , root , netatom [ NetClientList ] , XA_WINDOW , 32 , PropModeAppend ,
( unsigned char * ) & ( c - > win ) , 1 ) ;
XChangeProperty ( dpy , root , netatom [ NetClientListStacking ] , XA_WINDOW , 32 , PropModePrepend ,
( unsigned char * ) & ( c - > win ) , 1 ) ;
XMoveResizeWindow ( dpy , c - > win , c - > x + 2 * tw , c - > y , c - > w , c - > h ) ; /* some windows require this */
2022-08-23 21:48:34 +02:00
//setclientstate(c, NormalState);
2022-08-21 11:53:18 +02:00
if ( ! HIDDEN ( c ) )
setclientstate ( c , NormalState ) ;
if ( c - > mon = = selmon )
unfocus ( selmon - > sel , 0 ) ;
c - > mon - > sel = c ;
if ( ! HIDDEN ( c ) )
XMapWindow ( dpy , c - > win ) ;
if ( term )
swallow ( term , c ) ;
2022-10-08 01:16:37 +02:00
arrange ( c - > mon ) ;
2022-08-28 21:54:47 +02:00
if ( focusspawn & & ! warpcursor ) {
focus ( c ) ; // Auto focus next spawned window
} else {
focus ( NULL ) ; // No need if warpcursor is enabled because warpcursor is going to warp and focus the window anyway
}
2022-08-21 11:53:18 +02:00
}
void
managealtbar ( Window win , XWindowAttributes * wa )
{
Monitor * m ;
if ( ! ( m = recttomon ( wa - > x , wa - > y , wa - > width , wa - > height ) ) )
return ;
m - > barwin = win ;
m - > by = wa - > y ;
bh = m - > bh = wa - > height ;
updatebarpos ( m ) ;
arrange ( m ) ;
XSelectInput ( dpy , win , EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask ) ;
XMoveResizeWindow ( dpy , win , wa - > x , wa - > y , wa - > width , wa - > height ) ;
XMapWindow ( dpy , win ) ;
XChangeProperty ( dpy , root , netatom [ NetClientList ] , XA_WINDOW , 32 , PropModeAppend ,
( unsigned char * ) & win , 1 ) ;
}
void
managetray ( Window win , XWindowAttributes * wa )
{
Monitor * m ;
if ( ! ( m = recttomon ( wa - > x , wa - > y , wa - > width , wa - > height ) ) )
return ;
m - > traywin = win ;
m - > tx = wa - > x ;
m - > tw = wa - > width ;
updatebarpos ( m ) ;
arrange ( m ) ;
XSelectInput ( dpy , win , EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask ) ;
XMoveResizeWindow ( dpy , win , wa - > x , wa - > y , wa - > width , wa - > height ) ;
XMapWindow ( dpy , win ) ;
XChangeProperty ( dpy , root , netatom [ NetClientList ] , XA_WINDOW , 32 , PropModeAppend ,
( unsigned char * ) & win , 1 ) ;
}
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 ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
Client * i ;
if ( ( i = wintosystrayicon ( ev - > window ) ) ) {
sendevent ( i - > win , netatom [ Xembed ] , StructureNotifyMask , CurrentTime , XEMBED_WINDOW_ACTIVATE , 0 , systray - > win , XEMBED_EMBEDDED_VERSION ) ;
resizebarwin ( selmon ) ;
updatesystray ( ) ;
}
# endif
2022-09-11 00:46:21 +02:00
if ( ! XGetWindowAttributes ( dpy , ev - > window , & wa ) | | wa . override_redirect )
2022-08-21 11:53:18 +02:00
return ;
if ( ! wa . depth )
return ;
if ( wmclasscontains ( ev - > window , altbarclass , " " ) )
managealtbar ( ev - > window , & wa ) ;
else if ( ! wintoclient ( ev - > window ) )
manage ( ev - > window , & wa ) ;
}
2022-10-03 21:57:15 +02:00
void
motionnotify ( XEvent * e )
{
static Monitor * mon = NULL ;
Monitor * m ;
m = 0 ;
Client * sel ;
XMotionEvent * ev = & e - > xmotion ;
Client * c ;
unsigned int i , x , occ = 0 , lts = 0 ;
2022-08-21 11:53:18 +02:00
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-10-03 21:57:15 +02:00
if ( ev - > window = = selmon - > barwin ) {
i = x = 0 ;
// for leftlayout, we need to add the size of the layout indicator
if ( layoutposition ) {
lts = TEXTW ( selmon - > ltsymbol ) ;
}
for ( c = selmon - > clients ; c ; c = c - > next )
occ | = c - > tags = = 255 ? 0 : c - > tags ;
do {
if ( ! ( occ & 1 < < i | | selmon - > seltags & 1 < < i ) & & hideemptytags )
continue ;
x + = TEXTW ( tags [ i ] ) + lts ;
} while ( ev - > x > = x & & + + i < LENGTH ( tags ) ) ;
if ( mousepreview & & ! hidetags ) {
if ( i < LENGTH ( tags ) ) {
if ( selmon - > previewshow ! = ( i + 1 )
& & ! ( selmon - > seltags & 1 < < i ) ) {
2022-08-21 11:53:18 +02:00
selmon - > previewshow = i + 1 ;
showtagpreview ( i ) ;
2022-10-03 21:57:15 +02:00
} else if ( selmon - > seltags & 1 < < i ) {
2022-08-21 11:53:18 +02:00
selmon - > previewshow = 0 ;
2022-10-03 21:57:15 +02:00
XUnmapWindow ( dpy , selmon - > tagwin ) ;
2022-08-21 11:53:18 +02:00
}
} else if ( selmon - > previewshow ) {
selmon - > previewshow = 0 ;
XUnmapWindow ( dpy , selmon - > tagwin ) ;
}
2022-10-03 21:57:15 +02:00
} else if ( ev - > window = = selmon - > tagwin ) {
selmon - > previewshow = 0 ;
XUnmapWindow ( dpy , selmon - > tagwin ) ;
2022-08-21 11:53:18 +02:00
} else if ( selmon - > previewshow ) {
2022-10-03 21:57:15 +02:00
selmon - > previewshow = 0 ;
2022-08-21 11:53:18 +02:00
XUnmapWindow ( dpy , selmon - > tagwin ) ;
2022-10-03 21:57:15 +02:00
}
} // mousepreview && !hidetags
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
if ( ev - > window ! = root )
return ;
if ( ( m = recttomon ( ev - > x_root , ev - > y_root , 1 , 1 ) ) ! = mon & & mon ) {
2022-10-03 21:57:15 +02:00
sel = selmon - > sel ;
2022-08-21 11:53:18 +02:00
selmon = m ;
2022-10-03 21:57:15 +02:00
unfocus ( sel , 1 ) ;
2022-08-21 11:53:18 +02:00
focus ( NULL ) ;
}
mon = m ;
}
2022-09-17 18:20:59 +02:00
void
toggleview ( const Arg * arg )
{
unsigned int newtagset = selmon - > tagset [ selmon - > seltags ] ^ ( arg - > ui & TAGMASK ) ;
if ( newtagset ) {
selmon - > tagset [ selmon - > seltags ] = newtagset ;
focus ( NULL ) ;
arrange ( selmon ) ;
}
}
2022-08-21 11:53:18 +02:00
void
moveresize ( const Arg * arg ) {
/* only floating windows can be moved */
Client * c ;
c = selmon - > sel ;
int x , y , w , h , nx , ny , nw , nh , ox , oy , ow , oh ;
char xAbs , yAbs , wAbs , hAbs ;
int msx , msy , dx , dy , nmx , nmy ;
unsigned int dui ;
Window dummy ;
if ( ! c | | ! arg )
return ;
if ( selmon - > lt [ selmon - > sellt ] - > arrange & & ! c - > isfloating )
return ;
if ( sscanf ( ( char * ) arg - > v , " %d%c %d%c %d%c %d%c " , & x , & xAbs , & y , & yAbs , & w , & wAbs , & h , & hAbs ) ! = 8 )
return ;
/* compute new window position; prevent window from be positioned outside the current monitor */
nw = c - > w + w ;
if ( wAbs = = ' W ' )
nw = w < selmon - > mw - 2 * c - > bw ? w : selmon - > mw - 2 * c - > bw ;
nh = c - > h + h ;
if ( hAbs = = ' H ' )
nh = h < selmon - > mh - 2 * c - > bw ? h : selmon - > mh - 2 * c - > bw ;
nx = c - > x + x ;
if ( xAbs = = ' X ' ) {
if ( x < selmon - > mx )
nx = selmon - > mx ;
else if ( x > selmon - > mx + selmon - > mw )
nx = selmon - > mx + selmon - > mw - nw - 2 * c - > bw ;
else
nx = x ;
}
ny = c - > y + y ;
if ( yAbs = = ' Y ' ) {
if ( y < selmon - > my )
ny = selmon - > my ;
else if ( y > selmon - > my + selmon - > mh )
ny = selmon - > my + selmon - > mh - nh - 2 * c - > bw ;
else
ny = y ;
}
ox = c - > x ;
oy = c - > y ;
ow = c - > w ;
oh = c - > h ;
XRaiseWindow ( dpy , c - > win ) ;
Bool xqp = XQueryPointer ( dpy , root , & dummy , & dummy , & msx , & msy , & dx , & dy , & dui ) ;
resize ( c , nx , ny , nw , nh , True ) ;
/* move cursor along with the window to avoid problems caused by the sloppy focus */
if ( xqp & & ox < = msx & & ( ox + ow ) > = msx & & oy < = msy & & ( oy + oh ) > = msy )
{
nmx = c - > x - ox + c - > w - ow ;
nmy = c - > y - oy + c - > h - oh ;
/* make sure the cursor stays inside the window */
if ( ( msx + nmx ) > c - > x & & ( msy + nmy ) > c - > y )
XWarpPointer ( dpy , None , None , 0 , 0 , 0 , 0 , nmx , nmy ) ;
}
}
void
moveresizeedge ( const Arg * arg ) {
/* move or resize floating window to edge of screen */
Client * c ;
c = selmon - > sel ;
char e ;
int nx , ny , nw , nh , ox , oy , ow , oh , bp ;
int msx , msy , dx , dy , nmx , nmy ;
int starty ;
unsigned int dui ;
Window dummy ;
nx = c - > x ;
ny = c - > y ;
nw = c - > w ;
nh = c - > h ;
starty = selmon - > showbar & & barposition ? bh : 0 ;
bp = selmon - > showbar & & ! barposition ? bh : 0 ;
if ( ! c | | ! arg )
return ;
if ( selmon - > lt [ selmon - > sellt ] - > arrange & & ! c - > isfloating )
return ;
if ( sscanf ( ( char * ) arg - > v , " %c " , & e ) ! = 1 )
return ;
if ( e = = ' t ' )
ny = starty ;
if ( e = = ' b ' )
ny = c - > h > selmon - > mh - 2 * c - > bw ? c - > h - bp : selmon - > mh - c - > h - 2 * c - > bw - bp ;
if ( e = = ' l ' )
nx = selmon - > mx ;
if ( e = = ' r ' )
nx = c - > w > selmon - > mw - 2 * c - > bw ? selmon - > mx + c - > w : selmon - > mx + selmon - > mw - c - > w - 2 * c - > bw ;
if ( e = = ' T ' ) {
/* if you click to resize again, it will return to old size/position */
if ( c - > h + starty = = c - > oldh + c - > oldy ) {
nh = c - > oldh ;
ny = c - > oldy ;
} else {
nh = c - > h + c - > y - starty ;
ny = starty ;
}
}
if ( e = = ' B ' )
nh = c - > h + c - > y + 2 * c - > bw + bp = = selmon - > mh ? c - > oldh : selmon - > mh - c - > y - 2 * c - > bw - bp ;
if ( e = = ' L ' ) {
if ( selmon - > mx + c - > w = = c - > oldw + c - > oldx ) {
nw = c - > oldw ;
nx = c - > oldx ;
} else {
nw = c - > w + c - > x - selmon - > mx ;
nx = selmon - > mx ;
}
}
if ( e = = ' R ' )
nw = c - > w + c - > x + 2 * c - > bw = = selmon - > mx + selmon - > mw ? c - > oldw : selmon - > mx + selmon - > mw - c - > x - 2 * c - > bw ;
ox = c - > x ;
oy = c - > y ;
ow = c - > w ;
oh = c - > h ;
XRaiseWindow ( dpy , c - > win ) ;
Bool xqp = XQueryPointer ( dpy , root , & dummy , & dummy , & msx , & msy , & dx , & dy , & dui ) ;
resize ( c , nx , ny , nw , nh , True ) ;
/* move cursor along with the window to avoid problems caused by the sloppy focus */
if ( xqp & & ox < = msx & & ( ox + ow ) > = msx & & oy < = msy & & ( oy + oh ) > = msy ) {
nmx = c - > x - ox + c - > w - ow ;
nmy = c - > y - oy + c - > h - oh ;
/* make sure the cursor stays inside the window */
if ( ( msx + nmx ) > c - > x & & ( msy + nmy ) > c - > y )
XWarpPointer ( dpy , None , None , 0 , 0 , 0 , 0 , nmx , nmy ) ;
}
}
Client *
nexttagged ( Client * c ) {
Client * walked = c - > mon - > clients ;
for ( ;
walked & & ( walked - > isfloating | | ! ISVISIBLEONTAG ( walked , c - > tags ) ) ;
walked = walked - > next
) ;
return walked ;
}
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
void
moveorplace ( const Arg * arg ) {
if ( ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | ( selmon - > sel & & selmon - > sel - > isfloating ) ) )
movemouse ( arg ) ;
else
placemouse ( arg ) ;
}
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 ( ! c - > isfloating & & selmon - > lt [ selmon - > sellt ] - > arrange
& & ( abs ( nx - c - > x ) > snap | | abs ( ny - c - > y ) > snap ) )
togglefloating ( NULL ) ;
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | c - > isfloating )
resize ( c , nx , ny , c - > w , c - > h , 1 ) ;
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 ) ;
}
}
void
resizemouse ( const Arg * arg )
{
int ocx , ocy , nw , nh ;
Client * c ;
Monitor * m ;
XEvent ev ;
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 ;
if ( XGrabPointer ( dpy , root , False , MOUSEMASK , GrabModeAsync , GrabModeAsync ,
None , cursor [ CurResize ] - > cursor , CurrentTime ) ! = GrabSuccess )
return ;
2022-10-11 14:01:22 +02:00
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w + c - > bw - 1 , c - > h + c - > bw - 1 ) ;
2022-08-21 11:53:18 +02: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 ;
nw = MAX ( ev . xmotion . x - ocx - 2 * c - > bw + 1 , 1 ) ;
nh = MAX ( ev . xmotion . y - ocy - 2 * c - > bw + 1 , 1 ) ;
2022-10-11 14:01:22 +02:00
if ( c - > mon - > wx + nw > = selmon - > wx & & c - > mon - > wx + nw < = selmon - > wx + selmon - > ww
2022-08-21 11:53:18 +02:00
& & 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 ) ;
}
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | c - > isfloating )
resize ( c , c - > x , c - > y , nw , nh , 1 ) ;
break ;
}
} while ( ev . type ! = ButtonRelease ) ;
2022-10-11 14:01:22 +02:00
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w + c - > bw - 1 , c - > h + c - > bw - 1 ) ;
2022-08-21 11:53:18 +02: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 ) ;
}
}
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
Client *
nexttiled ( Client * c )
{
for ( ; c & & ( c - > isfloating | | ! ISVISIBLE ( c ) | | HIDDEN ( c ) ) ; c = c - > next ) ;
return c ;
}
2022-10-11 17:11:31 +02:00
unsigned int
nexttag ( void )
{
unsigned int seltag = selmon - > tagset [ selmon - > seltags ] ;
return seltag = = ( 1 < < ( LENGTH ( tags ) - 1 ) ) ? 1 : seltag < < 1 ;
}
2022-10-14 15:56:42 +02:00
unsigned int
nexttag_skip_vacant ( void )
{
unsigned int seltag = selmon - > tagset [ selmon - > seltags ] ;
unsigned int usedtags = 0 ;
Client * c = selmon - > clients ;
if ( ! c )
return seltag ;
/* skip vacant tags */
do {
usedtags | = c - > tags ;
c = c - > next ;
} while ( c ) ;
do {
seltag = seltag = = ( 1 < < ( LENGTH ( tags ) - 1 ) ) ? 1 : seltag < < 1 ;
} while ( ! ( seltag & usedtags ) ) ;
return seltag ;
}
2022-10-11 17:11:31 +02:00
unsigned int
prevtag ( void )
{
unsigned int seltag = selmon - > tagset [ selmon - > seltags ] ;
return seltag = = 1 ? ( 1 < < ( LENGTH ( tags ) - 1 ) ) : seltag > > 1 ;
}
2022-10-14 15:56:42 +02:00
unsigned int
prevtag_skip_vacant ( void )
{
unsigned int seltag = selmon - > tagset [ selmon - > seltags ] ;
unsigned int usedtags = 0 ;
Client * c = selmon - > clients ;
if ( ! c )
return seltag ;
/* skip vacant tags */
do {
usedtags | = c - > tags ;
c = c - > next ;
} while ( c ) ;
do {
seltag = seltag = = 1 ? ( 1 < < ( LENGTH ( tags ) - 1 ) ) : seltag > > 1 ;
} while ( ! ( seltag & usedtags ) ) ;
return seltag ;
}
2022-10-11 17:11:31 +02:00
2022-09-03 18:07:51 +02:00
# if USEFADE
2022-08-21 11:53:18 +02:00
void
opacity ( Client * c , double opacity )
{
if ( bUseOpacity & & opacity > 0 & & opacity < 1 & & fadeinactive ) {
unsigned long real_opacity [ ] = { opacity * 0xffffffff } ;
XChangeProperty ( dpy , c - > win , netatom [ NetWMWindowsOpacity ] , XA_CARDINAL ,
32 , PropModeReplace , ( unsigned char * ) real_opacity ,
1 ) ;
} else
XDeleteProperty ( dpy , c - > win , netatom [ NetWMWindowsOpacity ] ) ;
}
2022-09-03 18:07:51 +02:00
# endif
2022-08-21 11:53:18 +02:00
void
placemouse ( const Arg * arg )
{
int x , y , px , py , ocx , ocy , nx = - 9999 , ny = - 9999 , freemove = 0 ;
Client * c , * r = NULL , * at , * prevr ;
Monitor * m ;
XEvent ev ;
XWindowAttributes wa ;
Time lasttime = 0 ;
int attachmode , prevattachmode ;
attachmode = prevattachmode = - 1 ;
if ( ! ( c = selmon - > sel ) | | ! c - > mon - > lt [ c - > mon - > sellt ] - > arrange ) /* no support for placemouse when floating layout is used */
return ;
if ( c - > isfullscreen ) /* no support placing fullscreen windows by mouse */
return ;
restack ( selmon ) ;
prevr = c ;
if ( XGrabPointer ( dpy , root , False , MOUSEMASK , GrabModeAsync , GrabModeAsync ,
None , cursor [ CurMove ] - > cursor , CurrentTime ) ! = GrabSuccess )
return ;
c - > isfloating = 0 ;
c - > beingmoved = 1 ;
XGetWindowAttributes ( dpy , c - > win , & wa ) ;
ocx = wa . x ;
ocy = wa . y ;
if ( arg - > i = = 2 ) // warp cursor to client center
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , WIDTH ( c ) / 2 , HEIGHT ( c ) / 2 ) ;
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 ( ! freemove & & ( abs ( nx - ocx ) > snap | | abs ( ny - ocy ) > snap ) )
freemove = 1 ;
if ( freemove )
XMoveWindow ( dpy , c - > win , nx , ny ) ;
if ( ( m = recttomon ( ev . xmotion . x , ev . xmotion . y , 1 , 1 ) ) & & m ! = selmon )
selmon = m ;
if ( arg - > i = = 1 ) { // tiled position is relative to the client window center point
px = nx + wa . width / 2 ;
py = ny + wa . height / 2 ;
} else { // tiled position is relative to the mouse cursor
px = ev . xmotion . x ;
py = ev . xmotion . y ;
}
r = recttoclient ( px , py , 1 , 1 ) ;
if ( ! r | | r = = c )
break ;
attachmode = 0 ; // below
if ( ( ( float ) ( r - > y + r - > h - py ) / r - > h ) > ( ( float ) ( r - > x + r - > w - px ) / r - > w ) ) {
if ( abs ( r - > y - py ) < r - > h / 2 )
attachmode = 1 ; // above
} else if ( abs ( r - > x - px ) < r - > w / 2 )
attachmode = 1 ; // above
if ( ( r & & r ! = prevr ) | | ( attachmode ! = prevattachmode ) ) {
detachstack ( c ) ;
detach ( c ) ;
if ( c - > mon ! = r - > mon ) {
arrangemon ( c - > mon ) ;
c - > tags = r - > mon - > tagset [ r - > mon - > seltags ] ;
}
c - > mon = r - > mon ;
r - > mon - > sel = r ;
if ( attachmode ) {
if ( r = = r - > mon - > clients )
attach ( c ) ;
else {
for ( at = r - > mon - > clients ; at - > next ! = r ; at = at - > next ) ;
c - > next = at - > next ;
at - > next = c ;
}
} else {
c - > next = r - > next ;
r - > next = c ;
}
attachstack ( c ) ;
arrangemon ( r - > mon ) ;
prevr = r ;
prevattachmode = attachmode ;
}
break ;
}
} while ( ev . type ! = ButtonRelease ) ;
XUngrabPointer ( dpy , CurrentTime ) ;
if ( ( m = recttomon ( ev . xmotion . x , ev . xmotion . y , 1 , 1 ) ) & & m ! = c - > mon ) {
detach ( c ) ;
detachstack ( c ) ;
arrangemon ( c - > mon ) ;
c - > mon = m ;
c - > tags = m - > tagset [ m - > seltags ] ;
attach ( c ) ;
attachstack ( c ) ;
selmon = m ;
}
focus ( c ) ;
c - > beingmoved = 0 ;
if ( nx ! = - 9999 )
resize ( c , nx , ny , c - > w , c - > h , 0 ) ;
arrangemon ( c - > mon ) ;
}
void
pop ( Client * c )
{
2022-09-11 14:16:14 +02:00
int i ;
for ( i = 0 ; ! ( selmon - > tagset [ selmon - > seltags ] & 1 < < i ) ; i + + ) ;
i + + ;
2022-08-21 11:53:18 +02:00
detach ( c ) ;
attach ( c ) ;
focus ( c ) ;
arrange ( c - > mon ) ;
}
void
propertynotify ( XEvent * e )
{
Client * c ;
Window trans ;
XPropertyEvent * ev = & e - > xproperty ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( ( c = wintosystrayicon ( ev - > window ) ) ) {
if ( ev - > atom = = XA_WM_NORMAL_HINTS ) {
updatesizehints ( c ) ;
updatesystrayicongeom ( c , c - > w , c - > h ) ;
}
else
updatesystrayiconstate ( c , ev ) ;
resizebarwin ( selmon ) ;
updatesystray ( ) ;
}
# endif
2022-08-21 11:53:18 +02:00
if ( ( ev - > window = = root ) & & ( ev - > atom = = XA_WM_NAME ) ) {
2022-10-14 16:14:45 +02:00
if ( ! getsignal ( ) )
2022-08-21 11:53:18 +02:00
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 - > ignoretransient & & ! c - > isfloating & &
( XGetTransientForHint ( dpy , c - > win , & trans ) ) & &
( c - > isfloating = ( wintoclient ( trans ) ) ! = NULL ) )
arrange ( c - > mon ) ;
break ;
case XA_WM_NORMAL_HINTS :
2022-09-10 23:49:22 +02:00
c - > hintsvalid = 0 ;
2022-08-21 11:53:18 +02:00
break ;
case XA_WM_HINTS :
updatewmhints ( c ) ;
drawbars ( ) ;
break ;
}
if ( ev - > atom = = XA_WM_NAME | | ev - > atom = = netatom [ NetWMName ] ) {
updatetitle ( c ) ;
updaterules ( c ) ;
if ( c = = c - > mon - > sel )
drawbar ( c - > mon ) ;
}
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
else if ( ev - > atom = = netatom [ NetWMIcon ] ) {
updateicon ( c ) ;
if ( c = = c - > mon - > sel )
drawbar ( c - > mon ) ;
}
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
if ( ev - > atom = = netatom [ NetWMWindowType ] )
updatewindowtype ( c ) ;
if ( ev - > atom = = motifatom )
updatemotifhints ( c ) ;
if ( ev - > atom = = wmatom [ WMClass ] ) {
if ( wmclass ) {
applyrules ( c ) ;
}
}
}
}
void
quit ( const Arg * arg )
{
Monitor * m ;
Client * c ;
2022-08-23 21:48:34 +02:00
// fix: reloading dwm keeps all the hidden clients hidden
for ( m = mons ; m ; m = m - > next ) {
if ( m ) {
for ( c = m - > stack ; c ; c = c - > next )
if ( c & & HIDDEN ( c ) ) showwin ( c ) ;
}
2022-08-21 11:53:18 +02:00
}
if ( arg - > i ) restart = 1 ;
2022-09-25 15:11:40 +02:00
running = 0 ;
2022-08-21 11:53:18 +02:00
}
Client *
recttoclient ( int x , int y , int w , int h )
{
Client * c , * r = NULL ;
int a , area = 0 ;
for ( c = nexttiled ( selmon - > clients ) ; c ; c = nexttiled ( c - > next ) ) {
if ( ( a = INTERSECTC ( x , y , w , h , c ) ) > area ) {
area = a ;
r = c ;
}
}
return r ;
}
Monitor *
recttomon ( int x , int y , int w , int h )
{
Monitor * m , * r = selmon ;
int a , area = 0 ;
for ( m = mons ; m ; m = m - > next )
if ( ( a = INTERSECT ( x , y , w , h , m ) ) > area ) {
area = a ;
r = m ;
}
return r ;
}
void
2022-09-14 18:01:06 +02:00
reset_layout ( const Arg * arg )
2022-08-21 11:53:18 +02:00
{
2022-09-14 17:46:09 +02:00
Arg default_layout = { . v = & layouts [ 0 ] } ;
Arg default_mfact = { . f = mfact + 1 } ;
2022-08-21 11:53:18 +02:00
2022-09-14 18:01:06 +02:00
if ( resetlayout ) {
2022-08-21 11:53:18 +02:00
setlayout ( & default_layout ) ;
2022-09-14 17:46:09 +02:00
selmon - > isreset = 1 ;
}
2022-09-14 18:01:06 +02:00
if ( resetmfact ) {
2022-08-21 11:53:18 +02:00
setmfact ( & default_mfact ) ;
}
2022-10-04 18:12:17 +02:00
if ( enablegaps & & resetgaps ) {
defaultgaps ( NULL ) ;
}
2022-08-21 11:53:18 +02:00
}
2022-10-11 17:11:31 +02:00
void
reset_mfact ( const Arg * arg ) {
Arg new_mfact = { . f = mfact + 1 } ;
setmfact ( & new_mfact ) ;
}
2022-08-21 11:53:18 +02:00
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 ) ;
}
2022-09-21 15:50:53 +02:00
void
resetnmaster ( const Arg * arg )
{
selmon - > nmaster = selmon - > pertag - > nmasters [ selmon - > pertag - > curtag ] = 1 ;
arrange ( selmon ) ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
void
removesystrayicon ( Client * i )
{
Client * * ii ;
if ( ! showsystray | | ! i )
return ;
for ( ii = & systray - > icons ; * ii & & * ii ! = i ; ii = & ( * ii ) - > next ) ;
if ( ii )
* ii = i - > next ;
free ( i ) ;
}
void
resizebarwin ( Monitor * m ) {
unsigned int w = m - > ww ;
if ( showsystray & & m = = systraytomon ( m ) & & ! systrayonleft )
w - = getsystraywidth ( ) ;
XMoveResizeWindow ( dpy , m - > barwin , m - > wx + sp , m - > by + vp , m - > ww - 2 * sp , bh ) ;
}
void
resizerequest ( XEvent * e )
{
XResizeRequestEvent * ev = & e - > xresizerequest ;
Client * i ;
if ( ( i = wintosystrayicon ( ev - > window ) ) ) {
updatesystrayicongeom ( i , ev - > width , ev - > height ) ;
resizebarwin ( selmon ) ;
updatesystray ( ) ;
}
}
# endif
2022-08-21 11:53:18 +02:00
void
resize ( Client * c , int x , int y , int w , int h , int interact )
{
2022-09-14 17:46:09 +02:00
if ( applysizehints ( c , & x , & y , & w , & h , interact ) ) {
2022-08-21 11:53:18 +02:00
resizeclient ( c , x , y , w , h ) ;
2022-09-14 17:46:09 +02:00
selmon - > isreset = 1 ;
} else {
selmon - > isreset = 0 ;
}
2022-08-21 11:53:18 +02:00
}
void
resizeclient ( Client * c , int x , int y , int w , int h )
{
XWindowChanges wc ;
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 ;
if ( c - > beingmoved )
return ;
wc . border_width = c - > bw ;
if ( ( nexttiled ( c - > mon - > clients ) = = c ) & & ! ( nexttiled ( c - > next ) ) )
2022-09-14 18:01:06 +02:00
reset_layout ( NULL ) ;
2022-08-21 11:53:18 +02:00
XConfigureWindow ( dpy , c - > win , CWX | CWY | CWWidth | CWHeight | CWBorderWidth , & wc ) ;
configure ( c ) ;
XSync ( dpy , False ) ;
}
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 ) ) ;
2022-10-06 11:39:35 +02:00
if ( warpcursor ) {
if ( m = = selmon & & selmon - > allowwarp & & ( m - > tagset [ m - > seltags ] & m - > sel - > tags ) & & selmon - > lt [ selmon - > sellt ] ! = & layouts [ 2 ] )
2022-08-21 11:53:18 +02:00
warp ( m - > sel ) ;
}
}
void
run ( void )
{
2022-10-11 18:19:35 +02:00
XSync ( dpy , False ) ;
2022-08-26 11:41:11 +02:00
# if USEIPC
int event_count = 0 ;
const int MAX_EVENTS = 10 ;
struct epoll_event events [ MAX_EVENTS ] ;
2022-10-11 18:19:35 +02:00
# else
XEvent ev ;
while ( running & & ! XNextEvent ( dpy , & ev ) )
if ( handler [ ev . type ] )
handler [ ev . type ] ( & ev ) ; /* call handler */
2022-08-26 11:41:11 +02:00
# endif
# if USEIPC
/* main event loop */
while ( running ) {
event_count = epoll_wait ( epoll_fd , events , MAX_EVENTS , - 1 ) ;
for ( int i = 0 ; i < event_count ; i + + ) {
int event_fd = events [ i ] . data . fd ;
DEBUG ( " Got event from fd %d \n " , event_fd ) ;
if ( event_fd = = dpy_fd ) {
// -1 means EPOLLHUP
if ( handlexevent ( events + i ) = = - 1 )
return ;
} else if ( event_fd = = ipc_get_sock_fd ( ) ) {
ipc_handle_socket_epoll_event ( events + i ) ;
} else if ( ipc_is_client_registered ( event_fd ) ) {
if ( ipc_handle_client_epoll_event ( events + i , mons , & lastselmon , selmon ,
LENGTH ( tags ) , layouts , LENGTH ( layouts ) ) < 0 ) {
fprintf ( stderr , " Error handling IPC event on fd %d \n " , event_fd ) ;
}
} else {
fprintf ( stderr , " Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu " ,
event_fd , events [ i ] . data . ptr , events [ i ] . data . u32 ,
events [ i ] . data . u64 ) ;
fprintf ( stderr , " with events %d \n " , events [ i ] . events ) ;
return ;
}
}
}
# endif
2022-08-21 11:53:18 +02:00
}
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 ( altbar & & wmclasscontains ( wins [ i ] , altbarclass , " " ) )
managealtbar ( wins [ i ] , & wa ) ;
else 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 ) ;
}
}
static void scratchpad_hide ( )
{
if ( selmon - > sel )
{
selmon - > sel - > tags = SCRATCHPAD_MASK ;
if ( floatscratchpad )
selmon - > sel - > isfloating = 1 ;
focus ( NULL ) ;
arrange ( selmon ) ;
}
}
static _Bool scratchpad_last_showed_is_killed ( void )
{
_Bool killed = 1 ;
for ( Client * c = selmon - > clients ; c ! = NULL ; c = c - > next )
{
if ( c = = scratchpad_last_showed )
{
killed = 0 ;
break ;
}
}
return killed ;
}
2022-10-06 09:58:29 +02:00
void
scratchpad_remove ( )
2022-08-21 11:53:18 +02:00
{
2022-10-06 09:58:29 +02:00
if ( selmon - > sel & & scratchpad_last_showed ! = NULL & & selmon - > sel = = scratchpad_last_showed )
2022-08-21 11:53:18 +02:00
scratchpad_last_showed = NULL ;
}
2022-10-06 09:58:29 +02:00
void
scratchpad_show ( )
2022-08-21 11:53:18 +02:00
{
if ( scratchpad_last_showed = = NULL | | scratchpad_last_showed_is_killed ( ) )
scratchpad_show_first ( ) ;
else
{
if ( scratchpad_last_showed - > tags ! = SCRATCHPAD_MASK )
{
scratchpad_last_showed - > tags = SCRATCHPAD_MASK ;
focus ( NULL ) ;
arrange ( selmon ) ;
}
else
{
_Bool found_current = 0 ;
_Bool found_next = 0 ;
for ( Client * c = selmon - > clients ; c ! = NULL ; c = c - > next )
{
if ( found_current = = 0 )
{
if ( c = = scratchpad_last_showed )
{
found_current = 1 ;
continue ;
}
}
else
{
if ( c - > tags = = SCRATCHPAD_MASK )
{
found_next = 1 ;
scratchpad_show_client ( c ) ;
break ;
}
}
}
if ( found_next = = 0 ) scratchpad_show_first ( ) ;
}
}
2022-09-17 15:34:30 +02:00
show ( NULL ) ;
2022-08-21 11:53:18 +02:00
}
2022-10-06 09:58:29 +02:00
void
scratchpad_show_client ( Client * c )
2022-08-21 11:53:18 +02:00
{
scratchpad_last_showed = c ;
c - > tags = selmon - > tagset [ selmon - > seltags ] ;
focus ( c ) ;
arrange ( selmon ) ;
}
2022-10-06 09:58:29 +02:00
void
scratchpad_show_first ( void )
2022-08-21 11:53:18 +02:00
{
for ( Client * c = selmon - > clients ; c ! = NULL ; c = c - > next )
{
if ( c - > tags = = SCRATCHPAD_MASK )
{
scratchpad_show_client ( c ) ;
break ;
}
}
}
void
scantray ( void )
{
unsigned int num ;
Window d1 , d2 , * wins = NULL ;
XWindowAttributes wa ;
if ( XQueryTree ( dpy , root , & d1 , & d2 , & wins , & num ) ) {
for ( unsigned int i = 0 ; i < num ; i + + ) {
if ( wmclasscontains ( wins [ i ] , altbarclass , alttrayname ) ) {
if ( ! XGetWindowAttributes ( dpy , wins [ i ] , & wa ) )
break ;
managetray ( 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 ] ? m - > tagset [ m - > seltags ] : 1 ) ;
//attach(c);
switch ( attachdirection ) {
case 1 :
attachabove ( c ) ;
break ;
case 2 :
attachaside ( c ) ;
break ;
case 3 :
attachbelow ( c ) ;
break ;
case 4 :
attachbottom ( c ) ;
break ;
case 5 :
attachtop ( c ) ;
break ;
default :
attach ( c ) ;
}
attachstack ( c ) ;
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 ) ;
}
void
setcurrentdesktop ( void ) {
long data [ ] = { 0 } ;
XChangeProperty ( dpy , root , netatom [ NetCurrentDesktop ] , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) data , 1 ) ;
}
void
setdesktopnames ( void )
{
XTextProperty text ;
Xutf8TextListToTextProperty ( dpy , tags , TAGSLENGTH , XUTF8StringStyle , & text ) ;
XSetTextProperty ( dpy , root , & text , netatom [ NetDesktopNames ] ) ;
}
int
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
sendevent ( Window w , Atom proto , int mask , long d0 , long d1 , long d2 , long d3 , long d4 )
# else
2022-08-21 11:53:18 +02:00
sendevent ( Client * c , Atom proto )
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
{
int n ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
Atom * protocols , mt ;
# else
2022-08-21 11:53:18 +02:00
Atom * protocols ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
int exists = 0 ;
XEvent ev ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( proto = = wmatom [ WMTakeFocus ] | | proto = = wmatom [ WMDelete ] ) {
mt = wmatom [ WMProtocols ] ;
# endif
# if USESYSTRAY
if ( XGetWMProtocols ( dpy , w , & protocols , & n ) ) {
# else
2022-08-21 11:53:18 +02:00
if ( XGetWMProtocols ( dpy , c - > win , & protocols , & n ) ) {
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
while ( ! exists & & n - - )
exists = protocols [ n ] = = proto ;
XFree ( protocols ) ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
} else {
exists = True ;
mt = proto ;
}
# endif
2022-08-21 11:53:18 +02:00
if ( exists ) {
ev . type = ClientMessage ;
2022-10-02 15:34:11 +02:00
ev . xclient . format = 32 ;
# if USESYSTRAY
ev . xclient . window = w ;
ev . xclient . message_type = mt ;
ev . xclient . data . l [ 0 ] = d0 ;
ev . xclient . data . l [ 1 ] = d1 ;
ev . xclient . data . l [ 2 ] = d2 ;
ev . xclient . data . l [ 3 ] = d3 ;
ev . xclient . data . l [ 4 ] = d4 ;
XSendEvent ( dpy , w , False , mask , & ev ) ;
# else
2022-08-21 11:53:18 +02:00
ev . xclient . window = c - > win ;
ev . xclient . message_type = wmatom [ WMProtocols ] ;
ev . xclient . data . l [ 0 ] = proto ;
ev . xclient . data . l [ 1 ] = CurrentTime ;
XSendEvent ( dpy , c - > win , False , NoEventMask , & ev ) ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
return exists ;
}
void
setnumdesktops ( void ) {
long data [ ] = { TAGSLENGTH } ;
XChangeProperty ( dpy , root , netatom [ NetNumberOfDesktops ] , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) data , 1 ) ;
}
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 ) ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
sendevent ( c - > win , wmatom [ WMTakeFocus ] , NoEventMask , wmatom [ WMTakeFocus ] , CurrentTime , 0 , 0 , 0 ) ;
# else
2022-08-21 11:53:18 +02:00
sendevent ( c , wmatom [ WMTakeFocus ] ) ;
2022-10-02 15:34:11 +02:00
# endif
2022-08-21 11:53:18 +02:00
}
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 ) ;
2022-10-11 07:12:53 +02:00
# if USEROUNDCORNERS
if ( roundedcorners ) {
XRectangle rect = { . x = 0 , . y = 0 , . width = c - > w , . height = c - > h } ;
XShapeCombineRectangles ( dpy , c - > win , ShapeBounding , 0 , 0 , & rect , 1 , ShapeSet , 1 ) ;
}
# endif
2022-08-21 11:53:18 +02:00
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 ) ;
2022-10-11 07:12:53 +02:00
# if USEROUNDCORNERS
if ( roundedcorners ) {
XRectangle rect = { . x = 0 , . y = 0 , . width = c - > w , . height = c - > h } ;
XShapeCombineRectangles ( dpy , c - > win , ShapeBounding , 0 , 0 , & rect , 1 , ShapeSet , 1 ) ;
}
# endif
2022-08-21 11:53:18 +02:00
arrange ( c - > mon ) ;
}
}
void
setlayout ( const Arg * arg )
{
if ( ! arg | | ! arg - > v | | arg - > v ! = selmon - > lt [ selmon - > sellt ] )
selmon - > sellt = selmon - > pertag - > sellts [ selmon - > pertag - > curtag ] ^ = 1 ;
if ( arg & & arg - > v )
selmon - > lt [ selmon - > sellt ] = selmon - > pertag - > ltidxs [ selmon - > pertag - > curtag ] [ selmon - > sellt ] = ( Layout * ) arg - > v ;
if ( selmon - > sel )
arrange ( selmon ) ;
else
drawbar ( selmon ) ;
}
void
2022-08-28 01:47:41 +02:00
setcfact ( const Arg * arg )
{
2022-08-21 11:53:18 +02:00
float f ;
Client * c ;
c = selmon - > sel ;
2022-08-28 01:47:41 +02:00
if ( ! arg | | ! c | | ! selmon - > lt [ selmon - > sellt ] - > arrange )
2022-08-21 11:53:18 +02:00
return ;
2022-08-28 01:47:41 +02:00
if ( ! arg - > f )
2022-08-21 11:53:18 +02:00
f = 1.0 ;
2022-08-28 01:47:41 +02:00
else if ( arg - > f > 4.0 ) // set fact absolutely
f = arg - > f - 4.0 ;
else
f = arg - > f + c - > cfact ;
if ( f < 0.25 )
f = 0.25 ;
else if ( f > 4.0 )
f = 4.0 ;
2022-08-21 11:53:18 +02:00
c - > cfact = f ;
arrange ( selmon ) ;
}
2022-08-26 11:41:11 +02:00
# if USEIPC
void
setlayoutsafe ( const Arg * arg )
{
const Layout * ltptr = ( Layout * ) arg - > v ;
if ( ltptr = = 0 )
setlayout ( arg ) ;
for ( int i = 0 ; i < LENGTH ( layouts ) ; i + + ) {
if ( ltptr = = & layouts [ i ] )
setlayout ( arg ) ;
}
}
# endif
2022-08-21 11:53:18 +02:00
/* arg > 1.0 will set mfact absolutely */
void
setmfact ( const Arg * arg )
{
float f ;
if ( ! arg | | ! selmon - > lt [ selmon - > sellt ] - > arrange )
return ;
f = arg - > f < 1.0 ? arg - > f + selmon - > mfact : arg - > f - 1.0 ;
2022-09-17 00:45:58 +02:00
if ( f < 0.05 - lowestmfact | | f > 0.95 + lowestmfact )
2022-08-21 11:53:18 +02:00
return ;
selmon - > mfact = selmon - > pertag - > mfacts [ selmon - > pertag - > curtag ] = f ;
arrange ( selmon ) ;
}
2022-10-11 14:06:13 +02:00
# if USEFADE
2022-08-21 11:53:18 +02:00
void
toggleopacity ( const Arg * arg ) {
bUseOpacity = ! bUseOpacity ;
for ( Monitor * m = mons ; m ; m = m - > next )
for ( Client * c = m - > clients ; c ; c = c - > next )
opacity ( c , ( bUseOpacity & & c ! = selmon - > sel ) ? inactiveopacity : activeopacity ) ;
}
2022-10-11 14:06:13 +02:00
# endif
2022-08-21 11:53:18 +02:00
void
setup ( void )
{
XSetWindowAttributes wa ;
2022-08-25 18:53:04 +02:00
Atom utf8string ;
2022-08-21 11:53:18 +02:00
/* clean up any zombies immediately */
2022-10-03 00:24:54 +02:00
if ( signal ( SIGCHLD , sigchld ) = = SIG_ERR )
die ( " can't install SIGCHLD handler: " ) ;
2022-08-21 11:53:18 +02:00
sigchld ( 0 ) ;
signal ( SIGHUP , sighup ) ;
signal ( SIGTERM , sigterm ) ;
/* init screen */
screen = DefaultScreen ( dpy ) ;
tw = DisplayWidth ( dpy , screen ) ;
sh = DisplayHeight ( dpy , screen ) ;
root = RootWindow ( dpy , screen ) ;
xinitvisual ( ) ;
drw = drw_create ( dpy , screen , root , tw , sh , visual , depth , cmap ) ;
if ( ! drw_fontset_create ( drw , fonts , LENGTH ( fonts ) ) )
die ( " no fonts could be loaded. " ) ;
lrpad = drw - > fonts - > h ;
bh = altbar ? 0 : drw - > fonts - > h + barheight ;
2022-10-02 15:34:11 +02:00
// barpadding
2022-08-21 11:53:18 +02:00
sp = barpaddingh ;
vp = ( barposition = = 1 ) ? barpaddingv : - barpaddingv ;
updategeom ( ) ;
int i = 0 ;
/* init atoms */
2022-08-25 18:53:04 +02:00
utf8string = XInternAtom ( dpy , " UTF8_STRING " , False ) ;
2022-08-21 11:53:18 +02:00
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 ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
netatom [ NetSystemTray ] = XInternAtom ( dpy , " _NET_SYSTEM_TRAY_S0 " , False ) ;
netatom [ NetSystemTrayOP ] = XInternAtom ( dpy , " _NET_SYSTEM_TRAY_OPCODE " , False ) ;
netatom [ NetSystemTrayOrientation ] = XInternAtom ( dpy , " _NET_SYSTEM_TRAY_ORIENTATION " , False ) ;
netatom [ NetSystemTrayOrientationHorz ] = XInternAtom ( dpy , " _NET_SYSTEM_TRAY_ORIENTATION_HORZ " , False ) ;
# endif
2022-08-21 11:53:18 +02:00
netatom [ NetWMName ] = XInternAtom ( dpy , " _NET_WM_NAME " , False ) ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
netatom [ NetWMIcon ] = XInternAtom ( dpy , " _NET_WM_ICON " , False ) ;
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
netatom [ NetWMState ] = XInternAtom ( dpy , " _NET_WM_STATE " , False ) ;
2022-08-25 18:53:04 +02:00
if ( fullscreenhidebar )
netatom [ NetWMCheck ] = XInternAtom ( dpy , " _NET_SUPPORTING_WM_CHECK " , False ) ;
2022-08-21 11:53:18 +02:00
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 [ NetWMWindowTypeDesktop ] = XInternAtom ( dpy , " _NET_WM_WINDOW_TYPE_DESKTOP " , False ) ;
netatom [ NetClientList ] = XInternAtom ( dpy , " _NET_CLIENT_LIST " , False ) ;
2022-08-21 16:05:53 +02:00
dwmatom [ DWMTags ] = XInternAtom ( dpy , " _DWM_TAGS " , False ) ;
2022-08-21 11:53:18 +02:00
netatom [ NetClientInfo ] = XInternAtom ( dpy , " _NET_CLIENT_INFO " , False ) ;
netatom [ NetClientListStacking ] = XInternAtom ( dpy , " _NET_CLIENT_LIST_STACKING " , False ) ;
2022-09-03 18:07:51 +02:00
# if USEFADE
2022-08-21 11:53:18 +02:00
netatom [ NetWMWindowsOpacity ] = XInternAtom ( dpy , " _NET_WM_WINDOW_OPACITY " , False ) ;
2022-09-03 18:07:51 +02:00
# endif
2022-08-21 11:53:18 +02:00
netatom [ NetDesktopViewport ] = XInternAtom ( dpy , " _NET_DESKTOP_VIEWPORT " , False ) ;
netatom [ NetNumberOfDesktops ] = XInternAtom ( dpy , " _NET_NUMBER_OF_DESKTOPS " , False ) ;
netatom [ NetCurrentDesktop ] = XInternAtom ( dpy , " _NET_CURRENT_DESKTOP " , False ) ;
netatom [ NetDesktopNames ] = XInternAtom ( dpy , " _NET_DESKTOP_NAMES " , False ) ;
motifatom = XInternAtom ( dpy , " _MOTIF_WM_HINTS " , False ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
xatom [ Manager ] = XInternAtom ( dpy , " MANAGER " , False ) ;
xatom [ Xembed ] = XInternAtom ( dpy , " _XEMBED " , False ) ;
xatom [ XembedInfo ] = XInternAtom ( dpy , " _XEMBED_INFO " , False ) ;
# endif
2022-08-21 11:53:18 +02: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 ) ;
2022-10-11 14:01:22 +02:00
cursor [ CurResizeHorzArrow ] = drw_cur_create ( drw , XC_sb_h_double_arrow ) ;
cursor [ CurResizeVertArrow ] = drw_cur_create ( drw , XC_sb_v_double_arrow ) ;
2022-08-21 11:53:18 +02:00
/* init appearance */
scheme = ecalloc ( LENGTH ( colors ) + 1 , sizeof ( Clr * ) ) ;
scheme [ LENGTH ( colors ) ] = drw_scm_create ( drw , colors [ 0 ] , alphas [ i ] , 3 ) ;
if ( LENGTH ( tags ) > LENGTH ( tagsel ) )
die ( " too few color schemes for the tags " ) ;
for ( i = 0 ; i < LENGTH ( colors ) ; i + + )
scheme [ i ] = drw_scm_create ( drw , colors [ i ] , alphas [ i ] , 3 ) ;
tagscheme = ecalloc ( LENGTH ( tagsel ) , sizeof ( Clr * ) ) ;
for ( i = 0 ; i < LENGTH ( tagsel ) ; i + + )
tagscheme [ i ] = drw_scm_create ( drw , tagsel [ i ] , tagalpha , 2 ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
updatesystray ( ) ;
# endif
2022-08-21 11:53:18 +02:00
/* init bars */
updatebars ( ) ;
updatestatus ( ) ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
updatepreview ( ) ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-25 18:53:04 +02:00
2022-08-21 11:53:18 +02:00
/* supporting window for NetWMCheck */
2022-08-25 18:53:04 +02:00
if ( fullscreenhidebar ) {
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 * ) " speedwm " , 7 ) ;
XChangeProperty ( dpy , root , netatom [ NetWMCheck ] , XA_WINDOW , 32 ,
PropModeReplace , ( unsigned char * ) & wmcheckwin , 1 ) ;
}
2022-08-21 11:53:18 +02:00
/* EWMH support per view */
XChangeProperty ( dpy , root , netatom [ NetSupported ] , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) netatom , NetLast ) ;
setnumdesktops ( ) ;
setcurrentdesktop ( ) ;
setdesktopnames ( ) ;
setviewport ( ) ;
XDeleteProperty ( dpy , root , netatom [ NetClientList ] ) ;
XDeleteProperty ( dpy , root , netatom [ NetClientInfo ] ) ;
XDeleteProperty ( dpy , root , netatom [ NetClientListStacking ] ) ;
/* select events */
wa . cursor = cursor [ CurNormal ] - > cursor ;
wa . event_mask = SubstructureRedirectMask | SubstructureNotifyMask
| ButtonPressMask | PointerMotionMask | EnterWindowMask
| LeaveWindowMask | StructureNotifyMask | PropertyChangeMask | KeyPressMask ;
XChangeWindowAttributes ( dpy , root , CWEventMask | CWCursor , & wa ) ;
XSelectInput ( dpy , root , wa . event_mask ) ;
grabkeys ( ) ;
focus ( NULL ) ;
2022-08-26 11:41:11 +02:00
# if USEIPC
setupepoll ( ) ;
# endif
2022-08-21 11:53:18 +02:00
spawnbar ( ) ;
}
void
setviewport ( void ) {
long data [ ] = { 0 , 0 } ;
XChangeProperty ( dpy , root , netatom [ NetDesktopViewport ] , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) data , 2 ) ;
}
2022-08-26 11:41:11 +02:00
# if USEIPC
void
setupepoll ( void )
{
epoll_fd = epoll_create1 ( 0 ) ;
dpy_fd = ConnectionNumber ( dpy ) ;
struct epoll_event dpy_event ;
// Initialize struct to 0
memset ( & dpy_event , 0 , sizeof ( dpy_event ) ) ;
DEBUG ( " Display socket is fd %d \n " , dpy_fd ) ;
if ( epoll_fd = = - 1 ) {
fputs ( " Failed to create epoll file descriptor " , stderr ) ;
}
dpy_event . events = EPOLLIN ;
dpy_event . data . fd = dpy_fd ;
if ( epoll_ctl ( epoll_fd , EPOLL_CTL_ADD , dpy_fd , & dpy_event ) ) {
fputs ( " Failed to add display file descriptor to epoll " , stderr ) ;
close ( epoll_fd ) ;
exit ( 1 ) ;
}
if ( ipc_init ( ipcsockpath , epoll_fd , ipccommands , LENGTH ( ipccommands ) ) < 0 ) {
fputs ( " Failed to initialize IPC \n " , stderr ) ;
}
}
# endif
2022-08-21 11:53:18 +02:00
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 ) ;
}
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
void
showtagpreview ( unsigned int i )
{
if ( ! selmon - > previewshow | | ! selmon - > tagmap [ i ] ) {
XUnmapWindow ( dpy , selmon - > tagwin ) ;
return ;
}
2022-10-03 03:10:02 +02:00
if ( tagpreview & & barposition ) {
2022-08-21 11:53:18 +02:00
XSetWindowBackgroundPixmap ( dpy , selmon - > tagwin , selmon - > tagmap [ i ] ) ;
XCopyArea ( dpy , selmon - > tagmap [ i ] , selmon - > tagwin , drw - > gc , 0 , 0 ,
2022-10-03 02:13:33 +02:00
selmon - > mw / scalepreview , selmon - > mh / scalepreview + 50 ,
2022-08-21 11:53:18 +02:00
0 , 0 ) ;
XSync ( dpy , False ) ;
XMapWindow ( dpy , selmon - > tagwin ) ;
}
}
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
2022-10-05 13:42:45 +02:00
# if USEXRESOURCES
2022-10-03 16:49:24 +02:00
void
reloadcolors ( const Arg * arg )
{
// reload colors
load_xresources ( ) ;
setup ( ) ;
}
2022-10-05 13:42:45 +02:00
# endif
2022-10-03 16:49:24 +02:00
2022-08-21 11:53:18 +02:00
void
sigchld ( int unused )
{
pid_t pid ;
while ( 0 < ( pid = waitpid ( - 1 , NULL , WNOHANG ) ) ) {
pid_t * p , * lim ;
if ( ! ( p = autostart_pids ) )
continue ;
lim = & p [ autostart_len ] ;
for ( ; p < lim ; p + + ) {
if ( * p = = pid ) {
* p = - 1 ;
break ;
}
}
}
}
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
void
2022-09-09 10:07:24 +02:00
takepreview ( void )
2022-08-21 11:53:18 +02:00
{
unsigned int occ = 0 , i ;
Client * c ;
Imlib_Image image ;
for ( c = selmon - > clients ; c ; c = c - > next )
occ | = c - > tags = = 255 ? 0 : c - > tags ;
for ( i = 0 ; i < LENGTH ( tags ) ; i + + ) {
/* searching for tags that are occupied && selected */
if ( ! ( occ & 1 < < i ) | | ! ( selmon - > tagset [ selmon - > seltags ] & 1 < < i ) )
continue ;
if ( selmon - > tagmap [ i ] ) { /* tagmap exist, clean it */
XFreePixmap ( dpy , selmon - > tagmap [ i ] ) ;
selmon - > tagmap [ i ] = 0 ;
}
if ( ! ( image = imlib_create_image ( tw , sh ) ) ) {
fprintf ( stderr , " speedwm: imlib: failed to create image, skipping. \n " ) ;
continue ;
}
imlib_context_set_image ( image ) ;
imlib_context_set_display ( dpy ) ;
imlib_image_set_has_alpha ( 1 ) ;
imlib_context_set_blend ( 0 ) ;
imlib_context_set_visual ( visual ) ;
imlib_context_set_drawable ( root ) ;
2022-08-23 17:50:48 +02:00
if ( ! barpreview )
imlib_copy_drawable_to_image ( 0 , selmon - > wx , selmon - > wy , selmon - > ww , selmon - > wh , 0 , 0 , 1 ) ;
else
imlib_copy_drawable_to_image ( 0 , selmon - > mx , selmon - > my , selmon - > mw , selmon - > mh , 0 , 0 , 1 ) ;
2022-10-03 02:13:33 +02:00
selmon - > tagmap [ i ] = XCreatePixmap ( dpy , selmon - > tagwin , selmon - > mw / scalepreview , selmon - > mh / scalepreview , depth ) ;
2022-08-21 11:53:18 +02:00
imlib_context_set_drawable ( selmon - > tagmap [ i ] ) ;
2022-10-03 02:56:19 +02:00
imlib_render_image_part_on_drawable_at_size ( 0 , 0 , selmon - > mw , selmon - > mh , 0 , 0 , selmon - > mw / scalepreview , selmon - > mh / scalepreview ) ;
2022-08-21 11:53:18 +02:00
imlib_free_image ( ) ;
}
}
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
void
sighup ( int unused )
{
Arg a = { . i = 1 } ;
quit ( & a ) ;
}
void
sigterm ( int unused )
{
Arg a = { . i = 0 } ;
quit ( & a ) ;
}
# ifdef XINERAMA
void
sortscreens ( XineramaScreenInfo * screens , int n )
{
int i , j ;
XineramaScreenInfo * screen = ecalloc ( 1 , sizeof ( XineramaScreenInfo ) ) ;
for ( i = 0 ; i < n ; i + + )
for ( j = i + 1 ; j < n ; j + + )
if ( RIGHTOF ( screens [ i ] , screens [ j ] ) ) {
memcpy ( & screen [ 0 ] , & screens [ i ] , sizeof ( XineramaScreenInfo ) ) ;
memcpy ( & screens [ i ] , & screens [ j ] , sizeof ( XineramaScreenInfo ) ) ;
memcpy ( & screens [ j ] , & screen [ 0 ] , sizeof ( XineramaScreenInfo ) ) ;
}
XFree ( screen ) ;
}
# endif /* XINERAMA */
void
spawn ( const Arg * arg )
{
2022-10-08 11:18:25 +02:00
FILE * buttonfile = fopen ( " /tmp/speedwm-button " , " w " ) ;
2022-08-21 11:53:18 +02:00
if ( fork ( ) = = 0 ) {
if ( dpy )
close ( ConnectionNumber ( dpy ) ) ;
2022-09-03 16:46:19 +02:00
# if USEMOUSE
2022-08-21 11:53:18 +02:00
if ( arg - > v = = statuscmd ) {
for ( int i = 0 ; i < LENGTH ( statuscmds ) ; i + + ) {
if ( statuscmdn = = statuscmds [ i ] . id ) {
statuscmd [ 2 ] = statuscmds [ i ] . cmd ;
setenv ( " BUTTON " , lastbutton , 1 ) ;
2022-10-08 11:18:25 +02:00
int writestatus = fputs ( lastbutton , buttonfile ) ;
if ( writestatus = = EOF ) {
fprintf ( stderr , " speedwm: failed to write statuscmd button. \n " ) ;
return ;
}
fclose ( buttonfile ) ;
2022-08-21 11:53:18 +02:00
break ;
}
}
if ( ! statuscmd [ 2 ] )
exit ( EXIT_SUCCESS ) ;
}
2022-09-03 16:46:19 +02:00
# endif
2022-08-21 11:53:18 +02:00
setsid ( ) ;
execvp ( ( ( char * * ) arg - > v ) [ 0 ] , ( char * * ) arg - > v ) ;
2022-09-11 00:39:08 +02:00
die ( " dwm: execvp '%s' failed: " , ( ( char * * ) arg - > v ) [ 0 ] ) ;
2022-08-21 11:53:18 +02:00
}
}
2022-09-17 18:20:59 +02:00
void
tag ( const Arg * arg )
{
if ( selmon - > sel & & arg - > ui & TAGMASK ) {
selmon - > sel - > tags = arg - > ui & TAGMASK ;
focus ( NULL ) ;
arrange ( selmon ) ;
}
}
2022-08-21 11:53:18 +02:00
void
spawnbar ( )
{
if ( * altbarcmd )
if ( system ( altbarcmd ) = = 0 )
return ;
}
void
tagmon ( const Arg * arg )
{
Client * c = selmon - > sel ;
if ( ! c | | ! mons - > next )
return ;
if ( movefullscreenmon ) {
if ( c - > isfullscreen ) {
c - > isfullscreen = 0 ;
sendmon ( c , dirtomon ( arg - > i ) ) ;
c - > isfullscreen = 1 ;
resizeclient ( c , c - > mon - > mx , c - > mon - > my , c - > mon - > mw , c - > mon - > mh ) ;
XRaiseWindow ( dpy , c - > win ) ;
} else
sendmon ( c , dirtomon ( arg - > i ) ) ;
} else {
sendmon ( selmon - > sel , dirtomon ( arg - > i ) ) ;
}
}
void
2022-10-11 17:11:31 +02:00
viewtoright ( const Arg * arg )
{
view ( & ( const Arg ) { . ui = nexttag ( ) } ) ;
2022-08-21 11:53:18 +02:00
}
void
2022-10-11 17:11:31 +02:00
viewtoleft ( const Arg * arg )
{
view ( & ( const Arg ) { . ui = prevtag ( ) } ) ;
2022-08-21 11:53:18 +02:00
}
2022-10-14 15:56:42 +02:00
void
viewtoright_vacant ( const Arg * arg )
{
view ( & ( const Arg ) { . ui = nexttag_skip_vacant ( ) } ) ;
}
void
viewtoleft_vacant ( const Arg * arg )
{
view ( & ( const Arg ) { . ui = prevtag_skip_vacant ( ) } ) ;
}
2022-08-21 11:53:18 +02:00
void
togglebar ( const Arg * arg )
{
/**
* Polybar tray does not raise maprequest event . It must be manually scanned
* for . Scanning it too early while the tray is being populated would give
* wrong dimensions .
*/
if ( altbar & & ! selmon - > traywin )
scantray ( ) ;
selmon - > showbar = selmon - > pertag - > showbars [ selmon - > pertag - > curtag ] = ! selmon - > showbar ;
updatebarpos ( selmon ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
resizebarwin ( selmon ) ;
if ( showsystray ) {
XWindowChanges wc ;
if ( ! selmon - > showbar )
wc . y = - bh ;
else if ( selmon - > showbar ) {
wc . y = 0 ;
if ( ! selmon - > barposition )
wc . y = selmon - > mh - bh ;
}
XConfigureWindow ( dpy , systray - > win , CWY , & wc ) ;
}
# else
XMoveResizeWindow ( dpy , selmon - > barwin , selmon - > wx , selmon - > by , selmon - > ww , selmon - > bh ) ;
XMoveResizeWindow ( dpy , selmon - > traywin , selmon - > wx , selmon - > by , selmon - > ww , selmon - > bh ) ;
# endif
2022-08-21 11:53:18 +02:00
if ( altbar )
XMoveResizeWindow ( dpy , selmon - > traywin , selmon - > tx , selmon - > by , selmon - > tw , selmon - > bh ) ;
arrange ( selmon ) ;
}
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 )
{
if ( savefloat )
{
/* restore last known float dimensions */
resize ( selmon - > sel , selmon - > sel - > sfx , selmon - > sel - > sfy , selmon - > sel - > sfw , selmon - > sel - > sfh , False ) ;
}
else
{
resize ( selmon - > sel , selmon - > sel - > x , selmon - > sel - > y , selmon - > sel - > w , selmon - > sel - > h , 0 ) ;
}
}
else
{
selmon - > sel - > sfx = selmon - > sel - > x ;
selmon - > sel - > sfy = selmon - > sel - > y ;
selmon - > sel - > sfw = selmon - > sel - > w ;
selmon - > sel - > sfh = selmon - > sel - > h ;
}
arrange ( selmon ) ;
}
void
togglesticky ( const Arg * arg )
{
if ( ! selmon - > sel )
return ;
selmon - > sel - > issticky = ! selmon - > sel - > issticky ;
arrange ( selmon ) ;
}
void
togglefullscr ( const Arg * arg )
{
if ( selmon - > sel )
setfullscreen ( selmon - > sel , ! selmon - > sel - > isfullscreen ) ;
}
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
void
freeicon ( Client * c )
{
if ( c - > icon ) {
XRenderFreePicture ( dpy , c - > icon ) ;
c - > icon = None ;
}
updatecurrentdesktop ( ) ;
}
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
void
unfocus ( Client * c , int setfocus )
{
if ( ! c )
return ;
grabbuttons ( c , 0 ) ;
2022-09-03 18:07:51 +02:00
# if USEFADE
2022-08-21 11:53:18 +02:00
opacity ( c , inactiveopacity ) ;
2022-09-03 18:07:51 +02:00
# endif
2022-08-21 11:53:18 +02:00
XSetWindowBorder ( dpy , c - > win , scheme [ SchemeNormBorder ] [ ColBorder ] . pixel ) ;
if ( setfocus ) {
XSetInputFocus ( dpy , root , RevertToPointerRoot , CurrentTime ) ;
XDeleteProperty ( dpy , root , netatom [ NetActiveWindow ] ) ;
}
updatecurrentdesktop ( ) ;
}
void
unmanage ( Client * c , int destroyed )
{
Monitor * m = c - > mon ;
XWindowChanges wc ;
if ( c - > swallowing ) {
unswallow ( c ) ;
return ;
}
Client * s = swallowingclient ( c - > win ) ;
if ( s ) {
free ( s - > swallowing ) ;
s - > swallowing = NULL ;
arrange ( m ) ;
focus ( NULL ) ;
return ;
}
detach ( c ) ;
detachstack ( c ) ;
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
freeicon ( c ) ;
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
if ( ! destroyed ) {
wc . border_width = c - > oldbw ;
XGrabServer ( dpy ) ; /* avoid race conditions */
XSetErrorHandler ( xerrordummy ) ;
2022-09-11 00:35:18 +02:00
XSelectInput ( dpy , c - > win , NoEventMask ) ;
2022-08-21 11:53:18 +02:00
XConfigureWindow ( dpy , c - > win , CWBorderWidth , & wc ) ; /* restore border */
XUngrabButton ( dpy , AnyButton , AnyModifier , c - > win ) ;
setclientstate ( c , WithdrawnState ) ;
XSync ( dpy , False ) ;
XSetErrorHandler ( xerror ) ;
XUngrabServer ( dpy ) ;
}
if ( scratchpad_last_showed = = c )
scratchpad_last_showed = NULL ;
free ( c ) ;
if ( ! s ) {
arrange ( m ) ;
focus ( NULL ) ;
updateclientlist ( ) ;
}
}
void
unmanagealtbar ( Window w )
{
Monitor * m = wintomon ( w ) ;
if ( ! m )
return ;
m - > barwin = 0 ;
m - > by = 0 ;
m - > bh = 0 ;
updatebarpos ( m ) ;
arrange ( m ) ;
}
void
unmanagetray ( Window w )
{
Monitor * m = wintomon ( w ) ;
if ( ! m )
return ;
m - > traywin = 0 ;
m - > tx = 0 ;
m - > tw = 0 ;
updatebarpos ( m ) ;
arrange ( m ) ;
}
void
unmapnotify ( XEvent * e )
{
Client * c ;
Monitor * m ;
XUnmapEvent * ev = & e - > xunmap ;
if ( ( c = wintoclient ( ev - > window ) ) ) {
if ( ev - > send_event )
setclientstate ( c , WithdrawnState ) ;
else
unmanage ( c , 0 ) ;
2022-10-02 15:34:11 +02:00
}
# if USESYSTRAY
else if ( ( c = wintosystrayicon ( ev - > window ) ) ) {
/* KLUDGE! sometimes icons occasionally unmap their windows, but do
* _not_ destroy them . We map those windows back */
XMapRaised ( dpy , c - > win ) ;
updatesystray ( ) ;
}
# endif
else if ( altbar & & ( m = wintomon ( ev - > window ) ) & & m - > barwin = = ev - > window )
2022-08-21 11:53:18 +02:00
unmanagealtbar ( ev - > window ) ;
else if ( altbar & & m - > traywin = = ev - > window )
unmanagetray ( ev - > window ) ;
}
void
updatebars ( void )
{
if ( altbar )
return ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
unsigned int w ;
# endif
2022-08-21 11:53:18 +02:00
Monitor * m ;
XSetWindowAttributes wa = {
. override_redirect = True ,
. background_pixel = 0 ,
. border_pixel = 0 ,
. colormap = cmap ,
. event_mask = ButtonPressMask | ExposureMask | PointerMotionMask
} ;
2022-09-09 10:15:04 +02:00
XClassHint ch = { " speedwm " , " speedwm " } ;
2022-08-21 11:53:18 +02:00
for ( m = mons ; m ; m = m - > next ) {
2022-09-09 11:13:25 +02:00
# if USETAGPREVIEW
2022-09-09 10:15:04 +02:00
if ( ! m - > tagwin ) {
2022-10-03 02:56:19 +02:00
m - > tagwin = XCreateWindow ( dpy , root , m - > wx + sp , m - > by + bh + vp + gappov / 2 , m - > mw / scalepreview ,
2022-09-09 10:15:04 +02:00
m - > mh / scalepreview , 0 , DefaultDepth ( dpy , screen ) , CopyFromParent ,
DefaultVisual ( dpy , screen ) , CWOverrideRedirect | CWBackPixmap | CWEventMask , & wa ) ;
XDefineCursor ( dpy , m - > tagwin , cursor [ CurNormal ] - > cursor ) ;
XUnmapWindow ( dpy , m - > tagwin ) ;
}
2022-09-09 11:13:25 +02:00
# endif
2022-08-21 11:53:18 +02:00
if ( m - > barwin )
continue ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
w = m - > ww ;
if ( showsystray & & m = = systraytomon ( m ) )
w - = getsystraywidth ( ) ;
# endif
2022-08-21 11:53:18 +02:00
m - > barwin = XCreateWindow ( dpy , root , m - > wx + sp , m - > by + vp , m - > ww - 2 * sp , bh , 0 , depth ,
2022-10-02 15:34:11 +02:00
//m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen),
2022-08-21 11:53:18 +02:00
InputOutput , visual ,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask , & wa ) ;
XDefineCursor ( dpy , m - > barwin , cursor [ CurNormal ] - > cursor ) ;
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
if ( showsystray & & m = = systraytomon ( m ) )
XMapRaised ( dpy , systray - > win ) ;
# endif
2022-08-21 11:53:18 +02:00
XMapRaised ( dpy , m - > barwin ) ;
XSetClassHint ( dpy , m - > barwin , & ch ) ;
}
}
void
updatebarpos ( Monitor * m )
{
m - > wy = m - > my ;
m - > wh = m - > mh ;
2022-10-02 15:34:11 +02:00
if ( m - > showbar ) {
m - > wh = m - > wh - barpaddingv - bh ;
2022-08-21 11:53:18 +02:00
m - > by = m - > barposition ? m - > wy : m - > wy + m - > wh + barpaddingv ;
2022-10-02 15:34:11 +02:00
m - > wy = m - > barposition ? m - > wy + bh + vp : m - > wy ;
2022-08-21 11:53:18 +02:00
} else
2022-10-02 15:34:11 +02:00
m - > by = - bh - vp ;
2022-08-21 11:53:18 +02: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 ) ;
XDeleteProperty ( dpy , root , netatom [ NetClientListStacking ] ) ;
for ( m = mons ; m ; m = m - > next )
for ( c = m - > stack ; c ; c = c - > snext )
XChangeProperty ( dpy , root , netatom [ NetClientListStacking ] ,
XA_WINDOW , 32 , PropModeAppend ,
( unsigned char * ) & ( c - > win ) , 1 ) ;
}
void updatecurrentdesktop ( void ) {
long rawdata [ ] = { selmon - > tagset [ selmon - > seltags ] } ;
int i = 0 ;
while ( * rawdata > > ( i + 1 ) ) {
i + + ;
}
long data [ ] = { i } ;
XChangeProperty ( dpy , root , netatom [ NetCurrentDesktop ] , XA_CARDINAL , 32 , PropModeReplace , ( unsigned char * ) data , 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 ;
sortscreens ( unique , nn ) ;
if ( n < = nn ) { /* new monitors available */
for ( i = 0 ; i < ( nn - n ) ; 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 ) ;
}
} else { /* less monitors available nn < n */
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 ;
switch ( attachdirection ) {
case 1 :
attachabove ( c ) ;
break ;
case 2 :
attachaside ( c ) ;
break ;
case 3 :
attachbelow ( c ) ;
break ;
case 4 :
attachbottom ( c ) ;
break ;
case 5 :
attachtop ( c ) ;
break ;
default :
attach ( c ) ;
}
attachstack ( c ) ;
}
if ( m = = selmon )
selmon = mons ;
cleanupmon ( m ) ;
}
}
free ( unique ) ;
} else
# endif /* XINERAMA */
{ /* default monitor setup */
if ( ! mons )
mons = createmon ( ) ;
if ( mons - > mw ! = tw | | mons - > mh ! = sh ) {
dirty = 1 ;
mons - > mw = mons - > ww = tw ;
mons - > mh = mons - > wh = sh ;
updatebarpos ( mons ) ;
}
}
if ( dirty ) {
selmon = mons ;
selmon = wintomon ( root ) ;
}
return dirty ;
}
void
updatemotifhints ( Client * c )
{
Atom real ;
int format ;
unsigned char * p = NULL ;
unsigned long n , extra ;
unsigned long * motif ;
int width , height ;
if ( ! decorhints )
return ;
if ( XGetWindowProperty ( dpy , c - > win , motifatom , 0L , 5L , False , motifatom ,
& real , & format , & n , & extra , & p ) = = Success & & p ! = NULL ) {
motif = ( unsigned long * ) p ;
if ( motif [ MWM_HINTS_FLAGS_FIELD ] & MWM_HINTS_DECORATIONS ) {
width = WIDTH ( c ) ;
height = HEIGHT ( c ) ;
if ( motif [ MWM_HINTS_DECORATIONS_FIELD ] & MWM_DECOR_ALL | |
motif [ MWM_HINTS_DECORATIONS_FIELD ] & MWM_DECOR_BORDER | |
motif [ MWM_HINTS_DECORATIONS_FIELD ] & MWM_DECOR_TITLE )
c - > bw = c - > oldbw = borderpx ;
else
c - > bw = c - > oldbw = 0 ;
resize ( c , c - > x , c - > y , width - ( 2 * c - > bw ) , height - ( 2 * c - > bw ) , 0 ) ;
}
XFree ( p ) ;
}
}
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 ) ;
2022-09-10 23:49:22 +02:00
c - > hintsvalid = 1 ;
2022-08-21 11:53:18 +02:00
}
void
updatestatus ( void )
{
Monitor * m ;
2022-09-08 16:03:56 +02:00
if ( ! gettextprop ( root , XA_WM_NAME , rawstext , sizeof ( rawstext ) ) & & ! hidestatus ) {
2022-09-16 22:13:39 +02:00
strcpy ( stext , defaultstatus ) ;
2022-08-27 21:49:51 +02:00
statusw = TEXTW ( stext ) - lrpad + 2 ;
} else {
2022-09-08 16:03:56 +02:00
if ( ! hidestatus ) {
2022-08-21 11:53:18 +02:00
copyvalidchars ( stext , rawstext ) ;
2022-08-27 21:49:51 +02:00
char * text , * s , ch ;
statusw = 0 ;
for ( text = s = stext ; * s ; s + + ) {
if ( ( unsigned char ) ( * s ) < ' ' ) {
ch = * s ;
* s = ' \0 ' ;
statusw + = TEXTW ( text ) - lrpad ;
* s = ch ;
text = s + 1 ;
}
}
statusw + = TEXTW ( text ) - lrpad + 2 ;
}
2022-09-08 16:03:56 +02:00
}
2022-08-21 11:53:18 +02:00
if ( statusallmons ) {
for ( m = mons ; m ; m = m - > next )
drawbar ( m ) ;
} else {
drawbar ( selmon ) ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
updatesystray ( ) ;
# endif
2022-08-21 11:53:18 +02:00
}
void
updaterules ( Client * c )
{
if ( refreshrules )
{
const char * class , * instance ;
unsigned int i ;
const Rule * r ;
Monitor * m ;
XClassHint ch = { NULL , NULL } ;
/* rule matching */
XGetClassHint ( dpy , c - > win , & ch ) ;
2022-10-06 09:52:35 +02:00
class = ch . res_class ? ch . res_class : notitle ;
instance = ch . res_name ? ch . res_name : notitle ;
2022-08-21 11:53:18 +02:00
char found_rule = 0 ;
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 ) ) )
{
c - > isfloating = r - > isfloating ;
if ( ! found_rule )
{
c - > tags = 0 ;
found_rule = 1 ;
}
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 ] ;
// end apply rules
if ( c - > isfloating )
resize ( c , c - > x , c - > y ,
c - > w , c - > h , 0 ) ;
arrange ( c - > mon ) ;
}
}
void
updatetitle ( Client * c )
{
2022-08-26 11:41:11 +02:00
# if USEIPC
char oldname [ sizeof ( c - > name ) ] ;
strcpy ( oldname , c - > name ) ;
# endif
2022-08-21 11:53:18 +02:00
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 ' )
2022-10-06 09:52:35 +02:00
strcpy ( c - > name , notitle ) ;
2022-08-26 11:41:11 +02:00
# if USEIPC
for ( Monitor * m = mons ; m ; m = m - > next ) {
if ( m - > sel = = c & & strcmp ( oldname , c - > name ) ! = 0 )
ipc_focused_title_change_event ( m - > num , c - > win , oldname , c - > name ) ;
}
# endif
2022-08-21 11:53:18 +02:00
}
2022-09-03 17:05:20 +02:00
# if USEWINICON
2022-08-21 11:53:18 +02:00
void
updateicon ( Client * c )
{
freeicon ( c ) ;
c - > icon = geticonprop ( c - > win , & c - > icw , & c - > ich ) ;
}
2022-09-03 17:05:20 +02:00
# endif
2022-08-21 11:53:18 +02:00
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
void
updatepreview ( void )
{
Monitor * m ;
XSetWindowAttributes wa = {
. background_pixel = 0 ,
. border_pixel = 0 ,
. colormap = cmap ,
. override_redirect = True ,
. event_mask = ButtonPressMask | ExposureMask
} ;
for ( m = mons ; m ; m = m - > next ) {
2022-10-03 02:57:15 +02:00
m - > tagwin = XCreateWindow ( dpy , root , m - > wx + sp + tagpreviewpaddingh , m - > by + bh + vp + tagpreviewpaddingv + gappov / 2 , m - > mw / scalepreview , m - > mh / scalepreview , 0 ,
2022-08-21 11:53:18 +02:00
depth , CopyFromParent , visual ,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask , & wa ) ;
XDefineCursor ( dpy , m - > tagwin , cursor [ CurNormal ] - > cursor ) ;
XMapRaised ( dpy , m - > tagwin ) ;
XUnmapWindow ( dpy , m - > tagwin ) ;
}
}
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
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 ) ;
}
}
void
view ( const Arg * arg )
{
Monitor * m ;
int i ;
unsigned int tmptag ;
if ( arg - > ui & & ( arg - > ui & TAGMASK ) = = selmon - > tagset [ selmon - > seltags ] )
return ;
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-09-09 10:07:24 +02:00
takepreview ( ) ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02:00
for ( m = mons ; m ; m = m - > next )
m - > seltags ^ = 1 ;
if ( arg - > ui & TAGMASK ) {
2022-10-13 22:54:05 +02:00
for ( m = mons ; m ; m = m - > next )
m - > tagset [ m - > seltags ] = arg - > ui & TAGMASK ;
2022-08-21 11:53:18 +02:00
2022-10-13 22:54:05 +02:00
if ( pertag ) {
selmon - > pertag - > prevtag = selmon - > pertag - > curtag ;
2022-10-05 14:23:01 +02:00
2022-10-13 22:54:05 +02:00
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 ;
2022-08-21 11:53:18 +02:00
selmon - > pertag - > prevtag = selmon - > pertag - > curtag ;
selmon - > pertag - > curtag = tmptag ;
}
2022-10-13 22:54:05 +02:00
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 ] ;
2022-08-21 11:53:18 +02:00
if ( selmon - > showbar ! = selmon - > pertag - > showbars [ selmon - > pertag - > curtag ] )
togglebar ( NULL ) ;
}
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-25 16:33:13 +02:00
XUnmapWindow ( dpy , selmon - > tagwin ) ;
2022-09-09 10:07:24 +02:00
# endif
2022-08-21 11:53:18 +02:00
focus ( NULL ) ;
arrange ( NULL ) ;
updatecurrentdesktop ( ) ;
}
void
warp ( const Client * c )
{
int x , y ;
if ( ! c ) {
XWarpPointer ( dpy , None , root , 0 , 0 , 0 , 0 , selmon - > wx + selmon - > ww / 2 , selmon - > wy + selmon - > wh / 2 ) ;
return ;
}
if ( ! getrootptr ( & x , & y ) | |
( x > c - > x - c - > bw & &
y > c - > y - c - > bw & &
x < c - > x + c - > w + c - > bw * 2 & &
y < c - > y + c - > h + c - > bw * 2 ) | |
( y > c - > mon - > by & & y < c - > mon - > by + bh ) | |
( c - > mon - > barposition & & ! y ) )
return ;
XWarpPointer ( dpy , None , c - > win , 0 , 0 , 0 , 0 , c - > w / 2 , c - > h / 2 ) ;
}
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 ;
if ( fscanf ( f , " %*u %*s %*c %u " , ( unsigned * ) & v ) ! = 1 )
v = ( pid_t ) 0 ;
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 ;
}
2022-10-02 15:34:11 +02:00
# if USESYSTRAY
void
updatesystrayicongeom ( Client * i , int w , int h )
{
if ( i ) {
i - > h = bh ;
if ( w = = h )
i - > w = bh ;
else if ( h = = bh )
i - > w = w ;
else
i - > w = ( int ) ( ( float ) bh * ( ( float ) w / ( float ) h ) ) ;
applysizehints ( i , & ( i - > x ) , & ( i - > y ) , & ( i - > w ) , & ( i - > h ) , False ) ;
/* force icons into the systray dimensions if they don't want to */
if ( i - > h > bh ) {
if ( i - > w = = i - > h )
i - > w = bh ;
else
i - > w = ( int ) ( ( float ) bh * ( ( float ) i - > w / ( float ) i - > h ) ) ;
i - > h = bh ;
}
}
}
void
updatesystrayiconstate ( Client * i , XPropertyEvent * ev )
{
long flags ;
int code = 0 ;
if ( ! showsystray | | ! i | | ev - > atom ! = xatom [ XembedInfo ] | |
! ( flags = getatomprop ( i , xatom [ XembedInfo ] ) ) )
return ;
if ( flags & XEMBED_MAPPED & & ! i - > tags ) {
i - > tags = 1 ;
code = XEMBED_WINDOW_ACTIVATE ;
XMapRaised ( dpy , i - > win ) ;
setclientstate ( i , NormalState ) ;
}
else if ( ! ( flags & XEMBED_MAPPED ) & & i - > tags ) {
i - > tags = 0 ;
code = XEMBED_WINDOW_DEACTIVATE ;
XUnmapWindow ( dpy , i - > win ) ;
setclientstate ( i , WithdrawnState ) ;
}
else
return ;
sendevent ( i - > win , xatom [ Xembed ] , StructureNotifyMask , CurrentTime , code , 0 ,
systray - > win , XEMBED_EMBEDDED_VERSION ) ;
}
void
updatesystray ( void )
{
XSetWindowAttributes wa ;
XWindowChanges wc ;
Client * i ;
Monitor * m = systraytomon ( NULL ) ;
unsigned int x = m - > mx + m - > mw - sp ;
unsigned int y = m - > by + vp ;
unsigned int sw = TEXTW ( stext ) - lrpad + systrayspacing ;
unsigned int w = 1 ;
if ( ! showsystray )
return ;
if ( systrayonleft )
x - = sw + lrpad / 2 ;
if ( ! systray ) {
/* init systray */
if ( ! ( systray = ( Systray * ) calloc ( 1 , sizeof ( Systray ) ) ) )
die ( " fatal: could not malloc() %u bytes \n " , sizeof ( Systray ) ) ;
2022-10-06 08:22:06 +02:00
systray - > win = XCreateSimpleWindow ( dpy , root , x , y , w , bh , 0 , 0 , scheme [ SchemeSystray ] [ ColBg ] . pixel ) ;
2022-10-02 15:34:11 +02:00
wa . event_mask = ButtonPressMask | ExposureMask ;
wa . override_redirect = True ;
2022-10-06 08:22:06 +02:00
wa . background_pixel = scheme [ SchemeSystray ] [ ColBg ] . pixel ;
2022-10-02 15:34:11 +02:00
XSelectInput ( dpy , systray - > win , SubstructureNotifyMask ) ;
XChangeProperty ( dpy , systray - > win , netatom [ NetSystemTrayOrientation ] , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) & netatom [ NetSystemTrayOrientationHorz ] , 1 ) ;
XChangeWindowAttributes ( dpy , systray - > win , CWEventMask | CWOverrideRedirect | CWBackPixel , & wa ) ;
XMapRaised ( dpy , systray - > win ) ;
XSetSelectionOwner ( dpy , netatom [ NetSystemTray ] , systray - > win , CurrentTime ) ;
if ( XGetSelectionOwner ( dpy , netatom [ NetSystemTray ] ) = = systray - > win ) {
sendevent ( root , xatom [ Manager ] , StructureNotifyMask , CurrentTime , netatom [ NetSystemTray ] , systray - > win , 0 , 0 ) ;
XSync ( dpy , False ) ;
}
else {
2022-10-06 08:22:06 +02:00
fprintf ( stderr , " speedwm: failed to get systray. \n " ) ;
2022-10-02 15:34:11 +02:00
free ( systray ) ;
systray = NULL ;
return ;
}
}
for ( w = 0 , i = systray - > icons ; i ; i = i - > next ) {
/* make sure the background color stays the same */
2022-10-06 08:22:06 +02:00
wa . background_pixel = scheme [ SchemeSystray ] [ ColBg ] . pixel ;
2022-10-02 15:34:11 +02:00
XChangeWindowAttributes ( dpy , i - > win , CWBackPixel , & wa ) ;
XMapRaised ( dpy , i - > win ) ;
w + = systrayspacing ;
i - > x = w ;
XMoveResizeWindow ( dpy , i - > win , i - > x , 0 , i - > w , i - > h ) ;
w + = i - > w ;
if ( i - > mon ! = m )
i - > mon = m ;
}
w = w ? w + systrayspacing : 1 ;
x - = w ;
XMoveResizeWindow ( dpy , systray - > win , x , m - > by , w , bh ) ;
wc . x = x ; wc . y = y ; wc . width = w ; wc . height = bh ;
wc . stack_mode = Above ; wc . sibling = m - > barwin ;
XConfigureWindow ( dpy , systray - > win , CWX | CWY | CWWidth | CWHeight | CWSibling | CWStackMode , & wc ) ;
XMapWindow ( dpy , systray - > win ) ;
XMapSubwindows ( dpy , systray - > win ) ;
/* redraw background */
2022-10-06 08:22:06 +02:00
XSetForeground ( dpy , drw - > gc , scheme [ SchemeSystray ] [ ColBg ] . pixel ) ;
2022-10-03 01:36:47 +02:00
//XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); // vanilla
XFillRectangle ( dpy , systray - > win , XCreateGC ( dpy , root , 0 , NULL ) , 0 , 0 , w , bh ) ;
2022-10-02 15:34:11 +02:00
XSync ( dpy , False ) ;
}
Client *
wintosystrayicon ( Window w ) {
Client * i = NULL ;
if ( ! showsystray | | ! w )
return i ;
for ( i = systray - > icons ; i & & i - > win ! = w ; i = i - > next ) ;
return i ;
}
Monitor *
systraytomon ( Monitor * m ) {
Monitor * t ;
int i , n ;
if ( ! systraypinning ) {
if ( ! m )
return selmon ;
return m = = selmon ? m : NULL ;
}
for ( n = 1 , t = mons ; t & & t - > next ; n + + , t = t - > next ) ;
for ( i = 1 , t = mons ; t & & t - > next & & i < systraypinning ; i + + , t = t - > next ) ;
if ( systraypinningfailfirst & & n < systraypinning )
return mons ;
return t ;
}
# endif
2022-08-21 11:53:18 +02: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 )
if ( w = = m - > barwin | | w = = m - > traywin )
return m ;
if ( ( c = wintoclient ( w ) ) )
return c - > mon ;
return selmon ;
}
int
wmclasscontains ( Window win , const char * class , const char * name )
{
XClassHint ch = { NULL , NULL } ;
int res = 1 ;
if ( XGetClassHint ( dpy , win , & ch ) ) {
if ( ch . res_name & & strstr ( ch . res_name , name ) = = NULL )
res = 0 ;
if ( ch . res_class & & strstr ( ch . res_class , class ) = = NULL )
res = 0 ;
} else
res = 0 ;
if ( ch . res_class )
XFree ( ch . res_class ) ;
if ( ch . res_name )
XFree ( ch . res_name ) ;
return res ;
}
/* 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 , " speedwm: 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 )
{
2022-08-25 16:33:13 +02:00
die ( " speedwm: Do not start speedwm by running 'speedwm'. Your X session should run 'speedwm_run'. See 'speedwm-help -a' for more information. \n https://codeberg.org/speedie/speedwm " ) ;
2022-08-21 11:53:18 +02:00
return - 1 ;
}
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 ) ;
}
}
void
zoom ( const Arg * arg )
{
Client * c = selmon - > sel ;
2022-09-11 00:46:21 +02:00
if ( ! selmon - > lt [ selmon - > sellt ] - > arrange | | ! c | | c - > isfloating )
return ;
if ( c = = nexttiled ( selmon - > clients ) & & ! ( c = nexttiled ( c - > next ) ) )
2022-08-21 11:53:18 +02:00
return ;
pop ( c ) ;
}
2022-10-05 13:42:45 +02:00
# if USEXRESOURCES
2022-08-21 11:53:18 +02:00
void
resource_load ( XrmDatabase db , char * name , enum resource_type rtype , void * dst )
{
char * sdst = NULL ;
int * idst = NULL ;
float * fdst = NULL ;
sdst = dst ;
idst = dst ;
fdst = dst ;
char fullname [ 256 ] ;
char * type ;
XrmValue ret ;
snprintf ( fullname , sizeof ( fullname ) , " %s.%s " , " speedwm " , name ) ;
fullname [ sizeof ( fullname ) - 1 ] = ' \0 ' ;
XrmGetResource ( db , fullname , " * " , & type , & ret ) ;
if ( ! ( ret . addr = = NULL | | strncmp ( " String " , type , 64 ) ) )
{
switch ( rtype ) {
case STRING :
strcpy ( sdst , ret . addr ) ;
break ;
case INTEGER :
* idst = strtoul ( ret . addr , NULL , 10 ) ;
break ;
case FLOAT :
* fdst = strtof ( ret . addr , NULL ) ;
break ;
}
}
}
void
load_xresources ( void )
{
Display * display ;
char * resm ;
XrmDatabase db ;
ResourcePref * p ;
display = XOpenDisplay ( NULL ) ;
resm = XResourceManagerString ( display ) ;
if ( ! resm )
return ;
db = XrmGetStringDatabase ( resm ) ;
for ( p = resources ; p < resources + LENGTH ( resources ) ; p + + )
resource_load ( db , p - > name , p - > type , p - > dst ) ;
XCloseDisplay ( display ) ;
}
2022-10-05 13:42:45 +02:00
# endif
2022-08-21 11:53:18 +02:00
/* Thanks to https://codeberg.org/explosion-mental/demwm for this! */
void
previewtag ( const Arg * arg )
{
2022-09-03 17:44:49 +02:00
# if USETAGPREVIEW
2022-08-21 11:53:18 +02:00
if ( selmon - > previewshow ! = ( arg - > ui + 1 ) )
selmon - > previewshow = arg - > ui + 1 ;
else
selmon - > previewshow = 0 ;
showtagpreview ( arg - > ui ) ;
2022-09-03 17:44:49 +02:00
# endif
2022-08-21 11:53:18 +02: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 ) ;
}
2022-08-21 16:05:53 +02:00
void
settagsatom ( Window w , unsigned int tags ) {
XChangeProperty ( dpy , w , dwmatom [ DWMTags ] , XA_CARDINAL , 32 ,
PropModeReplace , ( unsigned char * ) & tags , 1 ) ;
}
2022-08-21 11:53:18 +02:00
int
main ( int argc , char * argv [ ] )
{
if ( argc = = 2 & & ! strcmp ( " -v " , argv [ 1 ] ) )
die ( " speedwm- " VERSION ) ;
else if ( argc ! = 1 )
die ( " usage: speedwm [-v] " ) ;
if ( ! setlocale ( LC_CTYPE , " " ) | | ! XSupportsLocale ( ) )
fputs ( " warning: no locale support \n " , stderr ) ;
if ( ! ( dpy = XOpenDisplay ( NULL ) ) )
die ( " speedwm: cannot open display " ) ;
if ( ! ( xcon = XGetXCBConnection ( dpy ) ) )
die ( " speedwm: cannot get xcb connection \n " ) ;
checkotherwm ( ) ;
autostart_exec ( ) ;
XrmInitialize ( ) ;
2022-10-05 13:42:45 +02:00
# if USEXRESOURCES
2022-08-21 11:53:18 +02:00
load_xresources ( ) ;
2022-10-05 13:42:45 +02:00
# endif
2022-08-21 11:53:18 +02:00
setup ( ) ;
# ifdef __OpenBSD__
if ( pledge ( " stdio rpath proc exec ps " , NULL ) = = - 1 )
die ( " pledge " ) ;
# endif /* __OpenBSD__ */
scan ( ) ;
run ( ) ;
if ( restart ) execvp ( argv [ 0 ] , argv ) ;
cleanup ( ) ;
XCloseDisplay ( dpy ) ;
return EXIT_SUCCESS ;
}
void
insertclient ( Client * item , Client * insertItem , int after ) {
Client * c ;
if ( item = = NULL | | insertItem = = NULL | | item = = insertItem ) return ;
detach ( insertItem ) ;
if ( ! after & & selmon - > clients = = item ) {
attach ( insertItem ) ;
return ;
}
if ( after ) {
c = item ;
} else {
for ( c = selmon - > clients ; c ; c = c - > next ) { if ( c - > next = = item ) break ; }
}
insertItem - > next = c - > next ;
c - > next = insertItem ;
}
void
inplacerotate ( const Arg * arg )
{
if ( ! selmon - > sel | | ( selmon - > sel - > isfloating & & ! arg - > f ) ) return ;
unsigned int selidx = 0 , i = 0 ;
Client * c = NULL , * stail = NULL , * mhead = NULL , * mtail = NULL , * shead = NULL ;
// Determine positionings for insertclient
for ( c = selmon - > clients ; c ; c = c - > next ) {
if ( ISVISIBLE ( c ) & & ! ( c - > isfloating ) ) {
if ( selmon - > sel = = c ) { selidx = i ; }
if ( i = = selmon - > nmaster - 1 ) { mtail = c ; }
if ( i = = selmon - > nmaster ) { shead = c ; }
if ( mhead = = NULL ) { mhead = c ; }
stail = c ;
i + + ;
}
}
// All clients rotate
if ( arg - > i = = 2 ) insertclient ( selmon - > clients , stail , 0 ) ;
if ( arg - > i = = - 2 ) insertclient ( stail , selmon - > clients , 1 ) ;
// Stack xor master rotate
if ( arg - > i = = - 1 & & selidx > = selmon - > nmaster ) insertclient ( stail , shead , 1 ) ;
if ( arg - > i = = 1 & & selidx > = selmon - > nmaster ) insertclient ( shead , stail , 0 ) ;
if ( arg - > i = = - 1 & & selidx < selmon - > nmaster ) insertclient ( mtail , mhead , 1 ) ;
if ( arg - > i = = 1 & & selidx < selmon - > nmaster ) insertclient ( mhead , mtail , 0 ) ;
// Restore focus position
i = 0 ;
for ( c = selmon - > clients ; c ; c = c - > next ) {
if ( ! ISVISIBLE ( c ) | | ( c - > isfloating ) ) continue ;
if ( i = = selidx ) { focus ( c ) ; break ; }
i + + ;
}
arrange ( selmon ) ;
focus ( c ) ;
}