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
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
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} "
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
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
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 <bsd.port.post.mk>
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
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
+++ /dev/null
-
-[Desktop Entry]
-Name=ScrotWM
-Comment=The ScrotWM window manager
-Type=Application
-Exec=/usr/bin/scrotwm
-TryExec=/usr/bin/scrotwm
--- /dev/null
+[Desktop Entry]
+Name=spectrwm
+Comment=The spectrwm window manager
+Type=Application
+Exec=/usr/bin/spectrwm
+TryExec=/usr/bin/spectrwm
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
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
# - Tags the release
# - Creates a release tarball
-PROJECT=scrotwm
+PROJECT=spectrwm
PROJECT_UC=$(echo $PROJECT | tr '[:lower:]' '[:upper:]')
SCRIPT=$(basename $0)
HEADER=version.h
+++ /dev/null
-.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
-.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
-.\"
-.\" 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[<idx>]: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[<idx>]: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[<name>] = <progpath> [<arg> [... <arg>]]
-.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-<TAB>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-<TAB>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-<TAB>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[<action>] = <keys>
-.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<class>:<name>] = <quirk> [ + <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_TOOLBAR<TAB>XXX" -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
+++ /dev/null
-/*
- * Copyright (c) 2009-2012 Marco Peereboom <marco@peereboom.us>
- * Copyright (c) 2009-2011 Ryan McBride <mcbride@countersiege.com>
- * Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
- * Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
- * Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
- * Copyright (c) 2011 Jason L. Wright <jason@thought.net>
- * Copyright (c) 2011-2012 Reginald Kennedy <rk@rejii.com>
- * Copyright (c) 2012 Lawrence Teo <lteo@lteo.net>
- * Copyright (c) 2012 Tiago Cunha <tcunha@gmx.com>
- *
- * 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 <garbeam at gmail dot com>
- * 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
- * 2006-2007 Jukka Salmi <jukka at salmi dot ch>
- * 2007 Premysl Hruby <dfenze at gmail dot com>
- * 2007 Szabolcs Nagy <nszabolcs at gmail dot com>
- * 2007 Christof Musik <christof at sendfax dot de>
- * 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
- * 2007-2008 Peter Hartlich <sgkkr at hartlich dot com>
- * 2008 Martin Hurton <martin dot hurton at gmail dot com>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <unistd.h>
-#include <time.h>
-#include <signal.h>
-#include <string.h>
-#include <util.h>
-#include <pwd.h>
-#include <paths.h>
-#include <ctype.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/queue.h>
-#include <sys/param.h>
-#include <sys/select.h>
-#if defined(__linux__)
-#include "tree.h"
-#elif defined(__OpenBSD__)
-#include <sys/tree.h>
-#elif defined(__FreeBSD__)
-#include <sys/tree.h>
-#else
-#include <sys/tree.h>
-#endif
-
-#include <X11/cursorfont.h>
-#include <X11/keysym.h>
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xproto.h>
-#include <X11/Xutil.h>
-#include <X11/extensions/Xrandr.h>
-#include <X11/extensions/XTest.h>
-
-#ifdef __OSX__
-#include <osx.h>
-#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[<n>]:<n>x<n>+<n>+<n>");
- 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[<idx>]: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[<idx>]:"
- "<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
- "<type>'");
- 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[<idx>]:"
- "<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
- "<type>'");
-
- 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);
-}
+++ /dev/null
-# 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
+++ /dev/null
-# Key bindings for Czech Republic (cz) keyboards
-# unbind with: bind[] = <keys>
-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
+++ /dev/null
-.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
-.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
-.\"
-.\" 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[<idx>]: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[<idx>]: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[<nombre>] = <progpath> [<arg> [... <arg>]]
-.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-<TAB>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-<TAB>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-<TAB>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[<accion>] = <teclas>
-.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<clases>:<nombre>] = <quirk> [ + <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.
+++ /dev/null
-# Key bindings for Spanish (es) keyboards
-# unbind with: bind[] = <keys>
-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
+++ /dev/null
-# Key bindings for French (fr) keyboards
-# unbind with: bind[] = <keys>
-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
+++ /dev/null
-# Key bindings for Swiss French (FR_CH) keyboards
-# unbind with: bind[] = <keys>
-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
+++ /dev/null
-.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
-.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
-.\"
-.\" 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[<idx>]: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[<idx>]: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[<idx>]: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[<nome>] = <percorso> [<arg> [... <arg>]]
-.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-<TAB>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-<TAB>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-<TAB>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[<azione>] = <tasti>
-.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<classe>:<nome>] = <quirk> [ + <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_TOOLBAR<TAB>XXX" -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.
+++ /dev/null
-.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
-.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
-.\"
-.\" 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[<idx>]: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[<name>] = <progpath> [<arg> [... <arg>]]
-.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-<TAB>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-<TAB>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-<TAB>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[<action>] = <keys>
-.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<class>:<name>] = <quirk> [ + <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.
+++ /dev/null
-.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
-.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
-.\"
-.\" 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[<idx>]: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[<name>] = <progpath> [<arg> [... <arg>]]
-.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-<TAB>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-<TAB>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-<TAB>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[<action>] = <keys>
-.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -offset indent -compact
-.It FLOAT
-Такое окно не нужно тайлить вообще, разрешить ему float
-.It TRANSSZ
-Тразиентое окно
-(Смотрите секцию
-.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ) .
-.It ANYWHERE
-Позволить окну самостоятельно выбрать местоположение
-.It XTERM_FONTADJ
-Изменять шрифты xterm при изменении размеров окна
-.It FULLSCREEN
-Позволить окну запускаться в полноэкранном режиме
-.El
-.Pp
-Назначать костыли можно следующим образом:
-.Pp
-.Dl quirk[<class>:<name>] = <quirk> [ + <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.
+++ /dev/null
-# Key bindings for Swedish (se) keyboards
-# unbind with: bind[] = <keys>
-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
+++ /dev/null
-# Key bindings for United States (us) keyboards
-# unbind with: bind[] = <keys>
-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
--- /dev/null
+.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
+.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
+.\"
+.\" 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[<idx>]: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[<idx>]: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[<name>] = <progpath> [<arg> [... <arg>]]
+.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-<TAB>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-<TAB>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-<TAB>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[<action>] = <keys>
+.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<class>:<name>] = <quirk> [ + <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_TOOLBAR<TAB>XXX" -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
--- /dev/null
+/*
+ * Copyright (c) 2009-2012 Marco Peereboom <marco@peereboom.us>
+ * Copyright (c) 2009-2011 Ryan McBride <mcbride@countersiege.com>
+ * Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
+ * Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
+ * Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
+ * Copyright (c) 2011 Jason L. Wright <jason@thought.net>
+ * Copyright (c) 2011-2012 Reginald Kennedy <rk@rejii.com>
+ * Copyright (c) 2012 Lawrence Teo <lteo@lteo.net>
+ * Copyright (c) 2012 Tiago Cunha <tcunha@gmx.com>
+ *
+ * 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 <garbeam at gmail dot com>
+ * 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+ * 2006-2007 Jukka Salmi <jukka at salmi dot ch>
+ * 2007 Premysl Hruby <dfenze at gmail dot com>
+ * 2007 Szabolcs Nagy <nszabolcs at gmail dot com>
+ * 2007 Christof Musik <christof at sendfax dot de>
+ * 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
+ * 2007-2008 Peter Hartlich <sgkkr at hartlich dot com>
+ * 2008 Martin Hurton <martin dot hurton at gmail dot com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+#include <string.h>
+#include <util.h>
+#include <pwd.h>
+#include <paths.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#if defined(__linux__)
+#include "tree.h"
+#elif defined(__OpenBSD__)
+#include <sys/tree.h>
+#elif defined(__FreeBSD__)
+#include <sys/tree.h>
+#else
+#include <sys/tree.h>
+#endif
+
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/XTest.h>
+
+#ifdef __OSX__
+#include <osx.h>
+#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[<n>]:<n>x<n>+<n>+<n>");
+ 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[<idx>]: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[<idx>]:"
+ "<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
+ "<type>'");
+ 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[<idx>]:"
+ "<master_grow>:<master_add>:<stack_inc>:<always_raise>:"
+ "<type>'");
+
+ 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);
+}
--- /dev/null
+# 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
--- /dev/null
+# Key bindings for Czech Republic (cz) keyboards
+# unbind with: bind[] = <keys>
+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
--- /dev/null
+.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
+.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
+.\"
+.\" 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[<idx>]: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[<idx>]: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[<nombre>] = <progpath> [<arg> [... <arg>]]
+.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-<TAB>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-<TAB>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-<TAB>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[<accion>] = <teclas>
+.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<clases>:<nombre>] = <quirk> [ + <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.
--- /dev/null
+# Key bindings for Spanish (es) keyboards
+# unbind with: bind[] = <keys>
+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
--- /dev/null
+# Key bindings for French (fr) keyboards
+# unbind with: bind[] = <keys>
+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
--- /dev/null
+# Key bindings for Swiss French (FR_CH) keyboards
+# unbind with: bind[] = <keys>
+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
--- /dev/null
+.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
+.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
+.\"
+.\" 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[<idx>]: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[<idx>]: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[<idx>]: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[<nome>] = <percorso> [<arg> [... <arg>]]
+.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-<TAB>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-<TAB>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-<TAB>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[<azione>] = <tasti>
+.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<classe>:<nome>] = <quirk> [ + <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_TOOLBAR<TAB>XXX" -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.
--- /dev/null
+.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
+.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
+.\"
+.\" 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[<idx>]: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[<name>] = <progpath> [<arg> [... <arg>]]
+.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-<TAB>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-<TAB>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-<TAB>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[<action>] = <keys>
+.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -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[<class>:<name>] = <quirk> [ + <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.
--- /dev/null
+.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
+.\" Copyright (c) 2009 Darrin Chandler <dwchandler@stilyagin.com>
+.\"
+.\" 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[<idx>]: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[<name>] = <progpath> [<arg> [... <arg>]]
+.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-<TAB>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-<TAB>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-<TAB>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[<action>] = <keys>
+.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:VCLSalFrame<TAB>XXX" -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_FONTADJ<TAB>XXX" -offset indent -compact
+.It FLOAT
+Такое окно не нужно тайлить вообще, разрешить ему float
+.It TRANSSZ
+Тразиентое окно
+(Смотрите секцию
+.Sx КОНФИГУРАЦИОННЫЕ ФАЙЛЫ) .
+.It ANYWHERE
+Позволить окну самостоятельно выбрать местоположение
+.It XTERM_FONTADJ
+Изменять шрифты xterm при изменении размеров окна
+.It FULLSCREEN
+Позволить окну запускаться в полноэкранном режиме
+.El
+.Pp
+Назначать костыли можно следующим образом:
+.Pp
+.Dl quirk[<class>:<name>] = <quirk> [ + <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.
--- /dev/null
+# Key bindings for Swedish (se) keyboards
+# unbind with: bind[] = <keys>
+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
--- /dev/null
+# Key bindings for United States (us) keyboards
+# unbind with: bind[] = <keys>
+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
*/
-#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 */