Initial commit
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | *.o | ||||||
|  | dwm | ||||||
|  | config.h | ||||||
|  | config.mk | ||||||
							
								
								
									
										37
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | MIT/X Consortium License | ||||||
|  |  | ||||||
|  | © 2006-2019 Anselm R Garbe <anselm@garbe.ca> | ||||||
|  | © 2006-2009 Jukka Salmi <jukka at salmi dot ch> | ||||||
|  | © 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com> | ||||||
|  | © 2007-2011 Peter Hartlich <sgkkr at hartlich dot com> | ||||||
|  | © 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com> | ||||||
|  | © 2007-2009 Christof Musik <christof at sendfax dot de> | ||||||
|  | © 2007-2009 Premysl Hruby <dfenze at gmail dot com> | ||||||
|  | © 2007-2008 Enno Gottox Boland <gottox at s01 dot de> | ||||||
|  | © 2008 Martin Hurton <martin dot hurton at gmail dot com> | ||||||
|  | © 2008 Neale Pickett <neale dot woozle dot org> | ||||||
|  | © 2009 Mate Nagy <mnagy at port70 dot net> | ||||||
|  | © 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org> | ||||||
|  | © 2010-2012 Connor Lane Smith <cls@lubutu.com> | ||||||
|  | © 2011 Christoph Lohmann <20h@r-36.net> | ||||||
|  | © 2015-2016 Quentin Rameau <quinq@fifth.space> | ||||||
|  | © 2015-2016 Eric Pruitt <eric.pruitt@gmail.com> | ||||||
|  | © 2016-2017 Markus Teich <markus.teich@stusta.mhn.de> | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  | copy of this software and associated documentation files (the "Software"), | ||||||
|  | to deal in the Software without restriction, including without limitation | ||||||
|  | the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  | and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  | Software is furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||||
|  | DEALINGS IN THE SOFTWARE. | ||||||
							
								
								
									
										51
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | # dwm - dynamic window manager | ||||||
|  | # See LICENSE file for copyright and license details. | ||||||
|  |  | ||||||
|  | include config.mk | ||||||
|  |  | ||||||
|  | SRC = drw.c dwm.c util.c | ||||||
|  | OBJ = ${SRC:.c=.o} | ||||||
|  |  | ||||||
|  | all: options dwm | ||||||
|  |  | ||||||
|  | options: | ||||||
|  | 	@echo dwm build options: | ||||||
|  | 	@echo "CFLAGS   = ${CFLAGS}" | ||||||
|  | 	@echo "LDFLAGS  = ${LDFLAGS}" | ||||||
|  | 	@echo "CC       = ${CC}" | ||||||
|  |  | ||||||
|  | .c.o: | ||||||
|  | 	${CC} -c ${CFLAGS} $< | ||||||
|  |  | ||||||
|  | ${OBJ}: config.h config.mk | ||||||
|  |  | ||||||
|  | config.h: | ||||||
|  | 	cp config.def.h $@ | ||||||
|  |  | ||||||
|  | dwm: ${OBJ} | ||||||
|  | 	${CC} -o $@ ${OBJ} ${LDFLAGS} | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz | ||||||
|  |  | ||||||
|  | dist: clean | ||||||
|  | 	mkdir -p dwm-${VERSION} | ||||||
|  | 	cp -R LICENSE Makefile README config.def.h config.mk\ | ||||||
|  | 		dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} | ||||||
|  | 	tar -cf dwm-${VERSION}.tar dwm-${VERSION} | ||||||
|  | 	gzip dwm-${VERSION}.tar | ||||||
|  | 	rm -rf dwm-${VERSION} | ||||||
|  |  | ||||||
|  | install: all | ||||||
|  | 	mkdir -p ${DESTDIR}${PREFIX}/bin | ||||||
|  | 	cp -f dwm ${DESTDIR}${PREFIX}/bin | ||||||
|  | 	chmod 755 ${DESTDIR}${PREFIX}/bin/dwm | ||||||
|  | 	mkdir -p ${DESTDIR}${MANPREFIX}/man1 | ||||||
|  | 	sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 | ||||||
|  | 	chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 | ||||||
|  |  | ||||||
|  | uninstall: | ||||||
|  | 	rm -f ${DESTDIR}${PREFIX}/bin/dwm\ | ||||||
|  | 		${DESTDIR}${MANPREFIX}/man1/dwm.1 | ||||||
|  |  | ||||||
|  | .PHONY: all options clean dist install uninstall | ||||||
							
								
								
									
										48
									
								
								README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								README
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | |||||||
|  | dwm - dynamic window manager | ||||||
|  | ============================ | ||||||
|  | dwm is an extremely fast, small, and dynamic window manager for X. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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. | ||||||
							
								
								
									
										130
									
								
								config.def.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								config.def.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | |||||||
|  | /* 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 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" }; | ||||||
|  | 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  }, | ||||||
|  | 	[SchemeStatus]  = { col_gray3, col_gray1,  "#000000"  }, // Statusbar right {text,background,not used but cannot be empty} | ||||||
|  | 	[SchemeTagsSel]  = { col_gray4, col_cyan,  "#000000"  }, // Tagbar left selected {text,background,not used but cannot be empty} | ||||||
|  |     [SchemeTagsNorm]  = { col_gray3, col_gray1,  "#000000"  }, // Tagbar left unselected {text,background,not used but cannot be empty} | ||||||
|  |     [SchemeInfoSel]  = { col_gray4, col_cyan,  "#000000"  }, // infobar middle  selected {text,background,not used but cannot be empty} | ||||||
|  |     [SchemeInfoNorm]  = { col_gray3, col_gray1,  "#000000"  }, // infobar middle  unselected {text,background,not used but cannot be empty} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* 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 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 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|ShiftMask,             XK_h,      setcfact,       {.f = +0.25} }, | ||||||
|  | 	{ MODKEY|ShiftMask,             XK_l,      setcfact,       {.f = -0.25} }, | ||||||
|  | 	{ MODKEY|ShiftMask,             XK_o,      setcfact,       {.f =  0.00} }, | ||||||
|  | 	{ 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|ShiftMask,             XK_space,  togglealwaysontop, {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 Button buttons[] = { | ||||||
|  | 	/* click                event mask      button          function        argument */ | ||||||
|  | 	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} }, | ||||||
|  | 	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} }, | ||||||
|  | 	{ 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} }, | ||||||
|  | }; | ||||||
|  |  | ||||||
							
								
								
									
										39
									
								
								config.def.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								config.def.mk
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | # dwm version | ||||||
|  | VERSION = 6.3 | ||||||
|  |  | ||||||
|  | # Customize below to fit your system | ||||||
|  |  | ||||||
|  | # paths | ||||||
|  | PREFIX = /usr/local | ||||||
|  | MANPREFIX = ${PREFIX}/share/man | ||||||
|  | SCRIPT_DIR = ${HOME}/Workspace/Scripts | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  |  | ||||||
|  | # includes and libs | ||||||
|  | INCS = -I${X11INC} -I${FREETYPEINC} | ||||||
|  | LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} | ||||||
|  |  | ||||||
|  | # flags | ||||||
|  | CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DSCRIPT_DIR=\"${SCRIPT_DIR}\" -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 | ||||||
							
								
								
									
										436
									
								
								drw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								drw.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,436 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <X11/Xlib.h> | ||||||
|  | #include <X11/Xft/Xft.h> | ||||||
|  |  | ||||||
|  | #include "drw.h" | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | #define UTF_INVALID 0xFFFD | ||||||
|  | #define UTF_SIZ     4 | ||||||
|  |  | ||||||
|  | static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80,    0, 0xC0, 0xE0, 0xF0}; | ||||||
|  | static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; | ||||||
|  | static const long utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000}; | ||||||
|  | static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; | ||||||
|  |  | ||||||
|  | static long | ||||||
|  | utf8decodebyte(const char c, size_t *i) | ||||||
|  | { | ||||||
|  | 	for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) | ||||||
|  | 		if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) | ||||||
|  | 			return (unsigned char)c & ~utfmask[*i]; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static size_t | ||||||
|  | utf8validate(long *u, size_t i) | ||||||
|  | { | ||||||
|  | 	if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) | ||||||
|  | 		*u = UTF_INVALID; | ||||||
|  | 	for (i = 1; *u > utfmax[i]; ++i) | ||||||
|  | 		; | ||||||
|  | 	return i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static size_t | ||||||
|  | utf8decode(const char *c, long *u, size_t clen) | ||||||
|  | { | ||||||
|  | 	size_t i, j, len, type; | ||||||
|  | 	long udecoded; | ||||||
|  |  | ||||||
|  | 	*u = UTF_INVALID; | ||||||
|  | 	if (!clen) | ||||||
|  | 		return 0; | ||||||
|  | 	udecoded = utf8decodebyte(c[0], &len); | ||||||
|  | 	if (!BETWEEN(len, 1, UTF_SIZ)) | ||||||
|  | 		return 1; | ||||||
|  | 	for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { | ||||||
|  | 		udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); | ||||||
|  | 		if (type) | ||||||
|  | 			return j; | ||||||
|  | 	} | ||||||
|  | 	if (j < len) | ||||||
|  | 		return 0; | ||||||
|  | 	*u = udecoded; | ||||||
|  | 	utf8validate(u, len); | ||||||
|  |  | ||||||
|  | 	return len; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Drw * | ||||||
|  | drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) | ||||||
|  | { | ||||||
|  | 	Drw *drw = ecalloc(1, sizeof(Drw)); | ||||||
|  |  | ||||||
|  | 	drw->dpy = dpy; | ||||||
|  | 	drw->screen = screen; | ||||||
|  | 	drw->root = root; | ||||||
|  | 	drw->w = w; | ||||||
|  | 	drw->h = h; | ||||||
|  | 	drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); | ||||||
|  | 	drw->gc = XCreateGC(dpy, root, 0, NULL); | ||||||
|  | 	XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); | ||||||
|  |  | ||||||
|  | 	return drw; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_resize(Drw *drw, unsigned int w, unsigned int h) | ||||||
|  | { | ||||||
|  | 	if (!drw) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	drw->w = w; | ||||||
|  | 	drw->h = h; | ||||||
|  | 	if (drw->drawable) | ||||||
|  | 		XFreePixmap(drw->dpy, drw->drawable); | ||||||
|  | 	drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_free(Drw *drw) | ||||||
|  | { | ||||||
|  | 	XFreePixmap(drw->dpy, drw->drawable); | ||||||
|  | 	XFreeGC(drw->dpy, drw->gc); | ||||||
|  | 	drw_fontset_free(drw->fonts); | ||||||
|  | 	free(drw); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* This function is an implementation detail. Library users should use | ||||||
|  |  * drw_fontset_create instead. | ||||||
|  |  */ | ||||||
|  | static Fnt * | ||||||
|  | xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) | ||||||
|  | { | ||||||
|  | 	Fnt *font; | ||||||
|  | 	XftFont *xfont = NULL; | ||||||
|  | 	FcPattern *pattern = NULL; | ||||||
|  |  | ||||||
|  | 	if (fontname) { | ||||||
|  | 		/* Using the pattern found at font->xfont->pattern does not yield the | ||||||
|  | 		 * same substitution results as using the pattern returned by | ||||||
|  | 		 * FcNameParse; using the latter results in the desired fallback | ||||||
|  | 		 * behaviour whereas the former just results in missing-character | ||||||
|  | 		 * rectangles being drawn, at least with some fonts. */ | ||||||
|  | 		if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { | ||||||
|  | 			fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 		if (!(pattern = FcNameParse((FcChar8 *) fontname))) { | ||||||
|  | 			fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); | ||||||
|  | 			XftFontClose(drw->dpy, xfont); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 	} else if (fontpattern) { | ||||||
|  | 		if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { | ||||||
|  | 			fprintf(stderr, "error, cannot load font from pattern.\n"); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		die("no font specified."); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Do not allow using color fonts. This is a workaround for a BadLength | ||||||
|  | 	 * error from Xft with color glyphs. Modelled on the Xterm workaround. See | ||||||
|  | 	 * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 | ||||||
|  | 	 * https://lists.suckless.org/dev/1701/30932.html | ||||||
|  | 	 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 | ||||||
|  | 	 * and lots more all over the internet. | ||||||
|  | 	 */ | ||||||
|  | 	FcBool iscol; | ||||||
|  | 	if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { | ||||||
|  | 		XftFontClose(drw->dpy, xfont); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	font = ecalloc(1, sizeof(Fnt)); | ||||||
|  | 	font->xfont = xfont; | ||||||
|  | 	font->pattern = pattern; | ||||||
|  | 	font->h = xfont->ascent + xfont->descent; | ||||||
|  | 	font->dpy = drw->dpy; | ||||||
|  |  | ||||||
|  | 	return font; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | xfont_free(Fnt *font) | ||||||
|  | { | ||||||
|  | 	if (!font) | ||||||
|  | 		return; | ||||||
|  | 	if (font->pattern) | ||||||
|  | 		FcPatternDestroy(font->pattern); | ||||||
|  | 	XftFontClose(font->dpy, font->xfont); | ||||||
|  | 	free(font); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Fnt* | ||||||
|  | drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) | ||||||
|  | { | ||||||
|  | 	Fnt *cur, *ret = NULL; | ||||||
|  | 	size_t i; | ||||||
|  |  | ||||||
|  | 	if (!drw || !fonts) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	for (i = 1; i <= fontcount; i++) { | ||||||
|  | 		if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { | ||||||
|  | 			cur->next = ret; | ||||||
|  | 			ret = cur; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (drw->fonts = ret); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_fontset_free(Fnt *font) | ||||||
|  | { | ||||||
|  | 	if (font) { | ||||||
|  | 		drw_fontset_free(font->next); | ||||||
|  | 		xfont_free(font); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_clr_create(Drw *drw, Clr *dest, const char *clrname) | ||||||
|  | { | ||||||
|  | 	if (!drw || !dest || !clrname) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), | ||||||
|  | 	                       DefaultColormap(drw->dpy, drw->screen), | ||||||
|  | 	                       clrname, dest)) | ||||||
|  | 		die("error, cannot allocate color '%s'", clrname); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Wrapper to create color schemes. The caller has to call free(3) on the | ||||||
|  |  * returned color scheme when done using it. */ | ||||||
|  | Clr * | ||||||
|  | drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) | ||||||
|  | { | ||||||
|  | 	size_t i; | ||||||
|  | 	Clr *ret; | ||||||
|  |  | ||||||
|  | 	/* need at least two colors for a scheme */ | ||||||
|  | 	if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < clrcount; i++) | ||||||
|  | 		drw_clr_create(drw, &ret[i], clrnames[i]); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_setfontset(Drw *drw, Fnt *set) | ||||||
|  | { | ||||||
|  | 	if (drw) | ||||||
|  | 		drw->fonts = set; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_setscheme(Drw *drw, Clr *scm) | ||||||
|  | { | ||||||
|  | 	if (drw) | ||||||
|  | 		drw->scheme = scm; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) | ||||||
|  | { | ||||||
|  | 	if (!drw || !drw->scheme) | ||||||
|  | 		return; | ||||||
|  | 	XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); | ||||||
|  | 	if (filled) | ||||||
|  | 		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | ||||||
|  | 	else | ||||||
|  | 		XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) | ||||||
|  | { | ||||||
|  | 	char buf[1024]; | ||||||
|  | 	int ty; | ||||||
|  | 	unsigned int ew; | ||||||
|  | 	XftDraw *d = NULL; | ||||||
|  | 	Fnt *usedfont, *curfont, *nextfont; | ||||||
|  | 	size_t i, len; | ||||||
|  | 	int utf8strlen, utf8charlen, render = x || y || w || h; | ||||||
|  | 	long utf8codepoint = 0; | ||||||
|  | 	const char *utf8str; | ||||||
|  | 	FcCharSet *fccharset; | ||||||
|  | 	FcPattern *fcpattern; | ||||||
|  | 	FcPattern *match; | ||||||
|  | 	XftResult result; | ||||||
|  | 	int charexists = 0; | ||||||
|  |  | ||||||
|  | 	if (!drw || (render && !drw->scheme) || !text || !drw->fonts) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	if (!render) { | ||||||
|  | 		w = ~w; | ||||||
|  | 	} else { | ||||||
|  | 		XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); | ||||||
|  | 		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); | ||||||
|  | 		d = XftDrawCreate(drw->dpy, drw->drawable, | ||||||
|  | 		                  DefaultVisual(drw->dpy, drw->screen), | ||||||
|  | 		                  DefaultColormap(drw->dpy, drw->screen)); | ||||||
|  | 		x += lpad; | ||||||
|  | 		w -= lpad; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	usedfont = drw->fonts; | ||||||
|  | 	while (1) { | ||||||
|  | 		utf8strlen = 0; | ||||||
|  | 		utf8str = text; | ||||||
|  | 		nextfont = NULL; | ||||||
|  | 		while (*text) { | ||||||
|  | 			utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); | ||||||
|  | 			for (curfont = drw->fonts; curfont; curfont = curfont->next) { | ||||||
|  | 				charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); | ||||||
|  | 				if (charexists) { | ||||||
|  | 					if (curfont == usedfont) { | ||||||
|  | 						utf8strlen += utf8charlen; | ||||||
|  | 						text += utf8charlen; | ||||||
|  | 					} else { | ||||||
|  | 						nextfont = curfont; | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (!charexists || nextfont) | ||||||
|  | 				break; | ||||||
|  | 			else | ||||||
|  | 				charexists = 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (utf8strlen) { | ||||||
|  | 			drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); | ||||||
|  | 			/* shorten text if necessary */ | ||||||
|  | 			for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) | ||||||
|  | 				drw_font_getexts(usedfont, utf8str, len, &ew, NULL); | ||||||
|  |  | ||||||
|  | 			if (len) { | ||||||
|  | 				memcpy(buf, utf8str, len); | ||||||
|  | 				buf[len] = '\0'; | ||||||
|  | 				if (len < utf8strlen) | ||||||
|  | 					for (i = len; i && i > len - 3; buf[--i] = '.') | ||||||
|  | 						; /* NOP */ | ||||||
|  |  | ||||||
|  | 				if (render) { | ||||||
|  | 					ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; | ||||||
|  | 					XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], | ||||||
|  | 					                  usedfont->xfont, x, ty, (XftChar8 *)buf, len); | ||||||
|  | 				} | ||||||
|  | 				x += ew; | ||||||
|  | 				w -= ew; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!*text) { | ||||||
|  | 			break; | ||||||
|  | 		} else if (nextfont) { | ||||||
|  | 			charexists = 0; | ||||||
|  | 			usedfont = nextfont; | ||||||
|  | 		} else { | ||||||
|  | 			/* Regardless of whether or not a fallback font is found, the | ||||||
|  | 			 * character must be drawn. */ | ||||||
|  | 			charexists = 1; | ||||||
|  |  | ||||||
|  | 			fccharset = FcCharSetCreate(); | ||||||
|  | 			FcCharSetAddChar(fccharset, utf8codepoint); | ||||||
|  |  | ||||||
|  | 			if (!drw->fonts->pattern) { | ||||||
|  | 				/* Refer to the comment in xfont_create for more information. */ | ||||||
|  | 				die("the first font in the cache must be loaded from a font string."); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			fcpattern = FcPatternDuplicate(drw->fonts->pattern); | ||||||
|  | 			FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); | ||||||
|  | 			FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); | ||||||
|  | 			FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); | ||||||
|  |  | ||||||
|  | 			FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); | ||||||
|  | 			FcDefaultSubstitute(fcpattern); | ||||||
|  | 			match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); | ||||||
|  |  | ||||||
|  | 			FcCharSetDestroy(fccharset); | ||||||
|  | 			FcPatternDestroy(fcpattern); | ||||||
|  |  | ||||||
|  | 			if (match) { | ||||||
|  | 				usedfont = xfont_create(drw, NULL, match); | ||||||
|  | 				if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { | ||||||
|  | 					for (curfont = drw->fonts; curfont->next; curfont = curfont->next) | ||||||
|  | 						; /* NOP */ | ||||||
|  | 					curfont->next = usedfont; | ||||||
|  | 				} else { | ||||||
|  | 					xfont_free(usedfont); | ||||||
|  | 					usedfont = drw->fonts; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (d) | ||||||
|  | 		XftDrawDestroy(d); | ||||||
|  |  | ||||||
|  | 	return x + (render ? w : 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) | ||||||
|  | { | ||||||
|  | 	if (!drw) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); | ||||||
|  | 	XSync(drw->dpy, False); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | unsigned int | ||||||
|  | drw_fontset_getwidth(Drw *drw, const char *text) | ||||||
|  | { | ||||||
|  | 	if (!drw || !drw->fonts || !text) | ||||||
|  | 		return 0; | ||||||
|  | 	return drw_text(drw, 0, 0, 0, 0, 0, text, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) | ||||||
|  | { | ||||||
|  | 	XGlyphInfo ext; | ||||||
|  |  | ||||||
|  | 	if (!font || !text) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); | ||||||
|  | 	if (w) | ||||||
|  | 		*w = ext.xOff; | ||||||
|  | 	if (h) | ||||||
|  | 		*h = font->h; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Cur * | ||||||
|  | drw_cur_create(Drw *drw, int shape) | ||||||
|  | { | ||||||
|  | 	Cur *cur; | ||||||
|  |  | ||||||
|  | 	if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	cur->cursor = XCreateFontCursor(drw->dpy, shape); | ||||||
|  |  | ||||||
|  | 	return cur; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | drw_cur_free(Drw *drw, Cur *cursor) | ||||||
|  | { | ||||||
|  | 	if (!cursor) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	XFreeCursor(drw->dpy, cursor->cursor); | ||||||
|  | 	free(cursor); | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								drw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								drw.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  | 	Cursor cursor; | ||||||
|  | } Cur; | ||||||
|  |  | ||||||
|  | typedef struct Fnt { | ||||||
|  | 	Display *dpy; | ||||||
|  | 	unsigned int h; | ||||||
|  | 	XftFont *xfont; | ||||||
|  | 	FcPattern *pattern; | ||||||
|  | 	struct Fnt *next; | ||||||
|  | } Fnt; | ||||||
|  |  | ||||||
|  | enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ | ||||||
|  | typedef XftColor Clr; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  | 	unsigned int w, h; | ||||||
|  | 	Display *dpy; | ||||||
|  | 	int screen; | ||||||
|  | 	Window root; | ||||||
|  | 	Drawable drawable; | ||||||
|  | 	GC gc; | ||||||
|  | 	Clr *scheme; | ||||||
|  | 	Fnt *fonts; | ||||||
|  | } Drw; | ||||||
|  |  | ||||||
|  | /* Drawable abstraction */ | ||||||
|  | Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); | ||||||
|  | void drw_resize(Drw *drw, unsigned int w, unsigned int h); | ||||||
|  | void drw_free(Drw *drw); | ||||||
|  |  | ||||||
|  | /* Fnt abstraction */ | ||||||
|  | Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); | ||||||
|  | void drw_fontset_free(Fnt* set); | ||||||
|  | unsigned int drw_fontset_getwidth(Drw *drw, const char *text); | ||||||
|  | void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); | ||||||
|  |  | ||||||
|  | /* Colorscheme abstraction */ | ||||||
|  | void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); | ||||||
|  | Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); | ||||||
|  |  | ||||||
|  | /* Cursor abstraction */ | ||||||
|  | Cur *drw_cur_create(Drw *drw, int shape); | ||||||
|  | void drw_cur_free(Drw *drw, Cur *cursor); | ||||||
|  |  | ||||||
|  | /* Drawing context manipulation */ | ||||||
|  | void drw_setfontset(Drw *drw, Fnt *set); | ||||||
|  | void drw_setscheme(Drw *drw, Clr *scm); | ||||||
|  |  | ||||||
|  | /* Drawing functions */ | ||||||
|  | void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); | ||||||
|  | int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); | ||||||
|  |  | ||||||
|  | /* Map functions */ | ||||||
|  | void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); | ||||||
							
								
								
									
										176
									
								
								dwm.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								dwm.1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | |||||||
|  | .TH DWM 1 dwm\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | dwm \- dynamic window manager | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B dwm | ||||||
|  | .RB [ \-v ] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | dwm is a dynamic window manager for X. It manages windows in tiled, monocle | ||||||
|  | and floating layouts. Either layout can be applied dynamically, optimising the | ||||||
|  | environment for the application in use and the task performed. | ||||||
|  | .P | ||||||
|  | In tiled layouts windows are managed in a master and stacking area. The master | ||||||
|  | area on the left contains one window by default, and the stacking area on the | ||||||
|  | right contains all other windows. The number of master area windows can be | ||||||
|  | adjusted from zero to an arbitrary number. In monocle layout all windows are | ||||||
|  | maximised to the screen size. In floating layout windows can be resized and | ||||||
|  | moved freely. Dialog windows are always managed floating, regardless of the | ||||||
|  | layout applied. | ||||||
|  | .P | ||||||
|  | Windows are grouped by tags. Each window can be tagged with one or multiple | ||||||
|  | tags. Selecting certain tags displays all windows with these tags. | ||||||
|  | .P | ||||||
|  | Each screen contains a small status bar which displays all available tags, the | ||||||
|  | layout, the title of the focused window, and the text read from the root window | ||||||
|  | name property, if the screen is focused. A floating window is indicated with an | ||||||
|  | empty square and a maximised floating window is indicated with a filled square | ||||||
|  | before the windows title.  The selected tags are indicated with a different | ||||||
|  | color. The tags of the focused window are indicated with a filled square in the | ||||||
|  | top left corner.  The tags which are applied to one or more windows are | ||||||
|  | indicated with an empty square in the top left corner. | ||||||
|  | .P | ||||||
|  | dwm draws a small border around windows to indicate the focus state. | ||||||
|  | .SH OPTIONS | ||||||
|  | .TP | ||||||
|  | .B \-v | ||||||
|  | prints version information to stderr, then exits. | ||||||
|  | .SH USAGE | ||||||
|  | .SS Status bar | ||||||
|  | .TP | ||||||
|  | .B X root window name | ||||||
|  | is read and displayed in the status text area. It can be set with the | ||||||
|  | .BR xsetroot (1) | ||||||
|  | command. | ||||||
|  | .TP | ||||||
|  | .B Button1 | ||||||
|  | click on a tag label to display all windows with that tag, click on the layout | ||||||
|  | label toggles between tiled and floating layout. | ||||||
|  | .TP | ||||||
|  | .B Button3 | ||||||
|  | click on a tag label adds/removes all windows with that tag to/from the view. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Button1 | ||||||
|  | click on a tag label applies that tag to the focused window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Button3 | ||||||
|  | click on a tag label adds/removes that tag to/from the focused window. | ||||||
|  | .SS Keyboard commands | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-Return | ||||||
|  | Start | ||||||
|  | .BR st(1). | ||||||
|  | .TP | ||||||
|  | .B Mod1\-p | ||||||
|  | Spawn | ||||||
|  | .BR dmenu(1) | ||||||
|  | for launching other programs. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-, | ||||||
|  | Focus previous screen, if any. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-. | ||||||
|  | Focus next screen, if any. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-, | ||||||
|  | Send focused window to previous screen, if any. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-. | ||||||
|  | Send focused window to next screen, if any. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-b | ||||||
|  | Toggles bar on and off. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-t | ||||||
|  | Sets tiled layout. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-f | ||||||
|  | Sets floating layout. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-m | ||||||
|  | Sets monocle layout. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-space | ||||||
|  | Toggles between current and previous layout. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-j | ||||||
|  | Focus next window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-k | ||||||
|  | Focus previous window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-i | ||||||
|  | Increase number of windows in master area. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-d | ||||||
|  | Decrease number of windows in master area. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-l | ||||||
|  | Increase master area size. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-h | ||||||
|  | Decrease master area size. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Return | ||||||
|  | Zooms/cycles focused window to/from master area (tiled layouts only). | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-c | ||||||
|  | Close focused window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-space | ||||||
|  | Toggle focused window between tiled and floating state. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Tab | ||||||
|  | Toggles to the previously selected tags. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-[1..n] | ||||||
|  | Apply nth tag to focused window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-0 | ||||||
|  | Apply all tags to focused window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Control\-Shift\-[1..n] | ||||||
|  | Add/remove nth tag to/from focused window. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-[1..n] | ||||||
|  | View all windows with nth tag. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-0 | ||||||
|  | View all windows with any tag. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Control\-[1..n] | ||||||
|  | Add/remove all windows with nth tag to/from the view. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Shift\-q | ||||||
|  | Quit dwm. | ||||||
|  | .SS Mouse commands | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Button1 | ||||||
|  | Move focused window while dragging. Tiled windows will be toggled to the floating state. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Button2 | ||||||
|  | Toggles focused window between floating and tiled state. | ||||||
|  | .TP | ||||||
|  | .B Mod1\-Button3 | ||||||
|  | Resize focused window while dragging. Tiled windows will be toggled to the floating state. | ||||||
|  | .SH CUSTOMIZATION | ||||||
|  | dwm is customized by creating a custom config.h and (re)compiling the source | ||||||
|  | code. This keeps it fast, secure and simple. | ||||||
|  | .SH SEE ALSO | ||||||
|  | .BR dmenu (1), | ||||||
|  | .BR st (1) | ||||||
|  | .SH ISSUES | ||||||
|  | Java applications which use the XToolkit/XAWT backend may draw grey windows | ||||||
|  | only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early | ||||||
|  | JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds | ||||||
|  | are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the | ||||||
|  | environment variable | ||||||
|  | .BR AWT_TOOLKIT=MToolkit | ||||||
|  | (to use the older Motif backend instead) or running | ||||||
|  | .B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D | ||||||
|  | or | ||||||
|  | .B wmname LG3D | ||||||
|  | (to pretend that a non-reparenting window manager is running that the | ||||||
|  | XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable | ||||||
|  | .BR _JAVA_AWT_WM_NONREPARENTING=1 . | ||||||
|  | .SH BUGS | ||||||
|  | Send all bug reports with a patch to hackers@suckless.org. | ||||||
							
								
								
									
										110
									
								
								patches/alwaysontop-6.2.diff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								patches/alwaysontop-6.2.diff
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | |||||||
|  | From 9cd160c4ba9c345c24644a7da77cc4f04fc93c4e Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Rob Pilling <robpilling@gmail.com> | ||||||
|  | Date: Mon, 27 Jul 2020 20:11:08 +0100 | ||||||
|  | Subject: [PATCH] alwaysontop | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  config.def.h |  1 + | ||||||
|  |  dwm.c        | 45 +++++++++++++++++++++++++++++++++++++++++++-- | ||||||
|  |  2 files changed, 44 insertions(+), 2 deletions(-) | ||||||
|  |  | ||||||
|  | diff --git a/config.def.h b/config.def.h | ||||||
|  | index 1c0b587..c3c7edd 100644 | ||||||
|  | --- a/config.def.h | ||||||
|  | +++ b/config.def.h | ||||||
|  | @@ -78,6 +78,7 @@ static Key keys[] = { | ||||||
|  |  	{ MODKEY,                       XK_m,      setlayout,      {.v = &layouts[2]} }, | ||||||
|  |  	{ MODKEY,                       XK_space,  setlayout,      {0} }, | ||||||
|  |  	{ MODKEY|ShiftMask,             XK_space,  togglefloating, {0} }, | ||||||
|  | +	{ MODKEY|ShiftMask,             XK_space,  togglealwaysontop, {0} }, | ||||||
|  |  	{ MODKEY,                       XK_0,      view,           {.ui = ~0 } }, | ||||||
|  |  	{ MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } }, | ||||||
|  |  	{ MODKEY,                       XK_comma,  focusmon,       {.i = -1 } }, | ||||||
|  | diff --git a/dwm.c b/dwm.c | ||||||
|  | index 4465af1..8d54b26 100644 | ||||||
|  | --- a/dwm.c | ||||||
|  | +++ b/dwm.c | ||||||
|  | @@ -92,7 +92,7 @@ struct Client { | ||||||
|  |  	int basew, baseh, incw, inch, maxw, maxh, minw, minh; | ||||||
|  |  	int bw, oldbw; | ||||||
|  |  	unsigned int tags; | ||||||
|  | -	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; | ||||||
|  | +	int isfixed, iscentered, isfloating, isalwaysontop, isurgent, neverfocus, oldstate, isfullscreen; | ||||||
|  |  	Client *next; | ||||||
|  |  	Client *snext; | ||||||
|  |  	Monitor *mon; | ||||||
|  | @@ -211,6 +211,7 @@ static void tagmon(const Arg *arg); | ||||||
|  |  static void tile(Monitor *); | ||||||
|  |  static void togglebar(const Arg *arg); | ||||||
|  |  static void togglefloating(const Arg *arg); | ||||||
|  | +static void togglealwaysontop(const Arg *arg); | ||||||
|  |  static void toggletag(const Arg *arg); | ||||||
|  |  static void toggleview(const Arg *arg); | ||||||
|  |  static void unfocus(Client *c, int setfocus); | ||||||
|  | @@ -732,8 +733,11 @@ drawbar(Monitor *m) | ||||||
|  |  		if (m->sel) { | ||||||
|  |  			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); | ||||||
|  |  			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); | ||||||
|  | -			if (m->sel->isfloating) | ||||||
|  | +			if (m->sel->isfloating) { | ||||||
|  |  				drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); | ||||||
|  | +				if (m->sel->isalwaysontop) | ||||||
|  | +					drw_rect(drw, x + boxs, bh - boxw, boxw, boxw, 0, 0); | ||||||
|  | +			} | ||||||
|  |  		} else { | ||||||
|  |  			drw_setscheme(drw, scheme[SchemeNorm]); | ||||||
|  |  			drw_rect(drw, x, 0, w, bh, 1, 1); | ||||||
|  | @@ -1356,6 +1360,17 @@ restack(Monitor *m) | ||||||
|  |  		return; | ||||||
|  |  	if (m->sel->isfloating || !m->lt[m->sellt]->arrange) | ||||||
|  |  		XRaiseWindow(dpy, m->sel->win); | ||||||
|  | + | ||||||
|  | +	/* raise the aot window */ | ||||||
|  | +	for(Monitor *m_search = mons; m_search; m_search = m_search->next){ | ||||||
|  | +		for(c = m_search->clients; c; c = c->next){ | ||||||
|  | +			if(c->isalwaysontop){ | ||||||
|  | +				XRaiseWindow(dpy, c->win); | ||||||
|  | +				break; | ||||||
|  | +			} | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	if (m->lt[m->sellt]->arrange) { | ||||||
|  |  		wc.stack_mode = Below; | ||||||
|  |  		wc.sibling = m->barwin; | ||||||
|  | @@ -1716,6 +1731,32 @@ togglefloating(const Arg *arg) | ||||||
|  |  	if (selmon->sel->isfloating) | ||||||
|  |  		resize(selmon->sel, selmon->sel->x, selmon->sel->y, | ||||||
|  |  			selmon->sel->w, selmon->sel->h, 0); | ||||||
|  | +	else | ||||||
|  | +		selmon->sel->isalwaysontop = 0; /* disabled, turn this off too */ | ||||||
|  | +	arrange(selmon); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void | ||||||
|  | +togglealwaysontop(const Arg *arg) | ||||||
|  | +{ | ||||||
|  | +	if (!selmon->sel) | ||||||
|  | +		return; | ||||||
|  | +	if (selmon->sel->isfullscreen) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	if(selmon->sel->isalwaysontop){ | ||||||
|  | +		selmon->sel->isalwaysontop = 0; | ||||||
|  | +	}else{ | ||||||
|  | +		/* disable others */ | ||||||
|  | +		for(Monitor *m = mons; m; m = m->next) | ||||||
|  | +			for(Client *c = m->clients; c; c = c->next) | ||||||
|  | +				c->isalwaysontop = 0; | ||||||
|  | + | ||||||
|  | +		/* turn on, make it float too */ | ||||||
|  | +		selmon->sel->isfloating = 1; | ||||||
|  | +		selmon->sel->isalwaysontop = 1; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	arrange(selmon); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | --  | ||||||
|  | 2.31.1 | ||||||
|  |  | ||||||
							
								
								
									
										117
									
								
								patches/dwm-cfacts-20200913-61bb8b2.diff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								patches/dwm-cfacts-20200913-61bb8b2.diff
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | |||||||
|  | From c32a879432573d71dec7fcb4bf68927d2f4cdf10 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: iofq <cjriddz@protonmail.com> | ||||||
|  | Date: Sat, 12 Sep 2020 22:28:09 -0500 | ||||||
|  | Subject: [PATCH] Fixed 'cfacts' patch failure due to upstream commit | ||||||
|  |  'f09418bbb...' | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  config.def.h |  3 +++ | ||||||
|  |  dwm.c        | 34 +++++++++++++++++++++++++++++++--- | ||||||
|  |  2 files changed, 34 insertions(+), 3 deletions(-) | ||||||
|  |  | ||||||
|  | diff --git a/config.def.h b/config.def.h | ||||||
|  | index 1c0b587..83910c1 100644 | ||||||
|  | --- a/config.def.h | ||||||
|  | +++ b/config.def.h | ||||||
|  | @@ -70,6 +70,9 @@ static Key keys[] = { | ||||||
|  |  	{ MODKEY,                       XK_d,      incnmaster,     {.i = -1 } }, | ||||||
|  |  	{ MODKEY,                       XK_h,      setmfact,       {.f = -0.05} }, | ||||||
|  |  	{ MODKEY,                       XK_l,      setmfact,       {.f = +0.05} }, | ||||||
|  | +	{ MODKEY|ShiftMask,             XK_h,      setcfact,       {.f = +0.25} }, | ||||||
|  | +	{ MODKEY|ShiftMask,             XK_l,      setcfact,       {.f = -0.25} }, | ||||||
|  | +	{ MODKEY|ShiftMask,             XK_o,      setcfact,       {.f =  0.00} }, | ||||||
|  |  	{ MODKEY,                       XK_Return, zoom,           {0} }, | ||||||
|  |  	{ MODKEY,                       XK_Tab,    view,           {0} }, | ||||||
|  |  	{ MODKEY|ShiftMask,             XK_c,      killclient,     {0} }, | ||||||
|  | diff --git a/dwm.c b/dwm.c | ||||||
|  | index 664c527..5233229 100644 | ||||||
|  | --- a/dwm.c | ||||||
|  | +++ b/dwm.c | ||||||
|  | @@ -87,6 +87,7 @@ typedef struct Client Client; | ||||||
|  |  struct Client { | ||||||
|  |  	char name[256]; | ||||||
|  |  	float mina, maxa; | ||||||
|  | +	float cfact; | ||||||
|  |  	int x, y, w, h; | ||||||
|  |  	int oldx, oldy, oldw, oldh; | ||||||
|  |  	int basew, baseh, incw, inch, maxw, maxh, minw, minh; | ||||||
|  | @@ -201,6 +202,7 @@ static void setclientstate(Client *c, long state); | ||||||
|  |  static void setfocus(Client *c); | ||||||
|  |  static void setfullscreen(Client *c, int fullscreen); | ||||||
|  |  static void setlayout(const Arg *arg); | ||||||
|  | +static void setcfact(const Arg *arg); | ||||||
|  |  static void setmfact(const Arg *arg); | ||||||
|  |  static void setup(void); | ||||||
|  |  static void seturgent(Client *c, int urg); | ||||||
|  | @@ -1030,6 +1032,7 @@ manage(Window w, XWindowAttributes *wa) | ||||||
|  |  	c->w = c->oldw = wa->width; | ||||||
|  |  	c->h = c->oldh = wa->height; | ||||||
|  |  	c->oldbw = wa->border_width; | ||||||
|  | +	c->cfact = 1.0; | ||||||
|  |   | ||||||
|  |  	updatetitle(c); | ||||||
|  |  	if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { | ||||||
|  | @@ -1512,6 +1515,23 @@ setlayout(const Arg *arg) | ||||||
|  |  		drawbar(selmon); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +void setcfact(const Arg *arg) { | ||||||
|  | +	float f; | ||||||
|  | +	Client *c; | ||||||
|  | + | ||||||
|  | +	c = selmon->sel; | ||||||
|  | + | ||||||
|  | +	if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) | ||||||
|  | +		return; | ||||||
|  | +	f = arg->f + c->cfact; | ||||||
|  | +	if(arg->f == 0.0) | ||||||
|  | +		f = 1.0; | ||||||
|  | +	else if(f < 0.25 || f > 4.0) | ||||||
|  | +		return; | ||||||
|  | +	c->cfact = f; | ||||||
|  | +	arrange(selmon); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  /* arg > 1.0 will set mfact absolutely */ | ||||||
|  |  void | ||||||
|  |  setmfact(const Arg *arg) | ||||||
|  | @@ -1675,9 +1695,15 @@ void | ||||||
|  |  tile(Monitor *m) | ||||||
|  |  { | ||||||
|  |  	unsigned int i, n, h, mw, my, ty; | ||||||
|  | +	float mfacts = 0, sfacts = 0; | ||||||
|  |  	Client *c; | ||||||
|  |   | ||||||
|  | -	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | ||||||
|  | +	for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { | ||||||
|  | +		if (n < m->nmaster) | ||||||
|  | +			mfacts += c->cfact; | ||||||
|  | +		else | ||||||
|  | +			sfacts += c->cfact; | ||||||
|  | +	} | ||||||
|  |  	if (n == 0) | ||||||
|  |  		return; | ||||||
|  |   | ||||||
|  | @@ -1687,15 +1713,17 @@ tile(Monitor *m) | ||||||
|  |  		mw = m->ww; | ||||||
|  |  	for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | ||||||
|  |  		if (i < m->nmaster) { | ||||||
|  | -			h = (m->wh - my) / (MIN(n, m->nmaster) - i); | ||||||
|  | +			h = (m->wh - my) * (c->cfact / mfacts); | ||||||
|  |  			resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); | ||||||
|  |  			if (my + HEIGHT(c) < m->wh) | ||||||
|  |  				my += HEIGHT(c); | ||||||
|  | +     mfacts -= c->cfact; | ||||||
|  |  		} else { | ||||||
|  | -			h = (m->wh - ty) / (n - i); | ||||||
|  | +			h = (m->wh - ty) * (c->cfact / sfacts); | ||||||
|  |  			resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); | ||||||
|  |  			if (ty + HEIGHT(c) < m->wh) | ||||||
|  |  				ty += HEIGHT(c); | ||||||
|  | +     sfacts -= c->cfact; | ||||||
|  |  		} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | --  | ||||||
|  | 2.28.0 | ||||||
|  |  | ||||||
							
								
								
									
										68
									
								
								patches/dwm-colorbar-6.2.diff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								patches/dwm-colorbar-6.2.diff
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | diff --git a/config.def.h b/config.def.h | ||||||
|  | index 1c0b587..a516645 100644 | ||||||
|  | --- a/config.def.h | ||||||
|  | +++ b/config.def.h | ||||||
|  | @@ -16,6 +16,11 @@ static const char *colors[][3]      = { | ||||||
|  |  	/*               fg         bg         border   */ | ||||||
|  |  	[SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, | ||||||
|  |  	[SchemeSel]  = { col_gray4, col_cyan,  col_cyan  }, | ||||||
|  | +	[SchemeStatus]  = { col_gray3, col_gray1,  "#000000"  }, // Statusbar right {text,background,not used but cannot be empty} | ||||||
|  | +	[SchemeTagsSel]  = { col_gray4, col_cyan,  "#000000"  }, // Tagbar left selected {text,background,not used but cannot be empty} | ||||||
|  | +    [SchemeTagsNorm]  = { col_gray3, col_gray1,  "#000000"  }, // Tagbar left unselected {text,background,not used but cannot be empty} | ||||||
|  | +    [SchemeInfoSel]  = { col_gray4, col_cyan,  "#000000"  }, // infobar middle  selected {text,background,not used but cannot be empty} | ||||||
|  | +    [SchemeInfoNorm]  = { col_gray3, col_gray1,  "#000000"  }, // infobar middle  unselected {text,background,not used but cannot be empty} | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /* tagging */ | ||||||
|  | diff --git a/dwm.c b/dwm.c | ||||||
|  | index 4465af1..0d1d2f7 100644 | ||||||
|  | --- a/dwm.c | ||||||
|  | +++ b/dwm.c | ||||||
|  | @@ -59,7 +59,7 @@ | ||||||
|  |   | ||||||
|  |  /* enums */ | ||||||
|  |  enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | ||||||
|  | -enum { SchemeNorm, SchemeSel }; /* color schemes */ | ||||||
|  | +enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ | ||||||
|  |  enum { NetSupported, NetWMName, NetWMState, NetWMCheck, | ||||||
|  |         NetWMFullscreen, NetActiveWindow, NetWMWindowType, | ||||||
|  |         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | ||||||
|  | @@ -703,7 +703,7 @@ drawbar(Monitor *m) | ||||||
|  |   | ||||||
|  |  	/* draw status first so it can be overdrawn by tags later */ | ||||||
|  |  	if (m == selmon) { /* status is only drawn on selected monitor */ | ||||||
|  | -		drw_setscheme(drw, scheme[SchemeNorm]); | ||||||
|  | +		drw_setscheme(drw, scheme[SchemeStatus]); | ||||||
|  |  		sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ | ||||||
|  |  		drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); | ||||||
|  |  	} | ||||||
|  | @@ -716,7 +716,7 @@ drawbar(Monitor *m) | ||||||
|  |  	x = 0; | ||||||
|  |  	for (i = 0; i < LENGTH(tags); i++) { | ||||||
|  |  		w = TEXTW(tags[i]); | ||||||
|  | -		drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); | ||||||
|  | +		drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); | ||||||
|  |  		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, | ||||||
|  | @@ -725,17 +725,17 @@ drawbar(Monitor *m) | ||||||
|  |  		x += w; | ||||||
|  |  	} | ||||||
|  |  	w = blw = TEXTW(m->ltsymbol); | ||||||
|  | -	drw_setscheme(drw, scheme[SchemeNorm]); | ||||||
|  | +	drw_setscheme(drw, scheme[SchemeTagsNorm]); | ||||||
|  |  	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); | ||||||
|  |   | ||||||
|  |  	if ((w = m->ww - sw - x) > bh) { | ||||||
|  |  		if (m->sel) { | ||||||
|  | -			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); | ||||||
|  | +			drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]); | ||||||
|  |  			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); | ||||||
|  |  			if (m->sel->isfloating) | ||||||
|  |  				drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); | ||||||
|  |  		} else { | ||||||
|  | -			drw_setscheme(drw, scheme[SchemeNorm]); | ||||||
|  | +			drw_setscheme(drw, scheme[SchemeInfoNorm]); | ||||||
|  |  			drw_rect(drw, x, 0, w, bh, 1, 1); | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
							
								
								
									
										763
									
								
								patches/dwm-systray-6.3.diff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										763
									
								
								patches/dwm-systray-6.3.diff
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,763 @@ | |||||||
|  | diff --git a/config.def.h b/config.def.h | ||||||
|  | index a2ac963..4be4c06 100644 | ||||||
|  | --- a/config.def.h | ||||||
|  | +++ b/config.def.h | ||||||
|  | @@ -2,9 +2,14 @@ | ||||||
|  |   | ||||||
|  |  /* 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 unsigned int snap      = 32;       /* snap pixel */ | ||||||
|  | +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" }; | ||||||
|  |  static const char dmenufont[]       = "monospace:size=10"; | ||||||
|  |  static const char col_gray1[]       = "#222222"; | ||||||
|  | @@ -101,8 +106,8 @@ static Key keys[] = { | ||||||
|  |  /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ | ||||||
|  |  static Button buttons[] = { | ||||||
|  |  	/* click                event mask      button          function        argument */ | ||||||
|  | -	{ ClkLtSymbol,          0,              Button1,        setlayout,      {0} }, | ||||||
|  | -	{ ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} }, | ||||||
|  | +	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} }, | ||||||
|  | +	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} }, | ||||||
|  |  	{ ClkWinTitle,          0,              Button2,        zoom,           {0} }, | ||||||
|  |  	{ ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } }, | ||||||
|  |  	{ ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} }, | ||||||
|  | diff --git a/dwm.c b/dwm.c | ||||||
|  | index a96f33c..941c1c0 100644 | ||||||
|  | --- a/dwm.c | ||||||
|  | +++ b/dwm.c | ||||||
|  | @@ -57,12 +57,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 */ | ||||||
|  | @@ -141,6 +156,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); | ||||||
|  | @@ -172,6 +193,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 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); | ||||||
|  | @@ -189,13 +211,16 @@ static void pop(Client *); | ||||||
|  |  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); | ||||||
|  | @@ -207,6 +232,7 @@ static void seturgent(Client *c, int urg); | ||||||
|  |  static void showhide(Client *c); | ||||||
|  |  static void sigchld(int unused); | ||||||
|  |  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 *); | ||||||
|  | @@ -224,18 +250,23 @@ 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); | ||||||
|  |  static void zoom(const Arg *arg); | ||||||
|  |   | ||||||
|  |  /* variables */ | ||||||
|  | +static Systray *systray = NULL; | ||||||
|  |  static const char broken[] = "broken"; | ||||||
|  |  static char stext[256]; | ||||||
|  |  static int screen; | ||||||
|  | @@ -258,9 +289,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; | ||||||
|  | @@ -440,7 +472,7 @@ buttonpress(XEvent *e) | ||||||
|  |  			arg.ui = 1 << i; | ||||||
|  |  		} else if (ev->x < x + blw) | ||||||
|  |  			click = ClkLtSymbol; | ||||||
|  | -		else if (ev->x > selmon->ww - (int)TEXTW(stext)) | ||||||
|  | +		else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) | ||||||
|  |  			click = ClkStatusText; | ||||||
|  |  		else | ||||||
|  |  			click = ClkWinTitle; | ||||||
|  | @@ -483,7 +515,14 @@ cleanup(void) | ||||||
|  |  	XUngrabKey(dpy, AnyKey, AnyModifier, root); | ||||||
|  |  	while (mons) | ||||||
|  |  		cleanupmon(mons); | ||||||
|  | -	for (i = 0; i < CurLast; i++) | ||||||
|  | + | ||||||
|  | +	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++) | ||||||
|  |  		free(scheme[i]); | ||||||
|  | @@ -513,9 +552,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]) { | ||||||
|  | @@ -568,7 +656,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); | ||||||
|  | @@ -653,6 +741,11 @@ destroynotify(XEvent *e) | ||||||
|  |   | ||||||
|  |  	if ((c = wintoclient(ev->window))) | ||||||
|  |  		unmanage(c, 1); | ||||||
|  | +	else if ((c = wintosystrayicon(ev->window))) { | ||||||
|  | +		removesystrayicon(c); | ||||||
|  | +		resizebarwin(selmon); | ||||||
|  | +		updatesystray(); | ||||||
|  | +	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  void | ||||||
|  | @@ -696,7 +789,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; | ||||||
|  | @@ -705,13 +798,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 */ | ||||||
|  |  		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); | ||||||
|  | +		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; | ||||||
|  |  		if (c->isurgent) | ||||||
|  | @@ -732,7 +829,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); | ||||||
|  | @@ -743,7 +840,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 | ||||||
|  | @@ -780,8 +877,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 | ||||||
|  | @@ -867,9 +967,17 @@ 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; | ||||||
|  | @@ -903,6 +1011,16 @@ getstate(Window w) | ||||||
|  |  	return result; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +unsigned int | ||||||
|  | +getsystraywidth() | ||||||
|  | +{ | ||||||
|  | +	unsigned int w = 0; | ||||||
|  | +	Client *i; | ||||||
|  | +	if(showsystray) | ||||||
|  | +		for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; | ||||||
|  | +	return w ? w + systrayspacing : 1; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  int | ||||||
|  |  gettextprop(Window w, Atom atom, char *text, unsigned int size) | ||||||
|  |  { | ||||||
|  | @@ -1007,7 +1125,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); | ||||||
|  | @@ -1096,6 +1215,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)) | ||||||
|  |  		return; | ||||||
|  |  	if (wa.override_redirect) | ||||||
|  | @@ -1219,7 +1345,18 @@ propertynotify(XEvent *e) | ||||||
|  |  	Window trans; | ||||||
|  |  	XPropertyEvent *ev = &e->xproperty; | ||||||
|  |   | ||||||
|  | -	if ((ev->window == root) && (ev->atom == XA_WM_NAME)) | ||||||
|  | +	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) | ||||||
|  |  		return; /* ignore */ | ||||||
|  | @@ -1269,6 +1406,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) | ||||||
|  |  { | ||||||
|  | @@ -1276,6 +1426,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) | ||||||
|  |  { | ||||||
|  | @@ -1348,6 +1506,19 @@ resizemouse(const Arg *arg) | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +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 | ||||||
|  |  restack(Monitor *m) | ||||||
|  |  { | ||||||
|  | @@ -1437,26 +1608,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; | ||||||
|  |  } | ||||||
|  | @@ -1470,7 +1652,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 | ||||||
|  | @@ -1558,15 +1740,22 @@ setup(void) | ||||||
|  |  	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); | ||||||
|  |  	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); | ||||||
|  |  	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); | ||||||
|  | -	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); | ||||||
|  | -	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); | ||||||
|  | +   netatom[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); | ||||||
|  |  	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); | ||||||
|  |  	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); | ||||||
|  |  	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); | ||||||
|  |  	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); | ||||||
|  | -	/* init cursors */ | ||||||
|  | +	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); | ||||||
|  |  	cursor[CurMove] = drw_cur_create(drw, XC_fleur); | ||||||
|  | @@ -1574,6 +1763,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(); | ||||||
|  | @@ -1707,7 +1898,18 @@ togglebar(const Arg *arg) | ||||||
|  |  { | ||||||
|  |  	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); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -1802,11 +2004,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, | ||||||
|  | @@ -1817,10 +2026,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); | ||||||
|  |  	} | ||||||
|  | @@ -1996,6 +2210,125 @@ updatestatus(void) | ||||||
|  |  	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) | ||||||
|  |  		strcpy(stext, "dwm-"VERSION); | ||||||
|  |  	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 | ||||||
|  | @@ -2063,6 +2396,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) | ||||||
|  |  { | ||||||
|  | @@ -2116,6 +2459,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) | ||||||
|  |  { | ||||||
							
								
								
									
										42
									
								
								transient.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								transient.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | /* cc transient.c -o transient -lX11 */ | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <X11/Xlib.h> | ||||||
|  | #include <X11/Xutil.h> | ||||||
|  |  | ||||||
|  | int main(void) { | ||||||
|  | 	Display *d; | ||||||
|  | 	Window r, f, t = None; | ||||||
|  | 	XSizeHints h; | ||||||
|  | 	XEvent e; | ||||||
|  |  | ||||||
|  | 	d = XOpenDisplay(NULL); | ||||||
|  | 	if (!d) | ||||||
|  | 		exit(1); | ||||||
|  | 	r = DefaultRootWindow(d); | ||||||
|  |  | ||||||
|  | 	f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0); | ||||||
|  | 	h.min_width = h.max_width = h.min_height = h.max_height = 400; | ||||||
|  | 	h.flags = PMinSize | PMaxSize; | ||||||
|  | 	XSetWMNormalHints(d, f, &h); | ||||||
|  | 	XStoreName(d, f, "floating"); | ||||||
|  | 	XMapWindow(d, f); | ||||||
|  |  | ||||||
|  | 	XSelectInput(d, f, ExposureMask); | ||||||
|  | 	while (1) { | ||||||
|  | 		XNextEvent(d, &e); | ||||||
|  |  | ||||||
|  | 		if (t == None) { | ||||||
|  | 			sleep(5); | ||||||
|  | 			t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0); | ||||||
|  | 			XSetTransientForHint(d, t, f); | ||||||
|  | 			XStoreName(d, t, "transient"); | ||||||
|  | 			XMapWindow(d, t); | ||||||
|  | 			XSelectInput(d, t, ExposureMask); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	XCloseDisplay(d); | ||||||
|  | 	exit(0); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								util.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | void * | ||||||
|  | ecalloc(size_t nmemb, size_t size) | ||||||
|  | { | ||||||
|  | 	void *p; | ||||||
|  |  | ||||||
|  | 	if (!(p = calloc(nmemb, size))) | ||||||
|  | 		die("calloc:"); | ||||||
|  | 	return p; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | die(const char *fmt, ...) { | ||||||
|  | 	va_list ap; | ||||||
|  |  | ||||||
|  | 	va_start(ap, fmt); | ||||||
|  | 	vfprintf(stderr, fmt, ap); | ||||||
|  | 	va_end(ap); | ||||||
|  |  | ||||||
|  | 	if (fmt[0] && fmt[strlen(fmt)-1] == ':') { | ||||||
|  | 		fputc(' ', stderr); | ||||||
|  | 		perror(NULL); | ||||||
|  | 	} else { | ||||||
|  | 		fputc('\n', stderr); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	exit(1); | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								util.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  |  | ||||||
|  | #define MAX(A, B)               ((A) > (B) ? (A) : (B)) | ||||||
|  | #define MIN(A, B)               ((A) < (B) ? (A) : (B)) | ||||||
|  | #define BETWEEN(X, A, B)        ((A) <= (X) && (X) <= (B)) | ||||||
|  |  | ||||||
|  | void die(const char *fmt, ...); | ||||||
|  | void *ecalloc(size_t nmemb, size_t size); | ||||||
		Reference in New Issue
	
	Block a user