From: Marco Peereboom Date: Wed, 15 Feb 2012 20:09:13 +0000 (-0600) Subject: rename scrotwm to spectrwm X-Git-Url: https://jasonwoof.com/gitweb/?a=commitdiff_plain;h=e83f3b790887174fe8b8fd6b3c98172b59ff9305;p=spectrwm.git rename scrotwm to spectrwm --- diff --git a/Makefile b/Makefile index ad27745..048eb32 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,9 @@ PREFIX?=/usr/local BINDIR=${PREFIX}/bin SUBDIR= lib -PROG=scrotwm -#MAN=scrotwm_pt.1 scrotwm_ru.1 -MAN=scrotwm.1 scrotwm_es.1 scrotwm_it.1 +PROG=spectrwm +#MAN=spectrwm_pt.1 spectrwm_ru.1 +MAN=spectrwm.1 spectrwm_es.1 spectrwm_it.1 CFLAGS+=-std=c89 -Wall -Wno-uninitialized -ggdb3 # Uncomment define below to disallow user settable clock format string @@ -16,13 +16,13 @@ CPPFLAGS+= -I${X11BASE}/include LDADD+=-lutil -L${X11BASE}/lib -lX11 -lXrandr -lXtst BUILDVERSION != sh "${.CURDIR}/buildver.sh" .if !${BUILDVERSION} == "" -CPPFLAGS+= -DSCROTWM_BUILDSTR=\"$(BUILDVERSION)\" +CPPFLAGS+= -DSPECTRWM_BUILDSTR=\"$(BUILDVERSION)\" .endif MANDIR= ${PREFIX}/man/man -#scrotwm_ru.cat1: scrotwm_ru.1 -# nroff -mandoc ${.CURDIR}/scrotwm_ru.1 > ${.TARGET} +#spectrwm_ru.cat1: spectrwm_ru.1 +# nroff -mandoc ${.CURDIR}/spectrwm_ru.1 > ${.TARGET} obj: _xenocara_obj diff --git a/baraction.sh b/baraction.sh index c3ac272..e87b93d 100644 --- a/baraction.sh +++ b/baraction.sh @@ -4,7 +4,7 @@ print_date() { # The date is printed to the status bar by default. # To print the date through this script, set clock_enabled to 0 - # in scrotwm.conf. Uncomment "print_date" below. + # in spectrwm.conf. Uncomment "print_date" below. FORMAT="%a %b %d %R %Z %Y" DATE=`date "+${FORMAT}"` echo -n "${DATE} " diff --git a/freebsd/Makefile b/freebsd/Makefile index 8b23a4d..c8f03b2 100644 --- a/freebsd/Makefile +++ b/freebsd/Makefile @@ -10,7 +10,7 @@ MANDIR?= $(PREFIX)/man LVERS!= awk -F = '/major/ { printf( "%s.", $$2 ) } /minor/ { printf( "%s", $$2 ) }' ${.CURDIR}/../lib/shlib_version BUILDVERSION!= sh "${.CURDIR}/../buildver.sh" .if !${BUILDVERSION} == "" -CFLAGS+= -DSCROTWM_BUILDSTR=\"$(BUILDVERSION)\" +CFLAGS+= -DSPECTRWM_BUILDSTR=\"$(BUILDVERSION)\" .endif CFLAGS+= -Wall -Wno-uninitialized -I. -I${LOCALBASE}/include @@ -18,16 +18,16 @@ CFLAGS+= -DSWM_LIB=\"$(LIBDIR)/libswmhack.so.$(LVERS)\" LDADD+= -lutil -L${LOCALBASE}/lib -lX11 -lXrandr -lXtst -all: scrotwm libswmhack.so.$(LVERS) +all: spectrwm libswmhack.so.$(LVERS) -scrotwm.c: - ln -sf ../scrotwm.c +spectrwm.c: + ln -sf ../spectrwm.c ln -sf ../version.h swm_hack.c: ln -sf ../lib/swm_hack.c -scrotwm: scrotwm.o +spectrwm: spectrwm.o $(CC) $(LDFLAGS) $(LDADD) -o ${.TARGET} ${.ALLSRC} swm_hack.so: swm_hack.c @@ -40,15 +40,15 @@ install: all install -m 755 -d $(DESTDIR)$(BINDIR) install -m 755 -d $(DESTDIR)$(LIBDIR) install -m 755 -d $(DESTDIR)$(MANDIR)/man1 - install -m 755 scrotwm $(DESTDIR)$(BINDIR) + install -m 755 spectrwm $(DESTDIR)$(BINDIR) install -m 755 libswmhack.so.$(LVERS) $(DESTDIR)$(LIBDIR) - install -m 644 ../scrotwm.1 $(DESTDIR)$(MANDIR)/man1/scrotwm.1 - install -m 644 ../scrotwm_es.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_es.1 - install -m 644 ../scrotwm_it.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_it.1 - install -m 644 ../scrotwm_pt.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_pt.1 - install -m 644 ../scrotwm_ru.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_ru.1 + install -m 644 ../spectrwm.1 $(DESTDIR)$(MANDIR)/man1/spectrwm.1 + install -m 644 ../spectrwm_es.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_es.1 + install -m 644 ../spectrwm_it.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_it.1 + install -m 644 ../spectrwm_pt.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_pt.1 + install -m 644 ../spectrwm_ru.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_ru.1 clean: - rm -f scrotwm *.o *.so libswmhack.so.* scrotwm.c swm_hack.c version.h + rm -f spectrwm *.o *.so libswmhack.so.* spectrwm.c swm_hack.c version.h .sinclude diff --git a/linux/Makefile b/linux/Makefile index d8f0206..2060184 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -11,16 +11,16 @@ CC= gcc LVERS= $(shell . ../lib/shlib_version; echo $$major.$$minor) -all: scrotwm libswmhack.so.$(LVERS) +all: spectrwm libswmhack.so.$(LVERS) -scrotwm.c: - ln -sf ../scrotwm.c +spectrwm.c: + ln -sf ../spectrwm.c ln -sf ../version.h swm_hack.c: ln -sf ../lib/swm_hack.c -scrotwm: scrotwm.o linux.o +spectrwm: spectrwm.o linux.o $(CC) $(LDFLAGS) -o $@ $+ $(LDADD) %.so: %.c @@ -33,15 +33,15 @@ install: all install -m 755 -d $(DESTDIR)$(BINDIR) install -m 755 -d $(DESTDIR)$(LIBDIR) install -m 755 -d $(DESTDIR)$(MANDIR)/man1 - install -m 755 scrotwm $(DESTDIR)$(BINDIR) + install -m 755 spectrwm $(DESTDIR)$(BINDIR) install -m 755 libswmhack.so.$(LVERS) $(DESTDIR)$(LIBDIR) - install -m 644 ../scrotwm.1 $(DESTDIR)$(MANDIR)/man1/scrotwm.1 - install -m 644 ../scrotwm_es.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_es.1 - install -m 644 ../scrotwm_it.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_it.1 - install -m 644 ../scrotwm_pt.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_pt.1 - install -m 644 ../scrotwm_ru.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_ru.1 + install -m 644 ../spectrwm.1 $(DESTDIR)$(MANDIR)/man1/spectrwm.1 + install -m 644 ../spectrwm_es.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_es.1 + install -m 644 ../spectrwm_it.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_it.1 + install -m 644 ../spectrwm_pt.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_pt.1 + install -m 644 ../spectrwm_ru.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_ru.1 clean: - rm -f scrotwm *.o *.so libswmhack.so.* scrotwm.c swm_hack.c version.h + rm -f spectrwm *.o *.so libswmhack.so.* spectrwm.c swm_hack.c version.h .PHONY: all install clean diff --git a/linux/scrotwm.desktop b/linux/scrotwm.desktop deleted file mode 100644 index fdc5ad2..0000000 --- a/linux/scrotwm.desktop +++ /dev/null @@ -1,7 +0,0 @@ - -[Desktop Entry] -Name=ScrotWM -Comment=The ScrotWM window manager -Type=Application -Exec=/usr/bin/scrotwm -TryExec=/usr/bin/scrotwm diff --git a/linux/spectrwm.desktop b/linux/spectrwm.desktop new file mode 100644 index 0000000..1ed4c7d --- /dev/null +++ b/linux/spectrwm.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Name=spectrwm +Comment=The spectrwm window manager +Type=Application +Exec=/usr/bin/spectrwm +TryExec=/usr/bin/spectrwm diff --git a/osx/Makefile b/osx/Makefile index 7d16a6d..7e34441 100644 --- a/osx/Makefile +++ b/osx/Makefile @@ -11,15 +11,15 @@ CC= gcc LVERS= $(shell . ../lib/shlib_version; echo $$major.$$minor) -all: scrotwm libswmhack.so.$(LVERS) +all: spectrwm libswmhack.so.$(LVERS) -scrotwm.c: - ln -sf ../scrotwm.c +spectrwm.c: + ln -sf ../spectrwm.c swm_hack.c: ln -sf ../lib/swm_hack.c -scrotwm: scrotwm.o osx.o +spectrwm: spectrwm.o osx.o $(CC) $(LDFLAGS) -o $@ $+ $(LDADD) %.so: %.c @@ -34,15 +34,15 @@ install: all install -m 755 -d $(DESTDIR)$(BINDIR) install -m 755 -d $(DESTDIR)$(LIBDIR) install -m 755 -d $(DESTDIR)$(MANDIR)/man1 - install -m 755 scrotwm $(DESTDIR)$(BINDIR) + install -m 755 spectrwm $(DESTDIR)$(BINDIR) install -m 755 libswmhack.so.$(LVERS) $(DESTDIR)$(LIBDIR) - install -m 644 ../scrotwm.1 $(DESTDIR)$(MANDIR)/man1/scrotwm.1 - install -m 644 ../scrotwm_es.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_es.1 - install -m 644 ../scrotwm_it.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_it.1 - install -m 644 ../scrotwm_pt.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_pt.1 - install -m 644 ../scrotwm_ru.1 $(DESTDIR)$(MANDIR)/man1/scrotwm_ru.1 + install -m 644 ../spectrwm.1 $(DESTDIR)$(MANDIR)/man1/spectrwm.1 + install -m 644 ../spectrwm_es.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_es.1 + install -m 644 ../spectrwm_it.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_it.1 + install -m 644 ../spectrwm_pt.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_pt.1 + install -m 644 ../spectrwm_ru.1 $(DESTDIR)$(MANDIR)/man1/spectrwm_ru.1 clean: - rm -f scrotwm *.o *.so libswmhack.so.* scrotwm.c swm_hack.c + rm -f spectrwm *.o *.so libswmhack.so.* spectrwm.c swm_hack.c .PHONY: all install clean diff --git a/release.sh b/release.sh index 3ac9b92..801b056 100644 --- a/release.sh +++ b/release.sh @@ -7,7 +7,7 @@ # - Tags the release # - Creates a release tarball -PROJECT=scrotwm +PROJECT=spectrwm PROJECT_UC=$(echo $PROJECT | tr '[:lower:]' '[:upper:]') SCRIPT=$(basename $0) HEADER=version.h diff --git a/scrotwm.1 b/scrotwm.1 deleted file mode 100644 index 21bc043..0000000 --- a/scrotwm.1 +++ /dev/null @@ -1,854 +0,0 @@ -.\" Copyright (c) 2009 Marco Peereboom -.\" Copyright (c) 2009 Darrin Chandler -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: February 8 2012 $ -.Dt SCROTWM 1 -.Os -.Sh NAME -.Nm scrotwm -.Nd window manager for X11 -.Sh SYNOPSIS -.Nm scrotwm -.Sh DESCRIPTION -.Nm -is a minimalistic window manager that tries to stay out of the way so that -valuable screen real estate can be used for much more important stuff. -It has sane defaults and does not require one to learn a language to do any -configuration. -It was written by hackers for hackers and it strives to be small, compact and -fast. -.Pp -When -.Nm -starts up, it reads settings from its configuration file, -.Pa scrotwm.conf . -See the -.Sx CONFIGURATION FILES -section below. -.Pp -The following notation is used throughout this page: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It Cm M -Meta -.It Cm S -Shift -.It Aq Cm Name -Named key -.It Cm M1 -Mouse button 1 -.It Cm M3 -Mouse button 3 -.El -.Pp -.Nm -is very simple in its use. -Most of the actions are initiated via key or mouse bindings. -See the -.Sx BINDINGS -section below for defaults and customizations. -.Sh CONFIGURATION FILES -.Nm -first tries to open the user specific file, -.Pa ~/.scrotwm.conf . -If that file is unavailable, -it then tries to open the global configuration file -.Pa /etc/scrotwm.conf . -.Pp -The format of the file is \*(Ltkeyword\*(Gt = \*(Ltsetting\*(Gt. -For example: -.Pp -.Dl color_focus = red -.Pp -Enabling or disabling an option is done by using 1 or 0 respectively. -.Pp -The file supports the following keywords: -.Bl -tag -width 2m -.It Ic autorun -Launch an application in a specified workspace at start-of-day. -Defined in the format ws[]:application, e.g. ws[2]:xterm launches an -xterm in workspace 2. -.It Ic bar_action -External script that populates additional information in the status bar, -such as battery life. -.It Ic bar_at_bottom -Place the statusbar at the bottom of each region instead of the top. -.It Ic bar_border Ns Bq Ar x -Color of the status bar border in screen -.Ar x . -.It Ic bar_border_width -Set status bar border thickness in pixels. -Disable border by setting to 0. -.It Ic bar_color Ns Bq Ar x -Color of the status bar window in screen -.Ar x . -.It Ic bar_delay -Update frequency, in seconds, of external script that populates the status bar. -.It Ic bar_enabled -Enable or disable status bar. -.It Ic bar_font -Status bar font. -.It Ic bar_font_color Ns Bq Ar x -Color of the font in status bar in screen -.Ar x . -.It Ic bar_justify -Justify the status bar text. Possible values are -.Pa left , -.Pa center , -and -.Pa right . -.It Ic bind Ns Bq Ar x -Bind key combo to action -.Ar x . -See the -.Sx BINDINGS -section below. -.It Ic border_width -Set window border thickness in pixels. -Disable all borders by setting to 0. -.It Ic clock_enabled -Enable or disable displaying the clock in the status bar. -Disable by setting to 0 -so a custom clock could be used in the -.Pa bar_action -script. -.It Ic color_focus -Border color of the currently focussed window. -.It Ic color_unfocus -Border color of unfocussed windows. -.It Ic dialog_ratio -Some applications have dialogue windows that are too small to be useful. -This ratio is the screen size to what they will be resized. -For example, 0.6 is 60% of the physical screen size. -.It Ic disable_border -Remove border when bar is disabled and there is only one window on the screen. -.It Ic focus_mode -Using a value of -.Pa follow_cursor -will make the window manager focus the window -under the mouse when switching workspaces and creating windows. -.It Ic keyboard_mapping -Clear all key bindings and load new key bindings from the specified file. -This allows you to load pre-defined key bindings for your keyboard layout. -See the -.Sx KEYBOARD MAPPING FILES -section below for a list of keyboard mapping files that have been provided -for several keyboard layouts. -.It Ic layout -Select layout to use at start-of-day. -Defined in the format -ws[idx]:master_grow:master_add:stack_inc:layout:always_raise:stack_mode, e.g. -ws[2]:-4:0:1:0:horizontal sets worskspace 2 to the horizontal stack mode and -shrinks the master area by 4 ticks and adds one window to the stack, while -maintaining default floating window behavior. -Possible stack_mode values are -.Pa vertical , -.Pa horizontal -and -.Pa fullscreen . -.Pp -See -.Pa master_grow , -.Pa master_shrink , -.Pa master_add , -.Pa master_del , -.Pa stack_inc , -.Pa stack_dec , -and -.Pa always_raise -for more information. -Note that the stacking options are complicated and have side-effects. -One should familiarize oneself with these commands before experimenting with the -.Pa layout -option. -.Pp -This setting is not retained at restart. -.It Ic modkey -Change mod key. -Mod1 is generally the ALT key and Mod4 is the windows key on a PC. -.It Ic program Ns Bq Ar p -Define new action to spawn a program -.Ar p . -See the -.Sx PROGRAMS -section below. -.It Ic quirk Ns Bq Ar c:n -Add "quirk" for windows with class -.Ar c -and name -.Ar n . -See the -.Sx QUIRKS -section below. -.It Ic region -Allocates a custom region, removing any autodetected regions which occupy the same -space on the screen. -Defined in the format screen[]:WIDTHxHEIGHT+X+Y, -e.g.\& screen[1]:800x1200+0+0. -.Pp -To make a screen span multiple monitors, create a region big enough to cover -them all, e.g. screen[1]:2048x768+0+0 makes the screen span two monitors with -1024x768 resolution sitting one next to the other. -.It Ic stack_enabled -Enable or disable displaying the current stacking algorithm in the status bar. -.It Ic term_width -Set a preferred minimum width for the terminal. -If this value is greater than 0, -.Nm -will attempt to adjust the font sizes in the terminal to keep the terminal -width above this number as the window is resized. -Only -.Xr xterm 1 -is currently supported. -The -.Xr xterm 1 -binary must not be setuid or setgid, which it is by default on most systems. -Users may need to set program[term] (see the -.Sx PROGRAMS -section) to use an alternate copy of the -.Xr xterm 1 -binary without the setgid bit set. -.It Ic title_class_enabled -Enable or disable displaying the window class in the status bar. -Enable by setting to 1. -.It Ic title_name_enabled -Enable or disable displaying the window title in the status bar. -Enable by setting to 1. -.It Ic urgent_enabled -Enable or disable the urgency hint. -Note that many terminal emulators require this to be enabled for it to -propagate. -In xterm, for example, one needs to add the following line -.Pa xterm.urgentOnBell: true -to -.Pa .Xdefaults . -.It Ic verbose_layout -Enable or disable displaying the current master and stack values in the status -bar. -Enable by setting to 1. -.It Ic window_name_enabled -Enable or disable displaying the window name in the status bar. -Enable by setting to 1. -.El -.Pp -Colors need to be specified per the -.Xr XQueryColor 3 -specification and fonts need to be specified per the -.Xr XQueryFont 3 -specification. -.Pp -To list the available fonts in your system see -.Xr fc-list 1 -or -.Xr xlsfonts 1 -manpages. -The -.Xr xfontsel 1 -application can help you to show the X Logical Font Description ("XLFD") used -as setting in the keyword -.Pa bar_font . -.Sh PROGRAMS -.Nm -allows you to define custom actions to launch programs of your choice and then -bind them the same as with built-in actions. -See the -.Sx BINDINGS -section below. -.Pp -The default programs are described below: -.Pp -.Bl -tag -width "screenshot_wind" -offset indent -compact -.It Cm term -xterm -.It Cm screenshot_all -screenshot.sh full -.It Cm screenshot_wind -screenshot.sh window -.It Cm lock -xlock -.It Cm initscr -initscreen.sh -.It Cm menu -dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color -.El -.Pp -Custom programs in the configuration file are specified as follows: -.Pp -.Dl program[] = [ [... ]] -.Pp -.Aq name -is any identifier that does not conflict with a built-in action or keyword, -.Aq progpath -is the desired program, and -.Aq arg -is zero or more arguments to the program. -.Pp -The following variables represent settable values in -.Nm -(see the -.Sx CONFIGURATION FILES -section above), -and may be used in the -.Aq arg -fields and will be substituted for values at the time the program is spawned: -.Pp -.Bl -tag -width "$bar_font_color" -offset indent -compact -.It Cm $bar_border -.It Cm $bar_color -.It Cm $bar_font -.It Cm $bar_font_color -.It Cm $color_focus -.It Cm $color_unfocus -.El -.Pp -Example: -.Bd -literal -offset indent -program[ff] = /usr/local/bin/firefox http://scrotwm.org/ -bind[ff] = Mod+Shift+b # Now Mod+Shift+B launches firefox -.Ed -.Pp -To undo the previous: -.Bd -literal -offset indent -bind[] = Mod+Shift+b -program[ff] = -.Ed -.Sh BINDINGS -.Nm -provides many functions (or actions) accessed via key or mouse bindings. -.Pp -The current mouse bindings are described below: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M1 -Focus window -.It Cm M-M1 -Move window -.It Cm M-M3 -Resize window -.It Cm M-S-M3 -Resize window while maintaining it centered -.El -.Pp -The default key bindings are described below: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M-S- Ns Aq Cm Return -term -.It Cm M-p -menu -.It Cm M-S-q -quit -.It Cm M-q -restart -.It Cm M- Ns Aq Cm Space -cycle_layout -.It Cm M-S- Ns Aq Cm \e -flip_layout -.It Cm M-S- Ns Aq Cm Space -stack_reset -.It Cm M-h -master_shrink -.It Cm M-l -master_grow -.It Cm M-, -master_add -.It Cm M-. -master_del -.It Cm M-S-, -stack_inc -.It Cm M-S-. -stack_dec -.It Cm M- Ns Aq Cm Return -swap_main -.It Xo -.Cm M-j , -.Cm M- Ns Aq Cm TAB -.Xc -focus_next -.It Xo -.Cm M-k , -.Cm M-S- Ns Aq Cm TAB -.Xc -focus_prev -.It Cm M-m -focus_main -.It Cm M-S-j -swap_next -.It Cm M-S-k -swap_prev -.It Cm M-b -bar_toggle -.It Cm M-x -wind_del -.It Cm M-S-x -wind_kill -.It Cm M- Ns Aq Ar n -.Pf ws_ Ar n -.It Cm M-S- Ns Aq Ar n -.Pf mvws_ Ar n -.It Cm M- Ns Aq Cm Right -ws_next -.It Cm M- Ns Aq Cm Left -ws_prev -.It Cm M- Ns Aq Cm Up -ws_next_all -.It Cm M- Ns Aq Cm Down -ws_prev_all -.It Cm M-a -ws_prior -.It Cm M-S- Ns Aq Cm Right -screen_next -.It Cm M-S- Ns Aq Cm Left -screen_prev -.It Cm M-s -screenshot_all -.It Cm M-S-s -screenshot_wind -.It Cm M-S-v -version -.It Cm M-t -float_toggle -.It Cm M-S- Ns Aq Cm Delete -lock -.It Cm M-S-i -initscr -.It Cm M-w -iconify -.It Cm M-S-w -uniconify -.It Cm M-S-r -always_raise -.It Cm M-v -button2 -.It Cm M-- -width_shrink -.It Cm M-= -width_grow -.It Cm M-S-- -height_shrink -.It Cm M-S-= -height_grow -.It Cm M-[ -move_left -.It Cm M-] -move_right -.It Cm M-S-[ -move_up -.It Cm M-S-] -move_down -.It Cm M-S-/ -name_workspace -.It Cm M-/ -search_workspace -.It Cm M-f -search_win -.El -.Pp -The action names and descriptions are listed below: -.Pp -.Bl -tag -width "M-j, M-XXXX" -offset indent -compact -.It Cm term -Spawn a new terminal -(see -.Sx PROGRAMS -above). -.It Cm menu -Menu -(see -.Sx PROGRAMS -above). -.It Cm quit -Quit -.Nm . -.It Cm restart -Restart -.Nm . -.It Cm cycle_layout -Cycle layout. -.It Cm flip_layout -Swap the master and stacking areas. -.It Cm stack_reset -Reset layout. -.It Cm master_shrink -Shrink master area. -.It Cm master_grow -Grow master area. -.It Cm master_add -Add windows to master area. -.It Cm master_del -Remove windows from master area. -.It Cm stack_inc -Add columns/rows to stacking area. -.It Cm stack_dec -Remove columns/rows from stacking area. -.It Cm swap_main -Move current window to master area. -.It Cm focus_next -Focus next window in workspace. -.It Cm focus_prev -Focus previous window in workspace. -.It Cm focus_main -Focus on main window in workspace. -.It Cm swap_next -Swap with next window in workspace. -.It Cm swap_prev -Swap with previous window in workspace. -.It Cm bar_toggle -Toggle status bar in all workspaces. -.It Cm wind_del -Delete current window in workspace. -.It Cm wind_kill -Destroy current window in workspace. -.It Cm ws_ Ns Ar n -Switch to workspace -.Ar n , -where -.Ar n -is 1 through 10. -.It Cm mvws_ Ns Ar n -Move current window to workspace -.Ar n , -where -.Ar n -is 1 through 10. -.It Cm ws_next -Switch to next workspace with a window in it. -.It Cm ws_prev -Switch to previous workspace with a window in it. -.It Cm ws_next_all -Switch to next workspace. -.It Cm ws_prev_all -Switch to previous workspace. -.It Cm ws_prior -Switch to last visited workspace. -.It Cm screen_next -Move pointer to next region. -.It Cm screen_prev -Move pointer to previous region. -.It Cm screenshot_all -Take screenshot of entire screen (if enabled) -(see -.Sx PROGRAMS -above). -.It Cm screenshot_wind -Take screenshot of selected window (if enabled) -(see -.Sx PROGRAMS -above). -.It Cm version -Toggle version in status bar. -.It Cm float_toggle -Toggle focused window between tiled and floating. -.It Cm lock -Lock screen -(see -.Sx PROGRAMS -above). -.It Cm initscr -Reinitialize physical screens -(see -.Sx PROGRAMS -above). -.It Cm iconify -Minimize (unmap) currently focused window. -.It Cm uniconify -Maximize (map) window returned by dmenu selection. -.It Cm always_raise -When set tiled windows are allowed to obscure floating windows. -.It Cm button2 -Fake a middle mouse button click (mouse button 2). -.It Cm width_shrink -Shrink the width of a floating window. -.It Cm width_grow -Grow the width of a floating window. -.It Cm height_shrink -Shrink the height of a floating window. -.It Cm height_grow -Grow the height of a floating window. -.It Cm move_left -Move a floating window a step to the left. -.It Cm move_right -Move a floating window a step to the right. -.It Cm move_up -Move a floating window a step upwards. -.It Cm move_down -Move a floating window a step downwards. -.It Cm name_workspace -Name the current workspace. -.It Cm search_workspace -Search for a workspace. -.It Cm search_win -Search the windows in the current workspace. -.El -.Pp -Custom bindings in the configuration file are specified as follows: -.Pp -.Dl bind[] = -.Pp -.Aq action -is one of the actions listed above (or empty) and -.Aq keys -is in the form of zero or more modifier keys -(MOD, Mod1, Shift, etc.) and one or more normal keys -(b, space, etc.), separated by "+". -For example: -.Bd -literal -offset indent -bind[reset] = Mod4+q # bind Windows-key + q to reset -bind[] = Mod1+q # unbind Alt + q -.Ed -.Pp -To use the currently defined -.Ic modkey , -specify MOD as the modifier key. -.Pp -Multiple key combinations may be bound to the same action. -.Sh KEYBOARD MAPPING FILES -Keyboard mapping files for several keyboard layouts are listed -below. -These files can be used with the -.Pa keyboard_mapping -setting to load pre-defined key bindings for the specified -keyboard layout. -.Pp -.Bl -tag -width "scrotwm_XX.confXXX" -offset indent -compact -.It Cm scrotwm_cz.conf -Czech Republic keyboard layout -.It Cm scrotwm_es.conf -Spanish keyboard layout -.It Cm scrotwm_fr.conf -French keyboard layout -.It Cm scrotwm_fr_ch.conf -Swiss French keyboard layout -.It Cm scrotwm_se.conf -Swedish keyboard layout -.It Cm scrotwm_us.conf -United States keyboard layout -.El -.Sh QUIRKS -.Nm -provides "quirks" which handle windows that must be treated specially -in a tiling window manager, such as some dialogs and fullscreen apps. -.Pp -The default quirks are described below: -.Pp -.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact -.It Firefox\-bin:firefox\-bin -TRANSSZ -.It Firefox:Dialog -FLOAT -.It Gimp:gimp -FLOAT + ANYWHERE -.It MPlayer:xv -FLOAT + FULLSCREEN + FOCUSPREV -.It OpenOffice.org 2.4:VCLSalFrame -FLOAT -.It OpenOffice.org 3.1:VCLSalFrame -FLOAT -.It pcb:pcb -FLOAT -.It xine:Xine Window -FLOAT + ANYWHERE -.It xine:xine Panel -FLOAT + ANYWHERE -.It xine:xine Video Fullscreen Window -FULLSCREEN + FLOAT -.It Xitk:Xitk Combo -FLOAT + ANYWHERE -.It Xitk:Xine Window -FLOAT + ANYWHERE -.It XTerm:xterm -XTERM_FONTADJ -.El -.Pp -The quirks themselves are described below: -.Pp -.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact -.It FLOAT -This window should not be tiled, but allowed to float freely. -.It TRANSSZ -Adjusts size on transient windows that are too small using dialog_ratio -(see -.Sx CONFIGURATION FILES ) . -.It ANYWHERE -Allow window to position itself, uncentered. -.It XTERM_FONTADJ -Adjust xterm fonts when resizing. -.It FULLSCREEN -Remove border to allow window to use full screen size. -.It FOCUSPREV -On exit force focus on previously focused application not previous application -in the stack. -.El -.Pp -Custom quirks in the configuration file are specified as follows: -.Pp -.Dl quirk[:] = [ + ... ] -.Pp -.Aq class -and -.Aq name -specify the window to which the quirk(s) apply, and -.Aq quirk -is one of the quirks from the list above. -For example: -.Bd -literal -offset indent -quirk[MPlayer:xv] = FLOAT + FULLSCREEN + FOCUSPREV -quirk[pcb:pcb] = NONE # remove existing quirk -.Ed -.Pp -You can obtain -.Aq class -and -.Aq name -by running -.Xr xprop 1 -and then clicking on the desired window. -In the following example the main window of Firefox was clicked: -.Bd -literal -offset indent -$ xprop | grep WM_CLASS -WM_CLASS(STRING) = "Navigator", "Firefox" -.Ed -.Pp -Note that grepping for WM_CLASS flips class and name. -In the example above the quirk entry would be: -.Bd -literal -offset indent -quirk[Firefox:Navigator] = FLOAT -.Ed -.Pp -.Nm -also automatically assigns quirks to windows based on the value -of the window's _NET_WM_WINDOW_TYPE property as follows: -.Pp -.Bl -tag -width "_NET_WM_WINDOW_TYPE_TOOLBARXXX" -offset indent -compact -.It _NET_WM_WINDOW_TYPE_DOCK -FLOAT + ANYWHERE -.It _NET_WM_WINDOW_TYPE_TOOLBAR -FLOAT + ANYWHERE -.It _NET_WM_WINDOW_TYPE_UTILITY -FLOAT + ANYWHERE -.It _NET_WM_WINDOW_TYPE_SPLASH -FLOAT -.It _NET_WM_WINDOW_TYPE_DIALOG -FLOAT -.El -.Pp -In all other cases, no automatic quirks are assigned to the window. -Quirks specified in the configuration file override the automatic quirks. -.Sh EWMH -.Nm -partially implements the Extended Window Manager Hints (EWMH) specification. -This enables controlling windows as well as -.Nm -itself from external scripts and programs. -This is achieved by -.Nm -responding to certain ClientMessage events. -From the terminal these events -can be conveniently sent using tools such as -.Xr wmctrl 1 -and -.Xr xdotool 1 . -For the -actual format of these ClientMessage events, see the EWMH specification. -.Pp -The id of the currently focused window is stored in the _NET_ACTIVE_WINDOW -property of the root window. -This can be used for example to retrieve the -title of the currently active window with -.Xr xprop 1 -and -.Xr grep 1 : -.Bd -literal -offset indent -$ WINDOWID=`xprop \-root _NET_ACTIVE_WINDOW | grep \-o "0x.*"` -$ xprop \-id $WINDOWID WM_NAME | grep \-o "\\".*\\"" -.Ed -.Pp -A window can be focused by sending a _NET_ACTIVE_WINDOW client message -to the root window. -For example, using -.Xr wmctrl 1 -to send the message -(assuming 0x4a0000b is the id of the window to be focused): -.Bd -literal -offset indent -$ wmctrl \-i \-a 0x4a0000b -.Ed -.Pp -Windows can be closed by sending a _NET_CLOSE_WINDOW client message -to the root window. -For example, using -.Xr wmctrl 1 -to send the message -(assuming 0x4a0000b is the id of the window to be closed): -.Bd -literal -offset indent -$ wmctrl \-i \-c 0x4a0000b -.Ed -.Pp -Windows can be floated and un-floated by adding or removing the -_NET_WM_STATE_ABOVE atom from the _NET_WM_STATE property of the window. -This can be achieved by sending a _NET_WM_STATE client message to the -root window. -For example, the following toggles the floating state of -a window using -.Xr wmctrl 1 -to send the message (assuming 0x4a0000b is the id of the window floated -or un-floated): -.Bd -literal -offset indent -$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE -.Ed -.Pp -Floating windows can also be resized and moved by sending a -_NET_MOVERESIZE_WINDOW client message to the root window. -For example, -using -.Xr wmctrl 1 -to send the message (assuming 0x4a0000b is the id of -the window to be resize/moved): -.Bd -literal -offset indent -$ wmctrl \-i \-r 0x4a0000b \-e 0,100,50,640,480 -.Ed -.Pp -This moves the window to (100,50) and resizes it to 640x480. -.Pp -Any _NET_MOVERESIZE_WINDOW events received for stacked windows are ignored. -.Sh SIGNALS -Sending -.Nm -a HUP signal will restart it. -.Sh FILES -.Bl -tag -width "/etc/scrotwm.confXXX" -compact -.It Pa ~/.scrotwm.conf -.Nm -user specific settings. -.It Pa /etc/scrotwm.conf -.Nm -global settings. -.El -.Sh HISTORY -.Nm -was inspired by xmonad & dwm. -.Sh AUTHORS -.An -nosplit -.Nm -was written by: -.Pp -.Bl -tag -width "Ryan Thomas McBride Aq mcbride@countersiege.com " -offset indent -compact -.It Cm Marco Peereboom Aq marco@peereboom.us -.It Cm Ryan Thomas McBride Aq mcbride@countersiege.com -.It Cm Darrin Chandler Aq dwchandler@stilyagin.com -.It Cm Pierre-Yves Ritschard Aq pyr@spootnik.org -.It Cm Tuukka Kataja Aq stuge@xor.fi -.It Cm Jason L. Wright Aq jason@thought.net -.It Cm Reginald Kennedy Aq rk@rejii.com -.El diff --git a/scrotwm.c b/scrotwm.c deleted file mode 100644 index 9545475..0000000 --- a/scrotwm.c +++ /dev/null @@ -1,7095 +0,0 @@ -/* - * Copyright (c) 2009-2012 Marco Peereboom - * Copyright (c) 2009-2011 Ryan McBride - * Copyright (c) 2009 Darrin Chandler - * Copyright (c) 2009 Pierre-Yves Ritschard - * Copyright (c) 2010 Tuukka Kataja - * Copyright (c) 2011 Jason L. Wright - * Copyright (c) 2011-2012 Reginald Kennedy - * Copyright (c) 2012 Lawrence Teo - * Copyright (c) 2012 Tiago Cunha - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Much code and ideas taken from dwm under the following license: - * MIT/X Consortium License - * - * 2006-2008 Anselm R Garbe - * 2006-2007 Sander van Dijk - * 2006-2007 Jukka Salmi - * 2007 Premysl Hruby - * 2007 Szabolcs Nagy - * 2007 Christof Musik - * 2007-2008 Enno Gottox Boland - * 2007-2008 Peter Hartlich - * 2008 Martin Hurton - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#if defined(__linux__) -#include "tree.h" -#elif defined(__OpenBSD__) -#include -#elif defined(__FreeBSD__) -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __OSX__ -#include -#endif - -#include "version.h" - -#ifdef SCROTWM_BUILDSTR -static const char *buildstr = SCROTWM_BUILDSTR; -#else -static const char *buildstr = SCROTWM_VERSION; -#endif - -#if RANDR_MAJOR < 1 -# error XRandR versions less than 1.0 are not supported -#endif - -#if RANDR_MAJOR >= 1 -#if RANDR_MINOR >= 2 -#define SWM_XRR_HAS_CRTC -#endif -#endif - -/*#define SWM_DEBUG*/ -#ifdef SWM_DEBUG -#define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0) -#define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0) -#define SWM_D_MISC 0x0001 -#define SWM_D_EVENT 0x0002 -#define SWM_D_WS 0x0004 -#define SWM_D_FOCUS 0x0008 -#define SWM_D_MOVE 0x0010 -#define SWM_D_STACK 0x0020 -#define SWM_D_MOUSE 0x0040 -#define SWM_D_PROP 0x0080 -#define SWM_D_CLASS 0x0100 -#define SWM_D_KEY 0x0200 -#define SWM_D_QUIRK 0x0400 -#define SWM_D_SPAWN 0x0800 -#define SWM_D_EVENTQ 0x1000 -#define SWM_D_CONF 0x2000 -#define SWM_D_BAR 0x4000 - -u_int32_t swm_debug = 0 - | SWM_D_MISC - | SWM_D_EVENT - | SWM_D_WS - | SWM_D_FOCUS - | SWM_D_MOVE - | SWM_D_STACK - | SWM_D_MOUSE - | SWM_D_PROP - | SWM_D_CLASS - | SWM_D_KEY - | SWM_D_QUIRK - | SWM_D_SPAWN - | SWM_D_EVENTQ - | SWM_D_CONF - | SWM_D_BAR - ; -#else -#define DPRINTF(x...) -#define DNPRINTF(n,x...) -#endif - -#define LENGTH(x) (sizeof x / sizeof x[0]) -#define MODKEY Mod1Mask -#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) -#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) -#define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define SWM_PROPLEN (16) -#define SWM_FUNCNAME_LEN (32) -#define SWM_KEYS_LEN (255) -#define SWM_QUIRK_LEN (64) -#define X(r) (r)->g.x -#define Y(r) (r)->g.y -#define WIDTH(r) (r)->g.w -#define HEIGHT(r) (r)->g.h -#define SH_MIN(w) (w)->sh_mask & PMinSize -#define SH_MIN_W(w) (w)->sh.min_width -#define SH_MIN_H(w) (w)->sh.min_height -#define SH_MAX(w) (w)->sh_mask & PMaxSize -#define SH_MAX_W(w) (w)->sh.max_width -#define SH_MAX_H(w) (w)->sh.max_height -#define SH_INC(w) (w)->sh_mask & PResizeInc -#define SH_INC_W(w) (w)->sh.width_inc -#define SH_INC_H(w) (w)->sh.height_inc -#define SWM_MAX_FONT_STEPS (3) -#define WINID(w) ((w) ? (w)->id : 0) -#define YESNO(x) ((x) ? "yes" : "no") - -#define SWM_FOCUS_DEFAULT (0) -#define SWM_FOCUS_SYNERGY (1) -#define SWM_FOCUS_FOLLOW (2) - -#define SWM_CONF_DEFAULT (0) -#define SWM_CONF_KEYMAPPING (1) - -#ifndef SWM_LIB -#define SWM_LIB "/usr/local/lib/libswmhack.so" -#endif - -char **start_argv; -Atom astate; -Atom aprot; -Atom adelete; -Atom takefocus; -Atom a_wmname; -Atom a_netwmname; -Atom a_utf8_string; -Atom a_string; -Atom a_swm_iconic; -volatile sig_atomic_t running = 1; -volatile sig_atomic_t restart_wm = 0; -int outputs = 0; -int last_focus_event = FocusOut; -int (*xerrorxlib)(Display *, XErrorEvent *); -int other_wm; -int ss_enabled = 0; -int xrandr_support; -int xrandr_eventbase; -unsigned int numlockmask = 0; -Display *display; - -int cycle_empty = 0; -int cycle_visible = 0; -int term_width = 0; -int font_adjusted = 0; -unsigned int mod_key = MODKEY; - -/* dmenu search */ -struct swm_region *search_r; -int select_list_pipe[2]; -int select_resp_pipe[2]; -pid_t searchpid; -volatile sig_atomic_t search_resp; -int search_resp_action; - -struct search_window { - TAILQ_ENTRY(search_window) entry; - int idx; - struct ws_win *win; - GC gc; - Window indicator; -}; -TAILQ_HEAD(search_winlist, search_window); - -struct search_winlist search_wl; - -/* search actions */ -enum { - SWM_SEARCH_NONE, - SWM_SEARCH_UNICONIFY, - SWM_SEARCH_NAME_WORKSPACE, - SWM_SEARCH_SEARCH_WORKSPACE, - SWM_SEARCH_SEARCH_WINDOW -}; - -/* dialog windows */ -double dialog_ratio = 0.6; -/* status bar */ -#define SWM_BAR_MAX (256) -#define SWM_BAR_JUSTIFY_LEFT (0) -#define SWM_BAR_JUSTIFY_CENTER (1) -#define SWM_BAR_JUSTIFY_RIGHT (2) -#define SWM_BAR_OFFSET (4) -#define SWM_BAR_FONTS "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*," \ - "-*-profont-*-*-*-*-*-*-*-*-*-*-*-*," \ - "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*," \ - "-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*" - -#ifdef X_HAVE_UTF8_STRING -#define DRAWSTRING(x...) Xutf8DrawString(x) -#else -#define DRAWSTRING(x...) XmbDrawString(x) -#endif - -char *bar_argv[] = { NULL, NULL }; -int bar_pipe[2]; -unsigned char bar_ext[SWM_BAR_MAX]; -char bar_vertext[SWM_BAR_MAX]; -int bar_version = 0; -sig_atomic_t bar_alarm = 0; -int bar_delay = 30; -int bar_enabled = 1; -int bar_border_width = 1; -int bar_at_bottom = 0; -int bar_extra = 1; -int bar_extra_running = 0; -int bar_verbose = 1; -int bar_height = 0; -int bar_justify = SWM_BAR_JUSTIFY_LEFT; -int stack_enabled = 1; -int clock_enabled = 1; -int urgent_enabled = 0; -char *clock_format = NULL; -int title_name_enabled = 0; -int title_class_enabled = 0; -int window_name_enabled = 0; -int focus_mode = SWM_FOCUS_DEFAULT; -int disable_border = 0; -int border_width = 1; -int verbose_layout = 0; -pid_t bar_pid; -XFontSet bar_fs; -XFontSetExtents *bar_fs_extents; -char *bar_fonts; -char *spawn_term[] = { NULL, NULL }; /* XXX fully dynamic */ -struct passwd *pwd; - -#define SWM_MENU_FN (2) -#define SWM_MENU_NB (4) -#define SWM_MENU_NF (6) -#define SWM_MENU_SB (8) -#define SWM_MENU_SF (10) - -/* layout manager data */ -struct swm_geometry { - int x; - int y; - int w; - int h; -}; - -struct swm_screen; -struct workspace; - -/* virtual "screens" */ -struct swm_region { - TAILQ_ENTRY(swm_region) entry; - struct swm_geometry g; - struct workspace *ws; /* current workspace on this region */ - struct workspace *ws_prior; /* prior workspace on this region */ - struct swm_screen *s; /* screen idx */ - Window bar_window; -}; -TAILQ_HEAD(swm_region_list, swm_region); - -struct ws_win { - TAILQ_ENTRY(ws_win) entry; - Window id; - Window transient; - struct ws_win *child_trans; /* transient child window */ - struct swm_geometry g; /* current geometry */ - struct swm_geometry g_float; /* geometry when floating */ - struct swm_geometry rg_float; /* region geom when floating */ - int g_floatvalid; /* g_float geometry validity */ - int floatmaxed; /* whether maxed by max_stack */ - int floating; - int manual; - int iconic; - unsigned int ewmh_flags; - int font_size_boundary[SWM_MAX_FONT_STEPS]; - int font_steps; - int last_inc; - int can_delete; - int take_focus; - int java; - unsigned long quirks; - struct workspace *ws; /* always valid */ - struct swm_screen *s; /* always valid, never changes */ - XWindowAttributes wa; - XSizeHints sh; - long sh_mask; - XClassHint ch; - XWMHints *hints; -}; -TAILQ_HEAD(ws_win_list, ws_win); - -/* pid goo */ -struct pid_e { - TAILQ_ENTRY(pid_e) entry; - long pid; - int ws; -}; -TAILQ_HEAD(pid_list, pid_e); -struct pid_list pidlist = TAILQ_HEAD_INITIALIZER(pidlist); - -/* layout handlers */ -void stack(void); -void vertical_config(struct workspace *, int); -void vertical_stack(struct workspace *, struct swm_geometry *); -void horizontal_config(struct workspace *, int); -void horizontal_stack(struct workspace *, struct swm_geometry *); -void max_stack(struct workspace *, struct swm_geometry *); -void plain_stacker(struct workspace *); -void fancy_stacker(struct workspace *); - -struct ws_win *find_window(Window); - -void grabbuttons(struct ws_win *, int); -void new_region(struct swm_screen *, int, int, int, int); -void unmanage_window(struct ws_win *); -long getstate(Window); - -int conf_load(char *, int); - -struct layout { - void (*l_stack)(struct workspace *, struct swm_geometry *); - void (*l_config)(struct workspace *, int); - u_int32_t flags; -#define SWM_L_FOCUSPREV (1<<0) -#define SWM_L_MAPONFOCUS (1<<1) - void (*l_string)(struct workspace *); -} layouts[] = { - /* stack, configure */ - { vertical_stack, vertical_config, 0, plain_stacker }, - { horizontal_stack, horizontal_config, 0, plain_stacker }, - { max_stack, NULL, - SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, plain_stacker }, - { NULL, NULL, 0, NULL }, -}; - -/* position of max_stack mode in the layouts array, index into layouts! */ -#define SWM_V_STACK (0) -#define SWM_H_STACK (1) -#define SWM_MAX_STACK (2) - -#define SWM_H_SLICE (32) -#define SWM_V_SLICE (32) - -/* define work spaces */ -struct workspace { - int idx; /* workspace index */ - char *name; /* workspace name */ - int always_raise; /* raise windows on focus */ - struct layout *cur_layout; /* current layout handlers */ - struct ws_win *focus; /* may be NULL */ - struct ws_win *focus_prev; /* may be NULL */ - struct swm_region *r; /* may be NULL */ - struct swm_region *old_r; /* may be NULL */ - struct ws_win_list winlist; /* list of windows in ws */ - struct ws_win_list unmanagedlist; /* list of dead windows in ws */ - char stacker[10]; /* display stacker and layout */ - - /* stacker state */ - struct { - int horizontal_msize; - int horizontal_mwin; - int horizontal_stacks; - int horizontal_flip; - int vertical_msize; - int vertical_mwin; - int vertical_stacks; - int vertical_flip; - } l_state; -}; - -enum { SWM_S_COLOR_BAR, SWM_S_COLOR_BAR_BORDER, SWM_S_COLOR_BAR_FONT, - SWM_S_COLOR_FOCUS, SWM_S_COLOR_UNFOCUS, SWM_S_COLOR_MAX }; - -/* physical screen mapping */ -#define SWM_WS_MAX (10) -struct swm_screen { - int idx; /* screen index */ - struct swm_region_list rl; /* list of regions on this screen */ - struct swm_region_list orl; /* list of old regions */ - Window root; - struct workspace ws[SWM_WS_MAX]; - - /* colors */ - struct { - unsigned long color; - char *name; - } c[SWM_S_COLOR_MAX]; - - GC bar_gc; -}; -struct swm_screen *screens; -int num_screens; - -/* args to functions */ -union arg { - int id; -#define SWM_ARG_ID_FOCUSNEXT (0) -#define SWM_ARG_ID_FOCUSPREV (1) -#define SWM_ARG_ID_FOCUSMAIN (2) -#define SWM_ARG_ID_FOCUSCUR (4) -#define SWM_ARG_ID_SWAPNEXT (10) -#define SWM_ARG_ID_SWAPPREV (11) -#define SWM_ARG_ID_SWAPMAIN (12) -#define SWM_ARG_ID_MOVELAST (13) -#define SWM_ARG_ID_MASTERSHRINK (20) -#define SWM_ARG_ID_MASTERGROW (21) -#define SWM_ARG_ID_MASTERADD (22) -#define SWM_ARG_ID_MASTERDEL (23) -#define SWM_ARG_ID_FLIPLAYOUT (24) -#define SWM_ARG_ID_STACKRESET (30) -#define SWM_ARG_ID_STACKINIT (31) -#define SWM_ARG_ID_CYCLEWS_UP (40) -#define SWM_ARG_ID_CYCLEWS_DOWN (41) -#define SWM_ARG_ID_CYCLESC_UP (42) -#define SWM_ARG_ID_CYCLESC_DOWN (43) -#define SWM_ARG_ID_CYCLEWS_UP_ALL (44) -#define SWM_ARG_ID_CYCLEWS_DOWN_ALL (45) -#define SWM_ARG_ID_STACKINC (50) -#define SWM_ARG_ID_STACKDEC (51) -#define SWM_ARG_ID_SS_ALL (60) -#define SWM_ARG_ID_SS_WINDOW (61) -#define SWM_ARG_ID_DONTCENTER (70) -#define SWM_ARG_ID_CENTER (71) -#define SWM_ARG_ID_KILLWINDOW (80) -#define SWM_ARG_ID_DELETEWINDOW (81) -#define SWM_ARG_ID_WIDTHGROW (90) -#define SWM_ARG_ID_WIDTHSHRINK (91) -#define SWM_ARG_ID_HEIGHTGROW (92) -#define SWM_ARG_ID_HEIGHTSHRINK (93) -#define SWM_ARG_ID_MOVEUP (100) -#define SWM_ARG_ID_MOVEDOWN (101) -#define SWM_ARG_ID_MOVELEFT (102) -#define SWM_ARG_ID_MOVERIGHT (103) - char **argv; -}; - -void focus(struct swm_region *, union arg *); -void focus_magic(struct ws_win *); - -/* quirks */ -struct quirk { - TAILQ_ENTRY(quirk) entry; - char *class; - char *name; - unsigned long quirk; -#define SWM_Q_FLOAT (1<<0) /* float this window */ -#define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */ -#define SWM_Q_ANYWHERE (1<<2) /* don't position this window */ -#define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */ -#define SWM_Q_FULLSCREEN (1<<4) /* remove border */ -#define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */ -}; -TAILQ_HEAD(quirk_list, quirk); -struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); - -/* - * Supported EWMH hints should be added to - * both the enum and the ewmh array - */ -enum { _NET_ACTIVE_WINDOW, _NET_MOVERESIZE_WINDOW, _NET_CLOSE_WINDOW, - _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK, - _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_UTILITY, - _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_DIALOG, - _NET_WM_WINDOW_TYPE_NORMAL, _NET_WM_STATE, - _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT, - _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER, - _NET_WM_STATE_HIDDEN, _NET_WM_STATE_ABOVE, _SWM_WM_STATE_MANUAL, - _NET_WM_STATE_FULLSCREEN, _NET_WM_ALLOWED_ACTIONS, _NET_WM_ACTION_MOVE, - _NET_WM_ACTION_RESIZE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_CLOSE, - SWM_EWMH_HINT_MAX }; - -struct ewmh_hint { - char *name; - Atom atom; -} ewmh[SWM_EWMH_HINT_MAX] = { - /* must be in same order as in the enum */ - {"_NET_ACTIVE_WINDOW", None}, - {"_NET_MOVERESIZE_WINDOW", None}, - {"_NET_CLOSE_WINDOW", None}, - {"_NET_WM_WINDOW_TYPE", None}, - {"_NET_WM_WINDOW_TYPE_DOCK", None}, - {"_NET_WM_WINDOW_TYPE_TOOLBAR", None}, - {"_NET_WM_WINDOW_TYPE_UTILITY", None}, - {"_NET_WM_WINDOW_TYPE_SPLASH", None}, - {"_NET_WM_WINDOW_TYPE_DIALOG", None}, - {"_NET_WM_WINDOW_TYPE_NORMAL", None}, - {"_NET_WM_STATE", None}, - {"_NET_WM_STATE_MAXIMIZED_HORZ", None}, - {"_NET_WM_STATE_MAXIMIZED_VERT", None}, - {"_NET_WM_STATE_SKIP_TASKBAR", None}, - {"_NET_WM_STATE_SKIP_PAGER", None}, - {"_NET_WM_STATE_HIDDEN", None}, - {"_NET_WM_STATE_ABOVE", None}, - {"_SWM_WM_STATE_MANUAL", None}, - {"_NET_WM_STATE_FULLSCREEN", None}, - {"_NET_WM_ALLOWED_ACTIONS", None}, - {"_NET_WM_ACTION_MOVE", None}, - {"_NET_WM_ACTION_RESIZE", None}, - {"_NET_WM_ACTION_FULLSCREEN", None}, - {"_NET_WM_ACTION_CLOSE", None}, -}; - -void store_float_geom(struct ws_win *, struct swm_region *); -int floating_toggle_win(struct ws_win *); -void spawn_select(struct swm_region *, union arg *, char *, int *); -unsigned char *get_win_name(Window); - -int -get_property(Window id, Atom atom, long count, Atom type, unsigned long *nitems, - unsigned long *nbytes, unsigned char **data) -{ - int format, status; - unsigned long *nbytes_ret, *nitems_ret; - unsigned long nbytes_tmp, nitems_tmp; - Atom real; - - nbytes_ret = nbytes != NULL ? nbytes : &nbytes_tmp; - nitems_ret = nitems != NULL ? nitems : &nitems_tmp; - - status = XGetWindowProperty(display, id, atom, 0L, count, False, type, - &real, &format, nitems_ret, nbytes_ret, data); - - if (status != Success) - return False; - if (real != type) - return False; - - return True; -} - -void -update_iconic(struct ws_win *win, int newv) -{ - int32_t v = newv; - Atom iprop; - - win->iconic = newv; - - iprop = XInternAtom(display, "_SWM_ICONIC", False); - if (!iprop) - return; - if (newv) - XChangeProperty(display, win->id, iprop, XA_INTEGER, 32, - PropModeReplace, (unsigned char *)&v, 1); - else - XDeleteProperty(display, win->id, iprop); -} - -int -get_iconic(struct ws_win *win) -{ - int32_t v = 0; - int retfmt, status; - Atom iprop, rettype; - unsigned long nitems, extra; - unsigned char *prop = NULL; - - iprop = XInternAtom(display, "_SWM_ICONIC", False); - if (!iprop) - goto out; - status = XGetWindowProperty(display, win->id, iprop, 0L, 1L, - False, XA_INTEGER, &rettype, &retfmt, &nitems, &extra, &prop); - if (status != Success) - goto out; - if (rettype != XA_INTEGER || retfmt != 32) - goto out; - if (nitems != 1) - goto out; - v = *((int32_t *)prop); - -out: - if (prop != NULL) - XFree(prop); - return (v); -} - -void -setup_ewmh(void) -{ - int i,j; - Atom sup_list; - - sup_list = XInternAtom(display, "_NET_SUPPORTED", False); - - for (i = 0; i < LENGTH(ewmh); i++) - ewmh[i].atom = XInternAtom(display, ewmh[i].name, False); - - for (i = 0; i < ScreenCount(display); i++) { - /* Support check window will be created by workaround(). */ - - /* Report supported atoms */ - XDeleteProperty(display, screens[i].root, sup_list); - for (j = 0; j < LENGTH(ewmh); j++) - XChangeProperty(display, screens[i].root, - sup_list, XA_ATOM, 32, - PropModeAppend, (unsigned char *)&ewmh[j].atom,1); - } -} - -void -teardown_ewmh(void) -{ - int i, success; - unsigned char *data = NULL; - unsigned long n; - Atom sup_check, sup_list; - Window id; - - sup_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); - sup_list = XInternAtom(display, "_NET_SUPPORTED", False); - - for (i = 0; i < ScreenCount(display); i++) { - /* Get the support check window and destroy it */ - success = get_property(screens[i].root, sup_check, 1, XA_WINDOW, - &n, NULL, &data); - - if (success) { - id = data[0]; - XDestroyWindow(display, id); - XDeleteProperty(display, screens[i].root, sup_check); - XDeleteProperty(display, screens[i].root, sup_list); - } - - XFree(data); - } -} - -void -ewmh_autoquirk(struct ws_win *win) -{ - int success, i; - unsigned long *data = NULL, n; - Atom type; - - success = get_property(win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, (~0L), - XA_ATOM, &n, NULL, (void *)&data); - - if (!success) { - XFree(data); - return; - } - - for (i = 0; i < n; i++) { - type = data[i]; - if (type == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom) - break; - if (type == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom || - type == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom || - type == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) { - win->floating = 1; - win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE; - break; - } - if (type == ewmh[_NET_WM_WINDOW_TYPE_SPLASH].atom || - type == ewmh[_NET_WM_WINDOW_TYPE_DIALOG].atom) { - win->floating = 1; - win->quirks = SWM_Q_FLOAT; - break; - } - } - - XFree(data); -} - -#define SWM_EWMH_ACTION_COUNT_MAX (6) -#define EWMH_F_FULLSCREEN (1<<0) -#define EWMH_F_ABOVE (1<<1) -#define EWMH_F_HIDDEN (1<<2) -#define EWMH_F_SKIP_PAGER (1<<3) -#define EWMH_F_SKIP_TASKBAR (1<<4) -#define SWM_F_MANUAL (1<<5) - -int -ewmh_set_win_fullscreen(struct ws_win *win, int fs) -{ - struct swm_geometry rg; - - if (!win->ws->r) - return 0; - - if (!win->floating) - return 0; - - DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: window: 0x%lx, " - "fullscreen %s\n", win->id, YESNO(fs)); - - rg = win->ws->r->g; - - if (fs) { - store_float_geom(win, win->ws->r); - - win->g = rg; - } else { - if (win->g_floatvalid) { - /* refloat at last floating relative position */ - X(win) = win->g_float.x - win->rg_float.x + rg.x; - Y(win) = win->g_float.y - win->rg_float.y + rg.y; - WIDTH(win) = win->g_float.w; - HEIGHT(win) = win->g_float.h; - } - } - - return 1; -} - -void -ewmh_update_actions(struct ws_win *win) -{ - Atom actions[SWM_EWMH_ACTION_COUNT_MAX]; - int n = 0; - - if (win == NULL) - return; - - actions[n++] = ewmh[_NET_WM_ACTION_CLOSE].atom; - - if (win->floating) { - actions[n++] = ewmh[_NET_WM_ACTION_MOVE].atom; - actions[n++] = ewmh[_NET_WM_ACTION_RESIZE].atom; - } - - XChangeProperty(display, win->id, ewmh[_NET_WM_ALLOWED_ACTIONS].atom, - XA_ATOM, 32, PropModeReplace, (unsigned char *)actions, n); -} - -#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ -#define _NET_WM_STATE_ADD 1 /* add/set property */ -#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ - -void -ewmh_update_win_state(struct ws_win *win, long state, long action) -{ - unsigned int mask = 0; - unsigned int changed = 0; - unsigned int orig_flags; - - if (win == NULL) - return; - - if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) - mask = EWMH_F_FULLSCREEN; - if (state == ewmh[_NET_WM_STATE_ABOVE].atom) - mask = EWMH_F_ABOVE; - if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) - mask = SWM_F_MANUAL; - if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom) - mask = EWMH_F_SKIP_PAGER; - if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) - mask = EWMH_F_SKIP_TASKBAR; - - - orig_flags = win->ewmh_flags; - - switch (action) { - case _NET_WM_STATE_REMOVE: - win->ewmh_flags &= ~mask; - break; - case _NET_WM_STATE_ADD: - win->ewmh_flags |= mask; - break; - case _NET_WM_STATE_TOGGLE: - win->ewmh_flags ^= mask; - break; - } - - changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0; - - if (state == ewmh[_NET_WM_STATE_ABOVE].atom) - if (changed) - if (!floating_toggle_win(win)) - win->ewmh_flags = orig_flags; /* revert */ - if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) - if (changed) - win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0; - if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) - if (changed) - if (!ewmh_set_win_fullscreen(win, - win->ewmh_flags & EWMH_F_FULLSCREEN)) - win->ewmh_flags = orig_flags; /* revert */ - - XDeleteProperty(display, win->id, ewmh[_NET_WM_STATE].atom); - - if (win->ewmh_flags & EWMH_F_FULLSCREEN) - XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, - XA_ATOM, 32, PropModeAppend, - (unsigned char *)&ewmh[_NET_WM_STATE_FULLSCREEN].atom, 1); - if (win->ewmh_flags & EWMH_F_SKIP_PAGER) - XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, - XA_ATOM, 32, PropModeAppend, - (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_PAGER].atom, 1); - if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR) - XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, - XA_ATOM, 32, PropModeAppend, - (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom, 1); - if (win->ewmh_flags & EWMH_F_ABOVE) - XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, - XA_ATOM, 32, PropModeAppend, - (unsigned char *)&ewmh[_NET_WM_STATE_ABOVE].atom, 1); - if (win->ewmh_flags & SWM_F_MANUAL) - XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, - XA_ATOM, 32, PropModeAppend, - (unsigned char *)&ewmh[_SWM_WM_STATE_MANUAL].atom, 1); -} - -void -ewmh_get_win_state(struct ws_win *win) -{ - int success, i; - unsigned long n; - Atom *states; - - if (win == NULL) - return; - - win->ewmh_flags = 0; - if (win->floating) - win->ewmh_flags |= EWMH_F_ABOVE; - if (win->manual) - win->ewmh_flags |= SWM_F_MANUAL; - - success = get_property(win->id, ewmh[_NET_WM_STATE].atom, - (~0L), XA_ATOM, &n, NULL, (void *)&states); - - if (!success) - return; - - for (i = 0; i < n; i++) - ewmh_update_win_state(win, states[i], _NET_WM_STATE_ADD); - - XFree(states); -} - -/* events */ -#ifdef SWM_DEBUG -char * -geteventname(XEvent *e) -{ - char *name = NULL; - - switch (e->type) { - case KeyPress: - name = "KeyPress"; - break; - case KeyRelease: - name = "KeyRelease"; - break; - case ButtonPress: - name = "ButtonPress"; - break; - case ButtonRelease: - name = "ButtonRelease"; - break; - case MotionNotify: - name = "MotionNotify"; - break; - case EnterNotify: - name = "EnterNotify"; - break; - case LeaveNotify: - name = "LeaveNotify"; - break; - case FocusIn: - name = "FocusIn"; - break; - case FocusOut: - name = "FocusOut"; - break; - case KeymapNotify: - name = "KeymapNotify"; - break; - case Expose: - name = "Expose"; - break; - case GraphicsExpose: - name = "GraphicsExpose"; - break; - case NoExpose: - name = "NoExpose"; - break; - case VisibilityNotify: - name = "VisibilityNotify"; - break; - case CreateNotify: - name = "CreateNotify"; - break; - case DestroyNotify: - name = "DestroyNotify"; - break; - case UnmapNotify: - name = "UnmapNotify"; - break; - case MapNotify: - name = "MapNotify"; - break; - case MapRequest: - name = "MapRequest"; - break; - case ReparentNotify: - name = "ReparentNotify"; - break; - case ConfigureNotify: - name = "ConfigureNotify"; - break; - case ConfigureRequest: - name = "ConfigureRequest"; - break; - case GravityNotify: - name = "GravityNotify"; - break; - case ResizeRequest: - name = "ResizeRequest"; - break; - case CirculateNotify: - name = "CirculateNotify"; - break; - case CirculateRequest: - name = "CirculateRequest"; - break; - case PropertyNotify: - name = "PropertyNotify"; - break; - case SelectionClear: - name = "SelectionClear"; - break; - case SelectionRequest: - name = "SelectionRequest"; - break; - case SelectionNotify: - name = "SelectionNotify"; - break; - case ColormapNotify: - name = "ColormapNotify"; - break; - case ClientMessage: - name = "ClientMessage"; - break; - case MappingNotify: - name = "MappingNotify"; - break; - default: - name = "Unknown"; - } - - return name; -} - -char * -xrandr_geteventname(XEvent *e) -{ - char *name = NULL; - - switch(e->type - xrandr_eventbase) { - case RRScreenChangeNotify: - name = "RRScreenChangeNotify"; - break; - default: - name = "Unknown"; - } - - return name; -} - -void -dumpwins(struct swm_region *r, union arg *args) -{ - struct ws_win *win; - unsigned int state; - XWindowAttributes wa; - - if (r->ws == NULL) { - warnx("dumpwins: invalid workspace"); - return; - } - - warnx("=== managed window list ws %02d ===", r->ws->idx); - - TAILQ_FOREACH(win, &r->ws->winlist, entry) { - state = getstate(win->id); - if (!XGetWindowAttributes(display, win->id, &wa)) - warnx("window: 0x%lx, failed XGetWindowAttributes", - win->id); - warnx("window: 0x%lx, map_state: %d, state: %d, " - "transient: 0x%lx", win->id, wa.map_state, state, - win->transient); - } - - warnx("===== unmanaged window list ====="); - TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) { - state = getstate(win->id); - if (!XGetWindowAttributes(display, win->id, &wa)) - warnx("window: 0x%lx, failed XGetWindowAttributes", - win->id); - warnx("window: 0x%lx, map_state: %d, state: %d, " - "transient: 0x%lx", win->id, wa.map_state, state, - win->transient); - } - - warnx("================================="); -} -#else -void -dumpwins(struct swm_region *r, union arg *args) -{ -} -#endif /* SWM_DEBUG */ - -void expose(XEvent *); -void keypress(XEvent *); -void buttonpress(XEvent *); -void configurerequest(XEvent *); -void configurenotify(XEvent *); -void destroynotify(XEvent *); -void enternotify(XEvent *); -void focusevent(XEvent *); -void mapnotify(XEvent *); -void mappingnotify(XEvent *); -void maprequest(XEvent *); -void propertynotify(XEvent *); -void unmapnotify(XEvent *); -void visibilitynotify(XEvent *); -void clientmessage(XEvent *); - -void (*handler[LASTEvent])(XEvent *) = { - [Expose] = expose, - [KeyPress] = keypress, - [ButtonPress] = buttonpress, - [ConfigureRequest] = configurerequest, - [ConfigureNotify] = configurenotify, - [DestroyNotify] = destroynotify, - [EnterNotify] = enternotify, - [FocusIn] = focusevent, - [FocusOut] = focusevent, - [MapNotify] = mapnotify, - [MappingNotify] = mappingnotify, - [MapRequest] = maprequest, - [PropertyNotify] = propertynotify, - [UnmapNotify] = unmapnotify, - [VisibilityNotify] = visibilitynotify, - [ClientMessage] = clientmessage, -}; - -void -sighdlr(int sig) -{ - int saved_errno, status; - pid_t pid; - - saved_errno = errno; - - switch (sig) { - case SIGCHLD: - while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) { - if (pid == -1) { - if (errno == EINTR) - continue; -#ifdef SWM_DEBUG - if (errno != ECHILD) - warn("sighdlr: waitpid"); -#endif /* SWM_DEBUG */ - break; - } - if (pid == searchpid) - search_resp = 1; - -#ifdef SWM_DEBUG - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != 0) - warnx("sighdlr: child exit status: %d", - WEXITSTATUS(status)); - } else - warnx("sighdlr: child is terminated " - "abnormally"); -#endif /* SWM_DEBUG */ - } - break; - - case SIGHUP: - restart_wm = 1; - break; - case SIGINT: - case SIGTERM: - case SIGQUIT: - running = 0; - break; - } - - errno = saved_errno; -} - -struct pid_e * -find_pid(long pid) -{ - struct pid_e *p = NULL; - - DNPRINTF(SWM_D_MISC, "find_pid: %lu\n", pid); - - if (pid == 0) - return (NULL); - - TAILQ_FOREACH(p, &pidlist, entry) { - if (p->pid == pid) - return (p); - } - - return (NULL); -} - -unsigned long -name_to_color(char *colorname) -{ - Colormap cmap; - Status status; - XColor screen_def, exact_def; - unsigned long result = 0; - char cname[32] = "#"; - - cmap = DefaultColormap(display, screens[0].idx); - status = XAllocNamedColor(display, cmap, colorname, - &screen_def, &exact_def); - if (!status) { - strlcat(cname, colorname + 2, sizeof cname - 1); - status = XAllocNamedColor(display, cmap, cname, &screen_def, - &exact_def); - } - if (status) - result = screen_def.pixel; - else - warnx("color '%s' not found", colorname); - - return (result); -} - -void -setscreencolor(char *val, int i, int c) -{ - if (i > 0 && i <= ScreenCount(display)) { - screens[i - 1].c[c].color = name_to_color(val); - free(screens[i - 1].c[c].name); - if ((screens[i - 1].c[c].name = strdup(val)) == NULL) - err(1, "strdup"); - } else if (i == -1) { - for (i = 0; i < ScreenCount(display); i++) { - screens[i].c[c].color = name_to_color(val); - free(screens[i].c[c].name); - if ((screens[i].c[c].name = strdup(val)) == NULL) - err(1, "strdup"); - } - } else - errx(1, "invalid screen index: %d out of bounds (maximum %d)", - i, ScreenCount(display)); -} - -void -fancy_stacker(struct workspace *ws) -{ - strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); - if (ws->cur_layout->l_stack == vertical_stack) - snprintf(ws->stacker, sizeof ws->stacker, - ws->l_state.vertical_flip ? "[%d>%d]" : "[%d|%d]", - ws->l_state.vertical_mwin, ws->l_state.vertical_stacks); - if (ws->cur_layout->l_stack == horizontal_stack) - snprintf(ws->stacker, sizeof ws->stacker, - ws->l_state.horizontal_flip ? "[%dv%d]" : "[%d-%d]", - ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks); -} - -void -plain_stacker(struct workspace *ws) -{ - strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); - if (ws->cur_layout->l_stack == vertical_stack) - strlcpy(ws->stacker, ws->l_state.vertical_flip ? "[>]" : "[|]", - sizeof ws->stacker); - if (ws->cur_layout->l_stack == horizontal_stack) - strlcpy(ws->stacker, ws->l_state.horizontal_flip ? "[v]" : "[-]", - sizeof ws->stacker); -} - -void -custom_region(char *val) -{ - unsigned int sidx, x, y, w, h; - - if (sscanf(val, "screen[%u]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5) - errx(1, "invalid custom region, " - "should be 'screen[]:x++"); - if (sidx < 1 || sidx > ScreenCount(display)) - errx(1, "invalid screen index: %d out of bounds (maximum %d)", - sidx, ScreenCount(display)); - sidx--; - - if (w < 1 || h < 1) - errx(1, "region %ux%u+%u+%u too small", w, h, x, y); - - if (x > DisplayWidth(display, sidx) || - y > DisplayHeight(display, sidx) || - w + x > DisplayWidth(display, sidx) || - h + y > DisplayHeight(display, sidx)) { - warnx("ignoring region %ux%u+%u+%u - not within screen " - "boundaries (%ux%u)", w, h, x, y, - DisplayWidth(display, sidx), DisplayHeight(display, sidx)); - return; - } - - new_region(&screens[sidx], x, y, w, h); -} - -void -socket_setnonblock(int fd) -{ - int flags; - - if ((flags = fcntl(fd, F_GETFL, 0)) == -1) - err(1, "fcntl F_GETFL"); - flags |= O_NONBLOCK; - if ((flags = fcntl(fd, F_SETFL, flags)) == -1) - err(1, "fcntl F_SETFL"); -} - -void -bar_print(struct swm_region *r, char *s) -{ - int x = 0; - size_t len; - XRectangle ibox, lbox; - - XClearWindow(display, r->bar_window); - - len = strlen(s); - XmbTextExtents(bar_fs, s, len, &ibox, &lbox); - - switch (bar_justify) { - case SWM_BAR_JUSTIFY_LEFT: - x = SWM_BAR_OFFSET; - break; - case SWM_BAR_JUSTIFY_CENTER: - x = (WIDTH(r) - lbox.width) / 2; - break; - case SWM_BAR_JUSTIFY_RIGHT: - x = WIDTH(r) - lbox.width - SWM_BAR_OFFSET; - break; - } - - if (x < SWM_BAR_OFFSET) - x = SWM_BAR_OFFSET; - - DRAWSTRING(display, r->bar_window, bar_fs, r->s->bar_gc, - x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 - - lbox.y, s, len); -} - -void -bar_extra_stop(void) -{ - if (bar_pipe[0]) { - close(bar_pipe[0]); - bzero(bar_pipe, sizeof bar_pipe); - } - if (bar_pid) { - kill(bar_pid, SIGTERM); - bar_pid = 0; - } - strlcpy((char *)bar_ext, "", sizeof bar_ext); - bar_extra = 0; -} - -void -bar_class_name(char *s, ssize_t sz, struct ws_win *cur_focus) -{ - int do_class, do_name; - Status status; - XClassHint *xch = NULL; - - if ((title_name_enabled == 1 || title_class_enabled == 1) && - cur_focus != NULL) { - if ((xch = XAllocClassHint()) == NULL) - goto out; - status = XGetClassHint(display, cur_focus->id, xch); - if (status == BadWindow || status == BadAlloc) - goto out; - do_class = (title_class_enabled && xch->res_class != NULL); - do_name = (title_name_enabled && xch->res_name != NULL); - if (do_class) - strlcat(s, xch->res_class, sz); - if (do_class && do_name) - strlcat(s, ":", sz); - if (do_name) - strlcat(s, xch->res_name, sz); - strlcat(s, " ", sz); - } -out: - if (xch) { - XFree(xch->res_name); - XFree(xch->res_class); - XFree(xch); - } -} - -void -bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus) -{ - unsigned char *title; - - if (window_name_enabled && cur_focus != NULL) { - title = get_win_name(cur_focus->id); - if (title != NULL) { - DNPRINTF(SWM_D_BAR, "bar_window_name: title: %s\n", - title); - - if (cur_focus->floating) - strlcat(s, "(f) ", sz); - strlcat(s, (char *)title, sz); - strlcat(s, " ", sz); - XFree(title); - } - } -} - -int urgent[SWM_WS_MAX]; -void -bar_urgent(char *s, ssize_t sz) -{ - XWMHints *wmh = NULL; - struct ws_win *win; - int i, j; - char b[8]; - - if (urgent_enabled == 0) - return; - - for (i = 0; i < SWM_WS_MAX; i++) - urgent[i] = 0; - - for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { - wmh = XGetWMHints(display, win->id); - if (wmh == NULL) - continue; - - if (wmh->flags & XUrgencyHint) - urgent[j] = 1; - XFree(wmh); - } - - strlcat(s, "* ", sz); - for (i = 0; i < SWM_WS_MAX; i++) { - if (urgent[i]) - snprintf(b, sizeof b, "%d ", i + 1); - else - snprintf(b, sizeof b, "- "); - strlcat(s, b, sz); - } - strlcat(s, "* ", sz); -} - -void -bar_update(void) -{ - time_t tmt; - struct tm tm; - struct swm_region *r; - int i, x; - size_t len; - char ws[SWM_BAR_MAX]; - char s[SWM_BAR_MAX]; - unsigned char cn[SWM_BAR_MAX]; - char loc[SWM_BAR_MAX]; - char *b, *stack = ""; - - if (bar_enabled == 0) - return; - if (bar_extra && bar_extra_running) { - /* ignore short reads; it'll correct itself */ - while ((b = fgetln(stdin, &len)) != NULL) - if (b && b[len - 1] == '\n') { - b[len - 1] = '\0'; - strlcpy((char *)bar_ext, b, sizeof bar_ext); - } - if (b == NULL && errno != EAGAIN) { - warn("bar_update: bar_extra failed"); - bar_extra_stop(); - } - } else - strlcpy((char *)bar_ext, "", sizeof bar_ext); - - if (clock_enabled == 0) - strlcpy(s, "", sizeof s); - else { - time(&tmt); - localtime_r(&tmt, &tm); - len = strftime(s, sizeof s, clock_format, &tm); - s[len] = '\0'; - strlcat(s, " ", sizeof s); - } - - for (i = 0; i < ScreenCount(display); i++) { - x = 1; - TAILQ_FOREACH(r, &screens[i].rl, entry) { - strlcpy((char *)cn, "", sizeof cn); - strlcpy(ws, "", sizeof ws); - if (r && r->ws) { - bar_urgent((char *)cn, sizeof cn); - bar_class_name((char *)cn, sizeof cn, - r->ws->focus); - bar_window_name((char *)cn, sizeof cn, - r->ws->focus); - if (r->ws->name) - snprintf(ws, sizeof ws, "<%s>", - r->ws->name); - } - if (stack_enabled) - stack = r->ws->stacker; - - snprintf(loc, sizeof loc, "%d:%d %s %s %s%s %s " - "%s", x++, r->ws->idx + 1, stack, ws, s, cn, - bar_ext, bar_vertext); - bar_print(r, loc); - } - } - alarm(bar_delay); -} - -void -bar_check_opts(void) -{ - if (title_class_enabled || title_name_enabled || window_name_enabled) - bar_update(); -} - -void -bar_signal(int sig) -{ - bar_alarm = 1; -} - -void -bar_toggle(struct swm_region *r, union arg *args) -{ - struct swm_region *tmpr; - int i, sc = ScreenCount(display); - - DNPRINTF(SWM_D_BAR, "bar_toggle\n"); - - if (bar_enabled) - for (i = 0; i < sc; i++) - TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - XUnmapWindow(display, tmpr->bar_window); - else - for (i = 0; i < sc; i++) - TAILQ_FOREACH(tmpr, &screens[i].rl, entry) - XMapRaised(display, tmpr->bar_window); - - bar_enabled = !bar_enabled; - - stack(); - /* must be after stack */ - bar_update(); -} - -void -bar_refresh(void) -{ - XSetWindowAttributes wa; - struct swm_region *r; - int i; - - /* do this here because the conf file is in memory */ - if (bar_extra && bar_extra_running == 0 && bar_argv[0]) { - /* launch external status app */ - bar_extra_running = 1; - if (pipe(bar_pipe) == -1) - err(1, "pipe error"); - socket_setnonblock(bar_pipe[0]); - socket_setnonblock(bar_pipe[1]); /* XXX hmmm, really? */ - if (dup2(bar_pipe[0], 0) == -1) - err(1, "dup2"); - if (dup2(bar_pipe[1], 1) == -1) - err(1, "dup2"); - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - err(1, "could not disable SIGPIPE"); - switch (bar_pid = fork()) { - case -1: - err(1, "cannot fork"); - break; - case 0: /* child */ - close(bar_pipe[0]); - execvp(bar_argv[0], bar_argv); - err(1, "%s external app failed", bar_argv[0]); - break; - default: /* parent */ - close(bar_pipe[1]); - break; - } - } - - bzero(&wa, sizeof wa); - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) { - wa.border_pixel = - screens[i].c[SWM_S_COLOR_BAR_BORDER].color; - wa.background_pixel = - screens[i].c[SWM_S_COLOR_BAR].color; - XChangeWindowAttributes(display, r->bar_window, - CWBackPixel | CWBorderPixel, &wa); - } - bar_update(); -} - -void -bar_setup(struct swm_region *r) -{ - char *default_string; - char **missing_charsets; - int num_missing_charsets = 0; - int i, x, y; - - if (bar_fs) { - XFreeFontSet(display, bar_fs); - bar_fs = NULL; - } - - - DNPRINTF(SWM_D_BAR, "bar_setup: loading bar_fonts: %s\n", bar_fonts); - - bar_fs = XCreateFontSet(display, bar_fonts, &missing_charsets, - &num_missing_charsets, &default_string); - - if (num_missing_charsets > 0) { - warnx("Unable to load charset(s):"); - - for (i = 0; i < num_missing_charsets; ++i) - warnx("%s", missing_charsets[i]); - - XFreeStringList(missing_charsets); - - if (strcmp(default_string, "")) - warnx("Glyphs from those sets will be replaced " - "by '%s'.", default_string); - else - warnx("Glyphs from those sets won't be drawn."); - } - - if (bar_fs == NULL) - errx(1, "Error creating font set structure."); - - bar_fs_extents = XExtentsOfFontSet(bar_fs); - - bar_height = bar_fs_extents->max_logical_extent.height + - 2 * bar_border_width; - - if (bar_height < 1) - bar_height = 1; - - x = X(r); - y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); - - r->bar_window = XCreateSimpleWindow(display, - r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, - bar_height - 2 * bar_border_width, - bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color, - r->s->c[SWM_S_COLOR_BAR].color); - XSelectInput(display, r->bar_window, VisibilityChangeMask); - if (bar_enabled) - XMapRaised(display, r->bar_window); - DNPRINTF(SWM_D_BAR, "bar_setup: bar_window: 0x%lx\n", r->bar_window); - - if (signal(SIGALRM, bar_signal) == SIG_ERR) - err(1, "could not install bar_signal"); - bar_refresh(); -} - -void -drain_enter_notify(void) -{ - int i = 0; - XEvent cne; - - while (XCheckMaskEvent(display, EnterWindowMask, &cne)) - i++; - - DNPRINTF(SWM_D_MISC, "drain_enter_notify: drained: %d\n", i); -} - -void -set_win_state(struct ws_win *win, long state) -{ - long data[] = {state, None}; - - DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%lx\n", win->id); - - if (win == NULL) - return; - - XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace, - (unsigned char *)data, 2); -} - -long -getstate(Window w) -{ - long result = -1; - unsigned char *p = NULL; - unsigned long n; - - if (!get_property(w, astate, 2L, astate, &n, NULL, &p)) - return (-1); - if (n != 0) - result = *((long *)p); - XFree(p); - return (result); -} - -void -version(struct swm_region *r, union arg *args) -{ - bar_version = !bar_version; - if (bar_version) - snprintf(bar_vertext, sizeof bar_vertext, - "Version: %s Build: %s", SCROTWM_VERSION, buildstr); - else - strlcpy(bar_vertext, "", sizeof bar_vertext); - bar_update(); -} - -void -client_msg(struct ws_win *win, Atom a) -{ - XClientMessageEvent cm; - - if (win == NULL) - return; - - bzero(&cm, sizeof cm); - cm.type = ClientMessage; - cm.window = win->id; - cm.message_type = aprot; - cm.format = 32; - cm.data.l[0] = a; - cm.data.l[1] = CurrentTime; - XSendEvent(display, win->id, False, 0L, (XEvent *)&cm); -} - -/* synthetic response to a ConfigureRequest when not making a change */ -void -config_win(struct ws_win *win, XConfigureRequestEvent *ev) -{ - XConfigureEvent ce; - - if (win == NULL) - return; - - /* send notification of unchanged state. */ - ce.type = ConfigureNotify; - ce.x = X(win); - ce.y = Y(win); - ce.width = WIDTH(win); - ce.height = HEIGHT(win); - ce.override_redirect = False; - - if (ev == NULL) { - /* EWMH */ - ce.display = display; - ce.event = win->id; - ce.window = win->id; - ce.border_width = border_width; - ce.above = None; - } else { - /* normal */ - ce.display = ev->display; - ce.event = ev->window; - ce.window = ev->window; - - /* make response appear more WM_SIZE_HINTS-compliant */ - if (win->sh_mask) - DNPRINTF(SWM_D_MISC, "config_win: hints: window: 0x%lx," - " sh_mask: %ld, min: %d x %d, max: %d x %d, inc: " - "%d x %d\n", win->id, win->sh_mask, SH_MIN_W(win), - SH_MIN_H(win), SH_MAX_W(win), SH_MAX_H(win), - SH_INC_W(win), SH_INC_H(win)); - - /* min size */ - if (SH_MIN(win)) { - /* the hint may be set... to 0! */ - if (SH_MIN_W(win) > 0 && ce.width < SH_MIN_W(win)) - ce.width = SH_MIN_W(win); - if (SH_MIN_H(win) > 0 && ce.height < SH_MIN_H(win)) - ce.height = SH_MIN_H(win); - } - - /* max size */ - if (SH_MAX(win)) { - /* may also be advertized as 0 */ - if (SH_MAX_W(win) > 0 && ce.width > SH_MAX_W(win)) - ce.width = SH_MAX_W(win); - if (SH_MAX_H(win) > 0 && ce.height > SH_MAX_H(win)) - ce.height = SH_MAX_H(win); - } - - /* resize increment. */ - if (SH_INC(win)) { - if (SH_INC_W(win) > 1 && ce.width > SH_INC_W(win)) - ce.width -= (ce.width - SH_MIN_W(win)) % - SH_INC_W(win); - if (SH_INC_H(win) > 1 && ce.height > SH_INC_H(win)) - ce.height -= (ce.height - SH_MIN_H(win)) % - SH_INC_H(win); - } - - /* adjust x and y for requested border_width. */ - ce.x += border_width - ev->border_width; - ce.y += border_width - ev->border_width; - ce.border_width = ev->border_width; - ce.above = ev->above; - } - - DNPRINTF(SWM_D_MISC, "config_win: ewmh: %s, window: 0x%lx, (x,y) w x h: " - "(%d,%d) %d x %d, border: %d\n", YESNO(ev == NULL), win->id, ce.x, - ce.y, ce.width, ce.height, ce.border_width); - - XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&ce); -} - -int -count_win(struct workspace *ws, int count_transient) -{ - struct ws_win *win; - int count = 0; - - TAILQ_FOREACH(win, &ws->winlist, entry) { - if (count_transient == 0 && win->floating) - continue; - if (count_transient == 0 && win->transient) - continue; - if (win->iconic) - continue; - count++; - } - DNPRINTF(SWM_D_MISC, "count_win: %d\n", count); - - return (count); -} - -void -quit(struct swm_region *r, union arg *args) -{ - DNPRINTF(SWM_D_MISC, "quit\n"); - running = 0; -} - -void -unmap_window(struct ws_win *win) -{ - if (win == NULL) - return; - - /* don't unmap again */ - if (getstate(win->id) == IconicState) - return; - - set_win_state(win, IconicState); - - XUnmapWindow(display, win->id); - XSetWindowBorder(display, win->id, - win->s->c[SWM_S_COLOR_UNFOCUS].color); -} - -void -unmap_all(void) -{ - struct ws_win *win; - int i, j; - - for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) - unmap_window(win); -} - -void -fake_keypress(struct ws_win *win, int keysym, int modifiers) -{ - XKeyEvent event; - - if (win == NULL) - return; - - event.display = display; /* Ignored, but what the hell */ - event.window = win->id; - event.root = win->s->root; - event.subwindow = None; - event.time = CurrentTime; - event.x = X(win); - event.y = Y(win); - event.x_root = 1; - event.y_root = 1; - event.same_screen = True; - event.keycode = XKeysymToKeycode(display, keysym); - event.state = modifiers; - - event.type = KeyPress; - XSendEvent(event.display, event.window, True, - KeyPressMask, (XEvent *)&event); - - event.type = KeyRelease; - XSendEvent(event.display, event.window, True, - KeyPressMask, (XEvent *)&event); - -} - -void -restart(struct swm_region *r, union arg *args) -{ - DNPRINTF(SWM_D_MISC, "restart: %s\n", start_argv[0]); - - /* disable alarm because the following code may not be interrupted */ - alarm(0); - if (signal(SIGALRM, SIG_IGN) == SIG_ERR) - err(1, "can't disable alarm"); - - bar_extra_stop(); - bar_extra = 1; - unmap_all(); - XCloseDisplay(display); - execvp(start_argv[0], start_argv); - warn("execvp failed"); - quit(NULL, NULL); -} - -struct swm_region * -root_to_region(Window root) -{ - struct swm_region *r = NULL; - Window rr, cr; - int i, x, y, wx, wy; - unsigned int mask; - - for (i = 0; i < ScreenCount(display); i++) - if (screens[i].root == root) - break; - - if (XQueryPointer(display, screens[i].root, - &rr, &cr, &x, &y, &wx, &wy, &mask) != False) { - /* choose a region based on pointer location */ - TAILQ_FOREACH(r, &screens[i].rl, entry) - if (x >= X(r) && x <= X(r) + WIDTH(r) && - y >= Y(r) && y <= Y(r) + HEIGHT(r)) - break; - } - - if (r == NULL) - r = TAILQ_FIRST(&screens[i].rl); - - return (r); -} - -struct ws_win * -find_unmanaged_window(Window id) -{ - struct ws_win *win; - int i, j; - - for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist, - entry) - if (id == win->id) - return (win); - return (NULL); -} - -struct ws_win * -find_window(Window id) -{ - struct ws_win *win; - Window wrr, wpr, *wcr = NULL; - int i, j; - unsigned int nc; - - for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) - if (id == win->id) - return (win); - - /* if we were looking for the parent return that window instead */ - if (XQueryTree(display, id, &wrr, &wpr, &wcr, &nc) == 0) - return (NULL); - if (wcr) - XFree(wcr); - - /* ignore not found and root */ - if (wpr == 0 || wrr == wpr) - return (NULL); - - /* look for parent */ - for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) - if (wpr == win->id) - return (win); - - return (NULL); -} - -void -spawn(int ws_idx, union arg *args, int close_fd) -{ - int fd; - char *ret = NULL; - - DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]); - - if (display) - close(ConnectionNumber(display)); - - setenv("LD_PRELOAD", SWM_LIB, 1); - - if (asprintf(&ret, "%d", ws_idx) == -1) { - warn("spawn: asprintf SWM_WS"); - _exit(1); - } - setenv("_SWM_WS", ret, 1); - free(ret); - ret = NULL; - - if (asprintf(&ret, "%d", getpid()) == -1) { - warn("spawn: asprintf _SWM_PID"); - _exit(1); - } - setenv("_SWM_PID", ret, 1); - free(ret); - ret = NULL; - - if (setsid() == -1) { - warn("spawn: setsid"); - _exit(1); - } - - if (close_fd) { - /* - * close stdin and stdout to prevent interaction between apps - * and the baraction script - * leave stderr open to record errors - */ - if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) { - warn("spawn: open"); - _exit(1); - } - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - if (fd > 2) - close(fd); - } - - execvp(args->argv[0], args->argv); - - warn("spawn: execvp"); - _exit(1); -} - -void -spawnterm(struct swm_region *r, union arg *args) -{ - DNPRINTF(SWM_D_MISC, "spawnterm\n"); - - if (fork() == 0) { - if (term_width) - setenv("_SWM_XTERM_FONTADJ", "", 1); - spawn(r->ws->idx, args, 1); - } -} - -void -kill_refs(struct ws_win *win) -{ - int i, x; - struct swm_region *r; - struct workspace *ws; - - if (win == NULL) - return; - - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) - for (x = 0; x < SWM_WS_MAX; x++) { - ws = &r->s->ws[x]; - if (win == ws->focus) - ws->focus = NULL; - if (win == ws->focus_prev) - ws->focus_prev = NULL; - } -} - -int -validate_win(struct ws_win *testwin) -{ - struct ws_win *win; - struct workspace *ws; - struct swm_region *r; - int i, x; - - if (testwin == NULL) - return (0); - - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) - for (x = 0; x < SWM_WS_MAX; x++) { - ws = &r->s->ws[x]; - TAILQ_FOREACH(win, &ws->winlist, entry) - if (win == testwin) - return (0); - } - return (1); -} - -int -validate_ws(struct workspace *testws) -{ - struct swm_region *r; - struct workspace *ws; - int i, x; - - /* validate all ws */ - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) - for (x = 0; x < SWM_WS_MAX; x++) { - ws = &r->s->ws[x]; - if (ws == testws) - return (0); - } - return (1); -} - -void -unfocus_win(struct ws_win *win) -{ - XEvent cne; - Window none = None; - - DNPRINTF(SWM_D_FOCUS, "unfocus_win: window: 0x%lx\n", WINID(win)); - - if (win == NULL) - return; - if (win->ws == NULL) - return; - - if (validate_ws(win->ws)) - return; /* XXX this gets hit with thunderbird, needs fixing */ - - if (win->ws->r == NULL) - return; - - if (validate_win(win)) { - kill_refs(win); - return; - } - - if (win->ws->focus == win) { - win->ws->focus = NULL; - win->ws->focus_prev = win; - } - - if (validate_win(win->ws->focus)) { - kill_refs(win->ws->focus); - win->ws->focus = NULL; - } - if (validate_win(win->ws->focus_prev)) { - kill_refs(win->ws->focus_prev); - win->ws->focus_prev = NULL; - } - - /* drain all previous unfocus events */ - while (XCheckTypedEvent(display, FocusOut, &cne) == True) - ; - - grabbuttons(win, 0); - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); - - XChangeProperty(display, win->s->root, - ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&none,1); -} - -void -unfocus_all(void) -{ - struct ws_win *win; - int i, j; - - DNPRINTF(SWM_D_FOCUS, "unfocus_all\n"); - - for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) - unfocus_win(win); -} - -void -focus_win(struct ws_win *win) -{ - XEvent cne; - Window cur_focus; - int rr; - struct ws_win *cfw = NULL; - - - DNPRINTF(SWM_D_FOCUS, "focus_win: window: 0x%lx\n", WINID(win)); - - if (win == NULL) - return; - if (win->ws == NULL) - return; - - if (validate_ws(win->ws)) - return; /* XXX this gets hit with thunderbird, needs fixing */ - - if (validate_win(win)) { - kill_refs(win); - return; - } - - if (validate_win(win)) { - kill_refs(win); - return; - } - - XGetInputFocus(display, &cur_focus, &rr); - if ((cfw = find_window(cur_focus)) != NULL) - unfocus_win(cfw); - else { - /* use larger hammer since the window was killed somehow */ - TAILQ_FOREACH(cfw, &win->ws->winlist, entry) - if (cfw->ws && cfw->ws->r && cfw->ws->r->s) - XSetWindowBorder(display, cfw->id, - cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); - } - - win->ws->focus = win; - - if (win->ws->r != NULL) { - /* drain all previous focus events */ - while (XCheckTypedEvent(display, FocusIn, &cne) == True) - ; - - if (win->java == 0) - XSetInputFocus(display, win->id, - RevertToParent, CurrentTime); - grabbuttons(win, 1); - XSetWindowBorder(display, win->id, - win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); - if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS || - win->ws->always_raise) - XMapRaised(display, win->id); - - XChangeProperty(display, win->s->root, - ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&win->id,1); - } - - bar_check_opts(); -} - -void -switchws(struct swm_region *r, union arg *args) -{ - int wsid = args->id, unmap_old = 0; - struct swm_region *this_r, *other_r; - struct ws_win *win; - struct workspace *new_ws, *old_ws; - union arg a; - - if (!(r && r->s)) - return; - - this_r = r; - old_ws = this_r->ws; - new_ws = &this_r->s->ws[wsid]; - - DNPRINTF(SWM_D_WS, "switchws: screen[%d]:%dx%d+%d+%d: %d -> %d\n", - r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), old_ws->idx, wsid); - - if (new_ws == NULL || old_ws == NULL) - return; - if (new_ws == old_ws) - return; - - other_r = new_ws->r; - if (other_r == NULL) { - /* the other workspace is hidden, hide this one */ - old_ws->r = NULL; - unmap_old = 1; - } else { - /* the other ws is visible in another region, exchange them */ - other_r->ws_prior = new_ws; - other_r->ws = old_ws; - old_ws->r = other_r; - } - this_r->ws_prior = old_ws; - this_r->ws = new_ws; - new_ws->r = this_r; - - /* this is needed so that we can click on a window after a restart */ - unfocus_all(); - - stack(); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(new_ws->r, &a); - - bar_update(); - - /* unmap old windows */ - if (unmap_old) - TAILQ_FOREACH(win, &old_ws->winlist, entry) - unmap_window(win); - - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); -} - -void -cyclews(struct swm_region *r, union arg *args) -{ - union arg a; - struct swm_screen *s = r->s; - int cycle_all = 0; - - DNPRINTF(SWM_D_WS, "cyclews: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", - args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); - - a.id = r->ws->idx; - do { - switch (args->id) { - case SWM_ARG_ID_CYCLEWS_UP_ALL: - cycle_all = 1; - /* FALLTHROUGH */ - case SWM_ARG_ID_CYCLEWS_UP: - if (a.id < SWM_WS_MAX - 1) - a.id++; - else - a.id = 0; - break; - case SWM_ARG_ID_CYCLEWS_DOWN_ALL: - cycle_all = 1; - /* FALLTHROUGH */ - case SWM_ARG_ID_CYCLEWS_DOWN: - if (a.id > 0) - a.id--; - else - a.id = SWM_WS_MAX - 1; - break; - default: - return; - }; - - if (!cycle_all && - (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist))) - continue; - if (cycle_visible == 0 && s->ws[a.id].r != NULL) - continue; - - switchws(r, &a); - } while (a.id != r->ws->idx); -} - -void -priorws(struct swm_region *r, union arg *args) -{ - union arg a; - - DNPRINTF(SWM_D_WS, "priorws: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", - args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); - - if (r->ws_prior == NULL) - return; - - a.id = r->ws_prior->idx; - switchws(r, &a); -} - -void -cyclescr(struct swm_region *r, union arg *args) -{ - struct swm_region *rr = NULL; - union arg a; - int i, x, y; - - /* do nothing if we don't have more than one screen */ - if (!(ScreenCount(display) > 1 || outputs > 1)) - return; - - i = r->s->idx; - switch (args->id) { - case SWM_ARG_ID_CYCLESC_UP: - rr = TAILQ_NEXT(r, entry); - if (rr == NULL) - rr = TAILQ_FIRST(&screens[i].rl); - break; - case SWM_ARG_ID_CYCLESC_DOWN: - rr = TAILQ_PREV(r, swm_region_list, entry); - if (rr == NULL) - rr = TAILQ_LAST(&screens[i].rl, swm_region_list); - break; - default: - return; - }; - if (rr == NULL) - return; - - /* move mouse to region */ - x = X(rr) + 1; - y = Y(rr) + 1 + (bar_enabled ? bar_height : 0); - XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y); - - a.id = SWM_ARG_ID_FOCUSCUR; - focus(rr, &a); - - if (rr->ws->focus) { - /* move to focus window */ - x = X(rr->ws->focus) + 1; - y = Y(rr->ws->focus) + 1; - XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y); - } -} - -void -sort_windows(struct ws_win_list *wl) -{ - struct ws_win *win, *parent, *nxt; - - if (wl == NULL) - return; - - for (win = TAILQ_FIRST(wl); win != TAILQ_END(wl); win = nxt) { - nxt = TAILQ_NEXT(win, entry); - if (win->transient) { - parent = find_window(win->transient); - if (parent == NULL) { - warnx("not possible bug"); - continue; - } - TAILQ_REMOVE(wl, win, entry); - TAILQ_INSERT_AFTER(wl, parent, win, entry); - } - } - -} - -void -swapwin(struct swm_region *r, union arg *args) -{ - struct ws_win *target, *source; - struct ws_win *cur_focus; - struct ws_win_list *wl; - - - DNPRINTF(SWM_D_WS, "swapwin: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", - args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); - - cur_focus = r->ws->focus; - if (cur_focus == NULL) - return; - - source = cur_focus; - wl = &source->ws->winlist; - - switch (args->id) { - case SWM_ARG_ID_SWAPPREV: - if (source->transient) - source = find_window(source->transient); - target = TAILQ_PREV(source, ws_win_list, entry); - if (target && target->transient) - target = find_window(target->transient); - TAILQ_REMOVE(wl, source, entry); - if (target == NULL) - TAILQ_INSERT_TAIL(wl, source, entry); - else - TAILQ_INSERT_BEFORE(target, source, entry); - break; - case SWM_ARG_ID_SWAPNEXT: - target = TAILQ_NEXT(source, entry); - /* move the parent and let the sort handle the move */ - if (source->transient) - source = find_window(source->transient); - TAILQ_REMOVE(wl, source, entry); - if (target == NULL) - TAILQ_INSERT_HEAD(wl, source, entry); - else - TAILQ_INSERT_AFTER(wl, target, source, entry); - break; - case SWM_ARG_ID_SWAPMAIN: - target = TAILQ_FIRST(wl); - if (target == source) { - if (source->ws->focus_prev != NULL && - source->ws->focus_prev != target) - - source = source->ws->focus_prev; - else - return; - } - if (target == NULL || source == NULL) - return; - source->ws->focus_prev = target; - TAILQ_REMOVE(wl, target, entry); - TAILQ_INSERT_BEFORE(source, target, entry); - TAILQ_REMOVE(wl, source, entry); - TAILQ_INSERT_HEAD(wl, source, entry); - break; - case SWM_ARG_ID_MOVELAST: - TAILQ_REMOVE(wl, source, entry); - TAILQ_INSERT_TAIL(wl, source, entry); - break; - default: - DNPRINTF(SWM_D_MOVE, "swapwin: invalid id: %d\n", args->id); - return; - } - - sort_windows(wl); - - stack(); -} - -void -focus_prev(struct ws_win *win) -{ - struct ws_win *winfocus = NULL; - struct ws_win *cur_focus = NULL; - struct ws_win_list *wl = NULL; - struct workspace *ws = NULL; - - DNPRINTF(SWM_D_FOCUS, "focus_prev: window: 0x%lx\n", WINID(win)); - - if (!(win && win->ws)) - return; - - ws = win->ws; - wl = &ws->winlist; - cur_focus = ws->focus; - - /* pickle, just focus on whatever */ - if (cur_focus == NULL) { - /* use prev_focus if valid */ - if (ws->focus_prev && ws->focus_prev != cur_focus && - find_window(WINID(ws->focus_prev))) - winfocus = ws->focus_prev; - if (winfocus == NULL) - winfocus = TAILQ_FIRST(wl); - goto done; - } - - /* if transient focus on parent */ - if (cur_focus->transient) { - winfocus = find_window(cur_focus->transient); - goto done; - } - - /* if in max_stack try harder */ - if ((win->quirks & SWM_Q_FOCUSPREV) || - (ws->cur_layout->flags & SWM_L_FOCUSPREV)) { - if (cur_focus != ws->focus_prev) - winfocus = ws->focus_prev; - else if (cur_focus != ws->focus) - winfocus = ws->focus; - else - winfocus = TAILQ_PREV(win, ws_win_list, entry); - if (winfocus) - goto done; - } - - if (cur_focus == win) - winfocus = TAILQ_PREV(win, ws_win_list, entry); - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, ws_win_list); - if (winfocus == NULL || winfocus == win) - winfocus = TAILQ_NEXT(cur_focus, entry); - -done: - focus_magic(winfocus); -} - -void -focus(struct swm_region *r, union arg *args) -{ - struct ws_win *winfocus = NULL, *head; - struct ws_win *cur_focus = NULL; - struct ws_win_list *wl = NULL; - struct workspace *ws = NULL; - int all_iconics; - - if (!(r && r->ws)) - return; - - DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id); - - /* treat FOCUS_CUR special */ - if (args->id == SWM_ARG_ID_FOCUSCUR) { - if (r->ws->focus && r->ws->focus->iconic == 0) - winfocus = r->ws->focus; - else if (r->ws->focus_prev && r->ws->focus_prev->iconic == 0) - winfocus = r->ws->focus_prev; - else - TAILQ_FOREACH(winfocus, &r->ws->winlist, entry) - if (winfocus->iconic == 0) - break; - - focus_magic(winfocus); - return; - } - - if ((cur_focus = r->ws->focus) == NULL) - return; - ws = r->ws; - wl = &ws->winlist; - if (TAILQ_EMPTY(wl)) - return; - /* make sure there is at least one uniconified window */ - all_iconics = 1; - TAILQ_FOREACH(winfocus, wl, entry) - if (winfocus->iconic == 0) { - all_iconics = 0; - break; - } - if (all_iconics) - return; - - switch (args->id) { - case SWM_ARG_ID_FOCUSPREV: - head = TAILQ_PREV(cur_focus, ws_win_list, entry); - if (head == NULL) - head = TAILQ_LAST(wl, ws_win_list); - winfocus = head; - if (WINID(winfocus) == cur_focus->transient) { - head = TAILQ_PREV(winfocus, ws_win_list, entry); - if (head == NULL) - head = TAILQ_LAST(wl, ws_win_list); - winfocus = head; - } - - /* skip iconics */ - if (winfocus && winfocus->iconic) { - while (winfocus != cur_focus) { - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, ws_win_list); - if (winfocus->iconic == 0) - break; - winfocus = TAILQ_PREV(winfocus, ws_win_list, - entry); - } - } - break; - - case SWM_ARG_ID_FOCUSNEXT: - head = TAILQ_NEXT(cur_focus, entry); - if (head == NULL) - head = TAILQ_FIRST(wl); - winfocus = head; - - /* skip iconics */ - if (winfocus && winfocus->iconic) { - while (winfocus != cur_focus) { - if (winfocus == NULL) - winfocus = TAILQ_FIRST(wl); - if (winfocus->iconic == 0) - break; - winfocus = TAILQ_NEXT(winfocus, entry); - } - } - break; - - case SWM_ARG_ID_FOCUSMAIN: - winfocus = TAILQ_FIRST(wl); - if (winfocus == cur_focus) - winfocus = cur_focus->ws->focus_prev; - break; - - default: - return; - } - - focus_magic(winfocus); -} - -void -cycle_layout(struct swm_region *r, union arg *args) -{ - struct workspace *ws = r->ws; - union arg a; - - DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx); - - ws->cur_layout++; - if (ws->cur_layout->l_stack == NULL) - ws->cur_layout = &layouts[0]; - - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - a.id = SWM_ARG_ID_FOCUSCUR; - focus(r, &a); - bar_update(); -} - -void -stack_config(struct swm_region *r, union arg *args) -{ - struct workspace *ws = r->ws; - - DNPRINTF(SWM_D_STACK, "stack_config: id: %d workspace: %d\n", - args->id, ws->idx); - - if (ws->cur_layout->l_config != NULL) - ws->cur_layout->l_config(ws, args->id); - - if (args->id != SWM_ARG_ID_STACKINIT) - stack(); - bar_update(); -} - -void -stack(void) { - struct swm_geometry g; - struct swm_region *r; - int i; -#ifdef SWM_DEBUG - int j; -#endif - - DNPRINTF(SWM_D_STACK, "stack: begin\n"); - - for (i = 0; i < ScreenCount(display); i++) { -#ifdef SWM_DEBUG - j = 0; -#endif - TAILQ_FOREACH(r, &screens[i].rl, entry) { - DNPRINTF(SWM_D_STACK, "stack: workspace: %d " - "(screen: %d, region: %d)\n", r->ws->idx, i, j++); - - /* start with screen geometry, adjust for bar */ - g = r->g; - g.w -= 2 * border_width; - g.h -= 2 * border_width; - if (bar_enabled) { - if (!bar_at_bottom) - g.y += bar_height; - g.h -= bar_height; - } - r->ws->cur_layout->l_stack(r->ws, &g); - r->ws->cur_layout->l_string(r->ws); - /* save r so we can track region changes */ - r->ws->old_r = r; - } - } - if (font_adjusted) - font_adjusted--; - - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - - DNPRINTF(SWM_D_STACK, "stack: end\n"); -} - -void -store_float_geom(struct ws_win *win, struct swm_region *r) -{ - /* retain window geom and region geom */ - win->g_float = win->g; - win->rg_float = r->g; - win->g_floatvalid = 1; -} - -void -stack_floater(struct ws_win *win, struct swm_region *r) -{ - unsigned int mask; - XWindowChanges wc; - - if (win == NULL) - return; - - bzero(&wc, sizeof wc); - mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight; - - /* - * to allow windows to change their size (e.g. mplayer fs) only retrieve - * geom on ws switches or return from max mode - */ - if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid - && !(win->ewmh_flags & EWMH_F_FULLSCREEN))) { - /* - * use stored g and rg to set relative position and size - * as in old region or before max stack mode - */ - X(win) = win->g_float.x - win->rg_float.x + X(r); - Y(win) = win->g_float.y - win->rg_float.y + Y(r); - WIDTH(win) = win->g_float.w; - HEIGHT(win) = win->g_float.h; - win->g_floatvalid = 0; - } - - win->floatmaxed = 0; - - if ((win->quirks & SWM_Q_FULLSCREEN) && (WIDTH(win) >= WIDTH(r)) && - (HEIGHT(win) >= HEIGHT(r))) - wc.border_width = 0; - else - wc.border_width = border_width; - if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) { - WIDTH(win) = (double)WIDTH(r) * dialog_ratio; - HEIGHT(win) = (double)HEIGHT(r) * dialog_ratio; - } - - if (!win->manual) { - /* - * floaters and transients are auto-centred unless moved - * or resized - */ - X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2 - wc.border_width; - Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2 - wc.border_width; - } - - /* win can be outside r if new r smaller than old r */ - /* Ensure top left corner inside r (move probs otherwise) */ - if (X(win) < X(r) - wc.border_width) - X(win) = X(r) - wc.border_width; - if (X(win) > X(r) + WIDTH(r) - 1) - X(win) = (WIDTH(win) > WIDTH(r)) ? X(r) : - (X(r) + WIDTH(r) - WIDTH(win) - 2 * wc.border_width); - if (Y(win) < Y(r) - wc.border_width) - Y(win) = Y(r) - wc.border_width; - if (Y(win) > Y(r) + HEIGHT(r) - 1) - Y(win) = (HEIGHT(win) > HEIGHT(r)) ? Y(r) : - (Y(r) + HEIGHT(r) - HEIGHT(win) - 2 * wc.border_width); - - wc.x = X(win); - wc.y = Y(win); - wc.width = WIDTH(win); - wc.height = HEIGHT(win); - - /* - * Retain floater and transient geometry for correct positioning - * when ws changes region - */ - if (!(win->ewmh_flags & EWMH_F_FULLSCREEN)) - store_float_geom(win, r); - - DNPRINTF(SWM_D_MISC, "stack_floater: window: %lu, (x,y) w x h: (%d,%d) " - "%d x %d\n", win->id, wc.x, wc.y, wc.width, wc.height); - - XConfigureWindow(display, win->id, mask, &wc); -} - -/* - * Send keystrokes to terminal to decrease/increase the font size as the - * window size changes. - */ -void -adjust_font(struct ws_win *win) -{ - if (!(win->quirks & SWM_Q_XTERM_FONTADJ) || - win->floating || win->transient) - return; - - if (win->sh.width_inc && win->last_inc != win->sh.width_inc && - WIDTH(win) / win->sh.width_inc < term_width && - win->font_steps < SWM_MAX_FONT_STEPS) { - win->font_size_boundary[win->font_steps] = - (win->sh.width_inc * term_width) + win->sh.base_width; - win->font_steps++; - font_adjusted++; - win->last_inc = win->sh.width_inc; - fake_keypress(win, XK_KP_Subtract, ShiftMask); - } else if (win->font_steps && win->last_inc != win->sh.width_inc && - WIDTH(win) > win->font_size_boundary[win->font_steps - 1]) { - win->font_steps--; - font_adjusted++; - win->last_inc = win->sh.width_inc; - fake_keypress(win, XK_KP_Add, ShiftMask); - } -} - -#define SWAPXY(g) do { \ - int tmp; \ - tmp = (g)->y; (g)->y = (g)->x; (g)->x = tmp; \ - tmp = (g)->h; (g)->h = (g)->w; (g)->w = tmp; \ -} while (0) -void -stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) -{ - XWindowChanges wc; - XWindowAttributes wa; - struct swm_geometry win_g, r_g = *g; - struct ws_win *win, *fs_win = 0; - int i, j, s, stacks; - int w_inc = 1, h_inc, w_base = 1, h_base; - int hrh, extra = 0, h_slice, last_h = 0; - int split, colno, winno, mwin, msize, mscale; - int remain, missing, v_slice, reconfigure; - unsigned int mask; - - DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, " - "flip: %s\n", ws->idx, YESNO(rot), YESNO(flip)); - - winno = count_win(ws, 0); - if (winno == 0 && count_win(ws, 1) == 0) - return; - - TAILQ_FOREACH(win, &ws->winlist, entry) - if (win->transient == 0 && win->floating == 0 - && win->iconic == 0) - break; - - if (win == NULL) - goto notiles; - - if (rot) { - w_inc = win->sh.width_inc; - w_base = win->sh.base_width; - mwin = ws->l_state.horizontal_mwin; - mscale = ws->l_state.horizontal_msize; - stacks = ws->l_state.horizontal_stacks; - SWAPXY(&r_g); - } else { - w_inc = win->sh.height_inc; - w_base = win->sh.base_height; - mwin = ws->l_state.vertical_mwin; - mscale = ws->l_state.vertical_msize; - stacks = ws->l_state.vertical_stacks; - } - win_g = r_g; - - if (stacks > winno - mwin) - stacks = winno - mwin; - if (stacks < 1) - stacks = 1; - - h_slice = r_g.h / SWM_H_SLICE; - if (mwin && winno > mwin) { - v_slice = r_g.w / SWM_V_SLICE; - - split = mwin; - colno = split; - win_g.w = v_slice * mscale; - - if (w_inc > 1 && w_inc < v_slice) { - /* adjust for window's requested size increment */ - remain = (win_g.w - w_base) % w_inc; - missing = w_inc - remain; - win_g.w -= remain; - extra += remain; - } - - msize = win_g.w; - if (flip) - win_g.x += r_g.w - msize; - } else { - msize = -2; - colno = split = winno / stacks; - win_g.w = ((r_g.w - (stacks * 2 * border_width) + - 2 * border_width) / stacks); - } - hrh = r_g.h / colno; - extra = r_g.h - (colno * hrh); - win_g.h = hrh - 2 * border_width; - - /* stack all the tiled windows */ - i = j = 0, s = stacks; - TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient != 0 || win->floating != 0) - continue; - if (win->iconic != 0) - continue; - - if (win->ewmh_flags & EWMH_F_FULLSCREEN) { - fs_win = win; - continue; - } - - if (split && i == split) { - colno = (winno - mwin) / stacks; - if (s <= (winno - mwin) % stacks) - colno++; - split = split + colno; - hrh = (r_g.h / colno); - extra = r_g.h - (colno * hrh); - if (flip) - win_g.x = r_g.x; - else - win_g.x += win_g.w + 2 * border_width; - win_g.w = (r_g.w - msize - - (stacks * 2 * border_width)) / stacks; - if (s == 1) - win_g.w += (r_g.w - msize - - (stacks * 2 * border_width)) % stacks; - s--; - j = 0; - } - win_g.h = hrh - 2 * border_width; - if (rot) { - h_inc = win->sh.width_inc; - h_base = win->sh.base_width; - } else { - h_inc = win->sh.height_inc; - h_base = win->sh.base_height; - } - if (j == colno - 1) { - win_g.h = hrh + extra; - } else if (h_inc > 1 && h_inc < h_slice) { - /* adjust for window's requested size increment */ - remain = (win_g.h - h_base) % h_inc; - missing = h_inc - remain; - - if (missing <= extra || j == 0) { - extra -= missing; - win_g.h += missing; - } else { - win_g.h -= remain; - extra += remain; - } - } - - if (j == 0) - win_g.y = r_g.y; - else - win_g.y += last_h + 2 * border_width; - - bzero(&wc, sizeof wc); - if (disable_border && bar_enabled == 0 && winno == 1){ - wc.border_width = 0; - win_g.w += 2 * border_width; - win_g.h += 2 * border_width; - } else - wc.border_width = border_width; - reconfigure = 0; - if (rot) { - if (X(win) != win_g.y || Y(win) != win_g.x || - WIDTH(win) != win_g.h || HEIGHT(win) != win_g.w) { - reconfigure = 1; - X(win) = wc.x = win_g.y; - Y(win) = wc.y = win_g.x; - WIDTH(win) = wc.width = win_g.h; - HEIGHT(win) = wc.height = win_g.w; - } - } else { - if (X(win) != win_g.x || Y(win) != win_g.y || - WIDTH(win) != win_g.w || HEIGHT(win) != win_g.h) { - reconfigure = 1; - X(win) = wc.x = win_g.x; - Y(win) = wc.y = win_g.y; - WIDTH(win) = wc.width = win_g.w; - HEIGHT(win) = wc.height = win_g.h; - } - } - if (reconfigure) { - adjust_font(win); - mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); - } - - if (XGetWindowAttributes(display, win->id, &wa)) - if (wa.map_state == IsUnmapped) - XMapRaised(display, win->id); - - last_h = win_g.h; - i++; - j++; - } - -notiles: - /* now, stack all the floaters and transients */ - TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient == 0 && win->floating == 0) - continue; - if (win->iconic == 1) - continue; - if (win->ewmh_flags & EWMH_F_FULLSCREEN) { - fs_win = win; - continue; - } - - stack_floater(win, ws->r); - XMapRaised(display, win->id); - } - - if (fs_win) { - stack_floater(fs_win, ws->r); - XMapRaised(display, fs_win->id); - } -} - -void -vertical_config(struct workspace *ws, int id) -{ - DNPRINTF(SWM_D_STACK, "vertical_config: id: %d, workspace: %d\n", - id, ws->idx); - - switch (id) { - case SWM_ARG_ID_STACKRESET: - case SWM_ARG_ID_STACKINIT: - ws->l_state.vertical_msize = SWM_V_SLICE / 2; - ws->l_state.vertical_mwin = 1; - ws->l_state.vertical_stacks = 1; - break; - case SWM_ARG_ID_MASTERSHRINK: - if (ws->l_state.vertical_msize > 1) - ws->l_state.vertical_msize--; - break; - case SWM_ARG_ID_MASTERGROW: - if (ws->l_state.vertical_msize < SWM_V_SLICE - 1) - ws->l_state.vertical_msize++; - break; - case SWM_ARG_ID_MASTERADD: - ws->l_state.vertical_mwin++; - break; - case SWM_ARG_ID_MASTERDEL: - if (ws->l_state.vertical_mwin > 0) - ws->l_state.vertical_mwin--; - break; - case SWM_ARG_ID_STACKINC: - ws->l_state.vertical_stacks++; - break; - case SWM_ARG_ID_STACKDEC: - if (ws->l_state.vertical_stacks > 1) - ws->l_state.vertical_stacks--; - break; - case SWM_ARG_ID_FLIPLAYOUT: - ws->l_state.vertical_flip = !ws->l_state.vertical_flip; - break; - default: - return; - } -} - -void -vertical_stack(struct workspace *ws, struct swm_geometry *g) -{ - DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); - - stack_master(ws, g, 0, ws->l_state.vertical_flip); -} - -void -horizontal_config(struct workspace *ws, int id) -{ - DNPRINTF(SWM_D_STACK, "horizontal_config: workspace: %d\n", ws->idx); - - switch (id) { - case SWM_ARG_ID_STACKRESET: - case SWM_ARG_ID_STACKINIT: - ws->l_state.horizontal_mwin = 1; - ws->l_state.horizontal_msize = SWM_H_SLICE / 2; - ws->l_state.horizontal_stacks = 1; - break; - case SWM_ARG_ID_MASTERSHRINK: - if (ws->l_state.horizontal_msize > 1) - ws->l_state.horizontal_msize--; - break; - case SWM_ARG_ID_MASTERGROW: - if (ws->l_state.horizontal_msize < SWM_H_SLICE - 1) - ws->l_state.horizontal_msize++; - break; - case SWM_ARG_ID_MASTERADD: - ws->l_state.horizontal_mwin++; - break; - case SWM_ARG_ID_MASTERDEL: - if (ws->l_state.horizontal_mwin > 0) - ws->l_state.horizontal_mwin--; - break; - case SWM_ARG_ID_STACKINC: - ws->l_state.horizontal_stacks++; - break; - case SWM_ARG_ID_STACKDEC: - if (ws->l_state.horizontal_stacks > 1) - ws->l_state.horizontal_stacks--; - break; - case SWM_ARG_ID_FLIPLAYOUT: - ws->l_state.horizontal_flip = !ws->l_state.horizontal_flip; - break; - default: - return; - } -} - -void -horizontal_stack(struct workspace *ws, struct swm_geometry *g) -{ - DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx); - - stack_master(ws, g, 1, ws->l_state.horizontal_flip); -} - -/* fullscreen view */ -void -max_stack(struct workspace *ws, struct swm_geometry *g) -{ - XWindowChanges wc; - struct swm_geometry gg = *g; - struct ws_win *win, *wintrans = NULL, *parent = NULL; - unsigned int mask; - int winno; - - DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx); - - if (ws == NULL) - return; - - winno = count_win(ws, 0); - if (winno == 0 && count_win(ws, 1) == 0) - return; - - TAILQ_FOREACH(win, &ws->winlist, entry) { - if (win->transient) { - wintrans = win; - parent = find_window(win->transient); - continue; - } - - if (win->floating && win->floatmaxed == 0 ) { - /* - * retain geometry for retrieval on exit from - * max_stack mode - */ - store_float_geom(win, ws->r); - win->floatmaxed = 1; - } - - /* only reconfigure if necessary */ - if (X(win) != gg.x || Y(win) != gg.y || WIDTH(win) != gg.w || - HEIGHT(win) != gg.h) { - bzero(&wc, sizeof wc); - X(win) = wc.x = gg.x; - Y(win) = wc.y = gg.y; - if (bar_enabled){ - wc.border_width = border_width; - WIDTH(win) = wc.width = gg.w; - HEIGHT(win) = wc.height = gg.h; - } else { - wc.border_width = 0; - WIDTH(win) = wc.width = gg.w + 2 * border_width; - HEIGHT(win) = wc.height = gg.h + - 2 * border_width; - } - mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); - } - /* unmap only if we don't have multi screen */ - if (win != ws->focus) - if (!(ScreenCount(display) > 1 || outputs > 1)) - unmap_window(win); - } - - /* put the last transient on top */ - if (wintrans) { - if (parent) - XMapRaised(display, parent->id); - stack_floater(wintrans, ws->r); - focus_magic(wintrans); - } -} - -void -send_to_ws(struct swm_region *r, union arg *args) -{ - int wsid = args->id; - struct ws_win *win = NULL, *parent; - struct workspace *ws, *nws; - Atom ws_idx_atom = 0; - unsigned char ws_idx_str[SWM_PROPLEN]; - union arg a; - - if (r && r->ws && r->ws->focus) - win = r->ws->focus; - else - return; - if (win == NULL) - return; - if (win->ws->idx == wsid) - return; - - DNPRINTF(SWM_D_MOVE, "send_to_ws: window: 0x%lx\n", win->id); - - ws = win->ws; - nws = &win->s->ws[wsid]; - - a.id = SWM_ARG_ID_FOCUSPREV; - focus(r, &a); - if (win->transient) { - parent = find_window(win->transient); - if (parent) { - unmap_window(parent); - TAILQ_REMOVE(&ws->winlist, parent, entry); - TAILQ_INSERT_TAIL(&nws->winlist, parent, entry); - parent->ws = nws; - } - } - unmap_window(win); - TAILQ_REMOVE(&ws->winlist, win, entry); - TAILQ_INSERT_TAIL(&nws->winlist, win, entry); - if (TAILQ_EMPTY(&ws->winlist)) - r->ws->focus = NULL; - win->ws = nws; - - /* Try to update the window's workspace property */ - ws_idx_atom = XInternAtom(display, "_SWM_WS", False); - if (ws_idx_atom && - snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < - SWM_PROPLEN) { - DNPRINTF(SWM_D_PROP, "send_to_ws: set property: _SWM_WS: %s\n", - ws_idx_str); - XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, - PropModeReplace, ws_idx_str, strlen((char *)ws_idx_str)); - } - - stack(); -} - -void -pressbutton(struct swm_region *r, union arg *args) -{ - XTestFakeButtonEvent(display, args->id, True, CurrentTime); - XTestFakeButtonEvent(display, args->id, False, CurrentTime); -} - -void -raise_toggle(struct swm_region *r, union arg *args) -{ - if (r && r->ws == NULL) - return; - - r->ws->always_raise = !r->ws->always_raise; - - /* bring floaters back to top */ - if (r->ws->always_raise == 0) - stack(); -} - -void -iconify(struct swm_region *r, union arg *args) -{ - union arg a; - - if (r->ws->focus == NULL) - return; - unmap_window(r->ws->focus); - update_iconic(r->ws->focus, 1); - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - r->ws->focus = NULL; - a.id = SWM_ARG_ID_FOCUSCUR; - focus(r, &a); -} - -unsigned char * -get_win_name(Window win) -{ - unsigned char *prop = NULL; - unsigned long nbytes, nitems; - - /* try _NET_WM_NAME first */ - if (get_property(win, a_netwmname, 0L, a_utf8_string, NULL, &nbytes, - &prop)) { - XFree(prop); - if (get_property(win, a_netwmname, nbytes, a_utf8_string, - &nitems, NULL, &prop)) - return (prop); - } - - /* fallback to WM_NAME */ - if (!get_property(win, a_wmname, 0L, a_string, NULL, &nbytes, &prop)) - return (NULL); - XFree(prop); - if (get_property(win, a_wmname, nbytes, a_string, &nitems, NULL, &prop)) - return (prop); - - return (NULL); -} - -void -uniconify(struct swm_region *r, union arg *args) -{ - struct ws_win *win; - FILE *lfile; - unsigned char *name; - int count = 0; - - DNPRINTF(SWM_D_MISC, "uniconify\n"); - - if (r && r->ws == NULL) - return; - - /* make sure we have anything to uniconify */ - TAILQ_FOREACH(win, &r->ws->winlist, entry) { - if (win->ws == NULL) - continue; /* should never happen */ - if (win->iconic == 0) - continue; - count++; - } - if (count == 0) - return; - - search_r = r; - search_resp_action = SWM_SEARCH_UNICONIFY; - - spawn_select(r, args, "search", &searchpid); - - if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) - return; - - TAILQ_FOREACH(win, &r->ws->winlist, entry) { - if (win->ws == NULL) - continue; /* should never happen */ - if (win->iconic == 0) - continue; - - name = get_win_name(win->id); - if (name == NULL) - continue; - fprintf(lfile, "%s.%lu\n", name, win->id); - XFree(name); - } - - fclose(lfile); -} - -void -name_workspace(struct swm_region *r, union arg *args) -{ - FILE *lfile; - - DNPRINTF(SWM_D_MISC, "name_workspace\n"); - - if (r == NULL) - return; - - search_r = r; - search_resp_action = SWM_SEARCH_NAME_WORKSPACE; - - spawn_select(r, args, "name_workspace", &searchpid); - - if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) - return; - - fprintf(lfile, "%s", ""); - fclose(lfile); -} - -void -search_workspace(struct swm_region *r, union arg *args) -{ - int i; - struct workspace *ws; - FILE *lfile; - - DNPRINTF(SWM_D_MISC, "search_workspace\n"); - - if (r == NULL) - return; - - search_r = r; - search_resp_action = SWM_SEARCH_SEARCH_WORKSPACE; - - spawn_select(r, args, "search", &searchpid); - - if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) - return; - - for (i = 0; i < SWM_WS_MAX; i++) { - ws = &r->s->ws[i]; - if (ws == NULL) - continue; - fprintf(lfile, "%d%s%s\n", ws->idx + 1, - (ws->name ? ":" : ""), (ws->name ? ws->name : "")); - } - - fclose(lfile); -} - -void -search_win_cleanup(void) -{ - struct search_window *sw = NULL; - - while ((sw = TAILQ_FIRST(&search_wl)) != NULL) { - XDestroyWindow(display, sw->indicator); - XFreeGC(display, sw->gc); - TAILQ_REMOVE(&search_wl, sw, entry); - free(sw); - } -} - -void -search_win(struct swm_region *r, union arg *args) -{ - struct ws_win *win = NULL; - struct search_window *sw = NULL; - Window w; - XGCValues gcv; - int i; - char s[8]; - FILE *lfile; - size_t len; - XRectangle ibox, lbox; - - DNPRINTF(SWM_D_MISC, "search_win\n"); - - search_r = r; - search_resp_action = SWM_SEARCH_SEARCH_WINDOW; - - spawn_select(r, args, "search", &searchpid); - - if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) - return; - - TAILQ_INIT(&search_wl); - - i = 1; - TAILQ_FOREACH(win, &r->ws->winlist, entry) { - if (win->iconic == 1) - continue; - - sw = calloc(1, sizeof(struct search_window)); - if (sw == NULL) { - warn("search_win: calloc"); - fclose(lfile); - search_win_cleanup(); - return; - } - sw->idx = i; - sw->win = win; - - snprintf(s, sizeof s, "%d", i); - len = strlen(s); - - XmbTextExtents(bar_fs, s, len, &ibox, &lbox); - - w = XCreateSimpleWindow(display, - win->id, 0, 0,lbox.width + 4, - bar_fs_extents->max_logical_extent.height, 1, - r->s->c[SWM_S_COLOR_UNFOCUS].color, - r->s->c[SWM_S_COLOR_FOCUS].color); - - sw->indicator = w; - TAILQ_INSERT_TAIL(&search_wl, sw, entry); - - sw->gc = XCreateGC(display, w, 0, &gcv); - XMapRaised(display, w); - XSetForeground(display, sw->gc, r->s->c[SWM_S_COLOR_BAR].color); - - DRAWSTRING(display, w, bar_fs, sw->gc, 2, - (bar_fs_extents->max_logical_extent.height - - lbox.height) / 2 - lbox.y, s, len); - - fprintf(lfile, "%d\n", i); - i++; - } - - fclose(lfile); -} - -void -search_resp_uniconify(char *resp, unsigned long len) -{ - unsigned char *name; - struct ws_win *win; - char *s; - - DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp: %s\n", resp); - - TAILQ_FOREACH(win, &search_r->ws->winlist, entry) { - if (win->iconic == 0) - continue; - name = get_win_name(win->id); - if (name == NULL) - continue; - if (asprintf(&s, "%s.%lu", name, win->id) == -1) { - XFree(name); - continue; - } - XFree(name); - if (strncmp(s, resp, len) == 0) { - /* XXX this should be a callback to generalize */ - update_iconic(win, 0); - free(s); - break; - } - free(s); - } -} - -void -search_resp_name_workspace(char *resp, unsigned long len) -{ - struct workspace *ws; - - DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: resp: %s\n", resp); - - if (search_r->ws == NULL) - return; - ws = search_r->ws; - - if (ws->name) { - free(search_r->ws->name); - search_r->ws->name = NULL; - } - - if (len > 1) { - ws->name = strdup(resp); - if (ws->name == NULL) { - DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: " - "strdup: %s", strerror(errno)); - return; - } - } -} - -void -search_resp_search_workspace(char *resp, unsigned long len) -{ - char *p, *q; - int ws_idx; - const char *errstr; - union arg a; - - DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: resp: %s\n", resp); - - q = strdup(resp); - if (!q) { - DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: strdup: %s", - strerror(errno)); - return; - } - p = strchr(q, ':'); - if (p != NULL) - *p = '\0'; - ws_idx = strtonum(q, 1, SWM_WS_MAX, &errstr); - if (errstr) { - DNPRINTF(SWM_D_MISC, "workspace idx is %s: %s", - errstr, q); - free(q); - return; - } - free(q); - a.id = ws_idx - 1; - switchws(search_r, &a); -} - -void -search_resp_search_window(char *resp, unsigned long len) -{ - char *s; - int idx; - const char *errstr; - struct search_window *sw; - - DNPRINTF(SWM_D_MISC, "search_resp_search_window: resp: %s\n", resp); - - s = strdup(resp); - if (!s) { - DNPRINTF(SWM_D_MISC, "search_resp_search_window: strdup: %s", - strerror(errno)); - return; - } - - idx = strtonum(s, 1, INT_MAX, &errstr); - if (errstr) { - DNPRINTF(SWM_D_MISC, "window idx is %s: %s", - errstr, s); - free(s); - return; - } - free(s); - - TAILQ_FOREACH(sw, &search_wl, entry) - if (idx == sw->idx) { - focus_win(sw->win); - break; - } -} - -#define MAX_RESP_LEN 1024 - -void -search_do_resp(void) -{ - ssize_t rbytes; - char *resp; - unsigned long len; - - DNPRINTF(SWM_D_MISC, "search_do_resp:\n"); - - search_resp = 0; - searchpid = 0; - - if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) { - warn("search: calloc"); - goto done; - } - - rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN); - if (rbytes <= 0) { - warn("search: read error"); - goto done; - } - resp[rbytes] = '\0'; - - /* XXX: - * Older versions of dmenu (Atleast pre 4.4.1) do not send a - * newline, so work around that by sanitizing the resp now. - */ - resp[strcspn(resp, "\n")] = '\0'; - len = strlen(resp); - - switch (search_resp_action) { - case SWM_SEARCH_UNICONIFY: - search_resp_uniconify(resp, len); - break; - case SWM_SEARCH_NAME_WORKSPACE: - search_resp_name_workspace(resp, len); - break; - case SWM_SEARCH_SEARCH_WORKSPACE: - search_resp_search_workspace(resp, len); - break; - case SWM_SEARCH_SEARCH_WINDOW: - search_resp_search_window(resp, len); - break; - } - -done: - if (search_resp_action == SWM_SEARCH_SEARCH_WINDOW) - search_win_cleanup(); - - search_resp_action = SWM_SEARCH_NONE; - close(select_resp_pipe[0]); - free(resp); -} - -void -wkill(struct swm_region *r, union arg *args) -{ - DNPRINTF(SWM_D_MISC, "wkill: id: %d\n", args->id); - - if (r->ws->focus == NULL) - return; - - if (args->id == SWM_ARG_ID_KILLWINDOW) - XKillClient(display, r->ws->focus->id); - else - if (r->ws->focus->can_delete) - client_msg(r->ws->focus, adelete); -} - - -int -floating_toggle_win(struct ws_win *win) -{ - struct swm_region *r; - - if (win == NULL) - return 0; - - if (!win->ws->r) - return 0; - - r = win->ws->r; - - /* reject floating toggles in max stack mode */ - if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) - return 0; - - if (win->floating) { - if (!win->floatmaxed) { - /* retain position for refloat */ - store_float_geom(win, r); - } - win->floating = 0; - } else { - if (win->g_floatvalid) { - /* refloat at last floating relative position */ - X(win) = win->g_float.x - win->rg_float.x + X(r); - Y(win) = win->g_float.y - win->rg_float.y + Y(r); - WIDTH(win) = win->g_float.w; - HEIGHT(win) = win->g_float.h; - } - win->floating = 1; - } - - ewmh_update_actions(win); - - return 1; -} - -void -floating_toggle(struct swm_region *r, union arg *args) -{ - struct ws_win *win = r->ws->focus; - union arg a; - - if (win == NULL) - return; - - ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, - _NET_WM_STATE_TOGGLE); - - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - - if (win == win->ws->focus) { - a.id = SWM_ARG_ID_FOCUSCUR; - focus(win->ws->r, &a); - } -} - -void -constrain_window(struct ws_win *win, struct swm_region *r, int resizable) -{ - if (X(win) + WIDTH(win) > X(r) + WIDTH(r) - border_width) { - if (resizable) - WIDTH(win) = X(r) + WIDTH(r) - X(win) - border_width; - else - X(win) = X(r) + WIDTH(r) - WIDTH(win) - border_width; - } - - if (X(win) < X(r) - border_width) { - if (resizable) - WIDTH(win) -= X(r) - X(win) - border_width; - - X(win) = X(r) - border_width; - } - - if (Y(win) + HEIGHT(win) > Y(r) + HEIGHT(r) - border_width) { - if (resizable) - HEIGHT(win) = Y(r) + HEIGHT(r) - Y(win) - border_width; - else - Y(win) = Y(r) + HEIGHT(r) - HEIGHT(win) - border_width; - } - - if (Y(win) < Y(r) - border_width) { - if (resizable) - HEIGHT(win) -= Y(r) - Y(win) - border_width; - - Y(win) = Y(r) - border_width; - } - - if (WIDTH(win) < 1) - WIDTH(win) = 1; - if (HEIGHT(win) < 1) - HEIGHT(win) = 1; -} - -void -update_window(struct ws_win *win) -{ - unsigned int mask; - XWindowChanges wc; - - bzero(&wc, sizeof wc); - mask = CWBorderWidth | CWWidth | CWHeight | CWX | CWY; - wc.border_width = border_width; - wc.x = X(win); - wc.y = Y(win); - wc.width = WIDTH(win); - wc.height = HEIGHT(win); - - DNPRINTF(SWM_D_MISC, "update_window: window: 0x%lx, (x,y) w x h: " - "(%d,%d) %d x %d\n", win->id, wc.x, wc.y, wc.width, wc.height); - - XConfigureWindow(display, win->id, mask, &wc); -} - -#define SWM_RESIZE_STEPS (50) - -void -resize(struct ws_win *win, union arg *args) -{ - XEvent ev; - Time time = 0; - struct swm_region *r = NULL; - int resize_step = 0; - Window rr, cr; - int x, y, wx, wy; - unsigned int mask; - struct swm_geometry g; - int top = 0, left = 0; - int dx, dy; - Cursor cursor; - unsigned int shape; /* cursor style */ - - if (win == NULL) - return; - r = win->ws->r; - - DNPRINTF(SWM_D_MOUSE, "resize: window: 0x%lx, floating: %s, " - "transient: 0x%lx\n", win->id, YESNO(win->floating), - win->transient); - - if (!(win->transient != 0 || win->floating != 0)) - return; - - /* reject resizes in max mode for floaters (transient ok) */ - if (win->floatmaxed) - return; - - win->manual = 1; - ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom, - _NET_WM_STATE_ADD); - - stack(); - - switch (args->id) { - case SWM_ARG_ID_WIDTHSHRINK: - WIDTH(win) -= SWM_RESIZE_STEPS; - resize_step = 1; - break; - case SWM_ARG_ID_WIDTHGROW: - WIDTH(win) += SWM_RESIZE_STEPS; - resize_step = 1; - break; - case SWM_ARG_ID_HEIGHTSHRINK: - HEIGHT(win) -= SWM_RESIZE_STEPS; - resize_step = 1; - break; - case SWM_ARG_ID_HEIGHTGROW: - HEIGHT(win) += SWM_RESIZE_STEPS; - resize_step = 1; - break; - default: - break; - } - if (resize_step) { - constrain_window(win, r, 1); - update_window(win); - store_float_geom(win,r); - return; - } - - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - - /* get cursor offset from window root */ - if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) - return; - - g = win->g; - - if (wx < WIDTH(win) / 2) - left = 1; - - if (wy < HEIGHT(win) / 2) - top = 1; - - if (args->id == SWM_ARG_ID_CENTER) - shape = XC_sizing; - else if (top) - shape = (left) ? XC_top_left_corner : XC_top_right_corner; - else - shape = (left) ? XC_bottom_left_corner : XC_bottom_right_corner; - - cursor = XCreateFontCursor(display, shape); - - if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, - GrabModeAsync, None, cursor, CurrentTime) != GrabSuccess) { - XFreeCursor(display, cursor); - return; - } - - do { - XMaskEvent(display, MOUSEMASK | ExposureMask | - SubstructureRedirectMask, &ev); - switch (ev.type) { - case ConfigureRequest: - case Expose: - case MapRequest: - handler[ev.type](&ev); - break; - case MotionNotify: - /* cursor offset/delta from start of the operation */ - dx = ev.xmotion.x_root - x; - dy = ev.xmotion.y_root - y; - - /* vertical */ - if (top) - dy = -dy; - - if (args->id == SWM_ARG_ID_CENTER) { - if (g.h / 2 + dy < 1) - dy = 1 - g.h / 2; - - Y(win) = g.y - dy; - HEIGHT(win) = g.h + 2 * dy; - } else { - if (g.h + dy < 1) - dy = 1 - g.h; - - if (top) - Y(win) = g.y - dy; - - HEIGHT(win) = g.h + dy; - } - - /* horizontal */ - if (left) - dx = -dx; - - if (args->id == SWM_ARG_ID_CENTER) { - if (g.w / 2 + dx < 1) - dx = 1 - g.w / 2; - - X(win) = g.x - dx; - WIDTH(win) = g.w + 2 * dx; - } else { - if (g.w + dx < 1) - dx = 1 - g.w; - - if (left) - X(win) = g.x - dx; - - WIDTH(win) = g.w + dx; - } - - constrain_window(win, r, 1); - - /* not free, don't sync more than 120 times / second */ - if ((ev.xmotion.time - time) > (1000 / 120) ) { - time = ev.xmotion.time; - XSync(display, False); - update_window(win); - } - break; - } - } while (ev.type != ButtonRelease); - if (time) { - XSync(display, False); - update_window(win); - } - store_float_geom(win,r); - - XUngrabPointer(display, CurrentTime); - XFreeCursor(display, cursor); - - /* drain events */ - drain_enter_notify(); -} - -void -resize_step(struct swm_region *r, union arg *args) -{ - struct ws_win *win = NULL; - - if (r && r->ws && r->ws->focus) - win = r->ws->focus; - else - return; - - resize(win, args); -} - -#define SWM_MOVE_STEPS (50) - -void -move(struct ws_win *win, union arg *args) -{ - XEvent ev; - Time time = 0; - int move_step = 0; - struct swm_region *r = NULL; - - Window rr, cr; - int x, y, wx, wy; - unsigned int mask; - - if (win == NULL) - return; - r = win->ws->r; - - DNPRINTF(SWM_D_MOUSE, "move: window: 0x%lx, floating: %s, transient: " - "0x%lx\n", win->id, YESNO(win->floating), win->transient); - - /* in max_stack mode should only move transients */ - if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !win->transient) - return; - - win->manual = 1; - if (win->floating == 0 && !win->transient) { - store_float_geom(win,r); - ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, - _NET_WM_STATE_ADD); - } - ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom, - _NET_WM_STATE_ADD); - - stack(); - - move_step = 0; - switch (args->id) { - case SWM_ARG_ID_MOVELEFT: - X(win) -= (SWM_MOVE_STEPS - border_width); - move_step = 1; - break; - case SWM_ARG_ID_MOVERIGHT: - X(win) += (SWM_MOVE_STEPS - border_width); - move_step = 1; - break; - case SWM_ARG_ID_MOVEUP: - Y(win) -= (SWM_MOVE_STEPS - border_width); - move_step = 1; - break; - case SWM_ARG_ID_MOVEDOWN: - Y(win) += (SWM_MOVE_STEPS - border_width); - move_step = 1; - break; - default: - break; - } - if (move_step) { - constrain_window(win, r, 0); - update_window(win); - store_float_geom(win, r); - return; - } - - if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, - GrabModeAsync, None, XCreateFontCursor(display, XC_fleur), - CurrentTime) != GrabSuccess) - return; - - /* get cursor offset from window root */ - if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) - return; - - do { - XMaskEvent(display, MOUSEMASK | ExposureMask | - SubstructureRedirectMask, &ev); - switch (ev.type) { - case ConfigureRequest: - case Expose: - case MapRequest: - handler[ev.type](&ev); - break; - case MotionNotify: - X(win) = ev.xmotion.x_root - wx - border_width; - Y(win) = ev.xmotion.y_root - wy - border_width; - - constrain_window(win, r, 0); - - /* not free, don't sync more than 120 times / second */ - if ((ev.xmotion.time - time) > (1000 / 120) ) { - time = ev.xmotion.time; - XSync(display, False); - update_window(win); - } - break; - } - } while (ev.type != ButtonRelease); - if (time) { - XSync(display, False); - update_window(win); - } - store_float_geom(win,r); - XUngrabPointer(display, CurrentTime); - - /* drain events */ - drain_enter_notify(); -} - -void -move_step(struct swm_region *r, union arg *args) -{ - struct ws_win *win = NULL; - - if (r && r->ws && r->ws->focus) - win = r->ws->focus; - else - return; - - if (!(win->transient != 0 || win->floating != 0)) - return; - - move(win, args); -} - - -/* user/key callable function IDs */ -enum keyfuncid { - kf_cycle_layout, - kf_flip_layout, - kf_stack_reset, - kf_master_shrink, - kf_master_grow, - kf_master_add, - kf_master_del, - kf_stack_inc, - kf_stack_dec, - kf_swap_main, - kf_focus_next, - kf_focus_prev, - kf_swap_next, - kf_swap_prev, - kf_spawn_term, - kf_spawn_menu, - kf_quit, - kf_restart, - kf_focus_main, - kf_ws_1, - kf_ws_2, - kf_ws_3, - kf_ws_4, - kf_ws_5, - kf_ws_6, - kf_ws_7, - kf_ws_8, - kf_ws_9, - kf_ws_10, - kf_ws_next, - kf_ws_prev, - kf_ws_next_all, - kf_ws_prev_all, - kf_ws_prior, - kf_screen_next, - kf_screen_prev, - kf_mvws_1, - kf_mvws_2, - kf_mvws_3, - kf_mvws_4, - kf_mvws_5, - kf_mvws_6, - kf_mvws_7, - kf_mvws_8, - kf_mvws_9, - kf_mvws_10, - kf_bar_toggle, - kf_wind_kill, - kf_wind_del, - kf_screenshot_all, - kf_screenshot_wind, - kf_float_toggle, - kf_version, - kf_spawn_lock, - kf_spawn_initscr, - kf_spawn_custom, - kf_iconify, - kf_uniconify, - kf_raise_toggle, - kf_button2, - kf_width_shrink, - kf_width_grow, - kf_height_shrink, - kf_height_grow, - kf_move_left, - kf_move_right, - kf_move_up, - kf_move_down, - kf_name_workspace, - kf_search_workspace, - kf_search_win, - kf_dumpwins, /* MUST BE LAST */ - kf_invalid -}; - -/* key definitions */ -void -dummykeyfunc(struct swm_region *r, union arg *args) -{ -}; - -void -legacyfunc(struct swm_region *r, union arg *args) -{ -}; - -struct keyfunc { - char name[SWM_FUNCNAME_LEN]; - void (*func)(struct swm_region *r, union arg *); - union arg args; -} keyfuncs[kf_invalid + 1] = { - /* name function argument */ - { "cycle_layout", cycle_layout, {0} }, - { "flip_layout", stack_config, {.id = SWM_ARG_ID_FLIPLAYOUT} }, - { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, - { "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, - { "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, - { "master_add", stack_config, {.id = SWM_ARG_ID_MASTERADD} }, - { "master_del", stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, - { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, - { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, - { "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, - { "focus_next", focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, - { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} }, - { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, - { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, - { "spawn_term", spawnterm, {.argv = spawn_term} }, - { "spawn_menu", legacyfunc, {0} }, - { "quit", quit, {0} }, - { "restart", restart, {0} }, - { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, - { "ws_1", switchws, {.id = 0} }, - { "ws_2", switchws, {.id = 1} }, - { "ws_3", switchws, {.id = 2} }, - { "ws_4", switchws, {.id = 3} }, - { "ws_5", switchws, {.id = 4} }, - { "ws_6", switchws, {.id = 5} }, - { "ws_7", switchws, {.id = 6} }, - { "ws_8", switchws, {.id = 7} }, - { "ws_9", switchws, {.id = 8} }, - { "ws_10", switchws, {.id = 9} }, - { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, - { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, - { "ws_next_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP_ALL} }, - { "ws_prev_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN_ALL} }, - { "ws_prior", priorws, {0} }, - { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, - { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, - { "mvws_1", send_to_ws, {.id = 0} }, - { "mvws_2", send_to_ws, {.id = 1} }, - { "mvws_3", send_to_ws, {.id = 2} }, - { "mvws_4", send_to_ws, {.id = 3} }, - { "mvws_5", send_to_ws, {.id = 4} }, - { "mvws_6", send_to_ws, {.id = 5} }, - { "mvws_7", send_to_ws, {.id = 6} }, - { "mvws_8", send_to_ws, {.id = 7} }, - { "mvws_9", send_to_ws, {.id = 8} }, - { "mvws_10", send_to_ws, {.id = 9} }, - { "bar_toggle", bar_toggle, {0} }, - { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, - { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, - { "screenshot_all", legacyfunc, {0} }, - { "screenshot_wind", legacyfunc, {0} }, - { "float_toggle", floating_toggle,{0} }, - { "version", version, {0} }, - { "spawn_lock", legacyfunc, {0} }, - { "spawn_initscr", legacyfunc, {0} }, - { "spawn_custom", dummykeyfunc, {0} }, - { "iconify", iconify, {0} }, - { "uniconify", uniconify, {0} }, - { "raise_toggle", raise_toggle, {0} }, - { "button2", pressbutton, {2} }, - { "width_shrink", resize_step, {.id = SWM_ARG_ID_WIDTHSHRINK} }, - { "width_grow", resize_step, {.id = SWM_ARG_ID_WIDTHGROW} }, - { "height_shrink", resize_step, {.id = SWM_ARG_ID_HEIGHTSHRINK} }, - { "height_grow", resize_step, {.id = SWM_ARG_ID_HEIGHTGROW} }, - { "move_left", move_step, {.id = SWM_ARG_ID_MOVELEFT} }, - { "move_right", move_step, {.id = SWM_ARG_ID_MOVERIGHT} }, - { "move_up", move_step, {.id = SWM_ARG_ID_MOVEUP} }, - { "move_down", move_step, {.id = SWM_ARG_ID_MOVEDOWN} }, - { "name_workspace", name_workspace, {0} }, - { "search_workspace", search_workspace, {0} }, - { "search_win", search_win, {0} }, - { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */ - { "invalid key func", NULL, {0} }, -}; -struct key { - RB_ENTRY(key) entry; - unsigned int mod; - KeySym keysym; - enum keyfuncid funcid; - char *spawn_name; -}; -RB_HEAD(key_list, key); - -int -key_cmp(struct key *kp1, struct key *kp2) -{ - if (kp1->keysym < kp2->keysym) - return (-1); - if (kp1->keysym > kp2->keysym) - return (1); - - if (kp1->mod < kp2->mod) - return (-1); - if (kp1->mod > kp2->mod) - return (1); - - return (0); -} - -RB_GENERATE_STATIC(key_list, key, entry, key_cmp); -struct key_list keys; - -/* mouse */ -enum { client_click, root_click }; -struct button { - unsigned int action; - unsigned int mask; - unsigned int button; - void (*func)(struct ws_win *, union arg *); - union arg args; -} buttons[] = { - /* action key mouse button func args */ - { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} }, - { client_click, MODKEY | ShiftMask, Button3, resize, {.id = SWM_ARG_ID_CENTER} }, - { client_click, MODKEY, Button1, move, {0} }, -}; - -void -update_modkey(unsigned int mod) -{ - int i; - struct key *kp; - - mod_key = mod; - RB_FOREACH(kp, key_list, &keys) - if (kp->mod & ShiftMask) - kp->mod = mod | ShiftMask; - else - kp->mod = mod; - - for (i = 0; i < LENGTH(buttons); i++) - if (buttons[i].mask & ShiftMask) - buttons[i].mask = mod | ShiftMask; - else - buttons[i].mask = mod; -} - -/* spawn */ -struct spawn_prog { - TAILQ_ENTRY(spawn_prog) entry; - char *name; - int argc; - char **argv; -}; -TAILQ_HEAD(spawn_list, spawn_prog); -struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns); - -int -spawn_expand(struct swm_region *r, union arg *args, char *spawn_name, - char ***ret_args) -{ - struct spawn_prog *prog = NULL; - int i; - char *ap, **real_args; - - DNPRINTF(SWM_D_SPAWN, "spawn_expand: %s\n", spawn_name); - - /* find program */ - TAILQ_FOREACH(prog, &spawns, entry) { - if (!strcasecmp(spawn_name, prog->name)) - break; - } - if (prog == NULL) { - warnx("spawn_custom: program %s not found", spawn_name); - return (-1); - } - - /* make room for expanded args */ - if ((real_args = calloc(prog->argc + 1, sizeof(char *))) == NULL) - err(1, "spawn_custom: calloc real_args"); - - /* expand spawn_args into real_args */ - for (i = 0; i < prog->argc; i++) { - ap = prog->argv[i]; - DNPRINTF(SWM_D_SPAWN, "spawn_custom: raw arg: %s\n", ap); - if (!strcasecmp(ap, "$bar_border")) { - if ((real_args[i] = - strdup(r->s->c[SWM_S_COLOR_BAR_BORDER].name)) - == NULL) - err(1, "spawn_custom border color"); - } else if (!strcasecmp(ap, "$bar_color")) { - if ((real_args[i] = - strdup(r->s->c[SWM_S_COLOR_BAR].name)) - == NULL) - err(1, "spawn_custom bar color"); - } else if (!strcasecmp(ap, "$bar_font")) { - if ((real_args[i] = strdup(bar_fonts)) - == NULL) - err(1, "spawn_custom bar fonts"); - } else if (!strcasecmp(ap, "$bar_font_color")) { - if ((real_args[i] = - strdup(r->s->c[SWM_S_COLOR_BAR_FONT].name)) - == NULL) - err(1, "spawn_custom color font"); - } else if (!strcasecmp(ap, "$color_focus")) { - if ((real_args[i] = - strdup(r->s->c[SWM_S_COLOR_FOCUS].name)) - == NULL) - err(1, "spawn_custom color focus"); - } else if (!strcasecmp(ap, "$color_unfocus")) { - if ((real_args[i] = - strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name)) - == NULL) - err(1, "spawn_custom color unfocus"); - } else { - /* no match --> copy as is */ - if ((real_args[i] = strdup(ap)) == NULL) - err(1, "spawn_custom strdup(ap)"); - } - DNPRINTF(SWM_D_SPAWN, "spawn_custom: cooked arg: %s\n", - real_args[i]); - } - -#ifdef SWM_DEBUG - DNPRINTF(SWM_D_SPAWN, "spawn_custom: result: "); - for (i = 0; i < prog->argc; i++) - DNPRINTF(SWM_D_SPAWN, "\"%s\" ", real_args[i]); - DNPRINTF(SWM_D_SPAWN, "\n"); -#endif - *ret_args = real_args; - return (prog->argc); -} - -void -spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) -{ - union arg a; - char **real_args; - int spawn_argc, i; - - if ((spawn_argc = spawn_expand(r, args, spawn_name, &real_args)) < 0) - return; - a.argv = real_args; - if (fork() == 0) - spawn(r->ws->idx, &a, 1); - - for (i = 0; i < spawn_argc; i++) - free(real_args[i]); - free(real_args); -} - -void -spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid) -{ - union arg a; - char **real_args; - int i, spawn_argc; - - if ((spawn_argc = spawn_expand(r, args, spawn_name, &real_args)) < 0) - return; - a.argv = real_args; - - if (pipe(select_list_pipe) == -1) - err(1, "pipe error"); - if (pipe(select_resp_pipe) == -1) - err(1, "pipe error"); - - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - err(1, "could not disable SIGPIPE"); - switch (*pid = fork()) { - case -1: - err(1, "cannot fork"); - break; - case 0: /* child */ - if (dup2(select_list_pipe[0], 0) == -1) - err(1, "dup2"); - if (dup2(select_resp_pipe[1], 1) == -1) - err(1, "dup2"); - close(select_list_pipe[1]); - close(select_resp_pipe[0]); - spawn(r->ws->idx, &a, 0); - break; - default: /* parent */ - close(select_list_pipe[0]); - close(select_resp_pipe[1]); - break; - } - - for (i = 0; i < spawn_argc; i++) - free(real_args[i]); - free(real_args); -} - -void -spawn_insert(char *name, char *args) -{ - char *arg, *cp, *ptr; - struct spawn_prog *sp; - - DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s\n", name); - - if ((sp = calloc(1, sizeof *sp)) == NULL) - err(1, "spawn_insert: malloc"); - if ((sp->name = strdup(name)) == NULL) - err(1, "spawn_insert: strdup"); - - /* convert the arguments to an argument list */ - if ((ptr = cp = strdup(args)) == NULL) - err(1, "spawn_insert: strdup"); - while ((arg = strsep(&ptr, " \t")) != NULL) { - /* empty field; skip it */ - if (*arg == '\0') - continue; - - sp->argc++; - if ((sp->argv = realloc(sp->argv, sp->argc * - sizeof *sp->argv)) == NULL) - err(1, "spawn_insert: realloc"); - if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL) - err(1, "spawn_insert: strdup"); - } - free(cp); - - TAILQ_INSERT_TAIL(&spawns, sp, entry); - DNPRINTF(SWM_D_SPAWN, "spawn_insert: leave\n"); -} - -void -spawn_remove(struct spawn_prog *sp) -{ - int i; - - DNPRINTF(SWM_D_SPAWN, "spawn_remove: %s\n", sp->name); - - TAILQ_REMOVE(&spawns, sp, entry); - for (i = 0; i < sp->argc; i++) - free(sp->argv[i]); - free(sp->argv); - free(sp->name); - free(sp); - - DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); -} - -void -spawn_replace(struct spawn_prog *sp, char *name, char *args) -{ - DNPRINTF(SWM_D_SPAWN, "spawn_replace: %s [%s]\n", sp->name, name); - - spawn_remove(sp); - spawn_insert(name, args); - - DNPRINTF(SWM_D_SPAWN, "spawn_replace: leave\n"); -} - -void -setspawn(char *name, char *args) -{ - struct spawn_prog *sp; - - DNPRINTF(SWM_D_SPAWN, "setspawn: %s\n", name); - - if (name == NULL) - return; - - TAILQ_FOREACH(sp, &spawns, entry) { - if (!strcmp(sp->name, name)) { - if (*args == '\0') - spawn_remove(sp); - else - spawn_replace(sp, name, args); - DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); - return; - } - } - if (*args == '\0') { - warnx("error: setspawn: cannot find program: %s", name); - return; - } - - spawn_insert(name, args); - DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); -} - -int -setconfspawn(char *selector, char *value, int flags) -{ - DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, value); - - setspawn(selector, value); - - DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n"); - return (0); -} - -void -setup_spawn(void) -{ - setconfspawn("term", "xterm", 0); - setconfspawn("screenshot_all", "screenshot.sh full", 0); - setconfspawn("screenshot_wind", "screenshot.sh window", 0); - setconfspawn("lock", "xlock", 0); - setconfspawn("initscr", "initscreen.sh", 0); - setconfspawn("menu", "dmenu_run" - " -fn $bar_font" - " -nb $bar_color" - " -nf $bar_font_color" - " -sb $bar_border" - " -sf $bar_color", 0); - setconfspawn("search", "dmenu" - " -i" - " -fn $bar_font" - " -nb $bar_color" - " -nf $bar_font_color" - " -sb $bar_border" - " -sf $bar_color", 0); - setconfspawn("name_workspace", "dmenu" - " -p Workspace" - " -fn $bar_font" - " -nb $bar_color" - " -nf $bar_font_color" - " -sb $bar_border" - " -sf $bar_color", 0); -} - -/* key bindings */ -#define SWM_MODNAME_SIZE 32 -#define SWM_KEY_WS "\n+ \t" -int -parsekeys(char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks) -{ - char *cp, *name; - KeySym uks; - DNPRINTF(SWM_D_KEY, "parsekeys: enter [%s]\n", keystr); - if (mod == NULL || ks == NULL) { - DNPRINTF(SWM_D_KEY, "parsekeys: no mod or key vars\n"); - return (1); - } - if (keystr == NULL || strlen(keystr) == 0) { - DNPRINTF(SWM_D_KEY, "parsekeys: no keystr\n"); - return (1); - } - cp = keystr; - *ks = NoSymbol; - *mod = 0; - while ((name = strsep(&cp, SWM_KEY_WS)) != NULL) { - DNPRINTF(SWM_D_KEY, "parsekeys: key [%s]\n", name); - if (cp) - cp += (long)strspn(cp, SWM_KEY_WS); - if (strncasecmp(name, "MOD", SWM_MODNAME_SIZE) == 0) - *mod |= currmod; - else if (!strncasecmp(name, "Mod1", SWM_MODNAME_SIZE)) - *mod |= Mod1Mask; - else if (!strncasecmp(name, "Mod2", SWM_MODNAME_SIZE)) - *mod += Mod2Mask; - else if (!strncmp(name, "Mod3", SWM_MODNAME_SIZE)) - *mod |= Mod3Mask; - else if (!strncmp(name, "Mod4", SWM_MODNAME_SIZE)) - *mod |= Mod4Mask; - else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) - *mod |= ShiftMask; - else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0) - *mod |= ControlMask; - else { - *ks = XStringToKeysym(name); - XConvertCase(*ks, ks, &uks); - if (ks == NoSymbol) { - DNPRINTF(SWM_D_KEY, - "parsekeys: invalid key %s\n", - name); - return (1); - } - } - } - DNPRINTF(SWM_D_KEY, "parsekeys: leave ok\n"); - return (0); -} - -char * -strdupsafe(char *str) -{ - if (str == NULL) - return (NULL); - else - return (strdup(str)); -} - -void -key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name) -{ - struct key *kp; - - DNPRINTF(SWM_D_KEY, "key_insert: enter %s [%s]\n", - keyfuncs[kfid].name, spawn_name); - - if ((kp = malloc(sizeof *kp)) == NULL) - err(1, "key_insert: malloc"); - - kp->mod = mod; - kp->keysym = ks; - kp->funcid = kfid; - kp->spawn_name = strdupsafe(spawn_name); - RB_INSERT(key_list, &keys, kp); - - DNPRINTF(SWM_D_KEY, "key_insert: leave\n"); -} - -struct key * -key_lookup(unsigned int mod, KeySym ks) -{ - struct key kp; - - kp.keysym = ks; - kp.mod = mod; - - return (RB_FIND(key_list, &keys, &kp)); -} - -void -key_remove(struct key *kp) -{ - DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name); - - RB_REMOVE(key_list, &keys, kp); - free(kp->spawn_name); - free(kp); - - DNPRINTF(SWM_D_KEY, "key_remove: leave\n"); -} - -void -key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid, - char *spawn_name) -{ - DNPRINTF(SWM_D_KEY, "key_replace: %s [%s]\n", keyfuncs[kp->funcid].name, - spawn_name); - - key_remove(kp); - key_insert(mod, ks, kfid, spawn_name); - - DNPRINTF(SWM_D_KEY, "key_replace: leave\n"); -} - -void -setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, - char *spawn_name) -{ - struct key *kp; - - DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n", - keyfuncs[kfid].name, spawn_name); - - if ((kp = key_lookup(mod, ks)) != NULL) { - if (kfid == kf_invalid) - key_remove(kp); - else - key_replace(kp, mod, ks, kfid, spawn_name); - DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); - return; - } - if (kfid == kf_invalid) { - warnx("error: setkeybinding: cannot find mod/key combination"); - DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); - return; - } - - key_insert(mod, ks, kfid, spawn_name); - DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); -} - -int -setconfbinding(char *selector, char *value, int flags) -{ - enum keyfuncid kfid; - unsigned int mod; - KeySym ks; - struct spawn_prog *sp; - DNPRINTF(SWM_D_KEY, "setconfbinding: enter\n"); - if (selector == NULL) { - DNPRINTF(SWM_D_KEY, "setconfbinding: unbind %s\n", value); - if (parsekeys(value, mod_key, &mod, &ks) == 0) { - kfid = kf_invalid; - setkeybinding(mod, ks, kfid, NULL); - return (0); - } else - return (1); - } - /* search by key function name */ - for (kfid = 0; kfid < kf_invalid; (kfid)++) { - if (strncasecmp(selector, keyfuncs[kfid].name, - SWM_FUNCNAME_LEN) == 0) { - DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n", - selector); - if (parsekeys(value, mod_key, &mod, &ks) == 0) { - setkeybinding(mod, ks, kfid, NULL); - return (0); - } else - return (1); - } - } - /* search by custom spawn name */ - TAILQ_FOREACH(sp, &spawns, entry) { - if (strcasecmp(selector, sp->name) == 0) { - DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n", - selector); - if (parsekeys(value, mod_key, &mod, &ks) == 0) { - setkeybinding(mod, ks, kf_spawn_custom, - sp->name); - return (0); - } else - return (1); - } - } - DNPRINTF(SWM_D_KEY, "setconfbinding: no match\n"); - return (1); -} - -void -setup_keys(void) -{ - setkeybinding(MODKEY, XK_space, kf_cycle_layout,NULL); - setkeybinding(MODKEY|ShiftMask, XK_backslash, kf_flip_layout, NULL); - setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset, NULL); - setkeybinding(MODKEY, XK_h, kf_master_shrink,NULL); - setkeybinding(MODKEY, XK_l, kf_master_grow, NULL); - setkeybinding(MODKEY, XK_comma, kf_master_add, NULL); - setkeybinding(MODKEY, XK_period, kf_master_del, NULL); - setkeybinding(MODKEY|ShiftMask, XK_comma, kf_stack_inc, NULL); - setkeybinding(MODKEY|ShiftMask, XK_period, kf_stack_dec, NULL); - setkeybinding(MODKEY, XK_Return, kf_swap_main, NULL); - setkeybinding(MODKEY, XK_j, kf_focus_next, NULL); - setkeybinding(MODKEY, XK_k, kf_focus_prev, NULL); - setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next, NULL); - setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_prev, NULL); - setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term, NULL); - setkeybinding(MODKEY, XK_p, kf_spawn_custom,"menu"); - setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit, NULL); - setkeybinding(MODKEY, XK_q, kf_restart, NULL); - setkeybinding(MODKEY, XK_m, kf_focus_main, NULL); - setkeybinding(MODKEY, XK_1, kf_ws_1, NULL); - setkeybinding(MODKEY, XK_2, kf_ws_2, NULL); - setkeybinding(MODKEY, XK_3, kf_ws_3, NULL); - setkeybinding(MODKEY, XK_4, kf_ws_4, NULL); - setkeybinding(MODKEY, XK_5, kf_ws_5, NULL); - setkeybinding(MODKEY, XK_6, kf_ws_6, NULL); - setkeybinding(MODKEY, XK_7, kf_ws_7, NULL); - setkeybinding(MODKEY, XK_8, kf_ws_8, NULL); - setkeybinding(MODKEY, XK_9, kf_ws_9, NULL); - setkeybinding(MODKEY, XK_0, kf_ws_10, NULL); - setkeybinding(MODKEY, XK_Right, kf_ws_next, NULL); - setkeybinding(MODKEY, XK_Left, kf_ws_prev, NULL); - setkeybinding(MODKEY, XK_Up, kf_ws_next_all, NULL); - setkeybinding(MODKEY, XK_Down, kf_ws_prev_all, NULL); - setkeybinding(MODKEY, XK_a, kf_ws_prior, NULL); - setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next, NULL); - setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev, NULL); - setkeybinding(MODKEY|ShiftMask, XK_1, kf_mvws_1, NULL); - setkeybinding(MODKEY|ShiftMask, XK_2, kf_mvws_2, NULL); - setkeybinding(MODKEY|ShiftMask, XK_3, kf_mvws_3, NULL); - setkeybinding(MODKEY|ShiftMask, XK_4, kf_mvws_4, NULL); - setkeybinding(MODKEY|ShiftMask, XK_5, kf_mvws_5, NULL); - setkeybinding(MODKEY|ShiftMask, XK_6, kf_mvws_6, NULL); - setkeybinding(MODKEY|ShiftMask, XK_7, kf_mvws_7, NULL); - setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8, NULL); - setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9, NULL); - setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10, NULL); - setkeybinding(MODKEY, XK_b, kf_bar_toggle, NULL); - setkeybinding(MODKEY, XK_Tab, kf_focus_next, NULL); - setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev, NULL); - setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill, NULL); - setkeybinding(MODKEY, XK_x, kf_wind_del, NULL); - setkeybinding(MODKEY, XK_s, kf_spawn_custom,"screenshot_all"); - setkeybinding(MODKEY|ShiftMask, XK_s, kf_spawn_custom,"screenshot_wind"); - setkeybinding(MODKEY, XK_t, kf_float_toggle,NULL); - setkeybinding(MODKEY|ShiftMask, XK_v, kf_version, NULL); - setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom,"lock"); - setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom,"initscr"); - setkeybinding(MODKEY, XK_w, kf_iconify, NULL); - setkeybinding(MODKEY|ShiftMask, XK_w, kf_uniconify, NULL); - setkeybinding(MODKEY|ShiftMask, XK_r, kf_raise_toggle,NULL); - setkeybinding(MODKEY, XK_v, kf_button2, NULL); - setkeybinding(MODKEY, XK_equal, kf_width_grow, NULL); - setkeybinding(MODKEY, XK_minus, kf_width_shrink,NULL); - setkeybinding(MODKEY|ShiftMask, XK_equal, kf_height_grow, NULL); - setkeybinding(MODKEY|ShiftMask, XK_minus, kf_height_shrink,NULL); - setkeybinding(MODKEY, XK_bracketleft, kf_move_left, NULL); - setkeybinding(MODKEY, XK_bracketright,kf_move_right, NULL); - setkeybinding(MODKEY|ShiftMask, XK_bracketleft, kf_move_up, NULL); - setkeybinding(MODKEY|ShiftMask, XK_bracketright,kf_move_down, NULL); - setkeybinding(MODKEY|ShiftMask, XK_slash, kf_name_workspace,NULL); - setkeybinding(MODKEY, XK_slash, kf_search_workspace,NULL); - setkeybinding(MODKEY, XK_f, kf_search_win, NULL); -#ifdef SWM_DEBUG - setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL); -#endif -} - -void -clear_keys(void) -{ - struct key *kp; - - while (RB_EMPTY(&keys) == 0) { - kp = RB_ROOT(&keys); - key_remove(kp); - } -} - -int -setkeymapping(char *selector, char *value, int flags) -{ - char keymapping_file[PATH_MAX]; - DNPRINTF(SWM_D_KEY, "setkeymapping: enter\n"); - if (value[0] == '~') - snprintf(keymapping_file, sizeof keymapping_file, "%s/%s", - pwd->pw_dir, &value[1]); - else - strlcpy(keymapping_file, value, sizeof keymapping_file); - clear_keys(); - /* load new key bindings; if it fails, revert to default bindings */ - if (conf_load(keymapping_file, SWM_CONF_KEYMAPPING)) { - clear_keys(); - setup_keys(); - } - DNPRINTF(SWM_D_KEY, "setkeymapping: leave\n"); - return (0); -} - -void -updatenumlockmask(void) -{ - unsigned int i, j; - XModifierKeymap *modmap; - - DNPRINTF(SWM_D_MISC, "updatenumlockmask\n"); - numlockmask = 0; - modmap = XGetModifierMapping(display); - for (i = 0; i < 8; i++) - for (j = 0; j < modmap->max_keypermod; j++) - if (modmap->modifiermap[i * modmap->max_keypermod + j] - == XKeysymToKeycode(display, XK_Num_Lock)) - numlockmask = (1 << i); - - XFreeModifiermap(modmap); -} - -void -grabkeys(void) -{ - unsigned int j, k; - KeyCode code; - unsigned int modifiers[] = - { 0, LockMask, numlockmask, numlockmask | LockMask }; - struct key *kp; - - DNPRINTF(SWM_D_MISC, "grabkeys\n"); - updatenumlockmask(); - - for (k = 0; k < ScreenCount(display); k++) { - if (TAILQ_EMPTY(&screens[k].rl)) - continue; - XUngrabKey(display, AnyKey, AnyModifier, screens[k].root); - RB_FOREACH(kp, key_list, &keys) { - if ((code = XKeysymToKeycode(display, kp->keysym))) - for (j = 0; j < LENGTH(modifiers); j++) - XGrabKey(display, code, - kp->mod | modifiers[j], - screens[k].root, True, - GrabModeAsync, GrabModeAsync); - } - } -} - -void -grabbuttons(struct ws_win *win, int focused) -{ - unsigned int i, j; - unsigned int modifiers[] = - { 0, LockMask, numlockmask, numlockmask|LockMask }; - - updatenumlockmask(); - XUngrabButton(display, AnyButton, AnyModifier, win->id); - if (focused) { - for (i = 0; i < LENGTH(buttons); i++) - if (buttons[i].action == client_click) - for (j = 0; j < LENGTH(modifiers); j++) - XGrabButton(display, buttons[i].button, - buttons[i].mask | modifiers[j], - win->id, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, - None); - } else - XGrabButton(display, AnyButton, AnyModifier, win->id, False, - BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); -} - -const char *quirkname[] = { - "NONE", /* config string for "no value" */ - "FLOAT", - "TRANSSZ", - "ANYWHERE", - "XTERM_FONTADJ", - "FULLSCREEN", - "FOCUSPREV", -}; - -/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */ -#define SWM_Q_WS "\n|+ \t" -int -parsequirks(char *qstr, unsigned long *quirk) -{ - char *cp, *name; - int i; - - if (quirk == NULL) - return (1); - - cp = qstr; - *quirk = 0; - while ((name = strsep(&cp, SWM_Q_WS)) != NULL) { - if (cp) - cp += (long)strspn(cp, SWM_Q_WS); - for (i = 0; i < LENGTH(quirkname); i++) { - if (!strncasecmp(name, quirkname[i], SWM_QUIRK_LEN)) { - DNPRINTF(SWM_D_QUIRK, - "parsequirks: %s\n", name); - if (i == 0) { - *quirk = 0; - return (0); - } - *quirk |= 1 << (i-1); - break; - } - } - if (i >= LENGTH(quirkname)) { - DNPRINTF(SWM_D_QUIRK, - "parsequirks: invalid quirk [%s]\n", name); - return (1); - } - } - return (0); -} - -void -quirk_insert(const char *class, const char *name, unsigned long quirk) -{ - struct quirk *qp; - - DNPRINTF(SWM_D_QUIRK, "quirk_insert: %s:%s [%lu]\n", class, name, - quirk); - - if ((qp = malloc(sizeof *qp)) == NULL) - err(1, "quirk_insert: malloc"); - if ((qp->class = strdup(class)) == NULL) - err(1, "quirk_insert: strdup"); - if ((qp->name = strdup(name)) == NULL) - err(1, "quirk_insert: strdup"); - - qp->quirk = quirk; - TAILQ_INSERT_TAIL(&quirks, qp, entry); - - DNPRINTF(SWM_D_QUIRK, "quirk_insert: leave\n"); -} - -void -quirk_remove(struct quirk *qp) -{ - DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%lu]\n", qp->class, - qp->name, qp->quirk); - - TAILQ_REMOVE(&quirks, qp, entry); - free(qp->class); - free(qp->name); - free(qp); - - DNPRINTF(SWM_D_QUIRK, "quirk_remove: leave\n"); -} - -void -quirk_replace(struct quirk *qp, const char *class, const char *name, - unsigned long quirk) -{ - DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s [%lu]\n", qp->class, - qp->name, qp->quirk); - - quirk_remove(qp); - quirk_insert(class, name, quirk); - - DNPRINTF(SWM_D_QUIRK, "quirk_replace: leave\n"); -} - -void -setquirk(const char *class, const char *name, unsigned long quirk) -{ - struct quirk *qp; - - DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s [%lu]\n", class, name, - quirk); - - TAILQ_FOREACH(qp, &quirks, entry) { - if (!strcmp(qp->class, class) && !strcmp(qp->name, name)) { - if (!quirk) - quirk_remove(qp); - else - quirk_replace(qp, class, name, quirk); - DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); - return; - } - } - if (!quirk) { - warnx("error: setquirk: cannot find class/name combination"); - return; - } - - quirk_insert(class, name, quirk); - DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); -} - -int -setconfquirk(char *selector, char *value, int flags) -{ - char *cp, *class, *name; - int retval; - unsigned long quirks; - if (selector == NULL) - return (0); - if ((cp = strchr(selector, ':')) == NULL) - return (0); - *cp = '\0'; - class = selector; - name = cp + 1; - if ((retval = parsequirks(value, &quirks)) == 0) - setquirk(class, name, quirks); - return (retval); -} - -void -setup_quirks(void) -{ - setquirk("MPlayer", "xv", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV); - setquirk("OpenOffice.org 3.2", "VCLSalFrame", SWM_Q_FLOAT); - setquirk("Firefox-bin", "firefox-bin", SWM_Q_TRANSSZ); - setquirk("Firefox", "Dialog", SWM_Q_FLOAT); - setquirk("Gimp", "gimp", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("XTerm", "xterm", SWM_Q_XTERM_FONTADJ); - setquirk("xine", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xitk Combo", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Panel", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("Xitk", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); - setquirk("xine", "xine Video Fullscreen Window", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); - setquirk("pcb", "pcb", SWM_Q_FLOAT); - setquirk("SDL_App", "SDL_App", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); -} - -/* conf file stuff */ -#define SWM_CONF_FILE "scrotwm.conf" - -enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, - SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, - SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, - SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED, - SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED, SWM_S_URGENT_ENABLED, - SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, - SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, - SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM, - SWM_S_VERBOSE_LAYOUT, SWM_S_BAR_JUSTIFY - }; - -int -setconfvalue(char *selector, char *value, int flags) -{ - int i; - char *b; - - switch (flags) { - case SWM_S_BAR_DELAY: - bar_delay = atoi(value); - break; - case SWM_S_BAR_ENABLED: - bar_enabled = atoi(value); - break; - case SWM_S_BAR_BORDER_WIDTH: - bar_border_width = atoi(value); - break; - case SWM_S_BAR_AT_BOTTOM: - bar_at_bottom = atoi(value); - break; - case SWM_S_BAR_JUSTIFY: - if (!strcmp(value, "left")) - bar_justify = SWM_BAR_JUSTIFY_LEFT; - else if (!strcmp(value, "center")) - bar_justify = SWM_BAR_JUSTIFY_CENTER; - else if (!strcmp(value, "right")) - bar_justify = SWM_BAR_JUSTIFY_RIGHT; - else - errx(1, "invalid bar_justify"); - break; - case SWM_S_STACK_ENABLED: - stack_enabled = atoi(value); - break; - case SWM_S_CLOCK_ENABLED: - clock_enabled = atoi(value); - break; - case SWM_S_CLOCK_FORMAT: -#ifndef SWM_DENY_CLOCK_FORMAT - free(clock_format); - if ((clock_format = strdup(value)) == NULL) - err(1, "setconfvalue: clock_format"); -#endif - break; - case SWM_S_CYCLE_EMPTY: - cycle_empty = atoi(value); - break; - case SWM_S_CYCLE_VISIBLE: - cycle_visible = atoi(value); - break; - case SWM_S_SS_ENABLED: - ss_enabled = atoi(value); - break; - case SWM_S_TERM_WIDTH: - term_width = atoi(value); - break; - case SWM_S_TITLE_CLASS_ENABLED: - title_class_enabled = atoi(value); - break; - case SWM_S_WINDOW_NAME_ENABLED: - window_name_enabled = atoi(value); - break; - case SWM_S_TITLE_NAME_ENABLED: - title_name_enabled = atoi(value); - break; - case SWM_S_URGENT_ENABLED: - urgent_enabled = atoi(value); - break; - case SWM_S_FOCUS_MODE: - if (!strcmp(value, "default")) - focus_mode = SWM_FOCUS_DEFAULT; - else if (!strcmp(value, "follow_cursor")) - focus_mode = SWM_FOCUS_FOLLOW; - else if (!strcmp(value, "synergy")) - focus_mode = SWM_FOCUS_SYNERGY; - else - errx(1, "focus_mode"); - break; - case SWM_S_DISABLE_BORDER: - disable_border = atoi(value); - break; - case SWM_S_BORDER_WIDTH: - border_width = atoi(value); - break; - case SWM_S_BAR_FONT: - b = bar_fonts; - if (asprintf(&bar_fonts, "%s,%s", value, bar_fonts) == -1) - err(1, "setconfvalue: asprintf: failed to allocate " - "memory for bar_fonts."); - - free(b); - break; - case SWM_S_BAR_ACTION: - free(bar_argv[0]); - if ((bar_argv[0] = strdup(value)) == NULL) - err(1, "setconfvalue: bar_action"); - break; - case SWM_S_SPAWN_TERM: - free(spawn_term[0]); - if ((spawn_term[0] = strdup(value)) == NULL) - err(1, "setconfvalue: spawn_term"); - break; - case SWM_S_SS_APP: - break; - case SWM_S_DIALOG_RATIO: - dialog_ratio = atof(value); - if (dialog_ratio > 1.0 || dialog_ratio <= .3) - dialog_ratio = .6; - break; - case SWM_S_VERBOSE_LAYOUT: - verbose_layout = atoi(value); - for (i = 0; layouts[i].l_stack != NULL; i++) { - if (verbose_layout) - layouts[i].l_string = fancy_stacker; - else - layouts[i].l_string = plain_stacker; - } - break; - default: - return (1); - } - return (0); -} - -int -setconfmodkey(char *selector, char *value, int flags) -{ - if (!strncasecmp(value, "Mod1", strlen("Mod1"))) - update_modkey(Mod1Mask); - else if (!strncasecmp(value, "Mod2", strlen("Mod2"))) - update_modkey(Mod2Mask); - else if (!strncasecmp(value, "Mod3", strlen("Mod3"))) - update_modkey(Mod3Mask); - else if (!strncasecmp(value, "Mod4", strlen("Mod4"))) - update_modkey(Mod4Mask); - else - return (1); - return (0); -} - -int -setconfcolor(char *selector, char *value, int flags) -{ - setscreencolor(value, ((selector == NULL)?-1:atoi(selector)), flags); - return (0); -} - -int -setconfregion(char *selector, char *value, int flags) -{ - custom_region(value); - return (0); -} - -int -setautorun(char *selector, char *value, int flags) -{ - int ws_id; - char s[1024]; - char *ap, *sp = s; - union arg a; - int argc = 0; - long pid; - struct pid_e *p; - - if (getenv("SWM_STARTED")) - return (0); - - bzero(s, sizeof s); - if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2) - errx(1, "invalid autorun entry, should be 'ws[]:command'"); - ws_id--; - if (ws_id < 0 || ws_id >= SWM_WS_MAX) - errx(1, "autorun: invalid workspace %d", ws_id + 1); - - /* - * This is a little intricate - * - * If the pid already exists we simply reuse it because it means it was - * used before AND not claimed by manage_window. We get away with - * altering it in the parent after INSERT because this can not be a race - */ - a.argv = NULL; - while ((ap = strsep(&sp, " \t")) != NULL) { - if (*ap == '\0') - continue; - DNPRINTF(SWM_D_SPAWN, "setautorun: arg [%s]\n", ap); - argc++; - if ((a.argv = realloc(a.argv, argc * sizeof(char *))) == NULL) - err(1, "setautorun: realloc"); - a.argv[argc - 1] = ap; - } - - if ((a.argv = realloc(a.argv, (argc + 1) * sizeof(char *))) == NULL) - err(1, "setautorun: realloc"); - a.argv[argc] = NULL; - - if ((pid = fork()) == 0) { - spawn(ws_id, &a, 1); - /* NOTREACHED */ - _exit(1); - } - free(a.argv); - - /* parent */ - p = find_pid(pid); - if (p == NULL) { - p = calloc(1, sizeof *p); - if (p == NULL) - return (1); - TAILQ_INSERT_TAIL(&pidlist, p, entry); - } - - p->pid = pid; - p->ws = ws_id; - - return (0); -} - -int -setlayout(char *selector, char *value, int flags) -{ - int ws_id, i, x, mg, ma, si, raise; - int st = SWM_V_STACK; - char s[1024]; - struct workspace *ws; - - if (getenv("SWM_STARTED")) - return (0); - - bzero(s, sizeof s); - if (sscanf(value, "ws[%d]:%d:%d:%d:%d:%1023c", - &ws_id, &mg, &ma, &si, &raise, s) != 6) - errx(1, "invalid layout entry, should be 'ws[]:" - "::::" - "'"); - ws_id--; - if (ws_id < 0 || ws_id >= SWM_WS_MAX) - errx(1, "layout: invalid workspace %d", ws_id + 1); - - if (!strcasecmp(s, "vertical")) - st = SWM_V_STACK; - else if (!strcasecmp(s, "horizontal")) - st = SWM_H_STACK; - else if (!strcasecmp(s, "fullscreen")) - st = SWM_MAX_STACK; - else - errx(1, "invalid layout entry, should be 'ws[]:" - "::::" - "'"); - - for (i = 0; i < ScreenCount(display); i++) { - ws = (struct workspace *)&screens[i].ws; - ws[ws_id].cur_layout = &layouts[st]; - - ws[ws_id].always_raise = raise; - if (st == SWM_MAX_STACK) - continue; - - /* master grow */ - for (x = 0; x < abs(mg); x++) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - mg >= 0 ? SWM_ARG_ID_MASTERGROW : - SWM_ARG_ID_MASTERSHRINK); - stack(); - } - /* master add */ - for (x = 0; x < abs(ma); x++) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - ma >= 0 ? SWM_ARG_ID_MASTERADD : - SWM_ARG_ID_MASTERDEL); - stack(); - } - /* stack inc */ - for (x = 0; x < abs(si); x++) { - ws[ws_id].cur_layout->l_config(&ws[ws_id], - si >= 0 ? SWM_ARG_ID_STACKINC : - SWM_ARG_ID_STACKDEC); - stack(); - } - } - - return (0); -} - -/* config options */ -struct config_option { - char *optname; - int (*func)(char*, char*, int); - int funcflags; -}; -struct config_option configopt[] = { - { "bar_enabled", setconfvalue, SWM_S_BAR_ENABLED }, - { "bar_at_bottom", setconfvalue, SWM_S_BAR_AT_BOTTOM }, - { "bar_border", setconfcolor, SWM_S_COLOR_BAR_BORDER }, - { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH }, - { "bar_color", setconfcolor, SWM_S_COLOR_BAR }, - { "bar_font_color", setconfcolor, SWM_S_COLOR_BAR_FONT }, - { "bar_font", setconfvalue, SWM_S_BAR_FONT }, - { "bar_action", setconfvalue, SWM_S_BAR_ACTION }, - { "bar_delay", setconfvalue, SWM_S_BAR_DELAY }, - { "bar_justify", setconfvalue, SWM_S_BAR_JUSTIFY }, - { "keyboard_mapping", setkeymapping, 0 }, - { "bind", setconfbinding, 0 }, - { "stack_enabled", setconfvalue, SWM_S_STACK_ENABLED }, - { "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED }, - { "clock_format", setconfvalue, SWM_S_CLOCK_FORMAT }, - { "color_focus", setconfcolor, SWM_S_COLOR_FOCUS }, - { "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS }, - { "cycle_empty", setconfvalue, SWM_S_CYCLE_EMPTY }, - { "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE }, - { "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO }, - { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, - { "modkey", setconfmodkey, 0 }, - { "program", setconfspawn, 0 }, - { "quirk", setconfquirk, 0 }, - { "region", setconfregion, 0 }, - { "spawn_term", setconfvalue, SWM_S_SPAWN_TERM }, - { "screenshot_enabled", setconfvalue, SWM_S_SS_ENABLED }, - { "screenshot_app", setconfvalue, SWM_S_SS_APP }, - { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, - { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, - { "term_width", setconfvalue, SWM_S_TERM_WIDTH }, - { "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED }, - { "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED }, - { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, - { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER }, - { "border_width", setconfvalue, SWM_S_BORDER_WIDTH }, - { "autorun", setautorun, 0 }, - { "layout", setlayout, 0 }, -}; - - -int -conf_load(char *filename, int keymapping) -{ - FILE *config; - char *line, *cp, *optsub, *optval; - size_t linelen, lineno = 0; - int wordlen, i, optind; - struct config_option *opt; - - DNPRINTF(SWM_D_CONF, "conf_load: begin\n"); - - if (filename == NULL) { - warnx("conf_load: no filename"); - return (1); - } - if ((config = fopen(filename, "r")) == NULL) { - warn("conf_load: fopen: %s", filename); - return (1); - } - - while (!feof(config)) { - if ((line = fparseln(config, &linelen, &lineno, NULL, 0)) - == NULL) { - if (ferror(config)) - err(1, "%s", filename); - else - continue; - } - cp = line; - cp += strspn(cp, " \t\n"); /* eat whitespace */ - if (cp[0] == '\0') { - /* empty line */ - free(line); - continue; - } - /* get config option */ - wordlen = strcspn(cp, "=[ \t\n"); - if (wordlen == 0) { - warnx("%s: line %zd: no option found", - filename, lineno); - goto out; - } - optind = -1; - for (i = 0; i < LENGTH(configopt); i++) { - opt = &configopt[i]; - if (!strncasecmp(cp, opt->optname, wordlen) && - strlen(opt->optname) == wordlen) { - optind = i; - break; - } - } - if (optind == -1) { - warnx("%s: line %zd: unknown option %.*s", - filename, lineno, wordlen, cp); - goto out; - } - if (keymapping && strcmp(opt->optname, "bind")) { - warnx("%s: line %zd: invalid option %.*s", - filename, lineno, wordlen, cp); - goto out; - } - cp += wordlen; - cp += strspn(cp, " \t\n"); /* eat whitespace */ - /* get [selector] if any */ - optsub = NULL; - if (*cp == '[') { - cp++; - wordlen = strcspn(cp, "]"); - if (*cp != ']') { - if (wordlen == 0) { - warnx("%s: line %zd: syntax error", - filename, lineno); - goto out; - } - - if (asprintf(&optsub, "%.*s", wordlen, cp) == - -1) { - warnx("%s: line %zd: unable to allocate" - "memory for selector", filename, - lineno); - goto out; - } - } - cp += wordlen; - cp += strspn(cp, "] \t\n"); /* eat trailing */ - } - cp += strspn(cp, "= \t\n"); /* eat trailing */ - /* get RHS value */ - optval = strdup(cp); - /* call function to deal with it all */ - if (configopt[optind].func(optsub, optval, - configopt[optind].funcflags) != 0) - errx(1, "%s: line %zd: invalid data for %s", - filename, lineno, configopt[optind].optname); - free(optval); - free(optsub); - free(line); - } - - fclose(config); - DNPRINTF(SWM_D_CONF, "conf_load: end\n"); - - return (0); - -out: - free(line); - fclose(config); - DNPRINTF(SWM_D_CONF, "conf_load: end with error.\n"); - - return (1); -} - -void -set_child_transient(struct ws_win *win, Window *trans) -{ - struct ws_win *parent, *w; - XWMHints *wmh = NULL; - struct swm_region *r; - struct workspace *ws; - - parent = find_window(win->transient); - if (parent) - parent->child_trans = win; - else { - DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist" - " for 0x%lx trans 0x%lx\n", win->id, win->transient); - - if (win->hints == NULL) { - warnx("no hints for 0x%lx", win->id); - return; - } - - r = root_to_region(win->wa.root); - ws = r->ws; - /* parent doen't exist in our window list */ - TAILQ_FOREACH(w, &ws->winlist, entry) { - if (wmh) - XFree(wmh); - - if ((wmh = XGetWMHints(display, w->id)) == NULL) { - warnx("can't get hints for 0x%lx", w->id); - continue; - } - - if (win->hints->window_group != wmh->window_group) - continue; - - w->child_trans = win; - win->transient = w->id; - *trans = w->id; - DNPRINTF(SWM_D_MISC, "set_child_transient: asjusting " - "transient to 0x%lx\n", win->transient); - break; - } - } - - if (wmh) - XFree(wmh); -} - -long -window_get_pid(Window win) -{ - Atom actual_type_return; - int actual_format_return = 0; - unsigned long nitems_return = 0; - unsigned long bytes_after_return = 0; - long *pid = NULL; - long ret = 0; - const char *errstr; - unsigned char *prop = NULL; - - if (XGetWindowProperty(display, win, - XInternAtom(display, "_NET_WM_PID", False), 0, 1, False, - XA_CARDINAL, &actual_type_return, &actual_format_return, - &nitems_return, &bytes_after_return, - (unsigned char**)(void*)&pid) != Success) - goto tryharder; - if (actual_type_return != XA_CARDINAL) - goto tryharder; - if (pid == NULL) - goto tryharder; - - ret = *pid; - XFree(pid); - - return (ret); - -tryharder: - if (XGetWindowProperty(display, win, - XInternAtom(display, "_SWM_PID", False), 0, SWM_PROPLEN, False, - XA_STRING, &actual_type_return, &actual_format_return, - &nitems_return, &bytes_after_return, &prop) != Success) - return (0); - if (actual_type_return != XA_STRING) - return (0); - if (prop == NULL) - return (0); - - ret = strtonum((const char *)prop, 0, UINT_MAX, &errstr); - /* ignore error because strtonum returns 0 anyway */ - XFree(prop); - - return (ret); -} - -struct ws_win * -manage_window(Window id) -{ - Window trans = 0; - struct workspace *ws; - struct ws_win *win, *ww; - int format, i, ws_idx, n, border_me = 0; - unsigned long nitems, bytes; - Atom ws_idx_atom = 0, type; - Atom *prot = NULL, *pp; - unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; - struct swm_region *r; - long mask; - const char *errstr; - XWindowChanges wc; - struct pid_e *p; - struct quirk *qp; - - if ((win = find_window(id)) != NULL) - return (win); /* already being managed */ - - /* see if we are on the unmanaged list */ - if ((win = find_unmanaged_window(id)) != NULL) { - DNPRINTF(SWM_D_MISC, "manage_window: previously unmanaged " - "window: 0x%lx\n", win->id); - TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); - if (win->transient) { - set_child_transient(win, &trans); - } if (trans && (ww = find_window(trans))) - TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); - else - TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); - ewmh_update_actions(win); - return (win); - } - - if ((win = calloc(1, sizeof(struct ws_win))) == NULL) - err(1, "manage_window: calloc: failed to allocate memory for " - "new window"); - - win->id = id; - - /* see if we need to override the workspace */ - p = find_pid(window_get_pid(id)); - - /* Get all the window data in one shot */ - ws_idx_atom = XInternAtom(display, "_SWM_WS", False); - if (ws_idx_atom) { - XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN, - False, XA_STRING, &type, &format, &nitems, &bytes, &prop); - } - XGetWindowAttributes(display, id, &win->wa); - XGetWMNormalHints(display, id, &win->sh, &win->sh_mask); - win->hints = XGetWMHints(display, id); - XGetTransientForHint(display, id, &trans); - if (trans) { - win->transient = trans; - set_child_transient(win, &trans); - DNPRINTF(SWM_D_MISC, "manage_window: window: 0x%lx, " - "transient: 0x%lx\n", win->id, win->transient); - } - - /* get supported protocols */ - if (XGetWMProtocols(display, id, &prot, &n)) { - for (i = 0, pp = prot; i < n; i++, pp++) { - if (*pp == takefocus) - win->take_focus = 1; - if (*pp == adelete) - win->can_delete = 1; - } - if (prot) - XFree(prot); - } - - win->iconic = get_iconic(win); - - /* - * Figure out where to put the window. If it was previously assigned to - * a workspace (either by spawn() or manually moving), and isn't - * transient, * put it in the same workspace - */ - r = root_to_region(win->wa.root); - if (p) { - ws = &r->s->ws[p->ws]; - TAILQ_REMOVE(&pidlist, p, entry); - free(p); - p = NULL; - } else if (prop && win->transient == 0) { - DNPRINTF(SWM_D_PROP, "manage_window: get _SWM_WS: %s\n", prop); - ws_idx = strtonum((const char *)prop, 0, 9, &errstr); - if (errstr) { - DNPRINTF(SWM_D_EVENT, "manage_window: window: #%s: %s", - errstr, prop); - } - ws = &r->s->ws[ws_idx]; - } else { - ws = r->ws; - /* this should launch transients in the same ws as parent */ - if (id && trans) - if ((ww = find_window(trans)) != NULL) - if (ws->r) { - ws = ww->ws; - if (ww->ws->r) - r = ww->ws->r; - else - warnx("manage_window: fix this " - "bug mcbride"); - border_me = 1; - } - } - - /* set up the window layout */ - win->id = id; - win->ws = ws; - win->s = r->s; /* this never changes */ - if (trans && (ww = find_window(trans))) - TAILQ_INSERT_AFTER(&ws->winlist, ww, win, entry); - else - TAILQ_INSERT_TAIL(&ws->winlist, win, entry); - - WIDTH(win) = win->wa.width; - HEIGHT(win) = win->wa.height; - X(win) = win->wa.x; - Y(win) = win->wa.y; - win->g_floatvalid = 0; - win->floatmaxed = 0; - win->ewmh_flags = 0; - - /* Set window properties so we can remember this after reincarnation */ - if (ws_idx_atom && prop == NULL && - snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < - SWM_PROPLEN) { - DNPRINTF(SWM_D_PROP, "manage_window: set _SWM_WS: %s\n", - ws_idx_str); - XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, - PropModeReplace, ws_idx_str, strlen((char *)ws_idx_str)); - } - if (prop) - XFree(prop); - - ewmh_autoquirk(win); - - if (XGetClassHint(display, win->id, &win->ch)) { - DNPRINTF(SWM_D_CLASS, "manage_window: class: %s, name: %s\n", - win->ch.res_class, win->ch.res_name); - - /* java is retarded so treat it special */ - if (strstr(win->ch.res_name, "sun-awt")) { - win->java = 1; - border_me = 1; - } - - TAILQ_FOREACH(qp, &quirks, entry) { - if (!strcmp(win->ch.res_class, qp->class) && - !strcmp(win->ch.res_name, qp->name)) { - DNPRINTF(SWM_D_CLASS, "manage_window: found: " - "class: %s, name: %s\n", win->ch.res_class, - win->ch.res_name); - if (qp->quirk & SWM_Q_FLOAT) { - win->floating = 1; - border_me = 1; - } - win->quirks = qp->quirk; - } - } - } - - /* alter window position if quirky */ - if (win->quirks & SWM_Q_ANYWHERE) { - win->manual = 1; /* don't center the quirky windows */ - bzero(&wc, sizeof wc); - mask = 0; - if (bar_enabled && Y(win) < bar_height) { - Y(win) = wc.y = bar_height; - mask |= CWY; - } - if (WIDTH(win) + X(win) > WIDTH(r)) { - X(win) = wc.x = WIDTH(r) - WIDTH(win) - 2; - mask |= CWX; - } - border_me = 1; - } - - /* Reset font sizes (the bruteforce way; no default keybinding). */ - if (win->quirks & SWM_Q_XTERM_FONTADJ) { - for (i = 0; i < SWM_MAX_FONT_STEPS; i++) - fake_keypress(win, XK_KP_Subtract, ShiftMask); - for (i = 0; i < SWM_MAX_FONT_STEPS; i++) - fake_keypress(win, XK_KP_Add, ShiftMask); - } - - ewmh_get_win_state(win); - ewmh_update_actions(win); - ewmh_update_win_state(win, None, _NET_WM_STATE_REMOVE); - - /* border me */ - if (border_me) { - bzero(&wc, sizeof wc); - wc.border_width = border_width; - mask = CWBorderWidth; - XConfigureWindow(display, win->id, mask, &wc); - } - - XSelectInput(display, id, EnterWindowMask | FocusChangeMask | - PropertyChangeMask | StructureNotifyMask); - - /* floaters need to be mapped if they are in the current workspace */ - if ((win->floating || win->transient) && (ws->idx == r->ws->idx)) - XMapRaised(display, win->id); - - return (win); -} - -void -free_window(struct ws_win *win) -{ - DNPRINTF(SWM_D_MISC, "free_window: window: 0x%lx\n", win->id); - - if (win == NULL) - return; - - /* needed for restart wm */ - set_win_state(win, WithdrawnState); - - TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); - - if (win->ch.res_class) - XFree(win->ch.res_class); - if (win->ch.res_name) - XFree(win->ch.res_name); - - kill_refs(win); - - /* paint memory */ - memset(win, 0xff, sizeof *win); /* XXX kill later */ - - free(win); -} - -void -unmanage_window(struct ws_win *win) -{ - struct ws_win *parent; - - if (win == NULL) - return; - - DNPRINTF(SWM_D_MISC, "unmanage_window: window: 0x%lx\n", win->id); - - if (win->transient) { - parent = find_window(win->transient); - if (parent) - parent->child_trans = NULL; - } - - /* focus on root just in case */ - XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); - - focus_prev(win); - - if (win->hints) { - XFree(win->hints); - win->hints = NULL; - } - - TAILQ_REMOVE(&win->ws->winlist, win, entry); - TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); - - kill_refs(win); -} - -void -focus_magic(struct ws_win *win) -{ - DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%lx\n", WINID(win)); - - if (win == NULL) { - /* if there are no windows clear the status-bar */ - bar_check_opts(); - return; - } - - if (win->child_trans) { - /* win = parent & has a transient so focus on that */ - if (win->java) { - focus_win(win->child_trans); - if (win->child_trans->take_focus) - client_msg(win, takefocus); - } else { - /* make sure transient hasn't disappeared */ - if (validate_win(win->child_trans) == 0) { - focus_win(win->child_trans); - if (win->child_trans->take_focus) - client_msg(win->child_trans, takefocus); - } else { - win->child_trans = NULL; - focus_win(win); - if (win->take_focus) - client_msg(win, takefocus); - } - } - } else { - /* regular focus */ - focus_win(win); - if (win->take_focus) - client_msg(win, takefocus); - } -} - -void -expose(XEvent *e) -{ - DNPRINTF(SWM_D_EVENT, "expose: window: 0x%lx\n", e->xexpose.window); -} - -void -keypress(XEvent *e) -{ - KeySym keysym; - XKeyEvent *ev = &e->xkey; - struct key *kp; - struct swm_region *r; - - keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0); - if ((kp = key_lookup(CLEANMASK(ev->state), keysym)) == NULL) - return; - if (keyfuncs[kp->funcid].func == NULL) - return; - - r = root_to_region(ev->root); - if (kp->funcid == kf_spawn_custom) - spawn_custom(r, &(keyfuncs[kp->funcid].args), kp->spawn_name); - else - keyfuncs[kp->funcid].func(r, &(keyfuncs[kp->funcid].args)); -} - -void -buttonpress(XEvent *e) -{ - struct ws_win *win; - int i, action; - XButtonPressedEvent *ev = &e->xbutton; - - if ((win = find_window(ev->window)) == NULL) - return; - - focus_magic(win); - action = client_click; - - for (i = 0; i < LENGTH(buttons); i++) - if (action == buttons[i].action && buttons[i].func && - buttons[i].button == ev->button && - CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) - buttons[i].func(win, &buttons[i].args); -} - -void -configurerequest(XEvent *e) -{ - XConfigureRequestEvent *ev = &e->xconfigurerequest; - struct ws_win *win; - int new = 0; - XWindowChanges wc; - - if ((win = find_window(ev->window)) == NULL) - if ((win = find_unmanaged_window(ev->window)) == NULL) - new = 1; - - DNPRINTF(SWM_D_EVENT, "configurerequest: window: 0x%lx, new: %s\n", - ev->window, YESNO(new)); - - if (new) { - bzero(&wc, sizeof wc); - wc.x = ev->x; - wc.y = ev->y; - wc.width = ev->width; - wc.height = ev->height; - wc.border_width = ev->border_width; - wc.sibling = ev->above; - wc.stack_mode = ev->detail; - XConfigureWindow(display, ev->window, ev->value_mask, &wc); - } else { - config_win(win, ev); - } -} - -void -configurenotify(XEvent *e) -{ - struct ws_win *win; - - DNPRINTF(SWM_D_EVENT, "configurenotify: window: 0x%lx\n", - e->xconfigure.window); - - win = find_window(e->xconfigure.window); - if (win) { - XGetWMNormalHints(display, win->id, &win->sh, &win->sh_mask); - adjust_font(win); - if (font_adjusted) - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - } -} - -void -destroynotify(XEvent *e) -{ - struct ws_win *win; - XDestroyWindowEvent *ev = &e->xdestroywindow; - - DNPRINTF(SWM_D_EVENT, "destroynotify: window: 0x%lx\n", ev->window); - - if ((win = find_window(ev->window)) == NULL) { - if ((win = find_unmanaged_window(ev->window)) == NULL) - return; - free_window(win); - return; - } - - /* make sure we focus on something */ - win->floating = 0; - - unmanage_window(win); - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - free_window(win); -} - -void -enternotify(XEvent *e) -{ - XCrossingEvent *ev = &e->xcrossing; - XEvent cne; - struct ws_win *win; -#if 0 - struct ws_win *w; - Window focus_return; - int revert_to_return; -#endif - DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%lx, mode: %d, detail: " - "%d, root: 0x%lx, subwindow: 0x%lx, same_screen: %s, focus: %s, " - "state: %d\n", ev->window, ev->mode, ev->detail, ev->root, - ev->subwindow, YESNO(ev->same_screen), YESNO(ev->focus), ev->state); - - if (ev->mode != NotifyNormal) { - DNPRINTF(SWM_D_EVENT, "skip enternotify: generated by " - "cursor grab.\n"); - return; - } - - switch (focus_mode) { - case SWM_FOCUS_DEFAULT: - break; - case SWM_FOCUS_FOLLOW: - break; - case SWM_FOCUS_SYNERGY: -#if 0 - /* - * all these checks need to be in this order because the - * XCheckTypedWindowEvent relies on weeding out the previous events - * - * making this code an option would enable a follow mouse for focus - * feature - */ - - /* - * state is set when we are switching workspaces and focus is set when - * the window or a subwindow already has focus (occurs during restart). - * - * Only honor the focus flag if last_focus_event is not FocusOut, - * this allows scrotwm to continue to control focus when another - * program is also playing with it. - */ - if (ev->state || (ev->focus && last_focus_event != FocusOut)) { - DNPRINTF(SWM_D_EVENT, "ignoring enternotify: focus\n"); - return; - } - - /* - * happens when a window is created or destroyed and the border - * crosses the mouse pointer and when switching ws - * - * we need the subwindow test to see if we came from root in order - * to give focus to floaters - */ - if (ev->mode == NotifyNormal && ev->detail == NotifyVirtual && - ev->subwindow == 0) { - DNPRINTF(SWM_D_EVENT, "ignoring enternotify: NotifyVirtual\n"); - return; - } - - /* this window already has focus */ - if (ev->mode == NotifyNormal && ev->detail == NotifyInferior) { - DNPRINTF(SWM_D_EVENT, "ignoring enternotify: win has focus\n"); - return; - } - - /* this window is being deleted or moved to another ws */ - if (XCheckTypedWindowEvent(display, ev->window, ConfigureNotify, - &cne) == True) { - DNPRINTF(SWM_D_EVENT, "ignoring enternotify: configurenotify\n"); - XPutBackEvent(display, &cne); - return; - } - - if ((win = find_window(ev->window)) == NULL) { - DNPRINTF(SWM_D_EVENT, "ignoring enternotify: win == NULL\n"); - return; - } - - /* - * In fullstack kill all enters unless they come from a different ws - * (i.e. another region) or focus has been grabbed externally. - */ - if (win->ws->cur_layout->flags & SWM_L_FOCUSPREV && - last_focus_event != FocusOut) { - XGetInputFocus(display, &focus_return, &revert_to_return); - if ((w = find_window(focus_return)) == NULL || - w->ws == win->ws) { - DNPRINTF(SWM_D_EVENT, "ignoring event: fullstack\n"); - return; - } - } -#endif - break; - } - - if ((win = find_window(ev->window)) == NULL) { - DNPRINTF(SWM_D_EVENT, "skip enternotify: window is NULL\n"); - return; - } - - /* - * if we have more enternotifies let them handle it in due time - */ - if (XCheckTypedEvent(display, EnterNotify, &cne) == True) { - DNPRINTF(SWM_D_EVENT, - "ignoring enternotify: got more enternotify\n"); - XPutBackEvent(display, &cne); - return; - } - - focus_magic(win); -} - -/* lets us use one switch statement for arbitrary mode/detail combinations */ -#define MERGE_MEMBERS(a,b) (((a & 0xffff) << 16) | (b & 0xffff)) - -void -focusevent(XEvent *e) -{ -#if 0 - struct ws_win *win; - u_int32_t mode_detail; - XFocusChangeEvent *ev = &e->xfocus; - - DNPRINTF(SWM_D_EVENT, "focusevent: %s window: 0x%lx mode: %d " - "detail: %d\n", ev->type == FocusIn ? "entering" : "leaving", - ev->window, ev->mode, ev->detail); - - if (last_focus_event == ev->type) { - DNPRINTF(SWM_D_FOCUS, "ignoring focusevent: bad ordering\n"); - return; - } - - last_focus_event = ev->type; - mode_detail = MERGE_MEMBERS(ev->mode, ev->detail); - - switch (mode_detail) { - /* synergy client focus operations */ - case MERGE_MEMBERS(NotifyNormal, NotifyNonlinear): - case MERGE_MEMBERS(NotifyNormal, NotifyNonlinearVirtual): - - /* synergy server focus operations */ - case MERGE_MEMBERS(NotifyWhileGrabbed, NotifyNonlinear): - - /* Entering applications like rdesktop that mangle the pointer */ - case MERGE_MEMBERS(NotifyNormal, NotifyPointer): - - if ((win = find_window(e->xfocus.window)) != NULL && win->ws->r) - XSetWindowBorder(display, win->id, - win->ws->r->s->c[ev->type == FocusIn ? - SWM_S_COLOR_FOCUS : SWM_S_COLOR_UNFOCUS].color); - break; - default: - warnx("ignoring focusevent"); - DNPRINTF(SWM_D_FOCUS, "ignoring focusevent\n"); - break; - } -#endif -} - -void -mapnotify(XEvent *e) -{ - struct ws_win *win; - XMapEvent *ev = &e->xmap; - - DNPRINTF(SWM_D_EVENT, "mapnotify: window: 0x%lx\n", ev->window); - - win = manage_window(ev->window); - if (win) - set_win_state(win, NormalState); -} - -void -mappingnotify(XEvent *e) -{ - XMappingEvent *ev = &e->xmapping; - - XRefreshKeyboardMapping(ev); - if (ev->request == MappingKeyboard) - grabkeys(); -} - -void -maprequest(XEvent *e) -{ - struct ws_win *win; - struct swm_region *r; - XWindowAttributes wa; - XMapRequestEvent *ev = &e->xmaprequest; - - DNPRINTF(SWM_D_EVENT, "maprequest: window: 0x%lx\n", - e->xmaprequest.window); - - if (!XGetWindowAttributes(display, ev->window, &wa)) - return; - if (wa.override_redirect) - return; - - win = manage_window(e->xmaprequest.window); - if (win == NULL) - return; /* can't happen */ - - stack(); - - /* make new win focused */ - r = root_to_region(win->wa.root); - if (win->ws == r->ws) - focus_magic(win); -} - -void -propertynotify(XEvent *e) -{ - struct ws_win *win; - XPropertyEvent *ev = &e->xproperty; -#ifdef SWM_DEBUG - char *name; - name = XGetAtomName(display, ev->atom); - DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%lx, atom: %s\n", - ev->window, name); - XFree(name); -#endif - - win = find_window(ev->window); - if (win == NULL) - return; - - if (ev->state == PropertyDelete && ev->atom == a_swm_iconic) { - update_iconic(win, 0); - XMapRaised(display, win->id); - stack(); - focus_win(win); - return; - } - - switch (ev->atom) { -#if 0 - case XA_WM_NORMAL_HINTS: - long mask; - XGetWMNormalHints(display, win->id, &win->sh, &mask); - warnx("normal hints: flag 0x%x", win->sh.flags); - if (win->sh.flags & PMinSize) { - WIDTH(win) = win->sh.min_width; - HEIGHT(win) = win->sh.min_height; - warnx("min %d %d", WIDTH(win), HEIGHT(win)); - } - XMoveResizeWindow(display, win->id, - X(win), Y(win), WIDTH(win), HEIGHT(win)); -#endif - case XA_WM_CLASS: - if (title_name_enabled || title_class_enabled) - bar_update(); - break; - case XA_WM_NAME: - if (window_name_enabled) - bar_update(); - break; - default: - break; - } -} - -void -unmapnotify(XEvent *e) -{ - struct ws_win *win; - - DNPRINTF(SWM_D_EVENT, "unmapnotify: window: 0x%lx\n", e->xunmap.window); - - /* determine if we need to help unmanage this window */ - win = find_window(e->xunmap.window); - if (win == NULL) - return; - - if (getstate(e->xunmap.window) == NormalState) { - unmanage_window(win); - stack(); - - /* giant hack for apps that don't destroy transient windows */ - /* eat a bunch of events to prevent remanaging the window */ - XEvent cne; - while (XCheckWindowEvent(display, e->xunmap.window, - EnterWindowMask, &cne)) - ; - while (XCheckWindowEvent(display, e->xunmap.window, - StructureNotifyMask, &cne)) - ; - while (XCheckWindowEvent(display, e->xunmap.window, - SubstructureNotifyMask, &cne)) - ; - /* resend unmap because we ated it */ - XUnmapWindow(display, e->xunmap.window); - } - - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); -} - -void -visibilitynotify(XEvent *e) -{ - int i; - struct swm_region *r; - - DNPRINTF(SWM_D_EVENT, "visibilitynotify: window: 0x%lx\n", - e->xvisibility.window); - if (e->xvisibility.state == VisibilityUnobscured) - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) - if (e->xvisibility.window == r->bar_window) - bar_update(); -} - -void -clientmessage(XEvent *e) -{ - XClientMessageEvent *ev; - struct ws_win *win; - - ev = &e->xclient; - - win = find_window(ev->window); - if (win == NULL) - return; - - DNPRINTF(SWM_D_EVENT, "clientmessage: window: 0x%lx, type: %ld\n", - ev->window, ev->message_type); - - if (ev->message_type == ewmh[_NET_ACTIVE_WINDOW].atom) { - DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n"); - focus_win(win); - } - if (ev->message_type == ewmh[_NET_CLOSE_WINDOW].atom) { - DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n"); - if (win->can_delete) - client_msg(win, adelete); - else - XKillClient(display, win->id); - } - if (ev->message_type == ewmh[_NET_MOVERESIZE_WINDOW].atom) { - DNPRINTF(SWM_D_EVENT, - "clientmessage: _NET_MOVERESIZE_WINDOW\n"); - if (win->floating) { - if (ev->data.l[0] & (1<<8)) /* x */ - X(win) = ev->data.l[1]; - if (ev->data.l[0] & (1<<9)) /* y */ - Y(win) = ev->data.l[2]; - if (ev->data.l[0] & (1<<10)) /* width */ - WIDTH(win) = ev->data.l[3]; - if (ev->data.l[0] & (1<<11)) /* height */ - HEIGHT(win) = ev->data.l[4]; - - update_window(win); - } - else { - /* TODO: Change stack sizes */ - /* notify no change was made. */ - config_win(win, NULL); - } - } - if (ev->message_type == ewmh[_NET_WM_STATE].atom) { - DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE\n"); - ewmh_update_win_state(win, ev->data.l[1], ev->data.l[0]); - if (ev->data.l[2]) - ewmh_update_win_state(win, ev->data.l[2], - ev->data.l[0]); - - stack(); - } -} - -int -xerror_start(Display *d, XErrorEvent *ee) -{ - other_wm = 1; - return (-1); -} - -int -xerror(Display *d, XErrorEvent *ee) -{ - /* warnx("error: %p %p", display, ee); */ - return (-1); -} - -int -active_wm(void) -{ - other_wm = 0; - xerrorxlib = XSetErrorHandler(xerror_start); - - /* this causes an error if some other window manager is running */ - XSelectInput(display, DefaultRootWindow(display), - SubstructureRedirectMask); - XSync(display, False); - if (other_wm) - return (1); - - XSetErrorHandler(xerror); - XSync(display, False); - return (0); -} - -void -new_region(struct swm_screen *s, int x, int y, int w, int h) -{ - struct swm_region *r, *n; - struct workspace *ws = NULL; - int i; - - DNPRINTF(SWM_D_MISC, "new region: screen[%d]:%dx%d+%d+%d\n", - s->idx, w, h, x, y); - - /* remove any conflicting regions */ - n = TAILQ_FIRST(&s->rl); - while (n) { - r = n; - n = TAILQ_NEXT(r, entry); - if (X(r) < (x + w) && - (X(r) + WIDTH(r)) > x && - Y(r) < (y + h) && - (Y(r) + HEIGHT(r)) > y) { - if (r->ws->r != NULL) - r->ws->old_r = r->ws->r; - r->ws->r = NULL; - XDestroyWindow(display, r->bar_window); - TAILQ_REMOVE(&s->rl, r, entry); - TAILQ_INSERT_TAIL(&s->orl, r, entry); - } - } - - /* search old regions for one to reuse */ - - /* size + location match */ - TAILQ_FOREACH(r, &s->orl, entry) - if (X(r) == x && Y(r) == y && - HEIGHT(r) == h && WIDTH(r) == w) - break; - - /* size match */ - TAILQ_FOREACH(r, &s->orl, entry) - if (HEIGHT(r) == h && WIDTH(r) == w) - break; - - if (r != NULL) { - TAILQ_REMOVE(&s->orl, r, entry); - /* try to use old region's workspace */ - if (r->ws->r == NULL) - ws = r->ws; - } else - if ((r = calloc(1, sizeof(struct swm_region))) == NULL) - err(1, "new_region: calloc: failed to allocate memory " - "for screen"); - - /* if we don't have a workspace already, find one */ - if (ws == NULL) { - for (i = 0; i < SWM_WS_MAX; i++) - if (s->ws[i].r == NULL) { - ws = &s->ws[i]; - break; - } - } - - if (ws == NULL) - errx(1, "new_region: no free workspaces"); - - X(r) = x; - Y(r) = y; - WIDTH(r) = w; - HEIGHT(r) = h; - r->s = s; - r->ws = ws; - r->ws_prior = NULL; - ws->r = r; - outputs++; - TAILQ_INSERT_TAIL(&s->rl, r, entry); -} - -void -scan_xrandr(int i) -{ -#ifdef SWM_XRR_HAS_CRTC - XRRCrtcInfo *ci; - XRRScreenResources *sr; - int c; - int ncrtc = 0; -#endif /* SWM_XRR_HAS_CRTC */ - struct swm_region *r; - - - if (i >= ScreenCount(display)) - errx(1, "scan_xrandr: invalid screen"); - - /* remove any old regions */ - while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { - r->ws->old_r = r->ws->r = NULL; - XDestroyWindow(display, r->bar_window); - TAILQ_REMOVE(&screens[i].rl, r, entry); - TAILQ_INSERT_TAIL(&screens[i].orl, r, entry); - } - outputs = 0; - - /* map virtual screens onto physical screens */ -#ifdef SWM_XRR_HAS_CRTC - if (xrandr_support) { - sr = XRRGetScreenResources(display, screens[i].root); - if (sr == NULL) - new_region(&screens[i], 0, 0, - DisplayWidth(display, i), - DisplayHeight(display, i)); - else - ncrtc = sr->ncrtc; - - for (c = 0, ci = NULL; c < ncrtc; c++) { - ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]); - if (ci->noutput == 0) - continue; - - if (ci != NULL && ci->mode == None) - new_region(&screens[i], 0, 0, - DisplayWidth(display, i), - DisplayHeight(display, i)); - else - new_region(&screens[i], - ci->x, ci->y, ci->width, ci->height); - } - if (ci) - XRRFreeCrtcInfo(ci); - XRRFreeScreenResources(sr); - } else -#endif /* SWM_XRR_HAS_CRTC */ - { - new_region(&screens[i], 0, 0, DisplayWidth(display, i), - DisplayHeight(display, i)); - } -} - -void -screenchange(XEvent *e) { - XRRScreenChangeNotifyEvent *xe = (XRRScreenChangeNotifyEvent *)e; - struct swm_region *r; - int i; - - DNPRINTF(SWM_D_EVENT, "screenchange: root: 0x%lx\n", xe->root); - - if (!XRRUpdateConfiguration(e)) - return; - - /* silly event doesn't include the screen index */ - for (i = 0; i < ScreenCount(display); i++) - if (screens[i].root == xe->root) - break; - if (i >= ScreenCount(display)) - errx(1, "screenchange: screen not found"); - - /* brute force for now, just re-enumerate the regions */ - scan_xrandr(i); - - /* add bars to all regions */ - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) - bar_setup(r); - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); -} - -void -grab_windows(void) -{ - Window d1, d2, *wins = NULL; - XWindowAttributes wa; - unsigned int no; - int i, j; - long state, manage; - - for (i = 0; i < ScreenCount(display); i++) { - if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no)) - continue; - - /* attach windows to a region */ - /* normal windows */ - for (j = 0; j < no; j++) { - if (!XGetWindowAttributes(display, wins[j], &wa) || - wa.override_redirect || - XGetTransientForHint(display, wins[j], &d1)) - continue; - - state = getstate(wins[j]); - manage = state == IconicState; - if (wa.map_state == IsViewable || manage) - manage_window(wins[j]); - } - /* transient windows */ - for (j = 0; j < no; j++) { - if (!XGetWindowAttributes(display, wins[j], &wa) || - wa.override_redirect) - continue; - - state = getstate(wins[j]); - manage = state == IconicState; - if (XGetTransientForHint(display, wins[j], &d1) && - manage) - manage_window(wins[j]); - } - if (wins) { - XFree(wins); - wins = NULL; - } - } -} - -void -setup_screens(void) -{ - int i, j, k; - int errorbase, major, minor; - struct workspace *ws; - XGCValues gcv; - - if ((screens = calloc(ScreenCount(display), - sizeof(struct swm_screen))) == NULL) - err(1, "setup_screens: calloc: failed to allocate memory for " - "screens"); - - /* initial Xrandr setup */ - xrandr_support = XRRQueryExtension(display, - &xrandr_eventbase, &errorbase); - if (xrandr_support) - if (XRRQueryVersion(display, &major, &minor) && major < 1) - xrandr_support = 0; - - /* map physical screens */ - for (i = 0; i < ScreenCount(display); i++) { - DNPRINTF(SWM_D_WS, "setup_screens: init screen: %d\n", i); - screens[i].idx = i; - TAILQ_INIT(&screens[i].rl); - TAILQ_INIT(&screens[i].orl); - screens[i].root = RootWindow(display, i); - - /* set default colors */ - setscreencolor("red", i + 1, SWM_S_COLOR_FOCUS); - setscreencolor("rgb:88/88/88", i + 1, SWM_S_COLOR_UNFOCUS); - setscreencolor("rgb:00/80/80", i + 1, SWM_S_COLOR_BAR_BORDER); - setscreencolor("black", i + 1, SWM_S_COLOR_BAR); - setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT); - - /* create graphics context on screen with default font color */ - screens[i].bar_gc = XCreateGC(display, screens[i].root, 0, - &gcv); - - XSetForeground(display, screens[i].bar_gc, - screens[i].c[SWM_S_COLOR_BAR_FONT].color); - - /* set default cursor */ - XDefineCursor(display, screens[i].root, - XCreateFontCursor(display, XC_left_ptr)); - - /* init all workspaces */ - /* XXX these should be dynamically allocated too */ - for (j = 0; j < SWM_WS_MAX; j++) { - ws = &screens[i].ws[j]; - ws->idx = j; - ws->name = NULL; - ws->focus = NULL; - ws->r = NULL; - ws->old_r = NULL; - TAILQ_INIT(&ws->winlist); - TAILQ_INIT(&ws->unmanagedlist); - - for (k = 0; layouts[k].l_stack != NULL; k++) - if (layouts[k].l_config != NULL) - layouts[k].l_config(ws, - SWM_ARG_ID_STACKINIT); - ws->cur_layout = &layouts[0]; - ws->cur_layout->l_string(ws); - } - - scan_xrandr(i); - - if (xrandr_support) - XRRSelectInput(display, screens[i].root, - RRScreenChangeNotifyMask); - } -} - -void -setup_globals(void) -{ - if ((bar_fonts = strdup(SWM_BAR_FONTS)) == NULL) - err(1, "setup_globals: strdup: failed to allocate memory."); - - if ((spawn_term[0] = strdup("xterm")) == NULL) - err(1, "setup_globals: strdup: failed to allocate memory."); - - if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL) - err(1, "setup_globals: strdup: failed to allocate memory."); -} - -void -workaround(void) -{ - int i; - Atom netwmcheck, netwmname, utf8_string; - Window root, win; - - /* work around sun jdk bugs, code from wmname */ - netwmcheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); - netwmname = XInternAtom(display, "_NET_WM_NAME", False); - utf8_string = XInternAtom(display, "UTF8_STRING", False); - for (i = 0; i < ScreenCount(display); i++) { - root = screens[i].root; - win = XCreateSimpleWindow(display,root, 0, 0, 1, 1, 0, - screens[i].c[SWM_S_COLOR_UNFOCUS].color, - screens[i].c[SWM_S_COLOR_UNFOCUS].color); - - XChangeProperty(display, root, netwmcheck, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&win,1); - XChangeProperty(display, win, netwmcheck, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&win,1); - XChangeProperty(display, win, netwmname, utf8_string, 8, - PropModeReplace, (unsigned char*)"LG3D", strlen("LG3D")); - } -} - -int -main(int argc, char *argv[]) -{ - struct swm_region *r, *rr; - struct ws_win *winfocus = NULL; - struct timeval tv; - union arg a; - char conf[PATH_MAX], *cfile = NULL; - struct stat sb; - XEvent e; - int xfd, i; - fd_set rd; - struct sigaction sact; - - start_argv = argv; - warnx("Welcome to scrotwm V%s Build: %s", SCROTWM_VERSION, buildstr); - if (!setlocale(LC_CTYPE, "") || !setlocale(LC_TIME, "") || - !XSupportsLocale()) - warnx("no locale support"); - - if (!X_HAVE_UTF8_STRING) - warnx("no UTF-8 support"); - - if (!(display = XOpenDisplay(0))) - errx(1, "can not open display"); - - if (active_wm()) - errx(1, "other wm running"); - - /* handle some signals */ - bzero(&sact, sizeof(sact)); - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; - sact.sa_handler = sighdlr; - sigaction(SIGINT, &sact, NULL); - sigaction(SIGQUIT, &sact, NULL); - sigaction(SIGTERM, &sact, NULL); - sigaction(SIGHUP, &sact, NULL); - - sact.sa_handler = sighdlr; - sact.sa_flags = SA_NOCLDSTOP; - sigaction(SIGCHLD, &sact, NULL); - - astate = XInternAtom(display, "WM_STATE", False); - aprot = XInternAtom(display, "WM_PROTOCOLS", False); - adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); - takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False); - a_wmname = XInternAtom(display, "WM_NAME", False); - a_netwmname = XInternAtom(display, "_NET_WM_NAME", False); - a_utf8_string = XInternAtom(display, "UTF8_STRING", False); - a_string = XInternAtom(display, "STRING", False); - a_swm_iconic = XInternAtom(display, "_SWM_ICONIC", False); - - /* look for local and global conf file */ - pwd = getpwuid(getuid()); - if (pwd == NULL) - errx(1, "invalid user: %d", getuid()); - - setup_globals(); - setup_screens(); - setup_keys(); - setup_quirks(); - setup_spawn(); - - /* load config */ - snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE); - if (stat(conf, &sb) != -1) { - if (S_ISREG(sb.st_mode)) - cfile = conf; - } else { - /* try global conf file */ - snprintf(conf, sizeof conf, "/etc/%s", SWM_CONF_FILE); - if (!stat(conf, &sb)) - if (S_ISREG(sb.st_mode)) - cfile = conf; - } - - /* load conf (if any) and refresh font color in bar graphics contexts */ - if (cfile && conf_load(cfile, SWM_CONF_DEFAULT) == 0) - for (i = 0; i < ScreenCount(display); ++i) - XSetForeground(display, screens[i].bar_gc, - screens[i].c[SWM_S_COLOR_BAR_FONT].color); - - setup_ewmh(); - /* set some values to work around bad programs */ - workaround(); - /* grab existing windows (before we build the bars) */ - grab_windows(); - - if (getenv("SWM_STARTED") == NULL) - setenv("SWM_STARTED", "YES", 1); - - /* setup all bars */ - for (i = 0; i < ScreenCount(display); i++) - TAILQ_FOREACH(r, &screens[i].rl, entry) { - if (winfocus == NULL) - winfocus = TAILQ_FIRST(&r->ws->winlist); - bar_setup(r); - } - - unfocus_all(); - - grabkeys(); - stack(); - if (focus_mode == SWM_FOCUS_DEFAULT) - drain_enter_notify(); - - xfd = ConnectionNumber(display); - while (running) { - while (XPending(display)) { - XNextEvent(display, &e); - if (running == 0) - goto done; - if (e.type < LASTEvent) { - DNPRINTF(SWM_D_EVENTQ ,"XEvent: handled: %s, " - "window: 0x%lx, type: %s (%d), %d remaining" - "\n", YESNO(handler[e.type]), - e.xany.window, geteventname(&e), - e.type, QLength(display)); - - if (handler[e.type]) - handler[e.type](&e); - } else { - DNPRINTF(SWM_D_EVENTQ, "XRandr Event: window: " - "0x%lx, type: %s (%d)\n", e.xany.window, - xrandr_geteventname(&e), e.type); - - switch (e.type - xrandr_eventbase) { - case RRScreenChangeNotify: - screenchange(&e); - break; - default: - break; - } - } - } - - /* if we are being restarted go focus on first window */ - if (winfocus) { - rr = winfocus->ws->r; - if (rr == NULL) { - /* not a visible window */ - winfocus = NULL; - continue; - } - /* move pointer to first screen if multi screen */ - if (ScreenCount(display) > 1 || outputs > 1) - XWarpPointer(display, None, rr->s[0].root, - 0, 0, 0, 0, X(rr), - Y(rr) + (bar_enabled ? bar_height : 0)); - - a.id = SWM_ARG_ID_FOCUSCUR; - focus(rr, &a); - winfocus = NULL; - continue; - } - - FD_ZERO(&rd); - FD_SET(xfd, &rd); - tv.tv_sec = 1; - tv.tv_usec = 0; - if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1) - if (errno != EINTR) - DNPRINTF(SWM_D_MISC, "select failed"); - if (restart_wm == 1) - restart(NULL, NULL); - if (search_resp == 1) - search_do_resp(); - if (running == 0) - goto done; - if (bar_alarm) { - bar_alarm = 0; - bar_update(); - } - } -done: - teardown_ewmh(); - bar_extra_stop(); - - for (i = 0; i < ScreenCount(display); ++i) - if (screens[i].bar_gc != NULL) - XFreeGC(display, screens[i].bar_gc); - - XFreeFontSet(display, bar_fs); - XCloseDisplay(display); - - return (0); -} diff --git a/scrotwm.conf b/scrotwm.conf deleted file mode 100644 index caca87e..0000000 --- a/scrotwm.conf +++ /dev/null @@ -1,84 +0,0 @@ -# PLEASE READ THE MAN PAGE BEFORE EDITING THIS FILE! -# http://opensource.conformal.com/cgi-bin/man-cgi?scrotwm - -# colors for focussed and unfocussed window borders -# NOTE: all colors in this file are in hex! see XQueryColor for examples -color_focus = red -color_unfocus = rgb:88/88/88 - -# bar settings -bar_enabled = 1 -bar_border_width = 1 -bar_border[1] = rgb:00/80/80 -bar_color[1] = black -bar_font_color[1] = rgb:a0/a0/a0 -bar_font = -*-terminus-medium-*-*-*-*-*-*-*-*-*-*-* -#bar_action = baraction.sh -#bar_delay = 1 -#bar_justify = left -#bar_at_bottom = 1 -stack_enabled = 1 -clock_enabled = 1 -#clock_format = %a %b %d %R %Z %Y -title_name_enabled = 0 -title_class_enabled = 0 -window_name_enabled = 0 -#verbose_layout = 1 -#focus_mode = default -#disable_border = 1 -#border_width = 1 -#urgent_enabled = 1 - -# spawn app -# program[term] = xterm -# program[screenshot_all] = screenshot.sh full -# program[screenshot_wind] = screenshot.sh window -# program[lock] = xlock -# program[initscr] = initscreen.sh -# program[menu] = dmenu_run -fn $bar_font -nb $bar_color -nf $bar_font_color -sb $bar_border -sf $bar_color -spawn_term = xterm - -# dialog box size ratio .3 >= r < 1 -dialog_ratio = 0.6 - -# Split a non-Xrandr dual head setup into one region per monitor -# (non-standard driver-based multihead is not seen by scrotwm) -# region = screen[1]:1280x1024+0+0 -# region = screen[1]:1280x1024+1280+0 - -# Launch applications in a workspace of choice -# autorun = ws[1]:xterm -# autorun = ws[2]:xxxterm http://www.openbsd.org - -# workspace layout -# layout = ws[1]:4:0:0:0:vertical -# layout = ws[2]:0:0:0:0:horizontal -# layout = ws[3]:0:0:0:0:fullscreen - -# mod key, (windows key is Mod4) (apple key on OSX is Mod2) -# modkey = Mod1 - -# Clear key bindings and load new key bindings from the specified file. -# This allows you to load pre-defined key bindings for your keyboard layout. -# keyboard_mapping = ~/.scrotwm_us.conf - -# quirks -# remove with: quirk[class:name] = NONE -#quirk[MPlayer:xv] = FLOAT + FULLSCREEN + FOCUSPREV -#quirk[OpenOffice.org 2.4:VCLSalFrame] = FLOAT -#quirk[OpenOffice.org 3.0:VCLSalFrame] = FLOAT -#quirk[OpenOffice.org 3.1:VCLSalFrame] = FLOAT -#quirk[Firefox-bin:firefox-bin] = TRANSSZ -#quirk[Firefox:Dialog] = FLOAT -#quirk[Gimp:gimp] = FLOAT + ANYWHERE -#quirk[XTerm:xterm] = XTERM_FONTADJ -#quirk[xine:Xine Window] = FLOAT + ANYWHERE -#quirk[Xitk:Xitk Combo] = FLOAT + ANYWHERE -#quirk[xine:xine Panel] = FLOAT + ANYWHERE -#quirk[Xitk:Xine Window] = FLOAT + ANYWHERE -#quirk[xine:xine Video Fullscreen Window] = FULLSCREEN + FLOAT -#quirk[pcb:pcb] = FLOAT - -# EXAMPLE: define firefox program and bind to key -# program[firefox] = firefox http://scrotwm.org/ -# bind[firefox] = MOD+Shift+b diff --git a/scrotwm_cz.conf b/scrotwm_cz.conf deleted file mode 100644 index 37baeb7..0000000 --- a/scrotwm_cz.conf +++ /dev/null @@ -1,74 +0,0 @@ -# Key bindings for Czech Republic (cz) keyboards -# unbind with: bind[] = -bind[cycle_layout] = MOD+space -bind[flip_layout] = MOD+Shift+backslash -bind[stack_reset] = MOD+Shift+space -bind[master_shrink] = MOD+h -bind[master_grow] = MOD+l -bind[master_add] = MOD+comma -bind[master_del] = MOD+period -bind[stack_inc] = MOD+Shift+comma -bind[stack_dec] = MOD+Shift+period -bind[swap_main] = MOD+Return -bind[focus_next] = MOD+j -bind[focus_prev] = MOD+k -bind[swap_next] = MOD+Shift+j -bind[swap_prev] = MOD+Shift+k -bind[spawn_term] = MOD+Shift+Return -bind[menu] = MOD+p -bind[quit] = MOD+Shift+q -bind[restart] = MOD+q -bind[focus_main] = MOD+m -bind[ws_1] = MOD+plus -bind[ws_2] = MOD+ecaron -bind[ws_3] = MOD+scaron -bind[ws_4] = MOD+ccaron -bind[ws_5] = MOD+rcaron -bind[ws_6] = MOD+zcaron -bind[ws_7] = MOD+yacute -bind[ws_8] = MOD+aacute -bind[ws_9] = MOD+iacute -bind[ws_10] = MOD+eacute -bind[ws_next] = MOD+Right -bind[ws_prev] = MOD+Left -bind[ws_next_all] = MOD+Up -bind[ws_prev_all] = MOD+Down -bind[ws_prior] = MOD+a -bind[screen_next] = MOD+Shift+Right -bind[screen_prev] = MOD+Shift+Left -bind[mvws_1] = MOD+Shift+plus -bind[mvws_2] = MOD+Shift+ecaron -bind[mvws_3] = MOD+Shift+scaron -bind[mvws_4] = MOD+Shift+ccaron -bind[mvws_5] = MOD+Shift+rcaron -bind[mvws_6] = MOD+Shift+zcaron -bind[mvws_7] = MOD+Shift+yacute -bind[mvws_8] = MOD+Shift+aacute -bind[mvws_9] = MOD+Shift+iacute -bind[mvws_10] = MOD+Shift+eacute -bind[bar_toggle] = MOD+b -bind[focus_next] = MOD+Tab -bind[focus_prev] = MOD+Shift+Tab -bind[wind_kill] = MOD+Shift+x -bind[wind_del] = MOD+x -bind[screenshot_all] = MOD+s -bind[screenshot_wind] = MOD+Shift+s -bind[float_toggle] = MOD+t -bind[version] = MOD+Shift+v -bind[lock] = MOD+Shift+Delete -bind[initscr] = MOD+Shift+i -bind[iconify] = MOD+w -bind[uniconify] = MOD+Shift+w -bind[raise_toggle] = MOD+Shift+r -bind[button2] = MOD+v -bind[width_shrink] = MOD+equal -bind[width_grow] = MOD+dead_acute -bind[height_shrink] = MOD+Shift+equal -bind[height_grow] = MOD+Shift+dead_acute -bind[move_left] = MOD+uacute -bind[move_right] = MOD+parenright -bind[move_up] = MOD+Shift+uacute -bind[move_down] = MOD+Shift+parenright -bind[name_workspace] = MOD+Shift+slash -bind[search_workspace] = MOD+slash -bind[search_win] = MOD+f diff --git a/scrotwm_es.1 b/scrotwm_es.1 deleted file mode 100644 index 9ae026f..0000000 --- a/scrotwm_es.1 +++ /dev/null @@ -1,746 +0,0 @@ -.\" Copyright (c) 2009 Marco Peereboom -.\" Copyright (c) 2009 Darrin Chandler -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate$ -.Dt SCROTWM 1 -.Os -.Sh NOMBRE -.Nm scrotwm -.Nd es un manejador de ventanas para X11 -.Sh SYNOPSIS -.Nm scrotwm -.Sh DESCRIPCIÓN -.Nm -es un manejador de ventanas super minimalista para X11. Intenta no superponer -las ventanas para que las mismas puedan usarse de manera eficiente y para cosas mas importantes. -Tiene configuraciones normales y no requiere que sepas un lenguaje de -programacion para configurarlo. Esta escrito por hackers para hackers y apunta -a ser pequeño, compacto y rápido. -.Pp -Cuando -.Nm -inicia, lo primero que hace es leer el archivo de configuracion, -.Pa scrotwm.conf . -Ver -.Sx ARCHIVOS DE CONFIGURACIÓN -. -.Pp -La siguiente anotacion se usa a través de esta pagina: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It Cm M -Meta -.It Cm S -Shift -.It Aq Cm Name -Nombre de tecla -.It Cm M1 -Boton 1 del mouse -.It Cm M3 -Boton 3 del mouse -.El -.Pp -.Nm -es muy simple de usar. -La mayoria de las acciones se hacen con los mapeos (bindings) de mouse -o teclado. -Ver la sección de -.Sx BINDINGS -para las personalizaciones y configuraciones por defecto. -.Sh ARCHIVOS DE CONFIGURACIÓN -.Nm -primero trata de abrir el archivo por defecto en el directorio del usuario, -.Pa ~/.scrotwm.conf . -Si ese archivo no esta disponible, -luego trata de abrir el archivo global de configuracion -.Pa /etc/scrotwm.conf . -.Pp -El formato del archivo es \*(Lttecla\*(Gt = \*(Ltconfiguracion\*(Gt. -Por ejemplo: -.Pp -.Dl color_focus = red -.Pp -Habilitamos o deshabilitamos la opción usando 1 o 0 respectivamente. -.Pp -El archivo soporta las siguientes palabras clave: -.Pp -.Bl -tag -width "title_class_enabledXXX" -offset indent -compact -.It Cm autorun -Inicia una aplicacion en un escritorio en particular al primer inicio. -Definido por el formato ws[]:aplicacion, ej. ws[2]:xterm lanza -xterm en el escritorio 2. -.It Cm color_focus -Color del borde de la ventana en foco. -.It Cm color_unfocus -Color del borde de la ventana fuera de foco. -.It Cm bar_enabled -Habilitar o deshabilitar la barra de estado. -.It Cm bar_border Ns Bq Ar x -Color del borde de la barra de estado en pantalla. -.Ar x . -.It Cm bar_border_width -Setea el grosor de la barra de estado en pixels. -Deshabilitado seteando 0. -.It Cm bar_color Ns Bq Ar x -Color de la ventana de la barra de estado en pantalla. -.Ar x . -.It Cm bar_font_color Ns Bq Ar x -Color de la fuente en la barra de estado en pantalla. -.Ar x . -.It Cm bar_font -Fuente de la barra de estado. -.It Cm bar_action -Scripts externos con populares agregados de información para la barra -de estado, como la vida de la bateria. -.It Cm bar_delay -Frecuencia de actualización, en segundos, de los scripts de la barra de -estado. -.It Cm bar_at_bottom -Puedes posicionar la statusbar en la parte inferior de la pantalla. -.It Cm stack_enabled -Habilitar o deshabilitar mostrar el algoritmo de apilamiento en la barra -de estado. -.It Cm clock_enabled -Habilitar o deshabilitar el reloj en la barra de estado, deshabilitado -por defecto con un 0, para usar el reloj de la barra de estado -(bar_action) -.Pa bar_action -script. -.It Cm dialog_ratio -Algunas aplicaciones tienen ventanas de dialogo muy pequeñas como para -ser usables. Este relación (ratio) es el tamaño de la pantalla, por -ejemplo 0.6 es 60% del tamaño físico de la pantalla. -.It Cm layout -Selecciona una disposicion para usar en el primer inicio. -Definido con el formato -ws[idx]:master_grow:master_add:stack_inc:layout:always_raise:stack_mode, -ej. -ws[2]:-4:0:1:0:horizontal setea el escritorio 2 en horizontal, el stack -principal y reduce 4 puntos agregando una ventana al stack, mientras -mantiene el comportamiento de ventanas flotantes. -Modos posible de stack_mode -.Pa vertical , -.Pa horizontal -and -.Pa fullscreen . -.Pp -Ver -.Pa master_grow , -.Pa master_shrink , -.Pa master_add , -.Pa master_del , -.Pa stack_inc , -.Pa stack_del , -y -.Pa always_raise -para mas informacion. -Tenga en cuenta que las opciones de stack son complicados y tienen -efectos secundarios. -Uno debe familiarizarse con estos comandos antes de experimentar con la -opcion -.Pa layout -.Pp -Esta opcion no necesita un reinicio. -.It Cm region -Acomodar una region personalizada, removiendo cualquier autodeteción de -regiones que ocupe el espacio en la pantalla. -Definiendo el formato screen[]:WIDTHxHEIGHT+X+Y, -e.g.\& screen[1]:800x1200+0+0. -.It Cm term_width -Setear un ancho minimo preferido para la terminal. -Si el valor es mayor que 0, -.Nm -intentará ajustar el tamaño de la fuente de la terminal para mantener -el ancho de la terminal por encima de este número cuando la ventana -cambia de tamaño. -Actualmente solo es soportado por -.Xr xterm 1 -El binario de -.Xr xterm 1 -no debe ser un setuid o setgid, que no sea el que viene por defecto en -la mayoria de los sistemas. -Los usuarios pueden necesitar setear program[term] (ver la sección -.Sx PROGRAMAS -) para usar una copia alternativa del binario de -.Xr xterm 1 -sin el seteo del setgid. -.It Cm title_class_enabled -Habilitar o deshabilitar la clase de ventana en la barre de estado. -Habilitado seteando 1 -.It Cm title_name_enabled -Habilitar o deshabilita el titulo de la ventana en la barra de estado. -Habilitado seteando 1 -.It Cm urgent_enabled -Habilitar o deshabilitar el aviso de urgencia. -Tenga en cuenta que muchos emuladores de terminal requieren de este -parametro habilitado para que funcione. -En xterm, por ejemplo, hay que agregar la siguiente linea -.Pa xterm.urgentOnBell: true -to -.Pa .Xdefaults . -.It Cm window_name_enabled -Habilitar o deshabilita el nombre de la ventana en la barra de estado. -Habilitado seteando 1 -.It Cm verbose_layout -Habilitar o deshabilita la notificacion del area principal y el -stack en la barra de estado. -Habilitado seteandolo a 1. -.It Cm modkey -Cambiar mod key. -Mod1 generalmente es la tecla ALT y Mod4 la tecla de windows en una PC. -.It Cm focus_mode -Usando el valor de -.Pa follow_cursor -puedes hacer que el manejador de ventanas -se enfoque en la ventana cuando el cursor pase por arriba de las mismas o -bien cambiando de estacion de trabajo. -.It Cm disable_border -Remueve el borde de una sola ventana cuando la barra de estado esta desactivada. -.It Cm border_width -Setea el grosor del borde de la ventana en pixels. -Deshabilitar todos los bordes seteandolo a 0. -.It Cm program Ns Bq Ar p -Definir una nueva accion para ejecutar un programa. -.Ar p . -Ver la sección de -.Sx PROGRAMAS -.It Cm bind Ns Bq Ar x -Combinación de teclas para una acción -.Ar x . -Ver la sección -.Sx BINDINGS -.It Cm quirk Ns Bq Ar c:n -Agregar un "quirk" (o forzados) para ventanas con clase -.Ar c -y nombre -.Ar n . -Ver la sección -.Sx QUIRKS -.El -.Pp -Los colores deben ser especificados por la especificación -.Xr XQueryColor 3 -y las fuentes por la especificación -.Xr XQueryFont 3 -.Sh PROGRAMAS -.Nm -te permite definir acciones personales para lanzar los programas que -quieras y luego obligar a la misma con una función de acciones. -Ver la sección -.Sx BINDINGS -.Pp -Los programas por defecto se describen acá: -.Pp -.Bl -tag -width "screenshot_wind" -offset indent -compact -.It Cm term -xterm -.It Cm screenshot_all -screenshot.sh completo -.It Cm screenshot_wind -screenshot.sh por ventana -.It Cm lock -xlock -.It Cm initscr -initscreen.sh -.It Cm menu -dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color -.El -.Pp -Los programas en la configuración personal, se especifican aca: -.Pp -.Dl program[] = [ [... ]] -.Pp -.Aq nombre -es un identificador, no genera conflictos con ninguna accion o palabra -clave, -.Aq progpath -es la ruta al programa, y -.Aq arg -es ninguno o mas de un argumento para el programa. -.Pp -Las siguientes variables de configuracion en -.Nm -(ver -.Sx ARCHIVOS DE CONFIGURACIÓN -), -y pueden ser usadas en los campos de -.Aq arg -como asi tambien sustituidas por valores al momento del inicio de un -programa: -.Pp -.Bl -tag -width "$bar_font_color" -offset indent -compact -.It Cm $bar_border -.It Cm $bar_color -.It Cm $bar_font -.It Cm $bar_font_color -.It Cm $color_focus -.It Cm $color_unfocus -.El -.Pp -Ejemplo: -.Bd -literal -offset indent -program[ff] = /usr/local/bin/firefox http://scrotwm.com.ar/ -bind[ff] = Mod+f # Ahora Mod+F inicia firefox -.Ed -.Pp -Para deshacer lo anterior: -.Bd -literal -offset indent -bind[] = Mod+f -program[ff] = -.Ed -.Sh BINDINGS -.Nm -provee muchas funciones (o acciones) accesibles por medio de la -asignación (bindings) de teclas o el mouse. -.Pp -Las corrientes asignaciones (bindings) del mouse son: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M1 -Enfoco una ventana -.It Cm M-M1 -Muevo una ventana -.It Cm M-M3 -Redimenciono una ventana -.It Cm M-S-M3 -Redimenciono una ventana hasta que quede centrada -.El -.Pp -Las corrientes asignaciones (bindings) de teclas son: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M-S- Ns Aq Cm Return -term -.It Cm M-p -menu -.It Cm M-S-q -quit -.It Cm M-q -restart -.Nm -.It Cm M- Ns Aq Cm Space -cycle_layout -.It Cm M-S- Ns Aq Cm Space -reset_layout -.It Cm M-h -master_shrink -.It Cm M-l -master_grow -.It Cm M-, -master_add -.It Cm M-. -master_del -.It Cm M-S-, -stack_inc -.It Cm M-S-. -stack_del -.It Cm M- Ns Aq Cm Return -swap_main -.It Xo -.Cm M-j , -.Cm M- Ns Aq Cm TAB -.Xc -focus_next -.It Xo -.Cm M-k , -.Cm M-S- Ns Aq Cm TAB -.Xc -focus_prev -.It Cm M-m -focus_main -.It Cm M-S-j -swap_next -.It Cm M-S-k -swap_prev -.It Cm M-b -bar_toggle -.It Cm M-x -wind_del -.It Cm M-S-x -wind_kill -.It Cm M- Ns Aq Ar n -.Ns ws_ Ns Ar n -.It Cm M-S- Ns Aq Ar n -.Ns mvws_ Ns Ar n -.It Cm M- Ns Aq Cm Right -ws_next -.It Cm M- Ns Aq Cm Left -ws_prev -.It Cm M-a -ws_prior -.It Cm M-S- Ns Aq Cm Right -screen_next -.It Cm M-S- Ns Aq Cm Left -screen_prev -.It Cm M-s -screenshot_all -.It Cm M-S-s -screenshot_wind -.It Cm M-S-v -version -.It Cm M-t -float_toggle -.It Cm M-S Aq Cm Delete -lock -.It Cm M-S-i -initscr -.It Cm M-w -iconify -.It Cm M-S-w -uniconify -.It Cm M-S-r -always_raise -.It Cm M-v -button2 -.It Cm M-- -width_shrink -.It Cm M-= -width_grow -.It Cm M-S- -height_shrink -.It Cm M-S-= -height_grow -.It Cm M-[ -move_left -.It Cm M-] -move_right -.It Cm M-S-[ -move_up -.It Cm M-S-] -move_down -.El -.Pp -El nombre de las acciónes descripta a continuación: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm term -Ejecutar una terminal -(ver -.Sx PROGRAMAS -) -.It Cm menu -Menu -(ver -.Sx PROGRAMAS -) -.It Cm quit -Salir -.Nm -.It Cm restart -Reiniciar -.Nm -.It Cm cycle_layout -Disposición de las ventanas -.It Cm reset_layout -Reiniciar la disposición de las ventanas -.It Cm master_shrink -Achicar la region principal -.It Cm master_grow -Agrandar la region principal -.It Cm master_add -Agregar una ventana a la region principal -.It Cm master_del -Quitar una ventana de la region principal -.It Cm stack_inc -Agregar columnas/filas a las pilas -.It Cm stack_del -Quitar columnas/filas de las pilas -.It Cm swap_main -Mover la ventana corriente a la region principal -.It Cm focus_next -Enfocar la proxima ventana en la estación de trabajo -.It Cm focus_prev -Enfocar la anterior ventana en la estación de trabajo -.It Cm focus_main -Enfocar en la ventana principal de la estación de trabajo -.It Cm swap_next -Ejecutar con la siguiente ventana en la estación de trabajo -.It Cm swap_prev -Ejecutar con la anterior ventana en la estación de trabajo -.It Cm bar_toggle -Cambiar la barra de estado en todas las estaciones de trabajo -.It Cm wind_del -Borrar la ventana corriente en la estación de trabajo -.It Cm wind_kill -Destruir la ventana corriente en la estación de trabajo -.It Cm ws_ Ns Ar n -Cambiar entre estaciones de trabajo -.Ar n , -donde -.Ar n -es 1 por 10 -.It Cm mvws_ Ns Ar n -Mover la ventana corriente a una estación de trabajo -.Ar n , -donde -.Ar n -es 1 por 10 -.It Cm ws_next -Cambiar a la proxima estación de trabajo con una ventana en ella -.It Cm ws_prev -Cambiar a la anterior estación de trabajo con una ventana en ella -.It Cm screen_next -Mover el puntero a la proxima region -.It Cm screen_prev -Mover el puntero a la anterior region -.It Cm screenshot_all -Tomar una captura de pantalla de todo la pantalla (si esta habilitado) -(ver -.Sx PROGRAMAS -) -.It Cm screenshot_wind -Tomar una captura de pantalla de la ventana seleccionada (si esta habilitado) -(ver -.Sx PROGRAMAS -) -.It Cm version -Mostrar la version en la barra de estado -.It Cm float_toggle -Mostar la ventana en foco entre las flotantes y acomodadas -.It Cm lock -Bloquear pantalla -(ver -.Sx PROGRAMAS -) -.It Cm initscr -Reiniciar la pantalla -(ver -.Sx PROGRAMAS -) -.It Cm iconify -Minimiza (unmap) la ventana en foco. -.It Cm uniconify -Maximiza (map) la ventana seleccionada por dmenu. -.It Cm always_raise -Cuando se establece las ventanas en cascada se esconden las -ventanas flotantes. -.It Cm button2 -Falsifica el boton del medio del mouse. -.It Cm width_shrink -Reducir el ancho de una ventana flotante. -.It Cm width_grow -Agranda el ancho de una ventana flotante. -.It Cm height_shrink -Reducir la altura de una ventana flotante. -.It Cm height_grow -Agranda la altura de una ventana flotante. -.It Cm move_left -Mueve la ventana flotante un paso a la izquierda. -.It Cm move_right -Mueve la ventana flotante un paso a la derecha. -.It Cm move_up -Mueve la ventana flotante un paso arriba. -.It Cm move_down -Mueve la ventana flotante un paso abajo. -.El -.Pp -Personalizar mapeos (bindings) en el archivo de configuración: -.Pp -.Dl bind[] = -.Pp -.Aq accion -una de las acciones listadas (o ninguna) y -.Aq teclas -una o mas teclas modificadas (puede ser ninguna tambien) -(MOD, Mod1, Shift, etc.) y una o mas teclas normales -(b, barra espaciadora, etc.), separadas por un "+". -Por ejemplo: -.Bd -literal -offset indent -bind[reset] = Mod4+q # combinación Tecla de Windows + q reinicia -bind[] = Mod1+q # des-hace la combinación Alt + q -.Ed -.Pp -Multiples combinaciones de teclas pueden hacer lo mismo. -.Sh QUIRKS -.Nm -te da "quirks" (o forzados) ventanas que tienen que ser tratas de manera especial, -como por ejemplo, popups, aplicaciones de pantalla completa, etc. -.Pp -Los "quirks" (o forzados) por defecto son: -.Pp -.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact -.It Firefox\-bin:firefox\-bin -TRANSSZ -.It Firefox:Dialog -FLOAT -.It Gimp:gimp -FLOAT + ANYWHERE -.It MPlayer:xv -FLOAT + FULLSCREEN -.It OpenOffice.org 2.4:VCLSalFrame -FLOAT -.It OpenOffice.org 3.1:VCLSalFrame -FLOAT -.It pcb:pcb -FLOAT -.It xine:Xine Window -FLOAT + ANYWHERE -.It xine:xine Panel -FLOAT + ANYWHERE -.It xine:xine Video Fullscreen Window -FULLSCREEN + FLOAT -.It Xitk:Xitk Combo -FLOAT + ANYWHERE -.It Xitk:Xine Window -FLOAT + ANYWHERE -.It XTerm:xterm -XTERM_FONTADJ -.El -.Pp -Los "quirks" (o forzados) se describen a continuación: -.Pp -.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact -.It FLOAT -Esta ventana no tiene que ser acomodada, pero le permitimos flotar libremente. -.It TRANSSZ -Ajusta el tamaño de las ventanas transitorias que son demasiado pequeñas utilizando dialog_ratio -(ver -.Sx ARCHIVOS DE CONFIGURACIÓN ) . -.It ANYWHERE -Permite que la ventana se ponga donde quiera. -.It XTERM_FONTADJ -Ajusta las fuentes de xterm cuando se redimenciona. -.It FULLSCREEN -Quita el borde para permitir las ventanas en pantalla completa. -.It FOCUSPREV -El enfoque de salida fuerza la solicitud de aplicacisn que -anteriormente se centraba en la aplicacion anterior del stack. -.El -.Pp -Las configuraciones de "quirks" (o forzados) en el archivo de configuración se ven a continuación: -.Pp -.Dl quirk[:] = [ + ... ] -.Pp -.Aq clases -y -.Aq nombre -especifica la ventana en la cual el "quirk(s)" (o forzados) se aplica, y -.Aq quirk -es uno de los "quirks" (o forzados) de la lista. -Por ejemplo: -.Bd -literal -offset indent -quirk[MPlayer:xv] = FLOAT + FULLSCREEN # dejamos que mplayer funcione libremente -quirk[pcb:pcb] = NONE # borramos el quirk existente -.Ed -.Pp -Podes obtener -.Aq clases -y -.Aq nombre -corriendo el programa xprop(1) y luego clickear en la ventana que quieras. -En el proximo ejemplo, podremos verlo en acción con una ventana de Firefox: -.Bd -literal -offset indent -$ xprop | grep WM_CLASS -WM_CLASS(STRING) = "Navigator", "Firefox" -.Ed -.Sh EWMH -.Nm -parcialmente implementa los Consejos de ventana extendido Manager (EWMH) especificacion. -Esto permite el control de las ventanas, asi como -.Nm -si a partir de scripts y programas externos. Esto se logra mediante -.Nm -responder a ciertos eventos ClientMessage. Desde la terminal de estos eventos -se puede enviar facilmente el uso de herramientas tales como -.Xr wmctrl 1 -y -.Xr xdotool 1 . -para el -formato real de estos eventos ClientMessage, consulte la especificacion EWMH. -.Pp -La Identificacion de la ventana actualmente enfocada se almacena en el _NET_ACTIVE_WINDOW -propiedad de la ventana raiz. Esto puede ser usado por ejemplo para recuperar el -titulo de la ventana activa con -.Xr xprop 1 -y -.Xr grep 1 : -.Bd -literal -offset indent -$ WINDOWID=`xprop \-root _NET_ACTIVE_WINDOW | grep \-o "0x.*"` -$ xprop \-id $WINDOWID WM_NAME | grep \-o "\\".*\\"" -.Ed -.Pp -Una ventana se puede enfocar mediante el envio de un mensaje del cliente _NET_ACTIVE_WINDOW -a la ventana principal. Por ejemplo, usando -.Xr wmctrl 1 -para enviar el mensaje -(suponiendo que 0x4a0000b es el ID de la ventana para ser especifico): -.Bd -literal -offset indent -$ wmctrl \-i \-a 0x4a0000b -.Ed -.Pp -Ventanas se pueden cerrar mediante el envmo de un mensaje del cliente _NET_CLOSE_WINDOW -a la ventana principal. Por ejemplo, usando -.Xr wmctrl 1 -para enviar el mensaje -(suponiendo que 0x4a0000b es el ID de la ventana se cierre): -.Bd -literal -offset indent -$ wmctrl \-i \-c 0x4a0000b -.Ed -.Pp -Las ventanas se pueden flotar y flotar sin-mediante la adicion o eliminacion de la -_NET_WM_STATE_ABOVE atom desde _NET_WM_STATE la propiedad de la ventana -Esto se puede lograr mediante el envio de un mensaje a los clientes _NET_WM_STATE -raiz de la ventana. Por ejemplo, el siguiente cambia el estado de la flota. -.Xr wmctrl 1 -para enviar el mensaje (suponiendo que 0x4a0000b es el ID de la ventana flotante -o no-flotante): -.Bd -literal -offset indent -$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE -.Ed -.Pp -Ventanas flotantes tambien se puede cambiar el tamano y movido por el envio de un -_NET_MOVERESIZE_WINDOW Mensaje del cliente de la ventana raiz. Por ejemplo, -uso -.Xr wmctrl 1 -para enviar el mensaje (suponiendo que 0x4a0000b es el ID de -la ventana a redimensionar / mover): -.Bd -literal -offset indent -$ wmctrl \-i \-r 0x4a0000b \-e 0,100,50,640,480 -.Ed -.Pp -Esto mueve la ventana de (100,50) y cambia el tamaqo a 640x480. -.Pp -Todos los eventos _NET_MOVERESIZE_WINDOW recibido por las ventanas apiladas se ignoran. -.Pp -.Sh SIGNALS -Enviando -.Nm -una senal de HUP reinicia scrotwm. -.Pp -.Sh ARCHIVOS -.Bl -tag -width "/etc/scrotwm.confXXX" -compact -.It Pa ~/.scrotwm.conf -.Nm -archivo de configuración especifico del usuario. -.It Pa /etc/scrotwm.conf -.Nm -configuraciones globales. -.El -.Sh HISTORIA -.Nm -fue inspirado en xmonad y dwm. -.Sh AUTORES -.An -nosplit -.Pp -.Nm -fue escrito por -.An Marco Peereboom Aq marco@peereboom.us , -.An Ryan Thomas McBride Aq mcbride@countersiege.com -and -.An Darrin Chandler Aq dwchandler@stilyagin.com . -.Sh BUGS -Actualmente el menu, se llama con -.Cm M-p , -depende de dmenu. diff --git a/scrotwm_es.conf b/scrotwm_es.conf deleted file mode 100644 index b585381..0000000 --- a/scrotwm_es.conf +++ /dev/null @@ -1,74 +0,0 @@ -# Key bindings for Spanish (es) keyboards -# unbind with: bind[] = -bind[cycle_layout] = MOD+space -bind[flip_layout] = MOD+Shift+backslash -bind[stack_reset] = MOD+Shift+space -bind[master_shrink] = MOD+h -bind[master_grow] = MOD+l -bind[master_add] = MOD+comma -bind[master_del] = MOD+period -bind[stack_inc] = MOD+Shift+comma -bind[stack_dec] = MOD+Shift+period -bind[swap_main] = MOD+Return -bind[focus_next] = MOD+j -bind[focus_prev] = MOD+k -bind[swap_next] = MOD+Shift+j -bind[swap_prev] = MOD+Shift+k -bind[spawn_term] = MOD+Shift+Return -bind[menu] = MOD+p -bind[quit] = MOD+Shift+q -bind[restart] = MOD+q -bind[focus_main] = MOD+m -bind[ws_1] = MOD+1 -bind[ws_2] = MOD+2 -bind[ws_3] = MOD+3 -bind[ws_4] = MOD+4 -bind[ws_5] = MOD+5 -bind[ws_6] = MOD+6 -bind[ws_7] = MOD+7 -bind[ws_8] = MOD+8 -bind[ws_9] = MOD+9 -bind[ws_10] = MOD+0 -bind[ws_next] = MOD+Right -bind[ws_prev] = MOD+Left -bind[ws_next_all] = MOD+Up -bind[ws_prev_all] = MOD+Down -bind[ws_prior] = MOD+a -bind[screen_next] = MOD+Shift+Right -bind[screen_prev] = MOD+Shift+Left -bind[mvws_1] = MOD+Shift+1 -bind[mvws_2] = MOD+Shift+2 -bind[mvws_3] = MOD+Shift+3 -bind[mvws_4] = MOD+Shift+4 -bind[mvws_5] = MOD+Shift+5 -bind[mvws_6] = MOD+Shift+6 -bind[mvws_7] = MOD+Shift+7 -bind[mvws_8] = MOD+Shift+8 -bind[mvws_9] = MOD+Shift+9 -bind[mvws_10] = MOD+Shift+0 -bind[bar_toggle] = MOD+b -bind[focus_next] = MOD+Tab -bind[focus_prev] = MOD+Shift+Tab -bind[wind_kill] = MOD+Shift+x -bind[wind_del] = MOD+x -bind[screenshot_all] = MOD+s -bind[screenshot_wind] = MOD+Shift+s -bind[float_toggle] = MOD+t -bind[version] = MOD+Shift+v -bind[lock] = MOD+Shift+Delete -bind[initscr] = MOD+Shift+i -bind[iconify] = MOD+w -bind[uniconify] = MOD+Shift+w -bind[raise_toggle] = MOD+Shift+r -bind[button2] = MOD+v -bind[width_shrink] = MOD+apostrophe -bind[width_grow] = MOD+exclamdown -bind[height_shrink] = MOD+Shift+apostrophe -bind[height_grow] = MOD+Shift+exclamdown -bind[move_left] = MOD+dead_grave -bind[move_right] = MOD+plus -bind[move_up] = MOD+Shift+dead_grave -bind[move_down] = MOD+Shift+plus -bind[name_workspace] = MOD+Shift+slash -bind[search_workspace] = MOD+slash -bind[search_win] = MOD+f diff --git a/scrotwm_fr.conf b/scrotwm_fr.conf deleted file mode 100644 index d56aabb..0000000 --- a/scrotwm_fr.conf +++ /dev/null @@ -1,74 +0,0 @@ -# Key bindings for French (fr) keyboards -# unbind with: bind[] = -bind[cycle_layout] = MOD+space -bind[flip_layout] = MOD+Shift+backslash -bind[stack_reset] = MOD+Shift+space -bind[master_shrink] = MOD+h -bind[master_grow] = MOD+l -bind[master_add] = MOD+comma -bind[master_del] = MOD+semicolon -bind[stack_inc] = MOD+Shift+comma -bind[stack_dec] = MOD+Shift+semicolon -bind[swap_main] = MOD+Return -bind[focus_next] = MOD+j -bind[focus_prev] = MOD+k -bind[swap_next] = MOD+Shift+j -bind[swap_prev] = MOD+Shift+k -bind[spawn_term] = MOD+Shift+Return -bind[menu] = MOD+p -bind[quit] = MOD+Shift+q -bind[restart] = MOD+q -bind[focus_main] = MOD+m -bind[ws_1] = MOD+ampersand -bind[ws_2] = MOD+eacute -bind[ws_3] = MOD+quotedbl -bind[ws_4] = MOD+apostrophe -bind[ws_5] = MOD+parenleft -bind[ws_6] = MOD+hyphen -bind[ws_7] = MOD+egrave -bind[ws_8] = MOD+underscore -bind[ws_9] = MOD+ccedilla -bind[ws_10] = MOD+agrave -bind[ws_next] = MOD+Right -bind[ws_prev] = MOD+Left -bind[ws_next_all] = MOD+Up -bind[ws_prev_all] = MOD+Down -bind[ws_prior] = MOD+a -bind[screen_next] = MOD+Shift+Right -bind[screen_prev] = MOD+Shift+Left -bind[mvws_1] = MOD+Shift+ampersand -bind[mvws_2] = MOD+Shift+eacute -bind[mvws_3] = MOD+Shift+quotedbl -bind[mvws_4] = MOD+Shift+apostrophe -bind[mvws_5] = MOD+Shift+parenleft -bind[mvws_6] = MOD+Shift+hyphen -bind[mvws_7] = MOD+Shift+egrave -bind[mvws_8] = MOD+Shift+underscore -bind[mvws_9] = MOD+Shift+ccedilla -bind[mvws_10] = MOD+Shift+agrave -bind[bar_toggle] = MOD+b -bind[focus_next] = MOD+Tab -bind[focus_prev] = MOD+Shift+Tab -bind[wind_kill] = MOD+Shift+x -bind[wind_del] = MOD+x -bind[screenshot_all] = MOD+s -bind[screenshot_wind] = MOD+Shift+s -bind[float_toggle] = MOD+t -bind[version] = MOD+Shift+v -bind[lock] = MOD+Shift+Delete -bind[initscr] = MOD+Shift+i -bind[iconify] = MOD+w -bind[uniconify] = MOD+Shift+w -bind[raise_toggle] = MOD+Shift+r -bind[button2] = MOD+v -bind[width_shrink] = MOD+minus -bind[width_grow] = MOD+equal -bind[height_shrink] = MOD+Shift+minus -bind[height_grow] = MOD+Shift+equal -bind[move_left] = MOD+ugrave -bind[move_right] = MOD+asterisk -bind[move_up] = MOD+Shift+ugrave -bind[move_down] = MOD+Shift+asterisk -bind[name_workspace] = MOD+Shift+slash -bind[search_workspace] = MOD+slash -bind[search_win] = MOD+f diff --git a/scrotwm_fr_ch.conf b/scrotwm_fr_ch.conf deleted file mode 100644 index f78c5bb..0000000 --- a/scrotwm_fr_ch.conf +++ /dev/null @@ -1,74 +0,0 @@ -# Key bindings for Swiss French (FR_CH) keyboards -# unbind with: bind[] = -bind[cycle_layout] = MOD+space -bind[flip_layout] = MOD+Shift+backslash -bind[stack_reset] = MOD+Shift+space -bind[master_shrink] = MOD+h -bind[master_grow] = MOD+l -bind[master_add] = MOD+comma -bind[master_del] = MOD+period -bind[stack_inc] = MOD+Shift+comma -bind[stack_dec] = MOD+Shift+period -bind[swap_main] = MOD+Return -bind[focus_next] = MOD+j -bind[focus_prev] = MOD+k -bind[swap_next] = MOD+Shift+j -bind[swap_prev] = MOD+Shift+k -bind[spawn_term] = MOD+Shift+Return -bind[menu] = MOD+p -bind[quit] = MOD+Shift+q -bind[restart] = MOD+q -bind[focus_main] = MOD+m -bind[ws_1] = MOD+1 -bind[ws_2] = MOD+2 -bind[ws_3] = MOD+3 -bind[ws_4] = MOD+4 -bind[ws_5] = MOD+5 -bind[ws_6] = MOD+6 -bind[ws_7] = MOD+7 -bind[ws_8] = MOD+8 -bind[ws_9] = MOD+9 -bind[ws_10] = MOD+0 -bind[ws_next] = MOD+Right -bind[ws_prev] = MOD+Left -bind[ws_next_all] = MOD+Up -bind[ws_prev_all] = MOD+Down -bind[ws_prior] = MOD+a -bind[screen_next] = MOD+Shift+Right -bind[screen_prev] = MOD+Shift+Left -bind[mvws_1] = MOD+Shift+1 -bind[mvws_2] = MOD+Shift+2 -bind[mvws_3] = MOD+Shift+3 -bind[mvws_4] = MOD+Shift+4 -bind[mvws_5] = MOD+Shift+5 -bind[mvws_6] = MOD+Shift+6 -bind[mvws_7] = MOD+Shift+7 -bind[mvws_8] = MOD+Shift+8 -bind[mvws_9] = MOD+Shift+9 -bind[mvws_10] = MOD+Shift+0 -bind[bar_toggle] = MOD+b -bind[focus_next] = MOD+Tab -bind[focus_prev] = MOD+Shift+Tab -bind[wind_kill] = MOD+Shift+x -bind[wind_del] = MOD+x -bind[screenshot_all] = MOD+s -bind[screenshot_wind] = MOD+Shift+s -bind[float_toggle] = MOD+t -bind[version] = MOD+Shift+v -bind[lock] = MOD+Shift+Delete -bind[initscr] = MOD+Shift+i -bind[iconify] = MOD+w -bind[uniconify] = MOD+Shift+w -bind[raise_toggle] = MOD+Shift+r -bind[button2] = MOD+v -bind[width_shrink] = MOD+minus -bind[width_grow] = MOD+egrave -bind[height_shrink] = MOD+Shift+minus -bind[height_grow] = MOD+Shift+egrave -bind[move_left] = MOD+eacute -bind[move_right] = MOD+agrave -bind[move_up] = MOD+Shift+eacute -bind[move_down] = MOD+Shift+agrave -bind[name_workspace] = MOD+Shift+apostrophe -bind[search_workspace] = MOD+apostrophe -bind[search_win] = MOD+f diff --git a/scrotwm_it.1 b/scrotwm_it.1 deleted file mode 100644 index 5121be5..0000000 --- a/scrotwm_it.1 +++ /dev/null @@ -1,755 +0,0 @@ -.\" Copyright (c) 2009 Marco Peereboom -.\" Copyright (c) 2009 Darrin Chandler -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate: September 15 2011 $ -.Dt SCROTWM 1 -.Os -.Sh NOME -.Nm scrotwm -.Nd gestore di finestre per X11 -.Sh SINTASSI -.Nm scrotwm -.Sh DESCRIZIONE -.Nm -? un gestore di finestre minimale che cerca di stare in disparte, in modo -che il prezioso spazio sullo schermo possa essere usato per cose pi? -importanti. Hai dei default sensati e non costringe l'utente ad imparare -un linguaggio di programmazione per configurarlo. ? stato scritto dagli -hacker per gli hacker e cerca di essere piccolo, compatto e veloce. -.Pp -Quando -.Nm -viene avviato, legge le impostazioni presenti nel file di configurazione -.Pa scrotwm.conf . -Vedere la sezione -.Sx FILE DI CONFIGURAZIONE -pi? sotto. -.Pp -In questa pagina di manuale viene usata la seguente notazione: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It Cm M -Meta -.It Cm S -Shift -.It Aq Cm Nome -Tasto nome -.It Cm M1 -Tasto 1 (sinistro) del mouse -.It Cm M3 -Tasto 3 (destro) del mouse -.El -.Pp -.Nm -? molto semplice da usare. La maggior parte delle operazioni vengono -svolte usando combinazioni di tasti sulla tastiera o sul mouse. -Vedere la sezione -.Sx SCORCIATOIE -pi? sotto per i default e le possibilit? di personalizzazione. -.Sh FILE DI CONFIGURAZIONE -.Nm -prova per prima cosa ad aprire il file di configurazione personale -dell'utente, -.Pa ~/.scrotwm.conf . -Se il file in questione non ? disponibile, prova ad usare il file di -configurazione globale -.Pa /etc/scrotwm.conf . -.Pp -Il formato di questo file ? \*(Ltchiave\*(Gt = \*(Ltvalore\*(Gt. -Per esempio: -.Pp -.Dl color_focus = red -.Pp -Per abilitare o disabilitare un'opzione, usare i valori 1 o 0 -rispettivamente. -.Pp -Il file supporta le seguenti chiavi: -.Pp -.Bl -tag -width "title_class_enabledXXX" -offset indent -compact -.It Cm autorun -Esegue un'applicazione nel workspace specificato all'avvio. -Definito nel formato ws[]:applicazione, eg. ws[2]:xterm esegue un -xterm nell'area di lavoro 2. -.It Cm color_focus -Colore del bordo della finestra che ha il focus. -.It Cm color_unfocus -Colore del bordo delle finestre che non hanno il focus. -.It Cm bar_enabled -Abilita o disabilita la barra di stato. -.It Cm bar_border Ns Bq Ar x -Colore del bordo della barra di stato nello schermo -.Ar x . -.It Cm bar_border_width -Spessore del bordo attorno alla barra di stato in pixel. Il bordo -pu? essere disabilitato usando il valore 0. -.It Cm bar_color Ns Bq Ar x -Colore della barra di stato nello schermo -.Ar x . -.It Cm bar_font_color Ns Bq Ar x -Colore del testo della barra di stato nello schermo -.Ar x . -.It Cm bar_font -Font della barra di stato. -.It Cm bar_action -Script esterno che aggiunge informazioni come la carica della batteria alla -barra di stato. -.It Cm bar_delay -Frequenza di aggiornamento, in secondi, dello script esterno che aggiunge -informazioni alla barra di stato. -.It Cm bar_at_bottom -Posiziona la barra di stato sul fondo dello schermo anzich? in cima. -.It Cm stack_enabled -Abilita o disabilita la visualizzazione dell'algoritmo di stacking -corrente nella barra di stato. -.It Cm clock_enabled -Abilita o disabilita l'orologio nella barra di stato. Se disabilitato, -usando il valore 0, ? possibile usare un orologio personalizzato nello -script specificato in -.Pa bar_action . -.It Cm dialog_ratio -Alcune applicazioni hanno finestre di dialogo troppo piccole per risultare -utili. Questa ? la percentuale dello schermo che verr? usata per le finestre -di dialogo: ad esempio, 0.6 indica il 60% della dimensione fisica dello -schermo. -.It Cm layout -Layout da utilizzare all'avvio. Definito nel formato -ws[]:master_grow:master_add:stack_inc:layout:always_raise:stack_mode, -eg. ws[2]:-4:0:1:0:horizontal assegna il layout orizzontale all'area di -lavoro 2, riduce l'area principale di 4 unit?, aggiunge una finestra allo -stack e mantiene il comportamento predefinito per quanto riguarda le -finestre floating. -I valori possibili per stack_mode sono -.Pa vertical , -.Pa horizontal -e -.Pa fullscreen . -.Pp -Fare riferimento a -.Pa master_grow , -.Pa master_shrink , -.Pa master_add , -.Pa master_del , -.Pa stack_inc , -.Pa stack_del -e -.Pa always_raise -per ulteriori informazioni. -Queste impostazioni sono complesse e hanno effetti secondari; ? opportuno -familiarizzare con questi comandi prima di modificare l'opzione -.Pa layout . -.Pp -Questa impostazione non viene applicata dopo il restart. -.It Cm region -Alloca una regione personalizzata, rimuovendo qualsiasi regione -automaticamente rilevata stia occupando lo stesso spazio sullo schermo. -Definita nel formato screen[]:LARGHEZZAxALTEZZA+X+Y, ad esempio -\& screen[1]:800x1200+0+0. -.Pp -Per fare s? che pi? monitor vengano considerati come una singola entit? -? sufficiente creare una regione sufficientemente grande da contenerli, -eg. screen[1]:2048x760+0+0 unisce due monitor con risoluzione 1024x768 -posizionati uno di fianco all'altro. -.It Cm term_width -Imposta la dimensione minima preferita per il terminale. Se questo valore -? maggiore di 0, -.Nm -cercher? di riaggiustare la dimensione del testo nel terminale in modo che -la larghezza del terminale rimanga sopra il valore quando la finestra -viene ridimensionata. Al momento solo -.Xr xterm 1 -? supportato. Il binario di -.Xr xterm 1 -deve essere setuid o setgid perch? questo funzioni: nella maggior parte dei -sistemi, questo ? il default. L'utente potrebbe voler impostare -program[term] (vedere la sezione -.Sx PROGRAMMI -pi? sotto) per usare una seconda copia del binario di -.Xr xterm 1 -che non abbia il bit setgid impostato. -.It Cm title_class_enabled -Abilita o disabilita la visualizzazione della classe della finestra nella -barra di stato. Impostare a 1 per abilitare. -.It Cm title_name_enabled -Abilita o disabilita la visualizzazione del titolo della finestra nella -barra di stato. Impostare a 1 per abilitare. -.It Cm urgent_enabled -Abilita o disabilita l'hint "urgente". -In molti emulatori di terminale, il supporto deve essere abilitato -separatamente: per xterm, ad esempio, ? necessario aggiungere la riga -.Pa xterm.urgentOnBell: true -al file -.Pa .Xdefaults . -.It Cm window_name_enabled -Abilita o disabilita la visualizzazione del nome della finestra nella -barra di stato. Impostare a 1 per abilitare. -.It Cm verbose_layout -Abilita o disabilita la visualizzazione dei valori correnti di master e -stack nella barra di stato. Impostare a 1 per abilitare. -.It Cm modkey -Cambia il tasto modificatore. -Solitamente Mod1 ? il tasto ALT e Mod4 ? il tasto Windows su un PC. -.It Cm focus_mode -Se viene usato il valore -.Pa follow_cursor , -il gestore di finestre dar? il focus alla finestra sotto il puntatore -quando si cambia area di lavoro o si creano finestre. -.It Cm disable_border -Rimuovi il bordo dalle finestre se la barra di stato ? nascosta e c'? -una sola finestra sullo schermo. -.It Cm border_width -Spessore del bordo delle finestre in pixel. Il valore 0 disabilita il bordo. -.It Cm program Ns Bq Ar p -Definisce una nuova azione per lanciare il programma -.Ar p . -Vedere la sezione -.Sx PROGRAMMI -pi? sotto. -.It Cm bind Ns Bq Ar x -Assegna una combinazione di tasti all'azione -.Ar x . -Vedere la sezione -.Sx SCORCIATOIE -pi? sotto. -.It Cm quirk Ns Bq Ar c:n -Aggiunge un "quirk" per le finestre di classe -.Ar c -e nome -.Ar n . -Vedere la sezione -.Sx QUIRKS -pi? sotto. -.El -.Pp -I colori devono essere specificati nel formato usato da -.Xr XQueryColor 3 -e i font in quello usato da -.Xr XQueryFont 3 . -.Pp -Per avere una lista dei font disponibili sul proprio sistema utilizzare -.Xr fc-list 1 -o -.Xr xlsfonts 1 . -L'applicazione -.Xr xfontsel 1 -? utile per visualizzare la X Logical Font Description ("XLFD") usata per -la chiave -.Pa bar_font . -.Sh PROGRAMMI -.Nm -consente la definizione di azioni personalizzate per lanciare programmi di -propria scelta, che possono essere assegnate a combinazioni di tasti nello -stesso modo in cui ? possibile farlo con le azioni predefinite. -Vedere la sezione -.Sx SCORCIATOIE -pi? sotto. -.Pp -I programmi di default sono descritte qui sotto: -.Pp -.Bl -tag -width "screenshot_wind" -offset indent -compact -.It Cm term -xterm -.It Cm screenshot_all -screenshot.sh full -.It Cm screenshot_wind -screenshot.sh window -.It Cm lock -xlock -.It Cm initscr -initscreen.sh -.It Cm menu -dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color -.El -.Pp -I programmi personalizzati vengono specificati con la seguente sintassi: -.Pp -.Dl program[] = [ [... ]] -.Pp -.Aq nome -? un qualsiasi identificatore che non va in conflitto con un'azione -predefinita o una chiave, -.Aq percorso -? il programma desiderato, e -.Aq arg -sono zero o pi? argomenti da passare al programma. -.Pp -Le seguenti variabili rappresentano valori impostabili in -.Nm -(vedere la sezione -.Sx FILE DI CONFIGURAZIONE -sopra), e possono essere usati nel campo -.Aq arg -dove saranno sostituite con il valore al momento del lancio del programma: -.Pp -.Bl -tag -width "$bar_font_color" -offset indent -compact -.It Cm $bar_border -.It Cm $bar_color -.It Cm $bar_font -.It Cm $bar_font_color -.It Cm $color_focus -.It Cm $color_unfocus -.El -.Pp -Esempio: -.Bd -literal -offset indent -program[ff] = /usr/local/bin/firefox http://scrotwm.org/ -bind[ff] = Mod+f # adesso Mod+F lancia firefox -.Ed -.Pp -Per eliminare la combinazione precedente: -.Bd -literal -offset indent -bind[] = Mod+f -program[ff] = -.Ed -.Pp -.Sh SCORCIATOIE -.Nm -fornisce molte funzioni (o azioni) accessibili tramite combinazioni di -tasti sul mouse o sulla tastiera. -.Pp -Le scorciatoie assegnate al mouse sono: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M1 -D? focus alla finestra -.It Cm M-M1 -Muove la finestra -.It Cm M-M3 -Ridimensiona la finestra -.It Cm M-S-M3 -Ridimensiona la finestra mantenendola centrata -.El -.Pp -Le scorciatoie da tastiera di default sono: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M-S- Ns Aq Cm Return -term -.It Cm M-p -menu -.It Cm M-S-q -quit -.It Cm M-q -restart -.It Cm M- Ns Aq Cm Space -cycle_layout -.It Cm M-S- Ns Aq Cm Space -reset_layout -.It Cm M-h -master_shrink -.It Cm M-l -master_grow -.It Cm M-, -master_add -.It Cm M-. -master_del -.It Cm M-S-, -stack_inc -.It Cm M-S-. -stack_del -.It Cm M- Ns Aq Cm Return -swap_main -.It Xo -.Cm M-j , -.Cm M- Ns Aq Cm TAB -.Xc -focus_next -.It Xo -.Cm M-k , -.Cm M-S- Ns Aq Cm TAB -.Xc -focus_prev -.It Cm M-m -focus_main -.It Cm M-S-j -swap_next -.It Cm M-S-k -swap_prev -.It Cm M-b -bar_toggle -.It Cm M-x -wind_del -.It Cm M-S-x -wind_kill -.It Cm M- Ns Aq Ar n -.Ns ws_ Ns Ar n -.It Cm M-S- Ns Aq Ar n -.Ns mvws_ Ns Ar n -.It Cm M- Ns Aq Cm Right -ws_next -.It Cm M- Ns Aq Cm Left -ws_prev -.It Cm M-a -ws_prior -.It Cm M-S- Ns Aq Cm Right -screen_next -.It Cm M-S- Ns Aq Cm Left -screen_prev -.It Cm M-s -screenshot_all -.It Cm M-S-s -screenshot_wind -.It Cm M-S-v -version -.It Cm M-t -float_toggle -.It Cm M-S Aq Cm Delete -lock -.It Cm M-S-i -initscr -.It Cm M-w -iconify -.It Cm M-S-w -uniconify -.It Cm M-S-r -always_raise -.It Cm M-v -button2 -.El -.Pp -I nomi delle azioni e le relative descrizioni sono le seguenti: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm term -Lancia un nuovo terminale -(vedi -.Sx PROGRAMMI -pi? in alto). -.It Cm menu -Menu -(vedi -.Sx PROGRAMMI -pi? in alto). -.It Cm quit -Chiude -.Nm . -.It Cm restart -Riavvia -.Nm . -.It Cm cycle_layout -Cambia layout. -.It Cm reset_layout -Re-inizializza il layout. -.It Cm master_shrink -Restringe l'area principale. -.It Cm master_grow -Allarga l'area principale. -.It Cm master_add -Aggiunge finestre all'area principale. -.It Cm master_del -Rimuove finestre dall'area principale. -.It Cm stack_inc -Aggiunge righe/colonne all'area di stacking. -.It Cm stack_del -Rimuove righe/colonne dall'area di stacking. -.It Cm swap_main -Muove la finestra corrente nell'area principale. -.It Cm focus_next -D? il focus alla finestra successiva. -.It Cm focus_prev -D? il focus alla finestra precedente. -.It Cm focus_main -D? il focus alla finestra principale. -.It Cm swap_next -Scambia con la finestra successiva dell'area di lavoro. -.It Cm swap_prev -Scambia con la finestra precedente dell'area di lavoro. -.It Cm bar_toggle -Mostra/nascondi la barra di stato da tutte le aree di lavoro. -.It Cm wind_del -Chiude la finestra corrente. -.It Cm wind_kill -Distrugge la finestra corrente. -.It Cm ws_ Ns Ar n -Passa all'area di lavoro -.Ar n , -dove -.Ar n -? compreso tra 1 e 10. -.It Cm mvws_ Ns Ar n -Sposta la finestra corrente nell'area di lavoro -.Ar n , -dove -.Ar n -? compreso tra 1 e 10. -.It Cm ws_next -Passa all'area di lavoro non vuota successiva. -.It Cm ws_prev -Passa all'area di lavoro non vuota precedente. -.It Cm ws_prior -Passa all'ultima area di lavoro visitata. -.It Cm screen_next -Sposta il puntatore nella regione successiva. -.It Cm screen_prev -Sposta il puntatore nella regione precedente. -.It Cm screenshot_all -Cattura uno screenshot dell'intero schermo, se abilitato (vedere la sezione -.Sx PROGRAMMI -pi? in alto). -.It Cm screenshot_wind -Cattura uno screenshot di una singola finestra, se abilitato (vedere la -sezione -.Sx PROGRAMMI -pi? in alto). -.It Cm version -Abilita/disabilita il numero di versione nella barra di stato. -.It Cm float_toggle -Passa la finestra che ha il focus da floating a tiled. -.It Cm lock -Blocca lo schermo (vedere la sezione -.Sx PROGRAMMI -pi? in alto). -.It Cm initscr -Re-inizializza gli schermi fisici (vedere la sezione -.Sx PROGRAMMI -pi? in alto). -.It Cm iconify -Minimizza (unmap) la finesta che ha il focus. -.It Cm uniconify -Massimizza (map) la finestra selezionata tramite dmenu. -.It Cm always_raise -Quando ? abilitato, le finestre floating possono essere oscurate da -finestre tiled. -.It Cm button2 -Simula la pressione del tasto centrale del mouse. -.El -.Pp -Le scorciatoie personalizzate sono specificate nel file di configurazione -come segue: -.Pp -.Dl bind[] = -.Pp -.Aq azione -? una delle azioni elencate sopra (oppure nulla) e -.Aq tasti -? dato da zero o pi? modificatori (MOD, Mod1, Shift, ecc.) e uno o pi? -tasti normali (b, space, ecc.), separati da "+". -Per esempio: -.Bd -literal -offset indent -bind[reset] = Mod4+q # assegna reset ai tasti Windows + q -bind[] = Mod1+q # rimuovi l'assegnazione di Alt + q -.Ed -.Pp -Pi? combinazioni di tasti possono essere assegnate alla stessa azione. -.Sh QUIRK -.Nm -fornisce la possibilit? di specificare dei "quirk" per la gestione di -finestre che devono subire un trattamento speciale da un gestore di finestre -tiling, come ad esempio alcune finestre di dialogo e applicazioni a -schermo intero. -.Pp -I quirk abilitati di default sono elencati qui sotto: -.Pp -.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact -.It Firefox\-bin:firefox\-bin -TRANSSZ -.It Firefox:Dialog -FLOAT -.It Gimp:gimp -FLOAT + ANYWHERE -.It MPlayer:xv -FLOAT + FULLSCREEN + FOCUSPREV -.It OpenOffice.org 2.4:VCLSalFrame -FLOAT -.It OpenOffice.org 3.1:VCLSalFrame -FLOAT -.It pcb:pcb -FLOAT -.It xine:Xine Window -FLOAT + ANYWHERE -.It xine:xine Panel -FLOAT + ANYWHERE -.It xine:xine Video Fullscreen Window -FULLSCREEN + FLOAT -.It Xitk:Xitk Combo -FLOAT + ANYWHERE -.It Xitk:Xine Window -FLOAT + ANYWHERE -.It XTerm:xterm -XTERM_FONTADJ -.El -.Pp -I quirk sono descritti qui sotto: -.Pp -.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact -.It FLOAT -Questa finestra deve essere lasciata libera di muoversi (float). -.It TRANSSZ -Aggiusta la dimensione delle finestre troppo piccole usando dialog_ratio -(vedere -.Sx FILE DI CONFIGURAZIONE ) . -.It ANYWHERE -Consente alla finestra di decidere da sola dove posizionarsi. -.It XTERM_FONTADJ -Ridimensiona il font di xterm quando viene ridimensionata la finestra. -.It FULLSCREEN -Rimuove i bordi, consentendo alla finestra di usare l'intera dimensione -dello schermo. -.It FOCUSPREV -Quando la finestra viene chiusa, d? il focus alla finestra che aveva il -focus precedente anzich? all'applicazione precedente nello stack. -.El -.Pp -I quirk personalizzati vanno specificati nel file di configurazione come -segue: -.Pp -.Dl quirk[:] = [ + ... ] -.Pp -.Aq classe -e -.Aq nome -specificano a quali finestre i quirk vanno applicati, e -.Aq quirk -? uno dei quirk presente nella lista sopra. -Ad esempio: -.Bd -literal -offset indent -quirk[MPlayer:xv] = FLOAT + FULLSCREEN + FOCUSPREV -quirk[pcb:pcb] = NONE # rimuovi un quirk precedentemente specificato -.Ed -.Pp -? possibile ottenere -.Aq classe -e -.Aq nome -usando xprop(1) e facendo click sulla finestra desiderata. -Nel seguente esempio ? stato fatto click sulla finestra principale di -Firefox: -.Bd -literal -offset indent -$ xprop | grep WM_CLASS -WM_CLASS(STRING) = "Navigator", "Firefox" -.Ed -.Pp -Bisogna tenere conto del fatto che usare grep per trovare WM_CLASS inverte -la classe e il nome. Nell'esempio precedente, la dichiarazione del quirk -sarebbe -.Bd -literal -offset indent -quirk[Firefox:Navigator] = FLOAT -.Ed -.Pp -.Nm -assegna automaticamente i quirk alle finestre in base al valore della -propriet? _NET_WM_WINDOW_TYPE in base al seguente schema: -.Pp -.Bl -tag -width "_NET_WM_WINDOW_TYPE_TOOLBARXXX" -offset indent -compact -.It _NET_WM_WINDOW_TYPE_DOCK -FLOAT + ANYWHERE -.It _NET_WM_WINDOW_TYPE_TOOLBAR -FLOAT + ANYWHERE -.It _NET_WM_WINDOW_TYPE_UTILITY -FLOAT + ANYWHERE -.It _NET_WM_WINDOW_TYPE_SPLASH -FLOAT -.It _NET_WM_WINDOW_TYPE_DIALOG -FLOAT -.El -.Pp -In tutti gli altri casi, nessun quirk ? automaticamente assegnato alla -finestra. I quirk specificati nel file di configurazione hanno la precedenza -sui quirk assegnati in automatico. -.Sh EWMH -.Nm -implementa in maniera parziale la specifica Extended Window Manager Hints -(EWMH). Ci? permette di controllare sia le finestre che -.Nm -stesso tramite script e programmi esterni. Per renderlo possibile, -.Nm -risponde ad alcuni eventi di tipo ClientMessage; questo tipo di messaggio -pu? essere inviato da un terminale usando programmi come -.Xr wmctrl 1 -e -.Xr xdotool 1 . -Per il formato esatto di questi messaggi, si veda la specifica EWMH. -.Pp -L'id della finestra che ha il focus ? memorizzato nella propriet? -_NET_ACTIVE_WINDOW della root window. ? quindi possibile ottenere il titolo -della finestra attiva usando -.Xr xprop 1 -e -.Xr grep 1 -.Bd -literal -offset indent -$ WINDOWID=`xprop \-root _NET_ACTIVE_WINDOW | grep \-o "0x.*"` -$ xprop \-id $WINDOWID WM_NAME | grep \-o "\\".*\\"" -.Ed -.Pp -Per dare il focus ad una finestra, ? sufficiente inviare il messaggio -_NET_ACTIVE_WINDOW alla root window. Ad esempio, usando -.Xr wmctrl 1 -(supponendo che 0x4a0000b sia l'id della finestra a cui dare il focus): -.Bd -literal -offset indent -$ wmctrl \-i \-c 0x4a0000b -.Ed -.Pp -Per chiudere una finestra si pu? inviare il messaggio _NET_CLOSE_WINDOW -alla root window. Ad esempio, usando -.Xr wmctrl 1 -(supponendo che 0x4a0000b sia l'id della finestra da chiudere): -.Bd -literal -offset indent -$ wmctrl \-i \-c 0x4a0000b -.Ed -.Pp -Per passare una finestra da floating a tiled si pu? aggiungere o rimuovere -l'atomo _NET_WM_STATE_ABOVE alla propriet? _NET_WM_STATE della finestra, -inviando il messaggio _NET_WM_STATE alla root window. Ad esempio, usando -.Xr wmctrl 1 -(supponendo che 0x4a0000b sia l'id della finestra): -.Bd -literal -offset indent -$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE -.Ed -.Pp -Le finestre floating possono essere ridimensionate o spostate inviando il -messaggio _NET_MOVERESIZE_WINDOW alla root window. Ad esempio, usando -.Xr wmctrl 1 -(supponendo che 0x4a0000b sia l'id della finestra da spostare): -.Bd -literal -offset indent -$ wmctrl \-i \-r 0x4a0000b \-e 0,100,50,640,480 -.Ed -.Pp -Questo comando sposta la finestra in (100,50) e la ridimensiona a 640x480. -.Pp -I messaggi _NET_MOVERESIZE_WINDOW vengono ignorati per le finestre stacked. -.Sh SEGNALI -? possibile riavviare -.Nm -inviandogli il segnale HUP. -.Sh FILE -.Bl -tag -width "/etc/scrotwm.confXXX" -compact -.It Pa ~/.scrotwm.conf -impostazioni di -.Nm -dell'utente. -.It Pa /etc/scrotwm.conf -impostazioni globali di -.Nm . -.El -.Sh ORIGINE -.Nm -prende ispirazione da xmonad & dwm. -.Sh AUTORI -.An -nosplit -.Pp -.Nm -? stato scritto da: -.Pp -.Bl -tag -width "Ryan Thomas McBride Aq mcbride@countersiege.com " -offset indent -compact -.It Cm Marco Peereboom Aq marco@peereboom.us -.It Cm Ryan Thomas McBride Aq mcbride@countersiege.com -.It Cm Darrin Chandler Aq dwchandler@stilyagin.com -.It Cm Pierre-Yves Ritschard Aq pyr@spootnik.org -.It Cm Tuukka Kataja Aq stuge@xor.fi -.It Cm Jason L. Wright Aq jason@thought.net -.El -.Sh BUGS -Al momento il menu, invocato usando -.Cm M-p , -dipende da dmenu. diff --git a/scrotwm_pt.1 b/scrotwm_pt.1 deleted file mode 100644 index 4534ade..0000000 --- a/scrotwm_pt.1 +++ /dev/null @@ -1,584 +0,0 @@ -.\" Copyright (c) 2009 Marco Peereboom -.\" Copyright (c) 2009 Darrin Chandler -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate$ -.Dt SCROTWM 1 -.Os -.Sh NOME -.Nm scrotwm -.Nd gerenciador de janela para o X11 -.Sh SINOPSE -.Nm scrotwm -.Sh DESCRI\(,C\(~AO -.Nm -\('e um gerenciador de janela minimalista que tenta n\(~ao atrapalhar a -valorosa forma real da tela para que essa possa -ser usada para coisas muito mais importantes. -Tem sensatos defaults e n\(~ao requer que algu\('em aprenda uma linguagem de -programa\(,c\(~ao para fazer qualquer configura\(,c\(~ao. -Ele foi escrito por hackers para hackers e esfor\(,ca-se em ser pequeno, compacto e -r\('apido. -.Pp -Quando o -.Nm -inicia, ele l\(^e as configura\(,c\(~oes do seu arquivo de configura\(,c\(~ao, -.Pa scrotwm.conf . -Veja a se\(,c\(~ao -.Sx ARQUIVOS DE CONFIGURA\(,C\(~AO -logo abaixo. -.Pp -A seguinte nota\(,c\(~ao \('e usada por toda essa p\('agina: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It Cm M -Meta -.It Cm S -Shift -.It Aq Cm Name -Nome da tecla -.It Cm M1 -Bot\(~ao 1 do mouse -.It Cm M3 -Bot\(~ao 3 do mouse -.El -.Pp -.Nm -\('e muito simples de usar. -Muitas das a\(,c\(~oes s\(~ao iniciadas por atalhos do mouse ou do teclado. -Veja a se\(,c\(~ao -.Sx ATALHOS -logo abaixo para os defaults e as personaliza\(,c\(~oes. -.Sh ARQUIVOS DE CONFIGURA\(,C\(~AO -.Nm -primeiro tenta abrir o arquivo de configura\(,c\(~ao no diret\('orio do usu\('ario, -.Pa ~/.scrotwm.conf . -Se o arquivo n\(~ao estiver dispon\('ivel, ent\(~ao tenta abrir o arquivo de -configura\(,c\(~ao global -.Pa /etc/scrotwm.conf . -.Pp -Assim \('e o formato do arquivo:\*(Ltpalavra-chave\*(Gt = \*(Ltconfigura\(,c\(~ao\*(Gt. -Por exemplo: -.Pp -.Dl color_focus = red -.Pp -Para habilitar ou desabilitar uma op\(,c\(~ao usa-se o 1 ou 0, respectivamente. -.Pp -O arquivo suporta as seguintes palavras-chave: -.Pp -.Bl -tag -width "title_class_enabledXXX" -offset indent -compact -.It Cm color_focus -Cor da borda da janela atualmente focada. -.It Cm color_unfocus -Cor da borda das janelas fora de foco. -.It Cm bar_enabled -Habilita ou desabilita a barra de status. -.It Cm bar_border Ns Bq Ar x -Cor da borda da barra de status na tela -.Ar x . -.It Cm bar_color Ns Bq Ar x -Cor da janela da barra de status na tela -.Ar x . -.It Cm bar_font_color Ns Bq Ar x -Cor da fonte na barra de status na tela -.Ar x . -.It Cm bar_font -Fonte da barra de status. -.It Cm bar_action -Script externo que preenche a barra de status com informa\(,c\(~oes adicionais, -como tempo de vida da bateria. -.It Cm bar_delay -Freq\(:u\(^encia da atualiza\(,c\(~ao, em segundos, do script externo que preenche -a barra de status. -.It Cm bar_at_bottom -Coloca a barra de status na parte inferior de cada regi\(~ao, ao inv\('es da parte superior. -.It Cm stack_enabled -Habilita ou desabilita mostrar o atual algor\('itmo de empilhamento na barra de status. -.It Cm clock_enabled -Habilita ou desabilita mostrar o rel\('ogio na barra de status. -Desabilite configurando para 0, ent\(~ao um rel\('ogio personalizado pode ser usado no -script bar_action. -.It Cm dialog_ratio -Algumas aplica\(,c\(~oes tem janelas de di\('alogo que s\(~ao muito pequenas para serem \('uteis. -Essa taxa \('e o tamanho da tela para o qual elas ser\(~ao redimencionadas. -Por exemplo, 0.6 equivale a 60% do tamanho da tela f\('isica. -.It Cm region -Aloca uma regi\(~ao personalizada, removendo qualquer regi\(~ao automaticamente detectada -que ocupe o mesmo espa\(,co na tela. -Definido no formato screen[]:WIDTHxHEIGHT+X+Y, -e.g.\& screen[1]:800x1200+0+0. -.It Cm term_width -Configura a largura m\('inima preferida para o terminal -Se esse valor for maior do que 0, -.Nm -vai tentar ajustar os tamanhos da fonte no terminal para manter a largura -do terminal acima desse n\('umero enquanto a janela \('e redimencionada. -Apenas o -.Xr xterm 1 -\('e suportado atualmente. -O bin\('ario do -.Xr xterm 1 -n\(~ao deve ser setuid ou setgid, que \('e o default em muitos sistemas. -Os usu\('arios podem precisar de configurar program[term] (veja a se\(,c\(~ao -.Sx PROGRAMAS -) para usar uma c\('opia alternativa do bin\('ario do -.Xr xterm 1 -sem o bit setgid ativado. -.It Cm title_class_enabled -Habilita ou desabilita mostrar a classe da janela na barra de status. -Habilite configurando para 1. -.It Cm title_name_enabled -Habilita ou desabilita mostrar o t\('itulo da janela na barra de status. -Habilite configurando para 1. -.It Cm window_name_enabled -Habilita ou desabilita mostrar a nome da janela na barra de status. -Habilite configurando para 1. -.It Cm modkey -Muda a tecla de modifica\(,c\(~ao. -Mod1 \('e geralmente a tecla ALT e Mod4 \('e a tecla windows em um PC. -.It Cm focus_mode -Usar um valor de follow_cursor vai fazer o gerenciador de janela focar -a janela sob o mouse quando trocando \('areas de trabalho e criando janelas. -.It Cm disable_border -Remove a borda quando a barra estiver desabilitada e houver apenas uma janela na tela. -.It Cm program Ns Bq Ar p -Define uma nova a\(,c\(~ao para executar um programa -.Ar p . -Veja a se\(,c\(~ao -.Sx PROGRAMAS -logo abaixo. -.It Cm bind Ns Bq Ar x -Cria uma combina\(,c\(~ao de teclas de atalho para a a\(,c\(~ao -.Ar x . -Veja a se\(,c\(~ao -.Sx ATALHOS -logo abaixo. -.It Cm quirk Ns Bq Ar c:n -Adicione "quirk" para janelas com classe -.Ar c -e nome -.Ar n . -Veja a se\(,c\(~ao -.Sx QUIRKS -logo abaixo. -.El -.Pp -Cores precisam ser especificadas pela especifica\(,c\(~ao -.Xr XQueryColor 3 -e fontes pela especifica\(,c\(~ao -.Xr XQueryFont 3 . -.Pp -Para listar as fontes dispon\('iveis em seu sistema veja o manual do -.Xr fc-list 1 -ou do -.Xr xlsfonts 1 . -A aplica\(,c\(~ao -.Xr xfontsel 1 -pode te ajudar a mostrar a X Logical Font Description ("XLFD") usada na -configura\(,c\(~ao da palavra-chave bar_font. -.Sh PROGRAMAS -.Nm -te permite definir a\(,c\(~oes personalizadas para executar programas de sua escolha -e ent\(~ao criar um atalho para elas da mesma forma que as a\(,c\(~oes embutidas. -Veja a se\(,c\(~ao -.Sx ATALHOS -logo abaixo. -.Pp -Os programas default s\(~ao descritos abaixo: -.Pp -.Bl -tag -width "screenshot_wind" -offset indent -compact -.It Cm term -xterm -.It Cm screenshot_all -screenshot.sh full -.It Cm screenshot_wind -screenshot.sh window -.It Cm lock -xlock -.It Cm initscr -initscreen.sh -.It Cm menu -dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color -.El -.Pp -Programas personalizados no arquivo de configura\(,c\(~ao s\(~ao especificados da seguinte maneira: -.Pp -.Dl program[] = [ [... ]] -.Pp -.Aq name -\('e um identificador qualquer que n\(~ao conflite com uma a\(,c\(~ao ou palavra-chave embutida, -.Aq progpath -\('e o programa desejado, e -.Aq arg -\('e zero ou mais argumentos para o programa. -.Pp -As seguintes vari\('aveis representam valores configur\('aveis no -.Nm -(veja a se\(,c\(~ao -.Sx ARQUIVOS DE CONFIGURA\(,C\(~AO -logo acima), -e podem ser usadas nos campos -.Aq arg -e ser\(~ao substitu\('idas pelos valores na hora em que o programa for executado: -.Pp -.Bl -tag -width "$bar_font_color" -offset indent -compact -.It Cm $bar_border -.It Cm $bar_color -.It Cm $bar_font -.It Cm $bar_font_color -.It Cm $color_focus -.It Cm $color_unfocus -.El -.Pp -Exemplo: -.Bd -literal -offset indent -program[ff] = /usr/local/bin/firefox http://scrotwm.org/ -bind[ff] = Mod+f # Agora Mod+F executa o firefox -.Ed -.Pp -Para desfazer a configura\(,c\(~ao anterior: -.Bd -literal -offset indent -bind[] = Mod+f -program[ff] = -.Ed -.Pp -.Sh ATALHOS -.Nm -prov\(^e muitas fun\(,c\(~oes (ou a\(,cões) acessadas pelos atalhos do teclado ou do mouse. -.Pp -Os atuais atalhos do mouse s\(~ao descritos abaixo: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M1 -Foca a janela -.It Cm M-M1 -Move a janela -.It Cm M-M3 -Redimenciona a janela -.It Cm M-S-M3 -Redimenciona a janela enquanto a mant\('em centralizada -.El -.Pp -Os atalhos default do teclado s\(~ao descritos abaixo: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M-S- Ns Aq Cm Return -term -.It Cm M-p -menu -.It Cm M-S-q -quit -.It Cm M-q -restart -.Nm -.It Cm M- Ns Aq Cm Space -cycle_layout -.It Cm M-S- Ns Aq Cm Space -reset_layout -.It Cm M-h -master_shrink -.It Cm M-l -master_grow -.It Cm M-, -master_add -.It Cm M-. -master_del -.It Cm M-S-, -stack_inc -.It Cm M-S-. -stack_del -.It Cm M- Ns Aq Cm Return -swap_main -.It Xo -.Cm M-j , -.Cm M- Ns Aq Cm TAB -.Xc -focus_next -.It Xo -.Cm M-k , -.Cm M-S- Ns Aq Cm TAB -.Xc -focus_prev -.It Cm M-m -focus_main -.It Cm M-S-j -swap_next -.It Cm M-S-k -swap_prev -.It Cm M-b -bar_toggle -.It Cm M-x -wind_del -.It Cm M-S-x -wind_kill -.It Cm M- Ns Aq Ar n -.Ns ws_ Ns Ar n -.It Cm M-S- Ns Aq Ar n -.Ns mvws_ Ns Ar n -.It Cm M- Ns Aq Cm Right -ws_next -.It Cm M- Ns Aq Cm Left -ws_prev -.It Cm M-a -ws_prior -.It Cm M-S- Ns Aq Cm Right -screen_next -.It Cm M-S- Ns Aq Cm Left -screen_prev -.It Cm M-s -screenshot_all -.It Cm M-S-s -screenshot_wind -.It Cm M-S-v -version -.It Cm M-t -float_toggle -.It Cm M-S Aq Cm Delete -lock -.It Cm M-S-i -initscr -.El -.Pp -Os nomes das a\(,c\(~oes e suas descri\(,cões est\(~ao listados abaixo: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm term -Executa um novo terminal -(veja a se\(,c\(~ao -.Sx PROGRAMAS -logo acima) -.It Cm menu -Menu -(veja a se\(,c\(~ao -.Sx PROGRAMAS -logo acima) -.It Cm quit -Sair -.Nm -.It Cm restart -Reiniciar -.Nm -.It Cm cycle_layout -Circula entre os poss\('iveis layouts -.It Cm reset_layout -Reinicia o layout -.It Cm master_shrink -Encolhe a \('area mestre -.It Cm master_grow -Aumenta a \('area mestre -.It Cm master_add -Adiciona janelas na \('area mestre -.It Cm master_del -Remove janelas da \('area mestre -.It Cm stack_inc -Adiciona colunas/linhas para a \('area de empilhamento -.It Cm stack_del -Remove colunas/linhas da \('area de empilhamento -.It Cm swap_main -Move a janela atual para a \('area mestre -.It Cm focus_next -Foca a pr\('oxima janela da \('area de trabalho -.It Cm focus_prev -Foca a janela anterior da \('area de trabalho -.It Cm focus_main -Foca a janela principal da \('area de trabalho -.It Cm swap_next -Troca com a pr\('oxima janela da \('area de trabalho -.It Cm swap_prev -Troca com a janela anterior da \('area de trabalho -.It Cm bar_toggle -Ativa/desativa a barra de status em todas as \('areas de trabalho -.It Cm wind_del -Apaga a janela atual da \('area de trabalho -.It Cm wind_kill -Destr\('oi a janela atual da \('area de trabalho -.It Cm ws_ Ns Ar n -Troca para a \('area de trabalho -.Ar n , -onde -.Ar n -vai de 1 at\('e 10 -.It Cm mvws_ Ns Ar n -Move a janela atual para a \('area de trabalho -.Ar n , -onde -.Ar n -vai de 1 at\('e 10 -.It Cm ws_next -Troca para a pr\('oxima \('area de trabalho que possua uma janela -.It Cm ws_prev -Troca para a \('area de trabalho anterior que possua uma janela -.It Cm ws_prior -Troca para a \('ultima \('area de trabalho visitada -.It Cm screen_next -Move o ponteiro para a pr\('oxima regi\(~ao -.It Cm screen_prev -Move o ponteiro para a regi\(~ao anterior -.It Cm screenshot_all -Tira screenshot da tela inteira (se habilitado) -(veja a se\(,c\(~ao -.Sx PROGRAMAS -logo acima) -.It Cm screenshot_wind -Tira screenshot da janela selecionada (se habilitado) -(veja a se\(,c\(~ao -.Sx PROGRAMAS -logo acima) -.It Cm version -Ativa/desativa a vers\(~ao na barras de status -.It Cm float_toggle -Troca o estado da janela focada entre flutuante e tiled -.It Cm lock -Trava a tela -(veja a se\(,c\(~ao -.Sx PROGRAMAS -logo acima) -.It Cm initscr -Reinicializa as telas f\('isicas -(veja a se\(,c\(~ao -.Sx PROGRAMAS -logo acima) -.El -.Pp -Atalhos personalizados no arquivo de configura\(,c\(~ao s\(~ao especificados da seguinte maneira: -.Pp -.Dl bind[] = -.Pp -.Aq action -\('e uma das a\(,c\(~oes listadas acima (ou vazio) e -.Aq keys -est\('a na forma de zero ou mais teclas de modifica\(,c\(~ao -(MOD, Mod1, Shift, etc.) e uma ou mais teclas normais -(b, space, etc.), separadas pelo "+". -Por exemplo: -.Bd -literal -offset indent -bind[reset] = Mod4+q # combina a tecla Windows + q para reiniciar -bind[] = Mod1+q # desfaz a combina\(,c\(~ao Alt + q -.Ed -.Pp -M\('ultiplas combina\(,c\(~oes de teclas podem ser usadas para a mesma a\(,c\(~ao. -.Sh QUIRKS -.Nm -prov\(^e "quirks" que manipulam janelas que devem ser tratadas especialmente -em um gerenciador de janela "tiling", tal como algumas aplica\(,c\(~oes de -di\('alogos e tela cheia. -.Pp -Os quirks default est\(~ao descritos abaixo: -.Pp -.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact -.It Firefox\-bin:firefox\-bin -TRANSSZ -.It Firefox:Dialog -FLOAT -.It Gimp:gimp -FLOAT + ANYWHERE -.It MPlayer:xv -FLOAT + FULLSCREEN -.It OpenOffice.org 2.4:VCLSalFrame -FLOAT -.It OpenOffice.org 3.1:VCLSalFrame -FLOAT -.It pcb:pcb -FLOAT -.It xine:Xine Window -FLOAT + ANYWHERE -.It xine:xine Panel -FLOAT + ANYWHERE -.It xine:xine Video Fullscreen Window -FULLSCREEN + FLOAT -.It Xitk:Xitk Combo -FLOAT + ANYWHERE -.It Xitk:Xine Window -FLOAT + ANYWHERE -.It XTerm:xterm -XTERM_FONTADJ -.El -.Pp -Os quirks em si est\(~ao descritos abaixo: -.Pp -.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact -.It FLOAT -Esta janela n\(~ao deve ser "tiled", mas permitida a flutuar livremente. -.It TRANSSZ -Ajusta o tamanho das janelas transit\('orias que sejam muito pequenas -usando dialog_ratio -(veja a se\(,c\(~ao -.Sx ARQUIVOS DE CONFIGURA\(,C\(~AO ) . -.It ANYWHERE -Permite que a janela posicione a si mesma, n\(~ao-centrada. -.It XTERM_FONTADJ -Ajusta as fontes do xterm quando redimencionando. -.It FULLSCREEN -Remove a borda para permitir a janela usar todo o tamanho da tela. -.El -.Pp -Quirks personalizados no arquivo de configura\(,c\(~ao s\(~ao especificados da seguinte maneira: -.Pp -.Dl quirk[:] = [ + ... ] -.Pp -.Aq class -e -.Aq name -especificam a janela ao qual o quirk se aplica, e -.Aq quirk -\('e um dos quirks da lista acima. -Por exemplo: -.Bd -literal -offset indent -quirk[MPlayer:xv] = FLOAT + FULLSCREEN # faz o mplayer tocar livremente -quirk[pcb:pcb] = NONE # remove quirk existente -.Ed -.Pp -Voc\(^e pode obter -.Aq class -e -.Aq name -executando o xprop(1) e ent\(~ao clicando na janela desejada. -No seguinte exemplo a jenela principal do Firefox foi clicada: -.Bd -literal -offset indent -$ xprop | grep WM_CLASS -WM_CLASS(STRING) = "Navigator", "Firefox" -.Ed -.Pp -Note que usando o grep(1) para WM_CLASS voc\(^e obt\('em class e name. -No exemplo acima a configura\(,c\(~ao do quirk poderia ser: -.Bd -literal -offset indent -quirk[Firefox:Navigator] = FLOAT -.Ed -.Sh SINAIS -Enviar ao -.Nm -um sinal HUP far\('a com que o mesmo seja reiniciado. -.Sh ARQUIVOS -.Bl -tag -width "/etc/scrotwm.confXXX" -compact -.It Pa ~/.scrotwm.conf -Configura\(,c\(~oes espec\('ificas do usu\('ario. -.It Pa /etc/scrotwm.conf -Configura\(,c\(~oes globais. -.El -.Sh HIST\('ORIA -.Nm -foi inspirado pelo xmonad & dwm. -.Sh AUTORES -.An -nosplit -.Pp -.Nm -foi escrito por -.An Marco Peereboom Aq marco@peereboom.us , -.An Ryan Thomas McBride Aq mcbride@countersiege.com -e -.An Darrin Chandler Aq dwchandler@stilyagin.com . -.Sh BUGS -Atualmente o menu, invocado com -.Cm M-p , -depende do dmenu. diff --git a/scrotwm_ru.1 b/scrotwm_ru.1 deleted file mode 100644 index 5925ff6..0000000 --- a/scrotwm_ru.1 +++ /dev/null @@ -1,557 +0,0 @@ -.\" Copyright (c) 2009 Marco Peereboom -.\" Copyright (c) 2009 Darrin Chandler -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.Dd $Mdocdate$ -.Dt SCROTWM 1 -.Os -.Sh НАЗВАНИЕ -.Nm scrotwm -.Nd Оконный менеджер для X11 -.Sh ИСПОЛЬЗОВАНИЕ -.Nm scrotwm -.Sh ОПИСАНИЕ -.Nm -это минималистичный менеджер окон, ставящий своей целью не мешать вам и не -занимать ценное пространство экрана. Его настройки по-умолчанию разумны и, -кроме того, он не требует знания языков программирования для работы с -конфигурационным файлом. Он написан хакерами для хакеров и старается быть -легким, компактным и быстрым. -.Pp -Когда -.Nm -запускается, он читает настройки из своего конфигурационного файла, -.Pa scrotwm.conf . -Смотрите секцию -.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ -ниже. -.Pp -На этой странице используются следующие обозначения: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It Cm M -Мета-клавиша -.It Cm S -Shift -.It Aq Cm Name -Имя клавиши -.It Cm M1 -Кнопка мыши 1 -.It Cm M3 -Кнопка мыши 3 -.El -.Pp -.Nm -должен быть понятным и очевидным. -Большинство действий выполняется комбинациями клавиш. -Смотрите секцию -.Sx ПРИВЯЗКИ -ниже, чтобы узнать о стандартных настройках. -.Sh КОНФИГУРАЦИОННЫЕ ФАЙЛЫ -.Nm -пытается прочитать файл в домашнем каталоге, -.Pa ~/.scrotwm.conf . -В случае, если он недоступен, -происходит обращение к глобальному файлу настроек, -.Pa /etc/scrotwm.conf . -.Pp -Формат файла следующий: \*(Ltключ\*(Gt = \*(Ltзначение\*(Gt. -Например: -.Pp -.Dl color_focus = red -.Pp -Однозначное включение и выключение задается значениями 1 и 0. -.Pp -Поддерживаются следующие ключевые слова: -.Pp -.Bl -tag -width "title_class_enabledXXX" -offset indent -compact -.It Cm color_focus -Цвет рамки окна в фокусе. -.It Cm color_unfocus -Цвет рамки окон не в фокусе. -.It Cm bar_enabled -Включение статусной строки. -.It Cm bar_border Ns Bq Ar x -Цвет рамки статусной строки -.Ar x . -.It Cm bar_color Ns Bq Ar x -Цвет статусной строки -.Ar x . -.It Cm bar_font_color Ns Bq Ar x -Цвет шрифта статусной строки -.Ar x . -.It Cm bar_font -Тип шрифта статусной строки. -.It Cm bar_action -Внешний файл скрипта для статусной строки, выводящий туда информацию, -например, уровень заряда батарей. -.It Cm bar_delay -Частота выполнения внешнего скрипта статусной строки, секунды. -.It Cm stack_enabled -Включить отображение способа укладки окон в статусной строке. -.It Cm clock_enabled -Включить часы в статусной строке. -Можно отключить, установив 0, и Вы сможете использовать -собственные часы из внешнего скрипта. -.It Cm dialog_ratio -Ряд приложений имеет слишком маленькие диалоговые окна. -Это значение - доля размера экрана, к которой они будут приведены. -Например, значение 0.6 будет соответствовать 60% от реального размера экрана. -.It Cm region -Выделяет область экрана на Ваше усмотрение, уничтожает все перекрытые области -экрана, определенные автоматически. -Формат: screen[]:WIDTHxHEIGHT+X+Y, -например\& screen[1]:1280x800+0+0. -.It Cm term_width -Установить минимальную допустимую ширину эмулятора терминала. -Если это значение больше 0, -.Nm -попытается отмасштабировать шрифты в терминале, чтобы ширина -была больше этого значения -. -Поодерживается только -.Xr xterm 1 -. -Также -.Xr xterm 1 -не может быть с setuid или setgid, хотя это так на многих системах. -Возможно необходимо задать program[term] (Смотрите секцию -.Sx ПРОГРАММЫ -) чтобы использовалась другая копия -.Xr xterm 1 -без заданного бита setgid. -.It Cm title_class_enabled -Отображать класс окна в статусной строке. -Обычно выключено -.It Cm title_name_enabled -Отображать заголовок окна в статусной строке. -Обычно выключено -.It Cm modkey -Назначить Мета-клавишу, клавишу-модификатор. -Mod1 соответствует клавише ALT, а Mod4 соответствует клавише WIN на PC. -.It Cm program Ns Bq Ar p -Добавить пользовательскую программу для назначения привязки -.Ar p . -Смотрите секцию -.Sx ПРОГРАММЫ -ниже. -.It Cm bind Ns Bq Ar x -Назначить привязку на действие -.Ar x . -Смотрите секцию -.Sx ПРИВЯЗКИ -ниже. -.It Cm quirk Ns Bq Ar c:n -Добавить костыль для окон с классом -.Ar c -и именем -.Ar n . -Смотрите секцию -.Sx КОСТЫЛИ -ниже. -.El -.Pp -Цвета задаются с помощью -.Xr XQueryColor 3 -А шрифты задаются с использованием -.Xr XQueryFont 3 -. -.Sh ПРОГРАММЫ -.Nm -позволяет Вам добавлять Ваши собственные действия для запуска -программ и делать к ним привязки как ко всем остальным действиям -Смотрите секцию -.Sx ПРИВЯЗКИ -ниже. -.Pp -Стандартные программы: -.Pp -.Bl -tag -width "screenshot_wind" -offset indent -compact -.It Cm term -xterm -.It Cm screenshot_all -screenshot.sh full -.It Cm screenshot_wind -screenshot.sh window -.It Cm lock -xlock -.It Cm initscr -initscreen.sh -.It Cm menu -dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color -.El -.Pp -Ваши собственные программы задаются следующим образом: -.Pp -.Dl program[] = [ [... ]] -.Pp -.Aq name -это любой идентификатор, не мешающийся с уже существующими, -.Aq progpath -это собственно путь к программе, -.Aq arg -это список передаваемых аргументов или оставьте пустым. -.Pp -Следующие переменные можно получать из -.Nm -(Смотрите секцию -.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ -выше), -и их можно использовать как -.Aq arg -(в момент запуска программы будет выполнена подстановка значений): -.Pp -.Bl -tag -width "$bar_font_color" -offset indent -compact -.It Cm $bar_border -.It Cm $bar_color -.It Cm $bar_font -.It Cm $bar_font_color -.It Cm $color_focus -.It Cm $color_unfocus -.El -.Pp -Например: -.Bd -literal -offset indent -program[ff] = /usr/local/bin/firefox http://scrotwm.org/ -bind[ff] = Mod+f # Значит Mod+F запускает firefox -.Ed -.Pp -Чтобы отменить назначение: -.Bd -literal -offset indent -bind[] = Mod+f -program[ff] = -.Ed -.Pp -.Sh ПРИВЯЗКИ -.Nm -предоставляет доступ к действиям с помощью клавиатурных комбинаций. -.Pp -Установленные привязки для мыши: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M1 -Сфокусироваться на окне -.It Cm M-M1 -Переместить окно -.It Cm M-M3 -Изменить размер окна -.It Cm M-S-M3 -Изменить размер окна, удерживая его в центре -.El -.Pp -Стандартные клавиатурные привязки: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm M-S- Ns Aq Cm Return -term -.It Cm M-p -menu -.It Cm M-S-q -quit -.It Cm M-q -restart -.Nm -.It Cm M- Ns Aq Cm Space -cycle_layout -.It Cm M-S- Ns Aq Cm Space -reset_layout -.It Cm M-h -master_shrink -.It Cm M-l -master_grow -.It Cm M-, -master_add -.It Cm M-. -master_del -.It Cm M-S-, -stack_inc -.It Cm M-S-. -stack_del -.It Cm M- Ns Aq Cm Return -swap_main -.It Xo -.Cm M-j , -.Cm M- Ns Aq Cm TAB -.Xc -focus_next -.It Xo -.Cm M-k , -.Cm M-S- Ns Aq Cm TAB -.Xc -focus_prev -.It Cm M-m -focus_main -.It Cm M-S-j -swap_next -.It Cm M-S-k -swap_prev -.It Cm M-b -bar_toggle -.It Cm M-x -wind_del -.It Cm M-S-x -wind_kill -.It Cm M- Ns Aq Ar n -.Ns ws_ Ns Ar n -.It Cm M-S- Ns Aq Ar n -.Ns mvws_ Ns Ar n -.It Cm M- Ns Aq Cm Right -ws_next -.It Cm M- Ns Aq Cm Left -ws_prev -.It Cm M-S- Ns Aq Cm Right -screen_next -.It Cm M-S- Ns Aq Cm Left -screen_prev -.It Cm M-s -screenshot_all -.It Cm M-S-s -screenshot_wind -.It Cm M-S-v -version -.It Cm M-t -float_toggle -.It Cm M-S Aq Cm Delete -lock -.It Cm M-S-i -initscr -.El -.Pp -Описания действий перечислены ниже: -.Pp -.Bl -tag -width "M-j, M-XXX" -offset indent -compact -.It Cm term -Запустить эмулятор терминала -(Смотрите секцию -.Sx ПРОГРАММЫ -выше) -.It Cm menu -Меню -(Смотрите секцию -.Sx ПРОГРАММЫ -выше) -.It Cm quit -Выйти -.Nm -.It Cm restart -Перезапустить -.Nm -.It Cm cycle_layout -Менять укладку окон -.It Cm reset_layout -Стандартная укладка -.It Cm master_shrink -Сжать область главного окна -.It Cm master_grow -Расширить область главного окна -.It Cm master_add -Добавить окна в главную область -.It Cm master_del -Убрать окна из главной области -.It Cm stack_inc -Увеличить число столбцов или рядов в текущей укладке -.It Cm stack_del -Уменьшить число столбцов или рядов в текущей укладке -.It Cm swap_main -Отправить текущее окно в главную область, сделать главным -.It Cm focus_next -Фокусироваться на следующем окне -.It Cm focus_prev -Фокусироваться на предыдущем окне -.It Cm focus_main -Фокусироваться на главном окне -.It Cm swap_next -Поменять со следующим окном -.It Cm swap_prev -Поменять со предыдущим окном -.It Cm bar_toggle -Выключить статусную строку на всех рабочих столах -.It Cm wind_del -Закрыть фокусированное окно -.It Cm wind_kill -Грохнуть фокусированное окно -.It Cm ws_ Ns Ar n -Переключиться на рабочий стол -.Ar n , -где -.Ar n -от 1 до 10 -.It Cm mvws_ Ns Ar n -Переместить фокусированное окно в рабочий стол -.Ar n , -где -.Ar n -от 1 до 10 -.It Cm ws_next -Перейти к следующему не пустому рабочему столу -.It Cm ws_prev -Перейти к следующему не пустому рабочему столу -.It Cm screen_next -Переместить указатель в следующую область -.It Cm screen_prev -Переместить указатель в следующую область -.It Cm screenshot_all -Сделать снимок всего экрана (если возможно) -(Смотрите секцию -.Sx ПРОГРАММЫ -выше) -.It Cm screenshot_wind -Сделать снимок окна (если возможно) -(Смотрите секцию -.Sx ПРОГРАММЫ -выше) -.It Cm version -Показать версию в статусной строке -.It Cm float_toggle -Переключить окно в фокусе в плавающий режим, float -.It Cm lock -Заблокировать экран -(Смотрите секцию -.Sx ПРОГРАММЫ -выше) -.It Cm initscr -Инициализировать экран еще раз -(Смотрите секцию -.Sx ПРОГРАММЫ -выше) -.El -.Pp -Собственные привязки назначаются следующим образом: -.Pp -.Dl bind[] = -.Pp -.Aq action -это действие из списка программ -.Aq keys -это не более одной клавиши-модификатора -(MOD, Mod1, Shift, и.т.п.) и обычные клавиши -(b, space, и.т.п.), разделенные "+". -Например: -.Bd -literal -offset indent -bind[reset] = Mod4+q # назначить WIN + q на действие reset -bind[] = Mod1+q # снять все действия с Alt + q -.Ed -.Pp -На одно действие можно назначить несколько комбинаций. -.Sh КОСТЫЛИ -.Nm -позволяет настроить костыли, нужные для специальной работы scrotwm -с рядом приложений, который вы определяете сами. То есть, Вы можете -принудительно установить способ тайлинга для какого-нибудь приложения -.Pp -Список стандартных костылей: -.Pp -.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact -.It Firefox\-bin:firefox\-bin -TRANSSZ -.It Firefox:Dialog -FLOAT -.It Gimp:gimp -FLOAT + ANYWHERE -.It MPlayer:xv -FLOAT + FULLSCREEN -.It OpenOffice.org 2.4:VCLSalFrame -FLOAT -.It OpenOffice.org 3.1:VCLSalFrame -FLOAT -.It pcb:pcb -FLOAT -.It xine:Xine Window -FLOAT + ANYWHERE -.It xine:xine Panel -FLOAT + ANYWHERE -.It xine:xine Video Fullscreen Window -FULLSCREEN + FLOAT -.It Xitk:Xitk Combo -FLOAT + ANYWHERE -.It Xitk:Xine Window -FLOAT + ANYWHERE -.It XTerm:xterm -XTERM_FONTADJ -.El -.Pp -Описание: -.Pp -.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact -.It FLOAT -Такое окно не нужно тайлить вообще, разрешить ему float -.It TRANSSZ -Тразиентое окно -(Смотрите секцию -.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ) . -.It ANYWHERE -Позволить окну самостоятельно выбрать местоположение -.It XTERM_FONTADJ -Изменять шрифты xterm при изменении размеров окна -.It FULLSCREEN -Позволить окну запускаться в полноэкранном режиме -.El -.Pp -Назначать костыли можно следующим образом: -.Pp -.Dl quirk[:] = [ + ... ] -.Pp -.Aq class -и -.Aq name -определяют к какому окну будет применяться костыль, а -.Aq quirk -один из вышеперечисленных способов. -Например: -.Bd -literal -offset indent -quirk[MPlayer:xv] = FLOAT + FULLSCREEN # mplayer настроен -quirk[pcb:pcb] = NONE # убрать существующий костыль -.Ed -.Pp -Вы можете узнать -.Aq class -и -.Aq name -запустив xprop и нажав в интересующее окно. -Вот как будет выглядеть вывод для Firefox: -.Bd -literal -offset indent -$ xprop | grep WM_CLASS -WM_CLASS(STRING) = "Navigator", "Firefox" -.Ed -.Pp -Обратите внимание, класс и имя меняются местами, -правильный костыль будет выглядеть так: -.Bd -literal -offset indent -quirk[Firefox:Navigator] = FLOAT -.Ed -.Sh ФАЙЛЫ -.Bl -tag -width "/etc/scrotwm.confXXX" -compact -.It Pa ~/.scrotwm.conf -.Nm -Личные настройки пользователя. -.It Pa /etc/scrotwm.conf -.Nm -Глобавльные настройки. -.El -.Sh ИСТОРИЯ -.Nm -идейно основан на dwm и xmonad -.Sh АВТОРЫ -.An -nosplit -.Pp -.Nm -написан: -.An Marco Peereboom Aq marco@peereboom.us , -.An Ryan Thomas McBride Aq mcbride@countersiege.com -and -.An Darrin Chandler Aq dwchandler@stilyagin.com . -.Sh БАГИ -При вызове меню с помощью -.Cm M-p , -необходима корректная работа dmenu. diff --git a/scrotwm_se.conf b/scrotwm_se.conf deleted file mode 100644 index 68dba05..0000000 --- a/scrotwm_se.conf +++ /dev/null @@ -1,74 +0,0 @@ -# Key bindings for Swedish (se) keyboards -# unbind with: bind[] = -bind[cycle_layout] = MOD+space -bind[flip_layout] = MOD+Shift+apostrophe -bind[stack_reset] = MOD+Shift+space -bind[master_shrink] = MOD+h -bind[master_grow] = MOD+l -bind[master_add] = MOD+comma -bind[master_del] = MOD+period -bind[stack_inc] = MOD+Shift+comma -bind[stack_dec] = MOD+Shift+period -bind[swap_main] = MOD+Return -bind[focus_next] = MOD+j -bind[focus_prev] = MOD+k -bind[swap_next] = MOD+Shift+j -bind[swap_prev] = MOD+Shift+k -bind[spawn_term] = MOD+Shift+Return -bind[menu] = MOD+p -bind[quit] = MOD+Shift+q -bind[restart] = MOD+q -bind[focus_main] = MOD+m -bind[ws_1] = MOD+1 -bind[ws_2] = MOD+2 -bind[ws_3] = MOD+3 -bind[ws_4] = MOD+4 -bind[ws_5] = MOD+5 -bind[ws_6] = MOD+6 -bind[ws_7] = MOD+7 -bind[ws_8] = MOD+8 -bind[ws_9] = MOD+9 -bind[ws_10] = MOD+0 -bind[ws_next] = MOD+Right -bind[ws_prev] = MOD+Left -bind[ws_next_all] = MOD+Up -bind[ws_prev_all] = MOD+Down -bind[ws_prior] = MOD+a -bind[screen_next] = MOD+Shift+Right -bind[screen_prev] = MOD+Shift+Left -bind[mvws_1] = MOD+Shift+1 -bind[mvws_2] = MOD+Shift+2 -bind[mvws_3] = MOD+Shift+3 -bind[mvws_4] = MOD+Shift+4 -bind[mvws_5] = MOD+Shift+5 -bind[mvws_6] = MOD+Shift+6 -bind[mvws_7] = MOD+Shift+7 -bind[mvws_8] = MOD+Shift+8 -bind[mvws_9] = MOD+Shift+9 -bind[mvws_10] = MOD+Shift+0 -bind[bar_toggle] = MOD+b -bind[focus_next] = MOD+Tab -bind[focus_prev] = MOD+Shift+Tab -bind[wind_kill] = MOD+Shift+x -bind[wind_del] = MOD+x -bind[screenshot_all] = MOD+s -bind[screenshot_wind] = MOD+Shift+s -bind[float_toggle] = MOD+t -bind[version] = MOD+Shift+v -bind[lock] = MOD+Shift+Delete -bind[initscr] = MOD+Shift+i -bind[iconify] = MOD+w -bind[uniconify] = MOD+Shift+w -bind[raise_toggle] = MOD+Shift+r -bind[button2] = MOD+v -bind[width_shrink] = MOD+plus -bind[width_grow] = MOD+dead_acute -bind[height_shrink] = MOD+Shift+plus -bind[height_grow] = MOD+Shift+dead_acute -bind[move_left] = MOD+aring -bind[move_right] = MOD+dead_diaeresis -bind[move_up] = MOD+Shift+aring -bind[move_down] = MOD+Shift+dead_diaeresis -bind[name_workspace] = MOD+Shift+minus -bind[search_workspace] = MOD+minus -bind[search_win] = MOD+f diff --git a/scrotwm_us.conf b/scrotwm_us.conf deleted file mode 100644 index f2ce392..0000000 --- a/scrotwm_us.conf +++ /dev/null @@ -1,74 +0,0 @@ -# Key bindings for United States (us) keyboards -# unbind with: bind[] = -bind[cycle_layout] = MOD+space -bind[flip_layout] = MOD+Shift+backslash -bind[stack_reset] = MOD+Shift+space -bind[master_shrink] = MOD+h -bind[master_grow] = MOD+l -bind[master_add] = MOD+comma -bind[master_del] = MOD+period -bind[stack_inc] = MOD+Shift+comma -bind[stack_dec] = MOD+Shift+period -bind[swap_main] = MOD+Return -bind[focus_next] = MOD+j -bind[focus_prev] = MOD+k -bind[swap_next] = MOD+Shift+j -bind[swap_prev] = MOD+Shift+k -bind[spawn_term] = MOD+Shift+Return -bind[menu] = MOD+p -bind[quit] = MOD+Shift+q -bind[restart] = MOD+q -bind[focus_main] = MOD+m -bind[ws_1] = MOD+1 -bind[ws_2] = MOD+2 -bind[ws_3] = MOD+3 -bind[ws_4] = MOD+4 -bind[ws_5] = MOD+5 -bind[ws_6] = MOD+6 -bind[ws_7] = MOD+7 -bind[ws_8] = MOD+8 -bind[ws_9] = MOD+9 -bind[ws_10] = MOD+0 -bind[ws_next] = MOD+Right -bind[ws_prev] = MOD+Left -bind[ws_next_all] = MOD+Up -bind[ws_prev_all] = MOD+Down -bind[ws_prior] = MOD+a -bind[screen_next] = MOD+Shift+Right -bind[screen_prev] = MOD+Shift+Left -bind[mvws_1] = MOD+Shift+1 -bind[mvws_2] = MOD+Shift+2 -bind[mvws_3] = MOD+Shift+3 -bind[mvws_4] = MOD+Shift+4 -bind[mvws_5] = MOD+Shift+5 -bind[mvws_6] = MOD+Shift+6 -bind[mvws_7] = MOD+Shift+7 -bind[mvws_8] = MOD+Shift+8 -bind[mvws_9] = MOD+Shift+9 -bind[mvws_10] = MOD+Shift+0 -bind[bar_toggle] = MOD+b -bind[focus_next] = MOD+Tab -bind[focus_prev] = MOD+Shift+Tab -bind[wind_kill] = MOD+Shift+x -bind[wind_del] = MOD+x -bind[screenshot_all] = MOD+s -bind[screenshot_wind] = MOD+Shift+s -bind[float_toggle] = MOD+t -bind[version] = MOD+Shift+v -bind[lock] = MOD+Shift+Delete -bind[initscr] = MOD+Shift+i -bind[iconify] = MOD+w -bind[uniconify] = MOD+Shift+w -bind[raise_toggle] = MOD+Shift+r -bind[button2] = MOD+v -bind[width_shrink] = MOD+minus -bind[width_grow] = MOD+equal -bind[height_shrink] = MOD+Shift+minus -bind[height_grow] = MOD+Shift+equal -bind[move_left] = MOD+bracketleft -bind[move_right] = MOD+bracketright -bind[move_up] = MOD+Shift+bracketleft -bind[move_down] = MOD+Shift+bracketright -bind[name_workspace] = MOD+Shift+slash -bind[search_workspace] = MOD+slash -bind[search_win] = MOD+f diff --git a/spectrwm.1 b/spectrwm.1 new file mode 100644 index 0000000..b85f44f --- /dev/null +++ b/spectrwm.1 @@ -0,0 +1,854 @@ +.\" Copyright (c) 2009 Marco Peereboom +.\" Copyright (c) 2009 Darrin Chandler +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: February 8 2012 $ +.Dt SPECTRWM 1 +.Os +.Sh NAME +.Nm spectrwm +.Nd window manager for X11 +.Sh SYNOPSIS +.Nm spectrwm +.Sh DESCRIPTION +.Nm +is a minimalistic window manager that tries to stay out of the way so that +valuable screen real estate can be used for much more important stuff. +It has sane defaults and does not require one to learn a language to do any +configuration. +It was written by hackers for hackers and it strives to be small, compact and +fast. +.Pp +When +.Nm +starts up, it reads settings from its configuration file, +.Pa spectrwm.conf . +See the +.Sx CONFIGURATION FILES +section below. +.Pp +The following notation is used throughout this page: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Cm M +Meta +.It Cm S +Shift +.It Aq Cm Name +Named key +.It Cm M1 +Mouse button 1 +.It Cm M3 +Mouse button 3 +.El +.Pp +.Nm +is very simple in its use. +Most of the actions are initiated via key or mouse bindings. +See the +.Sx BINDINGS +section below for defaults and customizations. +.Sh CONFIGURATION FILES +.Nm +first tries to open the user specific file, +.Pa ~/.spectrwm.conf . +If that file is unavailable, +it then tries to open the global configuration file +.Pa /etc/spectrwm.conf . +.Pp +The format of the file is \*(Ltkeyword\*(Gt = \*(Ltsetting\*(Gt. +For example: +.Pp +.Dl color_focus = red +.Pp +Enabling or disabling an option is done by using 1 or 0 respectively. +.Pp +The file supports the following keywords: +.Bl -tag -width 2m +.It Ic autorun +Launch an application in a specified workspace at start-of-day. +Defined in the format ws[]:application, e.g. ws[2]:xterm launches an +xterm in workspace 2. +.It Ic bar_action +External script that populates additional information in the status bar, +such as battery life. +.It Ic bar_at_bottom +Place the statusbar at the bottom of each region instead of the top. +.It Ic bar_border Ns Bq Ar x +Color of the status bar border in screen +.Ar x . +.It Ic bar_border_width +Set status bar border thickness in pixels. +Disable border by setting to 0. +.It Ic bar_color Ns Bq Ar x +Color of the status bar window in screen +.Ar x . +.It Ic bar_delay +Update frequency, in seconds, of external script that populates the status bar. +.It Ic bar_enabled +Enable or disable status bar. +.It Ic bar_font +Status bar font. +.It Ic bar_font_color Ns Bq Ar x +Color of the font in status bar in screen +.Ar x . +.It Ic bar_justify +Justify the status bar text. Possible values are +.Pa left , +.Pa center , +and +.Pa right . +.It Ic bind Ns Bq Ar x +Bind key combo to action +.Ar x . +See the +.Sx BINDINGS +section below. +.It Ic border_width +Set window border thickness in pixels. +Disable all borders by setting to 0. +.It Ic clock_enabled +Enable or disable displaying the clock in the status bar. +Disable by setting to 0 +so a custom clock could be used in the +.Pa bar_action +script. +.It Ic color_focus +Border color of the currently focussed window. +.It Ic color_unfocus +Border color of unfocussed windows. +.It Ic dialog_ratio +Some applications have dialogue windows that are too small to be useful. +This ratio is the screen size to what they will be resized. +For example, 0.6 is 60% of the physical screen size. +.It Ic disable_border +Remove border when bar is disabled and there is only one window on the screen. +.It Ic focus_mode +Using a value of +.Pa follow_cursor +will make the window manager focus the window +under the mouse when switching workspaces and creating windows. +.It Ic keyboard_mapping +Clear all key bindings and load new key bindings from the specified file. +This allows you to load pre-defined key bindings for your keyboard layout. +See the +.Sx KEYBOARD MAPPING FILES +section below for a list of keyboard mapping files that have been provided +for several keyboard layouts. +.It Ic layout +Select layout to use at start-of-day. +Defined in the format +ws[idx]:master_grow:master_add:stack_inc:layout:always_raise:stack_mode, e.g. +ws[2]:-4:0:1:0:horizontal sets worskspace 2 to the horizontal stack mode and +shrinks the master area by 4 ticks and adds one window to the stack, while +maintaining default floating window behavior. +Possible stack_mode values are +.Pa vertical , +.Pa horizontal +and +.Pa fullscreen . +.Pp +See +.Pa master_grow , +.Pa master_shrink , +.Pa master_add , +.Pa master_del , +.Pa stack_inc , +.Pa stack_dec , +and +.Pa always_raise +for more information. +Note that the stacking options are complicated and have side-effects. +One should familiarize oneself with these commands before experimenting with the +.Pa layout +option. +.Pp +This setting is not retained at restart. +.It Ic modkey +Change mod key. +Mod1 is generally the ALT key and Mod4 is the windows key on a PC. +.It Ic program Ns Bq Ar p +Define new action to spawn a program +.Ar p . +See the +.Sx PROGRAMS +section below. +.It Ic quirk Ns Bq Ar c:n +Add "quirk" for windows with class +.Ar c +and name +.Ar n . +See the +.Sx QUIRKS +section below. +.It Ic region +Allocates a custom region, removing any autodetected regions which occupy the same +space on the screen. +Defined in the format screen[]:WIDTHxHEIGHT+X+Y, +e.g.\& screen[1]:800x1200+0+0. +.Pp +To make a screen span multiple monitors, create a region big enough to cover +them all, e.g. screen[1]:2048x768+0+0 makes the screen span two monitors with +1024x768 resolution sitting one next to the other. +.It Ic stack_enabled +Enable or disable displaying the current stacking algorithm in the status bar. +.It Ic term_width +Set a preferred minimum width for the terminal. +If this value is greater than 0, +.Nm +will attempt to adjust the font sizes in the terminal to keep the terminal +width above this number as the window is resized. +Only +.Xr xterm 1 +is currently supported. +The +.Xr xterm 1 +binary must not be setuid or setgid, which it is by default on most systems. +Users may need to set program[term] (see the +.Sx PROGRAMS +section) to use an alternate copy of the +.Xr xterm 1 +binary without the setgid bit set. +.It Ic title_class_enabled +Enable or disable displaying the window class in the status bar. +Enable by setting to 1. +.It Ic title_name_enabled +Enable or disable displaying the window title in the status bar. +Enable by setting to 1. +.It Ic urgent_enabled +Enable or disable the urgency hint. +Note that many terminal emulators require this to be enabled for it to +propagate. +In xterm, for example, one needs to add the following line +.Pa xterm.urgentOnBell: true +to +.Pa .Xdefaults . +.It Ic verbose_layout +Enable or disable displaying the current master and stack values in the status +bar. +Enable by setting to 1. +.It Ic window_name_enabled +Enable or disable displaying the window name in the status bar. +Enable by setting to 1. +.El +.Pp +Colors need to be specified per the +.Xr XQueryColor 3 +specification and fonts need to be specified per the +.Xr XQueryFont 3 +specification. +.Pp +To list the available fonts in your system see +.Xr fc-list 1 +or +.Xr xlsfonts 1 +manpages. +The +.Xr xfontsel 1 +application can help you to show the X Logical Font Description ("XLFD") used +as setting in the keyword +.Pa bar_font . +.Sh PROGRAMS +.Nm +allows you to define custom actions to launch programs of your choice and then +bind them the same as with built-in actions. +See the +.Sx BINDINGS +section below. +.Pp +The default programs are described below: +.Pp +.Bl -tag -width "screenshot_wind" -offset indent -compact +.It Cm term +xterm +.It Cm screenshot_all +screenshot.sh full +.It Cm screenshot_wind +screenshot.sh window +.It Cm lock +xlock +.It Cm initscr +initscreen.sh +.It Cm menu +dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color +.El +.Pp +Custom programs in the configuration file are specified as follows: +.Pp +.Dl program[] = [ [... ]] +.Pp +.Aq name +is any identifier that does not conflict with a built-in action or keyword, +.Aq progpath +is the desired program, and +.Aq arg +is zero or more arguments to the program. +.Pp +The following variables represent settable values in +.Nm +(see the +.Sx CONFIGURATION FILES +section above), +and may be used in the +.Aq arg +fields and will be substituted for values at the time the program is spawned: +.Pp +.Bl -tag -width "$bar_font_color" -offset indent -compact +.It Cm $bar_border +.It Cm $bar_color +.It Cm $bar_font +.It Cm $bar_font_color +.It Cm $color_focus +.It Cm $color_unfocus +.El +.Pp +Example: +.Bd -literal -offset indent +program[ff] = /usr/local/bin/firefox http://spectrwm.org/ +bind[ff] = Mod+Shift+b # Now Mod+Shift+B launches firefox +.Ed +.Pp +To undo the previous: +.Bd -literal -offset indent +bind[] = Mod+Shift+b +program[ff] = +.Ed +.Sh BINDINGS +.Nm +provides many functions (or actions) accessed via key or mouse bindings. +.Pp +The current mouse bindings are described below: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M1 +Focus window +.It Cm M-M1 +Move window +.It Cm M-M3 +Resize window +.It Cm M-S-M3 +Resize window while maintaining it centered +.El +.Pp +The default key bindings are described below: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M-S- Ns Aq Cm Return +term +.It Cm M-p +menu +.It Cm M-S-q +quit +.It Cm M-q +restart +.It Cm M- Ns Aq Cm Space +cycle_layout +.It Cm M-S- Ns Aq Cm \e +flip_layout +.It Cm M-S- Ns Aq Cm Space +stack_reset +.It Cm M-h +master_shrink +.It Cm M-l +master_grow +.It Cm M-, +master_add +.It Cm M-. +master_del +.It Cm M-S-, +stack_inc +.It Cm M-S-. +stack_dec +.It Cm M- Ns Aq Cm Return +swap_main +.It Xo +.Cm M-j , +.Cm M- Ns Aq Cm TAB +.Xc +focus_next +.It Xo +.Cm M-k , +.Cm M-S- Ns Aq Cm TAB +.Xc +focus_prev +.It Cm M-m +focus_main +.It Cm M-S-j +swap_next +.It Cm M-S-k +swap_prev +.It Cm M-b +bar_toggle +.It Cm M-x +wind_del +.It Cm M-S-x +wind_kill +.It Cm M- Ns Aq Ar n +.Pf ws_ Ar n +.It Cm M-S- Ns Aq Ar n +.Pf mvws_ Ar n +.It Cm M- Ns Aq Cm Right +ws_next +.It Cm M- Ns Aq Cm Left +ws_prev +.It Cm M- Ns Aq Cm Up +ws_next_all +.It Cm M- Ns Aq Cm Down +ws_prev_all +.It Cm M-a +ws_prior +.It Cm M-S- Ns Aq Cm Right +screen_next +.It Cm M-S- Ns Aq Cm Left +screen_prev +.It Cm M-s +screenshot_all +.It Cm M-S-s +screenshot_wind +.It Cm M-S-v +version +.It Cm M-t +float_toggle +.It Cm M-S- Ns Aq Cm Delete +lock +.It Cm M-S-i +initscr +.It Cm M-w +iconify +.It Cm M-S-w +uniconify +.It Cm M-S-r +always_raise +.It Cm M-v +button2 +.It Cm M-- +width_shrink +.It Cm M-= +width_grow +.It Cm M-S-- +height_shrink +.It Cm M-S-= +height_grow +.It Cm M-[ +move_left +.It Cm M-] +move_right +.It Cm M-S-[ +move_up +.It Cm M-S-] +move_down +.It Cm M-S-/ +name_workspace +.It Cm M-/ +search_workspace +.It Cm M-f +search_win +.El +.Pp +The action names and descriptions are listed below: +.Pp +.Bl -tag -width "M-j, M-XXXX" -offset indent -compact +.It Cm term +Spawn a new terminal +(see +.Sx PROGRAMS +above). +.It Cm menu +Menu +(see +.Sx PROGRAMS +above). +.It Cm quit +Quit +.Nm . +.It Cm restart +Restart +.Nm . +.It Cm cycle_layout +Cycle layout. +.It Cm flip_layout +Swap the master and stacking areas. +.It Cm stack_reset +Reset layout. +.It Cm master_shrink +Shrink master area. +.It Cm master_grow +Grow master area. +.It Cm master_add +Add windows to master area. +.It Cm master_del +Remove windows from master area. +.It Cm stack_inc +Add columns/rows to stacking area. +.It Cm stack_dec +Remove columns/rows from stacking area. +.It Cm swap_main +Move current window to master area. +.It Cm focus_next +Focus next window in workspace. +.It Cm focus_prev +Focus previous window in workspace. +.It Cm focus_main +Focus on main window in workspace. +.It Cm swap_next +Swap with next window in workspace. +.It Cm swap_prev +Swap with previous window in workspace. +.It Cm bar_toggle +Toggle status bar in all workspaces. +.It Cm wind_del +Delete current window in workspace. +.It Cm wind_kill +Destroy current window in workspace. +.It Cm ws_ Ns Ar n +Switch to workspace +.Ar n , +where +.Ar n +is 1 through 10. +.It Cm mvws_ Ns Ar n +Move current window to workspace +.Ar n , +where +.Ar n +is 1 through 10. +.It Cm ws_next +Switch to next workspace with a window in it. +.It Cm ws_prev +Switch to previous workspace with a window in it. +.It Cm ws_next_all +Switch to next workspace. +.It Cm ws_prev_all +Switch to previous workspace. +.It Cm ws_prior +Switch to last visited workspace. +.It Cm screen_next +Move pointer to next region. +.It Cm screen_prev +Move pointer to previous region. +.It Cm screenshot_all +Take screenshot of entire screen (if enabled) +(see +.Sx PROGRAMS +above). +.It Cm screenshot_wind +Take screenshot of selected window (if enabled) +(see +.Sx PROGRAMS +above). +.It Cm version +Toggle version in status bar. +.It Cm float_toggle +Toggle focused window between tiled and floating. +.It Cm lock +Lock screen +(see +.Sx PROGRAMS +above). +.It Cm initscr +Reinitialize physical screens +(see +.Sx PROGRAMS +above). +.It Cm iconify +Minimize (unmap) currently focused window. +.It Cm uniconify +Maximize (map) window returned by dmenu selection. +.It Cm always_raise +When set tiled windows are allowed to obscure floating windows. +.It Cm button2 +Fake a middle mouse button click (mouse button 2). +.It Cm width_shrink +Shrink the width of a floating window. +.It Cm width_grow +Grow the width of a floating window. +.It Cm height_shrink +Shrink the height of a floating window. +.It Cm height_grow +Grow the height of a floating window. +.It Cm move_left +Move a floating window a step to the left. +.It Cm move_right +Move a floating window a step to the right. +.It Cm move_up +Move a floating window a step upwards. +.It Cm move_down +Move a floating window a step downwards. +.It Cm name_workspace +Name the current workspace. +.It Cm search_workspace +Search for a workspace. +.It Cm search_win +Search the windows in the current workspace. +.El +.Pp +Custom bindings in the configuration file are specified as follows: +.Pp +.Dl bind[] = +.Pp +.Aq action +is one of the actions listed above (or empty) and +.Aq keys +is in the form of zero or more modifier keys +(MOD, Mod1, Shift, etc.) and one or more normal keys +(b, space, etc.), separated by "+". +For example: +.Bd -literal -offset indent +bind[reset] = Mod4+q # bind Windows-key + q to reset +bind[] = Mod1+q # unbind Alt + q +.Ed +.Pp +To use the currently defined +.Ic modkey , +specify MOD as the modifier key. +.Pp +Multiple key combinations may be bound to the same action. +.Sh KEYBOARD MAPPING FILES +Keyboard mapping files for several keyboard layouts are listed +below. +These files can be used with the +.Pa keyboard_mapping +setting to load pre-defined key bindings for the specified +keyboard layout. +.Pp +.Bl -tag -width "spectrwm_XX.confXXX" -offset indent -compact +.It Cm spectrwm_cz.conf +Czech Republic keyboard layout +.It Cm spectrwm_es.conf +Spanish keyboard layout +.It Cm spectrwm_fr.conf +French keyboard layout +.It Cm spectrwm_fr_ch.conf +Swiss French keyboard layout +.It Cm spectrwm_se.conf +Swedish keyboard layout +.It Cm spectrwm_us.conf +United States keyboard layout +.El +.Sh QUIRKS +.Nm +provides "quirks" which handle windows that must be treated specially +in a tiling window manager, such as some dialogs and fullscreen apps. +.Pp +The default quirks are described below: +.Pp +.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact +.It Firefox\-bin:firefox\-bin +TRANSSZ +.It Firefox:Dialog +FLOAT +.It Gimp:gimp +FLOAT + ANYWHERE +.It MPlayer:xv +FLOAT + FULLSCREEN + FOCUSPREV +.It OpenOffice.org 2.4:VCLSalFrame +FLOAT +.It OpenOffice.org 3.1:VCLSalFrame +FLOAT +.It pcb:pcb +FLOAT +.It xine:Xine Window +FLOAT + ANYWHERE +.It xine:xine Panel +FLOAT + ANYWHERE +.It xine:xine Video Fullscreen Window +FULLSCREEN + FLOAT +.It Xitk:Xitk Combo +FLOAT + ANYWHERE +.It Xitk:Xine Window +FLOAT + ANYWHERE +.It XTerm:xterm +XTERM_FONTADJ +.El +.Pp +The quirks themselves are described below: +.Pp +.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact +.It FLOAT +This window should not be tiled, but allowed to float freely. +.It TRANSSZ +Adjusts size on transient windows that are too small using dialog_ratio +(see +.Sx CONFIGURATION FILES ) . +.It ANYWHERE +Allow window to position itself, uncentered. +.It XTERM_FONTADJ +Adjust xterm fonts when resizing. +.It FULLSCREEN +Remove border to allow window to use full screen size. +.It FOCUSPREV +On exit force focus on previously focused application not previous application +in the stack. +.El +.Pp +Custom quirks in the configuration file are specified as follows: +.Pp +.Dl quirk[:] = [ + ... ] +.Pp +.Aq class +and +.Aq name +specify the window to which the quirk(s) apply, and +.Aq quirk +is one of the quirks from the list above. +For example: +.Bd -literal -offset indent +quirk[MPlayer:xv] = FLOAT + FULLSCREEN + FOCUSPREV +quirk[pcb:pcb] = NONE # remove existing quirk +.Ed +.Pp +You can obtain +.Aq class +and +.Aq name +by running +.Xr xprop 1 +and then clicking on the desired window. +In the following example the main window of Firefox was clicked: +.Bd -literal -offset indent +$ xprop | grep WM_CLASS +WM_CLASS(STRING) = "Navigator", "Firefox" +.Ed +.Pp +Note that grepping for WM_CLASS flips class and name. +In the example above the quirk entry would be: +.Bd -literal -offset indent +quirk[Firefox:Navigator] = FLOAT +.Ed +.Pp +.Nm +also automatically assigns quirks to windows based on the value +of the window's _NET_WM_WINDOW_TYPE property as follows: +.Pp +.Bl -tag -width "_NET_WM_WINDOW_TYPE_TOOLBARXXX" -offset indent -compact +.It _NET_WM_WINDOW_TYPE_DOCK +FLOAT + ANYWHERE +.It _NET_WM_WINDOW_TYPE_TOOLBAR +FLOAT + ANYWHERE +.It _NET_WM_WINDOW_TYPE_UTILITY +FLOAT + ANYWHERE +.It _NET_WM_WINDOW_TYPE_SPLASH +FLOAT +.It _NET_WM_WINDOW_TYPE_DIALOG +FLOAT +.El +.Pp +In all other cases, no automatic quirks are assigned to the window. +Quirks specified in the configuration file override the automatic quirks. +.Sh EWMH +.Nm +partially implements the Extended Window Manager Hints (EWMH) specification. +This enables controlling windows as well as +.Nm +itself from external scripts and programs. +This is achieved by +.Nm +responding to certain ClientMessage events. +From the terminal these events +can be conveniently sent using tools such as +.Xr wmctrl 1 +and +.Xr xdotool 1 . +For the +actual format of these ClientMessage events, see the EWMH specification. +.Pp +The id of the currently focused window is stored in the _NET_ACTIVE_WINDOW +property of the root window. +This can be used for example to retrieve the +title of the currently active window with +.Xr xprop 1 +and +.Xr grep 1 : +.Bd -literal -offset indent +$ WINDOWID=`xprop \-root _NET_ACTIVE_WINDOW | grep \-o "0x.*"` +$ xprop \-id $WINDOWID WM_NAME | grep \-o "\\".*\\"" +.Ed +.Pp +A window can be focused by sending a _NET_ACTIVE_WINDOW client message +to the root window. +For example, using +.Xr wmctrl 1 +to send the message +(assuming 0x4a0000b is the id of the window to be focused): +.Bd -literal -offset indent +$ wmctrl \-i \-a 0x4a0000b +.Ed +.Pp +Windows can be closed by sending a _NET_CLOSE_WINDOW client message +to the root window. +For example, using +.Xr wmctrl 1 +to send the message +(assuming 0x4a0000b is the id of the window to be closed): +.Bd -literal -offset indent +$ wmctrl \-i \-c 0x4a0000b +.Ed +.Pp +Windows can be floated and un-floated by adding or removing the +_NET_WM_STATE_ABOVE atom from the _NET_WM_STATE property of the window. +This can be achieved by sending a _NET_WM_STATE client message to the +root window. +For example, the following toggles the floating state of +a window using +.Xr wmctrl 1 +to send the message (assuming 0x4a0000b is the id of the window floated +or un-floated): +.Bd -literal -offset indent +$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE +.Ed +.Pp +Floating windows can also be resized and moved by sending a +_NET_MOVERESIZE_WINDOW client message to the root window. +For example, +using +.Xr wmctrl 1 +to send the message (assuming 0x4a0000b is the id of +the window to be resize/moved): +.Bd -literal -offset indent +$ wmctrl \-i \-r 0x4a0000b \-e 0,100,50,640,480 +.Ed +.Pp +This moves the window to (100,50) and resizes it to 640x480. +.Pp +Any _NET_MOVERESIZE_WINDOW events received for stacked windows are ignored. +.Sh SIGNALS +Sending +.Nm +a HUP signal will restart it. +.Sh FILES +.Bl -tag -width "/etc/spectrwm.confXXX" -compact +.It Pa ~/.spectrwm.conf +.Nm +user specific settings. +.It Pa /etc/spectrwm.conf +.Nm +global settings. +.El +.Sh HISTORY +.Nm +was inspired by xmonad & dwm. +.Sh AUTHORS +.An -nosplit +.Nm +was written by: +.Pp +.Bl -tag -width "Ryan Thomas McBride Aq mcbride@countersiege.com " -offset indent -compact +.It Cm Marco Peereboom Aq marco@peereboom.us +.It Cm Ryan Thomas McBride Aq mcbride@countersiege.com +.It Cm Darrin Chandler Aq dwchandler@stilyagin.com +.It Cm Pierre-Yves Ritschard Aq pyr@spootnik.org +.It Cm Tuukka Kataja Aq stuge@xor.fi +.It Cm Jason L. Wright Aq jason@thought.net +.It Cm Reginald Kennedy Aq rk@rejii.com +.El diff --git a/spectrwm.c b/spectrwm.c new file mode 100644 index 0000000..2928f00 --- /dev/null +++ b/spectrwm.c @@ -0,0 +1,7096 @@ +/* + * Copyright (c) 2009-2012 Marco Peereboom + * Copyright (c) 2009-2011 Ryan McBride + * Copyright (c) 2009 Darrin Chandler + * Copyright (c) 2009 Pierre-Yves Ritschard + * Copyright (c) 2010 Tuukka Kataja + * Copyright (c) 2011 Jason L. Wright + * Copyright (c) 2011-2012 Reginald Kennedy + * Copyright (c) 2012 Lawrence Teo + * Copyright (c) 2012 Tiago Cunha + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Much code and ideas taken from dwm under the following license: + * MIT/X Consortium License + * + * 2006-2008 Anselm R Garbe + * 2006-2007 Sander van Dijk + * 2006-2007 Jukka Salmi + * 2007 Premysl Hruby + * 2007 Szabolcs Nagy + * 2007 Christof Musik + * 2007-2008 Enno Gottox Boland + * 2007-2008 Peter Hartlich + * 2008 Martin Hurton + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#if defined(__linux__) +#include "tree.h" +#elif defined(__OpenBSD__) +#include +#elif defined(__FreeBSD__) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __OSX__ +#include +#endif + +#include "version.h" + +#ifdef SPECTRWM_BUILDSTR +static const char *buildstr = SPECTRWM_BUILDSTR; +#else +static const char *buildstr = SPECTRWM_VERSION; +#endif + +#if RANDR_MAJOR < 1 +# error XRandR versions less than 1.0 are not supported +#endif + +#if RANDR_MAJOR >= 1 +#if RANDR_MINOR >= 2 +#define SWM_XRR_HAS_CRTC +#endif +#endif + +/*#define SWM_DEBUG*/ +#ifdef SWM_DEBUG +#define DPRINTF(x...) do { if (swm_debug) fprintf(stderr, x); } while (0) +#define DNPRINTF(n,x...) do { if (swm_debug & n) fprintf(stderr, x); } while (0) +#define SWM_D_MISC 0x0001 +#define SWM_D_EVENT 0x0002 +#define SWM_D_WS 0x0004 +#define SWM_D_FOCUS 0x0008 +#define SWM_D_MOVE 0x0010 +#define SWM_D_STACK 0x0020 +#define SWM_D_MOUSE 0x0040 +#define SWM_D_PROP 0x0080 +#define SWM_D_CLASS 0x0100 +#define SWM_D_KEY 0x0200 +#define SWM_D_QUIRK 0x0400 +#define SWM_D_SPAWN 0x0800 +#define SWM_D_EVENTQ 0x1000 +#define SWM_D_CONF 0x2000 +#define SWM_D_BAR 0x4000 + +u_int32_t swm_debug = 0 + | SWM_D_MISC + | SWM_D_EVENT + | SWM_D_WS + | SWM_D_FOCUS + | SWM_D_MOVE + | SWM_D_STACK + | SWM_D_MOUSE + | SWM_D_PROP + | SWM_D_CLASS + | SWM_D_KEY + | SWM_D_QUIRK + | SWM_D_SPAWN + | SWM_D_EVENTQ + | SWM_D_CONF + | SWM_D_BAR + ; +#else +#define DPRINTF(x...) +#define DNPRINTF(n,x...) +#endif + +#define LENGTH(x) (sizeof x / sizeof x[0]) +#define MODKEY Mod1Mask +#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define MOUSEMASK (BUTTONMASK|PointerMotionMask) +#define SWM_PROPLEN (16) +#define SWM_FUNCNAME_LEN (32) +#define SWM_KEYS_LEN (255) +#define SWM_QUIRK_LEN (64) +#define X(r) (r)->g.x +#define Y(r) (r)->g.y +#define WIDTH(r) (r)->g.w +#define HEIGHT(r) (r)->g.h +#define SH_MIN(w) (w)->sh_mask & PMinSize +#define SH_MIN_W(w) (w)->sh.min_width +#define SH_MIN_H(w) (w)->sh.min_height +#define SH_MAX(w) (w)->sh_mask & PMaxSize +#define SH_MAX_W(w) (w)->sh.max_width +#define SH_MAX_H(w) (w)->sh.max_height +#define SH_INC(w) (w)->sh_mask & PResizeInc +#define SH_INC_W(w) (w)->sh.width_inc +#define SH_INC_H(w) (w)->sh.height_inc +#define SWM_MAX_FONT_STEPS (3) +#define WINID(w) ((w) ? (w)->id : 0) +#define YESNO(x) ((x) ? "yes" : "no") + +#define SWM_FOCUS_DEFAULT (0) +#define SWM_FOCUS_SYNERGY (1) +#define SWM_FOCUS_FOLLOW (2) + +#define SWM_CONF_DEFAULT (0) +#define SWM_CONF_KEYMAPPING (1) + +#ifndef SWM_LIB +#define SWM_LIB "/usr/local/lib/libswmhack.so" +#endif + +char **start_argv; +Atom astate; +Atom aprot; +Atom adelete; +Atom takefocus; +Atom a_wmname; +Atom a_netwmname; +Atom a_utf8_string; +Atom a_string; +Atom a_swm_iconic; +volatile sig_atomic_t running = 1; +volatile sig_atomic_t restart_wm = 0; +int outputs = 0; +int last_focus_event = FocusOut; +int (*xerrorxlib)(Display *, XErrorEvent *); +int other_wm; +int ss_enabled = 0; +int xrandr_support; +int xrandr_eventbase; +unsigned int numlockmask = 0; +Display *display; + +int cycle_empty = 0; +int cycle_visible = 0; +int term_width = 0; +int font_adjusted = 0; +unsigned int mod_key = MODKEY; + +/* dmenu search */ +struct swm_region *search_r; +int select_list_pipe[2]; +int select_resp_pipe[2]; +pid_t searchpid; +volatile sig_atomic_t search_resp; +int search_resp_action; + +struct search_window { + TAILQ_ENTRY(search_window) entry; + int idx; + struct ws_win *win; + GC gc; + Window indicator; +}; +TAILQ_HEAD(search_winlist, search_window); + +struct search_winlist search_wl; + +/* search actions */ +enum { + SWM_SEARCH_NONE, + SWM_SEARCH_UNICONIFY, + SWM_SEARCH_NAME_WORKSPACE, + SWM_SEARCH_SEARCH_WORKSPACE, + SWM_SEARCH_SEARCH_WINDOW +}; + +/* dialog windows */ +double dialog_ratio = 0.6; +/* status bar */ +#define SWM_BAR_MAX (256) +#define SWM_BAR_JUSTIFY_LEFT (0) +#define SWM_BAR_JUSTIFY_CENTER (1) +#define SWM_BAR_JUSTIFY_RIGHT (2) +#define SWM_BAR_OFFSET (4) +#define SWM_BAR_FONTS "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*," \ + "-*-profont-*-*-*-*-*-*-*-*-*-*-*-*," \ + "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*," \ + "-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*" + +#ifdef X_HAVE_UTF8_STRING +#define DRAWSTRING(x...) Xutf8DrawString(x) +#else +#define DRAWSTRING(x...) XmbDrawString(x) +#endif + +char *bar_argv[] = { NULL, NULL }; +int bar_pipe[2]; +unsigned char bar_ext[SWM_BAR_MAX]; +char bar_vertext[SWM_BAR_MAX]; +int bar_version = 0; +sig_atomic_t bar_alarm = 0; +int bar_delay = 30; +int bar_enabled = 1; +int bar_border_width = 1; +int bar_at_bottom = 0; +int bar_extra = 1; +int bar_extra_running = 0; +int bar_verbose = 1; +int bar_height = 0; +int bar_justify = SWM_BAR_JUSTIFY_LEFT; +int stack_enabled = 1; +int clock_enabled = 1; +int urgent_enabled = 0; +char *clock_format = NULL; +int title_name_enabled = 0; +int title_class_enabled = 0; +int window_name_enabled = 0; +int focus_mode = SWM_FOCUS_DEFAULT; +int disable_border = 0; +int border_width = 1; +int verbose_layout = 0; +pid_t bar_pid; +XFontSet bar_fs; +XFontSetExtents *bar_fs_extents; +char *bar_fonts; +char *spawn_term[] = { NULL, NULL }; /* XXX fully dynamic */ +struct passwd *pwd; + +#define SWM_MENU_FN (2) +#define SWM_MENU_NB (4) +#define SWM_MENU_NF (6) +#define SWM_MENU_SB (8) +#define SWM_MENU_SF (10) + +/* layout manager data */ +struct swm_geometry { + int x; + int y; + int w; + int h; +}; + +struct swm_screen; +struct workspace; + +/* virtual "screens" */ +struct swm_region { + TAILQ_ENTRY(swm_region) entry; + struct swm_geometry g; + struct workspace *ws; /* current workspace on this region */ + struct workspace *ws_prior; /* prior workspace on this region */ + struct swm_screen *s; /* screen idx */ + Window bar_window; +}; +TAILQ_HEAD(swm_region_list, swm_region); + +struct ws_win { + TAILQ_ENTRY(ws_win) entry; + Window id; + Window transient; + struct ws_win *child_trans; /* transient child window */ + struct swm_geometry g; /* current geometry */ + struct swm_geometry g_float; /* geometry when floating */ + struct swm_geometry rg_float; /* region geom when floating */ + int g_floatvalid; /* g_float geometry validity */ + int floatmaxed; /* whether maxed by max_stack */ + int floating; + int manual; + int iconic; + unsigned int ewmh_flags; + int font_size_boundary[SWM_MAX_FONT_STEPS]; + int font_steps; + int last_inc; + int can_delete; + int take_focus; + int java; + unsigned long quirks; + struct workspace *ws; /* always valid */ + struct swm_screen *s; /* always valid, never changes */ + XWindowAttributes wa; + XSizeHints sh; + long sh_mask; + XClassHint ch; + XWMHints *hints; +}; +TAILQ_HEAD(ws_win_list, ws_win); + +/* pid goo */ +struct pid_e { + TAILQ_ENTRY(pid_e) entry; + long pid; + int ws; +}; +TAILQ_HEAD(pid_list, pid_e); +struct pid_list pidlist = TAILQ_HEAD_INITIALIZER(pidlist); + +/* layout handlers */ +void stack(void); +void vertical_config(struct workspace *, int); +void vertical_stack(struct workspace *, struct swm_geometry *); +void horizontal_config(struct workspace *, int); +void horizontal_stack(struct workspace *, struct swm_geometry *); +void max_stack(struct workspace *, struct swm_geometry *); +void plain_stacker(struct workspace *); +void fancy_stacker(struct workspace *); + +struct ws_win *find_window(Window); + +void grabbuttons(struct ws_win *, int); +void new_region(struct swm_screen *, int, int, int, int); +void unmanage_window(struct ws_win *); +long getstate(Window); + +int conf_load(char *, int); + +struct layout { + void (*l_stack)(struct workspace *, struct swm_geometry *); + void (*l_config)(struct workspace *, int); + u_int32_t flags; +#define SWM_L_FOCUSPREV (1<<0) +#define SWM_L_MAPONFOCUS (1<<1) + void (*l_string)(struct workspace *); +} layouts[] = { + /* stack, configure */ + { vertical_stack, vertical_config, 0, plain_stacker }, + { horizontal_stack, horizontal_config, 0, plain_stacker }, + { max_stack, NULL, + SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV, plain_stacker }, + { NULL, NULL, 0, NULL }, +}; + +/* position of max_stack mode in the layouts array, index into layouts! */ +#define SWM_V_STACK (0) +#define SWM_H_STACK (1) +#define SWM_MAX_STACK (2) + +#define SWM_H_SLICE (32) +#define SWM_V_SLICE (32) + +/* define work spaces */ +struct workspace { + int idx; /* workspace index */ + char *name; /* workspace name */ + int always_raise; /* raise windows on focus */ + struct layout *cur_layout; /* current layout handlers */ + struct ws_win *focus; /* may be NULL */ + struct ws_win *focus_prev; /* may be NULL */ + struct swm_region *r; /* may be NULL */ + struct swm_region *old_r; /* may be NULL */ + struct ws_win_list winlist; /* list of windows in ws */ + struct ws_win_list unmanagedlist; /* list of dead windows in ws */ + char stacker[10]; /* display stacker and layout */ + + /* stacker state */ + struct { + int horizontal_msize; + int horizontal_mwin; + int horizontal_stacks; + int horizontal_flip; + int vertical_msize; + int vertical_mwin; + int vertical_stacks; + int vertical_flip; + } l_state; +}; + +enum { SWM_S_COLOR_BAR, SWM_S_COLOR_BAR_BORDER, SWM_S_COLOR_BAR_FONT, + SWM_S_COLOR_FOCUS, SWM_S_COLOR_UNFOCUS, SWM_S_COLOR_MAX }; + +/* physical screen mapping */ +#define SWM_WS_MAX (10) +struct swm_screen { + int idx; /* screen index */ + struct swm_region_list rl; /* list of regions on this screen */ + struct swm_region_list orl; /* list of old regions */ + Window root; + struct workspace ws[SWM_WS_MAX]; + + /* colors */ + struct { + unsigned long color; + char *name; + } c[SWM_S_COLOR_MAX]; + + GC bar_gc; +}; +struct swm_screen *screens; +int num_screens; + +/* args to functions */ +union arg { + int id; +#define SWM_ARG_ID_FOCUSNEXT (0) +#define SWM_ARG_ID_FOCUSPREV (1) +#define SWM_ARG_ID_FOCUSMAIN (2) +#define SWM_ARG_ID_FOCUSCUR (4) +#define SWM_ARG_ID_SWAPNEXT (10) +#define SWM_ARG_ID_SWAPPREV (11) +#define SWM_ARG_ID_SWAPMAIN (12) +#define SWM_ARG_ID_MOVELAST (13) +#define SWM_ARG_ID_MASTERSHRINK (20) +#define SWM_ARG_ID_MASTERGROW (21) +#define SWM_ARG_ID_MASTERADD (22) +#define SWM_ARG_ID_MASTERDEL (23) +#define SWM_ARG_ID_FLIPLAYOUT (24) +#define SWM_ARG_ID_STACKRESET (30) +#define SWM_ARG_ID_STACKINIT (31) +#define SWM_ARG_ID_CYCLEWS_UP (40) +#define SWM_ARG_ID_CYCLEWS_DOWN (41) +#define SWM_ARG_ID_CYCLESC_UP (42) +#define SWM_ARG_ID_CYCLESC_DOWN (43) +#define SWM_ARG_ID_CYCLEWS_UP_ALL (44) +#define SWM_ARG_ID_CYCLEWS_DOWN_ALL (45) +#define SWM_ARG_ID_STACKINC (50) +#define SWM_ARG_ID_STACKDEC (51) +#define SWM_ARG_ID_SS_ALL (60) +#define SWM_ARG_ID_SS_WINDOW (61) +#define SWM_ARG_ID_DONTCENTER (70) +#define SWM_ARG_ID_CENTER (71) +#define SWM_ARG_ID_KILLWINDOW (80) +#define SWM_ARG_ID_DELETEWINDOW (81) +#define SWM_ARG_ID_WIDTHGROW (90) +#define SWM_ARG_ID_WIDTHSHRINK (91) +#define SWM_ARG_ID_HEIGHTGROW (92) +#define SWM_ARG_ID_HEIGHTSHRINK (93) +#define SWM_ARG_ID_MOVEUP (100) +#define SWM_ARG_ID_MOVEDOWN (101) +#define SWM_ARG_ID_MOVELEFT (102) +#define SWM_ARG_ID_MOVERIGHT (103) + char **argv; +}; + +void focus(struct swm_region *, union arg *); +void focus_magic(struct ws_win *); + +/* quirks */ +struct quirk { + TAILQ_ENTRY(quirk) entry; + char *class; + char *name; + unsigned long quirk; +#define SWM_Q_FLOAT (1<<0) /* float this window */ +#define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */ +#define SWM_Q_ANYWHERE (1<<2) /* don't position this window */ +#define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */ +#define SWM_Q_FULLSCREEN (1<<4) /* remove border */ +#define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */ +}; +TAILQ_HEAD(quirk_list, quirk); +struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); + +/* + * Supported EWMH hints should be added to + * both the enum and the ewmh array + */ +enum { _NET_ACTIVE_WINDOW, _NET_MOVERESIZE_WINDOW, _NET_CLOSE_WINDOW, + _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK, + _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_UTILITY, + _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_DIALOG, + _NET_WM_WINDOW_TYPE_NORMAL, _NET_WM_STATE, + _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER, + _NET_WM_STATE_HIDDEN, _NET_WM_STATE_ABOVE, _SWM_WM_STATE_MANUAL, + _NET_WM_STATE_FULLSCREEN, _NET_WM_ALLOWED_ACTIONS, _NET_WM_ACTION_MOVE, + _NET_WM_ACTION_RESIZE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_CLOSE, + SWM_EWMH_HINT_MAX }; + +struct ewmh_hint { + char *name; + Atom atom; +} ewmh[SWM_EWMH_HINT_MAX] = { + /* must be in same order as in the enum */ + {"_NET_ACTIVE_WINDOW", None}, + {"_NET_MOVERESIZE_WINDOW", None}, + {"_NET_CLOSE_WINDOW", None}, + {"_NET_WM_WINDOW_TYPE", None}, + {"_NET_WM_WINDOW_TYPE_DOCK", None}, + {"_NET_WM_WINDOW_TYPE_TOOLBAR", None}, + {"_NET_WM_WINDOW_TYPE_UTILITY", None}, + {"_NET_WM_WINDOW_TYPE_SPLASH", None}, + {"_NET_WM_WINDOW_TYPE_DIALOG", None}, + {"_NET_WM_WINDOW_TYPE_NORMAL", None}, + {"_NET_WM_STATE", None}, + {"_NET_WM_STATE_MAXIMIZED_HORZ", None}, + {"_NET_WM_STATE_MAXIMIZED_VERT", None}, + {"_NET_WM_STATE_SKIP_TASKBAR", None}, + {"_NET_WM_STATE_SKIP_PAGER", None}, + {"_NET_WM_STATE_HIDDEN", None}, + {"_NET_WM_STATE_ABOVE", None}, + {"_SWM_WM_STATE_MANUAL", None}, + {"_NET_WM_STATE_FULLSCREEN", None}, + {"_NET_WM_ALLOWED_ACTIONS", None}, + {"_NET_WM_ACTION_MOVE", None}, + {"_NET_WM_ACTION_RESIZE", None}, + {"_NET_WM_ACTION_FULLSCREEN", None}, + {"_NET_WM_ACTION_CLOSE", None}, +}; + +void store_float_geom(struct ws_win *, struct swm_region *); +int floating_toggle_win(struct ws_win *); +void spawn_select(struct swm_region *, union arg *, char *, int *); +unsigned char *get_win_name(Window); + +int +get_property(Window id, Atom atom, long count, Atom type, unsigned long *nitems, + unsigned long *nbytes, unsigned char **data) +{ + int format, status; + unsigned long *nbytes_ret, *nitems_ret; + unsigned long nbytes_tmp, nitems_tmp; + Atom real; + + nbytes_ret = nbytes != NULL ? nbytes : &nbytes_tmp; + nitems_ret = nitems != NULL ? nitems : &nitems_tmp; + + status = XGetWindowProperty(display, id, atom, 0L, count, False, type, + &real, &format, nitems_ret, nbytes_ret, data); + + if (status != Success) + return False; + if (real != type) + return False; + + return True; +} + +void +update_iconic(struct ws_win *win, int newv) +{ + int32_t v = newv; + Atom iprop; + + win->iconic = newv; + + iprop = XInternAtom(display, "_SWM_ICONIC", False); + if (!iprop) + return; + if (newv) + XChangeProperty(display, win->id, iprop, XA_INTEGER, 32, + PropModeReplace, (unsigned char *)&v, 1); + else + XDeleteProperty(display, win->id, iprop); +} + +int +get_iconic(struct ws_win *win) +{ + int32_t v = 0; + int retfmt, status; + Atom iprop, rettype; + unsigned long nitems, extra; + unsigned char *prop = NULL; + + iprop = XInternAtom(display, "_SWM_ICONIC", False); + if (!iprop) + goto out; + status = XGetWindowProperty(display, win->id, iprop, 0L, 1L, + False, XA_INTEGER, &rettype, &retfmt, &nitems, &extra, &prop); + if (status != Success) + goto out; + if (rettype != XA_INTEGER || retfmt != 32) + goto out; + if (nitems != 1) + goto out; + v = *((int32_t *)prop); + +out: + if (prop != NULL) + XFree(prop); + return (v); +} + +void +setup_ewmh(void) +{ + int i,j; + Atom sup_list; + + sup_list = XInternAtom(display, "_NET_SUPPORTED", False); + + for (i = 0; i < LENGTH(ewmh); i++) + ewmh[i].atom = XInternAtom(display, ewmh[i].name, False); + + for (i = 0; i < ScreenCount(display); i++) { + /* Support check window will be created by workaround(). */ + + /* Report supported atoms */ + XDeleteProperty(display, screens[i].root, sup_list); + for (j = 0; j < LENGTH(ewmh); j++) + XChangeProperty(display, screens[i].root, + sup_list, XA_ATOM, 32, + PropModeAppend, (unsigned char *)&ewmh[j].atom,1); + } +} + +void +teardown_ewmh(void) +{ + int i, success; + unsigned char *data = NULL; + unsigned long n; + Atom sup_check, sup_list; + Window id; + + sup_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); + sup_list = XInternAtom(display, "_NET_SUPPORTED", False); + + for (i = 0; i < ScreenCount(display); i++) { + /* Get the support check window and destroy it */ + success = get_property(screens[i].root, sup_check, 1, XA_WINDOW, + &n, NULL, &data); + + if (success) { + id = data[0]; + XDestroyWindow(display, id); + XDeleteProperty(display, screens[i].root, sup_check); + XDeleteProperty(display, screens[i].root, sup_list); + } + + XFree(data); + } +} + +void +ewmh_autoquirk(struct ws_win *win) +{ + int success, i; + unsigned long *data = NULL, n; + Atom type; + + success = get_property(win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, (~0L), + XA_ATOM, &n, NULL, (void *)&data); + + if (!success) { + XFree(data); + return; + } + + for (i = 0; i < n; i++) { + type = data[i]; + if (type == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom) + break; + if (type == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom || + type == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom || + type == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) { + win->floating = 1; + win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE; + break; + } + if (type == ewmh[_NET_WM_WINDOW_TYPE_SPLASH].atom || + type == ewmh[_NET_WM_WINDOW_TYPE_DIALOG].atom) { + win->floating = 1; + win->quirks = SWM_Q_FLOAT; + break; + } + } + + XFree(data); +} + +#define SWM_EWMH_ACTION_COUNT_MAX (6) +#define EWMH_F_FULLSCREEN (1<<0) +#define EWMH_F_ABOVE (1<<1) +#define EWMH_F_HIDDEN (1<<2) +#define EWMH_F_SKIP_PAGER (1<<3) +#define EWMH_F_SKIP_TASKBAR (1<<4) +#define SWM_F_MANUAL (1<<5) + +int +ewmh_set_win_fullscreen(struct ws_win *win, int fs) +{ + struct swm_geometry rg; + + if (!win->ws->r) + return 0; + + if (!win->floating) + return 0; + + DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: window: 0x%lx, " + "fullscreen %s\n", win->id, YESNO(fs)); + + rg = win->ws->r->g; + + if (fs) { + store_float_geom(win, win->ws->r); + + win->g = rg; + } else { + if (win->g_floatvalid) { + /* refloat at last floating relative position */ + X(win) = win->g_float.x - win->rg_float.x + rg.x; + Y(win) = win->g_float.y - win->rg_float.y + rg.y; + WIDTH(win) = win->g_float.w; + HEIGHT(win) = win->g_float.h; + } + } + + return 1; +} + +void +ewmh_update_actions(struct ws_win *win) +{ + Atom actions[SWM_EWMH_ACTION_COUNT_MAX]; + int n = 0; + + if (win == NULL) + return; + + actions[n++] = ewmh[_NET_WM_ACTION_CLOSE].atom; + + if (win->floating) { + actions[n++] = ewmh[_NET_WM_ACTION_MOVE].atom; + actions[n++] = ewmh[_NET_WM_ACTION_RESIZE].atom; + } + + XChangeProperty(display, win->id, ewmh[_NET_WM_ALLOWED_ACTIONS].atom, + XA_ATOM, 32, PropModeReplace, (unsigned char *)actions, n); +} + +#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ + +void +ewmh_update_win_state(struct ws_win *win, long state, long action) +{ + unsigned int mask = 0; + unsigned int changed = 0; + unsigned int orig_flags; + + if (win == NULL) + return; + + if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) + mask = EWMH_F_FULLSCREEN; + if (state == ewmh[_NET_WM_STATE_ABOVE].atom) + mask = EWMH_F_ABOVE; + if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) + mask = SWM_F_MANUAL; + if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom) + mask = EWMH_F_SKIP_PAGER; + if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom) + mask = EWMH_F_SKIP_TASKBAR; + + + orig_flags = win->ewmh_flags; + + switch (action) { + case _NET_WM_STATE_REMOVE: + win->ewmh_flags &= ~mask; + break; + case _NET_WM_STATE_ADD: + win->ewmh_flags |= mask; + break; + case _NET_WM_STATE_TOGGLE: + win->ewmh_flags ^= mask; + break; + } + + changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0; + + if (state == ewmh[_NET_WM_STATE_ABOVE].atom) + if (changed) + if (!floating_toggle_win(win)) + win->ewmh_flags = orig_flags; /* revert */ + if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) + if (changed) + win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0; + if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) + if (changed) + if (!ewmh_set_win_fullscreen(win, + win->ewmh_flags & EWMH_F_FULLSCREEN)) + win->ewmh_flags = orig_flags; /* revert */ + + XDeleteProperty(display, win->id, ewmh[_NET_WM_STATE].atom); + + if (win->ewmh_flags & EWMH_F_FULLSCREEN) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_FULLSCREEN].atom, 1); + if (win->ewmh_flags & EWMH_F_SKIP_PAGER) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_PAGER].atom, 1); + if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom, 1); + if (win->ewmh_flags & EWMH_F_ABOVE) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_NET_WM_STATE_ABOVE].atom, 1); + if (win->ewmh_flags & SWM_F_MANUAL) + XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeAppend, + (unsigned char *)&ewmh[_SWM_WM_STATE_MANUAL].atom, 1); +} + +void +ewmh_get_win_state(struct ws_win *win) +{ + int success, i; + unsigned long n; + Atom *states; + + if (win == NULL) + return; + + win->ewmh_flags = 0; + if (win->floating) + win->ewmh_flags |= EWMH_F_ABOVE; + if (win->manual) + win->ewmh_flags |= SWM_F_MANUAL; + + success = get_property(win->id, ewmh[_NET_WM_STATE].atom, + (~0L), XA_ATOM, &n, NULL, (void *)&states); + + if (!success) + return; + + for (i = 0; i < n; i++) + ewmh_update_win_state(win, states[i], _NET_WM_STATE_ADD); + + XFree(states); +} + +/* events */ +#ifdef SWM_DEBUG +char * +geteventname(XEvent *e) +{ + char *name = NULL; + + switch (e->type) { + case KeyPress: + name = "KeyPress"; + break; + case KeyRelease: + name = "KeyRelease"; + break; + case ButtonPress: + name = "ButtonPress"; + break; + case ButtonRelease: + name = "ButtonRelease"; + break; + case MotionNotify: + name = "MotionNotify"; + break; + case EnterNotify: + name = "EnterNotify"; + break; + case LeaveNotify: + name = "LeaveNotify"; + break; + case FocusIn: + name = "FocusIn"; + break; + case FocusOut: + name = "FocusOut"; + break; + case KeymapNotify: + name = "KeymapNotify"; + break; + case Expose: + name = "Expose"; + break; + case GraphicsExpose: + name = "GraphicsExpose"; + break; + case NoExpose: + name = "NoExpose"; + break; + case VisibilityNotify: + name = "VisibilityNotify"; + break; + case CreateNotify: + name = "CreateNotify"; + break; + case DestroyNotify: + name = "DestroyNotify"; + break; + case UnmapNotify: + name = "UnmapNotify"; + break; + case MapNotify: + name = "MapNotify"; + break; + case MapRequest: + name = "MapRequest"; + break; + case ReparentNotify: + name = "ReparentNotify"; + break; + case ConfigureNotify: + name = "ConfigureNotify"; + break; + case ConfigureRequest: + name = "ConfigureRequest"; + break; + case GravityNotify: + name = "GravityNotify"; + break; + case ResizeRequest: + name = "ResizeRequest"; + break; + case CirculateNotify: + name = "CirculateNotify"; + break; + case CirculateRequest: + name = "CirculateRequest"; + break; + case PropertyNotify: + name = "PropertyNotify"; + break; + case SelectionClear: + name = "SelectionClear"; + break; + case SelectionRequest: + name = "SelectionRequest"; + break; + case SelectionNotify: + name = "SelectionNotify"; + break; + case ColormapNotify: + name = "ColormapNotify"; + break; + case ClientMessage: + name = "ClientMessage"; + break; + case MappingNotify: + name = "MappingNotify"; + break; + default: + name = "Unknown"; + } + + return name; +} + +char * +xrandr_geteventname(XEvent *e) +{ + char *name = NULL; + + switch(e->type - xrandr_eventbase) { + case RRScreenChangeNotify: + name = "RRScreenChangeNotify"; + break; + default: + name = "Unknown"; + } + + return name; +} + +void +dumpwins(struct swm_region *r, union arg *args) +{ + struct ws_win *win; + unsigned int state; + XWindowAttributes wa; + + if (r->ws == NULL) { + warnx("dumpwins: invalid workspace"); + return; + } + + warnx("=== managed window list ws %02d ===", r->ws->idx); + + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + state = getstate(win->id); + if (!XGetWindowAttributes(display, win->id, &wa)) + warnx("window: 0x%lx, failed XGetWindowAttributes", + win->id); + warnx("window: 0x%lx, map_state: %d, state: %d, " + "transient: 0x%lx", win->id, wa.map_state, state, + win->transient); + } + + warnx("===== unmanaged window list ====="); + TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) { + state = getstate(win->id); + if (!XGetWindowAttributes(display, win->id, &wa)) + warnx("window: 0x%lx, failed XGetWindowAttributes", + win->id); + warnx("window: 0x%lx, map_state: %d, state: %d, " + "transient: 0x%lx", win->id, wa.map_state, state, + win->transient); + } + + warnx("================================="); +} +#else +void +dumpwins(struct swm_region *r, union arg *args) +{ +} +#endif /* SWM_DEBUG */ + +void expose(XEvent *); +void keypress(XEvent *); +void buttonpress(XEvent *); +void configurerequest(XEvent *); +void configurenotify(XEvent *); +void destroynotify(XEvent *); +void enternotify(XEvent *); +void focusevent(XEvent *); +void mapnotify(XEvent *); +void mappingnotify(XEvent *); +void maprequest(XEvent *); +void propertynotify(XEvent *); +void unmapnotify(XEvent *); +void visibilitynotify(XEvent *); +void clientmessage(XEvent *); + +void (*handler[LASTEvent])(XEvent *) = { + [Expose] = expose, + [KeyPress] = keypress, + [ButtonPress] = buttonpress, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [FocusIn] = focusevent, + [FocusOut] = focusevent, + [MapNotify] = mapnotify, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify, + [VisibilityNotify] = visibilitynotify, + [ClientMessage] = clientmessage, +}; + +void +sighdlr(int sig) +{ + int saved_errno, status; + pid_t pid; + + saved_errno = errno; + + switch (sig) { + case SIGCHLD: + while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) { + if (pid == -1) { + if (errno == EINTR) + continue; +#ifdef SWM_DEBUG + if (errno != ECHILD) + warn("sighdlr: waitpid"); +#endif /* SWM_DEBUG */ + break; + } + if (pid == searchpid) + search_resp = 1; + +#ifdef SWM_DEBUG + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + warnx("sighdlr: child exit status: %d", + WEXITSTATUS(status)); + } else + warnx("sighdlr: child is terminated " + "abnormally"); +#endif /* SWM_DEBUG */ + } + break; + + case SIGHUP: + restart_wm = 1; + break; + case SIGINT: + case SIGTERM: + case SIGQUIT: + running = 0; + break; + } + + errno = saved_errno; +} + +struct pid_e * +find_pid(long pid) +{ + struct pid_e *p = NULL; + + DNPRINTF(SWM_D_MISC, "find_pid: %lu\n", pid); + + if (pid == 0) + return (NULL); + + TAILQ_FOREACH(p, &pidlist, entry) { + if (p->pid == pid) + return (p); + } + + return (NULL); +} + +unsigned long +name_to_color(char *colorname) +{ + Colormap cmap; + Status status; + XColor screen_def, exact_def; + unsigned long result = 0; + char cname[32] = "#"; + + cmap = DefaultColormap(display, screens[0].idx); + status = XAllocNamedColor(display, cmap, colorname, + &screen_def, &exact_def); + if (!status) { + strlcat(cname, colorname + 2, sizeof cname - 1); + status = XAllocNamedColor(display, cmap, cname, &screen_def, + &exact_def); + } + if (status) + result = screen_def.pixel; + else + warnx("color '%s' not found", colorname); + + return (result); +} + +void +setscreencolor(char *val, int i, int c) +{ + if (i > 0 && i <= ScreenCount(display)) { + screens[i - 1].c[c].color = name_to_color(val); + free(screens[i - 1].c[c].name); + if ((screens[i - 1].c[c].name = strdup(val)) == NULL) + err(1, "strdup"); + } else if (i == -1) { + for (i = 0; i < ScreenCount(display); i++) { + screens[i].c[c].color = name_to_color(val); + free(screens[i].c[c].name); + if ((screens[i].c[c].name = strdup(val)) == NULL) + err(1, "strdup"); + } + } else + errx(1, "invalid screen index: %d out of bounds (maximum %d)", + i, ScreenCount(display)); +} + +void +fancy_stacker(struct workspace *ws) +{ + strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); + if (ws->cur_layout->l_stack == vertical_stack) + snprintf(ws->stacker, sizeof ws->stacker, + ws->l_state.vertical_flip ? "[%d>%d]" : "[%d|%d]", + ws->l_state.vertical_mwin, ws->l_state.vertical_stacks); + if (ws->cur_layout->l_stack == horizontal_stack) + snprintf(ws->stacker, sizeof ws->stacker, + ws->l_state.horizontal_flip ? "[%dv%d]" : "[%d-%d]", + ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks); +} + +void +plain_stacker(struct workspace *ws) +{ + strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); + if (ws->cur_layout->l_stack == vertical_stack) + strlcpy(ws->stacker, ws->l_state.vertical_flip ? "[>]" : "[|]", + sizeof ws->stacker); + if (ws->cur_layout->l_stack == horizontal_stack) + strlcpy(ws->stacker, ws->l_state.horizontal_flip ? "[v]" : "[-]", + sizeof ws->stacker); +} + +void +custom_region(char *val) +{ + unsigned int sidx, x, y, w, h; + + if (sscanf(val, "screen[%u]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5) + errx(1, "invalid custom region, " + "should be 'screen[]:x++"); + if (sidx < 1 || sidx > ScreenCount(display)) + errx(1, "invalid screen index: %d out of bounds (maximum %d)", + sidx, ScreenCount(display)); + sidx--; + + if (w < 1 || h < 1) + errx(1, "region %ux%u+%u+%u too small", w, h, x, y); + + if (x > DisplayWidth(display, sidx) || + y > DisplayHeight(display, sidx) || + w + x > DisplayWidth(display, sidx) || + h + y > DisplayHeight(display, sidx)) { + warnx("ignoring region %ux%u+%u+%u - not within screen " + "boundaries (%ux%u)", w, h, x, y, + DisplayWidth(display, sidx), DisplayHeight(display, sidx)); + return; + } + + new_region(&screens[sidx], x, y, w, h); +} + +void +socket_setnonblock(int fd) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + err(1, "fcntl F_GETFL"); + flags |= O_NONBLOCK; + if ((flags = fcntl(fd, F_SETFL, flags)) == -1) + err(1, "fcntl F_SETFL"); +} + +void +bar_print(struct swm_region *r, char *s) +{ + int x = 0; + size_t len; + XRectangle ibox, lbox; + + XClearWindow(display, r->bar_window); + + len = strlen(s); + XmbTextExtents(bar_fs, s, len, &ibox, &lbox); + + switch (bar_justify) { + case SWM_BAR_JUSTIFY_LEFT: + x = SWM_BAR_OFFSET; + break; + case SWM_BAR_JUSTIFY_CENTER: + x = (WIDTH(r) - lbox.width) / 2; + break; + case SWM_BAR_JUSTIFY_RIGHT: + x = WIDTH(r) - lbox.width - SWM_BAR_OFFSET; + break; + } + + if (x < SWM_BAR_OFFSET) + x = SWM_BAR_OFFSET; + + DRAWSTRING(display, r->bar_window, bar_fs, r->s->bar_gc, + x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 - + lbox.y, s, len); +} + +void +bar_extra_stop(void) +{ + if (bar_pipe[0]) { + close(bar_pipe[0]); + bzero(bar_pipe, sizeof bar_pipe); + } + if (bar_pid) { + kill(bar_pid, SIGTERM); + bar_pid = 0; + } + strlcpy((char *)bar_ext, "", sizeof bar_ext); + bar_extra = 0; +} + +void +bar_class_name(char *s, ssize_t sz, struct ws_win *cur_focus) +{ + int do_class, do_name; + Status status; + XClassHint *xch = NULL; + + if ((title_name_enabled == 1 || title_class_enabled == 1) && + cur_focus != NULL) { + if ((xch = XAllocClassHint()) == NULL) + goto out; + status = XGetClassHint(display, cur_focus->id, xch); + if (status == BadWindow || status == BadAlloc) + goto out; + do_class = (title_class_enabled && xch->res_class != NULL); + do_name = (title_name_enabled && xch->res_name != NULL); + if (do_class) + strlcat(s, xch->res_class, sz); + if (do_class && do_name) + strlcat(s, ":", sz); + if (do_name) + strlcat(s, xch->res_name, sz); + strlcat(s, " ", sz); + } +out: + if (xch) { + XFree(xch->res_name); + XFree(xch->res_class); + XFree(xch); + } +} + +void +bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus) +{ + unsigned char *title; + + if (window_name_enabled && cur_focus != NULL) { + title = get_win_name(cur_focus->id); + if (title != NULL) { + DNPRINTF(SWM_D_BAR, "bar_window_name: title: %s\n", + title); + + if (cur_focus->floating) + strlcat(s, "(f) ", sz); + strlcat(s, (char *)title, sz); + strlcat(s, " ", sz); + XFree(title); + } + } +} + +int urgent[SWM_WS_MAX]; +void +bar_urgent(char *s, ssize_t sz) +{ + XWMHints *wmh = NULL; + struct ws_win *win; + int i, j; + char b[8]; + + if (urgent_enabled == 0) + return; + + for (i = 0; i < SWM_WS_MAX; i++) + urgent[i] = 0; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { + wmh = XGetWMHints(display, win->id); + if (wmh == NULL) + continue; + + if (wmh->flags & XUrgencyHint) + urgent[j] = 1; + XFree(wmh); + } + + strlcat(s, "* ", sz); + for (i = 0; i < SWM_WS_MAX; i++) { + if (urgent[i]) + snprintf(b, sizeof b, "%d ", i + 1); + else + snprintf(b, sizeof b, "- "); + strlcat(s, b, sz); + } + strlcat(s, "* ", sz); +} + +void +bar_update(void) +{ + time_t tmt; + struct tm tm; + struct swm_region *r; + int i, x; + size_t len; + char ws[SWM_BAR_MAX]; + char s[SWM_BAR_MAX]; + unsigned char cn[SWM_BAR_MAX]; + char loc[SWM_BAR_MAX]; + char *b, *stack = ""; + + if (bar_enabled == 0) + return; + if (bar_extra && bar_extra_running) { + /* ignore short reads; it'll correct itself */ + while ((b = fgetln(stdin, &len)) != NULL) + if (b && b[len - 1] == '\n') { + b[len - 1] = '\0'; + strlcpy((char *)bar_ext, b, sizeof bar_ext); + } + if (b == NULL && errno != EAGAIN) { + warn("bar_update: bar_extra failed"); + bar_extra_stop(); + } + } else + strlcpy((char *)bar_ext, "", sizeof bar_ext); + + if (clock_enabled == 0) + strlcpy(s, "", sizeof s); + else { + time(&tmt); + localtime_r(&tmt, &tm); + len = strftime(s, sizeof s, clock_format, &tm); + s[len] = '\0'; + strlcat(s, " ", sizeof s); + } + + for (i = 0; i < ScreenCount(display); i++) { + x = 1; + TAILQ_FOREACH(r, &screens[i].rl, entry) { + strlcpy((char *)cn, "", sizeof cn); + strlcpy(ws, "", sizeof ws); + if (r && r->ws) { + bar_urgent((char *)cn, sizeof cn); + bar_class_name((char *)cn, sizeof cn, + r->ws->focus); + bar_window_name((char *)cn, sizeof cn, + r->ws->focus); + if (r->ws->name) + snprintf(ws, sizeof ws, "<%s>", + r->ws->name); + } + if (stack_enabled) + stack = r->ws->stacker; + + snprintf(loc, sizeof loc, "%d:%d %s %s %s%s %s " + "%s", x++, r->ws->idx + 1, stack, ws, s, cn, + bar_ext, bar_vertext); + bar_print(r, loc); + } + } + alarm(bar_delay); +} + +void +bar_check_opts(void) +{ + if (title_class_enabled || title_name_enabled || window_name_enabled) + bar_update(); +} + +void +bar_signal(int sig) +{ + bar_alarm = 1; +} + +void +bar_toggle(struct swm_region *r, union arg *args) +{ + struct swm_region *tmpr; + int i, sc = ScreenCount(display); + + DNPRINTF(SWM_D_BAR, "bar_toggle\n"); + + if (bar_enabled) + for (i = 0; i < sc; i++) + TAILQ_FOREACH(tmpr, &screens[i].rl, entry) + XUnmapWindow(display, tmpr->bar_window); + else + for (i = 0; i < sc; i++) + TAILQ_FOREACH(tmpr, &screens[i].rl, entry) + XMapRaised(display, tmpr->bar_window); + + bar_enabled = !bar_enabled; + + stack(); + /* must be after stack */ + bar_update(); +} + +void +bar_refresh(void) +{ + XSetWindowAttributes wa; + struct swm_region *r; + int i; + + /* do this here because the conf file is in memory */ + if (bar_extra && bar_extra_running == 0 && bar_argv[0]) { + /* launch external status app */ + bar_extra_running = 1; + if (pipe(bar_pipe) == -1) + err(1, "pipe error"); + socket_setnonblock(bar_pipe[0]); + socket_setnonblock(bar_pipe[1]); /* XXX hmmm, really? */ + if (dup2(bar_pipe[0], 0) == -1) + err(1, "dup2"); + if (dup2(bar_pipe[1], 1) == -1) + err(1, "dup2"); + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + err(1, "could not disable SIGPIPE"); + switch (bar_pid = fork()) { + case -1: + err(1, "cannot fork"); + break; + case 0: /* child */ + close(bar_pipe[0]); + execvp(bar_argv[0], bar_argv); + err(1, "%s external app failed", bar_argv[0]); + break; + default: /* parent */ + close(bar_pipe[1]); + break; + } + } + + bzero(&wa, sizeof wa); + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) { + wa.border_pixel = + screens[i].c[SWM_S_COLOR_BAR_BORDER].color; + wa.background_pixel = + screens[i].c[SWM_S_COLOR_BAR].color; + XChangeWindowAttributes(display, r->bar_window, + CWBackPixel | CWBorderPixel, &wa); + } + bar_update(); +} + +void +bar_setup(struct swm_region *r) +{ + char *default_string; + char **missing_charsets; + int num_missing_charsets = 0; + int i, x, y; + + if (bar_fs) { + XFreeFontSet(display, bar_fs); + bar_fs = NULL; + } + + + DNPRINTF(SWM_D_BAR, "bar_setup: loading bar_fonts: %s\n", bar_fonts); + + bar_fs = XCreateFontSet(display, bar_fonts, &missing_charsets, + &num_missing_charsets, &default_string); + + if (num_missing_charsets > 0) { + warnx("Unable to load charset(s):"); + + for (i = 0; i < num_missing_charsets; ++i) + warnx("%s", missing_charsets[i]); + + XFreeStringList(missing_charsets); + + if (strcmp(default_string, "")) + warnx("Glyphs from those sets will be replaced " + "by '%s'.", default_string); + else + warnx("Glyphs from those sets won't be drawn."); + } + + if (bar_fs == NULL) + errx(1, "Error creating font set structure."); + + bar_fs_extents = XExtentsOfFontSet(bar_fs); + + bar_height = bar_fs_extents->max_logical_extent.height + + 2 * bar_border_width; + + if (bar_height < 1) + bar_height = 1; + + x = X(r); + y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r); + + r->bar_window = XCreateSimpleWindow(display, + r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, + bar_height - 2 * bar_border_width, + bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color, + r->s->c[SWM_S_COLOR_BAR].color); + XSelectInput(display, r->bar_window, VisibilityChangeMask); + if (bar_enabled) + XMapRaised(display, r->bar_window); + DNPRINTF(SWM_D_BAR, "bar_setup: bar_window: 0x%lx\n", r->bar_window); + + if (signal(SIGALRM, bar_signal) == SIG_ERR) + err(1, "could not install bar_signal"); + bar_refresh(); +} + +void +drain_enter_notify(void) +{ + int i = 0; + XEvent cne; + + while (XCheckMaskEvent(display, EnterWindowMask, &cne)) + i++; + + DNPRINTF(SWM_D_MISC, "drain_enter_notify: drained: %d\n", i); +} + +void +set_win_state(struct ws_win *win, long state) +{ + long data[] = {state, None}; + + DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%lx\n", win->id); + + if (win == NULL) + return; + + XChangeProperty(display, win->id, astate, astate, 32, PropModeReplace, + (unsigned char *)data, 2); +} + +long +getstate(Window w) +{ + long result = -1; + unsigned char *p = NULL; + unsigned long n; + + if (!get_property(w, astate, 2L, astate, &n, NULL, &p)) + return (-1); + if (n != 0) + result = *((long *)p); + XFree(p); + return (result); +} + +void +version(struct swm_region *r, union arg *args) +{ + bar_version = !bar_version; + if (bar_version) + snprintf(bar_vertext, sizeof bar_vertext, + "Version: %s Build: %s", SPECTRWM_VERSION, buildstr); + else + strlcpy(bar_vertext, "", sizeof bar_vertext); + bar_update(); +} + +void +client_msg(struct ws_win *win, Atom a) +{ + XClientMessageEvent cm; + + if (win == NULL) + return; + + bzero(&cm, sizeof cm); + cm.type = ClientMessage; + cm.window = win->id; + cm.message_type = aprot; + cm.format = 32; + cm.data.l[0] = a; + cm.data.l[1] = CurrentTime; + XSendEvent(display, win->id, False, 0L, (XEvent *)&cm); +} + +/* synthetic response to a ConfigureRequest when not making a change */ +void +config_win(struct ws_win *win, XConfigureRequestEvent *ev) +{ + XConfigureEvent ce; + + if (win == NULL) + return; + + /* send notification of unchanged state. */ + ce.type = ConfigureNotify; + ce.x = X(win); + ce.y = Y(win); + ce.width = WIDTH(win); + ce.height = HEIGHT(win); + ce.override_redirect = False; + + if (ev == NULL) { + /* EWMH */ + ce.display = display; + ce.event = win->id; + ce.window = win->id; + ce.border_width = border_width; + ce.above = None; + } else { + /* normal */ + ce.display = ev->display; + ce.event = ev->window; + ce.window = ev->window; + + /* make response appear more WM_SIZE_HINTS-compliant */ + if (win->sh_mask) + DNPRINTF(SWM_D_MISC, "config_win: hints: window: 0x%lx," + " sh_mask: %ld, min: %d x %d, max: %d x %d, inc: " + "%d x %d\n", win->id, win->sh_mask, SH_MIN_W(win), + SH_MIN_H(win), SH_MAX_W(win), SH_MAX_H(win), + SH_INC_W(win), SH_INC_H(win)); + + /* min size */ + if (SH_MIN(win)) { + /* the hint may be set... to 0! */ + if (SH_MIN_W(win) > 0 && ce.width < SH_MIN_W(win)) + ce.width = SH_MIN_W(win); + if (SH_MIN_H(win) > 0 && ce.height < SH_MIN_H(win)) + ce.height = SH_MIN_H(win); + } + + /* max size */ + if (SH_MAX(win)) { + /* may also be advertized as 0 */ + if (SH_MAX_W(win) > 0 && ce.width > SH_MAX_W(win)) + ce.width = SH_MAX_W(win); + if (SH_MAX_H(win) > 0 && ce.height > SH_MAX_H(win)) + ce.height = SH_MAX_H(win); + } + + /* resize increment. */ + if (SH_INC(win)) { + if (SH_INC_W(win) > 1 && ce.width > SH_INC_W(win)) + ce.width -= (ce.width - SH_MIN_W(win)) % + SH_INC_W(win); + if (SH_INC_H(win) > 1 && ce.height > SH_INC_H(win)) + ce.height -= (ce.height - SH_MIN_H(win)) % + SH_INC_H(win); + } + + /* adjust x and y for requested border_width. */ + ce.x += border_width - ev->border_width; + ce.y += border_width - ev->border_width; + ce.border_width = ev->border_width; + ce.above = ev->above; + } + + DNPRINTF(SWM_D_MISC, "config_win: ewmh: %s, window: 0x%lx, (x,y) w x h: " + "(%d,%d) %d x %d, border: %d\n", YESNO(ev == NULL), win->id, ce.x, + ce.y, ce.width, ce.height, ce.border_width); + + XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&ce); +} + +int +count_win(struct workspace *ws, int count_transient) +{ + struct ws_win *win; + int count = 0; + + TAILQ_FOREACH(win, &ws->winlist, entry) { + if (count_transient == 0 && win->floating) + continue; + if (count_transient == 0 && win->transient) + continue; + if (win->iconic) + continue; + count++; + } + DNPRINTF(SWM_D_MISC, "count_win: %d\n", count); + + return (count); +} + +void +quit(struct swm_region *r, union arg *args) +{ + DNPRINTF(SWM_D_MISC, "quit\n"); + running = 0; +} + +void +unmap_window(struct ws_win *win) +{ + if (win == NULL) + return; + + /* don't unmap again */ + if (getstate(win->id) == IconicState) + return; + + set_win_state(win, IconicState); + + XUnmapWindow(display, win->id); + XSetWindowBorder(display, win->id, + win->s->c[SWM_S_COLOR_UNFOCUS].color); +} + +void +unmap_all(void) +{ + struct ws_win *win; + int i, j; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + unmap_window(win); +} + +void +fake_keypress(struct ws_win *win, int keysym, int modifiers) +{ + XKeyEvent event; + + if (win == NULL) + return; + + event.display = display; /* Ignored, but what the hell */ + event.window = win->id; + event.root = win->s->root; + event.subwindow = None; + event.time = CurrentTime; + event.x = X(win); + event.y = Y(win); + event.x_root = 1; + event.y_root = 1; + event.same_screen = True; + event.keycode = XKeysymToKeycode(display, keysym); + event.state = modifiers; + + event.type = KeyPress; + XSendEvent(event.display, event.window, True, + KeyPressMask, (XEvent *)&event); + + event.type = KeyRelease; + XSendEvent(event.display, event.window, True, + KeyPressMask, (XEvent *)&event); + +} + +void +restart(struct swm_region *r, union arg *args) +{ + DNPRINTF(SWM_D_MISC, "restart: %s\n", start_argv[0]); + + /* disable alarm because the following code may not be interrupted */ + alarm(0); + if (signal(SIGALRM, SIG_IGN) == SIG_ERR) + err(1, "can't disable alarm"); + + bar_extra_stop(); + bar_extra = 1; + unmap_all(); + XCloseDisplay(display); + execvp(start_argv[0], start_argv); + warn("execvp failed"); + quit(NULL, NULL); +} + +struct swm_region * +root_to_region(Window root) +{ + struct swm_region *r = NULL; + Window rr, cr; + int i, x, y, wx, wy; + unsigned int mask; + + for (i = 0; i < ScreenCount(display); i++) + if (screens[i].root == root) + break; + + if (XQueryPointer(display, screens[i].root, + &rr, &cr, &x, &y, &wx, &wy, &mask) != False) { + /* choose a region based on pointer location */ + TAILQ_FOREACH(r, &screens[i].rl, entry) + if (x >= X(r) && x <= X(r) + WIDTH(r) && + y >= Y(r) && y <= Y(r) + HEIGHT(r)) + break; + } + + if (r == NULL) + r = TAILQ_FIRST(&screens[i].rl); + + return (r); +} + +struct ws_win * +find_unmanaged_window(Window id) +{ + struct ws_win *win; + int i, j; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist, + entry) + if (id == win->id) + return (win); + return (NULL); +} + +struct ws_win * +find_window(Window id) +{ + struct ws_win *win; + Window wrr, wpr, *wcr = NULL; + int i, j; + unsigned int nc; + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + if (id == win->id) + return (win); + + /* if we were looking for the parent return that window instead */ + if (XQueryTree(display, id, &wrr, &wpr, &wcr, &nc) == 0) + return (NULL); + if (wcr) + XFree(wcr); + + /* ignore not found and root */ + if (wpr == 0 || wrr == wpr) + return (NULL); + + /* look for parent */ + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + if (wpr == win->id) + return (win); + + return (NULL); +} + +void +spawn(int ws_idx, union arg *args, int close_fd) +{ + int fd; + char *ret = NULL; + + DNPRINTF(SWM_D_MISC, "spawn: %s\n", args->argv[0]); + + if (display) + close(ConnectionNumber(display)); + + setenv("LD_PRELOAD", SWM_LIB, 1); + + if (asprintf(&ret, "%d", ws_idx) == -1) { + warn("spawn: asprintf SWM_WS"); + _exit(1); + } + setenv("_SWM_WS", ret, 1); + free(ret); + ret = NULL; + + if (asprintf(&ret, "%d", getpid()) == -1) { + warn("spawn: asprintf _SWM_PID"); + _exit(1); + } + setenv("_SWM_PID", ret, 1); + free(ret); + ret = NULL; + + if (setsid() == -1) { + warn("spawn: setsid"); + _exit(1); + } + + if (close_fd) { + /* + * close stdin and stdout to prevent interaction between apps + * and the baraction script + * leave stderr open to record errors + */ + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) { + warn("spawn: open"); + _exit(1); + } + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + if (fd > 2) + close(fd); + } + + execvp(args->argv[0], args->argv); + + warn("spawn: execvp"); + _exit(1); +} + +void +spawnterm(struct swm_region *r, union arg *args) +{ + DNPRINTF(SWM_D_MISC, "spawnterm\n"); + + if (fork() == 0) { + if (term_width) + setenv("_SWM_XTERM_FONTADJ", "", 1); + spawn(r->ws->idx, args, 1); + } +} + +void +kill_refs(struct ws_win *win) +{ + int i, x; + struct swm_region *r; + struct workspace *ws; + + if (win == NULL) + return; + + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) + for (x = 0; x < SWM_WS_MAX; x++) { + ws = &r->s->ws[x]; + if (win == ws->focus) + ws->focus = NULL; + if (win == ws->focus_prev) + ws->focus_prev = NULL; + } +} + +int +validate_win(struct ws_win *testwin) +{ + struct ws_win *win; + struct workspace *ws; + struct swm_region *r; + int i, x; + + if (testwin == NULL) + return (0); + + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) + for (x = 0; x < SWM_WS_MAX; x++) { + ws = &r->s->ws[x]; + TAILQ_FOREACH(win, &ws->winlist, entry) + if (win == testwin) + return (0); + } + return (1); +} + +int +validate_ws(struct workspace *testws) +{ + struct swm_region *r; + struct workspace *ws; + int i, x; + + /* validate all ws */ + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) + for (x = 0; x < SWM_WS_MAX; x++) { + ws = &r->s->ws[x]; + if (ws == testws) + return (0); + } + return (1); +} + +void +unfocus_win(struct ws_win *win) +{ + XEvent cne; + Window none = None; + + DNPRINTF(SWM_D_FOCUS, "unfocus_win: window: 0x%lx\n", WINID(win)); + + if (win == NULL) + return; + if (win->ws == NULL) + return; + + if (validate_ws(win->ws)) + return; /* XXX this gets hit with thunderbird, needs fixing */ + + if (win->ws->r == NULL) + return; + + if (validate_win(win)) { + kill_refs(win); + return; + } + + if (win->ws->focus == win) { + win->ws->focus = NULL; + win->ws->focus_prev = win; + } + + if (validate_win(win->ws->focus)) { + kill_refs(win->ws->focus); + win->ws->focus = NULL; + } + if (validate_win(win->ws->focus_prev)) { + kill_refs(win->ws->focus_prev); + win->ws->focus_prev = NULL; + } + + /* drain all previous unfocus events */ + while (XCheckTypedEvent(display, FocusOut, &cne) == True) + ; + + grabbuttons(win, 0); + XSetWindowBorder(display, win->id, + win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); + + XChangeProperty(display, win->s->root, + ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&none,1); +} + +void +unfocus_all(void) +{ + struct ws_win *win; + int i, j; + + DNPRINTF(SWM_D_FOCUS, "unfocus_all\n"); + + for (i = 0; i < ScreenCount(display); i++) + for (j = 0; j < SWM_WS_MAX; j++) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + unfocus_win(win); +} + +void +focus_win(struct ws_win *win) +{ + XEvent cne; + Window cur_focus; + int rr; + struct ws_win *cfw = NULL; + + + DNPRINTF(SWM_D_FOCUS, "focus_win: window: 0x%lx\n", WINID(win)); + + if (win == NULL) + return; + if (win->ws == NULL) + return; + + if (validate_ws(win->ws)) + return; /* XXX this gets hit with thunderbird, needs fixing */ + + if (validate_win(win)) { + kill_refs(win); + return; + } + + if (validate_win(win)) { + kill_refs(win); + return; + } + + XGetInputFocus(display, &cur_focus, &rr); + if ((cfw = find_window(cur_focus)) != NULL) + unfocus_win(cfw); + else { + /* use larger hammer since the window was killed somehow */ + TAILQ_FOREACH(cfw, &win->ws->winlist, entry) + if (cfw->ws && cfw->ws->r && cfw->ws->r->s) + XSetWindowBorder(display, cfw->id, + cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color); + } + + win->ws->focus = win; + + if (win->ws->r != NULL) { + /* drain all previous focus events */ + while (XCheckTypedEvent(display, FocusIn, &cne) == True) + ; + + if (win->java == 0) + XSetInputFocus(display, win->id, + RevertToParent, CurrentTime); + grabbuttons(win, 1); + XSetWindowBorder(display, win->id, + win->ws->r->s->c[SWM_S_COLOR_FOCUS].color); + if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS || + win->ws->always_raise) + XMapRaised(display, win->id); + + XChangeProperty(display, win->s->root, + ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&win->id,1); + } + + bar_check_opts(); +} + +void +switchws(struct swm_region *r, union arg *args) +{ + int wsid = args->id, unmap_old = 0; + struct swm_region *this_r, *other_r; + struct ws_win *win; + struct workspace *new_ws, *old_ws; + union arg a; + + if (!(r && r->s)) + return; + + this_r = r; + old_ws = this_r->ws; + new_ws = &this_r->s->ws[wsid]; + + DNPRINTF(SWM_D_WS, "switchws: screen[%d]:%dx%d+%d+%d: %d -> %d\n", + r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), old_ws->idx, wsid); + + if (new_ws == NULL || old_ws == NULL) + return; + if (new_ws == old_ws) + return; + + other_r = new_ws->r; + if (other_r == NULL) { + /* the other workspace is hidden, hide this one */ + old_ws->r = NULL; + unmap_old = 1; + } else { + /* the other ws is visible in another region, exchange them */ + other_r->ws_prior = new_ws; + other_r->ws = old_ws; + old_ws->r = other_r; + } + this_r->ws_prior = old_ws; + this_r->ws = new_ws; + new_ws->r = this_r; + + /* this is needed so that we can click on a window after a restart */ + unfocus_all(); + + stack(); + a.id = SWM_ARG_ID_FOCUSCUR; + focus(new_ws->r, &a); + + bar_update(); + + /* unmap old windows */ + if (unmap_old) + TAILQ_FOREACH(win, &old_ws->winlist, entry) + unmap_window(win); + + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); +} + +void +cyclews(struct swm_region *r, union arg *args) +{ + union arg a; + struct swm_screen *s = r->s; + int cycle_all = 0; + + DNPRINTF(SWM_D_WS, "cyclews: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", + args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); + + a.id = r->ws->idx; + do { + switch (args->id) { + case SWM_ARG_ID_CYCLEWS_UP_ALL: + cycle_all = 1; + /* FALLTHROUGH */ + case SWM_ARG_ID_CYCLEWS_UP: + if (a.id < SWM_WS_MAX - 1) + a.id++; + else + a.id = 0; + break; + case SWM_ARG_ID_CYCLEWS_DOWN_ALL: + cycle_all = 1; + /* FALLTHROUGH */ + case SWM_ARG_ID_CYCLEWS_DOWN: + if (a.id > 0) + a.id--; + else + a.id = SWM_WS_MAX - 1; + break; + default: + return; + }; + + if (!cycle_all && + (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist))) + continue; + if (cycle_visible == 0 && s->ws[a.id].r != NULL) + continue; + + switchws(r, &a); + } while (a.id != r->ws->idx); +} + +void +priorws(struct swm_region *r, union arg *args) +{ + union arg a; + + DNPRINTF(SWM_D_WS, "priorws: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", + args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); + + if (r->ws_prior == NULL) + return; + + a.id = r->ws_prior->idx; + switchws(r, &a); +} + +void +cyclescr(struct swm_region *r, union arg *args) +{ + struct swm_region *rr = NULL; + union arg a; + int i, x, y; + + /* do nothing if we don't have more than one screen */ + if (!(ScreenCount(display) > 1 || outputs > 1)) + return; + + i = r->s->idx; + switch (args->id) { + case SWM_ARG_ID_CYCLESC_UP: + rr = TAILQ_NEXT(r, entry); + if (rr == NULL) + rr = TAILQ_FIRST(&screens[i].rl); + break; + case SWM_ARG_ID_CYCLESC_DOWN: + rr = TAILQ_PREV(r, swm_region_list, entry); + if (rr == NULL) + rr = TAILQ_LAST(&screens[i].rl, swm_region_list); + break; + default: + return; + }; + if (rr == NULL) + return; + + /* move mouse to region */ + x = X(rr) + 1; + y = Y(rr) + 1 + (bar_enabled ? bar_height : 0); + XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y); + + a.id = SWM_ARG_ID_FOCUSCUR; + focus(rr, &a); + + if (rr->ws->focus) { + /* move to focus window */ + x = X(rr->ws->focus) + 1; + y = Y(rr->ws->focus) + 1; + XWarpPointer(display, None, rr->s[i].root, 0, 0, 0, 0, x, y); + } +} + +void +sort_windows(struct ws_win_list *wl) +{ + struct ws_win *win, *parent, *nxt; + + if (wl == NULL) + return; + + for (win = TAILQ_FIRST(wl); win != TAILQ_END(wl); win = nxt) { + nxt = TAILQ_NEXT(win, entry); + if (win->transient) { + parent = find_window(win->transient); + if (parent == NULL) { + warnx("not possible bug"); + continue; + } + TAILQ_REMOVE(wl, win, entry); + TAILQ_INSERT_AFTER(wl, parent, win, entry); + } + } + +} + +void +swapwin(struct swm_region *r, union arg *args) +{ + struct ws_win *target, *source; + struct ws_win *cur_focus; + struct ws_win_list *wl; + + + DNPRINTF(SWM_D_WS, "swapwin: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n", + args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx); + + cur_focus = r->ws->focus; + if (cur_focus == NULL) + return; + + source = cur_focus; + wl = &source->ws->winlist; + + switch (args->id) { + case SWM_ARG_ID_SWAPPREV: + if (source->transient) + source = find_window(source->transient); + target = TAILQ_PREV(source, ws_win_list, entry); + if (target && target->transient) + target = find_window(target->transient); + TAILQ_REMOVE(wl, source, entry); + if (target == NULL) + TAILQ_INSERT_TAIL(wl, source, entry); + else + TAILQ_INSERT_BEFORE(target, source, entry); + break; + case SWM_ARG_ID_SWAPNEXT: + target = TAILQ_NEXT(source, entry); + /* move the parent and let the sort handle the move */ + if (source->transient) + source = find_window(source->transient); + TAILQ_REMOVE(wl, source, entry); + if (target == NULL) + TAILQ_INSERT_HEAD(wl, source, entry); + else + TAILQ_INSERT_AFTER(wl, target, source, entry); + break; + case SWM_ARG_ID_SWAPMAIN: + target = TAILQ_FIRST(wl); + if (target == source) { + if (source->ws->focus_prev != NULL && + source->ws->focus_prev != target) + + source = source->ws->focus_prev; + else + return; + } + if (target == NULL || source == NULL) + return; + source->ws->focus_prev = target; + TAILQ_REMOVE(wl, target, entry); + TAILQ_INSERT_BEFORE(source, target, entry); + TAILQ_REMOVE(wl, source, entry); + TAILQ_INSERT_HEAD(wl, source, entry); + break; + case SWM_ARG_ID_MOVELAST: + TAILQ_REMOVE(wl, source, entry); + TAILQ_INSERT_TAIL(wl, source, entry); + break; + default: + DNPRINTF(SWM_D_MOVE, "swapwin: invalid id: %d\n", args->id); + return; + } + + sort_windows(wl); + + stack(); +} + +void +focus_prev(struct ws_win *win) +{ + struct ws_win *winfocus = NULL; + struct ws_win *cur_focus = NULL; + struct ws_win_list *wl = NULL; + struct workspace *ws = NULL; + + DNPRINTF(SWM_D_FOCUS, "focus_prev: window: 0x%lx\n", WINID(win)); + + if (!(win && win->ws)) + return; + + ws = win->ws; + wl = &ws->winlist; + cur_focus = ws->focus; + + /* pickle, just focus on whatever */ + if (cur_focus == NULL) { + /* use prev_focus if valid */ + if (ws->focus_prev && ws->focus_prev != cur_focus && + find_window(WINID(ws->focus_prev))) + winfocus = ws->focus_prev; + if (winfocus == NULL) + winfocus = TAILQ_FIRST(wl); + goto done; + } + + /* if transient focus on parent */ + if (cur_focus->transient) { + winfocus = find_window(cur_focus->transient); + goto done; + } + + /* if in max_stack try harder */ + if ((win->quirks & SWM_Q_FOCUSPREV) || + (ws->cur_layout->flags & SWM_L_FOCUSPREV)) { + if (cur_focus != ws->focus_prev) + winfocus = ws->focus_prev; + else if (cur_focus != ws->focus) + winfocus = ws->focus; + else + winfocus = TAILQ_PREV(win, ws_win_list, entry); + if (winfocus) + goto done; + } + + if (cur_focus == win) + winfocus = TAILQ_PREV(win, ws_win_list, entry); + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, ws_win_list); + if (winfocus == NULL || winfocus == win) + winfocus = TAILQ_NEXT(cur_focus, entry); + +done: + focus_magic(winfocus); +} + +void +focus(struct swm_region *r, union arg *args) +{ + struct ws_win *winfocus = NULL, *head; + struct ws_win *cur_focus = NULL; + struct ws_win_list *wl = NULL; + struct workspace *ws = NULL; + int all_iconics; + + if (!(r && r->ws)) + return; + + DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id); + + /* treat FOCUS_CUR special */ + if (args->id == SWM_ARG_ID_FOCUSCUR) { + if (r->ws->focus && r->ws->focus->iconic == 0) + winfocus = r->ws->focus; + else if (r->ws->focus_prev && r->ws->focus_prev->iconic == 0) + winfocus = r->ws->focus_prev; + else + TAILQ_FOREACH(winfocus, &r->ws->winlist, entry) + if (winfocus->iconic == 0) + break; + + focus_magic(winfocus); + return; + } + + if ((cur_focus = r->ws->focus) == NULL) + return; + ws = r->ws; + wl = &ws->winlist; + if (TAILQ_EMPTY(wl)) + return; + /* make sure there is at least one uniconified window */ + all_iconics = 1; + TAILQ_FOREACH(winfocus, wl, entry) + if (winfocus->iconic == 0) { + all_iconics = 0; + break; + } + if (all_iconics) + return; + + switch (args->id) { + case SWM_ARG_ID_FOCUSPREV: + head = TAILQ_PREV(cur_focus, ws_win_list, entry); + if (head == NULL) + head = TAILQ_LAST(wl, ws_win_list); + winfocus = head; + if (WINID(winfocus) == cur_focus->transient) { + head = TAILQ_PREV(winfocus, ws_win_list, entry); + if (head == NULL) + head = TAILQ_LAST(wl, ws_win_list); + winfocus = head; + } + + /* skip iconics */ + if (winfocus && winfocus->iconic) { + while (winfocus != cur_focus) { + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, ws_win_list); + if (winfocus->iconic == 0) + break; + winfocus = TAILQ_PREV(winfocus, ws_win_list, + entry); + } + } + break; + + case SWM_ARG_ID_FOCUSNEXT: + head = TAILQ_NEXT(cur_focus, entry); + if (head == NULL) + head = TAILQ_FIRST(wl); + winfocus = head; + + /* skip iconics */ + if (winfocus && winfocus->iconic) { + while (winfocus != cur_focus) { + if (winfocus == NULL) + winfocus = TAILQ_FIRST(wl); + if (winfocus->iconic == 0) + break; + winfocus = TAILQ_NEXT(winfocus, entry); + } + } + break; + + case SWM_ARG_ID_FOCUSMAIN: + winfocus = TAILQ_FIRST(wl); + if (winfocus == cur_focus) + winfocus = cur_focus->ws->focus_prev; + break; + + default: + return; + } + + focus_magic(winfocus); +} + +void +cycle_layout(struct swm_region *r, union arg *args) +{ + struct workspace *ws = r->ws; + union arg a; + + DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx); + + ws->cur_layout++; + if (ws->cur_layout->l_stack == NULL) + ws->cur_layout = &layouts[0]; + + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + a.id = SWM_ARG_ID_FOCUSCUR; + focus(r, &a); + bar_update(); +} + +void +stack_config(struct swm_region *r, union arg *args) +{ + struct workspace *ws = r->ws; + + DNPRINTF(SWM_D_STACK, "stack_config: id: %d workspace: %d\n", + args->id, ws->idx); + + if (ws->cur_layout->l_config != NULL) + ws->cur_layout->l_config(ws, args->id); + + if (args->id != SWM_ARG_ID_STACKINIT) + stack(); + bar_update(); +} + +void +stack(void) { + struct swm_geometry g; + struct swm_region *r; + int i; +#ifdef SWM_DEBUG + int j; +#endif + + DNPRINTF(SWM_D_STACK, "stack: begin\n"); + + for (i = 0; i < ScreenCount(display); i++) { +#ifdef SWM_DEBUG + j = 0; +#endif + TAILQ_FOREACH(r, &screens[i].rl, entry) { + DNPRINTF(SWM_D_STACK, "stack: workspace: %d " + "(screen: %d, region: %d)\n", r->ws->idx, i, j++); + + /* start with screen geometry, adjust for bar */ + g = r->g; + g.w -= 2 * border_width; + g.h -= 2 * border_width; + if (bar_enabled) { + if (!bar_at_bottom) + g.y += bar_height; + g.h -= bar_height; + } + r->ws->cur_layout->l_stack(r->ws, &g); + r->ws->cur_layout->l_string(r->ws); + /* save r so we can track region changes */ + r->ws->old_r = r; + } + } + if (font_adjusted) + font_adjusted--; + + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + + DNPRINTF(SWM_D_STACK, "stack: end\n"); +} + +void +store_float_geom(struct ws_win *win, struct swm_region *r) +{ + /* retain window geom and region geom */ + win->g_float = win->g; + win->rg_float = r->g; + win->g_floatvalid = 1; +} + +void +stack_floater(struct ws_win *win, struct swm_region *r) +{ + unsigned int mask; + XWindowChanges wc; + + if (win == NULL) + return; + + bzero(&wc, sizeof wc); + mask = CWX | CWY | CWBorderWidth | CWWidth | CWHeight; + + /* + * to allow windows to change their size (e.g. mplayer fs) only retrieve + * geom on ws switches or return from max mode + */ + if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid + && !(win->ewmh_flags & EWMH_F_FULLSCREEN))) { + /* + * use stored g and rg to set relative position and size + * as in old region or before max stack mode + */ + X(win) = win->g_float.x - win->rg_float.x + X(r); + Y(win) = win->g_float.y - win->rg_float.y + Y(r); + WIDTH(win) = win->g_float.w; + HEIGHT(win) = win->g_float.h; + win->g_floatvalid = 0; + } + + win->floatmaxed = 0; + + if ((win->quirks & SWM_Q_FULLSCREEN) && (WIDTH(win) >= WIDTH(r)) && + (HEIGHT(win) >= HEIGHT(r))) + wc.border_width = 0; + else + wc.border_width = border_width; + if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) { + WIDTH(win) = (double)WIDTH(r) * dialog_ratio; + HEIGHT(win) = (double)HEIGHT(r) * dialog_ratio; + } + + if (!win->manual) { + /* + * floaters and transients are auto-centred unless moved + * or resized + */ + X(win) = X(r) + (WIDTH(r) - WIDTH(win)) / 2 - wc.border_width; + Y(win) = Y(r) + (HEIGHT(r) - HEIGHT(win)) / 2 - wc.border_width; + } + + /* win can be outside r if new r smaller than old r */ + /* Ensure top left corner inside r (move probs otherwise) */ + if (X(win) < X(r) - wc.border_width) + X(win) = X(r) - wc.border_width; + if (X(win) > X(r) + WIDTH(r) - 1) + X(win) = (WIDTH(win) > WIDTH(r)) ? X(r) : + (X(r) + WIDTH(r) - WIDTH(win) - 2 * wc.border_width); + if (Y(win) < Y(r) - wc.border_width) + Y(win) = Y(r) - wc.border_width; + if (Y(win) > Y(r) + HEIGHT(r) - 1) + Y(win) = (HEIGHT(win) > HEIGHT(r)) ? Y(r) : + (Y(r) + HEIGHT(r) - HEIGHT(win) - 2 * wc.border_width); + + wc.x = X(win); + wc.y = Y(win); + wc.width = WIDTH(win); + wc.height = HEIGHT(win); + + /* + * Retain floater and transient geometry for correct positioning + * when ws changes region + */ + if (!(win->ewmh_flags & EWMH_F_FULLSCREEN)) + store_float_geom(win, r); + + DNPRINTF(SWM_D_MISC, "stack_floater: window: %lu, (x,y) w x h: (%d,%d) " + "%d x %d\n", win->id, wc.x, wc.y, wc.width, wc.height); + + XConfigureWindow(display, win->id, mask, &wc); +} + +/* + * Send keystrokes to terminal to decrease/increase the font size as the + * window size changes. + */ +void +adjust_font(struct ws_win *win) +{ + if (!(win->quirks & SWM_Q_XTERM_FONTADJ) || + win->floating || win->transient) + return; + + if (win->sh.width_inc && win->last_inc != win->sh.width_inc && + WIDTH(win) / win->sh.width_inc < term_width && + win->font_steps < SWM_MAX_FONT_STEPS) { + win->font_size_boundary[win->font_steps] = + (win->sh.width_inc * term_width) + win->sh.base_width; + win->font_steps++; + font_adjusted++; + win->last_inc = win->sh.width_inc; + fake_keypress(win, XK_KP_Subtract, ShiftMask); + } else if (win->font_steps && win->last_inc != win->sh.width_inc && + WIDTH(win) > win->font_size_boundary[win->font_steps - 1]) { + win->font_steps--; + font_adjusted++; + win->last_inc = win->sh.width_inc; + fake_keypress(win, XK_KP_Add, ShiftMask); + } +} + +#define SWAPXY(g) do { \ + int tmp; \ + tmp = (g)->y; (g)->y = (g)->x; (g)->x = tmp; \ + tmp = (g)->h; (g)->h = (g)->w; (g)->w = tmp; \ +} while (0) +void +stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) +{ + XWindowChanges wc; + XWindowAttributes wa; + struct swm_geometry win_g, r_g = *g; + struct ws_win *win, *fs_win = 0; + int i, j, s, stacks; + int w_inc = 1, h_inc, w_base = 1, h_base; + int hrh, extra = 0, h_slice, last_h = 0; + int split, colno, winno, mwin, msize, mscale; + int remain, missing, v_slice, reconfigure; + unsigned int mask; + + DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, " + "flip: %s\n", ws->idx, YESNO(rot), YESNO(flip)); + + winno = count_win(ws, 0); + if (winno == 0 && count_win(ws, 1) == 0) + return; + + TAILQ_FOREACH(win, &ws->winlist, entry) + if (win->transient == 0 && win->floating == 0 + && win->iconic == 0) + break; + + if (win == NULL) + goto notiles; + + if (rot) { + w_inc = win->sh.width_inc; + w_base = win->sh.base_width; + mwin = ws->l_state.horizontal_mwin; + mscale = ws->l_state.horizontal_msize; + stacks = ws->l_state.horizontal_stacks; + SWAPXY(&r_g); + } else { + w_inc = win->sh.height_inc; + w_base = win->sh.base_height; + mwin = ws->l_state.vertical_mwin; + mscale = ws->l_state.vertical_msize; + stacks = ws->l_state.vertical_stacks; + } + win_g = r_g; + + if (stacks > winno - mwin) + stacks = winno - mwin; + if (stacks < 1) + stacks = 1; + + h_slice = r_g.h / SWM_H_SLICE; + if (mwin && winno > mwin) { + v_slice = r_g.w / SWM_V_SLICE; + + split = mwin; + colno = split; + win_g.w = v_slice * mscale; + + if (w_inc > 1 && w_inc < v_slice) { + /* adjust for window's requested size increment */ + remain = (win_g.w - w_base) % w_inc; + missing = w_inc - remain; + win_g.w -= remain; + extra += remain; + } + + msize = win_g.w; + if (flip) + win_g.x += r_g.w - msize; + } else { + msize = -2; + colno = split = winno / stacks; + win_g.w = ((r_g.w - (stacks * 2 * border_width) + + 2 * border_width) / stacks); + } + hrh = r_g.h / colno; + extra = r_g.h - (colno * hrh); + win_g.h = hrh - 2 * border_width; + + /* stack all the tiled windows */ + i = j = 0, s = stacks; + TAILQ_FOREACH(win, &ws->winlist, entry) { + if (win->transient != 0 || win->floating != 0) + continue; + if (win->iconic != 0) + continue; + + if (win->ewmh_flags & EWMH_F_FULLSCREEN) { + fs_win = win; + continue; + } + + if (split && i == split) { + colno = (winno - mwin) / stacks; + if (s <= (winno - mwin) % stacks) + colno++; + split = split + colno; + hrh = (r_g.h / colno); + extra = r_g.h - (colno * hrh); + if (flip) + win_g.x = r_g.x; + else + win_g.x += win_g.w + 2 * border_width; + win_g.w = (r_g.w - msize - + (stacks * 2 * border_width)) / stacks; + if (s == 1) + win_g.w += (r_g.w - msize - + (stacks * 2 * border_width)) % stacks; + s--; + j = 0; + } + win_g.h = hrh - 2 * border_width; + if (rot) { + h_inc = win->sh.width_inc; + h_base = win->sh.base_width; + } else { + h_inc = win->sh.height_inc; + h_base = win->sh.base_height; + } + if (j == colno - 1) { + win_g.h = hrh + extra; + } else if (h_inc > 1 && h_inc < h_slice) { + /* adjust for window's requested size increment */ + remain = (win_g.h - h_base) % h_inc; + missing = h_inc - remain; + + if (missing <= extra || j == 0) { + extra -= missing; + win_g.h += missing; + } else { + win_g.h -= remain; + extra += remain; + } + } + + if (j == 0) + win_g.y = r_g.y; + else + win_g.y += last_h + 2 * border_width; + + bzero(&wc, sizeof wc); + if (disable_border && bar_enabled == 0 && winno == 1){ + wc.border_width = 0; + win_g.w += 2 * border_width; + win_g.h += 2 * border_width; + } else + wc.border_width = border_width; + reconfigure = 0; + if (rot) { + if (X(win) != win_g.y || Y(win) != win_g.x || + WIDTH(win) != win_g.h || HEIGHT(win) != win_g.w) { + reconfigure = 1; + X(win) = wc.x = win_g.y; + Y(win) = wc.y = win_g.x; + WIDTH(win) = wc.width = win_g.h; + HEIGHT(win) = wc.height = win_g.w; + } + } else { + if (X(win) != win_g.x || Y(win) != win_g.y || + WIDTH(win) != win_g.w || HEIGHT(win) != win_g.h) { + reconfigure = 1; + X(win) = wc.x = win_g.x; + Y(win) = wc.y = win_g.y; + WIDTH(win) = wc.width = win_g.w; + HEIGHT(win) = wc.height = win_g.h; + } + } + if (reconfigure) { + adjust_font(win); + mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; + XConfigureWindow(display, win->id, mask, &wc); + } + + if (XGetWindowAttributes(display, win->id, &wa)) + if (wa.map_state == IsUnmapped) + XMapRaised(display, win->id); + + last_h = win_g.h; + i++; + j++; + } + +notiles: + /* now, stack all the floaters and transients */ + TAILQ_FOREACH(win, &ws->winlist, entry) { + if (win->transient == 0 && win->floating == 0) + continue; + if (win->iconic == 1) + continue; + if (win->ewmh_flags & EWMH_F_FULLSCREEN) { + fs_win = win; + continue; + } + + stack_floater(win, ws->r); + XMapRaised(display, win->id); + } + + if (fs_win) { + stack_floater(fs_win, ws->r); + XMapRaised(display, fs_win->id); + } +} + +void +vertical_config(struct workspace *ws, int id) +{ + DNPRINTF(SWM_D_STACK, "vertical_config: id: %d, workspace: %d\n", + id, ws->idx); + + switch (id) { + case SWM_ARG_ID_STACKRESET: + case SWM_ARG_ID_STACKINIT: + ws->l_state.vertical_msize = SWM_V_SLICE / 2; + ws->l_state.vertical_mwin = 1; + ws->l_state.vertical_stacks = 1; + break; + case SWM_ARG_ID_MASTERSHRINK: + if (ws->l_state.vertical_msize > 1) + ws->l_state.vertical_msize--; + break; + case SWM_ARG_ID_MASTERGROW: + if (ws->l_state.vertical_msize < SWM_V_SLICE - 1) + ws->l_state.vertical_msize++; + break; + case SWM_ARG_ID_MASTERADD: + ws->l_state.vertical_mwin++; + break; + case SWM_ARG_ID_MASTERDEL: + if (ws->l_state.vertical_mwin > 0) + ws->l_state.vertical_mwin--; + break; + case SWM_ARG_ID_STACKINC: + ws->l_state.vertical_stacks++; + break; + case SWM_ARG_ID_STACKDEC: + if (ws->l_state.vertical_stacks > 1) + ws->l_state.vertical_stacks--; + break; + case SWM_ARG_ID_FLIPLAYOUT: + ws->l_state.vertical_flip = !ws->l_state.vertical_flip; + break; + default: + return; + } +} + +void +vertical_stack(struct workspace *ws, struct swm_geometry *g) +{ + DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); + + stack_master(ws, g, 0, ws->l_state.vertical_flip); +} + +void +horizontal_config(struct workspace *ws, int id) +{ + DNPRINTF(SWM_D_STACK, "horizontal_config: workspace: %d\n", ws->idx); + + switch (id) { + case SWM_ARG_ID_STACKRESET: + case SWM_ARG_ID_STACKINIT: + ws->l_state.horizontal_mwin = 1; + ws->l_state.horizontal_msize = SWM_H_SLICE / 2; + ws->l_state.horizontal_stacks = 1; + break; + case SWM_ARG_ID_MASTERSHRINK: + if (ws->l_state.horizontal_msize > 1) + ws->l_state.horizontal_msize--; + break; + case SWM_ARG_ID_MASTERGROW: + if (ws->l_state.horizontal_msize < SWM_H_SLICE - 1) + ws->l_state.horizontal_msize++; + break; + case SWM_ARG_ID_MASTERADD: + ws->l_state.horizontal_mwin++; + break; + case SWM_ARG_ID_MASTERDEL: + if (ws->l_state.horizontal_mwin > 0) + ws->l_state.horizontal_mwin--; + break; + case SWM_ARG_ID_STACKINC: + ws->l_state.horizontal_stacks++; + break; + case SWM_ARG_ID_STACKDEC: + if (ws->l_state.horizontal_stacks > 1) + ws->l_state.horizontal_stacks--; + break; + case SWM_ARG_ID_FLIPLAYOUT: + ws->l_state.horizontal_flip = !ws->l_state.horizontal_flip; + break; + default: + return; + } +} + +void +horizontal_stack(struct workspace *ws, struct swm_geometry *g) +{ + DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx); + + stack_master(ws, g, 1, ws->l_state.horizontal_flip); +} + +/* fullscreen view */ +void +max_stack(struct workspace *ws, struct swm_geometry *g) +{ + XWindowChanges wc; + struct swm_geometry gg = *g; + struct ws_win *win, *wintrans = NULL, *parent = NULL; + unsigned int mask; + int winno; + + DNPRINTF(SWM_D_STACK, "max_stack: workspace: %d\n", ws->idx); + + if (ws == NULL) + return; + + winno = count_win(ws, 0); + if (winno == 0 && count_win(ws, 1) == 0) + return; + + TAILQ_FOREACH(win, &ws->winlist, entry) { + if (win->transient) { + wintrans = win; + parent = find_window(win->transient); + continue; + } + + if (win->floating && win->floatmaxed == 0 ) { + /* + * retain geometry for retrieval on exit from + * max_stack mode + */ + store_float_geom(win, ws->r); + win->floatmaxed = 1; + } + + /* only reconfigure if necessary */ + if (X(win) != gg.x || Y(win) != gg.y || WIDTH(win) != gg.w || + HEIGHT(win) != gg.h) { + bzero(&wc, sizeof wc); + X(win) = wc.x = gg.x; + Y(win) = wc.y = gg.y; + if (bar_enabled){ + wc.border_width = border_width; + WIDTH(win) = wc.width = gg.w; + HEIGHT(win) = wc.height = gg.h; + } else { + wc.border_width = 0; + WIDTH(win) = wc.width = gg.w + 2 * border_width; + HEIGHT(win) = wc.height = gg.h + + 2 * border_width; + } + mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; + XConfigureWindow(display, win->id, mask, &wc); + } + /* unmap only if we don't have multi screen */ + if (win != ws->focus) + if (!(ScreenCount(display) > 1 || outputs > 1)) + unmap_window(win); + } + + /* put the last transient on top */ + if (wintrans) { + if (parent) + XMapRaised(display, parent->id); + stack_floater(wintrans, ws->r); + focus_magic(wintrans); + } +} + +void +send_to_ws(struct swm_region *r, union arg *args) +{ + int wsid = args->id; + struct ws_win *win = NULL, *parent; + struct workspace *ws, *nws; + Atom ws_idx_atom = 0; + unsigned char ws_idx_str[SWM_PROPLEN]; + union arg a; + + if (r && r->ws && r->ws->focus) + win = r->ws->focus; + else + return; + if (win == NULL) + return; + if (win->ws->idx == wsid) + return; + + DNPRINTF(SWM_D_MOVE, "send_to_ws: window: 0x%lx\n", win->id); + + ws = win->ws; + nws = &win->s->ws[wsid]; + + a.id = SWM_ARG_ID_FOCUSPREV; + focus(r, &a); + if (win->transient) { + parent = find_window(win->transient); + if (parent) { + unmap_window(parent); + TAILQ_REMOVE(&ws->winlist, parent, entry); + TAILQ_INSERT_TAIL(&nws->winlist, parent, entry); + parent->ws = nws; + } + } + unmap_window(win); + TAILQ_REMOVE(&ws->winlist, win, entry); + TAILQ_INSERT_TAIL(&nws->winlist, win, entry); + if (TAILQ_EMPTY(&ws->winlist)) + r->ws->focus = NULL; + win->ws = nws; + + /* Try to update the window's workspace property */ + ws_idx_atom = XInternAtom(display, "_SWM_WS", False); + if (ws_idx_atom && + snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < + SWM_PROPLEN) { + DNPRINTF(SWM_D_PROP, "send_to_ws: set property: _SWM_WS: %s\n", + ws_idx_str); + XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, + PropModeReplace, ws_idx_str, strlen((char *)ws_idx_str)); + } + + stack(); +} + +void +pressbutton(struct swm_region *r, union arg *args) +{ + XTestFakeButtonEvent(display, args->id, True, CurrentTime); + XTestFakeButtonEvent(display, args->id, False, CurrentTime); +} + +void +raise_toggle(struct swm_region *r, union arg *args) +{ + if (r && r->ws == NULL) + return; + + r->ws->always_raise = !r->ws->always_raise; + + /* bring floaters back to top */ + if (r->ws->always_raise == 0) + stack(); +} + +void +iconify(struct swm_region *r, union arg *args) +{ + union arg a; + + if (r->ws->focus == NULL) + return; + unmap_window(r->ws->focus); + update_iconic(r->ws->focus, 1); + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + r->ws->focus = NULL; + a.id = SWM_ARG_ID_FOCUSCUR; + focus(r, &a); +} + +unsigned char * +get_win_name(Window win) +{ + unsigned char *prop = NULL; + unsigned long nbytes, nitems; + + /* try _NET_WM_NAME first */ + if (get_property(win, a_netwmname, 0L, a_utf8_string, NULL, &nbytes, + &prop)) { + XFree(prop); + if (get_property(win, a_netwmname, nbytes, a_utf8_string, + &nitems, NULL, &prop)) + return (prop); + } + + /* fallback to WM_NAME */ + if (!get_property(win, a_wmname, 0L, a_string, NULL, &nbytes, &prop)) + return (NULL); + XFree(prop); + if (get_property(win, a_wmname, nbytes, a_string, &nitems, NULL, &prop)) + return (prop); + + return (NULL); +} + +void +uniconify(struct swm_region *r, union arg *args) +{ + struct ws_win *win; + FILE *lfile; + unsigned char *name; + int count = 0; + + DNPRINTF(SWM_D_MISC, "uniconify\n"); + + if (r && r->ws == NULL) + return; + + /* make sure we have anything to uniconify */ + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + if (win->ws == NULL) + continue; /* should never happen */ + if (win->iconic == 0) + continue; + count++; + } + if (count == 0) + return; + + search_r = r; + search_resp_action = SWM_SEARCH_UNICONIFY; + + spawn_select(r, args, "search", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + if (win->ws == NULL) + continue; /* should never happen */ + if (win->iconic == 0) + continue; + + name = get_win_name(win->id); + if (name == NULL) + continue; + fprintf(lfile, "%s.%lu\n", name, win->id); + XFree(name); + } + + fclose(lfile); +} + +void +name_workspace(struct swm_region *r, union arg *args) +{ + FILE *lfile; + + DNPRINTF(SWM_D_MISC, "name_workspace\n"); + + if (r == NULL) + return; + + search_r = r; + search_resp_action = SWM_SEARCH_NAME_WORKSPACE; + + spawn_select(r, args, "name_workspace", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + fprintf(lfile, "%s", ""); + fclose(lfile); +} + +void +search_workspace(struct swm_region *r, union arg *args) +{ + int i; + struct workspace *ws; + FILE *lfile; + + DNPRINTF(SWM_D_MISC, "search_workspace\n"); + + if (r == NULL) + return; + + search_r = r; + search_resp_action = SWM_SEARCH_SEARCH_WORKSPACE; + + spawn_select(r, args, "search", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + for (i = 0; i < SWM_WS_MAX; i++) { + ws = &r->s->ws[i]; + if (ws == NULL) + continue; + fprintf(lfile, "%d%s%s\n", ws->idx + 1, + (ws->name ? ":" : ""), (ws->name ? ws->name : "")); + } + + fclose(lfile); +} + +void +search_win_cleanup(void) +{ + struct search_window *sw = NULL; + + while ((sw = TAILQ_FIRST(&search_wl)) != NULL) { + XDestroyWindow(display, sw->indicator); + XFreeGC(display, sw->gc); + TAILQ_REMOVE(&search_wl, sw, entry); + free(sw); + } +} + +void +search_win(struct swm_region *r, union arg *args) +{ + struct ws_win *win = NULL; + struct search_window *sw = NULL; + Window w; + XGCValues gcv; + int i; + char s[8]; + FILE *lfile; + size_t len; + XRectangle ibox, lbox; + + DNPRINTF(SWM_D_MISC, "search_win\n"); + + search_r = r; + search_resp_action = SWM_SEARCH_SEARCH_WINDOW; + + spawn_select(r, args, "search", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + TAILQ_INIT(&search_wl); + + i = 1; + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + if (win->iconic == 1) + continue; + + sw = calloc(1, sizeof(struct search_window)); + if (sw == NULL) { + warn("search_win: calloc"); + fclose(lfile); + search_win_cleanup(); + return; + } + sw->idx = i; + sw->win = win; + + snprintf(s, sizeof s, "%d", i); + len = strlen(s); + + XmbTextExtents(bar_fs, s, len, &ibox, &lbox); + + w = XCreateSimpleWindow(display, + win->id, 0, 0,lbox.width + 4, + bar_fs_extents->max_logical_extent.height, 1, + r->s->c[SWM_S_COLOR_UNFOCUS].color, + r->s->c[SWM_S_COLOR_FOCUS].color); + + sw->indicator = w; + TAILQ_INSERT_TAIL(&search_wl, sw, entry); + + sw->gc = XCreateGC(display, w, 0, &gcv); + XMapRaised(display, w); + XSetForeground(display, sw->gc, r->s->c[SWM_S_COLOR_BAR].color); + + DRAWSTRING(display, w, bar_fs, sw->gc, 2, + (bar_fs_extents->max_logical_extent.height - + lbox.height) / 2 - lbox.y, s, len); + + fprintf(lfile, "%d\n", i); + i++; + } + + fclose(lfile); +} + +void +search_resp_uniconify(char *resp, unsigned long len) +{ + unsigned char *name; + struct ws_win *win; + char *s; + + DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp: %s\n", resp); + + TAILQ_FOREACH(win, &search_r->ws->winlist, entry) { + if (win->iconic == 0) + continue; + name = get_win_name(win->id); + if (name == NULL) + continue; + if (asprintf(&s, "%s.%lu", name, win->id) == -1) { + XFree(name); + continue; + } + XFree(name); + if (strncmp(s, resp, len) == 0) { + /* XXX this should be a callback to generalize */ + update_iconic(win, 0); + free(s); + break; + } + free(s); + } +} + +void +search_resp_name_workspace(char *resp, unsigned long len) +{ + struct workspace *ws; + + DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: resp: %s\n", resp); + + if (search_r->ws == NULL) + return; + ws = search_r->ws; + + if (ws->name) { + free(search_r->ws->name); + search_r->ws->name = NULL; + } + + if (len > 1) { + ws->name = strdup(resp); + if (ws->name == NULL) { + DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: " + "strdup: %s", strerror(errno)); + return; + } + } +} + +void +search_resp_search_workspace(char *resp, unsigned long len) +{ + char *p, *q; + int ws_idx; + const char *errstr; + union arg a; + + DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: resp: %s\n", resp); + + q = strdup(resp); + if (!q) { + DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: strdup: %s", + strerror(errno)); + return; + } + p = strchr(q, ':'); + if (p != NULL) + *p = '\0'; + ws_idx = strtonum(q, 1, SWM_WS_MAX, &errstr); + if (errstr) { + DNPRINTF(SWM_D_MISC, "workspace idx is %s: %s", + errstr, q); + free(q); + return; + } + free(q); + a.id = ws_idx - 1; + switchws(search_r, &a); +} + +void +search_resp_search_window(char *resp, unsigned long len) +{ + char *s; + int idx; + const char *errstr; + struct search_window *sw; + + DNPRINTF(SWM_D_MISC, "search_resp_search_window: resp: %s\n", resp); + + s = strdup(resp); + if (!s) { + DNPRINTF(SWM_D_MISC, "search_resp_search_window: strdup: %s", + strerror(errno)); + return; + } + + idx = strtonum(s, 1, INT_MAX, &errstr); + if (errstr) { + DNPRINTF(SWM_D_MISC, "window idx is %s: %s", + errstr, s); + free(s); + return; + } + free(s); + + TAILQ_FOREACH(sw, &search_wl, entry) + if (idx == sw->idx) { + focus_win(sw->win); + break; + } +} + +#define MAX_RESP_LEN 1024 + +void +search_do_resp(void) +{ + ssize_t rbytes; + char *resp; + unsigned long len; + + DNPRINTF(SWM_D_MISC, "search_do_resp:\n"); + + search_resp = 0; + searchpid = 0; + + if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) { + warn("search: calloc"); + goto done; + } + + rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN); + if (rbytes <= 0) { + warn("search: read error"); + goto done; + } + resp[rbytes] = '\0'; + + /* XXX: + * Older versions of dmenu (Atleast pre 4.4.1) do not send a + * newline, so work around that by sanitizing the resp now. + */ + resp[strcspn(resp, "\n")] = '\0'; + len = strlen(resp); + + switch (search_resp_action) { + case SWM_SEARCH_UNICONIFY: + search_resp_uniconify(resp, len); + break; + case SWM_SEARCH_NAME_WORKSPACE: + search_resp_name_workspace(resp, len); + break; + case SWM_SEARCH_SEARCH_WORKSPACE: + search_resp_search_workspace(resp, len); + break; + case SWM_SEARCH_SEARCH_WINDOW: + search_resp_search_window(resp, len); + break; + } + +done: + if (search_resp_action == SWM_SEARCH_SEARCH_WINDOW) + search_win_cleanup(); + + search_resp_action = SWM_SEARCH_NONE; + close(select_resp_pipe[0]); + free(resp); +} + +void +wkill(struct swm_region *r, union arg *args) +{ + DNPRINTF(SWM_D_MISC, "wkill: id: %d\n", args->id); + + if (r->ws->focus == NULL) + return; + + if (args->id == SWM_ARG_ID_KILLWINDOW) + XKillClient(display, r->ws->focus->id); + else + if (r->ws->focus->can_delete) + client_msg(r->ws->focus, adelete); +} + + +int +floating_toggle_win(struct ws_win *win) +{ + struct swm_region *r; + + if (win == NULL) + return 0; + + if (!win->ws->r) + return 0; + + r = win->ws->r; + + /* reject floating toggles in max stack mode */ + if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) + return 0; + + if (win->floating) { + if (!win->floatmaxed) { + /* retain position for refloat */ + store_float_geom(win, r); + } + win->floating = 0; + } else { + if (win->g_floatvalid) { + /* refloat at last floating relative position */ + X(win) = win->g_float.x - win->rg_float.x + X(r); + Y(win) = win->g_float.y - win->rg_float.y + Y(r); + WIDTH(win) = win->g_float.w; + HEIGHT(win) = win->g_float.h; + } + win->floating = 1; + } + + ewmh_update_actions(win); + + return 1; +} + +void +floating_toggle(struct swm_region *r, union arg *args) +{ + struct ws_win *win = r->ws->focus; + union arg a; + + if (win == NULL) + return; + + ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, + _NET_WM_STATE_TOGGLE); + + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + + if (win == win->ws->focus) { + a.id = SWM_ARG_ID_FOCUSCUR; + focus(win->ws->r, &a); + } +} + +void +constrain_window(struct ws_win *win, struct swm_region *r, int resizable) +{ + if (X(win) + WIDTH(win) > X(r) + WIDTH(r) - border_width) { + if (resizable) + WIDTH(win) = X(r) + WIDTH(r) - X(win) - border_width; + else + X(win) = X(r) + WIDTH(r) - WIDTH(win) - border_width; + } + + if (X(win) < X(r) - border_width) { + if (resizable) + WIDTH(win) -= X(r) - X(win) - border_width; + + X(win) = X(r) - border_width; + } + + if (Y(win) + HEIGHT(win) > Y(r) + HEIGHT(r) - border_width) { + if (resizable) + HEIGHT(win) = Y(r) + HEIGHT(r) - Y(win) - border_width; + else + Y(win) = Y(r) + HEIGHT(r) - HEIGHT(win) - border_width; + } + + if (Y(win) < Y(r) - border_width) { + if (resizable) + HEIGHT(win) -= Y(r) - Y(win) - border_width; + + Y(win) = Y(r) - border_width; + } + + if (WIDTH(win) < 1) + WIDTH(win) = 1; + if (HEIGHT(win) < 1) + HEIGHT(win) = 1; +} + +void +update_window(struct ws_win *win) +{ + unsigned int mask; + XWindowChanges wc; + + bzero(&wc, sizeof wc); + mask = CWBorderWidth | CWWidth | CWHeight | CWX | CWY; + wc.border_width = border_width; + wc.x = X(win); + wc.y = Y(win); + wc.width = WIDTH(win); + wc.height = HEIGHT(win); + + DNPRINTF(SWM_D_MISC, "update_window: window: 0x%lx, (x,y) w x h: " + "(%d,%d) %d x %d\n", win->id, wc.x, wc.y, wc.width, wc.height); + + XConfigureWindow(display, win->id, mask, &wc); +} + +#define SWM_RESIZE_STEPS (50) + +void +resize(struct ws_win *win, union arg *args) +{ + XEvent ev; + Time time = 0; + struct swm_region *r = NULL; + int resize_step = 0; + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + struct swm_geometry g; + int top = 0, left = 0; + int dx, dy; + Cursor cursor; + unsigned int shape; /* cursor style */ + + if (win == NULL) + return; + r = win->ws->r; + + DNPRINTF(SWM_D_MOUSE, "resize: window: 0x%lx, floating: %s, " + "transient: 0x%lx\n", win->id, YESNO(win->floating), + win->transient); + + if (!(win->transient != 0 || win->floating != 0)) + return; + + /* reject resizes in max mode for floaters (transient ok) */ + if (win->floatmaxed) + return; + + win->manual = 1; + ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom, + _NET_WM_STATE_ADD); + + stack(); + + switch (args->id) { + case SWM_ARG_ID_WIDTHSHRINK: + WIDTH(win) -= SWM_RESIZE_STEPS; + resize_step = 1; + break; + case SWM_ARG_ID_WIDTHGROW: + WIDTH(win) += SWM_RESIZE_STEPS; + resize_step = 1; + break; + case SWM_ARG_ID_HEIGHTSHRINK: + HEIGHT(win) -= SWM_RESIZE_STEPS; + resize_step = 1; + break; + case SWM_ARG_ID_HEIGHTGROW: + HEIGHT(win) += SWM_RESIZE_STEPS; + resize_step = 1; + break; + default: + break; + } + if (resize_step) { + constrain_window(win, r, 1); + update_window(win); + store_float_geom(win,r); + return; + } + + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + + /* get cursor offset from window root */ + if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) + return; + + g = win->g; + + if (wx < WIDTH(win) / 2) + left = 1; + + if (wy < HEIGHT(win) / 2) + top = 1; + + if (args->id == SWM_ARG_ID_CENTER) + shape = XC_sizing; + else if (top) + shape = (left) ? XC_top_left_corner : XC_top_right_corner; + else + shape = (left) ? XC_bottom_left_corner : XC_bottom_right_corner; + + cursor = XCreateFontCursor(display, shape); + + if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, + GrabModeAsync, None, cursor, CurrentTime) != GrabSuccess) { + XFreeCursor(display, cursor); + return; + } + + do { + XMaskEvent(display, MOUSEMASK | ExposureMask | + SubstructureRedirectMask, &ev); + switch (ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + /* cursor offset/delta from start of the operation */ + dx = ev.xmotion.x_root - x; + dy = ev.xmotion.y_root - y; + + /* vertical */ + if (top) + dy = -dy; + + if (args->id == SWM_ARG_ID_CENTER) { + if (g.h / 2 + dy < 1) + dy = 1 - g.h / 2; + + Y(win) = g.y - dy; + HEIGHT(win) = g.h + 2 * dy; + } else { + if (g.h + dy < 1) + dy = 1 - g.h; + + if (top) + Y(win) = g.y - dy; + + HEIGHT(win) = g.h + dy; + } + + /* horizontal */ + if (left) + dx = -dx; + + if (args->id == SWM_ARG_ID_CENTER) { + if (g.w / 2 + dx < 1) + dx = 1 - g.w / 2; + + X(win) = g.x - dx; + WIDTH(win) = g.w + 2 * dx; + } else { + if (g.w + dx < 1) + dx = 1 - g.w; + + if (left) + X(win) = g.x - dx; + + WIDTH(win) = g.w + dx; + } + + constrain_window(win, r, 1); + + /* not free, don't sync more than 120 times / second */ + if ((ev.xmotion.time - time) > (1000 / 120) ) { + time = ev.xmotion.time; + XSync(display, False); + update_window(win); + } + break; + } + } while (ev.type != ButtonRelease); + if (time) { + XSync(display, False); + update_window(win); + } + store_float_geom(win,r); + + XUngrabPointer(display, CurrentTime); + XFreeCursor(display, cursor); + + /* drain events */ + drain_enter_notify(); +} + +void +resize_step(struct swm_region *r, union arg *args) +{ + struct ws_win *win = NULL; + + if (r && r->ws && r->ws->focus) + win = r->ws->focus; + else + return; + + resize(win, args); +} + +#define SWM_MOVE_STEPS (50) + +void +move(struct ws_win *win, union arg *args) +{ + XEvent ev; + Time time = 0; + int move_step = 0; + struct swm_region *r = NULL; + + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + + if (win == NULL) + return; + r = win->ws->r; + + DNPRINTF(SWM_D_MOUSE, "move: window: 0x%lx, floating: %s, transient: " + "0x%lx\n", win->id, YESNO(win->floating), win->transient); + + /* in max_stack mode should only move transients */ + if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !win->transient) + return; + + win->manual = 1; + if (win->floating == 0 && !win->transient) { + store_float_geom(win,r); + ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, + _NET_WM_STATE_ADD); + } + ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom, + _NET_WM_STATE_ADD); + + stack(); + + move_step = 0; + switch (args->id) { + case SWM_ARG_ID_MOVELEFT: + X(win) -= (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + case SWM_ARG_ID_MOVERIGHT: + X(win) += (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + case SWM_ARG_ID_MOVEUP: + Y(win) -= (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + case SWM_ARG_ID_MOVEDOWN: + Y(win) += (SWM_MOVE_STEPS - border_width); + move_step = 1; + break; + default: + break; + } + if (move_step) { + constrain_window(win, r, 0); + update_window(win); + store_float_geom(win, r); + return; + } + + if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, + GrabModeAsync, None, XCreateFontCursor(display, XC_fleur), + CurrentTime) != GrabSuccess) + return; + + /* get cursor offset from window root */ + if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) + return; + + do { + XMaskEvent(display, MOUSEMASK | ExposureMask | + SubstructureRedirectMask, &ev); + switch (ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + X(win) = ev.xmotion.x_root - wx - border_width; + Y(win) = ev.xmotion.y_root - wy - border_width; + + constrain_window(win, r, 0); + + /* not free, don't sync more than 120 times / second */ + if ((ev.xmotion.time - time) > (1000 / 120) ) { + time = ev.xmotion.time; + XSync(display, False); + update_window(win); + } + break; + } + } while (ev.type != ButtonRelease); + if (time) { + XSync(display, False); + update_window(win); + } + store_float_geom(win,r); + XUngrabPointer(display, CurrentTime); + + /* drain events */ + drain_enter_notify(); +} + +void +move_step(struct swm_region *r, union arg *args) +{ + struct ws_win *win = NULL; + + if (r && r->ws && r->ws->focus) + win = r->ws->focus; + else + return; + + if (!(win->transient != 0 || win->floating != 0)) + return; + + move(win, args); +} + + +/* user/key callable function IDs */ +enum keyfuncid { + kf_cycle_layout, + kf_flip_layout, + kf_stack_reset, + kf_master_shrink, + kf_master_grow, + kf_master_add, + kf_master_del, + kf_stack_inc, + kf_stack_dec, + kf_swap_main, + kf_focus_next, + kf_focus_prev, + kf_swap_next, + kf_swap_prev, + kf_spawn_term, + kf_spawn_menu, + kf_quit, + kf_restart, + kf_focus_main, + kf_ws_1, + kf_ws_2, + kf_ws_3, + kf_ws_4, + kf_ws_5, + kf_ws_6, + kf_ws_7, + kf_ws_8, + kf_ws_9, + kf_ws_10, + kf_ws_next, + kf_ws_prev, + kf_ws_next_all, + kf_ws_prev_all, + kf_ws_prior, + kf_screen_next, + kf_screen_prev, + kf_mvws_1, + kf_mvws_2, + kf_mvws_3, + kf_mvws_4, + kf_mvws_5, + kf_mvws_6, + kf_mvws_7, + kf_mvws_8, + kf_mvws_9, + kf_mvws_10, + kf_bar_toggle, + kf_wind_kill, + kf_wind_del, + kf_screenshot_all, + kf_screenshot_wind, + kf_float_toggle, + kf_version, + kf_spawn_lock, + kf_spawn_initscr, + kf_spawn_custom, + kf_iconify, + kf_uniconify, + kf_raise_toggle, + kf_button2, + kf_width_shrink, + kf_width_grow, + kf_height_shrink, + kf_height_grow, + kf_move_left, + kf_move_right, + kf_move_up, + kf_move_down, + kf_name_workspace, + kf_search_workspace, + kf_search_win, + kf_dumpwins, /* MUST BE LAST */ + kf_invalid +}; + +/* key definitions */ +void +dummykeyfunc(struct swm_region *r, union arg *args) +{ +}; + +void +legacyfunc(struct swm_region *r, union arg *args) +{ +}; + +struct keyfunc { + char name[SWM_FUNCNAME_LEN]; + void (*func)(struct swm_region *r, union arg *); + union arg args; +} keyfuncs[kf_invalid + 1] = { + /* name function argument */ + { "cycle_layout", cycle_layout, {0} }, + { "flip_layout", stack_config, {.id = SWM_ARG_ID_FLIPLAYOUT} }, + { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, + { "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, + { "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, + { "master_add", stack_config, {.id = SWM_ARG_ID_MASTERADD} }, + { "master_del", stack_config, {.id = SWM_ARG_ID_MASTERDEL} }, + { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, + { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, + { "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, + { "focus_next", focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, + { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} }, + { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, + { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, + { "spawn_term", spawnterm, {.argv = spawn_term} }, + { "spawn_menu", legacyfunc, {0} }, + { "quit", quit, {0} }, + { "restart", restart, {0} }, + { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, + { "ws_1", switchws, {.id = 0} }, + { "ws_2", switchws, {.id = 1} }, + { "ws_3", switchws, {.id = 2} }, + { "ws_4", switchws, {.id = 3} }, + { "ws_5", switchws, {.id = 4} }, + { "ws_6", switchws, {.id = 5} }, + { "ws_7", switchws, {.id = 6} }, + { "ws_8", switchws, {.id = 7} }, + { "ws_9", switchws, {.id = 8} }, + { "ws_10", switchws, {.id = 9} }, + { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, + { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, + { "ws_next_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP_ALL} }, + { "ws_prev_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN_ALL} }, + { "ws_prior", priorws, {0} }, + { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, + { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, + { "mvws_1", send_to_ws, {.id = 0} }, + { "mvws_2", send_to_ws, {.id = 1} }, + { "mvws_3", send_to_ws, {.id = 2} }, + { "mvws_4", send_to_ws, {.id = 3} }, + { "mvws_5", send_to_ws, {.id = 4} }, + { "mvws_6", send_to_ws, {.id = 5} }, + { "mvws_7", send_to_ws, {.id = 6} }, + { "mvws_8", send_to_ws, {.id = 7} }, + { "mvws_9", send_to_ws, {.id = 8} }, + { "mvws_10", send_to_ws, {.id = 9} }, + { "bar_toggle", bar_toggle, {0} }, + { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, + { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, + { "screenshot_all", legacyfunc, {0} }, + { "screenshot_wind", legacyfunc, {0} }, + { "float_toggle", floating_toggle,{0} }, + { "version", version, {0} }, + { "spawn_lock", legacyfunc, {0} }, + { "spawn_initscr", legacyfunc, {0} }, + { "spawn_custom", dummykeyfunc, {0} }, + { "iconify", iconify, {0} }, + { "uniconify", uniconify, {0} }, + { "raise_toggle", raise_toggle, {0} }, + { "button2", pressbutton, {2} }, + { "width_shrink", resize_step, {.id = SWM_ARG_ID_WIDTHSHRINK} }, + { "width_grow", resize_step, {.id = SWM_ARG_ID_WIDTHGROW} }, + { "height_shrink", resize_step, {.id = SWM_ARG_ID_HEIGHTSHRINK} }, + { "height_grow", resize_step, {.id = SWM_ARG_ID_HEIGHTGROW} }, + { "move_left", move_step, {.id = SWM_ARG_ID_MOVELEFT} }, + { "move_right", move_step, {.id = SWM_ARG_ID_MOVERIGHT} }, + { "move_up", move_step, {.id = SWM_ARG_ID_MOVEUP} }, + { "move_down", move_step, {.id = SWM_ARG_ID_MOVEDOWN} }, + { "name_workspace", name_workspace, {0} }, + { "search_workspace", search_workspace, {0} }, + { "search_win", search_win, {0} }, + { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */ + { "invalid key func", NULL, {0} }, +}; +struct key { + RB_ENTRY(key) entry; + unsigned int mod; + KeySym keysym; + enum keyfuncid funcid; + char *spawn_name; +}; +RB_HEAD(key_list, key); + +int +key_cmp(struct key *kp1, struct key *kp2) +{ + if (kp1->keysym < kp2->keysym) + return (-1); + if (kp1->keysym > kp2->keysym) + return (1); + + if (kp1->mod < kp2->mod) + return (-1); + if (kp1->mod > kp2->mod) + return (1); + + return (0); +} + +RB_GENERATE_STATIC(key_list, key, entry, key_cmp); +struct key_list keys; + +/* mouse */ +enum { client_click, root_click }; +struct button { + unsigned int action; + unsigned int mask; + unsigned int button; + void (*func)(struct ws_win *, union arg *); + union arg args; +} buttons[] = { + /* action key mouse button func args */ + { client_click, MODKEY, Button3, resize, {.id = SWM_ARG_ID_DONTCENTER} }, + { client_click, MODKEY | ShiftMask, Button3, resize, {.id = SWM_ARG_ID_CENTER} }, + { client_click, MODKEY, Button1, move, {0} }, +}; + +void +update_modkey(unsigned int mod) +{ + int i; + struct key *kp; + + mod_key = mod; + RB_FOREACH(kp, key_list, &keys) + if (kp->mod & ShiftMask) + kp->mod = mod | ShiftMask; + else + kp->mod = mod; + + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].mask & ShiftMask) + buttons[i].mask = mod | ShiftMask; + else + buttons[i].mask = mod; +} + +/* spawn */ +struct spawn_prog { + TAILQ_ENTRY(spawn_prog) entry; + char *name; + int argc; + char **argv; +}; +TAILQ_HEAD(spawn_list, spawn_prog); +struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns); + +int +spawn_expand(struct swm_region *r, union arg *args, char *spawn_name, + char ***ret_args) +{ + struct spawn_prog *prog = NULL; + int i; + char *ap, **real_args; + + DNPRINTF(SWM_D_SPAWN, "spawn_expand: %s\n", spawn_name); + + /* find program */ + TAILQ_FOREACH(prog, &spawns, entry) { + if (!strcasecmp(spawn_name, prog->name)) + break; + } + if (prog == NULL) { + warnx("spawn_custom: program %s not found", spawn_name); + return (-1); + } + + /* make room for expanded args */ + if ((real_args = calloc(prog->argc + 1, sizeof(char *))) == NULL) + err(1, "spawn_custom: calloc real_args"); + + /* expand spawn_args into real_args */ + for (i = 0; i < prog->argc; i++) { + ap = prog->argv[i]; + DNPRINTF(SWM_D_SPAWN, "spawn_custom: raw arg: %s\n", ap); + if (!strcasecmp(ap, "$bar_border")) { + if ((real_args[i] = + strdup(r->s->c[SWM_S_COLOR_BAR_BORDER].name)) + == NULL) + err(1, "spawn_custom border color"); + } else if (!strcasecmp(ap, "$bar_color")) { + if ((real_args[i] = + strdup(r->s->c[SWM_S_COLOR_BAR].name)) + == NULL) + err(1, "spawn_custom bar color"); + } else if (!strcasecmp(ap, "$bar_font")) { + if ((real_args[i] = strdup(bar_fonts)) + == NULL) + err(1, "spawn_custom bar fonts"); + } else if (!strcasecmp(ap, "$bar_font_color")) { + if ((real_args[i] = + strdup(r->s->c[SWM_S_COLOR_BAR_FONT].name)) + == NULL) + err(1, "spawn_custom color font"); + } else if (!strcasecmp(ap, "$color_focus")) { + if ((real_args[i] = + strdup(r->s->c[SWM_S_COLOR_FOCUS].name)) + == NULL) + err(1, "spawn_custom color focus"); + } else if (!strcasecmp(ap, "$color_unfocus")) { + if ((real_args[i] = + strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name)) + == NULL) + err(1, "spawn_custom color unfocus"); + } else { + /* no match --> copy as is */ + if ((real_args[i] = strdup(ap)) == NULL) + err(1, "spawn_custom strdup(ap)"); + } + DNPRINTF(SWM_D_SPAWN, "spawn_custom: cooked arg: %s\n", + real_args[i]); + } + +#ifdef SWM_DEBUG + DNPRINTF(SWM_D_SPAWN, "spawn_custom: result: "); + for (i = 0; i < prog->argc; i++) + DNPRINTF(SWM_D_SPAWN, "\"%s\" ", real_args[i]); + DNPRINTF(SWM_D_SPAWN, "\n"); +#endif + *ret_args = real_args; + return (prog->argc); +} + +void +spawn_custom(struct swm_region *r, union arg *args, char *spawn_name) +{ + union arg a; + char **real_args; + int spawn_argc, i; + + if ((spawn_argc = spawn_expand(r, args, spawn_name, &real_args)) < 0) + return; + a.argv = real_args; + if (fork() == 0) + spawn(r->ws->idx, &a, 1); + + for (i = 0; i < spawn_argc; i++) + free(real_args[i]); + free(real_args); +} + +void +spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid) +{ + union arg a; + char **real_args; + int i, spawn_argc; + + if ((spawn_argc = spawn_expand(r, args, spawn_name, &real_args)) < 0) + return; + a.argv = real_args; + + if (pipe(select_list_pipe) == -1) + err(1, "pipe error"); + if (pipe(select_resp_pipe) == -1) + err(1, "pipe error"); + + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + err(1, "could not disable SIGPIPE"); + switch (*pid = fork()) { + case -1: + err(1, "cannot fork"); + break; + case 0: /* child */ + if (dup2(select_list_pipe[0], 0) == -1) + err(1, "dup2"); + if (dup2(select_resp_pipe[1], 1) == -1) + err(1, "dup2"); + close(select_list_pipe[1]); + close(select_resp_pipe[0]); + spawn(r->ws->idx, &a, 0); + break; + default: /* parent */ + close(select_list_pipe[0]); + close(select_resp_pipe[1]); + break; + } + + for (i = 0; i < spawn_argc; i++) + free(real_args[i]); + free(real_args); +} + +void +spawn_insert(char *name, char *args) +{ + char *arg, *cp, *ptr; + struct spawn_prog *sp; + + DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s\n", name); + + if ((sp = calloc(1, sizeof *sp)) == NULL) + err(1, "spawn_insert: malloc"); + if ((sp->name = strdup(name)) == NULL) + err(1, "spawn_insert: strdup"); + + /* convert the arguments to an argument list */ + if ((ptr = cp = strdup(args)) == NULL) + err(1, "spawn_insert: strdup"); + while ((arg = strsep(&ptr, " \t")) != NULL) { + /* empty field; skip it */ + if (*arg == '\0') + continue; + + sp->argc++; + if ((sp->argv = realloc(sp->argv, sp->argc * + sizeof *sp->argv)) == NULL) + err(1, "spawn_insert: realloc"); + if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL) + err(1, "spawn_insert: strdup"); + } + free(cp); + + TAILQ_INSERT_TAIL(&spawns, sp, entry); + DNPRINTF(SWM_D_SPAWN, "spawn_insert: leave\n"); +} + +void +spawn_remove(struct spawn_prog *sp) +{ + int i; + + DNPRINTF(SWM_D_SPAWN, "spawn_remove: %s\n", sp->name); + + TAILQ_REMOVE(&spawns, sp, entry); + for (i = 0; i < sp->argc; i++) + free(sp->argv[i]); + free(sp->argv); + free(sp->name); + free(sp); + + DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); +} + +void +spawn_replace(struct spawn_prog *sp, char *name, char *args) +{ + DNPRINTF(SWM_D_SPAWN, "spawn_replace: %s [%s]\n", sp->name, name); + + spawn_remove(sp); + spawn_insert(name, args); + + DNPRINTF(SWM_D_SPAWN, "spawn_replace: leave\n"); +} + +void +setspawn(char *name, char *args) +{ + struct spawn_prog *sp; + + DNPRINTF(SWM_D_SPAWN, "setspawn: %s\n", name); + + if (name == NULL) + return; + + TAILQ_FOREACH(sp, &spawns, entry) { + if (!strcmp(sp->name, name)) { + if (*args == '\0') + spawn_remove(sp); + else + spawn_replace(sp, name, args); + DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); + return; + } + } + if (*args == '\0') { + warnx("error: setspawn: cannot find program: %s", name); + return; + } + + spawn_insert(name, args); + DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); +} + +int +setconfspawn(char *selector, char *value, int flags) +{ + DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, value); + + setspawn(selector, value); + + DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n"); + return (0); +} + +void +setup_spawn(void) +{ + setconfspawn("term", "xterm", 0); + setconfspawn("screenshot_all", "screenshot.sh full", 0); + setconfspawn("screenshot_wind", "screenshot.sh window", 0); + setconfspawn("lock", "xlock", 0); + setconfspawn("initscr", "initscreen.sh", 0); + setconfspawn("menu", "dmenu_run" + " -fn $bar_font" + " -nb $bar_color" + " -nf $bar_font_color" + " -sb $bar_border" + " -sf $bar_color", 0); + setconfspawn("search", "dmenu" + " -i" + " -fn $bar_font" + " -nb $bar_color" + " -nf $bar_font_color" + " -sb $bar_border" + " -sf $bar_color", 0); + setconfspawn("name_workspace", "dmenu" + " -p Workspace" + " -fn $bar_font" + " -nb $bar_color" + " -nf $bar_font_color" + " -sb $bar_border" + " -sf $bar_color", 0); +} + +/* key bindings */ +#define SWM_MODNAME_SIZE 32 +#define SWM_KEY_WS "\n+ \t" +int +parsekeys(char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks) +{ + char *cp, *name; + KeySym uks; + DNPRINTF(SWM_D_KEY, "parsekeys: enter [%s]\n", keystr); + if (mod == NULL || ks == NULL) { + DNPRINTF(SWM_D_KEY, "parsekeys: no mod or key vars\n"); + return (1); + } + if (keystr == NULL || strlen(keystr) == 0) { + DNPRINTF(SWM_D_KEY, "parsekeys: no keystr\n"); + return (1); + } + cp = keystr; + *ks = NoSymbol; + *mod = 0; + while ((name = strsep(&cp, SWM_KEY_WS)) != NULL) { + DNPRINTF(SWM_D_KEY, "parsekeys: key [%s]\n", name); + if (cp) + cp += (long)strspn(cp, SWM_KEY_WS); + if (strncasecmp(name, "MOD", SWM_MODNAME_SIZE) == 0) + *mod |= currmod; + else if (!strncasecmp(name, "Mod1", SWM_MODNAME_SIZE)) + *mod |= Mod1Mask; + else if (!strncasecmp(name, "Mod2", SWM_MODNAME_SIZE)) + *mod += Mod2Mask; + else if (!strncmp(name, "Mod3", SWM_MODNAME_SIZE)) + *mod |= Mod3Mask; + else if (!strncmp(name, "Mod4", SWM_MODNAME_SIZE)) + *mod |= Mod4Mask; + else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) + *mod |= ShiftMask; + else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0) + *mod |= ControlMask; + else { + *ks = XStringToKeysym(name); + XConvertCase(*ks, ks, &uks); + if (ks == NoSymbol) { + DNPRINTF(SWM_D_KEY, + "parsekeys: invalid key %s\n", + name); + return (1); + } + } + } + DNPRINTF(SWM_D_KEY, "parsekeys: leave ok\n"); + return (0); +} + +char * +strdupsafe(char *str) +{ + if (str == NULL) + return (NULL); + else + return (strdup(str)); +} + +void +key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name) +{ + struct key *kp; + + DNPRINTF(SWM_D_KEY, "key_insert: enter %s [%s]\n", + keyfuncs[kfid].name, spawn_name); + + if ((kp = malloc(sizeof *kp)) == NULL) + err(1, "key_insert: malloc"); + + kp->mod = mod; + kp->keysym = ks; + kp->funcid = kfid; + kp->spawn_name = strdupsafe(spawn_name); + RB_INSERT(key_list, &keys, kp); + + DNPRINTF(SWM_D_KEY, "key_insert: leave\n"); +} + +struct key * +key_lookup(unsigned int mod, KeySym ks) +{ + struct key kp; + + kp.keysym = ks; + kp.mod = mod; + + return (RB_FIND(key_list, &keys, &kp)); +} + +void +key_remove(struct key *kp) +{ + DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name); + + RB_REMOVE(key_list, &keys, kp); + free(kp->spawn_name); + free(kp); + + DNPRINTF(SWM_D_KEY, "key_remove: leave\n"); +} + +void +key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid, + char *spawn_name) +{ + DNPRINTF(SWM_D_KEY, "key_replace: %s [%s]\n", keyfuncs[kp->funcid].name, + spawn_name); + + key_remove(kp); + key_insert(mod, ks, kfid, spawn_name); + + DNPRINTF(SWM_D_KEY, "key_replace: leave\n"); +} + +void +setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, + char *spawn_name) +{ + struct key *kp; + + DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n", + keyfuncs[kfid].name, spawn_name); + + if ((kp = key_lookup(mod, ks)) != NULL) { + if (kfid == kf_invalid) + key_remove(kp); + else + key_replace(kp, mod, ks, kfid, spawn_name); + DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); + return; + } + if (kfid == kf_invalid) { + warnx("error: setkeybinding: cannot find mod/key combination"); + DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); + return; + } + + key_insert(mod, ks, kfid, spawn_name); + DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); +} + +int +setconfbinding(char *selector, char *value, int flags) +{ + enum keyfuncid kfid; + unsigned int mod; + KeySym ks; + struct spawn_prog *sp; + DNPRINTF(SWM_D_KEY, "setconfbinding: enter\n"); + if (selector == NULL) { + DNPRINTF(SWM_D_KEY, "setconfbinding: unbind %s\n", value); + if (parsekeys(value, mod_key, &mod, &ks) == 0) { + kfid = kf_invalid; + setkeybinding(mod, ks, kfid, NULL); + return (0); + } else + return (1); + } + /* search by key function name */ + for (kfid = 0; kfid < kf_invalid; (kfid)++) { + if (strncasecmp(selector, keyfuncs[kfid].name, + SWM_FUNCNAME_LEN) == 0) { + DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n", + selector); + if (parsekeys(value, mod_key, &mod, &ks) == 0) { + setkeybinding(mod, ks, kfid, NULL); + return (0); + } else + return (1); + } + } + /* search by custom spawn name */ + TAILQ_FOREACH(sp, &spawns, entry) { + if (strcasecmp(selector, sp->name) == 0) { + DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n", + selector); + if (parsekeys(value, mod_key, &mod, &ks) == 0) { + setkeybinding(mod, ks, kf_spawn_custom, + sp->name); + return (0); + } else + return (1); + } + } + DNPRINTF(SWM_D_KEY, "setconfbinding: no match\n"); + return (1); +} + +void +setup_keys(void) +{ + setkeybinding(MODKEY, XK_space, kf_cycle_layout,NULL); + setkeybinding(MODKEY|ShiftMask, XK_backslash, kf_flip_layout, NULL); + setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset, NULL); + setkeybinding(MODKEY, XK_h, kf_master_shrink,NULL); + setkeybinding(MODKEY, XK_l, kf_master_grow, NULL); + setkeybinding(MODKEY, XK_comma, kf_master_add, NULL); + setkeybinding(MODKEY, XK_period, kf_master_del, NULL); + setkeybinding(MODKEY|ShiftMask, XK_comma, kf_stack_inc, NULL); + setkeybinding(MODKEY|ShiftMask, XK_period, kf_stack_dec, NULL); + setkeybinding(MODKEY, XK_Return, kf_swap_main, NULL); + setkeybinding(MODKEY, XK_j, kf_focus_next, NULL); + setkeybinding(MODKEY, XK_k, kf_focus_prev, NULL); + setkeybinding(MODKEY|ShiftMask, XK_j, kf_swap_next, NULL); + setkeybinding(MODKEY|ShiftMask, XK_k, kf_swap_prev, NULL); + setkeybinding(MODKEY|ShiftMask, XK_Return, kf_spawn_term, NULL); + setkeybinding(MODKEY, XK_p, kf_spawn_custom,"menu"); + setkeybinding(MODKEY|ShiftMask, XK_q, kf_quit, NULL); + setkeybinding(MODKEY, XK_q, kf_restart, NULL); + setkeybinding(MODKEY, XK_m, kf_focus_main, NULL); + setkeybinding(MODKEY, XK_1, kf_ws_1, NULL); + setkeybinding(MODKEY, XK_2, kf_ws_2, NULL); + setkeybinding(MODKEY, XK_3, kf_ws_3, NULL); + setkeybinding(MODKEY, XK_4, kf_ws_4, NULL); + setkeybinding(MODKEY, XK_5, kf_ws_5, NULL); + setkeybinding(MODKEY, XK_6, kf_ws_6, NULL); + setkeybinding(MODKEY, XK_7, kf_ws_7, NULL); + setkeybinding(MODKEY, XK_8, kf_ws_8, NULL); + setkeybinding(MODKEY, XK_9, kf_ws_9, NULL); + setkeybinding(MODKEY, XK_0, kf_ws_10, NULL); + setkeybinding(MODKEY, XK_Right, kf_ws_next, NULL); + setkeybinding(MODKEY, XK_Left, kf_ws_prev, NULL); + setkeybinding(MODKEY, XK_Up, kf_ws_next_all, NULL); + setkeybinding(MODKEY, XK_Down, kf_ws_prev_all, NULL); + setkeybinding(MODKEY, XK_a, kf_ws_prior, NULL); + setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next, NULL); + setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev, NULL); + setkeybinding(MODKEY|ShiftMask, XK_1, kf_mvws_1, NULL); + setkeybinding(MODKEY|ShiftMask, XK_2, kf_mvws_2, NULL); + setkeybinding(MODKEY|ShiftMask, XK_3, kf_mvws_3, NULL); + setkeybinding(MODKEY|ShiftMask, XK_4, kf_mvws_4, NULL); + setkeybinding(MODKEY|ShiftMask, XK_5, kf_mvws_5, NULL); + setkeybinding(MODKEY|ShiftMask, XK_6, kf_mvws_6, NULL); + setkeybinding(MODKEY|ShiftMask, XK_7, kf_mvws_7, NULL); + setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8, NULL); + setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9, NULL); + setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10, NULL); + setkeybinding(MODKEY, XK_b, kf_bar_toggle, NULL); + setkeybinding(MODKEY, XK_Tab, kf_focus_next, NULL); + setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev, NULL); + setkeybinding(MODKEY|ShiftMask, XK_x, kf_wind_kill, NULL); + setkeybinding(MODKEY, XK_x, kf_wind_del, NULL); + setkeybinding(MODKEY, XK_s, kf_spawn_custom,"screenshot_all"); + setkeybinding(MODKEY|ShiftMask, XK_s, kf_spawn_custom,"screenshot_wind"); + setkeybinding(MODKEY, XK_t, kf_float_toggle,NULL); + setkeybinding(MODKEY|ShiftMask, XK_v, kf_version, NULL); + setkeybinding(MODKEY|ShiftMask, XK_Delete, kf_spawn_custom,"lock"); + setkeybinding(MODKEY|ShiftMask, XK_i, kf_spawn_custom,"initscr"); + setkeybinding(MODKEY, XK_w, kf_iconify, NULL); + setkeybinding(MODKEY|ShiftMask, XK_w, kf_uniconify, NULL); + setkeybinding(MODKEY|ShiftMask, XK_r, kf_raise_toggle,NULL); + setkeybinding(MODKEY, XK_v, kf_button2, NULL); + setkeybinding(MODKEY, XK_equal, kf_width_grow, NULL); + setkeybinding(MODKEY, XK_minus, kf_width_shrink,NULL); + setkeybinding(MODKEY|ShiftMask, XK_equal, kf_height_grow, NULL); + setkeybinding(MODKEY|ShiftMask, XK_minus, kf_height_shrink,NULL); + setkeybinding(MODKEY, XK_bracketleft, kf_move_left, NULL); + setkeybinding(MODKEY, XK_bracketright,kf_move_right, NULL); + setkeybinding(MODKEY|ShiftMask, XK_bracketleft, kf_move_up, NULL); + setkeybinding(MODKEY|ShiftMask, XK_bracketright,kf_move_down, NULL); + setkeybinding(MODKEY|ShiftMask, XK_slash, kf_name_workspace,NULL); + setkeybinding(MODKEY, XK_slash, kf_search_workspace,NULL); + setkeybinding(MODKEY, XK_f, kf_search_win, NULL); +#ifdef SWM_DEBUG + setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL); +#endif +} + +void +clear_keys(void) +{ + struct key *kp; + + while (RB_EMPTY(&keys) == 0) { + kp = RB_ROOT(&keys); + key_remove(kp); + } +} + +int +setkeymapping(char *selector, char *value, int flags) +{ + char keymapping_file[PATH_MAX]; + DNPRINTF(SWM_D_KEY, "setkeymapping: enter\n"); + if (value[0] == '~') + snprintf(keymapping_file, sizeof keymapping_file, "%s/%s", + pwd->pw_dir, &value[1]); + else + strlcpy(keymapping_file, value, sizeof keymapping_file); + clear_keys(); + /* load new key bindings; if it fails, revert to default bindings */ + if (conf_load(keymapping_file, SWM_CONF_KEYMAPPING)) { + clear_keys(); + setup_keys(); + } + DNPRINTF(SWM_D_KEY, "setkeymapping: leave\n"); + return (0); +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + DNPRINTF(SWM_D_MISC, "updatenumlockmask\n"); + numlockmask = 0; + modmap = XGetModifierMapping(display); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(display, XK_Num_Lock)) + numlockmask = (1 << i); + + XFreeModifiermap(modmap); +} + +void +grabkeys(void) +{ + unsigned int j, k; + KeyCode code; + unsigned int modifiers[] = + { 0, LockMask, numlockmask, numlockmask | LockMask }; + struct key *kp; + + DNPRINTF(SWM_D_MISC, "grabkeys\n"); + updatenumlockmask(); + + for (k = 0; k < ScreenCount(display); k++) { + if (TAILQ_EMPTY(&screens[k].rl)) + continue; + XUngrabKey(display, AnyKey, AnyModifier, screens[k].root); + RB_FOREACH(kp, key_list, &keys) { + if ((code = XKeysymToKeycode(display, kp->keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(display, code, + kp->mod | modifiers[j], + screens[k].root, True, + GrabModeAsync, GrabModeAsync); + } + } +} + +void +grabbuttons(struct ws_win *win, int focused) +{ + unsigned int i, j; + unsigned int modifiers[] = + { 0, LockMask, numlockmask, numlockmask|LockMask }; + + updatenumlockmask(); + XUngrabButton(display, AnyButton, AnyModifier, win->id); + if (focused) { + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].action == client_click) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(display, buttons[i].button, + buttons[i].mask | modifiers[j], + win->id, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, + None); + } else + XGrabButton(display, AnyButton, AnyModifier, win->id, False, + BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); +} + +const char *quirkname[] = { + "NONE", /* config string for "no value" */ + "FLOAT", + "TRANSSZ", + "ANYWHERE", + "XTERM_FONTADJ", + "FULLSCREEN", + "FOCUSPREV", +}; + +/* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */ +#define SWM_Q_WS "\n|+ \t" +int +parsequirks(char *qstr, unsigned long *quirk) +{ + char *cp, *name; + int i; + + if (quirk == NULL) + return (1); + + cp = qstr; + *quirk = 0; + while ((name = strsep(&cp, SWM_Q_WS)) != NULL) { + if (cp) + cp += (long)strspn(cp, SWM_Q_WS); + for (i = 0; i < LENGTH(quirkname); i++) { + if (!strncasecmp(name, quirkname[i], SWM_QUIRK_LEN)) { + DNPRINTF(SWM_D_QUIRK, + "parsequirks: %s\n", name); + if (i == 0) { + *quirk = 0; + return (0); + } + *quirk |= 1 << (i-1); + break; + } + } + if (i >= LENGTH(quirkname)) { + DNPRINTF(SWM_D_QUIRK, + "parsequirks: invalid quirk [%s]\n", name); + return (1); + } + } + return (0); +} + +void +quirk_insert(const char *class, const char *name, unsigned long quirk) +{ + struct quirk *qp; + + DNPRINTF(SWM_D_QUIRK, "quirk_insert: %s:%s [%lu]\n", class, name, + quirk); + + if ((qp = malloc(sizeof *qp)) == NULL) + err(1, "quirk_insert: malloc"); + if ((qp->class = strdup(class)) == NULL) + err(1, "quirk_insert: strdup"); + if ((qp->name = strdup(name)) == NULL) + err(1, "quirk_insert: strdup"); + + qp->quirk = quirk; + TAILQ_INSERT_TAIL(&quirks, qp, entry); + + DNPRINTF(SWM_D_QUIRK, "quirk_insert: leave\n"); +} + +void +quirk_remove(struct quirk *qp) +{ + DNPRINTF(SWM_D_QUIRK, "quirk_remove: %s:%s [%lu]\n", qp->class, + qp->name, qp->quirk); + + TAILQ_REMOVE(&quirks, qp, entry); + free(qp->class); + free(qp->name); + free(qp); + + DNPRINTF(SWM_D_QUIRK, "quirk_remove: leave\n"); +} + +void +quirk_replace(struct quirk *qp, const char *class, const char *name, + unsigned long quirk) +{ + DNPRINTF(SWM_D_QUIRK, "quirk_replace: %s:%s [%lu]\n", qp->class, + qp->name, qp->quirk); + + quirk_remove(qp); + quirk_insert(class, name, quirk); + + DNPRINTF(SWM_D_QUIRK, "quirk_replace: leave\n"); +} + +void +setquirk(const char *class, const char *name, unsigned long quirk) +{ + struct quirk *qp; + + DNPRINTF(SWM_D_QUIRK, "setquirk: enter %s:%s [%lu]\n", class, name, + quirk); + + TAILQ_FOREACH(qp, &quirks, entry) { + if (!strcmp(qp->class, class) && !strcmp(qp->name, name)) { + if (!quirk) + quirk_remove(qp); + else + quirk_replace(qp, class, name, quirk); + DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); + return; + } + } + if (!quirk) { + warnx("error: setquirk: cannot find class/name combination"); + return; + } + + quirk_insert(class, name, quirk); + DNPRINTF(SWM_D_QUIRK, "setquirk: leave\n"); +} + +int +setconfquirk(char *selector, char *value, int flags) +{ + char *cp, *class, *name; + int retval; + unsigned long quirks; + if (selector == NULL) + return (0); + if ((cp = strchr(selector, ':')) == NULL) + return (0); + *cp = '\0'; + class = selector; + name = cp + 1; + if ((retval = parsequirks(value, &quirks)) == 0) + setquirk(class, name, quirks); + return (retval); +} + +void +setup_quirks(void) +{ + setquirk("MPlayer", "xv", SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV); + setquirk("OpenOffice.org 3.2", "VCLSalFrame", SWM_Q_FLOAT); + setquirk("Firefox-bin", "firefox-bin", SWM_Q_TRANSSZ); + setquirk("Firefox", "Dialog", SWM_Q_FLOAT); + setquirk("Gimp", "gimp", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("XTerm", "xterm", SWM_Q_XTERM_FONTADJ); + setquirk("xine", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("Xitk", "Xitk Combo", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("xine", "xine Panel", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("Xitk", "Xine Window", SWM_Q_FLOAT | SWM_Q_ANYWHERE); + setquirk("xine", "xine Video Fullscreen Window", SWM_Q_FULLSCREEN | SWM_Q_FLOAT); + setquirk("pcb", "pcb", SWM_Q_FLOAT); + setquirk("SDL_App", "SDL_App", SWM_Q_FLOAT | SWM_Q_FULLSCREEN); +} + +/* conf file stuff */ +#define SWM_CONF_FILE "spectrwm.conf" +#define SWM_CONF_FILE_OLD "scrotwm.conf" + +enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, + SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, + SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, + SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED, + SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED, SWM_S_URGENT_ENABLED, + SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, + SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, + SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM, + SWM_S_VERBOSE_LAYOUT, SWM_S_BAR_JUSTIFY + }; + +int +setconfvalue(char *selector, char *value, int flags) +{ + int i; + char *b; + + switch (flags) { + case SWM_S_BAR_DELAY: + bar_delay = atoi(value); + break; + case SWM_S_BAR_ENABLED: + bar_enabled = atoi(value); + break; + case SWM_S_BAR_BORDER_WIDTH: + bar_border_width = atoi(value); + break; + case SWM_S_BAR_AT_BOTTOM: + bar_at_bottom = atoi(value); + break; + case SWM_S_BAR_JUSTIFY: + if (!strcmp(value, "left")) + bar_justify = SWM_BAR_JUSTIFY_LEFT; + else if (!strcmp(value, "center")) + bar_justify = SWM_BAR_JUSTIFY_CENTER; + else if (!strcmp(value, "right")) + bar_justify = SWM_BAR_JUSTIFY_RIGHT; + else + errx(1, "invalid bar_justify"); + break; + case SWM_S_STACK_ENABLED: + stack_enabled = atoi(value); + break; + case SWM_S_CLOCK_ENABLED: + clock_enabled = atoi(value); + break; + case SWM_S_CLOCK_FORMAT: +#ifndef SWM_DENY_CLOCK_FORMAT + free(clock_format); + if ((clock_format = strdup(value)) == NULL) + err(1, "setconfvalue: clock_format"); +#endif + break; + case SWM_S_CYCLE_EMPTY: + cycle_empty = atoi(value); + break; + case SWM_S_CYCLE_VISIBLE: + cycle_visible = atoi(value); + break; + case SWM_S_SS_ENABLED: + ss_enabled = atoi(value); + break; + case SWM_S_TERM_WIDTH: + term_width = atoi(value); + break; + case SWM_S_TITLE_CLASS_ENABLED: + title_class_enabled = atoi(value); + break; + case SWM_S_WINDOW_NAME_ENABLED: + window_name_enabled = atoi(value); + break; + case SWM_S_TITLE_NAME_ENABLED: + title_name_enabled = atoi(value); + break; + case SWM_S_URGENT_ENABLED: + urgent_enabled = atoi(value); + break; + case SWM_S_FOCUS_MODE: + if (!strcmp(value, "default")) + focus_mode = SWM_FOCUS_DEFAULT; + else if (!strcmp(value, "follow_cursor")) + focus_mode = SWM_FOCUS_FOLLOW; + else if (!strcmp(value, "synergy")) + focus_mode = SWM_FOCUS_SYNERGY; + else + errx(1, "focus_mode"); + break; + case SWM_S_DISABLE_BORDER: + disable_border = atoi(value); + break; + case SWM_S_BORDER_WIDTH: + border_width = atoi(value); + break; + case SWM_S_BAR_FONT: + b = bar_fonts; + if (asprintf(&bar_fonts, "%s,%s", value, bar_fonts) == -1) + err(1, "setconfvalue: asprintf: failed to allocate " + "memory for bar_fonts."); + + free(b); + break; + case SWM_S_BAR_ACTION: + free(bar_argv[0]); + if ((bar_argv[0] = strdup(value)) == NULL) + err(1, "setconfvalue: bar_action"); + break; + case SWM_S_SPAWN_TERM: + free(spawn_term[0]); + if ((spawn_term[0] = strdup(value)) == NULL) + err(1, "setconfvalue: spawn_term"); + break; + case SWM_S_SS_APP: + break; + case SWM_S_DIALOG_RATIO: + dialog_ratio = atof(value); + if (dialog_ratio > 1.0 || dialog_ratio <= .3) + dialog_ratio = .6; + break; + case SWM_S_VERBOSE_LAYOUT: + verbose_layout = atoi(value); + for (i = 0; layouts[i].l_stack != NULL; i++) { + if (verbose_layout) + layouts[i].l_string = fancy_stacker; + else + layouts[i].l_string = plain_stacker; + } + break; + default: + return (1); + } + return (0); +} + +int +setconfmodkey(char *selector, char *value, int flags) +{ + if (!strncasecmp(value, "Mod1", strlen("Mod1"))) + update_modkey(Mod1Mask); + else if (!strncasecmp(value, "Mod2", strlen("Mod2"))) + update_modkey(Mod2Mask); + else if (!strncasecmp(value, "Mod3", strlen("Mod3"))) + update_modkey(Mod3Mask); + else if (!strncasecmp(value, "Mod4", strlen("Mod4"))) + update_modkey(Mod4Mask); + else + return (1); + return (0); +} + +int +setconfcolor(char *selector, char *value, int flags) +{ + setscreencolor(value, ((selector == NULL)?-1:atoi(selector)), flags); + return (0); +} + +int +setconfregion(char *selector, char *value, int flags) +{ + custom_region(value); + return (0); +} + +int +setautorun(char *selector, char *value, int flags) +{ + int ws_id; + char s[1024]; + char *ap, *sp = s; + union arg a; + int argc = 0; + long pid; + struct pid_e *p; + + if (getenv("SWM_STARTED")) + return (0); + + bzero(s, sizeof s); + if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2) + errx(1, "invalid autorun entry, should be 'ws[]:command'"); + ws_id--; + if (ws_id < 0 || ws_id >= SWM_WS_MAX) + errx(1, "autorun: invalid workspace %d", ws_id + 1); + + /* + * This is a little intricate + * + * If the pid already exists we simply reuse it because it means it was + * used before AND not claimed by manage_window. We get away with + * altering it in the parent after INSERT because this can not be a race + */ + a.argv = NULL; + while ((ap = strsep(&sp, " \t")) != NULL) { + if (*ap == '\0') + continue; + DNPRINTF(SWM_D_SPAWN, "setautorun: arg [%s]\n", ap); + argc++; + if ((a.argv = realloc(a.argv, argc * sizeof(char *))) == NULL) + err(1, "setautorun: realloc"); + a.argv[argc - 1] = ap; + } + + if ((a.argv = realloc(a.argv, (argc + 1) * sizeof(char *))) == NULL) + err(1, "setautorun: realloc"); + a.argv[argc] = NULL; + + if ((pid = fork()) == 0) { + spawn(ws_id, &a, 1); + /* NOTREACHED */ + _exit(1); + } + free(a.argv); + + /* parent */ + p = find_pid(pid); + if (p == NULL) { + p = calloc(1, sizeof *p); + if (p == NULL) + return (1); + TAILQ_INSERT_TAIL(&pidlist, p, entry); + } + + p->pid = pid; + p->ws = ws_id; + + return (0); +} + +int +setlayout(char *selector, char *value, int flags) +{ + int ws_id, i, x, mg, ma, si, raise; + int st = SWM_V_STACK; + char s[1024]; + struct workspace *ws; + + if (getenv("SWM_STARTED")) + return (0); + + bzero(s, sizeof s); + if (sscanf(value, "ws[%d]:%d:%d:%d:%d:%1023c", + &ws_id, &mg, &ma, &si, &raise, s) != 6) + errx(1, "invalid layout entry, should be 'ws[]:" + "::::" + "'"); + ws_id--; + if (ws_id < 0 || ws_id >= SWM_WS_MAX) + errx(1, "layout: invalid workspace %d", ws_id + 1); + + if (!strcasecmp(s, "vertical")) + st = SWM_V_STACK; + else if (!strcasecmp(s, "horizontal")) + st = SWM_H_STACK; + else if (!strcasecmp(s, "fullscreen")) + st = SWM_MAX_STACK; + else + errx(1, "invalid layout entry, should be 'ws[]:" + "::::" + "'"); + + for (i = 0; i < ScreenCount(display); i++) { + ws = (struct workspace *)&screens[i].ws; + ws[ws_id].cur_layout = &layouts[st]; + + ws[ws_id].always_raise = raise; + if (st == SWM_MAX_STACK) + continue; + + /* master grow */ + for (x = 0; x < abs(mg); x++) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + mg >= 0 ? SWM_ARG_ID_MASTERGROW : + SWM_ARG_ID_MASTERSHRINK); + stack(); + } + /* master add */ + for (x = 0; x < abs(ma); x++) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + ma >= 0 ? SWM_ARG_ID_MASTERADD : + SWM_ARG_ID_MASTERDEL); + stack(); + } + /* stack inc */ + for (x = 0; x < abs(si); x++) { + ws[ws_id].cur_layout->l_config(&ws[ws_id], + si >= 0 ? SWM_ARG_ID_STACKINC : + SWM_ARG_ID_STACKDEC); + stack(); + } + } + + return (0); +} + +/* config options */ +struct config_option { + char *optname; + int (*func)(char*, char*, int); + int funcflags; +}; +struct config_option configopt[] = { + { "bar_enabled", setconfvalue, SWM_S_BAR_ENABLED }, + { "bar_at_bottom", setconfvalue, SWM_S_BAR_AT_BOTTOM }, + { "bar_border", setconfcolor, SWM_S_COLOR_BAR_BORDER }, + { "bar_border_width", setconfvalue, SWM_S_BAR_BORDER_WIDTH }, + { "bar_color", setconfcolor, SWM_S_COLOR_BAR }, + { "bar_font_color", setconfcolor, SWM_S_COLOR_BAR_FONT }, + { "bar_font", setconfvalue, SWM_S_BAR_FONT }, + { "bar_action", setconfvalue, SWM_S_BAR_ACTION }, + { "bar_delay", setconfvalue, SWM_S_BAR_DELAY }, + { "bar_justify", setconfvalue, SWM_S_BAR_JUSTIFY }, + { "keyboard_mapping", setkeymapping, 0 }, + { "bind", setconfbinding, 0 }, + { "stack_enabled", setconfvalue, SWM_S_STACK_ENABLED }, + { "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED }, + { "clock_format", setconfvalue, SWM_S_CLOCK_FORMAT }, + { "color_focus", setconfcolor, SWM_S_COLOR_FOCUS }, + { "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS }, + { "cycle_empty", setconfvalue, SWM_S_CYCLE_EMPTY }, + { "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE }, + { "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO }, + { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, + { "modkey", setconfmodkey, 0 }, + { "program", setconfspawn, 0 }, + { "quirk", setconfquirk, 0 }, + { "region", setconfregion, 0 }, + { "spawn_term", setconfvalue, SWM_S_SPAWN_TERM }, + { "screenshot_enabled", setconfvalue, SWM_S_SS_ENABLED }, + { "screenshot_app", setconfvalue, SWM_S_SS_APP }, + { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, + { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, + { "term_width", setconfvalue, SWM_S_TERM_WIDTH }, + { "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED }, + { "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED }, + { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, + { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER }, + { "border_width", setconfvalue, SWM_S_BORDER_WIDTH }, + { "autorun", setautorun, 0 }, + { "layout", setlayout, 0 }, +}; + + +int +conf_load(char *filename, int keymapping) +{ + FILE *config; + char *line, *cp, *optsub, *optval; + size_t linelen, lineno = 0; + int wordlen, i, optind; + struct config_option *opt; + + DNPRINTF(SWM_D_CONF, "conf_load: begin\n"); + + if (filename == NULL) { + warnx("conf_load: no filename"); + return (1); + } + if ((config = fopen(filename, "r")) == NULL) { + warn("conf_load: fopen: %s", filename); + return (1); + } + + while (!feof(config)) { + if ((line = fparseln(config, &linelen, &lineno, NULL, 0)) + == NULL) { + if (ferror(config)) + err(1, "%s", filename); + else + continue; + } + cp = line; + cp += strspn(cp, " \t\n"); /* eat whitespace */ + if (cp[0] == '\0') { + /* empty line */ + free(line); + continue; + } + /* get config option */ + wordlen = strcspn(cp, "=[ \t\n"); + if (wordlen == 0) { + warnx("%s: line %zd: no option found", + filename, lineno); + goto out; + } + optind = -1; + for (i = 0; i < LENGTH(configopt); i++) { + opt = &configopt[i]; + if (!strncasecmp(cp, opt->optname, wordlen) && + strlen(opt->optname) == wordlen) { + optind = i; + break; + } + } + if (optind == -1) { + warnx("%s: line %zd: unknown option %.*s", + filename, lineno, wordlen, cp); + goto out; + } + if (keymapping && strcmp(opt->optname, "bind")) { + warnx("%s: line %zd: invalid option %.*s", + filename, lineno, wordlen, cp); + goto out; + } + cp += wordlen; + cp += strspn(cp, " \t\n"); /* eat whitespace */ + /* get [selector] if any */ + optsub = NULL; + if (*cp == '[') { + cp++; + wordlen = strcspn(cp, "]"); + if (*cp != ']') { + if (wordlen == 0) { + warnx("%s: line %zd: syntax error", + filename, lineno); + goto out; + } + + if (asprintf(&optsub, "%.*s", wordlen, cp) == + -1) { + warnx("%s: line %zd: unable to allocate" + "memory for selector", filename, + lineno); + goto out; + } + } + cp += wordlen; + cp += strspn(cp, "] \t\n"); /* eat trailing */ + } + cp += strspn(cp, "= \t\n"); /* eat trailing */ + /* get RHS value */ + optval = strdup(cp); + /* call function to deal with it all */ + if (configopt[optind].func(optsub, optval, + configopt[optind].funcflags) != 0) + errx(1, "%s: line %zd: invalid data for %s", + filename, lineno, configopt[optind].optname); + free(optval); + free(optsub); + free(line); + } + + fclose(config); + DNPRINTF(SWM_D_CONF, "conf_load: end\n"); + + return (0); + +out: + free(line); + fclose(config); + DNPRINTF(SWM_D_CONF, "conf_load: end with error.\n"); + + return (1); +} + +void +set_child_transient(struct ws_win *win, Window *trans) +{ + struct ws_win *parent, *w; + XWMHints *wmh = NULL; + struct swm_region *r; + struct workspace *ws; + + parent = find_window(win->transient); + if (parent) + parent->child_trans = win; + else { + DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist" + " for 0x%lx trans 0x%lx\n", win->id, win->transient); + + if (win->hints == NULL) { + warnx("no hints for 0x%lx", win->id); + return; + } + + r = root_to_region(win->wa.root); + ws = r->ws; + /* parent doen't exist in our window list */ + TAILQ_FOREACH(w, &ws->winlist, entry) { + if (wmh) + XFree(wmh); + + if ((wmh = XGetWMHints(display, w->id)) == NULL) { + warnx("can't get hints for 0x%lx", w->id); + continue; + } + + if (win->hints->window_group != wmh->window_group) + continue; + + w->child_trans = win; + win->transient = w->id; + *trans = w->id; + DNPRINTF(SWM_D_MISC, "set_child_transient: asjusting " + "transient to 0x%lx\n", win->transient); + break; + } + } + + if (wmh) + XFree(wmh); +} + +long +window_get_pid(Window win) +{ + Atom actual_type_return; + int actual_format_return = 0; + unsigned long nitems_return = 0; + unsigned long bytes_after_return = 0; + long *pid = NULL; + long ret = 0; + const char *errstr; + unsigned char *prop = NULL; + + if (XGetWindowProperty(display, win, + XInternAtom(display, "_NET_WM_PID", False), 0, 1, False, + XA_CARDINAL, &actual_type_return, &actual_format_return, + &nitems_return, &bytes_after_return, + (unsigned char**)(void*)&pid) != Success) + goto tryharder; + if (actual_type_return != XA_CARDINAL) + goto tryharder; + if (pid == NULL) + goto tryharder; + + ret = *pid; + XFree(pid); + + return (ret); + +tryharder: + if (XGetWindowProperty(display, win, + XInternAtom(display, "_SWM_PID", False), 0, SWM_PROPLEN, False, + XA_STRING, &actual_type_return, &actual_format_return, + &nitems_return, &bytes_after_return, &prop) != Success) + return (0); + if (actual_type_return != XA_STRING) + return (0); + if (prop == NULL) + return (0); + + ret = strtonum((const char *)prop, 0, UINT_MAX, &errstr); + /* ignore error because strtonum returns 0 anyway */ + XFree(prop); + + return (ret); +} + +struct ws_win * +manage_window(Window id) +{ + Window trans = 0; + struct workspace *ws; + struct ws_win *win, *ww; + int format, i, ws_idx, n, border_me = 0; + unsigned long nitems, bytes; + Atom ws_idx_atom = 0, type; + Atom *prot = NULL, *pp; + unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; + struct swm_region *r; + long mask; + const char *errstr; + XWindowChanges wc; + struct pid_e *p; + struct quirk *qp; + + if ((win = find_window(id)) != NULL) + return (win); /* already being managed */ + + /* see if we are on the unmanaged list */ + if ((win = find_unmanaged_window(id)) != NULL) { + DNPRINTF(SWM_D_MISC, "manage_window: previously unmanaged " + "window: 0x%lx\n", win->id); + TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); + if (win->transient) { + set_child_transient(win, &trans); + } if (trans && (ww = find_window(trans))) + TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); + else + TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); + ewmh_update_actions(win); + return (win); + } + + if ((win = calloc(1, sizeof(struct ws_win))) == NULL) + err(1, "manage_window: calloc: failed to allocate memory for " + "new window"); + + win->id = id; + + /* see if we need to override the workspace */ + p = find_pid(window_get_pid(id)); + + /* Get all the window data in one shot */ + ws_idx_atom = XInternAtom(display, "_SWM_WS", False); + if (ws_idx_atom) { + XGetWindowProperty(display, id, ws_idx_atom, 0, SWM_PROPLEN, + False, XA_STRING, &type, &format, &nitems, &bytes, &prop); + } + XGetWindowAttributes(display, id, &win->wa); + XGetWMNormalHints(display, id, &win->sh, &win->sh_mask); + win->hints = XGetWMHints(display, id); + XGetTransientForHint(display, id, &trans); + if (trans) { + win->transient = trans; + set_child_transient(win, &trans); + DNPRINTF(SWM_D_MISC, "manage_window: window: 0x%lx, " + "transient: 0x%lx\n", win->id, win->transient); + } + + /* get supported protocols */ + if (XGetWMProtocols(display, id, &prot, &n)) { + for (i = 0, pp = prot; i < n; i++, pp++) { + if (*pp == takefocus) + win->take_focus = 1; + if (*pp == adelete) + win->can_delete = 1; + } + if (prot) + XFree(prot); + } + + win->iconic = get_iconic(win); + + /* + * Figure out where to put the window. If it was previously assigned to + * a workspace (either by spawn() or manually moving), and isn't + * transient, * put it in the same workspace + */ + r = root_to_region(win->wa.root); + if (p) { + ws = &r->s->ws[p->ws]; + TAILQ_REMOVE(&pidlist, p, entry); + free(p); + p = NULL; + } else if (prop && win->transient == 0) { + DNPRINTF(SWM_D_PROP, "manage_window: get _SWM_WS: %s\n", prop); + ws_idx = strtonum((const char *)prop, 0, 9, &errstr); + if (errstr) { + DNPRINTF(SWM_D_EVENT, "manage_window: window: #%s: %s", + errstr, prop); + } + ws = &r->s->ws[ws_idx]; + } else { + ws = r->ws; + /* this should launch transients in the same ws as parent */ + if (id && trans) + if ((ww = find_window(trans)) != NULL) + if (ws->r) { + ws = ww->ws; + if (ww->ws->r) + r = ww->ws->r; + else + warnx("manage_window: fix this " + "bug mcbride"); + border_me = 1; + } + } + + /* set up the window layout */ + win->id = id; + win->ws = ws; + win->s = r->s; /* this never changes */ + if (trans && (ww = find_window(trans))) + TAILQ_INSERT_AFTER(&ws->winlist, ww, win, entry); + else + TAILQ_INSERT_TAIL(&ws->winlist, win, entry); + + WIDTH(win) = win->wa.width; + HEIGHT(win) = win->wa.height; + X(win) = win->wa.x; + Y(win) = win->wa.y; + win->g_floatvalid = 0; + win->floatmaxed = 0; + win->ewmh_flags = 0; + + /* Set window properties so we can remember this after reincarnation */ + if (ws_idx_atom && prop == NULL && + snprintf((char *)ws_idx_str, SWM_PROPLEN, "%d", ws->idx) < + SWM_PROPLEN) { + DNPRINTF(SWM_D_PROP, "manage_window: set _SWM_WS: %s\n", + ws_idx_str); + XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8, + PropModeReplace, ws_idx_str, strlen((char *)ws_idx_str)); + } + if (prop) + XFree(prop); + + ewmh_autoquirk(win); + + if (XGetClassHint(display, win->id, &win->ch)) { + DNPRINTF(SWM_D_CLASS, "manage_window: class: %s, name: %s\n", + win->ch.res_class, win->ch.res_name); + + /* java is retarded so treat it special */ + if (strstr(win->ch.res_name, "sun-awt")) { + win->java = 1; + border_me = 1; + } + + TAILQ_FOREACH(qp, &quirks, entry) { + if (!strcmp(win->ch.res_class, qp->class) && + !strcmp(win->ch.res_name, qp->name)) { + DNPRINTF(SWM_D_CLASS, "manage_window: found: " + "class: %s, name: %s\n", win->ch.res_class, + win->ch.res_name); + if (qp->quirk & SWM_Q_FLOAT) { + win->floating = 1; + border_me = 1; + } + win->quirks = qp->quirk; + } + } + } + + /* alter window position if quirky */ + if (win->quirks & SWM_Q_ANYWHERE) { + win->manual = 1; /* don't center the quirky windows */ + bzero(&wc, sizeof wc); + mask = 0; + if (bar_enabled && Y(win) < bar_height) { + Y(win) = wc.y = bar_height; + mask |= CWY; + } + if (WIDTH(win) + X(win) > WIDTH(r)) { + X(win) = wc.x = WIDTH(r) - WIDTH(win) - 2; + mask |= CWX; + } + border_me = 1; + } + + /* Reset font sizes (the bruteforce way; no default keybinding). */ + if (win->quirks & SWM_Q_XTERM_FONTADJ) { + for (i = 0; i < SWM_MAX_FONT_STEPS; i++) + fake_keypress(win, XK_KP_Subtract, ShiftMask); + for (i = 0; i < SWM_MAX_FONT_STEPS; i++) + fake_keypress(win, XK_KP_Add, ShiftMask); + } + + ewmh_get_win_state(win); + ewmh_update_actions(win); + ewmh_update_win_state(win, None, _NET_WM_STATE_REMOVE); + + /* border me */ + if (border_me) { + bzero(&wc, sizeof wc); + wc.border_width = border_width; + mask = CWBorderWidth; + XConfigureWindow(display, win->id, mask, &wc); + } + + XSelectInput(display, id, EnterWindowMask | FocusChangeMask | + PropertyChangeMask | StructureNotifyMask); + + /* floaters need to be mapped if they are in the current workspace */ + if ((win->floating || win->transient) && (ws->idx == r->ws->idx)) + XMapRaised(display, win->id); + + return (win); +} + +void +free_window(struct ws_win *win) +{ + DNPRINTF(SWM_D_MISC, "free_window: window: 0x%lx\n", win->id); + + if (win == NULL) + return; + + /* needed for restart wm */ + set_win_state(win, WithdrawnState); + + TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); + + if (win->ch.res_class) + XFree(win->ch.res_class); + if (win->ch.res_name) + XFree(win->ch.res_name); + + kill_refs(win); + + /* paint memory */ + memset(win, 0xff, sizeof *win); /* XXX kill later */ + + free(win); +} + +void +unmanage_window(struct ws_win *win) +{ + struct ws_win *parent; + + if (win == NULL) + return; + + DNPRINTF(SWM_D_MISC, "unmanage_window: window: 0x%lx\n", win->id); + + if (win->transient) { + parent = find_window(win->transient); + if (parent) + parent->child_trans = NULL; + } + + /* focus on root just in case */ + XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); + + focus_prev(win); + + if (win->hints) { + XFree(win->hints); + win->hints = NULL; + } + + TAILQ_REMOVE(&win->ws->winlist, win, entry); + TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); + + kill_refs(win); +} + +void +focus_magic(struct ws_win *win) +{ + DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%lx\n", WINID(win)); + + if (win == NULL) { + /* if there are no windows clear the status-bar */ + bar_check_opts(); + return; + } + + if (win->child_trans) { + /* win = parent & has a transient so focus on that */ + if (win->java) { + focus_win(win->child_trans); + if (win->child_trans->take_focus) + client_msg(win, takefocus); + } else { + /* make sure transient hasn't disappeared */ + if (validate_win(win->child_trans) == 0) { + focus_win(win->child_trans); + if (win->child_trans->take_focus) + client_msg(win->child_trans, takefocus); + } else { + win->child_trans = NULL; + focus_win(win); + if (win->take_focus) + client_msg(win, takefocus); + } + } + } else { + /* regular focus */ + focus_win(win); + if (win->take_focus) + client_msg(win, takefocus); + } +} + +void +expose(XEvent *e) +{ + DNPRINTF(SWM_D_EVENT, "expose: window: 0x%lx\n", e->xexpose.window); +} + +void +keypress(XEvent *e) +{ + KeySym keysym; + XKeyEvent *ev = &e->xkey; + struct key *kp; + struct swm_region *r; + + keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0); + if ((kp = key_lookup(CLEANMASK(ev->state), keysym)) == NULL) + return; + if (keyfuncs[kp->funcid].func == NULL) + return; + + r = root_to_region(ev->root); + if (kp->funcid == kf_spawn_custom) + spawn_custom(r, &(keyfuncs[kp->funcid].args), kp->spawn_name); + else + keyfuncs[kp->funcid].func(r, &(keyfuncs[kp->funcid].args)); +} + +void +buttonpress(XEvent *e) +{ + struct ws_win *win; + int i, action; + XButtonPressedEvent *ev = &e->xbutton; + + if ((win = find_window(ev->window)) == NULL) + return; + + focus_magic(win); + action = client_click; + + for (i = 0; i < LENGTH(buttons); i++) + if (action == buttons[i].action && buttons[i].func && + buttons[i].button == ev->button && + CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(win, &buttons[i].args); +} + +void +configurerequest(XEvent *e) +{ + XConfigureRequestEvent *ev = &e->xconfigurerequest; + struct ws_win *win; + int new = 0; + XWindowChanges wc; + + if ((win = find_window(ev->window)) == NULL) + if ((win = find_unmanaged_window(ev->window)) == NULL) + new = 1; + + DNPRINTF(SWM_D_EVENT, "configurerequest: window: 0x%lx, new: %s\n", + ev->window, YESNO(new)); + + if (new) { + bzero(&wc, sizeof wc); + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(display, ev->window, ev->value_mask, &wc); + } else { + config_win(win, ev); + } +} + +void +configurenotify(XEvent *e) +{ + struct ws_win *win; + + DNPRINTF(SWM_D_EVENT, "configurenotify: window: 0x%lx\n", + e->xconfigure.window); + + win = find_window(e->xconfigure.window); + if (win) { + XGetWMNormalHints(display, win->id, &win->sh, &win->sh_mask); + adjust_font(win); + if (font_adjusted) + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + } +} + +void +destroynotify(XEvent *e) +{ + struct ws_win *win; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + DNPRINTF(SWM_D_EVENT, "destroynotify: window: 0x%lx\n", ev->window); + + if ((win = find_window(ev->window)) == NULL) { + if ((win = find_unmanaged_window(ev->window)) == NULL) + return; + free_window(win); + return; + } + + /* make sure we focus on something */ + win->floating = 0; + + unmanage_window(win); + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + free_window(win); +} + +void +enternotify(XEvent *e) +{ + XCrossingEvent *ev = &e->xcrossing; + XEvent cne; + struct ws_win *win; +#if 0 + struct ws_win *w; + Window focus_return; + int revert_to_return; +#endif + DNPRINTF(SWM_D_FOCUS, "enternotify: window: 0x%lx, mode: %d, detail: " + "%d, root: 0x%lx, subwindow: 0x%lx, same_screen: %s, focus: %s, " + "state: %d\n", ev->window, ev->mode, ev->detail, ev->root, + ev->subwindow, YESNO(ev->same_screen), YESNO(ev->focus), ev->state); + + if (ev->mode != NotifyNormal) { + DNPRINTF(SWM_D_EVENT, "skip enternotify: generated by " + "cursor grab.\n"); + return; + } + + switch (focus_mode) { + case SWM_FOCUS_DEFAULT: + break; + case SWM_FOCUS_FOLLOW: + break; + case SWM_FOCUS_SYNERGY: +#if 0 + /* + * all these checks need to be in this order because the + * XCheckTypedWindowEvent relies on weeding out the previous events + * + * making this code an option would enable a follow mouse for focus + * feature + */ + + /* + * state is set when we are switching workspaces and focus is set when + * the window or a subwindow already has focus (occurs during restart). + * + * Only honor the focus flag if last_focus_event is not FocusOut, + * this allows spectrwm to continue to control focus when another + * program is also playing with it. + */ + if (ev->state || (ev->focus && last_focus_event != FocusOut)) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: focus\n"); + return; + } + + /* + * happens when a window is created or destroyed and the border + * crosses the mouse pointer and when switching ws + * + * we need the subwindow test to see if we came from root in order + * to give focus to floaters + */ + if (ev->mode == NotifyNormal && ev->detail == NotifyVirtual && + ev->subwindow == 0) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: NotifyVirtual\n"); + return; + } + + /* this window already has focus */ + if (ev->mode == NotifyNormal && ev->detail == NotifyInferior) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: win has focus\n"); + return; + } + + /* this window is being deleted or moved to another ws */ + if (XCheckTypedWindowEvent(display, ev->window, ConfigureNotify, + &cne) == True) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: configurenotify\n"); + XPutBackEvent(display, &cne); + return; + } + + if ((win = find_window(ev->window)) == NULL) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: win == NULL\n"); + return; + } + + /* + * In fullstack kill all enters unless they come from a different ws + * (i.e. another region) or focus has been grabbed externally. + */ + if (win->ws->cur_layout->flags & SWM_L_FOCUSPREV && + last_focus_event != FocusOut) { + XGetInputFocus(display, &focus_return, &revert_to_return); + if ((w = find_window(focus_return)) == NULL || + w->ws == win->ws) { + DNPRINTF(SWM_D_EVENT, "ignoring event: fullstack\n"); + return; + } + } +#endif + break; + } + + if ((win = find_window(ev->window)) == NULL) { + DNPRINTF(SWM_D_EVENT, "skip enternotify: window is NULL\n"); + return; + } + + /* + * if we have more enternotifies let them handle it in due time + */ + if (XCheckTypedEvent(display, EnterNotify, &cne) == True) { + DNPRINTF(SWM_D_EVENT, + "ignoring enternotify: got more enternotify\n"); + XPutBackEvent(display, &cne); + return; + } + + focus_magic(win); +} + +/* lets us use one switch statement for arbitrary mode/detail combinations */ +#define MERGE_MEMBERS(a,b) (((a & 0xffff) << 16) | (b & 0xffff)) + +void +focusevent(XEvent *e) +{ +#if 0 + struct ws_win *win; + u_int32_t mode_detail; + XFocusChangeEvent *ev = &e->xfocus; + + DNPRINTF(SWM_D_EVENT, "focusevent: %s window: 0x%lx mode: %d " + "detail: %d\n", ev->type == FocusIn ? "entering" : "leaving", + ev->window, ev->mode, ev->detail); + + if (last_focus_event == ev->type) { + DNPRINTF(SWM_D_FOCUS, "ignoring focusevent: bad ordering\n"); + return; + } + + last_focus_event = ev->type; + mode_detail = MERGE_MEMBERS(ev->mode, ev->detail); + + switch (mode_detail) { + /* synergy client focus operations */ + case MERGE_MEMBERS(NotifyNormal, NotifyNonlinear): + case MERGE_MEMBERS(NotifyNormal, NotifyNonlinearVirtual): + + /* synergy server focus operations */ + case MERGE_MEMBERS(NotifyWhileGrabbed, NotifyNonlinear): + + /* Entering applications like rdesktop that mangle the pointer */ + case MERGE_MEMBERS(NotifyNormal, NotifyPointer): + + if ((win = find_window(e->xfocus.window)) != NULL && win->ws->r) + XSetWindowBorder(display, win->id, + win->ws->r->s->c[ev->type == FocusIn ? + SWM_S_COLOR_FOCUS : SWM_S_COLOR_UNFOCUS].color); + break; + default: + warnx("ignoring focusevent"); + DNPRINTF(SWM_D_FOCUS, "ignoring focusevent\n"); + break; + } +#endif +} + +void +mapnotify(XEvent *e) +{ + struct ws_win *win; + XMapEvent *ev = &e->xmap; + + DNPRINTF(SWM_D_EVENT, "mapnotify: window: 0x%lx\n", ev->window); + + win = manage_window(ev->window); + if (win) + set_win_state(win, NormalState); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +maprequest(XEvent *e) +{ + struct ws_win *win; + struct swm_region *r; + XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; + + DNPRINTF(SWM_D_EVENT, "maprequest: window: 0x%lx\n", + e->xmaprequest.window); + + if (!XGetWindowAttributes(display, ev->window, &wa)) + return; + if (wa.override_redirect) + return; + + win = manage_window(e->xmaprequest.window); + if (win == NULL) + return; /* can't happen */ + + stack(); + + /* make new win focused */ + r = root_to_region(win->wa.root); + if (win->ws == r->ws) + focus_magic(win); +} + +void +propertynotify(XEvent *e) +{ + struct ws_win *win; + XPropertyEvent *ev = &e->xproperty; +#ifdef SWM_DEBUG + char *name; + name = XGetAtomName(display, ev->atom); + DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%lx, atom: %s\n", + ev->window, name); + XFree(name); +#endif + + win = find_window(ev->window); + if (win == NULL) + return; + + if (ev->state == PropertyDelete && ev->atom == a_swm_iconic) { + update_iconic(win, 0); + XMapRaised(display, win->id); + stack(); + focus_win(win); + return; + } + + switch (ev->atom) { +#if 0 + case XA_WM_NORMAL_HINTS: + long mask; + XGetWMNormalHints(display, win->id, &win->sh, &mask); + warnx("normal hints: flag 0x%x", win->sh.flags); + if (win->sh.flags & PMinSize) { + WIDTH(win) = win->sh.min_width; + HEIGHT(win) = win->sh.min_height; + warnx("min %d %d", WIDTH(win), HEIGHT(win)); + } + XMoveResizeWindow(display, win->id, + X(win), Y(win), WIDTH(win), HEIGHT(win)); +#endif + case XA_WM_CLASS: + if (title_name_enabled || title_class_enabled) + bar_update(); + break; + case XA_WM_NAME: + if (window_name_enabled) + bar_update(); + break; + default: + break; + } +} + +void +unmapnotify(XEvent *e) +{ + struct ws_win *win; + + DNPRINTF(SWM_D_EVENT, "unmapnotify: window: 0x%lx\n", e->xunmap.window); + + /* determine if we need to help unmanage this window */ + win = find_window(e->xunmap.window); + if (win == NULL) + return; + + if (getstate(e->xunmap.window) == NormalState) { + unmanage_window(win); + stack(); + + /* giant hack for apps that don't destroy transient windows */ + /* eat a bunch of events to prevent remanaging the window */ + XEvent cne; + while (XCheckWindowEvent(display, e->xunmap.window, + EnterWindowMask, &cne)) + ; + while (XCheckWindowEvent(display, e->xunmap.window, + StructureNotifyMask, &cne)) + ; + while (XCheckWindowEvent(display, e->xunmap.window, + SubstructureNotifyMask, &cne)) + ; + /* resend unmap because we ated it */ + XUnmapWindow(display, e->xunmap.window); + } + + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); +} + +void +visibilitynotify(XEvent *e) +{ + int i; + struct swm_region *r; + + DNPRINTF(SWM_D_EVENT, "visibilitynotify: window: 0x%lx\n", + e->xvisibility.window); + if (e->xvisibility.state == VisibilityUnobscured) + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) + if (e->xvisibility.window == r->bar_window) + bar_update(); +} + +void +clientmessage(XEvent *e) +{ + XClientMessageEvent *ev; + struct ws_win *win; + + ev = &e->xclient; + + win = find_window(ev->window); + if (win == NULL) + return; + + DNPRINTF(SWM_D_EVENT, "clientmessage: window: 0x%lx, type: %ld\n", + ev->window, ev->message_type); + + if (ev->message_type == ewmh[_NET_ACTIVE_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n"); + focus_win(win); + } + if (ev->message_type == ewmh[_NET_CLOSE_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n"); + if (win->can_delete) + client_msg(win, adelete); + else + XKillClient(display, win->id); + } + if (ev->message_type == ewmh[_NET_MOVERESIZE_WINDOW].atom) { + DNPRINTF(SWM_D_EVENT, + "clientmessage: _NET_MOVERESIZE_WINDOW\n"); + if (win->floating) { + if (ev->data.l[0] & (1<<8)) /* x */ + X(win) = ev->data.l[1]; + if (ev->data.l[0] & (1<<9)) /* y */ + Y(win) = ev->data.l[2]; + if (ev->data.l[0] & (1<<10)) /* width */ + WIDTH(win) = ev->data.l[3]; + if (ev->data.l[0] & (1<<11)) /* height */ + HEIGHT(win) = ev->data.l[4]; + + update_window(win); + } + else { + /* TODO: Change stack sizes */ + /* notify no change was made. */ + config_win(win, NULL); + } + } + if (ev->message_type == ewmh[_NET_WM_STATE].atom) { + DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE\n"); + ewmh_update_win_state(win, ev->data.l[1], ev->data.l[0]); + if (ev->data.l[2]) + ewmh_update_win_state(win, ev->data.l[2], + ev->data.l[0]); + + stack(); + } +} + +int +xerror_start(Display *d, XErrorEvent *ee) +{ + other_wm = 1; + return (-1); +} + +int +xerror(Display *d, XErrorEvent *ee) +{ + /* warnx("error: %p %p", display, ee); */ + return (-1); +} + +int +active_wm(void) +{ + other_wm = 0; + xerrorxlib = XSetErrorHandler(xerror_start); + + /* this causes an error if some other window manager is running */ + XSelectInput(display, DefaultRootWindow(display), + SubstructureRedirectMask); + XSync(display, False); + if (other_wm) + return (1); + + XSetErrorHandler(xerror); + XSync(display, False); + return (0); +} + +void +new_region(struct swm_screen *s, int x, int y, int w, int h) +{ + struct swm_region *r, *n; + struct workspace *ws = NULL; + int i; + + DNPRINTF(SWM_D_MISC, "new region: screen[%d]:%dx%d+%d+%d\n", + s->idx, w, h, x, y); + + /* remove any conflicting regions */ + n = TAILQ_FIRST(&s->rl); + while (n) { + r = n; + n = TAILQ_NEXT(r, entry); + if (X(r) < (x + w) && + (X(r) + WIDTH(r)) > x && + Y(r) < (y + h) && + (Y(r) + HEIGHT(r)) > y) { + if (r->ws->r != NULL) + r->ws->old_r = r->ws->r; + r->ws->r = NULL; + XDestroyWindow(display, r->bar_window); + TAILQ_REMOVE(&s->rl, r, entry); + TAILQ_INSERT_TAIL(&s->orl, r, entry); + } + } + + /* search old regions for one to reuse */ + + /* size + location match */ + TAILQ_FOREACH(r, &s->orl, entry) + if (X(r) == x && Y(r) == y && + HEIGHT(r) == h && WIDTH(r) == w) + break; + + /* size match */ + TAILQ_FOREACH(r, &s->orl, entry) + if (HEIGHT(r) == h && WIDTH(r) == w) + break; + + if (r != NULL) { + TAILQ_REMOVE(&s->orl, r, entry); + /* try to use old region's workspace */ + if (r->ws->r == NULL) + ws = r->ws; + } else + if ((r = calloc(1, sizeof(struct swm_region))) == NULL) + err(1, "new_region: calloc: failed to allocate memory " + "for screen"); + + /* if we don't have a workspace already, find one */ + if (ws == NULL) { + for (i = 0; i < SWM_WS_MAX; i++) + if (s->ws[i].r == NULL) { + ws = &s->ws[i]; + break; + } + } + + if (ws == NULL) + errx(1, "new_region: no free workspaces"); + + X(r) = x; + Y(r) = y; + WIDTH(r) = w; + HEIGHT(r) = h; + r->s = s; + r->ws = ws; + r->ws_prior = NULL; + ws->r = r; + outputs++; + TAILQ_INSERT_TAIL(&s->rl, r, entry); +} + +void +scan_xrandr(int i) +{ +#ifdef SWM_XRR_HAS_CRTC + XRRCrtcInfo *ci; + XRRScreenResources *sr; + int c; + int ncrtc = 0; +#endif /* SWM_XRR_HAS_CRTC */ + struct swm_region *r; + + + if (i >= ScreenCount(display)) + errx(1, "scan_xrandr: invalid screen"); + + /* remove any old regions */ + while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { + r->ws->old_r = r->ws->r = NULL; + XDestroyWindow(display, r->bar_window); + TAILQ_REMOVE(&screens[i].rl, r, entry); + TAILQ_INSERT_TAIL(&screens[i].orl, r, entry); + } + outputs = 0; + + /* map virtual screens onto physical screens */ +#ifdef SWM_XRR_HAS_CRTC + if (xrandr_support) { + sr = XRRGetScreenResources(display, screens[i].root); + if (sr == NULL) + new_region(&screens[i], 0, 0, + DisplayWidth(display, i), + DisplayHeight(display, i)); + else + ncrtc = sr->ncrtc; + + for (c = 0, ci = NULL; c < ncrtc; c++) { + ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]); + if (ci->noutput == 0) + continue; + + if (ci != NULL && ci->mode == None) + new_region(&screens[i], 0, 0, + DisplayWidth(display, i), + DisplayHeight(display, i)); + else + new_region(&screens[i], + ci->x, ci->y, ci->width, ci->height); + } + if (ci) + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } else +#endif /* SWM_XRR_HAS_CRTC */ + { + new_region(&screens[i], 0, 0, DisplayWidth(display, i), + DisplayHeight(display, i)); + } +} + +void +screenchange(XEvent *e) { + XRRScreenChangeNotifyEvent *xe = (XRRScreenChangeNotifyEvent *)e; + struct swm_region *r; + int i; + + DNPRINTF(SWM_D_EVENT, "screenchange: root: 0x%lx\n", xe->root); + + if (!XRRUpdateConfiguration(e)) + return; + + /* silly event doesn't include the screen index */ + for (i = 0; i < ScreenCount(display); i++) + if (screens[i].root == xe->root) + break; + if (i >= ScreenCount(display)) + errx(1, "screenchange: screen not found"); + + /* brute force for now, just re-enumerate the regions */ + scan_xrandr(i); + + /* add bars to all regions */ + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) + bar_setup(r); + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); +} + +void +grab_windows(void) +{ + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + unsigned int no; + int i, j; + long state, manage; + + for (i = 0; i < ScreenCount(display); i++) { + if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no)) + continue; + + /* attach windows to a region */ + /* normal windows */ + for (j = 0; j < no; j++) { + if (!XGetWindowAttributes(display, wins[j], &wa) || + wa.override_redirect || + XGetTransientForHint(display, wins[j], &d1)) + continue; + + state = getstate(wins[j]); + manage = state == IconicState; + if (wa.map_state == IsViewable || manage) + manage_window(wins[j]); + } + /* transient windows */ + for (j = 0; j < no; j++) { + if (!XGetWindowAttributes(display, wins[j], &wa) || + wa.override_redirect) + continue; + + state = getstate(wins[j]); + manage = state == IconicState; + if (XGetTransientForHint(display, wins[j], &d1) && + manage) + manage_window(wins[j]); + } + if (wins) { + XFree(wins); + wins = NULL; + } + } +} + +void +setup_screens(void) +{ + int i, j, k; + int errorbase, major, minor; + struct workspace *ws; + XGCValues gcv; + + if ((screens = calloc(ScreenCount(display), + sizeof(struct swm_screen))) == NULL) + err(1, "setup_screens: calloc: failed to allocate memory for " + "screens"); + + /* initial Xrandr setup */ + xrandr_support = XRRQueryExtension(display, + &xrandr_eventbase, &errorbase); + if (xrandr_support) + if (XRRQueryVersion(display, &major, &minor) && major < 1) + xrandr_support = 0; + + /* map physical screens */ + for (i = 0; i < ScreenCount(display); i++) { + DNPRINTF(SWM_D_WS, "setup_screens: init screen: %d\n", i); + screens[i].idx = i; + TAILQ_INIT(&screens[i].rl); + TAILQ_INIT(&screens[i].orl); + screens[i].root = RootWindow(display, i); + + /* set default colors */ + setscreencolor("red", i + 1, SWM_S_COLOR_FOCUS); + setscreencolor("rgb:88/88/88", i + 1, SWM_S_COLOR_UNFOCUS); + setscreencolor("rgb:00/80/80", i + 1, SWM_S_COLOR_BAR_BORDER); + setscreencolor("black", i + 1, SWM_S_COLOR_BAR); + setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT); + + /* create graphics context on screen with default font color */ + screens[i].bar_gc = XCreateGC(display, screens[i].root, 0, + &gcv); + + XSetForeground(display, screens[i].bar_gc, + screens[i].c[SWM_S_COLOR_BAR_FONT].color); + + /* set default cursor */ + XDefineCursor(display, screens[i].root, + XCreateFontCursor(display, XC_left_ptr)); + + /* init all workspaces */ + /* XXX these should be dynamically allocated too */ + for (j = 0; j < SWM_WS_MAX; j++) { + ws = &screens[i].ws[j]; + ws->idx = j; + ws->name = NULL; + ws->focus = NULL; + ws->r = NULL; + ws->old_r = NULL; + TAILQ_INIT(&ws->winlist); + TAILQ_INIT(&ws->unmanagedlist); + + for (k = 0; layouts[k].l_stack != NULL; k++) + if (layouts[k].l_config != NULL) + layouts[k].l_config(ws, + SWM_ARG_ID_STACKINIT); + ws->cur_layout = &layouts[0]; + ws->cur_layout->l_string(ws); + } + + scan_xrandr(i); + + if (xrandr_support) + XRRSelectInput(display, screens[i].root, + RRScreenChangeNotifyMask); + } +} + +void +setup_globals(void) +{ + if ((bar_fonts = strdup(SWM_BAR_FONTS)) == NULL) + err(1, "setup_globals: strdup: failed to allocate memory."); + + if ((spawn_term[0] = strdup("xterm")) == NULL) + err(1, "setup_globals: strdup: failed to allocate memory."); + + if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL) + err(1, "setup_globals: strdup: failed to allocate memory."); +} + +void +workaround(void) +{ + int i; + Atom netwmcheck, netwmname, utf8_string; + Window root, win; + + /* work around sun jdk bugs, code from wmname */ + netwmcheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); + netwmname = XInternAtom(display, "_NET_WM_NAME", False); + utf8_string = XInternAtom(display, "UTF8_STRING", False); + for (i = 0; i < ScreenCount(display); i++) { + root = screens[i].root; + win = XCreateSimpleWindow(display,root, 0, 0, 1, 1, 0, + screens[i].c[SWM_S_COLOR_UNFOCUS].color, + screens[i].c[SWM_S_COLOR_UNFOCUS].color); + + XChangeProperty(display, root, netwmcheck, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&win,1); + XChangeProperty(display, win, netwmcheck, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)&win,1); + XChangeProperty(display, win, netwmname, utf8_string, 8, + PropModeReplace, (unsigned char*)"LG3D", strlen("LG3D")); + } +} + +int +main(int argc, char *argv[]) +{ + struct swm_region *r, *rr; + struct ws_win *winfocus = NULL; + struct timeval tv; + union arg a; + char conf[PATH_MAX], *cfile = NULL; + struct stat sb; + XEvent e; + int xfd, i; + fd_set rd; + struct sigaction sact; + + start_argv = argv; + warnx("Welcome to spectrwm V%s Build: %s", SPECTRWM_VERSION, buildstr); + if (!setlocale(LC_CTYPE, "") || !setlocale(LC_TIME, "") || + !XSupportsLocale()) + warnx("no locale support"); + + if (!X_HAVE_UTF8_STRING) + warnx("no UTF-8 support"); + + if (!(display = XOpenDisplay(0))) + errx(1, "can not open display"); + + if (active_wm()) + errx(1, "other wm running"); + + /* handle some signals */ + bzero(&sact, sizeof(sact)); + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; + sact.sa_handler = sighdlr; + sigaction(SIGINT, &sact, NULL); + sigaction(SIGQUIT, &sact, NULL); + sigaction(SIGTERM, &sact, NULL); + sigaction(SIGHUP, &sact, NULL); + + sact.sa_handler = sighdlr; + sact.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &sact, NULL); + + astate = XInternAtom(display, "WM_STATE", False); + aprot = XInternAtom(display, "WM_PROTOCOLS", False); + adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); + takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False); + a_wmname = XInternAtom(display, "WM_NAME", False); + a_netwmname = XInternAtom(display, "_NET_WM_NAME", False); + a_utf8_string = XInternAtom(display, "UTF8_STRING", False); + a_string = XInternAtom(display, "STRING", False); + a_swm_iconic = XInternAtom(display, "_SWM_ICONIC", False); + + /* look for local and global conf file */ + pwd = getpwuid(getuid()); + if (pwd == NULL) + errx(1, "invalid user: %d", getuid()); + + setup_globals(); + setup_screens(); + setup_keys(); + setup_quirks(); + setup_spawn(); + + /* load config */ + snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE); + if (stat(conf, &sb) != -1) { + if (S_ISREG(sb.st_mode)) + cfile = conf; + } else { + /* try global conf file */ + snprintf(conf, sizeof conf, "/etc/%s", SWM_CONF_FILE); + if (!stat(conf, &sb)) + if (S_ISREG(sb.st_mode)) + cfile = conf; + } + + /* load conf (if any) and refresh font color in bar graphics contexts */ + if (cfile && conf_load(cfile, SWM_CONF_DEFAULT) == 0) + for (i = 0; i < ScreenCount(display); ++i) + XSetForeground(display, screens[i].bar_gc, + screens[i].c[SWM_S_COLOR_BAR_FONT].color); + + setup_ewmh(); + /* set some values to work around bad programs */ + workaround(); + /* grab existing windows (before we build the bars) */ + grab_windows(); + + if (getenv("SWM_STARTED") == NULL) + setenv("SWM_STARTED", "YES", 1); + + /* setup all bars */ + for (i = 0; i < ScreenCount(display); i++) + TAILQ_FOREACH(r, &screens[i].rl, entry) { + if (winfocus == NULL) + winfocus = TAILQ_FIRST(&r->ws->winlist); + bar_setup(r); + } + + unfocus_all(); + + grabkeys(); + stack(); + if (focus_mode == SWM_FOCUS_DEFAULT) + drain_enter_notify(); + + xfd = ConnectionNumber(display); + while (running) { + while (XPending(display)) { + XNextEvent(display, &e); + if (running == 0) + goto done; + if (e.type < LASTEvent) { + DNPRINTF(SWM_D_EVENTQ ,"XEvent: handled: %s, " + "window: 0x%lx, type: %s (%d), %d remaining" + "\n", YESNO(handler[e.type]), + e.xany.window, geteventname(&e), + e.type, QLength(display)); + + if (handler[e.type]) + handler[e.type](&e); + } else { + DNPRINTF(SWM_D_EVENTQ, "XRandr Event: window: " + "0x%lx, type: %s (%d)\n", e.xany.window, + xrandr_geteventname(&e), e.type); + + switch (e.type - xrandr_eventbase) { + case RRScreenChangeNotify: + screenchange(&e); + break; + default: + break; + } + } + } + + /* if we are being restarted go focus on first window */ + if (winfocus) { + rr = winfocus->ws->r; + if (rr == NULL) { + /* not a visible window */ + winfocus = NULL; + continue; + } + /* move pointer to first screen if multi screen */ + if (ScreenCount(display) > 1 || outputs > 1) + XWarpPointer(display, None, rr->s[0].root, + 0, 0, 0, 0, X(rr), + Y(rr) + (bar_enabled ? bar_height : 0)); + + a.id = SWM_ARG_ID_FOCUSCUR; + focus(rr, &a); + winfocus = NULL; + continue; + } + + FD_ZERO(&rd); + FD_SET(xfd, &rd); + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(xfd + 1, &rd, NULL, NULL, &tv) == -1) + if (errno != EINTR) + DNPRINTF(SWM_D_MISC, "select failed"); + if (restart_wm == 1) + restart(NULL, NULL); + if (search_resp == 1) + search_do_resp(); + if (running == 0) + goto done; + if (bar_alarm) { + bar_alarm = 0; + bar_update(); + } + } +done: + teardown_ewmh(); + bar_extra_stop(); + + for (i = 0; i < ScreenCount(display); ++i) + if (screens[i].bar_gc != NULL) + XFreeGC(display, screens[i].bar_gc); + + XFreeFontSet(display, bar_fs); + XCloseDisplay(display); + + return (0); +} diff --git a/spectrwm.conf b/spectrwm.conf new file mode 100644 index 0000000..5e460d5 --- /dev/null +++ b/spectrwm.conf @@ -0,0 +1,84 @@ +# PLEASE READ THE MAN PAGE BEFORE EDITING THIS FILE! +# http://opensource.conformal.com/cgi-bin/man-cgi?spectrwm + +# colors for focussed and unfocussed window borders +# NOTE: all colors in this file are in hex! see XQueryColor for examples +# color_focus = red +# color_unfocus = rgb:88/88/88 + +# bar settings +# bar_enabled = 1 +# bar_border_width = 1 +# bar_border[1] = rgb:00/80/80 +# bar_color[1] = black +# bar_font_color[1] = rgb:a0/a0/a0 +# bar_font = -*-terminus-medium-*-*-*-*-*-*-*-*-*-*-* +# bar_action = baraction.sh +# bar_delay = 1 +# bar_justify = left +# bar_at_bottom = 1 +# stack_enabled = 1 +# clock_enabled = 1 +# clock_format = %a %b %d %R %Z %Y +# title_name_enabled = 0 +# title_class_enabled = 0 +# window_name_enabled = 0 +# verbose_layout = 1 +# focus_mode = default +# disable_border = 1 +# border_width = 1 +# urgent_enabled = 1 + +# spawn app +# program[term] = xterm +# program[screenshot_all] = screenshot.sh full +# program[screenshot_wind] = screenshot.sh window +# program[lock] = xlock +# program[initscr] = initscreen.sh +# program[menu] = dmenu_run -fn $bar_font -nb $bar_color -nf $bar_font_color -sb $bar_border -sf $bar_color +# spawn_term = xterm + +# dialog box size ratio .3 >= r < 1 +# dialog_ratio = 0.6 + +# Split a non-Xrandr dual head setup into one region per monitor +# (non-standard driver-based multihead is not seen by spectrwm) +# region = screen[1]:1280x1024+0+0 +# region = screen[1]:1280x1024+1280+0 + +# Launch applications in a workspace of choice +# autorun = ws[1]:xterm +# autorun = ws[2]:xxxterm http://www.openbsd.org + +# workspace layout +# layout = ws[1]:4:0:0:0:vertical +# layout = ws[2]:0:0:0:0:horizontal +# layout = ws[3]:0:0:0:0:fullscreen + +# mod key, (windows key is Mod4) (apple key on OSX is Mod2) +# modkey = Mod1 + +# Clear key bindings and load new key bindings from the specified file. +# This allows you to load pre-defined key bindings for your keyboard layout. +# keyboard_mapping = ~/.spectrwm_us.conf + +# quirks +# remove with: quirk[class:name] = NONE +# quirk[MPlayer:xv] = FLOAT + FULLSCREEN + FOCUSPREV +# quirk[OpenOffice.org 2.4:VCLSalFrame] = FLOAT +# quirk[OpenOffice.org 3.0:VCLSalFrame] = FLOAT +# quirk[OpenOffice.org 3.1:VCLSalFrame] = FLOAT +# quirk[Firefox-bin:firefox-bin] = TRANSSZ +# quirk[Firefox:Dialog] = FLOAT +# quirk[Gimp:gimp] = FLOAT + ANYWHERE +# quirk[XTerm:xterm] = XTERM_FONTADJ +# quirk[xine:Xine Window] = FLOAT + ANYWHERE +# quirk[Xitk:Xitk Combo] = FLOAT + ANYWHERE +# quirk[xine:xine Panel] = FLOAT + ANYWHERE +# quirk[Xitk:Xine Window] = FLOAT + ANYWHERE +# quirk[xine:xine Video Fullscreen Window] = FULLSCREEN + FLOAT +# quirk[pcb:pcb] = FLOAT + +# EXAMPLE: define firefox program and bind to key +# program[firefox] = firefox http://spectrwm.org/ +# bind[firefox] = MOD+Shift+b diff --git a/spectrwm_cz.conf b/spectrwm_cz.conf new file mode 100644 index 0000000..37baeb7 --- /dev/null +++ b/spectrwm_cz.conf @@ -0,0 +1,74 @@ +# Key bindings for Czech Republic (cz) keyboards +# unbind with: bind[] = +bind[cycle_layout] = MOD+space +bind[flip_layout] = MOD+Shift+backslash +bind[stack_reset] = MOD+Shift+space +bind[master_shrink] = MOD+h +bind[master_grow] = MOD+l +bind[master_add] = MOD+comma +bind[master_del] = MOD+period +bind[stack_inc] = MOD+Shift+comma +bind[stack_dec] = MOD+Shift+period +bind[swap_main] = MOD+Return +bind[focus_next] = MOD+j +bind[focus_prev] = MOD+k +bind[swap_next] = MOD+Shift+j +bind[swap_prev] = MOD+Shift+k +bind[spawn_term] = MOD+Shift+Return +bind[menu] = MOD+p +bind[quit] = MOD+Shift+q +bind[restart] = MOD+q +bind[focus_main] = MOD+m +bind[ws_1] = MOD+plus +bind[ws_2] = MOD+ecaron +bind[ws_3] = MOD+scaron +bind[ws_4] = MOD+ccaron +bind[ws_5] = MOD+rcaron +bind[ws_6] = MOD+zcaron +bind[ws_7] = MOD+yacute +bind[ws_8] = MOD+aacute +bind[ws_9] = MOD+iacute +bind[ws_10] = MOD+eacute +bind[ws_next] = MOD+Right +bind[ws_prev] = MOD+Left +bind[ws_next_all] = MOD+Up +bind[ws_prev_all] = MOD+Down +bind[ws_prior] = MOD+a +bind[screen_next] = MOD+Shift+Right +bind[screen_prev] = MOD+Shift+Left +bind[mvws_1] = MOD+Shift+plus +bind[mvws_2] = MOD+Shift+ecaron +bind[mvws_3] = MOD+Shift+scaron +bind[mvws_4] = MOD+Shift+ccaron +bind[mvws_5] = MOD+Shift+rcaron +bind[mvws_6] = MOD+Shift+zcaron +bind[mvws_7] = MOD+Shift+yacute +bind[mvws_8] = MOD+Shift+aacute +bind[mvws_9] = MOD+Shift+iacute +bind[mvws_10] = MOD+Shift+eacute +bind[bar_toggle] = MOD+b +bind[focus_next] = MOD+Tab +bind[focus_prev] = MOD+Shift+Tab +bind[wind_kill] = MOD+Shift+x +bind[wind_del] = MOD+x +bind[screenshot_all] = MOD+s +bind[screenshot_wind] = MOD+Shift+s +bind[float_toggle] = MOD+t +bind[version] = MOD+Shift+v +bind[lock] = MOD+Shift+Delete +bind[initscr] = MOD+Shift+i +bind[iconify] = MOD+w +bind[uniconify] = MOD+Shift+w +bind[raise_toggle] = MOD+Shift+r +bind[button2] = MOD+v +bind[width_shrink] = MOD+equal +bind[width_grow] = MOD+dead_acute +bind[height_shrink] = MOD+Shift+equal +bind[height_grow] = MOD+Shift+dead_acute +bind[move_left] = MOD+uacute +bind[move_right] = MOD+parenright +bind[move_up] = MOD+Shift+uacute +bind[move_down] = MOD+Shift+parenright +bind[name_workspace] = MOD+Shift+slash +bind[search_workspace] = MOD+slash +bind[search_win] = MOD+f diff --git a/spectrwm_es.1 b/spectrwm_es.1 new file mode 100644 index 0000000..003487a --- /dev/null +++ b/spectrwm_es.1 @@ -0,0 +1,746 @@ +.\" Copyright (c) 2009 Marco Peereboom +.\" Copyright (c) 2009 Darrin Chandler +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt SPECTRWM 1 +.Os +.Sh NOMBRE +.Nm spectrwm +.Nd es un manejador de ventanas para X11 +.Sh SYNOPSIS +.Nm spectrwm +.Sh DESCRIPCIÓN +.Nm +es un manejador de ventanas super minimalista para X11. Intenta no superponer +las ventanas para que las mismas puedan usarse de manera eficiente y para cosas mas importantes. +Tiene configuraciones normales y no requiere que sepas un lenguaje de +programacion para configurarlo. Esta escrito por hackers para hackers y apunta +a ser pequeño, compacto y rápido. +.Pp +Cuando +.Nm +inicia, lo primero que hace es leer el archivo de configuracion, +.Pa spectrwm.conf . +Ver +.Sx ARCHIVOS DE CONFIGURACIÓN +. +.Pp +La siguiente anotacion se usa a través de esta pagina: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Cm M +Meta +.It Cm S +Shift +.It Aq Cm Name +Nombre de tecla +.It Cm M1 +Boton 1 del mouse +.It Cm M3 +Boton 3 del mouse +.El +.Pp +.Nm +es muy simple de usar. +La mayoria de las acciones se hacen con los mapeos (bindings) de mouse +o teclado. +Ver la sección de +.Sx BINDINGS +para las personalizaciones y configuraciones por defecto. +.Sh ARCHIVOS DE CONFIGURACIÓN +.Nm +primero trata de abrir el archivo por defecto en el directorio del usuario, +.Pa ~/.spectrwm.conf . +Si ese archivo no esta disponible, +luego trata de abrir el archivo global de configuracion +.Pa /etc/spectrwm.conf . +.Pp +El formato del archivo es \*(Lttecla\*(Gt = \*(Ltconfiguracion\*(Gt. +Por ejemplo: +.Pp +.Dl color_focus = red +.Pp +Habilitamos o deshabilitamos la opción usando 1 o 0 respectivamente. +.Pp +El archivo soporta las siguientes palabras clave: +.Pp +.Bl -tag -width "title_class_enabledXXX" -offset indent -compact +.It Cm autorun +Inicia una aplicacion en un escritorio en particular al primer inicio. +Definido por el formato ws[]:aplicacion, ej. ws[2]:xterm lanza +xterm en el escritorio 2. +.It Cm color_focus +Color del borde de la ventana en foco. +.It Cm color_unfocus +Color del borde de la ventana fuera de foco. +.It Cm bar_enabled +Habilitar o deshabilitar la barra de estado. +.It Cm bar_border Ns Bq Ar x +Color del borde de la barra de estado en pantalla. +.Ar x . +.It Cm bar_border_width +Setea el grosor de la barra de estado en pixels. +Deshabilitado seteando 0. +.It Cm bar_color Ns Bq Ar x +Color de la ventana de la barra de estado en pantalla. +.Ar x . +.It Cm bar_font_color Ns Bq Ar x +Color de la fuente en la barra de estado en pantalla. +.Ar x . +.It Cm bar_font +Fuente de la barra de estado. +.It Cm bar_action +Scripts externos con populares agregados de información para la barra +de estado, como la vida de la bateria. +.It Cm bar_delay +Frecuencia de actualización, en segundos, de los scripts de la barra de +estado. +.It Cm bar_at_bottom +Puedes posicionar la statusbar en la parte inferior de la pantalla. +.It Cm stack_enabled +Habilitar o deshabilitar mostrar el algoritmo de apilamiento en la barra +de estado. +.It Cm clock_enabled +Habilitar o deshabilitar el reloj en la barra de estado, deshabilitado +por defecto con un 0, para usar el reloj de la barra de estado +(bar_action) +.Pa bar_action +script. +.It Cm dialog_ratio +Algunas aplicaciones tienen ventanas de dialogo muy pequeñas como para +ser usables. Este relación (ratio) es el tamaño de la pantalla, por +ejemplo 0.6 es 60% del tamaño físico de la pantalla. +.It Cm layout +Selecciona una disposicion para usar en el primer inicio. +Definido con el formato +ws[idx]:master_grow:master_add:stack_inc:layout:always_raise:stack_mode, +ej. +ws[2]:-4:0:1:0:horizontal setea el escritorio 2 en horizontal, el stack +principal y reduce 4 puntos agregando una ventana al stack, mientras +mantiene el comportamiento de ventanas flotantes. +Modos posible de stack_mode +.Pa vertical , +.Pa horizontal +and +.Pa fullscreen . +.Pp +Ver +.Pa master_grow , +.Pa master_shrink , +.Pa master_add , +.Pa master_del , +.Pa stack_inc , +.Pa stack_del , +y +.Pa always_raise +para mas informacion. +Tenga en cuenta que las opciones de stack son complicados y tienen +efectos secundarios. +Uno debe familiarizarse con estos comandos antes de experimentar con la +opcion +.Pa layout +.Pp +Esta opcion no necesita un reinicio. +.It Cm region +Acomodar una region personalizada, removiendo cualquier autodeteción de +regiones que ocupe el espacio en la pantalla. +Definiendo el formato screen[]:WIDTHxHEIGHT+X+Y, +e.g.\& screen[1]:800x1200+0+0. +.It Cm term_width +Setear un ancho minimo preferido para la terminal. +Si el valor es mayor que 0, +.Nm +intentará ajustar el tamaño de la fuente de la terminal para mantener +el ancho de la terminal por encima de este número cuando la ventana +cambia de tamaño. +Actualmente solo es soportado por +.Xr xterm 1 +El binario de +.Xr xterm 1 +no debe ser un setuid o setgid, que no sea el que viene por defecto en +la mayoria de los sistemas. +Los usuarios pueden necesitar setear program[term] (ver la sección +.Sx PROGRAMAS +) para usar una copia alternativa del binario de +.Xr xterm 1 +sin el seteo del setgid. +.It Cm title_class_enabled +Habilitar o deshabilitar la clase de ventana en la barre de estado. +Habilitado seteando 1 +.It Cm title_name_enabled +Habilitar o deshabilita el titulo de la ventana en la barra de estado. +Habilitado seteando 1 +.It Cm urgent_enabled +Habilitar o deshabilitar el aviso de urgencia. +Tenga en cuenta que muchos emuladores de terminal requieren de este +parametro habilitado para que funcione. +En xterm, por ejemplo, hay que agregar la siguiente linea +.Pa xterm.urgentOnBell: true +to +.Pa .Xdefaults . +.It Cm window_name_enabled +Habilitar o deshabilita el nombre de la ventana en la barra de estado. +Habilitado seteando 1 +.It Cm verbose_layout +Habilitar o deshabilita la notificacion del area principal y el +stack en la barra de estado. +Habilitado seteandolo a 1. +.It Cm modkey +Cambiar mod key. +Mod1 generalmente es la tecla ALT y Mod4 la tecla de windows en una PC. +.It Cm focus_mode +Usando el valor de +.Pa follow_cursor +puedes hacer que el manejador de ventanas +se enfoque en la ventana cuando el cursor pase por arriba de las mismas o +bien cambiando de estacion de trabajo. +.It Cm disable_border +Remueve el borde de una sola ventana cuando la barra de estado esta desactivada. +.It Cm border_width +Setea el grosor del borde de la ventana en pixels. +Deshabilitar todos los bordes seteandolo a 0. +.It Cm program Ns Bq Ar p +Definir una nueva accion para ejecutar un programa. +.Ar p . +Ver la sección de +.Sx PROGRAMAS +.It Cm bind Ns Bq Ar x +Combinación de teclas para una acción +.Ar x . +Ver la sección +.Sx BINDINGS +.It Cm quirk Ns Bq Ar c:n +Agregar un "quirk" (o forzados) para ventanas con clase +.Ar c +y nombre +.Ar n . +Ver la sección +.Sx QUIRKS +.El +.Pp +Los colores deben ser especificados por la especificación +.Xr XQueryColor 3 +y las fuentes por la especificación +.Xr XQueryFont 3 +.Sh PROGRAMAS +.Nm +te permite definir acciones personales para lanzar los programas que +quieras y luego obligar a la misma con una función de acciones. +Ver la sección +.Sx BINDINGS +.Pp +Los programas por defecto se describen acá: +.Pp +.Bl -tag -width "screenshot_wind" -offset indent -compact +.It Cm term +xterm +.It Cm screenshot_all +screenshot.sh completo +.It Cm screenshot_wind +screenshot.sh por ventana +.It Cm lock +xlock +.It Cm initscr +initscreen.sh +.It Cm menu +dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color +.El +.Pp +Los programas en la configuración personal, se especifican aca: +.Pp +.Dl program[] = [ [... ]] +.Pp +.Aq nombre +es un identificador, no genera conflictos con ninguna accion o palabra +clave, +.Aq progpath +es la ruta al programa, y +.Aq arg +es ninguno o mas de un argumento para el programa. +.Pp +Las siguientes variables de configuracion en +.Nm +(ver +.Sx ARCHIVOS DE CONFIGURACIÓN +), +y pueden ser usadas en los campos de +.Aq arg +como asi tambien sustituidas por valores al momento del inicio de un +programa: +.Pp +.Bl -tag -width "$bar_font_color" -offset indent -compact +.It Cm $bar_border +.It Cm $bar_color +.It Cm $bar_font +.It Cm $bar_font_color +.It Cm $color_focus +.It Cm $color_unfocus +.El +.Pp +Ejemplo: +.Bd -literal -offset indent +program[ff] = /usr/local/bin/firefox http://spectrwm.com.ar/ +bind[ff] = Mod+f # Ahora Mod+F inicia firefox +.Ed +.Pp +Para deshacer lo anterior: +.Bd -literal -offset indent +bind[] = Mod+f +program[ff] = +.Ed +.Sh BINDINGS +.Nm +provee muchas funciones (o acciones) accesibles por medio de la +asignación (bindings) de teclas o el mouse. +.Pp +Las corrientes asignaciones (bindings) del mouse son: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M1 +Enfoco una ventana +.It Cm M-M1 +Muevo una ventana +.It Cm M-M3 +Redimenciono una ventana +.It Cm M-S-M3 +Redimenciono una ventana hasta que quede centrada +.El +.Pp +Las corrientes asignaciones (bindings) de teclas son: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M-S- Ns Aq Cm Return +term +.It Cm M-p +menu +.It Cm M-S-q +quit +.It Cm M-q +restart +.Nm +.It Cm M- Ns Aq Cm Space +cycle_layout +.It Cm M-S- Ns Aq Cm Space +reset_layout +.It Cm M-h +master_shrink +.It Cm M-l +master_grow +.It Cm M-, +master_add +.It Cm M-. +master_del +.It Cm M-S-, +stack_inc +.It Cm M-S-. +stack_del +.It Cm M- Ns Aq Cm Return +swap_main +.It Xo +.Cm M-j , +.Cm M- Ns Aq Cm TAB +.Xc +focus_next +.It Xo +.Cm M-k , +.Cm M-S- Ns Aq Cm TAB +.Xc +focus_prev +.It Cm M-m +focus_main +.It Cm M-S-j +swap_next +.It Cm M-S-k +swap_prev +.It Cm M-b +bar_toggle +.It Cm M-x +wind_del +.It Cm M-S-x +wind_kill +.It Cm M- Ns Aq Ar n +.Ns ws_ Ns Ar n +.It Cm M-S- Ns Aq Ar n +.Ns mvws_ Ns Ar n +.It Cm M- Ns Aq Cm Right +ws_next +.It Cm M- Ns Aq Cm Left +ws_prev +.It Cm M-a +ws_prior +.It Cm M-S- Ns Aq Cm Right +screen_next +.It Cm M-S- Ns Aq Cm Left +screen_prev +.It Cm M-s +screenshot_all +.It Cm M-S-s +screenshot_wind +.It Cm M-S-v +version +.It Cm M-t +float_toggle +.It Cm M-S Aq Cm Delete +lock +.It Cm M-S-i +initscr +.It Cm M-w +iconify +.It Cm M-S-w +uniconify +.It Cm M-S-r +always_raise +.It Cm M-v +button2 +.It Cm M-- +width_shrink +.It Cm M-= +width_grow +.It Cm M-S- +height_shrink +.It Cm M-S-= +height_grow +.It Cm M-[ +move_left +.It Cm M-] +move_right +.It Cm M-S-[ +move_up +.It Cm M-S-] +move_down +.El +.Pp +El nombre de las acciónes descripta a continuación: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm term +Ejecutar una terminal +(ver +.Sx PROGRAMAS +) +.It Cm menu +Menu +(ver +.Sx PROGRAMAS +) +.It Cm quit +Salir +.Nm +.It Cm restart +Reiniciar +.Nm +.It Cm cycle_layout +Disposición de las ventanas +.It Cm reset_layout +Reiniciar la disposición de las ventanas +.It Cm master_shrink +Achicar la region principal +.It Cm master_grow +Agrandar la region principal +.It Cm master_add +Agregar una ventana a la region principal +.It Cm master_del +Quitar una ventana de la region principal +.It Cm stack_inc +Agregar columnas/filas a las pilas +.It Cm stack_del +Quitar columnas/filas de las pilas +.It Cm swap_main +Mover la ventana corriente a la region principal +.It Cm focus_next +Enfocar la proxima ventana en la estación de trabajo +.It Cm focus_prev +Enfocar la anterior ventana en la estación de trabajo +.It Cm focus_main +Enfocar en la ventana principal de la estación de trabajo +.It Cm swap_next +Ejecutar con la siguiente ventana en la estación de trabajo +.It Cm swap_prev +Ejecutar con la anterior ventana en la estación de trabajo +.It Cm bar_toggle +Cambiar la barra de estado en todas las estaciones de trabajo +.It Cm wind_del +Borrar la ventana corriente en la estación de trabajo +.It Cm wind_kill +Destruir la ventana corriente en la estación de trabajo +.It Cm ws_ Ns Ar n +Cambiar entre estaciones de trabajo +.Ar n , +donde +.Ar n +es 1 por 10 +.It Cm mvws_ Ns Ar n +Mover la ventana corriente a una estación de trabajo +.Ar n , +donde +.Ar n +es 1 por 10 +.It Cm ws_next +Cambiar a la proxima estación de trabajo con una ventana en ella +.It Cm ws_prev +Cambiar a la anterior estación de trabajo con una ventana en ella +.It Cm screen_next +Mover el puntero a la proxima region +.It Cm screen_prev +Mover el puntero a la anterior region +.It Cm screenshot_all +Tomar una captura de pantalla de todo la pantalla (si esta habilitado) +(ver +.Sx PROGRAMAS +) +.It Cm screenshot_wind +Tomar una captura de pantalla de la ventana seleccionada (si esta habilitado) +(ver +.Sx PROGRAMAS +) +.It Cm version +Mostrar la version en la barra de estado +.It Cm float_toggle +Mostar la ventana en foco entre las flotantes y acomodadas +.It Cm lock +Bloquear pantalla +(ver +.Sx PROGRAMAS +) +.It Cm initscr +Reiniciar la pantalla +(ver +.Sx PROGRAMAS +) +.It Cm iconify +Minimiza (unmap) la ventana en foco. +.It Cm uniconify +Maximiza (map) la ventana seleccionada por dmenu. +.It Cm always_raise +Cuando se establece las ventanas en cascada se esconden las +ventanas flotantes. +.It Cm button2 +Falsifica el boton del medio del mouse. +.It Cm width_shrink +Reducir el ancho de una ventana flotante. +.It Cm width_grow +Agranda el ancho de una ventana flotante. +.It Cm height_shrink +Reducir la altura de una ventana flotante. +.It Cm height_grow +Agranda la altura de una ventana flotante. +.It Cm move_left +Mueve la ventana flotante un paso a la izquierda. +.It Cm move_right +Mueve la ventana flotante un paso a la derecha. +.It Cm move_up +Mueve la ventana flotante un paso arriba. +.It Cm move_down +Mueve la ventana flotante un paso abajo. +.El +.Pp +Personalizar mapeos (bindings) en el archivo de configuración: +.Pp +.Dl bind[] = +.Pp +.Aq accion +una de las acciones listadas (o ninguna) y +.Aq teclas +una o mas teclas modificadas (puede ser ninguna tambien) +(MOD, Mod1, Shift, etc.) y una o mas teclas normales +(b, barra espaciadora, etc.), separadas por un "+". +Por ejemplo: +.Bd -literal -offset indent +bind[reset] = Mod4+q # combinación Tecla de Windows + q reinicia +bind[] = Mod1+q # des-hace la combinación Alt + q +.Ed +.Pp +Multiples combinaciones de teclas pueden hacer lo mismo. +.Sh QUIRKS +.Nm +te da "quirks" (o forzados) ventanas que tienen que ser tratas de manera especial, +como por ejemplo, popups, aplicaciones de pantalla completa, etc. +.Pp +Los "quirks" (o forzados) por defecto son: +.Pp +.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact +.It Firefox\-bin:firefox\-bin +TRANSSZ +.It Firefox:Dialog +FLOAT +.It Gimp:gimp +FLOAT + ANYWHERE +.It MPlayer:xv +FLOAT + FULLSCREEN +.It OpenOffice.org 2.4:VCLSalFrame +FLOAT +.It OpenOffice.org 3.1:VCLSalFrame +FLOAT +.It pcb:pcb +FLOAT +.It xine:Xine Window +FLOAT + ANYWHERE +.It xine:xine Panel +FLOAT + ANYWHERE +.It xine:xine Video Fullscreen Window +FULLSCREEN + FLOAT +.It Xitk:Xitk Combo +FLOAT + ANYWHERE +.It Xitk:Xine Window +FLOAT + ANYWHERE +.It XTerm:xterm +XTERM_FONTADJ +.El +.Pp +Los "quirks" (o forzados) se describen a continuación: +.Pp +.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact +.It FLOAT +Esta ventana no tiene que ser acomodada, pero le permitimos flotar libremente. +.It TRANSSZ +Ajusta el tamaño de las ventanas transitorias que son demasiado pequeñas utilizando dialog_ratio +(ver +.Sx ARCHIVOS DE CONFIGURACIÓN ) . +.It ANYWHERE +Permite que la ventana se ponga donde quiera. +.It XTERM_FONTADJ +Ajusta las fuentes de xterm cuando se redimenciona. +.It FULLSCREEN +Quita el borde para permitir las ventanas en pantalla completa. +.It FOCUSPREV +El enfoque de salida fuerza la solicitud de aplicacisn que +anteriormente se centraba en la aplicacion anterior del stack. +.El +.Pp +Las configuraciones de "quirks" (o forzados) en el archivo de configuración se ven a continuación: +.Pp +.Dl quirk[:] = [ + ... ] +.Pp +.Aq clases +y +.Aq nombre +especifica la ventana en la cual el "quirk(s)" (o forzados) se aplica, y +.Aq quirk +es uno de los "quirks" (o forzados) de la lista. +Por ejemplo: +.Bd -literal -offset indent +quirk[MPlayer:xv] = FLOAT + FULLSCREEN # dejamos que mplayer funcione libremente +quirk[pcb:pcb] = NONE # borramos el quirk existente +.Ed +.Pp +Podes obtener +.Aq clases +y +.Aq nombre +corriendo el programa xprop(1) y luego clickear en la ventana que quieras. +En el proximo ejemplo, podremos verlo en acción con una ventana de Firefox: +.Bd -literal -offset indent +$ xprop | grep WM_CLASS +WM_CLASS(STRING) = "Navigator", "Firefox" +.Ed +.Sh EWMH +.Nm +parcialmente implementa los Consejos de ventana extendido Manager (EWMH) especificacion. +Esto permite el control de las ventanas, asi como +.Nm +si a partir de scripts y programas externos. Esto se logra mediante +.Nm +responder a ciertos eventos ClientMessage. Desde la terminal de estos eventos +se puede enviar facilmente el uso de herramientas tales como +.Xr wmctrl 1 +y +.Xr xdotool 1 . +para el +formato real de estos eventos ClientMessage, consulte la especificacion EWMH. +.Pp +La Identificacion de la ventana actualmente enfocada se almacena en el _NET_ACTIVE_WINDOW +propiedad de la ventana raiz. Esto puede ser usado por ejemplo para recuperar el +titulo de la ventana activa con +.Xr xprop 1 +y +.Xr grep 1 : +.Bd -literal -offset indent +$ WINDOWID=`xprop \-root _NET_ACTIVE_WINDOW | grep \-o "0x.*"` +$ xprop \-id $WINDOWID WM_NAME | grep \-o "\\".*\\"" +.Ed +.Pp +Una ventana se puede enfocar mediante el envio de un mensaje del cliente _NET_ACTIVE_WINDOW +a la ventana principal. Por ejemplo, usando +.Xr wmctrl 1 +para enviar el mensaje +(suponiendo que 0x4a0000b es el ID de la ventana para ser especifico): +.Bd -literal -offset indent +$ wmctrl \-i \-a 0x4a0000b +.Ed +.Pp +Ventanas se pueden cerrar mediante el envmo de un mensaje del cliente _NET_CLOSE_WINDOW +a la ventana principal. Por ejemplo, usando +.Xr wmctrl 1 +para enviar el mensaje +(suponiendo que 0x4a0000b es el ID de la ventana se cierre): +.Bd -literal -offset indent +$ wmctrl \-i \-c 0x4a0000b +.Ed +.Pp +Las ventanas se pueden flotar y flotar sin-mediante la adicion o eliminacion de la +_NET_WM_STATE_ABOVE atom desde _NET_WM_STATE la propiedad de la ventana +Esto se puede lograr mediante el envio de un mensaje a los clientes _NET_WM_STATE +raiz de la ventana. Por ejemplo, el siguiente cambia el estado de la flota. +.Xr wmctrl 1 +para enviar el mensaje (suponiendo que 0x4a0000b es el ID de la ventana flotante +o no-flotante): +.Bd -literal -offset indent +$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE +.Ed +.Pp +Ventanas flotantes tambien se puede cambiar el tamano y movido por el envio de un +_NET_MOVERESIZE_WINDOW Mensaje del cliente de la ventana raiz. Por ejemplo, +uso +.Xr wmctrl 1 +para enviar el mensaje (suponiendo que 0x4a0000b es el ID de +la ventana a redimensionar / mover): +.Bd -literal -offset indent +$ wmctrl \-i \-r 0x4a0000b \-e 0,100,50,640,480 +.Ed +.Pp +Esto mueve la ventana de (100,50) y cambia el tamaqo a 640x480. +.Pp +Todos los eventos _NET_MOVERESIZE_WINDOW recibido por las ventanas apiladas se ignoran. +.Pp +.Sh SIGNALS +Enviando +.Nm +una senal de HUP reinicia spectrwm. +.Pp +.Sh ARCHIVOS +.Bl -tag -width "/etc/spectrwm.confXXX" -compact +.It Pa ~/.spectrwm.conf +.Nm +archivo de configuración especifico del usuario. +.It Pa /etc/spectrwm.conf +.Nm +configuraciones globales. +.El +.Sh HISTORIA +.Nm +fue inspirado en xmonad y dwm. +.Sh AUTORES +.An -nosplit +.Pp +.Nm +fue escrito por +.An Marco Peereboom Aq marco@peereboom.us , +.An Ryan Thomas McBride Aq mcbride@countersiege.com +and +.An Darrin Chandler Aq dwchandler@stilyagin.com . +.Sh BUGS +Actualmente el menu, se llama con +.Cm M-p , +depende de dmenu. diff --git a/spectrwm_es.conf b/spectrwm_es.conf new file mode 100644 index 0000000..b585381 --- /dev/null +++ b/spectrwm_es.conf @@ -0,0 +1,74 @@ +# Key bindings for Spanish (es) keyboards +# unbind with: bind[] = +bind[cycle_layout] = MOD+space +bind[flip_layout] = MOD+Shift+backslash +bind[stack_reset] = MOD+Shift+space +bind[master_shrink] = MOD+h +bind[master_grow] = MOD+l +bind[master_add] = MOD+comma +bind[master_del] = MOD+period +bind[stack_inc] = MOD+Shift+comma +bind[stack_dec] = MOD+Shift+period +bind[swap_main] = MOD+Return +bind[focus_next] = MOD+j +bind[focus_prev] = MOD+k +bind[swap_next] = MOD+Shift+j +bind[swap_prev] = MOD+Shift+k +bind[spawn_term] = MOD+Shift+Return +bind[menu] = MOD+p +bind[quit] = MOD+Shift+q +bind[restart] = MOD+q +bind[focus_main] = MOD+m +bind[ws_1] = MOD+1 +bind[ws_2] = MOD+2 +bind[ws_3] = MOD+3 +bind[ws_4] = MOD+4 +bind[ws_5] = MOD+5 +bind[ws_6] = MOD+6 +bind[ws_7] = MOD+7 +bind[ws_8] = MOD+8 +bind[ws_9] = MOD+9 +bind[ws_10] = MOD+0 +bind[ws_next] = MOD+Right +bind[ws_prev] = MOD+Left +bind[ws_next_all] = MOD+Up +bind[ws_prev_all] = MOD+Down +bind[ws_prior] = MOD+a +bind[screen_next] = MOD+Shift+Right +bind[screen_prev] = MOD+Shift+Left +bind[mvws_1] = MOD+Shift+1 +bind[mvws_2] = MOD+Shift+2 +bind[mvws_3] = MOD+Shift+3 +bind[mvws_4] = MOD+Shift+4 +bind[mvws_5] = MOD+Shift+5 +bind[mvws_6] = MOD+Shift+6 +bind[mvws_7] = MOD+Shift+7 +bind[mvws_8] = MOD+Shift+8 +bind[mvws_9] = MOD+Shift+9 +bind[mvws_10] = MOD+Shift+0 +bind[bar_toggle] = MOD+b +bind[focus_next] = MOD+Tab +bind[focus_prev] = MOD+Shift+Tab +bind[wind_kill] = MOD+Shift+x +bind[wind_del] = MOD+x +bind[screenshot_all] = MOD+s +bind[screenshot_wind] = MOD+Shift+s +bind[float_toggle] = MOD+t +bind[version] = MOD+Shift+v +bind[lock] = MOD+Shift+Delete +bind[initscr] = MOD+Shift+i +bind[iconify] = MOD+w +bind[uniconify] = MOD+Shift+w +bind[raise_toggle] = MOD+Shift+r +bind[button2] = MOD+v +bind[width_shrink] = MOD+apostrophe +bind[width_grow] = MOD+exclamdown +bind[height_shrink] = MOD+Shift+apostrophe +bind[height_grow] = MOD+Shift+exclamdown +bind[move_left] = MOD+dead_grave +bind[move_right] = MOD+plus +bind[move_up] = MOD+Shift+dead_grave +bind[move_down] = MOD+Shift+plus +bind[name_workspace] = MOD+Shift+slash +bind[search_workspace] = MOD+slash +bind[search_win] = MOD+f diff --git a/spectrwm_fr.conf b/spectrwm_fr.conf new file mode 100644 index 0000000..d56aabb --- /dev/null +++ b/spectrwm_fr.conf @@ -0,0 +1,74 @@ +# Key bindings for French (fr) keyboards +# unbind with: bind[] = +bind[cycle_layout] = MOD+space +bind[flip_layout] = MOD+Shift+backslash +bind[stack_reset] = MOD+Shift+space +bind[master_shrink] = MOD+h +bind[master_grow] = MOD+l +bind[master_add] = MOD+comma +bind[master_del] = MOD+semicolon +bind[stack_inc] = MOD+Shift+comma +bind[stack_dec] = MOD+Shift+semicolon +bind[swap_main] = MOD+Return +bind[focus_next] = MOD+j +bind[focus_prev] = MOD+k +bind[swap_next] = MOD+Shift+j +bind[swap_prev] = MOD+Shift+k +bind[spawn_term] = MOD+Shift+Return +bind[menu] = MOD+p +bind[quit] = MOD+Shift+q +bind[restart] = MOD+q +bind[focus_main] = MOD+m +bind[ws_1] = MOD+ampersand +bind[ws_2] = MOD+eacute +bind[ws_3] = MOD+quotedbl +bind[ws_4] = MOD+apostrophe +bind[ws_5] = MOD+parenleft +bind[ws_6] = MOD+hyphen +bind[ws_7] = MOD+egrave +bind[ws_8] = MOD+underscore +bind[ws_9] = MOD+ccedilla +bind[ws_10] = MOD+agrave +bind[ws_next] = MOD+Right +bind[ws_prev] = MOD+Left +bind[ws_next_all] = MOD+Up +bind[ws_prev_all] = MOD+Down +bind[ws_prior] = MOD+a +bind[screen_next] = MOD+Shift+Right +bind[screen_prev] = MOD+Shift+Left +bind[mvws_1] = MOD+Shift+ampersand +bind[mvws_2] = MOD+Shift+eacute +bind[mvws_3] = MOD+Shift+quotedbl +bind[mvws_4] = MOD+Shift+apostrophe +bind[mvws_5] = MOD+Shift+parenleft +bind[mvws_6] = MOD+Shift+hyphen +bind[mvws_7] = MOD+Shift+egrave +bind[mvws_8] = MOD+Shift+underscore +bind[mvws_9] = MOD+Shift+ccedilla +bind[mvws_10] = MOD+Shift+agrave +bind[bar_toggle] = MOD+b +bind[focus_next] = MOD+Tab +bind[focus_prev] = MOD+Shift+Tab +bind[wind_kill] = MOD+Shift+x +bind[wind_del] = MOD+x +bind[screenshot_all] = MOD+s +bind[screenshot_wind] = MOD+Shift+s +bind[float_toggle] = MOD+t +bind[version] = MOD+Shift+v +bind[lock] = MOD+Shift+Delete +bind[initscr] = MOD+Shift+i +bind[iconify] = MOD+w +bind[uniconify] = MOD+Shift+w +bind[raise_toggle] = MOD+Shift+r +bind[button2] = MOD+v +bind[width_shrink] = MOD+minus +bind[width_grow] = MOD+equal +bind[height_shrink] = MOD+Shift+minus +bind[height_grow] = MOD+Shift+equal +bind[move_left] = MOD+ugrave +bind[move_right] = MOD+asterisk +bind[move_up] = MOD+Shift+ugrave +bind[move_down] = MOD+Shift+asterisk +bind[name_workspace] = MOD+Shift+slash +bind[search_workspace] = MOD+slash +bind[search_win] = MOD+f diff --git a/spectrwm_fr_ch.conf b/spectrwm_fr_ch.conf new file mode 100644 index 0000000..f78c5bb --- /dev/null +++ b/spectrwm_fr_ch.conf @@ -0,0 +1,74 @@ +# Key bindings for Swiss French (FR_CH) keyboards +# unbind with: bind[] = +bind[cycle_layout] = MOD+space +bind[flip_layout] = MOD+Shift+backslash +bind[stack_reset] = MOD+Shift+space +bind[master_shrink] = MOD+h +bind[master_grow] = MOD+l +bind[master_add] = MOD+comma +bind[master_del] = MOD+period +bind[stack_inc] = MOD+Shift+comma +bind[stack_dec] = MOD+Shift+period +bind[swap_main] = MOD+Return +bind[focus_next] = MOD+j +bind[focus_prev] = MOD+k +bind[swap_next] = MOD+Shift+j +bind[swap_prev] = MOD+Shift+k +bind[spawn_term] = MOD+Shift+Return +bind[menu] = MOD+p +bind[quit] = MOD+Shift+q +bind[restart] = MOD+q +bind[focus_main] = MOD+m +bind[ws_1] = MOD+1 +bind[ws_2] = MOD+2 +bind[ws_3] = MOD+3 +bind[ws_4] = MOD+4 +bind[ws_5] = MOD+5 +bind[ws_6] = MOD+6 +bind[ws_7] = MOD+7 +bind[ws_8] = MOD+8 +bind[ws_9] = MOD+9 +bind[ws_10] = MOD+0 +bind[ws_next] = MOD+Right +bind[ws_prev] = MOD+Left +bind[ws_next_all] = MOD+Up +bind[ws_prev_all] = MOD+Down +bind[ws_prior] = MOD+a +bind[screen_next] = MOD+Shift+Right +bind[screen_prev] = MOD+Shift+Left +bind[mvws_1] = MOD+Shift+1 +bind[mvws_2] = MOD+Shift+2 +bind[mvws_3] = MOD+Shift+3 +bind[mvws_4] = MOD+Shift+4 +bind[mvws_5] = MOD+Shift+5 +bind[mvws_6] = MOD+Shift+6 +bind[mvws_7] = MOD+Shift+7 +bind[mvws_8] = MOD+Shift+8 +bind[mvws_9] = MOD+Shift+9 +bind[mvws_10] = MOD+Shift+0 +bind[bar_toggle] = MOD+b +bind[focus_next] = MOD+Tab +bind[focus_prev] = MOD+Shift+Tab +bind[wind_kill] = MOD+Shift+x +bind[wind_del] = MOD+x +bind[screenshot_all] = MOD+s +bind[screenshot_wind] = MOD+Shift+s +bind[float_toggle] = MOD+t +bind[version] = MOD+Shift+v +bind[lock] = MOD+Shift+Delete +bind[initscr] = MOD+Shift+i +bind[iconify] = MOD+w +bind[uniconify] = MOD+Shift+w +bind[raise_toggle] = MOD+Shift+r +bind[button2] = MOD+v +bind[width_shrink] = MOD+minus +bind[width_grow] = MOD+egrave +bind[height_shrink] = MOD+Shift+minus +bind[height_grow] = MOD+Shift+egrave +bind[move_left] = MOD+eacute +bind[move_right] = MOD+agrave +bind[move_up] = MOD+Shift+eacute +bind[move_down] = MOD+Shift+agrave +bind[name_workspace] = MOD+Shift+apostrophe +bind[search_workspace] = MOD+apostrophe +bind[search_win] = MOD+f diff --git a/spectrwm_it.1 b/spectrwm_it.1 new file mode 100644 index 0000000..09d7356 --- /dev/null +++ b/spectrwm_it.1 @@ -0,0 +1,755 @@ +.\" Copyright (c) 2009 Marco Peereboom +.\" Copyright (c) 2009 Darrin Chandler +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: September 15 2011 $ +.Dt SPECTRWM 1 +.Os +.Sh NOME +.Nm spectrwm +.Nd gestore di finestre per X11 +.Sh SINTASSI +.Nm spectrwm +.Sh DESCRIZIONE +.Nm +? un gestore di finestre minimale che cerca di stare in disparte, in modo +che il prezioso spazio sullo schermo possa essere usato per cose pi? +importanti. Hai dei default sensati e non costringe l'utente ad imparare +un linguaggio di programmazione per configurarlo. ? stato scritto dagli +hacker per gli hacker e cerca di essere piccolo, compatto e veloce. +.Pp +Quando +.Nm +viene avviato, legge le impostazioni presenti nel file di configurazione +.Pa spectrwm.conf . +Vedere la sezione +.Sx FILE DI CONFIGURAZIONE +pi? sotto. +.Pp +In questa pagina di manuale viene usata la seguente notazione: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Cm M +Meta +.It Cm S +Shift +.It Aq Cm Nome +Tasto nome +.It Cm M1 +Tasto 1 (sinistro) del mouse +.It Cm M3 +Tasto 3 (destro) del mouse +.El +.Pp +.Nm +? molto semplice da usare. La maggior parte delle operazioni vengono +svolte usando combinazioni di tasti sulla tastiera o sul mouse. +Vedere la sezione +.Sx SCORCIATOIE +pi? sotto per i default e le possibilit? di personalizzazione. +.Sh FILE DI CONFIGURAZIONE +.Nm +prova per prima cosa ad aprire il file di configurazione personale +dell'utente, +.Pa ~/.spectrwm.conf . +Se il file in questione non ? disponibile, prova ad usare il file di +configurazione globale +.Pa /etc/spectrwm.conf . +.Pp +Il formato di questo file ? \*(Ltchiave\*(Gt = \*(Ltvalore\*(Gt. +Per esempio: +.Pp +.Dl color_focus = red +.Pp +Per abilitare o disabilitare un'opzione, usare i valori 1 o 0 +rispettivamente. +.Pp +Il file supporta le seguenti chiavi: +.Pp +.Bl -tag -width "title_class_enabledXXX" -offset indent -compact +.It Cm autorun +Esegue un'applicazione nel workspace specificato all'avvio. +Definito nel formato ws[]:applicazione, eg. ws[2]:xterm esegue un +xterm nell'area di lavoro 2. +.It Cm color_focus +Colore del bordo della finestra che ha il focus. +.It Cm color_unfocus +Colore del bordo delle finestre che non hanno il focus. +.It Cm bar_enabled +Abilita o disabilita la barra di stato. +.It Cm bar_border Ns Bq Ar x +Colore del bordo della barra di stato nello schermo +.Ar x . +.It Cm bar_border_width +Spessore del bordo attorno alla barra di stato in pixel. Il bordo +pu? essere disabilitato usando il valore 0. +.It Cm bar_color Ns Bq Ar x +Colore della barra di stato nello schermo +.Ar x . +.It Cm bar_font_color Ns Bq Ar x +Colore del testo della barra di stato nello schermo +.Ar x . +.It Cm bar_font +Font della barra di stato. +.It Cm bar_action +Script esterno che aggiunge informazioni come la carica della batteria alla +barra di stato. +.It Cm bar_delay +Frequenza di aggiornamento, in secondi, dello script esterno che aggiunge +informazioni alla barra di stato. +.It Cm bar_at_bottom +Posiziona la barra di stato sul fondo dello schermo anzich? in cima. +.It Cm stack_enabled +Abilita o disabilita la visualizzazione dell'algoritmo di stacking +corrente nella barra di stato. +.It Cm clock_enabled +Abilita o disabilita l'orologio nella barra di stato. Se disabilitato, +usando il valore 0, ? possibile usare un orologio personalizzato nello +script specificato in +.Pa bar_action . +.It Cm dialog_ratio +Alcune applicazioni hanno finestre di dialogo troppo piccole per risultare +utili. Questa ? la percentuale dello schermo che verr? usata per le finestre +di dialogo: ad esempio, 0.6 indica il 60% della dimensione fisica dello +schermo. +.It Cm layout +Layout da utilizzare all'avvio. Definito nel formato +ws[]:master_grow:master_add:stack_inc:layout:always_raise:stack_mode, +eg. ws[2]:-4:0:1:0:horizontal assegna il layout orizzontale all'area di +lavoro 2, riduce l'area principale di 4 unit?, aggiunge una finestra allo +stack e mantiene il comportamento predefinito per quanto riguarda le +finestre floating. +I valori possibili per stack_mode sono +.Pa vertical , +.Pa horizontal +e +.Pa fullscreen . +.Pp +Fare riferimento a +.Pa master_grow , +.Pa master_shrink , +.Pa master_add , +.Pa master_del , +.Pa stack_inc , +.Pa stack_del +e +.Pa always_raise +per ulteriori informazioni. +Queste impostazioni sono complesse e hanno effetti secondari; ? opportuno +familiarizzare con questi comandi prima di modificare l'opzione +.Pa layout . +.Pp +Questa impostazione non viene applicata dopo il restart. +.It Cm region +Alloca una regione personalizzata, rimuovendo qualsiasi regione +automaticamente rilevata stia occupando lo stesso spazio sullo schermo. +Definita nel formato screen[]:LARGHEZZAxALTEZZA+X+Y, ad esempio +\& screen[1]:800x1200+0+0. +.Pp +Per fare s? che pi? monitor vengano considerati come una singola entit? +? sufficiente creare una regione sufficientemente grande da contenerli, +eg. screen[1]:2048x760+0+0 unisce due monitor con risoluzione 1024x768 +posizionati uno di fianco all'altro. +.It Cm term_width +Imposta la dimensione minima preferita per il terminale. Se questo valore +? maggiore di 0, +.Nm +cercher? di riaggiustare la dimensione del testo nel terminale in modo che +la larghezza del terminale rimanga sopra il valore quando la finestra +viene ridimensionata. Al momento solo +.Xr xterm 1 +? supportato. Il binario di +.Xr xterm 1 +deve essere setuid o setgid perch? questo funzioni: nella maggior parte dei +sistemi, questo ? il default. L'utente potrebbe voler impostare +program[term] (vedere la sezione +.Sx PROGRAMMI +pi? sotto) per usare una seconda copia del binario di +.Xr xterm 1 +che non abbia il bit setgid impostato. +.It Cm title_class_enabled +Abilita o disabilita la visualizzazione della classe della finestra nella +barra di stato. Impostare a 1 per abilitare. +.It Cm title_name_enabled +Abilita o disabilita la visualizzazione del titolo della finestra nella +barra di stato. Impostare a 1 per abilitare. +.It Cm urgent_enabled +Abilita o disabilita l'hint "urgente". +In molti emulatori di terminale, il supporto deve essere abilitato +separatamente: per xterm, ad esempio, ? necessario aggiungere la riga +.Pa xterm.urgentOnBell: true +al file +.Pa .Xdefaults . +.It Cm window_name_enabled +Abilita o disabilita la visualizzazione del nome della finestra nella +barra di stato. Impostare a 1 per abilitare. +.It Cm verbose_layout +Abilita o disabilita la visualizzazione dei valori correnti di master e +stack nella barra di stato. Impostare a 1 per abilitare. +.It Cm modkey +Cambia il tasto modificatore. +Solitamente Mod1 ? il tasto ALT e Mod4 ? il tasto Windows su un PC. +.It Cm focus_mode +Se viene usato il valore +.Pa follow_cursor , +il gestore di finestre dar? il focus alla finestra sotto il puntatore +quando si cambia area di lavoro o si creano finestre. +.It Cm disable_border +Rimuovi il bordo dalle finestre se la barra di stato ? nascosta e c'? +una sola finestra sullo schermo. +.It Cm border_width +Spessore del bordo delle finestre in pixel. Il valore 0 disabilita il bordo. +.It Cm program Ns Bq Ar p +Definisce una nuova azione per lanciare il programma +.Ar p . +Vedere la sezione +.Sx PROGRAMMI +pi? sotto. +.It Cm bind Ns Bq Ar x +Assegna una combinazione di tasti all'azione +.Ar x . +Vedere la sezione +.Sx SCORCIATOIE +pi? sotto. +.It Cm quirk Ns Bq Ar c:n +Aggiunge un "quirk" per le finestre di classe +.Ar c +e nome +.Ar n . +Vedere la sezione +.Sx QUIRKS +pi? sotto. +.El +.Pp +I colori devono essere specificati nel formato usato da +.Xr XQueryColor 3 +e i font in quello usato da +.Xr XQueryFont 3 . +.Pp +Per avere una lista dei font disponibili sul proprio sistema utilizzare +.Xr fc-list 1 +o +.Xr xlsfonts 1 . +L'applicazione +.Xr xfontsel 1 +? utile per visualizzare la X Logical Font Description ("XLFD") usata per +la chiave +.Pa bar_font . +.Sh PROGRAMMI +.Nm +consente la definizione di azioni personalizzate per lanciare programmi di +propria scelta, che possono essere assegnate a combinazioni di tasti nello +stesso modo in cui ? possibile farlo con le azioni predefinite. +Vedere la sezione +.Sx SCORCIATOIE +pi? sotto. +.Pp +I programmi di default sono descritte qui sotto: +.Pp +.Bl -tag -width "screenshot_wind" -offset indent -compact +.It Cm term +xterm +.It Cm screenshot_all +screenshot.sh full +.It Cm screenshot_wind +screenshot.sh window +.It Cm lock +xlock +.It Cm initscr +initscreen.sh +.It Cm menu +dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color +.El +.Pp +I programmi personalizzati vengono specificati con la seguente sintassi: +.Pp +.Dl program[] = [ [... ]] +.Pp +.Aq nome +? un qualsiasi identificatore che non va in conflitto con un'azione +predefinita o una chiave, +.Aq percorso +? il programma desiderato, e +.Aq arg +sono zero o pi? argomenti da passare al programma. +.Pp +Le seguenti variabili rappresentano valori impostabili in +.Nm +(vedere la sezione +.Sx FILE DI CONFIGURAZIONE +sopra), e possono essere usati nel campo +.Aq arg +dove saranno sostituite con il valore al momento del lancio del programma: +.Pp +.Bl -tag -width "$bar_font_color" -offset indent -compact +.It Cm $bar_border +.It Cm $bar_color +.It Cm $bar_font +.It Cm $bar_font_color +.It Cm $color_focus +.It Cm $color_unfocus +.El +.Pp +Esempio: +.Bd -literal -offset indent +program[ff] = /usr/local/bin/firefox http://spectrwm.org/ +bind[ff] = Mod+f # adesso Mod+F lancia firefox +.Ed +.Pp +Per eliminare la combinazione precedente: +.Bd -literal -offset indent +bind[] = Mod+f +program[ff] = +.Ed +.Pp +.Sh SCORCIATOIE +.Nm +fornisce molte funzioni (o azioni) accessibili tramite combinazioni di +tasti sul mouse o sulla tastiera. +.Pp +Le scorciatoie assegnate al mouse sono: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M1 +D? focus alla finestra +.It Cm M-M1 +Muove la finestra +.It Cm M-M3 +Ridimensiona la finestra +.It Cm M-S-M3 +Ridimensiona la finestra mantenendola centrata +.El +.Pp +Le scorciatoie da tastiera di default sono: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M-S- Ns Aq Cm Return +term +.It Cm M-p +menu +.It Cm M-S-q +quit +.It Cm M-q +restart +.It Cm M- Ns Aq Cm Space +cycle_layout +.It Cm M-S- Ns Aq Cm Space +reset_layout +.It Cm M-h +master_shrink +.It Cm M-l +master_grow +.It Cm M-, +master_add +.It Cm M-. +master_del +.It Cm M-S-, +stack_inc +.It Cm M-S-. +stack_del +.It Cm M- Ns Aq Cm Return +swap_main +.It Xo +.Cm M-j , +.Cm M- Ns Aq Cm TAB +.Xc +focus_next +.It Xo +.Cm M-k , +.Cm M-S- Ns Aq Cm TAB +.Xc +focus_prev +.It Cm M-m +focus_main +.It Cm M-S-j +swap_next +.It Cm M-S-k +swap_prev +.It Cm M-b +bar_toggle +.It Cm M-x +wind_del +.It Cm M-S-x +wind_kill +.It Cm M- Ns Aq Ar n +.Ns ws_ Ns Ar n +.It Cm M-S- Ns Aq Ar n +.Ns mvws_ Ns Ar n +.It Cm M- Ns Aq Cm Right +ws_next +.It Cm M- Ns Aq Cm Left +ws_prev +.It Cm M-a +ws_prior +.It Cm M-S- Ns Aq Cm Right +screen_next +.It Cm M-S- Ns Aq Cm Left +screen_prev +.It Cm M-s +screenshot_all +.It Cm M-S-s +screenshot_wind +.It Cm M-S-v +version +.It Cm M-t +float_toggle +.It Cm M-S Aq Cm Delete +lock +.It Cm M-S-i +initscr +.It Cm M-w +iconify +.It Cm M-S-w +uniconify +.It Cm M-S-r +always_raise +.It Cm M-v +button2 +.El +.Pp +I nomi delle azioni e le relative descrizioni sono le seguenti: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm term +Lancia un nuovo terminale +(vedi +.Sx PROGRAMMI +pi? in alto). +.It Cm menu +Menu +(vedi +.Sx PROGRAMMI +pi? in alto). +.It Cm quit +Chiude +.Nm . +.It Cm restart +Riavvia +.Nm . +.It Cm cycle_layout +Cambia layout. +.It Cm reset_layout +Re-inizializza il layout. +.It Cm master_shrink +Restringe l'area principale. +.It Cm master_grow +Allarga l'area principale. +.It Cm master_add +Aggiunge finestre all'area principale. +.It Cm master_del +Rimuove finestre dall'area principale. +.It Cm stack_inc +Aggiunge righe/colonne all'area di stacking. +.It Cm stack_del +Rimuove righe/colonne dall'area di stacking. +.It Cm swap_main +Muove la finestra corrente nell'area principale. +.It Cm focus_next +D? il focus alla finestra successiva. +.It Cm focus_prev +D? il focus alla finestra precedente. +.It Cm focus_main +D? il focus alla finestra principale. +.It Cm swap_next +Scambia con la finestra successiva dell'area di lavoro. +.It Cm swap_prev +Scambia con la finestra precedente dell'area di lavoro. +.It Cm bar_toggle +Mostra/nascondi la barra di stato da tutte le aree di lavoro. +.It Cm wind_del +Chiude la finestra corrente. +.It Cm wind_kill +Distrugge la finestra corrente. +.It Cm ws_ Ns Ar n +Passa all'area di lavoro +.Ar n , +dove +.Ar n +? compreso tra 1 e 10. +.It Cm mvws_ Ns Ar n +Sposta la finestra corrente nell'area di lavoro +.Ar n , +dove +.Ar n +? compreso tra 1 e 10. +.It Cm ws_next +Passa all'area di lavoro non vuota successiva. +.It Cm ws_prev +Passa all'area di lavoro non vuota precedente. +.It Cm ws_prior +Passa all'ultima area di lavoro visitata. +.It Cm screen_next +Sposta il puntatore nella regione successiva. +.It Cm screen_prev +Sposta il puntatore nella regione precedente. +.It Cm screenshot_all +Cattura uno screenshot dell'intero schermo, se abilitato (vedere la sezione +.Sx PROGRAMMI +pi? in alto). +.It Cm screenshot_wind +Cattura uno screenshot di una singola finestra, se abilitato (vedere la +sezione +.Sx PROGRAMMI +pi? in alto). +.It Cm version +Abilita/disabilita il numero di versione nella barra di stato. +.It Cm float_toggle +Passa la finestra che ha il focus da floating a tiled. +.It Cm lock +Blocca lo schermo (vedere la sezione +.Sx PROGRAMMI +pi? in alto). +.It Cm initscr +Re-inizializza gli schermi fisici (vedere la sezione +.Sx PROGRAMMI +pi? in alto). +.It Cm iconify +Minimizza (unmap) la finesta che ha il focus. +.It Cm uniconify +Massimizza (map) la finestra selezionata tramite dmenu. +.It Cm always_raise +Quando ? abilitato, le finestre floating possono essere oscurate da +finestre tiled. +.It Cm button2 +Simula la pressione del tasto centrale del mouse. +.El +.Pp +Le scorciatoie personalizzate sono specificate nel file di configurazione +come segue: +.Pp +.Dl bind[] = +.Pp +.Aq azione +? una delle azioni elencate sopra (oppure nulla) e +.Aq tasti +? dato da zero o pi? modificatori (MOD, Mod1, Shift, ecc.) e uno o pi? +tasti normali (b, space, ecc.), separati da "+". +Per esempio: +.Bd -literal -offset indent +bind[reset] = Mod4+q # assegna reset ai tasti Windows + q +bind[] = Mod1+q # rimuovi l'assegnazione di Alt + q +.Ed +.Pp +Pi? combinazioni di tasti possono essere assegnate alla stessa azione. +.Sh QUIRK +.Nm +fornisce la possibilit? di specificare dei "quirk" per la gestione di +finestre che devono subire un trattamento speciale da un gestore di finestre +tiling, come ad esempio alcune finestre di dialogo e applicazioni a +schermo intero. +.Pp +I quirk abilitati di default sono elencati qui sotto: +.Pp +.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact +.It Firefox\-bin:firefox\-bin +TRANSSZ +.It Firefox:Dialog +FLOAT +.It Gimp:gimp +FLOAT + ANYWHERE +.It MPlayer:xv +FLOAT + FULLSCREEN + FOCUSPREV +.It OpenOffice.org 2.4:VCLSalFrame +FLOAT +.It OpenOffice.org 3.1:VCLSalFrame +FLOAT +.It pcb:pcb +FLOAT +.It xine:Xine Window +FLOAT + ANYWHERE +.It xine:xine Panel +FLOAT + ANYWHERE +.It xine:xine Video Fullscreen Window +FULLSCREEN + FLOAT +.It Xitk:Xitk Combo +FLOAT + ANYWHERE +.It Xitk:Xine Window +FLOAT + ANYWHERE +.It XTerm:xterm +XTERM_FONTADJ +.El +.Pp +I quirk sono descritti qui sotto: +.Pp +.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact +.It FLOAT +Questa finestra deve essere lasciata libera di muoversi (float). +.It TRANSSZ +Aggiusta la dimensione delle finestre troppo piccole usando dialog_ratio +(vedere +.Sx FILE DI CONFIGURAZIONE ) . +.It ANYWHERE +Consente alla finestra di decidere da sola dove posizionarsi. +.It XTERM_FONTADJ +Ridimensiona il font di xterm quando viene ridimensionata la finestra. +.It FULLSCREEN +Rimuove i bordi, consentendo alla finestra di usare l'intera dimensione +dello schermo. +.It FOCUSPREV +Quando la finestra viene chiusa, d? il focus alla finestra che aveva il +focus precedente anzich? all'applicazione precedente nello stack. +.El +.Pp +I quirk personalizzati vanno specificati nel file di configurazione come +segue: +.Pp +.Dl quirk[:] = [ + ... ] +.Pp +.Aq classe +e +.Aq nome +specificano a quali finestre i quirk vanno applicati, e +.Aq quirk +? uno dei quirk presente nella lista sopra. +Ad esempio: +.Bd -literal -offset indent +quirk[MPlayer:xv] = FLOAT + FULLSCREEN + FOCUSPREV +quirk[pcb:pcb] = NONE # rimuovi un quirk precedentemente specificato +.Ed +.Pp +? possibile ottenere +.Aq classe +e +.Aq nome +usando xprop(1) e facendo click sulla finestra desiderata. +Nel seguente esempio ? stato fatto click sulla finestra principale di +Firefox: +.Bd -literal -offset indent +$ xprop | grep WM_CLASS +WM_CLASS(STRING) = "Navigator", "Firefox" +.Ed +.Pp +Bisogna tenere conto del fatto che usare grep per trovare WM_CLASS inverte +la classe e il nome. Nell'esempio precedente, la dichiarazione del quirk +sarebbe +.Bd -literal -offset indent +quirk[Firefox:Navigator] = FLOAT +.Ed +.Pp +.Nm +assegna automaticamente i quirk alle finestre in base al valore della +propriet? _NET_WM_WINDOW_TYPE in base al seguente schema: +.Pp +.Bl -tag -width "_NET_WM_WINDOW_TYPE_TOOLBARXXX" -offset indent -compact +.It _NET_WM_WINDOW_TYPE_DOCK +FLOAT + ANYWHERE +.It _NET_WM_WINDOW_TYPE_TOOLBAR +FLOAT + ANYWHERE +.It _NET_WM_WINDOW_TYPE_UTILITY +FLOAT + ANYWHERE +.It _NET_WM_WINDOW_TYPE_SPLASH +FLOAT +.It _NET_WM_WINDOW_TYPE_DIALOG +FLOAT +.El +.Pp +In tutti gli altri casi, nessun quirk ? automaticamente assegnato alla +finestra. I quirk specificati nel file di configurazione hanno la precedenza +sui quirk assegnati in automatico. +.Sh EWMH +.Nm +implementa in maniera parziale la specifica Extended Window Manager Hints +(EWMH). Ci? permette di controllare sia le finestre che +.Nm +stesso tramite script e programmi esterni. Per renderlo possibile, +.Nm +risponde ad alcuni eventi di tipo ClientMessage; questo tipo di messaggio +pu? essere inviato da un terminale usando programmi come +.Xr wmctrl 1 +e +.Xr xdotool 1 . +Per il formato esatto di questi messaggi, si veda la specifica EWMH. +.Pp +L'id della finestra che ha il focus ? memorizzato nella propriet? +_NET_ACTIVE_WINDOW della root window. ? quindi possibile ottenere il titolo +della finestra attiva usando +.Xr xprop 1 +e +.Xr grep 1 +.Bd -literal -offset indent +$ WINDOWID=`xprop \-root _NET_ACTIVE_WINDOW | grep \-o "0x.*"` +$ xprop \-id $WINDOWID WM_NAME | grep \-o "\\".*\\"" +.Ed +.Pp +Per dare il focus ad una finestra, ? sufficiente inviare il messaggio +_NET_ACTIVE_WINDOW alla root window. Ad esempio, usando +.Xr wmctrl 1 +(supponendo che 0x4a0000b sia l'id della finestra a cui dare il focus): +.Bd -literal -offset indent +$ wmctrl \-i \-c 0x4a0000b +.Ed +.Pp +Per chiudere una finestra si pu? inviare il messaggio _NET_CLOSE_WINDOW +alla root window. Ad esempio, usando +.Xr wmctrl 1 +(supponendo che 0x4a0000b sia l'id della finestra da chiudere): +.Bd -literal -offset indent +$ wmctrl \-i \-c 0x4a0000b +.Ed +.Pp +Per passare una finestra da floating a tiled si pu? aggiungere o rimuovere +l'atomo _NET_WM_STATE_ABOVE alla propriet? _NET_WM_STATE della finestra, +inviando il messaggio _NET_WM_STATE alla root window. Ad esempio, usando +.Xr wmctrl 1 +(supponendo che 0x4a0000b sia l'id della finestra): +.Bd -literal -offset indent +$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE +.Ed +.Pp +Le finestre floating possono essere ridimensionate o spostate inviando il +messaggio _NET_MOVERESIZE_WINDOW alla root window. Ad esempio, usando +.Xr wmctrl 1 +(supponendo che 0x4a0000b sia l'id della finestra da spostare): +.Bd -literal -offset indent +$ wmctrl \-i \-r 0x4a0000b \-e 0,100,50,640,480 +.Ed +.Pp +Questo comando sposta la finestra in (100,50) e la ridimensiona a 640x480. +.Pp +I messaggi _NET_MOVERESIZE_WINDOW vengono ignorati per le finestre stacked. +.Sh SEGNALI +? possibile riavviare +.Nm +inviandogli il segnale HUP. +.Sh FILE +.Bl -tag -width "/etc/spectrwm.confXXX" -compact +.It Pa ~/.spectrwm.conf +impostazioni di +.Nm +dell'utente. +.It Pa /etc/spectrwm.conf +impostazioni globali di +.Nm . +.El +.Sh ORIGINE +.Nm +prende ispirazione da xmonad & dwm. +.Sh AUTORI +.An -nosplit +.Pp +.Nm +? stato scritto da: +.Pp +.Bl -tag -width "Ryan Thomas McBride Aq mcbride@countersiege.com " -offset indent -compact +.It Cm Marco Peereboom Aq marco@peereboom.us +.It Cm Ryan Thomas McBride Aq mcbride@countersiege.com +.It Cm Darrin Chandler Aq dwchandler@stilyagin.com +.It Cm Pierre-Yves Ritschard Aq pyr@spootnik.org +.It Cm Tuukka Kataja Aq stuge@xor.fi +.It Cm Jason L. Wright Aq jason@thought.net +.El +.Sh BUGS +Al momento il menu, invocato usando +.Cm M-p , +dipende da dmenu. diff --git a/spectrwm_pt.1 b/spectrwm_pt.1 new file mode 100644 index 0000000..3249901 --- /dev/null +++ b/spectrwm_pt.1 @@ -0,0 +1,584 @@ +.\" Copyright (c) 2009 Marco Peereboom +.\" Copyright (c) 2009 Darrin Chandler +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt SPECTRWM 1 +.Os +.Sh NOME +.Nm spectrwm +.Nd gerenciador de janela para o X11 +.Sh SINOPSE +.Nm spectrwm +.Sh DESCRI\(,C\(~AO +.Nm +\('e um gerenciador de janela minimalista que tenta n\(~ao atrapalhar a +valorosa forma real da tela para que essa possa +ser usada para coisas muito mais importantes. +Tem sensatos defaults e n\(~ao requer que algu\('em aprenda uma linguagem de +programa\(,c\(~ao para fazer qualquer configura\(,c\(~ao. +Ele foi escrito por hackers para hackers e esfor\(,ca-se em ser pequeno, compacto e +r\('apido. +.Pp +Quando o +.Nm +inicia, ele l\(^e as configura\(,c\(~oes do seu arquivo de configura\(,c\(~ao, +.Pa spectrwm.conf . +Veja a se\(,c\(~ao +.Sx ARQUIVOS DE CONFIGURA\(,C\(~AO +logo abaixo. +.Pp +A seguinte nota\(,c\(~ao \('e usada por toda essa p\('agina: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Cm M +Meta +.It Cm S +Shift +.It Aq Cm Name +Nome da tecla +.It Cm M1 +Bot\(~ao 1 do mouse +.It Cm M3 +Bot\(~ao 3 do mouse +.El +.Pp +.Nm +\('e muito simples de usar. +Muitas das a\(,c\(~oes s\(~ao iniciadas por atalhos do mouse ou do teclado. +Veja a se\(,c\(~ao +.Sx ATALHOS +logo abaixo para os defaults e as personaliza\(,c\(~oes. +.Sh ARQUIVOS DE CONFIGURA\(,C\(~AO +.Nm +primeiro tenta abrir o arquivo de configura\(,c\(~ao no diret\('orio do usu\('ario, +.Pa ~/.spectrwm.conf . +Se o arquivo n\(~ao estiver dispon\('ivel, ent\(~ao tenta abrir o arquivo de +configura\(,c\(~ao global +.Pa /etc/spectrwm.conf . +.Pp +Assim \('e o formato do arquivo:\*(Ltpalavra-chave\*(Gt = \*(Ltconfigura\(,c\(~ao\*(Gt. +Por exemplo: +.Pp +.Dl color_focus = red +.Pp +Para habilitar ou desabilitar uma op\(,c\(~ao usa-se o 1 ou 0, respectivamente. +.Pp +O arquivo suporta as seguintes palavras-chave: +.Pp +.Bl -tag -width "title_class_enabledXXX" -offset indent -compact +.It Cm color_focus +Cor da borda da janela atualmente focada. +.It Cm color_unfocus +Cor da borda das janelas fora de foco. +.It Cm bar_enabled +Habilita ou desabilita a barra de status. +.It Cm bar_border Ns Bq Ar x +Cor da borda da barra de status na tela +.Ar x . +.It Cm bar_color Ns Bq Ar x +Cor da janela da barra de status na tela +.Ar x . +.It Cm bar_font_color Ns Bq Ar x +Cor da fonte na barra de status na tela +.Ar x . +.It Cm bar_font +Fonte da barra de status. +.It Cm bar_action +Script externo que preenche a barra de status com informa\(,c\(~oes adicionais, +como tempo de vida da bateria. +.It Cm bar_delay +Freq\(:u\(^encia da atualiza\(,c\(~ao, em segundos, do script externo que preenche +a barra de status. +.It Cm bar_at_bottom +Coloca a barra de status na parte inferior de cada regi\(~ao, ao inv\('es da parte superior. +.It Cm stack_enabled +Habilita ou desabilita mostrar o atual algor\('itmo de empilhamento na barra de status. +.It Cm clock_enabled +Habilita ou desabilita mostrar o rel\('ogio na barra de status. +Desabilite configurando para 0, ent\(~ao um rel\('ogio personalizado pode ser usado no +script bar_action. +.It Cm dialog_ratio +Algumas aplica\(,c\(~oes tem janelas de di\('alogo que s\(~ao muito pequenas para serem \('uteis. +Essa taxa \('e o tamanho da tela para o qual elas ser\(~ao redimencionadas. +Por exemplo, 0.6 equivale a 60% do tamanho da tela f\('isica. +.It Cm region +Aloca uma regi\(~ao personalizada, removendo qualquer regi\(~ao automaticamente detectada +que ocupe o mesmo espa\(,co na tela. +Definido no formato screen[]:WIDTHxHEIGHT+X+Y, +e.g.\& screen[1]:800x1200+0+0. +.It Cm term_width +Configura a largura m\('inima preferida para o terminal +Se esse valor for maior do que 0, +.Nm +vai tentar ajustar os tamanhos da fonte no terminal para manter a largura +do terminal acima desse n\('umero enquanto a janela \('e redimencionada. +Apenas o +.Xr xterm 1 +\('e suportado atualmente. +O bin\('ario do +.Xr xterm 1 +n\(~ao deve ser setuid ou setgid, que \('e o default em muitos sistemas. +Os usu\('arios podem precisar de configurar program[term] (veja a se\(,c\(~ao +.Sx PROGRAMAS +) para usar uma c\('opia alternativa do bin\('ario do +.Xr xterm 1 +sem o bit setgid ativado. +.It Cm title_class_enabled +Habilita ou desabilita mostrar a classe da janela na barra de status. +Habilite configurando para 1. +.It Cm title_name_enabled +Habilita ou desabilita mostrar o t\('itulo da janela na barra de status. +Habilite configurando para 1. +.It Cm window_name_enabled +Habilita ou desabilita mostrar a nome da janela na barra de status. +Habilite configurando para 1. +.It Cm modkey +Muda a tecla de modifica\(,c\(~ao. +Mod1 \('e geralmente a tecla ALT e Mod4 \('e a tecla windows em um PC. +.It Cm focus_mode +Usar um valor de follow_cursor vai fazer o gerenciador de janela focar +a janela sob o mouse quando trocando \('areas de trabalho e criando janelas. +.It Cm disable_border +Remove a borda quando a barra estiver desabilitada e houver apenas uma janela na tela. +.It Cm program Ns Bq Ar p +Define uma nova a\(,c\(~ao para executar um programa +.Ar p . +Veja a se\(,c\(~ao +.Sx PROGRAMAS +logo abaixo. +.It Cm bind Ns Bq Ar x +Cria uma combina\(,c\(~ao de teclas de atalho para a a\(,c\(~ao +.Ar x . +Veja a se\(,c\(~ao +.Sx ATALHOS +logo abaixo. +.It Cm quirk Ns Bq Ar c:n +Adicione "quirk" para janelas com classe +.Ar c +e nome +.Ar n . +Veja a se\(,c\(~ao +.Sx QUIRKS +logo abaixo. +.El +.Pp +Cores precisam ser especificadas pela especifica\(,c\(~ao +.Xr XQueryColor 3 +e fontes pela especifica\(,c\(~ao +.Xr XQueryFont 3 . +.Pp +Para listar as fontes dispon\('iveis em seu sistema veja o manual do +.Xr fc-list 1 +ou do +.Xr xlsfonts 1 . +A aplica\(,c\(~ao +.Xr xfontsel 1 +pode te ajudar a mostrar a X Logical Font Description ("XLFD") usada na +configura\(,c\(~ao da palavra-chave bar_font. +.Sh PROGRAMAS +.Nm +te permite definir a\(,c\(~oes personalizadas para executar programas de sua escolha +e ent\(~ao criar um atalho para elas da mesma forma que as a\(,c\(~oes embutidas. +Veja a se\(,c\(~ao +.Sx ATALHOS +logo abaixo. +.Pp +Os programas default s\(~ao descritos abaixo: +.Pp +.Bl -tag -width "screenshot_wind" -offset indent -compact +.It Cm term +xterm +.It Cm screenshot_all +screenshot.sh full +.It Cm screenshot_wind +screenshot.sh window +.It Cm lock +xlock +.It Cm initscr +initscreen.sh +.It Cm menu +dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color +.El +.Pp +Programas personalizados no arquivo de configura\(,c\(~ao s\(~ao especificados da seguinte maneira: +.Pp +.Dl program[] = [ [... ]] +.Pp +.Aq name +\('e um identificador qualquer que n\(~ao conflite com uma a\(,c\(~ao ou palavra-chave embutida, +.Aq progpath +\('e o programa desejado, e +.Aq arg +\('e zero ou mais argumentos para o programa. +.Pp +As seguintes vari\('aveis representam valores configur\('aveis no +.Nm +(veja a se\(,c\(~ao +.Sx ARQUIVOS DE CONFIGURA\(,C\(~AO +logo acima), +e podem ser usadas nos campos +.Aq arg +e ser\(~ao substitu\('idas pelos valores na hora em que o programa for executado: +.Pp +.Bl -tag -width "$bar_font_color" -offset indent -compact +.It Cm $bar_border +.It Cm $bar_color +.It Cm $bar_font +.It Cm $bar_font_color +.It Cm $color_focus +.It Cm $color_unfocus +.El +.Pp +Exemplo: +.Bd -literal -offset indent +program[ff] = /usr/local/bin/firefox http://spectrwm.org/ +bind[ff] = Mod+f # Agora Mod+F executa o firefox +.Ed +.Pp +Para desfazer a configura\(,c\(~ao anterior: +.Bd -literal -offset indent +bind[] = Mod+f +program[ff] = +.Ed +.Pp +.Sh ATALHOS +.Nm +prov\(^e muitas fun\(,c\(~oes (ou a\(,cões) acessadas pelos atalhos do teclado ou do mouse. +.Pp +Os atuais atalhos do mouse s\(~ao descritos abaixo: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M1 +Foca a janela +.It Cm M-M1 +Move a janela +.It Cm M-M3 +Redimenciona a janela +.It Cm M-S-M3 +Redimenciona a janela enquanto a mant\('em centralizada +.El +.Pp +Os atalhos default do teclado s\(~ao descritos abaixo: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M-S- Ns Aq Cm Return +term +.It Cm M-p +menu +.It Cm M-S-q +quit +.It Cm M-q +restart +.Nm +.It Cm M- Ns Aq Cm Space +cycle_layout +.It Cm M-S- Ns Aq Cm Space +reset_layout +.It Cm M-h +master_shrink +.It Cm M-l +master_grow +.It Cm M-, +master_add +.It Cm M-. +master_del +.It Cm M-S-, +stack_inc +.It Cm M-S-. +stack_del +.It Cm M- Ns Aq Cm Return +swap_main +.It Xo +.Cm M-j , +.Cm M- Ns Aq Cm TAB +.Xc +focus_next +.It Xo +.Cm M-k , +.Cm M-S- Ns Aq Cm TAB +.Xc +focus_prev +.It Cm M-m +focus_main +.It Cm M-S-j +swap_next +.It Cm M-S-k +swap_prev +.It Cm M-b +bar_toggle +.It Cm M-x +wind_del +.It Cm M-S-x +wind_kill +.It Cm M- Ns Aq Ar n +.Ns ws_ Ns Ar n +.It Cm M-S- Ns Aq Ar n +.Ns mvws_ Ns Ar n +.It Cm M- Ns Aq Cm Right +ws_next +.It Cm M- Ns Aq Cm Left +ws_prev +.It Cm M-a +ws_prior +.It Cm M-S- Ns Aq Cm Right +screen_next +.It Cm M-S- Ns Aq Cm Left +screen_prev +.It Cm M-s +screenshot_all +.It Cm M-S-s +screenshot_wind +.It Cm M-S-v +version +.It Cm M-t +float_toggle +.It Cm M-S Aq Cm Delete +lock +.It Cm M-S-i +initscr +.El +.Pp +Os nomes das a\(,c\(~oes e suas descri\(,cões est\(~ao listados abaixo: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm term +Executa um novo terminal +(veja a se\(,c\(~ao +.Sx PROGRAMAS +logo acima) +.It Cm menu +Menu +(veja a se\(,c\(~ao +.Sx PROGRAMAS +logo acima) +.It Cm quit +Sair +.Nm +.It Cm restart +Reiniciar +.Nm +.It Cm cycle_layout +Circula entre os poss\('iveis layouts +.It Cm reset_layout +Reinicia o layout +.It Cm master_shrink +Encolhe a \('area mestre +.It Cm master_grow +Aumenta a \('area mestre +.It Cm master_add +Adiciona janelas na \('area mestre +.It Cm master_del +Remove janelas da \('area mestre +.It Cm stack_inc +Adiciona colunas/linhas para a \('area de empilhamento +.It Cm stack_del +Remove colunas/linhas da \('area de empilhamento +.It Cm swap_main +Move a janela atual para a \('area mestre +.It Cm focus_next +Foca a pr\('oxima janela da \('area de trabalho +.It Cm focus_prev +Foca a janela anterior da \('area de trabalho +.It Cm focus_main +Foca a janela principal da \('area de trabalho +.It Cm swap_next +Troca com a pr\('oxima janela da \('area de trabalho +.It Cm swap_prev +Troca com a janela anterior da \('area de trabalho +.It Cm bar_toggle +Ativa/desativa a barra de status em todas as \('areas de trabalho +.It Cm wind_del +Apaga a janela atual da \('area de trabalho +.It Cm wind_kill +Destr\('oi a janela atual da \('area de trabalho +.It Cm ws_ Ns Ar n +Troca para a \('area de trabalho +.Ar n , +onde +.Ar n +vai de 1 at\('e 10 +.It Cm mvws_ Ns Ar n +Move a janela atual para a \('area de trabalho +.Ar n , +onde +.Ar n +vai de 1 at\('e 10 +.It Cm ws_next +Troca para a pr\('oxima \('area de trabalho que possua uma janela +.It Cm ws_prev +Troca para a \('area de trabalho anterior que possua uma janela +.It Cm ws_prior +Troca para a \('ultima \('area de trabalho visitada +.It Cm screen_next +Move o ponteiro para a pr\('oxima regi\(~ao +.It Cm screen_prev +Move o ponteiro para a regi\(~ao anterior +.It Cm screenshot_all +Tira screenshot da tela inteira (se habilitado) +(veja a se\(,c\(~ao +.Sx PROGRAMAS +logo acima) +.It Cm screenshot_wind +Tira screenshot da janela selecionada (se habilitado) +(veja a se\(,c\(~ao +.Sx PROGRAMAS +logo acima) +.It Cm version +Ativa/desativa a vers\(~ao na barras de status +.It Cm float_toggle +Troca o estado da janela focada entre flutuante e tiled +.It Cm lock +Trava a tela +(veja a se\(,c\(~ao +.Sx PROGRAMAS +logo acima) +.It Cm initscr +Reinicializa as telas f\('isicas +(veja a se\(,c\(~ao +.Sx PROGRAMAS +logo acima) +.El +.Pp +Atalhos personalizados no arquivo de configura\(,c\(~ao s\(~ao especificados da seguinte maneira: +.Pp +.Dl bind[] = +.Pp +.Aq action +\('e uma das a\(,c\(~oes listadas acima (ou vazio) e +.Aq keys +est\('a na forma de zero ou mais teclas de modifica\(,c\(~ao +(MOD, Mod1, Shift, etc.) e uma ou mais teclas normais +(b, space, etc.), separadas pelo "+". +Por exemplo: +.Bd -literal -offset indent +bind[reset] = Mod4+q # combina a tecla Windows + q para reiniciar +bind[] = Mod1+q # desfaz a combina\(,c\(~ao Alt + q +.Ed +.Pp +M\('ultiplas combina\(,c\(~oes de teclas podem ser usadas para a mesma a\(,c\(~ao. +.Sh QUIRKS +.Nm +prov\(^e "quirks" que manipulam janelas que devem ser tratadas especialmente +em um gerenciador de janela "tiling", tal como algumas aplica\(,c\(~oes de +di\('alogos e tela cheia. +.Pp +Os quirks default est\(~ao descritos abaixo: +.Pp +.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact +.It Firefox\-bin:firefox\-bin +TRANSSZ +.It Firefox:Dialog +FLOAT +.It Gimp:gimp +FLOAT + ANYWHERE +.It MPlayer:xv +FLOAT + FULLSCREEN +.It OpenOffice.org 2.4:VCLSalFrame +FLOAT +.It OpenOffice.org 3.1:VCLSalFrame +FLOAT +.It pcb:pcb +FLOAT +.It xine:Xine Window +FLOAT + ANYWHERE +.It xine:xine Panel +FLOAT + ANYWHERE +.It xine:xine Video Fullscreen Window +FULLSCREEN + FLOAT +.It Xitk:Xitk Combo +FLOAT + ANYWHERE +.It Xitk:Xine Window +FLOAT + ANYWHERE +.It XTerm:xterm +XTERM_FONTADJ +.El +.Pp +Os quirks em si est\(~ao descritos abaixo: +.Pp +.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact +.It FLOAT +Esta janela n\(~ao deve ser "tiled", mas permitida a flutuar livremente. +.It TRANSSZ +Ajusta o tamanho das janelas transit\('orias que sejam muito pequenas +usando dialog_ratio +(veja a se\(,c\(~ao +.Sx ARQUIVOS DE CONFIGURA\(,C\(~AO ) . +.It ANYWHERE +Permite que a janela posicione a si mesma, n\(~ao-centrada. +.It XTERM_FONTADJ +Ajusta as fontes do xterm quando redimencionando. +.It FULLSCREEN +Remove a borda para permitir a janela usar todo o tamanho da tela. +.El +.Pp +Quirks personalizados no arquivo de configura\(,c\(~ao s\(~ao especificados da seguinte maneira: +.Pp +.Dl quirk[:] = [ + ... ] +.Pp +.Aq class +e +.Aq name +especificam a janela ao qual o quirk se aplica, e +.Aq quirk +\('e um dos quirks da lista acima. +Por exemplo: +.Bd -literal -offset indent +quirk[MPlayer:xv] = FLOAT + FULLSCREEN # faz o mplayer tocar livremente +quirk[pcb:pcb] = NONE # remove quirk existente +.Ed +.Pp +Voc\(^e pode obter +.Aq class +e +.Aq name +executando o xprop(1) e ent\(~ao clicando na janela desejada. +No seguinte exemplo a jenela principal do Firefox foi clicada: +.Bd -literal -offset indent +$ xprop | grep WM_CLASS +WM_CLASS(STRING) = "Navigator", "Firefox" +.Ed +.Pp +Note que usando o grep(1) para WM_CLASS voc\(^e obt\('em class e name. +No exemplo acima a configura\(,c\(~ao do quirk poderia ser: +.Bd -literal -offset indent +quirk[Firefox:Navigator] = FLOAT +.Ed +.Sh SINAIS +Enviar ao +.Nm +um sinal HUP far\('a com que o mesmo seja reiniciado. +.Sh ARQUIVOS +.Bl -tag -width "/etc/spectrwm.confXXX" -compact +.It Pa ~/.spectrwm.conf +Configura\(,c\(~oes espec\('ificas do usu\('ario. +.It Pa /etc/spectrwm.conf +Configura\(,c\(~oes globais. +.El +.Sh HIST\('ORIA +.Nm +foi inspirado pelo xmonad & dwm. +.Sh AUTORES +.An -nosplit +.Pp +.Nm +foi escrito por +.An Marco Peereboom Aq marco@peereboom.us , +.An Ryan Thomas McBride Aq mcbride@countersiege.com +e +.An Darrin Chandler Aq dwchandler@stilyagin.com . +.Sh BUGS +Atualmente o menu, invocado com +.Cm M-p , +depende do dmenu. diff --git a/spectrwm_ru.1 b/spectrwm_ru.1 new file mode 100644 index 0000000..c65a21b --- /dev/null +++ b/spectrwm_ru.1 @@ -0,0 +1,557 @@ +.\" Copyright (c) 2009 Marco Peereboom +.\" Copyright (c) 2009 Darrin Chandler +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt SPECTRWM 1 +.Os +.Sh НАЗВАНИЕ +.Nm spectrwm +.Nd Оконный менеджер для X11 +.Sh ИСПОЛЬЗОВАНИЕ +.Nm spectrwm +.Sh ОПИСАНИЕ +.Nm +это минималистичный менеджер окон, ставящий своей целью не мешать вам и не +занимать ценное пространство экрана. Его настройки по-умолчанию разумны и, +кроме того, он не требует знания языков программирования для работы с +конфигурационным файлом. Он написан хакерами для хакеров и старается быть +легким, компактным и быстрым. +.Pp +Когда +.Nm +запускается, он читает настройки из своего конфигурационного файла, +.Pa spectrwm.conf . +Смотрите секцию +.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ +ниже. +.Pp +На этой странице используются следующие обозначения: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Cm M +Мета-клавиша +.It Cm S +Shift +.It Aq Cm Name +Имя клавиши +.It Cm M1 +Кнопка мыши 1 +.It Cm M3 +Кнопка мыши 3 +.El +.Pp +.Nm +должен быть понятным и очевидным. +Большинство действий выполняется комбинациями клавиш. +Смотрите секцию +.Sx ПРИВЯЗКИ +ниже, чтобы узнать о стандартных настройках. +.Sh КОНФИГУРАЦИОННЫЕ ФАЙЛЫ +.Nm +пытается прочитать файл в домашнем каталоге, +.Pa ~/.spectrwm.conf . +В случае, если он недоступен, +происходит обращение к глобальному файлу настроек, +.Pa /etc/spectrwm.conf . +.Pp +Формат файла следующий: \*(Ltключ\*(Gt = \*(Ltзначение\*(Gt. +Например: +.Pp +.Dl color_focus = red +.Pp +Однозначное включение и выключение задается значениями 1 и 0. +.Pp +Поддерживаются следующие ключевые слова: +.Pp +.Bl -tag -width "title_class_enabledXXX" -offset indent -compact +.It Cm color_focus +Цвет рамки окна в фокусе. +.It Cm color_unfocus +Цвет рамки окон не в фокусе. +.It Cm bar_enabled +Включение статусной строки. +.It Cm bar_border Ns Bq Ar x +Цвет рамки статусной строки +.Ar x . +.It Cm bar_color Ns Bq Ar x +Цвет статусной строки +.Ar x . +.It Cm bar_font_color Ns Bq Ar x +Цвет шрифта статусной строки +.Ar x . +.It Cm bar_font +Тип шрифта статусной строки. +.It Cm bar_action +Внешний файл скрипта для статусной строки, выводящий туда информацию, +например, уровень заряда батарей. +.It Cm bar_delay +Частота выполнения внешнего скрипта статусной строки, секунды. +.It Cm stack_enabled +Включить отображение способа укладки окон в статусной строке. +.It Cm clock_enabled +Включить часы в статусной строке. +Можно отключить, установив 0, и Вы сможете использовать +собственные часы из внешнего скрипта. +.It Cm dialog_ratio +Ряд приложений имеет слишком маленькие диалоговые окна. +Это значение - доля размера экрана, к которой они будут приведены. +Например, значение 0.6 будет соответствовать 60% от реального размера экрана. +.It Cm region +Выделяет область экрана на Ваше усмотрение, уничтожает все перекрытые области +экрана, определенные автоматически. +Формат: screen[]:WIDTHxHEIGHT+X+Y, +например\& screen[1]:1280x800+0+0. +.It Cm term_width +Установить минимальную допустимую ширину эмулятора терминала. +Если это значение больше 0, +.Nm +попытается отмасштабировать шрифты в терминале, чтобы ширина +была больше этого значения +. +Поодерживается только +.Xr xterm 1 +. +Также +.Xr xterm 1 +не может быть с setuid или setgid, хотя это так на многих системах. +Возможно необходимо задать program[term] (Смотрите секцию +.Sx ПРОГРАММЫ +) чтобы использовалась другая копия +.Xr xterm 1 +без заданного бита setgid. +.It Cm title_class_enabled +Отображать класс окна в статусной строке. +Обычно выключено +.It Cm title_name_enabled +Отображать заголовок окна в статусной строке. +Обычно выключено +.It Cm modkey +Назначить Мета-клавишу, клавишу-модификатор. +Mod1 соответствует клавише ALT, а Mod4 соответствует клавише WIN на PC. +.It Cm program Ns Bq Ar p +Добавить пользовательскую программу для назначения привязки +.Ar p . +Смотрите секцию +.Sx ПРОГРАММЫ +ниже. +.It Cm bind Ns Bq Ar x +Назначить привязку на действие +.Ar x . +Смотрите секцию +.Sx ПРИВЯЗКИ +ниже. +.It Cm quirk Ns Bq Ar c:n +Добавить костыль для окон с классом +.Ar c +и именем +.Ar n . +Смотрите секцию +.Sx КОСТЫЛИ +ниже. +.El +.Pp +Цвета задаются с помощью +.Xr XQueryColor 3 +А шрифты задаются с использованием +.Xr XQueryFont 3 +. +.Sh ПРОГРАММЫ +.Nm +позволяет Вам добавлять Ваши собственные действия для запуска +программ и делать к ним привязки как ко всем остальным действиям +Смотрите секцию +.Sx ПРИВЯЗКИ +ниже. +.Pp +Стандартные программы: +.Pp +.Bl -tag -width "screenshot_wind" -offset indent -compact +.It Cm term +xterm +.It Cm screenshot_all +screenshot.sh full +.It Cm screenshot_wind +screenshot.sh window +.It Cm lock +xlock +.It Cm initscr +initscreen.sh +.It Cm menu +dmenu_run \-fn $bar_font \-nb $bar_color \-nf $bar_font_color \-sb $bar_border \-sf $bar_color +.El +.Pp +Ваши собственные программы задаются следующим образом: +.Pp +.Dl program[] = [ [... ]] +.Pp +.Aq name +это любой идентификатор, не мешающийся с уже существующими, +.Aq progpath +это собственно путь к программе, +.Aq arg +это список передаваемых аргументов или оставьте пустым. +.Pp +Следующие переменные можно получать из +.Nm +(Смотрите секцию +.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ +выше), +и их можно использовать как +.Aq arg +(в момент запуска программы будет выполнена подстановка значений): +.Pp +.Bl -tag -width "$bar_font_color" -offset indent -compact +.It Cm $bar_border +.It Cm $bar_color +.It Cm $bar_font +.It Cm $bar_font_color +.It Cm $color_focus +.It Cm $color_unfocus +.El +.Pp +Например: +.Bd -literal -offset indent +program[ff] = /usr/local/bin/firefox http://spectrwm.org/ +bind[ff] = Mod+f # Значит Mod+F запускает firefox +.Ed +.Pp +Чтобы отменить назначение: +.Bd -literal -offset indent +bind[] = Mod+f +program[ff] = +.Ed +.Pp +.Sh ПРИВЯЗКИ +.Nm +предоставляет доступ к действиям с помощью клавиатурных комбинаций. +.Pp +Установленные привязки для мыши: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M1 +Сфокусироваться на окне +.It Cm M-M1 +Переместить окно +.It Cm M-M3 +Изменить размер окна +.It Cm M-S-M3 +Изменить размер окна, удерживая его в центре +.El +.Pp +Стандартные клавиатурные привязки: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm M-S- Ns Aq Cm Return +term +.It Cm M-p +menu +.It Cm M-S-q +quit +.It Cm M-q +restart +.Nm +.It Cm M- Ns Aq Cm Space +cycle_layout +.It Cm M-S- Ns Aq Cm Space +reset_layout +.It Cm M-h +master_shrink +.It Cm M-l +master_grow +.It Cm M-, +master_add +.It Cm M-. +master_del +.It Cm M-S-, +stack_inc +.It Cm M-S-. +stack_del +.It Cm M- Ns Aq Cm Return +swap_main +.It Xo +.Cm M-j , +.Cm M- Ns Aq Cm TAB +.Xc +focus_next +.It Xo +.Cm M-k , +.Cm M-S- Ns Aq Cm TAB +.Xc +focus_prev +.It Cm M-m +focus_main +.It Cm M-S-j +swap_next +.It Cm M-S-k +swap_prev +.It Cm M-b +bar_toggle +.It Cm M-x +wind_del +.It Cm M-S-x +wind_kill +.It Cm M- Ns Aq Ar n +.Ns ws_ Ns Ar n +.It Cm M-S- Ns Aq Ar n +.Ns mvws_ Ns Ar n +.It Cm M- Ns Aq Cm Right +ws_next +.It Cm M- Ns Aq Cm Left +ws_prev +.It Cm M-S- Ns Aq Cm Right +screen_next +.It Cm M-S- Ns Aq Cm Left +screen_prev +.It Cm M-s +screenshot_all +.It Cm M-S-s +screenshot_wind +.It Cm M-S-v +version +.It Cm M-t +float_toggle +.It Cm M-S Aq Cm Delete +lock +.It Cm M-S-i +initscr +.El +.Pp +Описания действий перечислены ниже: +.Pp +.Bl -tag -width "M-j, M-XXX" -offset indent -compact +.It Cm term +Запустить эмулятор терминала +(Смотрите секцию +.Sx ПРОГРАММЫ +выше) +.It Cm menu +Меню +(Смотрите секцию +.Sx ПРОГРАММЫ +выше) +.It Cm quit +Выйти +.Nm +.It Cm restart +Перезапустить +.Nm +.It Cm cycle_layout +Менять укладку окон +.It Cm reset_layout +Стандартная укладка +.It Cm master_shrink +Сжать область главного окна +.It Cm master_grow +Расширить область главного окна +.It Cm master_add +Добавить окна в главную область +.It Cm master_del +Убрать окна из главной области +.It Cm stack_inc +Увеличить число столбцов или рядов в текущей укладке +.It Cm stack_del +Уменьшить число столбцов или рядов в текущей укладке +.It Cm swap_main +Отправить текущее окно в главную область, сделать главным +.It Cm focus_next +Фокусироваться на следующем окне +.It Cm focus_prev +Фокусироваться на предыдущем окне +.It Cm focus_main +Фокусироваться на главном окне +.It Cm swap_next +Поменять со следующим окном +.It Cm swap_prev +Поменять со предыдущим окном +.It Cm bar_toggle +Выключить статусную строку на всех рабочих столах +.It Cm wind_del +Закрыть фокусированное окно +.It Cm wind_kill +Грохнуть фокусированное окно +.It Cm ws_ Ns Ar n +Переключиться на рабочий стол +.Ar n , +где +.Ar n +от 1 до 10 +.It Cm mvws_ Ns Ar n +Переместить фокусированное окно в рабочий стол +.Ar n , +где +.Ar n +от 1 до 10 +.It Cm ws_next +Перейти к следующему не пустому рабочему столу +.It Cm ws_prev +Перейти к следующему не пустому рабочему столу +.It Cm screen_next +Переместить указатель в следующую область +.It Cm screen_prev +Переместить указатель в следующую область +.It Cm screenshot_all +Сделать снимок всего экрана (если возможно) +(Смотрите секцию +.Sx ПРОГРАММЫ +выше) +.It Cm screenshot_wind +Сделать снимок окна (если возможно) +(Смотрите секцию +.Sx ПРОГРАММЫ +выше) +.It Cm version +Показать версию в статусной строке +.It Cm float_toggle +Переключить окно в фокусе в плавающий режим, float +.It Cm lock +Заблокировать экран +(Смотрите секцию +.Sx ПРОГРАММЫ +выше) +.It Cm initscr +Инициализировать экран еще раз +(Смотрите секцию +.Sx ПРОГРАММЫ +выше) +.El +.Pp +Собственные привязки назначаются следующим образом: +.Pp +.Dl bind[] = +.Pp +.Aq action +это действие из списка программ +.Aq keys +это не более одной клавиши-модификатора +(MOD, Mod1, Shift, и.т.п.) и обычные клавиши +(b, space, и.т.п.), разделенные "+". +Например: +.Bd -literal -offset indent +bind[reset] = Mod4+q # назначить WIN + q на действие reset +bind[] = Mod1+q # снять все действия с Alt + q +.Ed +.Pp +На одно действие можно назначить несколько комбинаций. +.Sh КОСТЫЛИ +.Nm +позволяет настроить костыли, нужные для специальной работы spectrwm +с рядом приложений, который вы определяете сами. То есть, Вы можете +принудительно установить способ тайлинга для какого-нибудь приложения +.Pp +Список стандартных костылей: +.Pp +.Bl -tag -width "OpenOffice.org N.M:VCLSalFrameXXX" -offset indent -compact +.It Firefox\-bin:firefox\-bin +TRANSSZ +.It Firefox:Dialog +FLOAT +.It Gimp:gimp +FLOAT + ANYWHERE +.It MPlayer:xv +FLOAT + FULLSCREEN +.It OpenOffice.org 2.4:VCLSalFrame +FLOAT +.It OpenOffice.org 3.1:VCLSalFrame +FLOAT +.It pcb:pcb +FLOAT +.It xine:Xine Window +FLOAT + ANYWHERE +.It xine:xine Panel +FLOAT + ANYWHERE +.It xine:xine Video Fullscreen Window +FULLSCREEN + FLOAT +.It Xitk:Xitk Combo +FLOAT + ANYWHERE +.It Xitk:Xine Window +FLOAT + ANYWHERE +.It XTerm:xterm +XTERM_FONTADJ +.El +.Pp +Описание: +.Pp +.Bl -tag -width "XTERM_FONTADJXXX" -offset indent -compact +.It FLOAT +Такое окно не нужно тайлить вообще, разрешить ему float +.It TRANSSZ +Тразиентое окно +(Смотрите секцию +.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ) . +.It ANYWHERE +Позволить окну самостоятельно выбрать местоположение +.It XTERM_FONTADJ +Изменять шрифты xterm при изменении размеров окна +.It FULLSCREEN +Позволить окну запускаться в полноэкранном режиме +.El +.Pp +Назначать костыли можно следующим образом: +.Pp +.Dl quirk[:] = [ + ... ] +.Pp +.Aq class +и +.Aq name +определяют к какому окну будет применяться костыль, а +.Aq quirk +один из вышеперечисленных способов. +Например: +.Bd -literal -offset indent +quirk[MPlayer:xv] = FLOAT + FULLSCREEN # mplayer настроен +quirk[pcb:pcb] = NONE # убрать существующий костыль +.Ed +.Pp +Вы можете узнать +.Aq class +и +.Aq name +запустив xprop и нажав в интересующее окно. +Вот как будет выглядеть вывод для Firefox: +.Bd -literal -offset indent +$ xprop | grep WM_CLASS +WM_CLASS(STRING) = "Navigator", "Firefox" +.Ed +.Pp +Обратите внимание, класс и имя меняются местами, +правильный костыль будет выглядеть так: +.Bd -literal -offset indent +quirk[Firefox:Navigator] = FLOAT +.Ed +.Sh ФАЙЛЫ +.Bl -tag -width "/etc/spectrwm.confXXX" -compact +.It Pa ~/.spectrwm.conf +.Nm +Личные настройки пользователя. +.It Pa /etc/spectrwm.conf +.Nm +Глобавльные настройки. +.El +.Sh ИСТОРИЯ +.Nm +идейно основан на dwm и xmonad +.Sh АВТОРЫ +.An -nosplit +.Pp +.Nm +написан: +.An Marco Peereboom Aq marco@peereboom.us , +.An Ryan Thomas McBride Aq mcbride@countersiege.com +and +.An Darrin Chandler Aq dwchandler@stilyagin.com . +.Sh БАГИ +При вызове меню с помощью +.Cm M-p , +необходима корректная работа dmenu. diff --git a/spectrwm_se.conf b/spectrwm_se.conf new file mode 100644 index 0000000..68dba05 --- /dev/null +++ b/spectrwm_se.conf @@ -0,0 +1,74 @@ +# Key bindings for Swedish (se) keyboards +# unbind with: bind[] = +bind[cycle_layout] = MOD+space +bind[flip_layout] = MOD+Shift+apostrophe +bind[stack_reset] = MOD+Shift+space +bind[master_shrink] = MOD+h +bind[master_grow] = MOD+l +bind[master_add] = MOD+comma +bind[master_del] = MOD+period +bind[stack_inc] = MOD+Shift+comma +bind[stack_dec] = MOD+Shift+period +bind[swap_main] = MOD+Return +bind[focus_next] = MOD+j +bind[focus_prev] = MOD+k +bind[swap_next] = MOD+Shift+j +bind[swap_prev] = MOD+Shift+k +bind[spawn_term] = MOD+Shift+Return +bind[menu] = MOD+p +bind[quit] = MOD+Shift+q +bind[restart] = MOD+q +bind[focus_main] = MOD+m +bind[ws_1] = MOD+1 +bind[ws_2] = MOD+2 +bind[ws_3] = MOD+3 +bind[ws_4] = MOD+4 +bind[ws_5] = MOD+5 +bind[ws_6] = MOD+6 +bind[ws_7] = MOD+7 +bind[ws_8] = MOD+8 +bind[ws_9] = MOD+9 +bind[ws_10] = MOD+0 +bind[ws_next] = MOD+Right +bind[ws_prev] = MOD+Left +bind[ws_next_all] = MOD+Up +bind[ws_prev_all] = MOD+Down +bind[ws_prior] = MOD+a +bind[screen_next] = MOD+Shift+Right +bind[screen_prev] = MOD+Shift+Left +bind[mvws_1] = MOD+Shift+1 +bind[mvws_2] = MOD+Shift+2 +bind[mvws_3] = MOD+Shift+3 +bind[mvws_4] = MOD+Shift+4 +bind[mvws_5] = MOD+Shift+5 +bind[mvws_6] = MOD+Shift+6 +bind[mvws_7] = MOD+Shift+7 +bind[mvws_8] = MOD+Shift+8 +bind[mvws_9] = MOD+Shift+9 +bind[mvws_10] = MOD+Shift+0 +bind[bar_toggle] = MOD+b +bind[focus_next] = MOD+Tab +bind[focus_prev] = MOD+Shift+Tab +bind[wind_kill] = MOD+Shift+x +bind[wind_del] = MOD+x +bind[screenshot_all] = MOD+s +bind[screenshot_wind] = MOD+Shift+s +bind[float_toggle] = MOD+t +bind[version] = MOD+Shift+v +bind[lock] = MOD+Shift+Delete +bind[initscr] = MOD+Shift+i +bind[iconify] = MOD+w +bind[uniconify] = MOD+Shift+w +bind[raise_toggle] = MOD+Shift+r +bind[button2] = MOD+v +bind[width_shrink] = MOD+plus +bind[width_grow] = MOD+dead_acute +bind[height_shrink] = MOD+Shift+plus +bind[height_grow] = MOD+Shift+dead_acute +bind[move_left] = MOD+aring +bind[move_right] = MOD+dead_diaeresis +bind[move_up] = MOD+Shift+aring +bind[move_down] = MOD+Shift+dead_diaeresis +bind[name_workspace] = MOD+Shift+minus +bind[search_workspace] = MOD+minus +bind[search_win] = MOD+f diff --git a/spectrwm_us.conf b/spectrwm_us.conf new file mode 100644 index 0000000..f2ce392 --- /dev/null +++ b/spectrwm_us.conf @@ -0,0 +1,74 @@ +# Key bindings for United States (us) keyboards +# unbind with: bind[] = +bind[cycle_layout] = MOD+space +bind[flip_layout] = MOD+Shift+backslash +bind[stack_reset] = MOD+Shift+space +bind[master_shrink] = MOD+h +bind[master_grow] = MOD+l +bind[master_add] = MOD+comma +bind[master_del] = MOD+period +bind[stack_inc] = MOD+Shift+comma +bind[stack_dec] = MOD+Shift+period +bind[swap_main] = MOD+Return +bind[focus_next] = MOD+j +bind[focus_prev] = MOD+k +bind[swap_next] = MOD+Shift+j +bind[swap_prev] = MOD+Shift+k +bind[spawn_term] = MOD+Shift+Return +bind[menu] = MOD+p +bind[quit] = MOD+Shift+q +bind[restart] = MOD+q +bind[focus_main] = MOD+m +bind[ws_1] = MOD+1 +bind[ws_2] = MOD+2 +bind[ws_3] = MOD+3 +bind[ws_4] = MOD+4 +bind[ws_5] = MOD+5 +bind[ws_6] = MOD+6 +bind[ws_7] = MOD+7 +bind[ws_8] = MOD+8 +bind[ws_9] = MOD+9 +bind[ws_10] = MOD+0 +bind[ws_next] = MOD+Right +bind[ws_prev] = MOD+Left +bind[ws_next_all] = MOD+Up +bind[ws_prev_all] = MOD+Down +bind[ws_prior] = MOD+a +bind[screen_next] = MOD+Shift+Right +bind[screen_prev] = MOD+Shift+Left +bind[mvws_1] = MOD+Shift+1 +bind[mvws_2] = MOD+Shift+2 +bind[mvws_3] = MOD+Shift+3 +bind[mvws_4] = MOD+Shift+4 +bind[mvws_5] = MOD+Shift+5 +bind[mvws_6] = MOD+Shift+6 +bind[mvws_7] = MOD+Shift+7 +bind[mvws_8] = MOD+Shift+8 +bind[mvws_9] = MOD+Shift+9 +bind[mvws_10] = MOD+Shift+0 +bind[bar_toggle] = MOD+b +bind[focus_next] = MOD+Tab +bind[focus_prev] = MOD+Shift+Tab +bind[wind_kill] = MOD+Shift+x +bind[wind_del] = MOD+x +bind[screenshot_all] = MOD+s +bind[screenshot_wind] = MOD+Shift+s +bind[float_toggle] = MOD+t +bind[version] = MOD+Shift+v +bind[lock] = MOD+Shift+Delete +bind[initscr] = MOD+Shift+i +bind[iconify] = MOD+w +bind[uniconify] = MOD+Shift+w +bind[raise_toggle] = MOD+Shift+r +bind[button2] = MOD+v +bind[width_shrink] = MOD+minus +bind[width_grow] = MOD+equal +bind[height_shrink] = MOD+Shift+minus +bind[height_grow] = MOD+Shift+equal +bind[move_left] = MOD+bracketleft +bind[move_right] = MOD+bracketright +bind[move_up] = MOD+Shift+bracketleft +bind[move_down] = MOD+Shift+bracketright +bind[name_workspace] = MOD+Shift+slash +bind[search_workspace] = MOD+slash +bind[search_win] = MOD+f diff --git a/version.h b/version.h index 83efea9..3cf35e5 100644 --- a/version.h +++ b/version.h @@ -15,18 +15,18 @@ */ -#ifndef SCROTWM_VERSION_H -#define SCROTWM_VERSION_H +#ifndef SPECTRWM_VERSION_H +#define SPECTRWM_VERSION_H -#define SCROTWM_STR(x) #x -#define SCROTWM_STRINGIZE(x) SCROTWM_STR(x) +#define SPECTRWM_STR(x) #x +#define SPECTRWM_STRINGIZE(x) SPECTRWM_STR(x) -#define SCROTWM_MAJOR 0 -#define SCROTWM_MINOR 11 -#define SCROTWM_PATCH 0 -#define SCROTWM_VERSION SCROTWM_STRINGIZE(SCROTWM_MAJOR) "." \ - SCROTWM_STRINGIZE(SCROTWM_MINOR) "." \ - SCROTWM_STRINGIZE(SCROTWM_PATCH) +#define SPECTRWM_MAJOR 0 +#define SPECTRWM_MINOR 11 +#define SPECTRWM_PATCH 0 +#define SPECTRWM_VERSION SPECTRWM_STRINGIZE(SPECTRWM_MAJOR) "." \ + SPECTRWM_STRINGIZE(SPECTRWM_MINOR) "." \ + SPECTRWM_STRINGIZE(SPECTRWM_PATCH) -#endif /* SCROTWM_VERSION_H */ +#endif /* SPECTRWM_VERSION_H */