Compare commits
	
		
			9 Commits
		
	
	
		
			master
			...
			5cb7791680
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 5cb7791680 | ||
|   | 68e1b709c0 | ||
|   | 25fb7fc1b1 | ||
|   | 1dce644122 | ||
|   | c38c736add | ||
|   | 51f20203eb | ||
|   | 41a035f450 | ||
|   | 849093159a | ||
|   | a0ea960f7b | 
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,2 +1,5 @@ | ||||
| dwm | ||||
| *.o | ||||
| dwm | ||||
| patches/ | ||||
| *.rej | ||||
| *.orig | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| patches | ||||
| @@ -1 +0,0 @@ | ||||
| series | ||||
| @@ -1 +0,0 @@ | ||||
| 2 | ||||
| @@ -1,4 +0,0 @@ | ||||
| dwm-swallow-6.3.diff | ||||
| dwm-hide_vacant_tags-6.4.diff | ||||
| dwm-pertag-20200914-61bb8b2.diff | ||||
| dwm-statuscmd-20241009-8933ebc.diff | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,120 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
|  | ||||
| /* appearance */ | ||||
| static const unsigned int borderpx  = 1;        /* border pixel of windows */ | ||||
| static const unsigned int snap      = 32;       /* snap pixel */ | ||||
| static const int swallowfloating    = 0;        /* 1 means swallow floating windows by default */ | ||||
| static const int showbar            = 1;        /* 0 means no bar */ | ||||
| static const int topbar             = 1;        /* 0 means bottom bar */ | ||||
| static const char *fonts[]          = { "monospace:size=10" }; | ||||
| static const char dmenufont[]       = "monospace:size=10"; | ||||
| static const char col_gray1[]       = "#222222"; | ||||
| static const char col_gray2[]       = "#444444"; | ||||
| static const char col_gray3[]       = "#bbbbbb"; | ||||
| static const char col_gray4[]       = "#eeeeee"; | ||||
| static const char col_cyan[]        = "#005577"; | ||||
| static const char *colors[][3]      = { | ||||
| 	/*               fg         bg         border   */ | ||||
| 	[SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, | ||||
| 	[SchemeSel]  = { col_gray4, col_cyan,  col_cyan  }, | ||||
| }; | ||||
|  | ||||
| /* tagging */ | ||||
| static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; | ||||
|  | ||||
| static const Rule rules[] = { | ||||
| 	/* xprop(1): | ||||
| 	 *	WM_CLASS(STRING) = instance, class | ||||
| 	 *	WM_NAME(STRING) = title | ||||
| 	 */ | ||||
| 	/* class     instance  title           tags mask  isfloating  isterminal  noswallow  monitor */ | ||||
| 	{ "Gimp",    NULL,     NULL,           0,         1,          0,           0,        -1 }, | ||||
| 	{ "Firefox", NULL,     NULL,           1 << 8,    0,          0,          -1,        -1 }, | ||||
| 	{ "St",      NULL,     NULL,           0,         0,          1,           0,        -1 }, | ||||
| 	{ NULL,      NULL,     "Event Tester", 0,         0,          0,           1,        -1 }, /* xev */ | ||||
| }; | ||||
|  | ||||
| /* layout(s) */ | ||||
| static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */ | ||||
| static const int nmaster     = 1;    /* number of clients in master area */ | ||||
| static const int resizehints = 1;    /* 1 means respect size hints in tiled resizals */ | ||||
| static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ | ||||
| static const int refreshrate = 120;  /* refresh rate (per second) for client move/resize */ | ||||
|  | ||||
| static const Layout layouts[] = { | ||||
| 	/* symbol     arrange function */ | ||||
| 	{ "[]=",      tile },    /* first entry is default */ | ||||
| 	{ "><>",      NULL },    /* no layout function means floating behavior */ | ||||
| 	{ "[M]",      monocle }, | ||||
| }; | ||||
|  | ||||
| /* key definitions */ | ||||
| #define MODKEY Mod1Mask | ||||
| #define TAGKEYS(KEY,TAG) \ | ||||
| 	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \ | ||||
| 	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \ | ||||
| 	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \ | ||||
| 	{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} }, | ||||
|  | ||||
| /* helper for spawning shell commands in the pre dwm-5.0 fashion */ | ||||
| #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | ||||
|  | ||||
| /* commands */ | ||||
| static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | ||||
| static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; | ||||
| static const char *termcmd[]  = { "st", NULL }; | ||||
|  | ||||
| static const Key keys[] = { | ||||
| 	/* modifier                     key        function        argument */ | ||||
| 	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } }, | ||||
| 	{ MODKEY,                       XK_b,      togglebar,      {0} }, | ||||
| 	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } }, | ||||
| 	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } }, | ||||
| 	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } }, | ||||
| 	{ MODKEY,                       XK_d,      incnmaster,     {.i = -1 } }, | ||||
| 	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} }, | ||||
| 	{ MODKEY,                       XK_l,      setmfact,       {.f = +0.05} }, | ||||
| 	{ MODKEY,                       XK_Return, zoom,           {0} }, | ||||
| 	{ MODKEY,                       XK_Tab,    view,           {0} }, | ||||
| 	{ MODKEY|ShiftMask,             XK_c,      killclient,     {0} }, | ||||
| 	{ MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} }, | ||||
| 	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} }, | ||||
| 	{ MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} }, | ||||
| 	{ MODKEY,                       XK_space,  setlayout,      {0} }, | ||||
| 	{ MODKEY|ShiftMask,             XK_space,  togglefloating, {0} }, | ||||
| 	{ MODKEY,                       XK_0,      view,           {.ui = ~0 } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } }, | ||||
| 	{ MODKEY,                       XK_comma,  focusmon,       {.i = -1 } }, | ||||
| 	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } }, | ||||
| 	TAGKEYS(                        XK_1,                      0) | ||||
| 	TAGKEYS(                        XK_2,                      1) | ||||
| 	TAGKEYS(                        XK_3,                      2) | ||||
| 	TAGKEYS(                        XK_4,                      3) | ||||
| 	TAGKEYS(                        XK_5,                      4) | ||||
| 	TAGKEYS(                        XK_6,                      5) | ||||
| 	TAGKEYS(                        XK_7,                      6) | ||||
| 	TAGKEYS(                        XK_8,                      7) | ||||
| 	TAGKEYS(                        XK_9,                      8) | ||||
| 	{ MODKEY|ShiftMask,             XK_q,      quit,           {0} }, | ||||
| }; | ||||
|  | ||||
| /* button definitions */ | ||||
| /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ | ||||
| static const Button buttons[] = { | ||||
| 	/* click                event mask      button          function        argument */ | ||||
| 	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} }, | ||||
| 	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} }, | ||||
| 	{ ClkWinTitle,          0,              Button2,        zoom,           {0} }, | ||||
| 	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} }, | ||||
| 	{ ClkTagBar,            0,              Button1,        view,           {0} }, | ||||
| 	{ ClkTagBar,            0,              Button3,        toggleview,     {0} }, | ||||
| 	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} }, | ||||
| 	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} }, | ||||
| }; | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,117 +0,0 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
|  | ||||
| /* appearance */ | ||||
| static const unsigned int borderpx  = 1;        /* border pixel of windows */ | ||||
| static const unsigned int snap      = 32;       /* snap pixel */ | ||||
| static const int showbar            = 1;        /* 0 means no bar */ | ||||
| static const int topbar             = 1;        /* 0 means bottom bar */ | ||||
| static const char *fonts[]          = { "monospace:size=10" }; | ||||
| static const char dmenufont[]       = "monospace:size=10"; | ||||
| static const char col_gray1[]       = "#222222"; | ||||
| static const char col_gray2[]       = "#444444"; | ||||
| static const char col_gray3[]       = "#bbbbbb"; | ||||
| static const char col_gray4[]       = "#eeeeee"; | ||||
| static const char col_cyan[]        = "#005577"; | ||||
| static const char *colors[][3]      = { | ||||
| 	/*               fg         bg         border   */ | ||||
| 	[SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, | ||||
| 	[SchemeSel]  = { col_gray4, col_cyan,  col_cyan  }, | ||||
| }; | ||||
|  | ||||
| /* tagging */ | ||||
| static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; | ||||
|  | ||||
| static const Rule rules[] = { | ||||
| 	/* xprop(1): | ||||
| 	 *	WM_CLASS(STRING) = instance, class | ||||
| 	 *	WM_NAME(STRING) = title | ||||
| 	 */ | ||||
| 	/* class      instance    title       tags mask     isfloating   monitor */ | ||||
| 	{ "Gimp",     NULL,       NULL,       0,            1,           -1 }, | ||||
| 	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 }, | ||||
| }; | ||||
|  | ||||
| /* layout(s) */ | ||||
| static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */ | ||||
| static const int nmaster     = 1;    /* number of clients in master area */ | ||||
| static const int resizehints = 1;    /* 1 means respect size hints in tiled resizals */ | ||||
| static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ | ||||
| static const int refreshrate = 120;  /* refresh rate (per second) for client move/resize */ | ||||
|  | ||||
| static const Layout layouts[] = { | ||||
| 	/* symbol     arrange function */ | ||||
| 	{ "[]=",      tile },    /* first entry is default */ | ||||
| 	{ "><>",      NULL },    /* no layout function means floating behavior */ | ||||
| 	{ "[M]",      monocle }, | ||||
| }; | ||||
|  | ||||
| /* key definitions */ | ||||
| #define MODKEY Mod1Mask | ||||
| #define TAGKEYS(KEY,TAG) \ | ||||
| 	{ MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \ | ||||
| 	{ MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \ | ||||
| 	{ MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \ | ||||
| 	{ MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} }, | ||||
|  | ||||
| /* helper for spawning shell commands in the pre dwm-5.0 fashion */ | ||||
| #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | ||||
|  | ||||
| /* commands */ | ||||
| static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | ||||
| static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; | ||||
| static const char *termcmd[]  = { "st", NULL }; | ||||
|  | ||||
| static const Key keys[] = { | ||||
| 	/* modifier                     key        function        argument */ | ||||
| 	{ MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } }, | ||||
| 	{ MODKEY,                       XK_b,      togglebar,      {0} }, | ||||
| 	{ MODKEY,                       XK_j,      focusstack,     {.i = +1 } }, | ||||
| 	{ MODKEY,                       XK_k,      focusstack,     {.i = -1 } }, | ||||
| 	{ MODKEY,                       XK_i,      incnmaster,     {.i = +1 } }, | ||||
| 	{ MODKEY,                       XK_d,      incnmaster,     {.i = -1 } }, | ||||
| 	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} }, | ||||
| 	{ MODKEY,                       XK_l,      setmfact,       {.f = +0.05} }, | ||||
| 	{ MODKEY,                       XK_Return, zoom,           {0} }, | ||||
| 	{ MODKEY,                       XK_Tab,    view,           {0} }, | ||||
| 	{ MODKEY|ShiftMask,             XK_c,      killclient,     {0} }, | ||||
| 	{ MODKEY,                       XK_t,      setlayout,      {.v = &layouts[0]} }, | ||||
| 	{ MODKEY,                       XK_f,      setlayout,      {.v = &layouts[1]} }, | ||||
| 	{ MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} }, | ||||
| 	{ MODKEY,                       XK_space,  setlayout,      {0} }, | ||||
| 	{ MODKEY|ShiftMask,             XK_space,  togglefloating, {0} }, | ||||
| 	{ MODKEY,                       XK_0,      view,           {.ui = ~0 } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } }, | ||||
| 	{ MODKEY,                       XK_comma,  focusmon,       {.i = -1 } }, | ||||
| 	{ MODKEY,                       XK_period, focusmon,       {.i = +1 } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } }, | ||||
| 	{ MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } }, | ||||
| 	TAGKEYS(                        XK_1,                      0) | ||||
| 	TAGKEYS(                        XK_2,                      1) | ||||
| 	TAGKEYS(                        XK_3,                      2) | ||||
| 	TAGKEYS(                        XK_4,                      3) | ||||
| 	TAGKEYS(                        XK_5,                      4) | ||||
| 	TAGKEYS(                        XK_6,                      5) | ||||
| 	TAGKEYS(                        XK_7,                      6) | ||||
| 	TAGKEYS(                        XK_8,                      7) | ||||
| 	TAGKEYS(                        XK_9,                      8) | ||||
| 	{ MODKEY|ShiftMask,             XK_q,      quit,           {0} }, | ||||
| }; | ||||
|  | ||||
| /* button definitions */ | ||||
| /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ | ||||
| static const Button buttons[] = { | ||||
| 	/* click                event mask      button          function        argument */ | ||||
| 	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} }, | ||||
| 	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} }, | ||||
| 	{ ClkWinTitle,          0,              Button2,        zoom,           {0} }, | ||||
| 	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} }, | ||||
| 	{ ClkTagBar,            0,              Button1,        view,           {0} }, | ||||
| 	{ ClkTagBar,            0,              Button3,        toggleview,     {0} }, | ||||
| 	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} }, | ||||
| 	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} }, | ||||
| }; | ||||
|  | ||||
| @@ -1,39 +0,0 @@ | ||||
| # dwm version | ||||
| VERSION = 6.6 | ||||
|  | ||||
| # Customize below to fit your system | ||||
|  | ||||
| # paths | ||||
| PREFIX = /usr/local | ||||
| MANPREFIX = ${PREFIX}/share/man | ||||
|  | ||||
| X11INC = /usr/X11R6/include | ||||
| X11LIB = /usr/X11R6/lib | ||||
|  | ||||
| # Xinerama, comment if you don't want it | ||||
| XINERAMALIBS  = -lXinerama | ||||
| XINERAMAFLAGS = -DXINERAMA | ||||
|  | ||||
| # freetype | ||||
| FREETYPELIBS = -lfontconfig -lXft | ||||
| FREETYPEINC = /usr/include/freetype2 | ||||
| # OpenBSD (uncomment) | ||||
| #FREETYPEINC = ${X11INC}/freetype2 | ||||
| #MANPREFIX = ${PREFIX}/man | ||||
|  | ||||
| # includes and libs | ||||
| INCS = -I${X11INC} -I${FREETYPEINC} | ||||
| LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} | ||||
|  | ||||
| # flags | ||||
| CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} | ||||
| #CFLAGS   = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} | ||||
| CFLAGS   = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} | ||||
| LDFLAGS  = ${LIBS} | ||||
|  | ||||
| # Solaris | ||||
| #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" | ||||
| #LDFLAGS = ${LIBS} | ||||
|  | ||||
| # compiler and linker | ||||
| CC = cc | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										68
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,20 +1,60 @@ | ||||
| # dwm - dynamic window manager - Mike's build | ||||
| # Changes in this build | ||||
|  | ||||
| ## Patches Applied | ||||
| ## Patches | ||||
|  | ||||
| * [Swallow](https://dwm.suckless.org/patches/swallow/) *Note: I had to change "St" in my config.h to "st" for this to work with st* | ||||
| * [Hide Vacant Tags](https://dwm.suckless.org/patches/hide_vacant_tags/) | ||||
| * [Pertag](https://dwm.suckless.org/patches/pertag/) | ||||
| * [statuscmd](https://dwm.suckless.org/patches/statuscmd/) *Note: intended to be used with [dwmblocks](https://git.mjwilson.org/mike/dwmblocks-async)* | ||||
| #### [Swallow](https://dwm.suckless.org/patches/swallow/)  | ||||
| 1. `git apply --reject <diff file>` | ||||
| 2. Manually apply any failed hunks | ||||
| 3. Add your terminal of choice to your config.h (simply copy the St line from the patch) | ||||
|  | ||||
| ### Patch Management | ||||
| #### [Hide Vacant Tags](https://dwm.suckless.org/patches/hide_vacant_tags/) | ||||
| 1. `git apply <diff file>` | ||||
|  | ||||
| Patches are applied using [Quilt](https://savannah.nongnu.org/projects/quilt/quilt/), which is a patch manager that allows you to easily apply multiple patches, revert specific patches, etc. It makes customizing suckless projects much easier since most changes are done via patches. | ||||
| dwm - dynamic window manager | ||||
| ============================ | ||||
| dwm is an extremely fast, small, and dynamic window manager for X. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| ```sh | ||||
| git clone https://git.mjwilson.org/mike/dwm.git | ||||
| cd dwm | ||||
| sudo make clean install | ||||
| ``` | ||||
| Requirements | ||||
| ------------ | ||||
| In order to build dwm you need the Xlib header files. | ||||
|  | ||||
|  | ||||
| Installation | ||||
| ------------ | ||||
| Edit config.mk to match your local setup (dwm is installed into | ||||
| the /usr/local namespace by default). | ||||
|  | ||||
| Afterwards enter the following command to build and install dwm (if | ||||
| necessary as root): | ||||
|  | ||||
|     make clean install | ||||
|  | ||||
|  | ||||
| Running dwm | ||||
| ----------- | ||||
| Add the following line to your .xinitrc to start dwm using startx: | ||||
|  | ||||
|     exec dwm | ||||
|  | ||||
| In order to connect dwm to a specific display, make sure that | ||||
| the DISPLAY environment variable is set correctly, e.g.: | ||||
|  | ||||
|     DISPLAY=foo.bar:1 exec dwm | ||||
|  | ||||
| (This will start dwm on display :1 of the host foo.bar.) | ||||
|  | ||||
| In order to display status info in the bar, you can do something | ||||
| like this in your .xinitrc: | ||||
|  | ||||
|     while xsetroot -name "`date` `uptime | sed 's/.*,//'`" | ||||
|     do | ||||
|     	sleep 1 | ||||
|     done & | ||||
|     exec dwm | ||||
|  | ||||
|  | ||||
| Configuration | ||||
| ------------- | ||||
| The configuration of dwm is done by creating a custom config.h | ||||
| and (re)compiling the source code. | ||||
|   | ||||
							
								
								
									
										12
									
								
								config.def.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								config.def.h
									
									
									
									
									
								
							| @@ -4,6 +4,11 @@ | ||||
| static const unsigned int borderpx  = 1;        /* border pixel of windows */ | ||||
| static const unsigned int snap      = 32;       /* snap pixel */ | ||||
| static const int swallowfloating    = 0;        /* 1 means swallow floating windows by default */ | ||||
| static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ | ||||
| static const unsigned int systrayonleft = 0;    /* 0: systray in the right corner, >0: systray on left of status text */ | ||||
| static const unsigned int systrayspacing = 2;   /* systray spacing */ | ||||
| static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ | ||||
| static const int showsystray        = 1;        /* 0 means no systray */ | ||||
| static const int showbar            = 1;        /* 0 means no bar */ | ||||
| static const int topbar             = 1;        /* 0 means bottom bar */ | ||||
| static const char *fonts[]          = { "monospace:size=10" }; | ||||
| @@ -39,7 +44,6 @@ static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] | ||||
| static const int nmaster     = 1;    /* number of clients in master area */ | ||||
| static const int resizehints = 1;    /* 1 means respect size hints in tiled resizals */ | ||||
| static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ | ||||
| static const int refreshrate = 120;  /* refresh rate (per second) for client move/resize */ | ||||
|  | ||||
| static const Layout layouts[] = { | ||||
| 	/* symbol     arrange function */ | ||||
| @@ -59,8 +63,6 @@ static const Layout layouts[] = { | ||||
| /* helper for spawning shell commands in the pre dwm-5.0 fashion */ | ||||
| #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | ||||
|  | ||||
| #define STATUSBAR "dwmblocks" | ||||
|  | ||||
| /* commands */ | ||||
| static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | ||||
| static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; | ||||
| @@ -110,9 +112,7 @@ static const Button buttons[] = { | ||||
| 	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} }, | ||||
| 	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} }, | ||||
| 	{ ClkWinTitle,          0,              Button2,        zoom,           {0} }, | ||||
| 	{ ClkStatusText,        0,              Button1,        sigstatusbar,   {.i = 1} }, | ||||
| 	{ ClkStatusText,        0,              Button2,        sigstatusbar,   {.i = 2} }, | ||||
| 	{ ClkStatusText,        0,              Button3,        sigstatusbar,   {.i = 3} }, | ||||
| 	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} }, | ||||
|   | ||||
							
								
								
									
										23
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								config.h
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| /* See LICENSE file for copyright and license details. */ | ||||
| #include <X11/XF86keysym.h> | ||||
|  | ||||
| /* appearance */ | ||||
| static const unsigned int borderpx  = 1;        /* border pixel of windows */ | ||||
| @@ -30,7 +30,8 @@ static const Rule rules[] = { | ||||
| 	/* class     instance  title           tags mask  isfloating  isterminal  noswallow  monitor */ | ||||
| 	{ "Gimp",    NULL,     NULL,           0,         1,          0,           0,        -1 }, | ||||
| 	{ "Firefox", NULL,     NULL,           1 << 8,    0,          0,          -1,        -1 }, | ||||
| 	{ "st",      NULL,     NULL,           0,         0,          1,           0,        -1 }, | ||||
| 	{ "St",      NULL,     NULL,           0,         0,          1,           0,        -1 }, | ||||
| 	{ "Alacritty",      NULL,     NULL,           0,         0,          1,           0,        -1 }, | ||||
| 	{ NULL,      NULL,     "Event Tester", 0,         0,          0,           1,        -1 }, /* xev */ | ||||
| }; | ||||
|  | ||||
| @@ -39,7 +40,6 @@ static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] | ||||
| static const int nmaster     = 1;    /* number of clients in master area */ | ||||
| static const int resizehints = 1;    /* 1 means respect size hints in tiled resizals */ | ||||
| static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ | ||||
| static const int refreshrate = 120;  /* refresh rate (per second) for client move/resize */ | ||||
|  | ||||
| static const Layout layouts[] = { | ||||
| 	/* symbol     arrange function */ | ||||
| @@ -59,12 +59,15 @@ static const Layout layouts[] = { | ||||
| /* helper for spawning shell commands in the pre dwm-5.0 fashion */ | ||||
| #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | ||||
|  | ||||
| #define STATUSBAR "dwmblocks" | ||||
|  | ||||
| /* commands */ | ||||
| static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | ||||
| static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; | ||||
| static const char *termcmd[]  = { "st", NULL }; | ||||
| static const char *brighter[] = { "brightnessctl", "set", "10%+", NULL }; | ||||
| static const char *dimmer[]   = { "brightnessctl", "set", "10%-", NULL }; | ||||
| static const char *up_vol[]   = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "+10%",   NULL }; | ||||
| static const char *down_vol[] = { "pactl", "set-sink-volume", "@DEFAULT_SINK@", "-10%",   NULL }; | ||||
| static const char *mute_vol[] = { "pactl", "set-sink-mute",   "@DEFAULT_SINK@", "toggle", NULL }; | ||||
|  | ||||
| static const Key keys[] = { | ||||
| 	/* modifier                     key        function        argument */ | ||||
| @@ -101,6 +104,11 @@ static const Key keys[] = { | ||||
| 	TAGKEYS(                        XK_8,                      7) | ||||
| 	TAGKEYS(                        XK_9,                      8) | ||||
| 	{ MODKEY|ShiftMask,             XK_q,      quit,           {0} }, | ||||
| 	{ 0, XF86XK_MonBrightnessDown, spawn, {.v = dimmer } }, | ||||
| 	{ 0, XF86XK_MonBrightnessUp,   spawn, {.v = brighter } }, | ||||
| 	{ 0, XF86XK_AudioMute,        spawn, {.v = mute_vol } }, | ||||
| 	{ 0, XF86XK_AudioLowerVolume, spawn, {.v = down_vol } }, | ||||
| 	{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = up_vol } }, | ||||
| }; | ||||
|  | ||||
| /* button definitions */ | ||||
| @@ -110,9 +118,7 @@ static const Button buttons[] = { | ||||
| 	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} }, | ||||
| 	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} }, | ||||
| 	{ ClkWinTitle,          0,              Button2,        zoom,           {0} }, | ||||
| 	{ ClkStatusText,        0,              Button1,        sigstatusbar,   {.i = 1} }, | ||||
| 	{ ClkStatusText,        0,              Button2,        sigstatusbar,   {.i = 2} }, | ||||
| 	{ ClkStatusText,        0,              Button3,        sigstatusbar,   {.i = 3} }, | ||||
| 	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} }, | ||||
| 	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} }, | ||||
| @@ -121,4 +127,3 @@ static const Button buttons[] = { | ||||
| 	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} }, | ||||
| 	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} }, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| # dwm version | ||||
| VERSION = 6.6 | ||||
| VERSION = 6.5 | ||||
|  | ||||
| # Customize below to fit your system | ||||
|  | ||||
|   | ||||
							
								
								
									
										595
									
								
								dwm.c
									
									
									
									
									
								
							
							
						
						
									
										595
									
								
								dwm.c
									
									
									
									
									
								
							| @@ -62,12 +62,27 @@ | ||||
| #define TAGMASK                 ((1 << LENGTH(tags)) - 1) | ||||
| #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad) | ||||
|  | ||||
| #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 | ||||
|  | ||||
| /* enums */ | ||||
| enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | ||||
| enum { SchemeNorm, SchemeSel }; /* color schemes */ | ||||
| enum { NetSupported, NetWMName, NetWMState, NetWMCheck, | ||||
|        NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, | ||||
|        NetWMFullscreen, NetActiveWindow, NetWMWindowType, | ||||
|        NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | ||||
| enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ | ||||
| enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ | ||||
| enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, | ||||
|        ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ | ||||
| @@ -118,7 +133,6 @@ typedef struct { | ||||
| 	void (*arrange)(Monitor *); | ||||
| } Layout; | ||||
|  | ||||
| typedef struct Pertag Pertag; | ||||
| struct Monitor { | ||||
| 	char ltsymbol[16]; | ||||
| 	float mfact; | ||||
| @@ -138,7 +152,6 @@ struct Monitor { | ||||
| 	Monitor *next; | ||||
| 	Window barwin; | ||||
| 	const Layout *lt[2]; | ||||
| 	Pertag *pertag; | ||||
| }; | ||||
|  | ||||
| typedef struct { | ||||
| @@ -152,6 +165,12 @@ typedef struct { | ||||
| 	int monitor; | ||||
| } Rule; | ||||
|  | ||||
| typedef struct Systray   Systray; | ||||
| struct Systray { | ||||
| 	Window win; | ||||
| 	Client *icons; | ||||
| }; | ||||
|  | ||||
| /* function declarations */ | ||||
| static void applyrules(Client *c); | ||||
| static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); | ||||
| @@ -183,7 +202,7 @@ static void focusstack(const Arg *arg); | ||||
| static Atom getatomprop(Client *c, Atom prop); | ||||
| static int getrootptr(int *x, int *y); | ||||
| static long getstate(Window w); | ||||
| static pid_t getstatusbarpid(); | ||||
| static unsigned int getsystraywidth(); | ||||
| static int gettextprop(Window w, Atom atom, char *text, unsigned int size); | ||||
| static void grabbuttons(Client *c, int focused); | ||||
| static void grabkeys(void); | ||||
| @@ -201,13 +220,16 @@ static void pop(Client *c); | ||||
| static void propertynotify(XEvent *e); | ||||
| static void quit(const Arg *arg); | ||||
| static Monitor *recttomon(int x, int y, int w, int h); | ||||
| static void removesystrayicon(Client *i); | ||||
| static void resize(Client *c, int x, int y, int w, int h, int interact); | ||||
| static void resizebarwin(Monitor *m); | ||||
| static void resizeclient(Client *c, int x, int y, int w, int h); | ||||
| static void resizemouse(const Arg *arg); | ||||
| static void resizerequest(XEvent *e); | ||||
| static void restack(Monitor *m); | ||||
| static void run(void); | ||||
| static void scan(void); | ||||
| static int sendevent(Client *c, Atom proto); | ||||
| static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); | ||||
| static void sendmon(Client *c, Monitor *m); | ||||
| static void setclientstate(Client *c, long state); | ||||
| static void setfocus(Client *c); | ||||
| @@ -217,8 +239,8 @@ static void setmfact(const Arg *arg); | ||||
| static void setup(void); | ||||
| static void seturgent(Client *c, int urg); | ||||
| static void showhide(Client *c); | ||||
| static void sigstatusbar(const Arg *arg); | ||||
| static void spawn(const Arg *arg); | ||||
| static Monitor *systraytomon(Monitor *m); | ||||
| static void tag(const Arg *arg); | ||||
| static void tagmon(const Arg *arg); | ||||
| static void tile(Monitor *m); | ||||
| @@ -236,12 +258,16 @@ static int updategeom(void); | ||||
| static void updatenumlockmask(void); | ||||
| static void updatesizehints(Client *c); | ||||
| static void updatestatus(void); | ||||
| static void updatesystray(void); | ||||
| static void updatesystrayicongeom(Client *i, int w, int h); | ||||
| static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); | ||||
| static void updatetitle(Client *c); | ||||
| static void updatewindowtype(Client *c); | ||||
| static void updatewmhints(Client *c); | ||||
| static void view(const Arg *arg); | ||||
| static Client *wintoclient(Window w); | ||||
| static Monitor *wintomon(Window w); | ||||
| static Client *wintosystrayicon(Window w); | ||||
| static int xerror(Display *dpy, XErrorEvent *ee); | ||||
| static int xerrordummy(Display *dpy, XErrorEvent *ee); | ||||
| static int xerrorstart(Display *dpy, XErrorEvent *ee); | ||||
| @@ -254,11 +280,9 @@ static Client *termforwin(const Client *c); | ||||
| static pid_t winpid(Window w); | ||||
|  | ||||
| /* variables */ | ||||
| static Systray *systray = NULL; | ||||
| static const char broken[] = "broken"; | ||||
| static char stext[256]; | ||||
| static int statusw; | ||||
| static int statussig; | ||||
| static pid_t statuspid = -1; | ||||
| static int screen; | ||||
| static int sw, sh;           /* X display screen geometry width, height */ | ||||
| static int bh;               /* bar height */ | ||||
| @@ -279,9 +303,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { | ||||
| 	[MapRequest] = maprequest, | ||||
| 	[MotionNotify] = motionnotify, | ||||
| 	[PropertyNotify] = propertynotify, | ||||
| 	[ResizeRequest] = resizerequest, | ||||
| 	[UnmapNotify] = unmapnotify | ||||
| }; | ||||
| static Atom wmatom[WMLast], netatom[NetLast]; | ||||
| static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; | ||||
| static int running = 1; | ||||
| static Cur *cursor[CurLast]; | ||||
| static Clr **scheme; | ||||
| @@ -295,15 +320,6 @@ static xcb_connection_t *xcon; | ||||
| /* configuration, allows nested code to access above variables */ | ||||
| #include "config.h" | ||||
|  | ||||
| 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 */ | ||||
| }; | ||||
|  | ||||
| /* compile-time check if all tags fit into an unsigned int bit array. */ | ||||
| struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; | ||||
|  | ||||
| @@ -505,7 +521,6 @@ buttonpress(XEvent *e) | ||||
| 	Client *c; | ||||
| 	Monitor *m; | ||||
| 	XButtonPressedEvent *ev = &e->xbutton; | ||||
| 	char *text, *s, ch; | ||||
|  | ||||
| 	click = ClkRootWin; | ||||
| 	/* focus monitor if necessary */ | ||||
| @@ -530,27 +545,9 @@ buttonpress(XEvent *e) | ||||
| 			arg.ui = 1 << i; | ||||
| 		} else if (ev->x < x + TEXTW(selmon->ltsymbol)) | ||||
| 			click = ClkLtSymbol; | ||||
| 		else if (ev->x > selmon->ww - statusw) { | ||||
| 			x = selmon->ww - statusw; | ||||
| 		else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) | ||||
| 			click = ClkStatusText; | ||||
| 			statussig = 0; | ||||
| 			for (text = s = stext; *s && x <= ev->x; s++) { | ||||
| 				if ((unsigned char)(*s) < ' ') { | ||||
| 					ch = *s; | ||||
| 					*s = '\0'; | ||||
| 					x += TEXTW(text) - lrpad; | ||||
| 					*s = ch; | ||||
| 					text = s + 1; | ||||
| 					if (x >= ev->x) | ||||
| 						break; | ||||
| 					/* reset on matching signal raw byte */ | ||||
| 					if (ch == statussig) | ||||
| 						statussig = 0; | ||||
| 					else | ||||
| 						statussig = ch; | ||||
| 				} | ||||
| 			} | ||||
| 		} else | ||||
| 		else | ||||
| 			click = ClkWinTitle; | ||||
| 	} else if ((c = wintoclient(ev->window))) { | ||||
| 		focus(c); | ||||
| @@ -591,6 +588,13 @@ cleanup(void) | ||||
| 	XUngrabKey(dpy, AnyKey, AnyModifier, root); | ||||
| 	while (mons) | ||||
| 		cleanupmon(mons); | ||||
|  | ||||
| 	if (showsystray) { | ||||
| 		XUnmapWindow(dpy, systray->win); | ||||
| 		XDestroyWindow(dpy, systray->win); | ||||
| 		free(systray); | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < CurLast; i++) | ||||
| 		drw_cur_free(drw, cursor[i]); | ||||
| 	for (i = 0; i < LENGTH(colors); i++) | ||||
| @@ -622,9 +626,58 @@ cleanupmon(Monitor *mon) | ||||
| void | ||||
| clientmessage(XEvent *e) | ||||
| { | ||||
| 	XWindowAttributes wa; | ||||
| 	XSetWindowAttributes swa; | ||||
| 	XClientMessageEvent *cme = &e->xclient; | ||||
| 	Client *c = wintoclient(cme->window); | ||||
|  | ||||
| 	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[SchemeNorm][ColBg].pixel; | ||||
| 			XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); | ||||
| 			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); | ||||
| 			/* FIXME not sure if I have to send these events, too */ | ||||
| 			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; | ||||
| 	} | ||||
|  | ||||
| 	if (!c) | ||||
| 		return; | ||||
| 	if (cme->message_type == netatom[NetWMState]) { | ||||
| @@ -677,7 +730,7 @@ configurenotify(XEvent *e) | ||||
| 				for (c = m->clients; c; c = c->next) | ||||
| 					if (c->isfullscreen) | ||||
| 						resizeclient(c, m->mx, m->my, m->mw, m->mh); | ||||
| 				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); | ||||
| 				resizebarwin(m); | ||||
| 			} | ||||
| 			focus(NULL); | ||||
| 			arrange(NULL); | ||||
| @@ -741,7 +794,6 @@ Monitor * | ||||
| createmon(void) | ||||
| { | ||||
| 	Monitor *m; | ||||
| 	unsigned int i; | ||||
|  | ||||
| 	m = ecalloc(1, sizeof(Monitor)); | ||||
| 	m->tagset[0] = m->tagset[1] = 1; | ||||
| @@ -752,20 +804,6 @@ createmon(void) | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	return m; | ||||
| } | ||||
|  | ||||
| @@ -780,6 +818,11 @@ destroynotify(XEvent *e) | ||||
|  | ||||
| 	else if ((c = swallowingclient(ev->window))) | ||||
| 		unmanage(c->swallowing, 1); | ||||
| 	else if ((c = wintosystrayicon(ev->window))) { | ||||
| 		removesystrayicon(c); | ||||
| 		resizebarwin(selmon); | ||||
| 		updatesystray(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -823,7 +866,7 @@ dirtomon(int dir) | ||||
| void | ||||
| drawbar(Monitor *m) | ||||
| { | ||||
| 	int x, w, tw = 0; | ||||
| 	int x, w, tw = 0, stw = 0; | ||||
| 	int boxs = drw->fonts->h / 9; | ||||
| 	int boxw = drw->fonts->h / 6 + 2; | ||||
| 	unsigned int i, occ = 0, urg = 0; | ||||
| @@ -832,28 +875,17 @@ drawbar(Monitor *m) | ||||
| 	if (!m->showbar) | ||||
| 		return; | ||||
|  | ||||
| 	if(showsystray && m == systraytomon(m) && !systrayonleft) | ||||
| 		stw = getsystraywidth(); | ||||
|  | ||||
| 	/* draw status first so it can be overdrawn by tags later */ | ||||
| 	if (m == selmon) { /* status is only drawn on selected monitor */ | ||||
| 		char *text, *s, ch; | ||||
| 		drw_setscheme(drw, scheme[SchemeNorm]); | ||||
|  | ||||
| 		x = 0; | ||||
| 		for (text = s = stext; *s; s++) { | ||||
| 			if ((unsigned char)(*s) < ' ') { | ||||
| 				ch = *s; | ||||
| 				*s = '\0'; | ||||
| 				tw = TEXTW(text) - lrpad; | ||||
| 				drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); | ||||
| 				x += tw; | ||||
| 				*s = ch; | ||||
| 				text = s + 1; | ||||
| 			} | ||||
| 		} | ||||
| 		tw = TEXTW(text) - lrpad + 2; | ||||
| 		drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); | ||||
| 		tw = statusw; | ||||
| 		tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ | ||||
| 		drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); | ||||
| 	} | ||||
|  | ||||
| 	resizebarwin(m); | ||||
| 	for (c = m->clients; c; c = c->next) { | ||||
| 		occ |= c->tags == TAGMASK ? 0 : c->tags; | ||||
| 		if (c->isurgent) | ||||
| @@ -873,7 +905,7 @@ drawbar(Monitor *m) | ||||
| 	drw_setscheme(drw, scheme[SchemeNorm]); | ||||
| 	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); | ||||
|  | ||||
| 	if ((w = m->ww - tw - x) > bh) { | ||||
| 	if ((w = m->ww - tw - stw - x) > bh) { | ||||
| 		if (m->sel) { | ||||
| 			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); | ||||
| 			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); | ||||
| @@ -884,7 +916,7 @@ drawbar(Monitor *m) | ||||
| 			drw_rect(drw, x, 0, w, bh, 1, 1); | ||||
| 		} | ||||
| 	} | ||||
| 	drw_map(drw, m->barwin, 0, 0, m->ww, bh); | ||||
| 	drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -921,8 +953,11 @@ expose(XEvent *e) | ||||
| 	Monitor *m; | ||||
| 	XExposeEvent *ev = &e->xexpose; | ||||
|  | ||||
| 	if (ev->count == 0 && (m = wintomon(ev->window))) | ||||
| 	if (ev->count == 0 && (m = wintomon(ev->window))) { | ||||
| 		drawbar(m); | ||||
| 		if (m == selmon) | ||||
| 			updatesystray(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -1008,36 +1043,30 @@ getatomprop(Client *c, Atom prop) | ||||
| 	unsigned char *p = NULL; | ||||
| 	Atom da, atom = None; | ||||
|  | ||||
| 	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, | ||||
| 	/* FIXME getatomprop should return the number of items and a pointer to | ||||
| 	 * the stored data instead of this workaround */ | ||||
| 	Atom req = XA_ATOM; | ||||
| 	if (prop == xatom[XembedInfo]) | ||||
| 		req = xatom[XembedInfo]; | ||||
|  | ||||
| 	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, | ||||
| 		&da, &di, &dl, &dl, &p) == Success && p) { | ||||
| 		atom = *(Atom *)p; | ||||
| 		if (da == xatom[XembedInfo] && dl == 2) | ||||
| 			atom = ((Atom *)p)[1]; | ||||
| 		XFree(p); | ||||
| 	} | ||||
| 	return atom; | ||||
| } | ||||
|  | ||||
| pid_t | ||||
| getstatusbarpid() | ||||
| unsigned int | ||||
| getsystraywidth() | ||||
| { | ||||
| 	char buf[32], *str = buf, *c; | ||||
| 	FILE *fp; | ||||
|  | ||||
| 	if (statuspid > 0) { | ||||
| 		snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid); | ||||
| 		if ((fp = fopen(buf, "r"))) { | ||||
| 			fgets(buf, sizeof(buf), fp); | ||||
| 			while ((c = strchr(str, '/'))) | ||||
| 				str = c + 1; | ||||
| 			fclose(fp); | ||||
| 			if (!strcmp(str, STATUSBAR)) | ||||
| 				return statuspid; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!(fp = popen("pidof -s "STATUSBAR, "r"))) | ||||
| 		return -1; | ||||
| 	fgets(buf, sizeof(buf), fp); | ||||
| 	pclose(fp); | ||||
| 	return strtol(buf, NULL, 10); | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| int | ||||
| @@ -1143,7 +1172,7 @@ grabkeys(void) | ||||
| void | ||||
| incnmaster(const Arg *arg) | ||||
| { | ||||
| 	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); | ||||
| 	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); | ||||
| 	arrange(selmon); | ||||
| } | ||||
|  | ||||
| @@ -1180,7 +1209,8 @@ killclient(const Arg *arg) | ||||
| { | ||||
| 	if (!selmon->sel) | ||||
| 		return; | ||||
| 	if (!sendevent(selmon->sel, wmatom[WMDelete])) { | ||||
|  | ||||
| 	if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { | ||||
| 		XGrabServer(dpy); | ||||
| 		XSetErrorHandler(xerrordummy); | ||||
| 		XSetCloseDownMode(dpy, DestroyAll); | ||||
| @@ -1271,6 +1301,13 @@ maprequest(XEvent *e) | ||||
| 	static XWindowAttributes wa; | ||||
| 	XMapRequestEvent *ev = &e->xmaprequest; | ||||
|  | ||||
| 	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(); | ||||
| 	} | ||||
|  | ||||
| 	if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) | ||||
| 		return; | ||||
| 	if (!wintoclient(ev->window)) | ||||
| @@ -1339,7 +1376,7 @@ movemouse(const Arg *arg) | ||||
| 			handler[ev.type](&ev); | ||||
| 			break; | ||||
| 		case MotionNotify: | ||||
| 			if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) | ||||
| 			if ((ev.xmotion.time - lasttime) <= (1000 / 60)) | ||||
| 				continue; | ||||
| 			lasttime = ev.xmotion.time; | ||||
|  | ||||
| @@ -1392,6 +1429,17 @@ propertynotify(XEvent *e) | ||||
| 	Window trans; | ||||
| 	XPropertyEvent *ev = &e->xproperty; | ||||
|  | ||||
| 	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(); | ||||
| 	} | ||||
|  | ||||
| 	if ((ev->window == root) && (ev->atom == XA_WM_NAME)) | ||||
| 		updatestatus(); | ||||
| 	else if (ev->state == PropertyDelete) | ||||
| @@ -1442,6 +1490,19 @@ recttomon(int x, int y, int w, int h) | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| 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 | ||||
| resize(Client *c, int x, int y, int w, int h, int interact) | ||||
| { | ||||
| @@ -1449,6 +1510,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) | ||||
| 		resizeclient(c, x, y, w, h); | ||||
| } | ||||
|  | ||||
| void | ||||
| resizebarwin(Monitor *m) { | ||||
| 	unsigned int w = m->ww; | ||||
| 	if (showsystray && m == systraytomon(m) && !systrayonleft) | ||||
| 		w -= getsystraywidth(); | ||||
| 	XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); | ||||
| } | ||||
|  | ||||
| void | ||||
| resizeclient(Client *c, int x, int y, int w, int h) | ||||
| { | ||||
| @@ -1464,6 +1533,19 @@ resizeclient(Client *c, int x, int y, int w, int h) | ||||
| 	XSync(dpy, False); | ||||
| } | ||||
|  | ||||
| void | ||||
| resizerequest(XEvent *e) | ||||
| { | ||||
| 	XResizeRequestEvent *ev = &e->xresizerequest; | ||||
| 	Client *i; | ||||
|  | ||||
| 	if ((i = wintosystrayicon(ev->window))) { | ||||
| 		updatesystrayicongeom(i, ev->width, ev->height); | ||||
| 		resizebarwin(selmon); | ||||
| 		updatesystray(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| resizemouse(const Arg *arg) | ||||
| { | ||||
| @@ -1493,7 +1575,7 @@ resizemouse(const Arg *arg) | ||||
| 			handler[ev.type](&ev); | ||||
| 			break; | ||||
| 		case MotionNotify: | ||||
| 			if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) | ||||
| 			if ((ev.xmotion.time - lasttime) <= (1000 / 60)) | ||||
| 				continue; | ||||
| 			lasttime = ev.xmotion.time; | ||||
|  | ||||
| @@ -1610,26 +1692,37 @@ setclientstate(Client *c, long state) | ||||
| } | ||||
|  | ||||
| int | ||||
| sendevent(Client *c, Atom proto) | ||||
| sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) | ||||
| { | ||||
| 	int n; | ||||
| 	Atom *protocols; | ||||
| 	Atom *protocols, mt; | ||||
| 	int exists = 0; | ||||
| 	XEvent ev; | ||||
|  | ||||
| 	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { | ||||
| 		while (!exists && n--) | ||||
| 			exists = protocols[n] == proto; | ||||
| 		XFree(protocols); | ||||
| 	if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { | ||||
| 		mt = wmatom[WMProtocols]; | ||||
| 		if (XGetWMProtocols(dpy, w, &protocols, &n)) { | ||||
| 			while (!exists && n--) | ||||
| 				exists = protocols[n] == proto; | ||||
| 			XFree(protocols); | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		exists = True; | ||||
| 		mt = proto; | ||||
| 	} | ||||
|  | ||||
| 	if (exists) { | ||||
| 		ev.type = ClientMessage; | ||||
| 		ev.xclient.window = c->win; | ||||
| 		ev.xclient.message_type = wmatom[WMProtocols]; | ||||
| 		ev.xclient.window = w; | ||||
| 		ev.xclient.message_type = mt; | ||||
| 		ev.xclient.format = 32; | ||||
| 		ev.xclient.data.l[0] = proto; | ||||
| 		ev.xclient.data.l[1] = CurrentTime; | ||||
| 		XSendEvent(dpy, c->win, False, NoEventMask, &ev); | ||||
| 		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); | ||||
| 	} | ||||
| 	return exists; | ||||
| } | ||||
| @@ -1643,7 +1736,7 @@ setfocus(Client *c) | ||||
| 			XA_WINDOW, 32, PropModeReplace, | ||||
| 			(unsigned char *) &(c->win), 1); | ||||
| 	} | ||||
| 	sendevent(c, wmatom[WMTakeFocus]); | ||||
| 	sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -1678,9 +1771,9 @@ void | ||||
| setlayout(const Arg *arg) | ||||
| { | ||||
| 	if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) | ||||
| 		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; | ||||
| 		selmon->sellt ^= 1; | ||||
| 	if (arg && arg->v) | ||||
| 		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; | ||||
| 		selmon->lt[selmon->sellt] = (Layout *)arg->v; | ||||
| 	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); | ||||
| 	if (selmon->sel) | ||||
| 		arrange(selmon); | ||||
| @@ -1699,7 +1792,7 @@ setmfact(const Arg *arg) | ||||
| 	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; | ||||
| 	if (f < 0.05 || f > 0.95) | ||||
| 		return; | ||||
| 	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; | ||||
| 	selmon->mfact = f; | ||||
| 	arrange(selmon); | ||||
| } | ||||
|  | ||||
| @@ -1739,6 +1832,10 @@ setup(void) | ||||
| 	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); | ||||
| 	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); | ||||
| 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); | ||||
| 	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); | ||||
| 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); | ||||
| 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); | ||||
| 	netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); | ||||
| @@ -1746,6 +1843,9 @@ setup(void) | ||||
| 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); | ||||
| 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); | ||||
| 	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); | ||||
| 	xatom[Manager] = XInternAtom(dpy, "MANAGER", False); | ||||
| 	xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); | ||||
| 	xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); | ||||
| 	/* init cursors */ | ||||
| 	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); | ||||
| 	cursor[CurResize] = drw_cur_create(drw, XC_sizing); | ||||
| @@ -1754,6 +1854,8 @@ setup(void) | ||||
| 	scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); | ||||
| 	for (i = 0; i < LENGTH(colors); i++) | ||||
| 		scheme[i] = drw_scm_create(drw, colors[i], 3); | ||||
| 	/* init system tray */ | ||||
| 	updatesystray(); | ||||
| 	/* init bars */ | ||||
| 	updatebars(); | ||||
| 	updatestatus(); | ||||
| @@ -1811,20 +1913,6 @@ showhide(Client *c) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| sigstatusbar(const Arg *arg) | ||||
| { | ||||
| 	union sigval sv; | ||||
|  | ||||
| 	if (!statussig) | ||||
| 		return; | ||||
| 	sv.sival_int = arg->i; | ||||
| 	if ((statuspid = getstatusbarpid()) <= 0) | ||||
| 		return; | ||||
|  | ||||
| 	sigqueue(statuspid, SIGRTMIN+statussig, sv); | ||||
| } | ||||
|  | ||||
| void | ||||
| spawn(const Arg *arg) | ||||
| { | ||||
| @@ -1896,9 +1984,20 @@ tile(Monitor *m) | ||||
| void | ||||
| togglebar(const Arg *arg) | ||||
| { | ||||
| 	selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; | ||||
| 	selmon->showbar = !selmon->showbar; | ||||
| 	updatebarpos(selmon); | ||||
| 	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); | ||||
| 	resizebarwin(selmon); | ||||
| 	if (showsystray) { | ||||
| 		XWindowChanges wc; | ||||
| 		if (!selmon->showbar) | ||||
| 			wc.y = -bh; | ||||
| 		else if (selmon->showbar) { | ||||
| 			wc.y = 0; | ||||
| 			if (!selmon->topbar) | ||||
| 				wc.y = selmon->mh - bh; | ||||
| 		} | ||||
| 		XConfigureWindow(dpy, systray->win, CWY, &wc); | ||||
| 	} | ||||
| 	arrange(selmon); | ||||
| } | ||||
|  | ||||
| @@ -1935,33 +2034,9 @@ void | ||||
| toggleview(const Arg *arg) | ||||
| { | ||||
| 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); | ||||
| 	int i; | ||||
|  | ||||
| 	if (newtagset) { | ||||
| 		selmon->tagset[selmon->seltags] = newtagset; | ||||
|  | ||||
| 		if (newtagset == ~0) { | ||||
| 			selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| 			selmon->pertag->curtag = 0; | ||||
| 		} | ||||
|  | ||||
| 		/* test if the user did not select the same tag */ | ||||
| 		if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { | ||||
| 			selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| 			for (i = 0; !(newtagset & 1 << i); i++) ; | ||||
| 			selmon->pertag->curtag = i + 1; | ||||
| 		} | ||||
|  | ||||
| 		/* apply settings for this view */ | ||||
| 		selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; | ||||
| 		selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; | ||||
| 		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; | ||||
| 		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; | ||||
| 		selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; | ||||
|  | ||||
| 		if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) | ||||
| 			togglebar(NULL); | ||||
|  | ||||
| 		focus(NULL); | ||||
| 		arrange(selmon); | ||||
| 	} | ||||
| @@ -2035,11 +2110,18 @@ unmapnotify(XEvent *e) | ||||
| 		else | ||||
| 			unmanage(c, 0); | ||||
| 	} | ||||
| 	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(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| updatebars(void) | ||||
| { | ||||
| 	unsigned int w; | ||||
| 	Monitor *m; | ||||
| 	XSetWindowAttributes wa = { | ||||
| 		.override_redirect = True, | ||||
| @@ -2050,10 +2132,15 @@ updatebars(void) | ||||
| 	for (m = mons; m; m = m->next) { | ||||
| 		if (m->barwin) | ||||
| 			continue; | ||||
| 		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), | ||||
| 		w = m->ww; | ||||
| 		if (showsystray && m == systraytomon(m)) | ||||
| 			w -= getsystraywidth(); | ||||
| 		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), | ||||
| 				CopyFromParent, DefaultVisual(dpy, screen), | ||||
| 				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); | ||||
| 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); | ||||
| 		if (showsystray && m == systraytomon(m)) | ||||
| 			XMapRaised(dpy, systray->win); | ||||
| 		XMapRaised(dpy, m->barwin); | ||||
| 		XSetClassHint(dpy, m->barwin, &ch); | ||||
| 	} | ||||
| @@ -2227,26 +2314,128 @@ updatesizehints(Client *c) | ||||
| void | ||||
| updatestatus(void) | ||||
| { | ||||
| 	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { | ||||
| 	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) | ||||
| 		strcpy(stext, "dwm-"VERSION); | ||||
| 		statusw = TEXTW(stext) - lrpad + 2; | ||||
| 	} else { | ||||
| 		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; | ||||
|  | ||||
| 	} | ||||
| 	drawbar(selmon); | ||||
| 	updatesystray(); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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; | ||||
| 	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)); | ||||
| 		systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); | ||||
| 		wa.event_mask        = ButtonPressMask | ExposureMask; | ||||
| 		wa.override_redirect = True; | ||||
| 		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel; | ||||
| 		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 { | ||||
| 			fprintf(stderr, "dwm: unable to obtain system tray.\n"); | ||||
| 			free(systray); | ||||
| 			systray = NULL; | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	for (w = 0, i = systray->icons; i; i = i->next) { | ||||
| 		/* make sure the background color stays the same */ | ||||
| 		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel; | ||||
| 		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 = m->by; 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 */ | ||||
| 	XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); | ||||
| 	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); | ||||
| 	XSync(dpy, False); | ||||
| } | ||||
|  | ||||
| void | ||||
| @@ -2292,37 +2481,11 @@ updatewmhints(Client *c) | ||||
| void | ||||
| view(const Arg *arg) | ||||
| { | ||||
| 	int i; | ||||
| 	unsigned int tmptag; | ||||
|  | ||||
| 	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) | ||||
| 		return; | ||||
| 	selmon->seltags ^= 1; /* toggle sel tagset */ | ||||
| 	if (arg->ui & TAGMASK) { | ||||
| 	if (arg->ui & TAGMASK) | ||||
| 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; | ||||
| 		selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
|  | ||||
| 		if (arg->ui == ~0) | ||||
| 			selmon->pertag->curtag = 0; | ||||
| 		else { | ||||
| 			for (i = 0; !(arg->ui & 1 << i); i++) ; | ||||
| 			selmon->pertag->curtag = i + 1; | ||||
| 		} | ||||
| 	} else { | ||||
| 		tmptag = selmon->pertag->prevtag; | ||||
| 		selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| 		selmon->pertag->curtag = tmptag; | ||||
| 	} | ||||
|  | ||||
| 	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; | ||||
| 	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; | ||||
| 	selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; | ||||
| 	selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; | ||||
| 	selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; | ||||
|  | ||||
| 	if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) | ||||
| 		togglebar(NULL); | ||||
|  | ||||
| 	focus(NULL); | ||||
| 	arrange(selmon); | ||||
| } | ||||
| @@ -2470,6 +2633,16 @@ wintoclient(Window w) | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| 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 * | ||||
| wintomon(Window w) | ||||
| { | ||||
| @@ -2523,6 +2696,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| void | ||||
| zoom(const Arg *arg) | ||||
| { | ||||
|   | ||||
| @@ -1,48 +0,0 @@ | ||||
| :100644 100644 f1d86b2 0000000 M	dwm.c | ||||
|  | ||||
| diff --git a/dwm.c b/dwm.c | ||||
| index f1d86b2..d41cc14 100644 | ||||
| --- a/dwm.c | ||||
| +++ b/dwm.c | ||||
| @@ -433,9 +433,15 @@ buttonpress(XEvent *e) | ||||
|  	} | ||||
|  	if (ev->window == selmon->barwin) { | ||||
|  		i = x = 0; | ||||
| -		do | ||||
| +		unsigned int occ = 0; | ||||
| +		for(c = m->clients; c; c=c->next) | ||||
| +			occ |= c->tags == TAGMASK ? 0 : c->tags; | ||||
| +		do { | ||||
| +			/* Do not reserve space for vacant tags */ | ||||
| +			if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) | ||||
| +				continue; | ||||
|  			x += TEXTW(tags[i]); | ||||
| -		while (ev->x >= x && ++i < LENGTH(tags)); | ||||
| +		} while (ev->x >= x && ++i < LENGTH(tags)); | ||||
|  		if (i < LENGTH(tags)) { | ||||
|  			click = ClkTagBar; | ||||
|  			arg.ui = 1 << i; | ||||
| @@ -715,19 +721,18 @@ drawbar(Monitor *m) | ||||
|  	} | ||||
|   | ||||
|  	for (c = m->clients; c; c = c->next) { | ||||
| -		occ |= c->tags; | ||||
| +		occ |= c->tags == TAGMASK ? 0 : c->tags; | ||||
|  		if (c->isurgent) | ||||
|  			urg |= c->tags; | ||||
|  	} | ||||
|  	x = 0; | ||||
|  	for (i = 0; i < LENGTH(tags); i++) { | ||||
| +		/* Do not draw vacant tags */ | ||||
| +		if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) | ||||
| +			continue; | ||||
|  		w = TEXTW(tags[i]); | ||||
|  		drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); | ||||
|  		drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); | ||||
| -		if (occ & 1 << i) | ||||
| -			drw_rect(drw, x + boxs, boxs, boxw, boxw, | ||||
| -				m == selmon && selmon->sel && selmon->sel->tags & 1 << i, | ||||
| -				urg & 1 << i); | ||||
|  		x += w; | ||||
|  	} | ||||
|  	w = TEXTW(m->ltsymbol); | ||||
| @@ -1,177 +0,0 @@ | ||||
| diff --git a/dwm.c b/dwm.c | ||||
| index 664c527..ac8e4ec 100644 | ||||
| --- a/dwm.c | ||||
| +++ b/dwm.c | ||||
| @@ -111,6 +111,7 @@ typedef struct { | ||||
|  	void (*arrange)(Monitor *); | ||||
|  } Layout; | ||||
|   | ||||
| +typedef struct Pertag Pertag; | ||||
|  struct Monitor { | ||||
|  	char ltsymbol[16]; | ||||
|  	float mfact; | ||||
| @@ -130,6 +131,7 @@ struct Monitor { | ||||
|  	Monitor *next; | ||||
|  	Window barwin; | ||||
|  	const Layout *lt[2]; | ||||
| +	Pertag *pertag; | ||||
|  }; | ||||
|   | ||||
|  typedef struct { | ||||
| @@ -272,6 +274,15 @@ static Window root, wmcheckwin; | ||||
|  /* configuration, allows nested code to access above variables */ | ||||
|  #include "config.h" | ||||
|   | ||||
| +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 */ | ||||
| +}; | ||||
| + | ||||
|  /* compile-time check if all tags fit into an unsigned int bit array. */ | ||||
|  struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; | ||||
|   | ||||
| @@ -632,6 +643,7 @@ Monitor * | ||||
|  createmon(void) | ||||
|  { | ||||
|  	Monitor *m; | ||||
| +	unsigned int i; | ||||
|   | ||||
|  	m = ecalloc(1, sizeof(Monitor)); | ||||
|  	m->tagset[0] = m->tagset[1] = 1; | ||||
| @@ -642,6 +654,20 @@ createmon(void) | ||||
|  	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; | ||||
| +	} | ||||
| + | ||||
|  	return m; | ||||
|  } | ||||
|   | ||||
| @@ -967,7 +993,7 @@ grabkeys(void) | ||||
|  void | ||||
|  incnmaster(const Arg *arg) | ||||
|  { | ||||
| -	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); | ||||
| +	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); | ||||
|  	arrange(selmon); | ||||
|  } | ||||
|   | ||||
| @@ -1502,9 +1528,9 @@ void | ||||
|  setlayout(const Arg *arg) | ||||
|  { | ||||
|  	if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) | ||||
| -		selmon->sellt ^= 1; | ||||
| +		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; | ||||
|  	if (arg && arg->v) | ||||
| -		selmon->lt[selmon->sellt] = (Layout *)arg->v; | ||||
| +		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; | ||||
|  	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); | ||||
|  	if (selmon->sel) | ||||
|  		arrange(selmon); | ||||
| @@ -1523,7 +1549,7 @@ setmfact(const Arg *arg) | ||||
|  	f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; | ||||
|  	if (f < 0.05 || f > 0.95) | ||||
|  		return; | ||||
| -	selmon->mfact = f; | ||||
| +	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; | ||||
|  	arrange(selmon); | ||||
|  } | ||||
|   | ||||
| @@ -1702,7 +1728,7 @@ tile(Monitor *m) | ||||
|  void | ||||
|  togglebar(const Arg *arg) | ||||
|  { | ||||
| -	selmon->showbar = !selmon->showbar; | ||||
| +	selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; | ||||
|  	updatebarpos(selmon); | ||||
|  	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); | ||||
|  	arrange(selmon); | ||||
| @@ -1741,9 +1767,33 @@ void | ||||
|  toggleview(const Arg *arg) | ||||
|  { | ||||
|  	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); | ||||
| +	int i; | ||||
|   | ||||
|  	if (newtagset) { | ||||
|  		selmon->tagset[selmon->seltags] = newtagset; | ||||
| + | ||||
| +		if (newtagset == ~0) { | ||||
| +			selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| +			selmon->pertag->curtag = 0; | ||||
| +		} | ||||
| + | ||||
| +		/* test if the user did not select the same tag */ | ||||
| +		if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { | ||||
| +			selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| +			for (i = 0; !(newtagset & 1 << i); i++) ; | ||||
| +			selmon->pertag->curtag = i + 1; | ||||
| +		} | ||||
| + | ||||
| +		/* apply settings for this view */ | ||||
| +		selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; | ||||
| +		selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; | ||||
| +		selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; | ||||
| +		selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; | ||||
| +		selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; | ||||
| + | ||||
| +		if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) | ||||
| +			togglebar(NULL); | ||||
| + | ||||
|  		focus(NULL); | ||||
|  		arrange(selmon); | ||||
|  	} | ||||
| @@ -2038,11 +2088,37 @@ updatewmhints(Client *c) | ||||
|  void | ||||
|  view(const Arg *arg) | ||||
|  { | ||||
| +	int i; | ||||
| +	unsigned int tmptag; | ||||
| + | ||||
|  	if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) | ||||
|  		return; | ||||
|  	selmon->seltags ^= 1; /* toggle sel tagset */ | ||||
| -	if (arg->ui & TAGMASK) | ||||
| +	if (arg->ui & TAGMASK) { | ||||
|  		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; | ||||
| +		selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| + | ||||
| +		if (arg->ui == ~0) | ||||
| +			selmon->pertag->curtag = 0; | ||||
| +		else { | ||||
| +			for (i = 0; !(arg->ui & 1 << i); i++) ; | ||||
| +			selmon->pertag->curtag = i + 1; | ||||
| +		} | ||||
| +	} else { | ||||
| +		tmptag = selmon->pertag->prevtag; | ||||
| +		selmon->pertag->prevtag = selmon->pertag->curtag; | ||||
| +		selmon->pertag->curtag = tmptag; | ||||
| +	} | ||||
| + | ||||
| +	selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; | ||||
| +	selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; | ||||
| +	selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; | ||||
| +	selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; | ||||
| +	selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; | ||||
| + | ||||
| +	if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) | ||||
| +		togglebar(NULL); | ||||
| + | ||||
|  	focus(NULL); | ||||
|  	arrange(selmon); | ||||
|  } | ||||
| @@ -1,220 +0,0 @@ | ||||
| From ca2a2e6386a746ebfc3480787e5d99da11e7abee Mon Sep 17 00:00:00 2001 | ||||
| From: Justinas Grigas <dev@jstnas.com> | ||||
| Date: Wed, 9 Oct 2024 01:00:20 +0100 | ||||
| Subject: [PATCH] [dwm][statuscmd] better click regions | ||||
|  | ||||
| The main improvement of this patch over the previous version 20210405 is that | ||||
| the click region now ends on a matching signal raw byte. | ||||
|  | ||||
| The matching byte is optional, and without it dwm will behave as before. | ||||
|  | ||||
| To take advantage of this feature, scripts need to be modified to print the raw | ||||
| byte at the end as well. | ||||
|  | ||||
| In addition, this patch cleanly applies onto master branch. | ||||
| --- | ||||
|  config.def.h |   6 ++- | ||||
|  dwm.c        | 104 ++++++++++++++++++++++++++++++++++++++++++++++++--- | ||||
|  2 files changed, 104 insertions(+), 6 deletions(-) | ||||
|  | ||||
| diff --git a/config.def.h b/config.def.h | ||||
| index 9efa774..d008275 100644 | ||||
| --- a/config.def.h | ||||
| +++ b/config.def.h | ||||
| @@ -55,6 +55,8 @@ static const Layout layouts[] = { | ||||
|  /* helper for spawning shell commands in the pre dwm-5.0 fashion */ | ||||
|  #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | ||||
|   | ||||
| +#define STATUSBAR "dwmblocks" | ||||
| + | ||||
|  /* commands */ | ||||
|  static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | ||||
|  static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; | ||||
| @@ -104,7 +106,9 @@ static const Button buttons[] = { | ||||
|  	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} }, | ||||
|  	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} }, | ||||
|  	{ ClkWinTitle,          0,              Button2,        zoom,           {0} }, | ||||
| -	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } }, | ||||
| +	{ ClkStatusText,        0,              Button1,        sigstatusbar,   {.i = 1} }, | ||||
| +	{ ClkStatusText,        0,              Button2,        sigstatusbar,   {.i = 2} }, | ||||
| +	{ ClkStatusText,        0,              Button3,        sigstatusbar,   {.i = 3} }, | ||||
|  	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} }, | ||||
|  	{ ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} }, | ||||
|  	{ ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} }, | ||||
| diff --git a/dwm.c b/dwm.c | ||||
| index 1443802..94ee0c7 100644 | ||||
| --- a/dwm.c | ||||
| +++ b/dwm.c | ||||
| @@ -171,6 +171,7 @@ static void focusstack(const Arg *arg); | ||||
|  static Atom getatomprop(Client *c, Atom prop); | ||||
|  static int getrootptr(int *x, int *y); | ||||
|  static long getstate(Window w); | ||||
| +static pid_t getstatusbarpid(); | ||||
|  static int gettextprop(Window w, Atom atom, char *text, unsigned int size); | ||||
|  static void grabbuttons(Client *c, int focused); | ||||
|  static void grabkeys(void); | ||||
| @@ -204,6 +205,7 @@ static void setmfact(const Arg *arg); | ||||
|  static void setup(void); | ||||
|  static void seturgent(Client *c, int urg); | ||||
|  static void showhide(Client *c); | ||||
| +static void sigstatusbar(const Arg *arg); | ||||
|  static void spawn(const Arg *arg); | ||||
|  static void tag(const Arg *arg); | ||||
|  static void tagmon(const Arg *arg); | ||||
| @@ -236,6 +238,9 @@ static void zoom(const Arg *arg); | ||||
|  /* variables */ | ||||
|  static const char broken[] = "broken"; | ||||
|  static char stext[256]; | ||||
| +static int statusw; | ||||
| +static int statussig; | ||||
| +static pid_t statuspid = -1; | ||||
|  static int screen; | ||||
|  static int sw, sh;           /* X display screen geometry width, height */ | ||||
|  static int bh;               /* bar height */ | ||||
| @@ -422,6 +427,7 @@ buttonpress(XEvent *e) | ||||
|  	Client *c; | ||||
|  	Monitor *m; | ||||
|  	XButtonPressedEvent *ev = &e->xbutton; | ||||
| +	char *text, *s, ch; | ||||
|   | ||||
|  	click = ClkRootWin; | ||||
|  	/* focus monitor if necessary */ | ||||
| @@ -440,9 +446,27 @@ buttonpress(XEvent *e) | ||||
|  			arg.ui = 1 << i; | ||||
|  		} else if (ev->x < x + TEXTW(selmon->ltsymbol)) | ||||
|  			click = ClkLtSymbol; | ||||
| -		else if (ev->x > selmon->ww - (int)TEXTW(stext)) | ||||
| +		else if (ev->x > selmon->ww - statusw) { | ||||
| +			x = selmon->ww - statusw; | ||||
|  			click = ClkStatusText; | ||||
| -		else | ||||
| +			statussig = 0; | ||||
| +			for (text = s = stext; *s && x <= ev->x; s++) { | ||||
| +				if ((unsigned char)(*s) < ' ') { | ||||
| +					ch = *s; | ||||
| +					*s = '\0'; | ||||
| +					x += TEXTW(text) - lrpad; | ||||
| +					*s = ch; | ||||
| +					text = s + 1; | ||||
| +					if (x >= ev->x) | ||||
| +						break; | ||||
| +					/* reset on matching signal raw byte */ | ||||
| +					if (ch == statussig) | ||||
| +						statussig = 0; | ||||
| +					else | ||||
| +						statussig = ch; | ||||
| +				} | ||||
| +			} | ||||
| +		} else | ||||
|  			click = ClkWinTitle; | ||||
|  	} else if ((c = wintoclient(ev->window))) { | ||||
|  		focus(c); | ||||
| @@ -708,9 +732,24 @@ drawbar(Monitor *m) | ||||
|   | ||||
|  	/* draw status first so it can be overdrawn by tags later */ | ||||
|  	if (m == selmon) { /* status is only drawn on selected monitor */ | ||||
| +		char *text, *s, ch; | ||||
|  		drw_setscheme(drw, scheme[SchemeNorm]); | ||||
| -		tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ | ||||
| -		drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); | ||||
| + | ||||
| +		x = 0; | ||||
| +		for (text = s = stext; *s; s++) { | ||||
| +			if ((unsigned char)(*s) < ' ') { | ||||
| +				ch = *s; | ||||
| +				*s = '\0'; | ||||
| +				tw = TEXTW(text) - lrpad; | ||||
| +				drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); | ||||
| +				x += tw; | ||||
| +				*s = ch; | ||||
| +				text = s + 1; | ||||
| +			} | ||||
| +		} | ||||
| +		tw = TEXTW(text) - lrpad + 2; | ||||
| +		drw_text(drw, m->ww - statusw + x, 0, tw, bh, 0, text, 0); | ||||
| +		tw = statusw; | ||||
|  	} | ||||
|   | ||||
|  	for (c = m->clients; c; c = c->next) { | ||||
| @@ -876,6 +915,30 @@ getatomprop(Client *c, Atom prop) | ||||
|  	return atom; | ||||
|  } | ||||
|   | ||||
| +pid_t | ||||
| +getstatusbarpid() | ||||
| +{ | ||||
| +	char buf[32], *str = buf, *c; | ||||
| +	FILE *fp; | ||||
| + | ||||
| +	if (statuspid > 0) { | ||||
| +		snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid); | ||||
| +		if ((fp = fopen(buf, "r"))) { | ||||
| +			fgets(buf, sizeof(buf), fp); | ||||
| +			while ((c = strchr(str, '/'))) | ||||
| +				str = c + 1; | ||||
| +			fclose(fp); | ||||
| +			if (!strcmp(str, STATUSBAR)) | ||||
| +				return statuspid; | ||||
| +		} | ||||
| +	} | ||||
| +	if (!(fp = popen("pidof -s "STATUSBAR, "r"))) | ||||
| +		return -1; | ||||
| +	fgets(buf, sizeof(buf), fp); | ||||
| +	pclose(fp); | ||||
| +	return strtol(buf, NULL, 10); | ||||
| +} | ||||
| + | ||||
|  int | ||||
|  getrootptr(int *x, int *y) | ||||
|  { | ||||
| @@ -1643,6 +1706,20 @@ showhide(Client *c) | ||||
|  	} | ||||
|  } | ||||
|   | ||||
| +void | ||||
| +sigstatusbar(const Arg *arg) | ||||
| +{ | ||||
| +	union sigval sv; | ||||
| + | ||||
| +	if (!statussig) | ||||
| +		return; | ||||
| +	sv.sival_int = arg->i; | ||||
| +	if ((statuspid = getstatusbarpid()) <= 0) | ||||
| +		return; | ||||
| + | ||||
| +	sigqueue(statuspid, SIGRTMIN+statussig, sv); | ||||
| +} | ||||
| + | ||||
|  void | ||||
|  spawn(const Arg *arg) | ||||
|  { | ||||
| @@ -2004,8 +2081,25 @@ updatesizehints(Client *c) | ||||
|  void | ||||
|  updatestatus(void) | ||||
|  { | ||||
| -	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) | ||||
| +	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { | ||||
|  		strcpy(stext, "dwm-"VERSION); | ||||
| +		statusw = TEXTW(stext) - lrpad + 2; | ||||
| +	} else { | ||||
| +		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; | ||||
| + | ||||
| +	} | ||||
|  	drawbar(selmon); | ||||
|  } | ||||
|   | ||||
| --  | ||||
| 2.46.2 | ||||
|  | ||||
| @@ -1,412 +0,0 @@ | ||||
| From 0cf9a007511f7dfd7dd94171b172562ebac9b6d5 Mon Sep 17 00:00:00 2001 | ||||
| From: Tom Schwindl <schwindl@posteo.de> | ||||
| Date: Sat, 10 Sep 2022 12:51:09 +0200 | ||||
| Subject: [PATCH] 6.3 swallow patch | ||||
|  | ||||
| --- | ||||
|  config.def.h |   9 +- | ||||
|  config.mk    |   3 +- | ||||
|  dwm.c        | 235 +++++++++++++++++++++++++++++++++++++++++++++++++-- | ||||
|  3 files changed, 237 insertions(+), 10 deletions(-) | ||||
|  | ||||
| diff --git a/config.def.h b/config.def.h | ||||
| index 061ad662f82a..0b2b8ffd30d5 100644 | ||||
| --- a/config.def.h | ||||
| +++ b/config.def.h | ||||
| @@ -3,6 +3,7 @@ | ||||
|  /* appearance */ | ||||
|  static const unsigned int borderpx  = 1;        /* border pixel of windows */ | ||||
|  static const unsigned int snap      = 32;       /* snap pixel */ | ||||
| +static const int swallowfloating    = 0;        /* 1 means swallow floating windows by default */ | ||||
|  static const int showbar            = 1;        /* 0 means no bar */ | ||||
|  static const int topbar             = 1;        /* 0 means bottom bar */ | ||||
|  static const char *fonts[]          = { "monospace:size=10" }; | ||||
| @@ -26,9 +27,11 @@ static const Rule rules[] = { | ||||
|  	 *	WM_CLASS(STRING) = instance, class | ||||
|  	 *	WM_NAME(STRING) = title | ||||
|  	 */ | ||||
| -	/* class      instance    title       tags mask     isfloating   monitor */ | ||||
| -	{ "Gimp",     NULL,       NULL,       0,            1,           -1 }, | ||||
| -	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 }, | ||||
| +	/* class     instance  title           tags mask  isfloating  isterminal  noswallow  monitor */ | ||||
| +	{ "Gimp",    NULL,     NULL,           0,         1,          0,           0,        -1 }, | ||||
| +	{ "Firefox", NULL,     NULL,           1 << 8,    0,          0,          -1,        -1 }, | ||||
| +	{ "St",      NULL,     NULL,           0,         0,          1,           0,        -1 }, | ||||
| +	{ NULL,      NULL,     "Event Tester", 0,         0,          0,           1,        -1 }, /* xev */ | ||||
|  }; | ||||
|   | ||||
|  /* layout(s) */ | ||||
| diff --git a/config.mk b/config.mk | ||||
| index 81c493ef4aff..52d1ebf30bec 100644 | ||||
| --- a/config.mk | ||||
| +++ b/config.mk | ||||
| @@ -20,10 +20,11 @@ FREETYPEINC = /usr/include/freetype2 | ||||
|  # OpenBSD (uncomment) | ||||
|  #FREETYPEINC = ${X11INC}/freetype2 | ||||
|  #MANPREFIX = ${PREFIX}/man | ||||
| +#KVMLIB = -lkvm | ||||
|   | ||||
|  # includes and libs | ||||
|  INCS = -I${X11INC} -I${FREETYPEINC} | ||||
| -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} | ||||
| +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB} | ||||
|   | ||||
|  # flags | ||||
|  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} | ||||
| diff --git a/dwm.c b/dwm.c | ||||
| index e5efb6a22806..e68294b6b679 100644 | ||||
| --- a/dwm.c | ||||
| +++ b/dwm.c | ||||
| @@ -40,6 +40,12 @@ | ||||
|  #include <X11/extensions/Xinerama.h> | ||||
|  #endif /* XINERAMA */ | ||||
|  #include <X11/Xft/Xft.h> | ||||
| +#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" | ||||
| @@ -92,9 +98,11 @@ struct Client { | ||||
|  	int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; | ||||
|  	int bw, oldbw; | ||||
|  	unsigned int tags; | ||||
| -	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; | ||||
| +	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; | ||||
| +	pid_t pid; | ||||
|  	Client *next; | ||||
|  	Client *snext; | ||||
| +	Client *swallowing; | ||||
|  	Monitor *mon; | ||||
|  	Window win; | ||||
|  }; | ||||
| @@ -138,6 +146,8 @@ typedef struct { | ||||
|  	const char *title; | ||||
|  	unsigned int tags; | ||||
|  	int isfloating; | ||||
| +	int isterminal; | ||||
| +	int noswallow; | ||||
|  	int monitor; | ||||
|  } Rule; | ||||
|   | ||||
| @@ -235,6 +245,12 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); | ||||
|  static int xerrorstart(Display *dpy, XErrorEvent *ee); | ||||
|  static void zoom(const Arg *arg); | ||||
|   | ||||
| +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 */ | ||||
|  static const char broken[] = "broken"; | ||||
|  static char stext[256]; | ||||
| @@ -269,6 +285,8 @@ static Drw *drw; | ||||
|  static Monitor *mons, *selmon; | ||||
|  static Window root, wmcheckwin; | ||||
|   | ||||
| +static xcb_connection_t *xcon; | ||||
| + | ||||
|  /* configuration, allows nested code to access above variables */ | ||||
|  #include "config.h" | ||||
|   | ||||
| @@ -298,6 +316,8 @@ applyrules(Client *c) | ||||
|  		&& (!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->tags |= r->tags; | ||||
|  			for (m = mons; m && m->num != r->monitor; m = m->next); | ||||
| @@ -416,6 +436,53 @@ attachstack(Client *c) | ||||
|  	c->mon->stack = c; | ||||
|  } | ||||
|   | ||||
| +void | ||||
| +swallow(Client *p, Client *c) | ||||
| +{ | ||||
| + | ||||
| +	if (c->noswallow || c->isterminal) | ||||
| +		return; | ||||
| +	if (c->noswallow && !swallowfloating && c->isfloating) | ||||
| +		return; | ||||
| + | ||||
| +	detach(c); | ||||
| +	detachstack(c); | ||||
| + | ||||
| +	setclientstate(c, WithdrawnState); | ||||
| +	XUnmapWindow(dpy, p->win); | ||||
| + | ||||
| +	p->swallowing = c; | ||||
| +	c->mon = p->mon; | ||||
| + | ||||
| +	Window w = p->win; | ||||
| +	p->win = c->win; | ||||
| +	c->win = w; | ||||
| +	updatetitle(p); | ||||
| +	XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h); | ||||
| +	arrange(p->mon); | ||||
| +	configure(p); | ||||
| +	updateclientlist(); | ||||
| +} | ||||
| + | ||||
| +void | ||||
| +unswallow(Client *c) | ||||
| +{ | ||||
| +	c->win = c->swallowing->win; | ||||
| + | ||||
| +	free(c->swallowing); | ||||
| +	c->swallowing = NULL; | ||||
| + | ||||
| +	/* unfullscreen the client */ | ||||
| +	setfullscreen(c, 0); | ||||
| +	updatetitle(c); | ||||
| +	arrange(c->mon); | ||||
| +	XMapWindow(dpy, c->win); | ||||
| +	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); | ||||
| +	setclientstate(c, NormalState); | ||||
| +	focus(NULL); | ||||
| +	arrange(c->mon); | ||||
| +} | ||||
| + | ||||
|  void | ||||
|  buttonpress(XEvent *e) | ||||
|  { | ||||
| @@ -656,6 +723,9 @@ destroynotify(XEvent *e) | ||||
|   | ||||
|  	if ((c = wintoclient(ev->window))) | ||||
|  		unmanage(c, 1); | ||||
| + | ||||
| +	else if ((c = swallowingclient(ev->window))) | ||||
| +		unmanage(c->swallowing, 1); | ||||
|  } | ||||
|   | ||||
|  void | ||||
| @@ -1022,12 +1092,13 @@ killclient(const Arg *arg) | ||||
|  void | ||||
|  manage(Window w, XWindowAttributes *wa) | ||||
|  { | ||||
| -	Client *c, *t = NULL; | ||||
| +	Client *c, *t = NULL, *term = NULL; | ||||
|  	Window trans = None; | ||||
|  	XWindowChanges wc; | ||||
|   | ||||
|  	c = ecalloc(1, sizeof(Client)); | ||||
|  	c->win = w; | ||||
| +	c->pid = winpid(w); | ||||
|  	/* geometry */ | ||||
|  	c->x = c->oldx = wa->x; | ||||
|  	c->y = c->oldy = wa->y; | ||||
| @@ -1042,6 +1113,7 @@ manage(Window w, XWindowAttributes *wa) | ||||
|  	} else { | ||||
|  		c->mon = selmon; | ||||
|  		applyrules(c); | ||||
| +		term = termforwin(c); | ||||
|  	} | ||||
|   | ||||
|  	if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) | ||||
| @@ -1076,6 +1148,8 @@ manage(Window w, XWindowAttributes *wa) | ||||
|  	c->mon->sel = c; | ||||
|  	arrange(c->mon); | ||||
|  	XMapWindow(dpy, c->win); | ||||
| +	if (term) | ||||
| +		swallow(term, c); | ||||
|  	focus(NULL); | ||||
|  } | ||||
|   | ||||
| @@ -1763,6 +1837,20 @@ 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); | ||||
|  	if (!destroyed) { | ||||
| @@ -1778,9 +1866,12 @@ unmanage(Client *c, int destroyed) | ||||
|  		XUngrabServer(dpy); | ||||
|  	} | ||||
|  	free(c); | ||||
| -	focus(NULL); | ||||
| -	updateclientlist(); | ||||
| -	arrange(m); | ||||
| + | ||||
| +	if (!s) { | ||||
| +		arrange(m); | ||||
| +		focus(NULL); | ||||
| +		updateclientlist(); | ||||
| +	} | ||||
|  } | ||||
|   | ||||
|  void | ||||
| @@ -2044,6 +2135,136 @@ view(const Arg *arg) | ||||
|  	arrange(selmon); | ||||
|  } | ||||
|   | ||||
| +pid_t | ||||
| +winpid(Window w) | ||||
| +{ | ||||
| + | ||||
| +	pid_t result = 0; | ||||
| + | ||||
| +#ifdef __linux__ | ||||
| +	xcb_res_client_id_spec_t spec = {0}; | ||||
| +	spec.client = w; | ||||
| +	spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; | ||||
| + | ||||
| +	xcb_generic_error_t *e = NULL; | ||||
| +	xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); | ||||
| +	xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); | ||||
| + | ||||
| +	if (!r) | ||||
| +		return (pid_t)0; | ||||
| + | ||||
| +	xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); | ||||
| +	for (; i.rem; xcb_res_client_id_value_next(&i)) { | ||||
| +		spec = i.data->spec; | ||||
| +		if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { | ||||
| +			uint32_t *t = xcb_res_client_id_value_value(i.data); | ||||
| +			result = *t; | ||||
| +			break; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
| +	free(r); | ||||
| + | ||||
| +	if (result == (pid_t)-1) | ||||
| +		result = 0; | ||||
| + | ||||
| +#endif /* __linux__ */ | ||||
| + | ||||
| +#ifdef __OpenBSD__ | ||||
| +        Atom type; | ||||
| +        int format; | ||||
| +        unsigned long len, bytes; | ||||
| +        unsigned char *prop; | ||||
| +        pid_t ret; | ||||
| + | ||||
| +        if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop) | ||||
| +               return 0; | ||||
| + | ||||
| +        ret = *(pid_t*)prop; | ||||
| +        XFree(prop); | ||||
| +        result = ret; | ||||
| + | ||||
| +#endif /* __OpenBSD__ */ | ||||
| +	return result; | ||||
| +} | ||||
| + | ||||
| +pid_t | ||||
| +getparentprocess(pid_t p) | ||||
| +{ | ||||
| +	unsigned int v = 0; | ||||
| + | ||||
| +#ifdef __linux__ | ||||
| +	FILE *f; | ||||
| +	char buf[256]; | ||||
| +	snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); | ||||
| + | ||||
| +	if (!(f = fopen(buf, "r"))) | ||||
| +		return 0; | ||||
| + | ||||
| +	fscanf(f, "%*u %*s %*c %u", &v); | ||||
| +	fclose(f); | ||||
| +#endif /* __linux__*/ | ||||
| + | ||||
| +#ifdef __OpenBSD__ | ||||
| +	int n; | ||||
| +	kvm_t *kd; | ||||
| +	struct kinfo_proc *kp; | ||||
| + | ||||
| +	kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); | ||||
| +	if (!kd) | ||||
| +		return 0; | ||||
| + | ||||
| +	kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); | ||||
| +	v = kp->p_ppid; | ||||
| +#endif /* __OpenBSD__ */ | ||||
| + | ||||
| +	return (pid_t)v; | ||||
| +} | ||||
| + | ||||
| +int | ||||
| +isdescprocess(pid_t p, pid_t c) | ||||
| +{ | ||||
| +	while (p != c && c != 0) | ||||
| +		c = getparentprocess(c); | ||||
| + | ||||
| +	return (int)c; | ||||
| +} | ||||
| + | ||||
| +Client * | ||||
| +termforwin(const Client *w) | ||||
| +{ | ||||
| +	Client *c; | ||||
| +	Monitor *m; | ||||
| + | ||||
| +	if (!w->pid || w->isterminal) | ||||
| +		return NULL; | ||||
| + | ||||
| +	for (m = mons; m; m = m->next) { | ||||
| +		for (c = m->clients; c; c = c->next) { | ||||
| +			if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) | ||||
| +				return c; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
| +	return NULL; | ||||
| +} | ||||
| + | ||||
| +Client * | ||||
| +swallowingclient(Window w) | ||||
| +{ | ||||
| +	Client *c; | ||||
| +	Monitor *m; | ||||
| + | ||||
| +	for (m = mons; m; m = m->next) { | ||||
| +		for (c = m->clients; c; c = c->next) { | ||||
| +			if (c->swallowing && c->swallowing->win == w) | ||||
| +				return c; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
| +	return NULL; | ||||
| +} | ||||
| + | ||||
|  Client * | ||||
|  wintoclient(Window w) | ||||
|  { | ||||
| @@ -2133,10 +2354,12 @@ main(int argc, char *argv[]) | ||||
|  		fputs("warning: no locale support\n", stderr); | ||||
|  	if (!(dpy = XOpenDisplay(NULL))) | ||||
|  		die("dwm: cannot open display"); | ||||
| +	if (!(xcon = XGetXCBConnection(dpy))) | ||||
| +		die("dwm: cannot get xcb connection\n"); | ||||
|  	checkotherwm(); | ||||
|  	setup(); | ||||
|  #ifdef __OpenBSD__ | ||||
| -	if (pledge("stdio rpath proc exec", NULL) == -1) | ||||
| +	if (pledge("stdio rpath proc exec ps", NULL) == -1) | ||||
|  		die("pledge"); | ||||
|  #endif /* __OpenBSD__ */ | ||||
|  	scan(); | ||||
| --  | ||||
| 2.37.2 | ||||
|  | ||||
| @@ -1,4 +0,0 @@ | ||||
| dwm-swallow-6.3.diff | ||||
| dwm-hide_vacant_tags-6.4.diff | ||||
| dwm-pertag-20200914-61bb8b2.diff | ||||
| dwm-statuscmd-20241009-8933ebc.diff | ||||
		Reference in New Issue
	
	Block a user