Compare commits

...

No commits in common. "wmfs1" and "master" have entirely different histories.

68 changed files with 8745 additions and 11609 deletions

12
.gitignore vendored
View File

@ -1,11 +1,3 @@
*.o
.*.sw?
wmfs
#*
\#*
wmfs.1.gz
tags
*.patch
*.diff
Makefile Makefile
build/ wmfs
src/*.o

View File

@ -1,134 +0,0 @@
#
# CMake for wmfs David Demelier <markand@malikania.fr>
#
# General settings
cmake_minimum_required(VERSION 2.8)
project(wmfs)
set(CMAKE_C_FLAGS_RELEASE "-Wall")
set(CMAKE_C_FLAGS_DEBUG "-Wall -g -ansi -pendantic -O3 -funroll-loops")
# General option
option(WITH_XINERAMA "Build with X.Org xinerama support" ON)
option(WITH_XRANDR "Build with X.Org xrandr support" ON)
option(WITH_XFT "Build with X.Org xft support" ON)
option(WITH_IMLIB2 "Build with imlib2 graphic library" ON)
# WMFS Version and XDG directory
set(WMFS_VERSION "201106")
if (NOT XDG_CONFIG_DIR)
set(XDG_CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/etc/wmfs")
endif ()
# Man prefix
if (NOT MANPREFIX)
set(MANPREFIX "${CMAKE_INSTALL_PREFIX}/share")
endif ()
# Libraries are optional
find_package(X11)
if (NOT X11_FOUND)
message(FATAL_ERROR "You need x11 libraries to build wmfs")
else ()
list(APPEND INCLUDES ${X11_INCLUDE_DIR})
list(APPEND LIBRARIES ${X11_LIBRARIES})
endif ()
# pthread is needed
set(CMAKE_THREAD_PREFER_PTHREAD)
find_package(Threads)
if (NOT CMAKE_USE_PTHREADS_INIT)
message(FATAL_ERROR "You need pthread libraries to build wmfs")
else ()
list(APPEND LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
endif ()
# The following are optional X11 libraries
if (X11_Xinerama_FOUND AND WITH_XINERAMA)
list(APPEND INCLUDES ${X11_Xinerama_INCLUDE_PATH})
list(APPEND LIBRARIES ${X11_Xinerama_LIB})
list(APPEND DEFINES "HAVE_XINERAMA")
else ()
list(APPEND DISABLED "HAVE_XINERAMA")
endif ()
if (X11_Xrandr_FOUND AND WITH_XRANDR)
list(APPEND INCLUDES ${X11_Xrandr_INCLUDE_PATH})
list(APPEND LIBRARIES ${X11_Xrandr_LIB})
list(APPEND DEFINES "HAVE_XRANDR")
else ()
list(APPEND DISABLED "HAVE_XRANDR")
endif ()
if (X11_Xft_FOUND AND WITH_XFT)
find_package(Freetype)
if (FREETYPE_FOUND)
list(APPEND INCLUDES ${FREETYPE_INCLUDE_DIRS}
${X11_Xft_INCLUDE_PATH})
list(APPEND LIBRARIES ${FREETYPE_LIBRARIES}
${X11_Xft_LIB})
list(APPEND DEFINES "HAVE_XFT")
else ()
list(APPEND DISABLED "HAVE_XFT")
endif ()
endif ()
if (WITH_IMLIB2)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(IMLIB2 imlib2)
if (IMLIB2_FOUND)
list(APPEND INCLUDES ${IMLIB2_INCLUDE_DIRS})
list(APPEND LIBRARIES ${IMLIB2_LIBRARIES})
list(APPEND DEFINES "HAVE_IMLIB")
link_directories(${IMLIB2_LIBRARY_DIRS})
else ()
list(APPEND DISABLED "HAVE_IMLIB")
endif ()
else ()
list(APPEND DISABLED "HAVE_IMLIB")
endif ()
endif ()
# Enable the optional module to compilation
foreach (modname ${DEFINES})
add_definitions(-D${modname})
# Set a variable to print all enabled modules.
# Remove the HAVE_ from module names
string(SUBSTRING ${modname} 5 -1 upcase)
string(TOLOWER ${upcase} module)
message("INFO: ${module} enabled")
endforeach ()
# Show modules disabled
foreach (modname ${DISABLED})
string(SUBSTRING ${modname} 5 -1 upcase)
string(TOLOWER ${upcase} module)
message("INFO: ${module} disabled")
endforeach ()
file(
GLOB
SOURCES
src/*.c
src/*.h
)
# Add definitions for the version and XDG
add_definitions(-DWMFS_VERSION=\"${WMFS_VERSION}\")
add_definitions(-DXDG_CONFIG_DIR=\"${XDG_CONFIG_DIR}\")
include_directories(${INCLUDES})
add_executable(wmfs ${SOURCES})
target_link_libraries(wmfs ${LIBRARIES})
# Install targets
install(TARGETS wmfs DESTINATION bin/)
install(FILES wmfsrc DESTINATION ${XDG_CONFIG_DIR}/)
install(FILES wmfs.1 DESTINATION ${MANPREFIX}/man1/)

View File

@ -24,4 +24,3 @@
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE. SUCH DAMAGE.

View File

@ -1,34 +1,28 @@
PROG=wmfs PROG=wmfs
MAN=wmfs.1
# wmfs version # wmfs version
VERSION=$(shell scripts/setlocalversion) VERSION=$(shell scripts/setlocalversion)
SRCS= \ SRCS= \
src/barwin.c \ src/barwin.c \
src/client.c \ src/config.c \
src/config.c \ src/client.c \
src/draw.c \ src/event.c \
src/event.c \ src/ewmh.c \
src/ewmh.c \ src/infobar.c \
src/frame.c \ src/layout.c \
src/infobar.c \ src/launcher.c \
src/init.c \ src/parse_api.c \
src/launcher.c \ src/parse.c \
src/layout.c \ src/screen.c \
src/menu.c \ src/tag.c \
src/mouse.c \ src/util.c \
src/parse_api.c \ src/status.c \
src/parse.c \ src/systray.c \
src/screen.c \ src/mouse.c \
src/status.c \ src/log.c \
src/systray.c \ src/wmfs.c
src/tag.c \
src/util.c \
src/color.c \
src/split.c \
src/cfactor.c \
src/wmfs.c
# flags # flags
CFLAGS+= -DXDG_CONFIG_DIR=\"${XDG_CONFIG_DIR}\" CFLAGS+= -DXDG_CONFIG_DIR=\"${XDG_CONFIG_DIR}\"
@ -37,21 +31,18 @@ CFLAGS+= -Wall -Wextra
OBJS= ${SRCS:.c=.o} OBJS= ${SRCS:.c=.o}
all: ${PROG} ${MAN}.gz all: ${PROG}
${PROG}: ${OBJS} src/structs.h src/wmfs.h src/parse.h ${PROG}: ${OBJS}
${CC} -o $@ ${OBJS} ${LDFLAGS} ${CC} -o $@ ${OBJS} ${LDFLAGS}
${MAN}.gz: ${MAN}
gzip -cn -9 ${MAN} > $@
.c.o: .c.o:
${CC} -c ${CFLAGS} $< -o $@ ${CC} -c ${CFLAGS} $< -o $@
.PHONY: all clean distclean install uninstall dist .PHONY: all clean distclean install uninstall dist
clean: clean:
rm -f ${OBJS} wmfs ${MAN}.gz rm -f ${OBJS} wmfs
distclean: clean distclean: clean
rm -f Makefile rm -f Makefile
@ -60,26 +51,25 @@ install: all
@echo installing executable file to ${DESTDIR}${PREFIX}/bin @echo installing executable file to ${DESTDIR}${PREFIX}/bin
mkdir -p ${DESTDIR}${PREFIX}/bin mkdir -p ${DESTDIR}${PREFIX}/bin
install ${PROG} ${DESTDIR}${PREFIX}/bin install ${PROG} ${DESTDIR}${PREFIX}/bin
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
mkdir -p ${DESTDIR}${MANPREFIX}/man1
install -m 644 ${MAN}.gz ${DESTDIR}${MANPREFIX}/man1/
@echo installing xsession file to ${DESTDIR}${PREFIX}/share/xsessions @echo installing xsession file to ${DESTDIR}${PREFIX}/share/xsessions
mkdir -p ${DESTDIR}${PREFIX}/share/xsessions mkdir -p ${DESTDIR}${PREFIX}/share/xsessions
install -m 644 wmfs.desktop ${DESTDIR}${PREFIX}/share/xsessions/ install -m 444 wmfs.desktop ${DESTDIR}${PREFIX}/share/xsessions
@echo installing default config file to ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/ @echo installing default config file to ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
mkdir -p ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/ mkdir -p ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
install -m 444 wmfsrc ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/ install -m 444 wmfsrc ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
@echo installing manual pages to ${DESTDIR}${MANPREFIX}/man1/
mkdir -p ${DESTDIR}${MANPREFIX}/man1/
install -m 644 wmfs.1 ${DESTDIR}${MANPREFIX}/man1/wmfs.1
uninstall: uninstall:
@echo removing executable file from ${DESTDIR}${PREFIX}/bin @echo removing executable file from ${DESTDIR}${PREFIX}/bin
rm -f ${DESTDIR}${PREFIX}/bin/wmfs rm -f ${DESTDIR}${PREFIX}/bin/wmfs
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
rm -f ${DESTDIR}${MANPREFIX}/man1/wmfs.1.gz
@echo removing xsession file from ${DESTDIR}${PREFIX}/share/xsessions @echo removing xsession file from ${DESTDIR}${PREFIX}/share/xsessions
rm -f ${DESTDIR}${PREFIX}/share/xsessions/wmfs.desktop
@echo removing config file from ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/ @echo removing config file from ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
rm -f ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/wmfsrc rm -f ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/wmfsrc
rmdir ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/ rmdir ${DESTDIR}${XDG_CONFIG_DIR}/wmfs/
@echo removing manual pages from ${DESTDIR}${MANPREFIX}/man1
rm -f ${DESTDIR}${MANPREFIX}/man1/wmfs.1
dist: dist:
@echo "Generate wmfs-`date +%Y%m`.tar.gz" @echo "Generate wmfs-`date +%Y%m`.tar.gz"

44
README
View File

@ -1,43 +1 @@
ABOUT : next WMFS dev branch.
WMFS Window Manager.
* Window Manager From Scratch
A highly configurable and manageable tiling Window Manager created from scratch
AUTHOR :
- Martin Duquesnoy <xorg62@gmail.com>
CONTRIBUTORS :
- Philippe Pepiot <phil@philpep.org>
- Marc Lagrange <markocpc@gmail.com>
- OldMan <tele-post@mail.ru>
- Raphael Khaiat <raphael@khaiat.org>
- Tomáš Chvátal <scarabeus@gentoo.org>
- David Delassus <linkdd@ydb.me>
- David Demelier <markand@malikania.fr>
LICENSE : BSD, see COPYING.
REQUIREMENT :
- libx11
- libxft (optional)
- freetype
- libxinerama (optional)
- libxrandr (optional)
- imlib2 (optional)
- cmake>=2.8 (build system, optional)
OS :
- GNU/Linux : Supported.
- FreeBSD/OpenBSD/NetBSD : Supported.
INSTALL :
mkdir build/ && cd build/
cmake ..
You can also use old build system if you don't want^Whave cmake
./configure && make
DISTROS :
- wmfs port for FreeBSD at x11-wm/wmfs
- wmfs is available with AUR in ArchLinux (wmfs or wmfs-git)

24
TODO
View File

@ -1,24 +0,0 @@
,
dM
MMr
4MMML .
MMMMM. xf
. "M6MMM .MM-
Mh.. +MM5MMM .MMMM
.MMM. .MMMMML. MMMMMh
)MMMh. MM5MMM MMMMMMM
3MMMMx. 'MMM3MMf xnMMMMMM"
'*MMMMM MMMMMM. nMMMMMMP"
*MMMMMx "MMM5M\ .MMMMMMM=
*MMMMMh "MMMMM" JMMMMMMP
MMMMMM GMMMM. dMMMMMM .
MMMMMM "MMMM .MMMMM( .nnMP"
.. *MMMMx MMM" dMMMM" .nnMMMMM*
"MMn... 'MMMMr 'MM MMM" .nMMMMMMM*"
"4MMMMnn.. *MMM MM MMP" .dMMMMMMM""
^MMMMMMMMx. *ML "M .M* .MMMMMM**"
*PMMMMMMhn. *x > M .MMMM**""
""**MMMMhx/.h/ .=*"
.3P"%....
nP" "*MMnx

46
configure vendored
View File

@ -14,38 +14,32 @@ while true; do
case "$1" in case "$1" in
--without-xinerama) --without-xinerama)
USE_XINERAMA=""; shift;; USE_XINERAMA=""; shift;;
--without-xrandr)
USE_XRANDR=""; shift;;
--without-imlib2) --without-imlib2)
USE_IMLIB2=""; shift;; USE_IMLIB2=""; shift;;
--without-xft)
USE_XFT=""; shift;;
--prefix) --prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1 [ -z "$2" ] && echo "Missing argument" && exit 1
PREFIX=$2; shift 2;; PREFIX=$2; shift 2;;
--xdg-config-dir)
[ -z "$2" ] && echo "Missing argument" && exit 1
XDG_CONFIG_DIR=$2; shift 2;;
--man-prefix) --man-prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1 [ -z "$2" ] && echo "Missing argument" && exit 1
MANPREFIX=$2; shift 2;; MANPREFIX=$2; shift 2;;
--xdg-config-dir)
[ -z "$2" ] && echo "Missing argument" && exit 1
XDG_CONFIG_DIR=$2; shift 2;;
--help|-h) --help|-h)
echo "Usage: ./configure [options] echo "Usage: ./configure [options]
--without-imlib2 : compile without imlib2 support
--without-xrandr : compile without xrandr support
--without-xinerama : compile without xinerama support --without-xinerama : compile without xinerama support
--without-xft : compile without xft support --without-imlib2 : compile without imlib2 support
--prefix DIRECTORY : install binary with specified prefix (default $PREFIX) --prefix DIRECTORY : install binary with specified prefix (default $PREFIX)
--xdg-config-dir DIRECTORY : install configuration to specified directory (default $XDG_CONFIG_DIR) --man-prefix DIRECTORY : install binary with specified prefix (default $PREFIX)
--man-prefix DIRECTORY : install man page to specified prefix (default $MANPREFIX)" --xdg-config-dir DIRECTORY : install configuration to specified directory (default $XDG_CONFIG_DIR)"
exit 0;; exit 0;;
*) break;; *) break;;
esac esac
done done
LIBS="$LIBS $USE_XINERAMA $USE_XRANDR $USE_IMLIB2 $USE_XFT" LIBS="$LIBS $USE_XINERAMA $USE_IMLIB2"
which pkg-config >/dev/null 2>&1 which pkg-config > /dev/null 2>&1
if [ $? -eq 0 ]; if [ $? -eq 0 ];
then then
@ -55,16 +49,16 @@ else
# Try to use some known paths # Try to use some known paths
case $OS in case $OS in
FreeBSD) FreeBSD)
CFLAGS="-I/usr/local/include -I/usr/local/include/freetype2" CFLAGS="-I/usr/local/include"
LDFLAGS="-L/usr/local/lib";; LDFLAGS="-L/usr/local/lib";;
OpenBSD) OpenBSD)
CFLAGS="-I/usr/X11R6/include -I/usr/X11R6/include/freetype2 -I/usr/local/include" CFLAGS="-I/usr/X11R6/include -I/usr/local/include"
LDFLAGS="-L/usr/X11R6/lib -L/usr/local/lib";; LDFLAGS="-L/usr/X11R6/lib -L/usr/local/lib";;
NetBSD) NetBSD)
CFLAGS="-I/usr/X11R7/include -I/usr/X11R7/include/freetype2 -I/usr/local/include" CFLAGS="-I/usr/X11R7/include -I/usr/pkg/include"
LDFLAGS="-L/usr/X11R7/lib -L/usr/local/lib";; LDFLAGS="-L/usr/X11R7/lib -L/usr/pkg/lib";;
Linux) Linux)
CFLAGS="-I/usr/include/freetype2" CFLAGS=""
LDFLAGS="" LDFLAGS=""
;; ;;
*) *)
@ -75,17 +69,19 @@ else
LDFLAGS="$LDFLAGS -lX11" LDFLAGS="$LDFLAGS -lX11"
[ -n "$USE_XINERAMA" ] && LDFLAGS="$LDFLAGS -lXinerama" [ -n "$USE_XINERAMA" ] && LDFLAGS="$LDFLAGS -lXinerama"
[ -n "$USE_XRANDR" ] && LDFLAGS="$LDFLAGS -lXrandr"
[ -n "$USE_IMLIB2" ] && LDFLAGS="$LDFLAGS -lImlib2" [ -n "$USE_IMLIB2" ] && LDFLAGS="$LDFLAGS -lImlib2"
[ -n "$USE_XFT" ] && LDFLAGS="$LDFLAGS -lXft -lfreetype"
fi fi
[ -n "$USE_XINERAMA" ] && CFLAGS="$CFLAGS -DHAVE_XINERAMA" [ -n "$USE_XINERAMA" ] && CFLAGS="$CFLAGS -DHAVE_XINERAMA"
[ -n "$USE_XRANDR" ] && CFLAGS="$CFLAGS -DHAVE_XRANDR" [ -n "$USE_IMLIB2" ] && CFLAGS="$CFLAGS -DHAVE_IMLIB2"
[ -n "$USE_IMLIB2" ] && CFLAGS="$CFLAGS -DHAVE_IMLIB"
[ -n "$USE_XFT" ] && CFLAGS="$CFLAGS -DHAVE_XFT"
LDFLAGS="$LDFLAGS -lpthread" # Debian hardening options http://wiki.debian.org/Hardening
which dpkg-buildflags > /dev/null 2>&1
if [ $? -eq 0 ];
then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 `dpkg-buildflags --get CFLAGS`"
LDFLAGS="$LDFLAGS `dpkg-buildflags --get LDFLAGS`"
fi
cat > Makefile << EOF cat > Makefile << EOF
PREFIX=$PREFIX PREFIX=$PREFIX

45
debian/changelog vendored Normal file
View File

@ -0,0 +1,45 @@
wmfs (2~beta201206-3) unstable; urgency=low
* No hardening-related Lintiant warnings
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sun, 24 Jun 2012 16:40:54 +0200
wmfs (2~beta201206-2) unstable; urgency=low
* Fixed some Lintian warnings
* New standards version
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sun, 24 Jun 2012 15:19:38 +0200
wmfs (2~beta201206-1) unstable; urgency=low
* Updated changelog version
* Added build-depends to the control file
* Updated Vcs-* fields in the control file
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sun, 24 Jun 2012 13:12:26 +0200
wmfs (2~beta-3) unstable; urgency=low
* Modified build script (debian/rules)
* Modified versions in changelog
* Removed the old manpage
* The configuration is done in override_dh_auto_configure (in debian/rules)
* The .desktop file is installed by dh_install
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sat, 18 Feb 2012 19:40:09 +0100
wmfs (2~beta-2) unstable; urgency=low
* Added a manpage
* Modified the debian/rules script
* Filled debian/copying
* Added dependencies
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sat, 28 Jan 2012 12:44:18 +0100
wmfs (2~beta-1) unstable; urgency=low
* Initial release
-- Mickaël Raybaud-Roig <raybaudroigm@gmail.com> Sat, 21 Jan 2012 13:22:37 +0100

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
8

16
debian/control vendored Normal file
View File

@ -0,0 +1,16 @@
Source: wmfs
Section: x11
Priority: extra
Maintainer: Mickaël Raybaud-Roig <raybaudroigm@gmail.com>
Build-Depends: debhelper (>= 8.0.0), libimlib2-dev, libxinerama-dev, libx11-dev
Standards-Version: 3.9.3
Homepage: http://wmfs.info
Vcs-Git: git://github.com/xorg62/wmfs.git
Vcs-Browser: https://github.com/xorg62/wmfs
Package: wmfs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libxinerama1, libimlib2, libxcb1, libfreetype6
Description: Window Manager From Scratch
WMFS (Window Manager From Scratch) is a lightweight and highly configurable
tiling window manager for X.

54
debian/copyright vendored Normal file
View File

@ -0,0 +1,54 @@
Format: http://dep.debian.net/deps/dep5
Upstream-Name: wmfs
Source: http://wmfs.info
Files: *
Copyright: 2011-2012 Martin Duquesnoy <xorg62@gmail.com>
License: BSD-3-Clauses
Files: debian/*
Copyright: 2012 Mickaël Raybaud-Roig <raybaudroigm@gmail.com>
License: WTFPL-2
License: BSD-3-Clauses
Copyright (c) 1983 The Regents of the University of California.
All rights reserved.
.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
License: WTFPL-2
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
.
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
.
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
.
0. You just DO WHAT THE FUCK YOU WANT TO.

1
debian/docs vendored Normal file
View File

@ -0,0 +1 @@
README

16
debian/rules vendored Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
override_dh_auto_configure:
./configure --prefix /usr --xdg-config-dir /etc/xdg --man-prefix /usr/share/man/
%:
dh $@

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (quilt)

1
debian/wmfs.install vendored Normal file
View File

@ -0,0 +1 @@
wmfs.desktop /usr/share/xsessions

1
debian/wmfs.manpages vendored Normal file
View File

@ -0,0 +1 @@
wmfs.1

1
debian/wmfs.wm vendored Normal file
View File

@ -0,0 +1 @@
/usr/bin/wmfs

64
scripts/keybind_help.sh Executable file
View File

@ -0,0 +1,64 @@
#! /bin/sh
# simple help script for WMFS2 by arpinux
# default keybinds list
xpos="5"
ypos="5"
width="350"
height="730"
bg="#222222"
fg="#7D7D7D"
l01="^s[80;12;$bg;WMFS² Keybinds Help]"
l03="^s[15;35;$fg;launch terminal:]^s[190;35;$fg;Super + Return]"
l04="^s[15;50;$fg;launch prompt:]^s[190;50;$fg;Super + p]"
l05="^s[15;65;$fg;close client:]^s[190;65;$fg;Super + q]"
l06="^s[15;80;$fg;reload wmfs:]^s[190;80;$fg;Control + Alt + r]"
l07="^s[15;95;$fg;quit wmfs:]^s[190;95;$fg;Control + Alt + q]"
l08="^s[15;115;$fg;next client:]^s[190;115;$fg;Alt + Tab]"
l09="^s[15;130;$fg;prev client:]^s[190;130;$fg;Alt + Shift + Tab]"
l10="^s[15;145;$fg;next tabbed client:]^s[190;145;$fg;Super + Tab]"
l11="^s[15;160;$fg;prev tabbed client:]^s[190;160;$fg;Super + Shift + Tab]"
l12="^s[15;175;$fg;left client:]^s[190;175;$fg;Alt + h]"
l13="^s[15;190;$fg;right client:]^s[190;190;$fg;Alt + l]"
l14="^s[15;205;$fg;top client:]^s[190;205;$fg;Alt + k]"
l15="^s[15;220;$fg;bottom client:]^s[190;220;$fg;Alt + j]"
l16="^s[15;235;$fg;swap client left:]^s[190;235;$fg;Control + Shift + h]"
l17="^s[15;250;$fg;swap client right:]^s[190;250;$fg;Control + Shift + l]"
l18="^s[15;265;$fg;swap client top:]^s[190;265;$fg;Control + Shift + k]"
l19="^s[15;280;$fg;swap client bottom:]^s[190;280;$fg;Control + Shift + j]"
l20="^s[15;295;$fg;tab client left:]^s[190;295;$fg;Alt + Shift + h]"
l21="^s[15;310;$fg;tab client right:]^s[190;310;$fg;Alt + Shift + l]"
l22="^s[15;325;$fg;tab client top:]^s[190;325;$fg;Alt + Shift + k]"
l23="^s[15;340;$fg;tab client bottom:]^s[190;340;$fg;Alt + Shift + j]"
l24="^s[15;355;$fg;untab client:]^s[190;355;$fg;Alt + Shift + u]"
l25="^s[15;375;$fg;increase client on left:]^s[190;375;$fg;Super + h]"
l26="^s[15;390;$fg;decrease client from left:]^s[190;390;$fg;Super + l]"
l27="^s[15;405;$fg;increase client on top:]^s[190;405;$fg;Super + k]"
l28="^s[15;420;$fg;decrease client from top:]^s[190;420;$fg;Super + j]"
l29="^s[15;435;$fg;decrease client from right:]^s[190;435;$fg;Super + Control + h]"
l30="^s[15;450;$fg;increase client on right:]^s[190;450;$fg;Super + Control + l]"
l31="^s[15;465;$fg;decrease client from bottom:]^s[190;465;$fg;Super + Control + k]"
l32="^s[15;480;$fg;increase client to bottom:]^s[190;480;$fg;Super + Control + j]"
l33="^s[15;495;$fg;integrate client to left:]^s[190;495;$fg;Super + Control + Alt + h]"
l34="^s[15;510;$fg;integrate client to right:]^s[190;510;$fg;Super + Control + Alt + l]"
l35="^s[15;525;$fg;integrate client to top:]^s[190;525;$fg;Super + Control + Alt + k]"
l36="^s[15;540;$fg;integrate client to bottom:]^s[190;540;$fg;Super + Control + Alt + j]"
l37="^s[15;560;$fg;horizontal layout:]^s[190;560;$fg;Super + Shift + m]"
l38="^s[15;575;$fg;vertical layout:]^s[190;575;$fg;Super + m]"
l39="^s[15;590;$fg;layout rotate right:]^s[190;590;$fg;Super + r]"
l40="^s[15;605;$fg;layout rotate left:]^s[190;605;$fg;Super + Shift + r]"
l41="^s[15;620;$fg;toggle client free:]^s[190;620;$fg;Super + f]"
l42="^s[15;640;$fg;prev/next tag:]^s[190;640;$fg;Control + Left/Right]"
l43="^s[15;655;$fg;prev/next screen:]^s[190;655;$fg;Control + Up/Down]"
l44="^s[15;670;$fg;set tag (x):]^s[190;670;$fg;Super + F(x)]"
l45="^s[15;685;$fg;tag client with (x):]^s[190;685;$fg;Super + Shift + F(x)]"
l46="^s[15;700;$fg;add tag:]^s[190;700;$fg;Super + Shift + -]"
l47="^s[15;715;$fg;delete tag:]^s[190;715;$fg;Super + -]"
frame="^R[0;0;350;15;$fg] ^R[0;728;350;2;$fg] ^R[0;0;2;730;$fg] ^R[348;0;2;730;$fg]"
wmfs -c status_surface "$xpos,$ypos,$width,$height,$bg $frame $l01 $l03 $l04 $l05 $l06 $l07 $l08 $l09 $l10 $l11 $l12 $l13 $l14 $l15 $l16 $l17 $l18 $l19 $l20 $l21 $l22 $l23 $l24 $l25 $l26 $l27 $l28 $l29 $l30 $l31 $l32 $l33 $l34 $l35 $l36 $l37 $l38 $l39 $l40 $l41 $l42 $l43 $l44 $l45 $l46 $l47"

View File

@ -1,11 +1,17 @@
#!/bin/sh #!/bin/sh
#WMFS status.sh example file #WMFS status.sh example file
#Will be executed if put in ~/.config/wmfs/
#Timing adjustable in wmfsrc (misc -> status_timing) TIMING=10
statustext() statustext()
{ {
wmfs -s "`date`" # Syntax : status <bar name> <data>
# possible sequences as data: \s[] \R[] \i[]
wmfs -c status "default `date`"
} }
while true; do statustext; sleep 10; done while true;
do
statustext
sleep $TIMING
done

View File

@ -1,241 +1,107 @@
/* /*
* barwin.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h" #include "wmfs.h"
#include "barwin.h"
#include "util.h"
/** Create a BarWindow /** Create a barwin
* \param parent Parent window of the BarWindow * \param parent Parent window of the BarWindow
* \param x X position * \param x X position
* \param y Y position * \param y Y position
* \param w BarWindow Width * \param w barwin Width
* \param h BarWindow Height * \param h barwin Height
* \param color BarWindow color * \param color barwin color
* \param entermask bool for know if the EnterMask mask is needed * \param entermask bool for know if the EnterMask mask is needed
* \return The BarWindow pointer * \return The BarWindow pointer
*/ */
BarWindow* struct barwin*
barwin_create(Window parent, barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool entermask)
int x,
int y,
int w,
int h,
uint bg,
char *fg,
bool entermask,
bool stipple,
bool border)
{ {
XSetWindowAttributes at; struct barwin *b = (struct barwin*)xcalloc(1, sizeof(struct barwin));
BarWindow *bw; XSetWindowAttributes at =
{
/* Allocate memory */ .override_redirect = true,
bw = zcalloc(sizeof(*bw)); .background_pixmap = ParentRelative,
.event_mask = BARWIN_MASK
/* Barwin attributes */ };
at.override_redirect = True;
at.background_pixmap = ParentRelative;
at.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
|ButtonMask|MouseMask
|ExposureMask|VisibilityChangeMask
|StructureNotifyMask|SubstructureRedirectMask;
if(entermask) if(entermask)
at.event_mask |= EnterWindowMask|LeaveWindowMask|FocusChangeMask; at.event_mask |= BARWIN_ENTERMASK;
/* Create window */ /* Create window */
bw->win = XCreateWindow(dpy, parent, x, y, w, h, 0, DefaultDepth(dpy, SCREEN), b->win = XCreateWindow(W->dpy, parent,
CopyFromParent, DefaultVisual(dpy, SCREEN), x, y, w, h,
CWOverrideRedirect | CWBackPixmap | CWEventMask, &at); 0, W->xdepth,
bw->dr = XCreatePixmap(dpy, parent, w, h, DefaultDepth(dpy, SCREEN)); CopyFromParent,
DefaultVisual(W->dpy, W->xscreen),
BARWIN_WINCW,
&at);
/* His border */ b->dr = XCreatePixmap(W->dpy, parent, w, h, W->xdepth);
if(border)
{
bw->flags |= BordFlag;
bw->border.light = color_shade(bg, conf.colors.bar_light_shade);
bw->border.dark = color_shade(bg, conf.colors.bar_dark_shade);
CWIN(bw->border.left, bw->win, 0, 0, SHADH, h, 0, CWBackPixel, bg, &at);
CWIN(bw->border.top, bw->win, 0, 0, w, SHADH, 0, CWBackPixel, bg, &at);
CWIN(bw->border.bottom, bw->win, 0, h - SHADH, w, SHADH, 0, CWBackPixel, bg, &at);
CWIN(bw->border.right, bw->win, w - SHADH, 0, SHADH, h, 0, CWBackPixel, bg, &at);
}
/* Property */ /* Property */
bw->geo.x = x; b->geo.x = x;
bw->geo.y = y; b->geo.y = y;
bw->geo.width = w; b->geo.w = w;
bw->geo.height = h; b->geo.h = h;
bw->bg = bg; b->bg = bg;
bw->fg = fg; b->fg = fg;
FLAGAPPLY(bw->flags, stipple, StippleFlag);
bw->stipple_color = 0xffffffff; SLIST_INIT(&b->mousebinds);
SLIST_INIT(&b->statusmousebinds);
/* Attach */ /* Attach */
SLIST_INSERT_HEAD(&bwhead, bw, next); SLIST_INSERT_HEAD(&W->h.barwin, b, next);
return bw; return b;
} }
/** Draw text in a Barwindow /** Delete a barwin
* \param bw barwin pointer
*/ */
void void
barwin_draw_text(BarWindow *bw, int x, int y, char *text) barwin_remove(struct barwin *b)
{ {
/* Background color of the text if there is stipple */ SLIST_REMOVE(&W->h.barwin, b, barwin, next);
if(bw->flags & StippleFlag)
draw_rectangle(bw->dr, x - 4, 0, textw(text) + 8, bw->geo.height, bw->bg);
/* Draw text */ XSelectInput(W->dpy, b->win, NoEventMask);
draw_text(bw->dr, x, y, bw->fg, text); XDestroyWindow(W->dpy, b->win);
XFreePixmap(W->dpy, b->dr);
barwin_refresh(bw); free(b);
return;
} }
void /** Resize a barwin
barwin_color_set(BarWindow *bw, uint bg, char *fg) * \param bw barwin pointer
{
bw->bg = bg;
bw->fg = fg;
if(bw->flags & BordFlag)
{
bw->border.light = color_shade(bg, conf.colors.bar_light_shade);
bw->border.dark = color_shade(bg, conf.colors.bar_dark_shade);
}
if(bw->flags & StippleFlag && bw->stipple_color == 0xffffffff)
bw->stipple_color = getcolor(fg);
return;
}
/** Delete a BarWindow
* \param bw BarWindow pointer
*/
void
barwin_delete(BarWindow *bw)
{
SLIST_REMOVE(&bwhead, bw, BarWindow, next);
XSelectInput(dpy, bw->win, NoEventMask);
XDestroyWindow(dpy, bw->win);
XFreePixmap(dpy, bw->dr);
free(bw);
return;
}
/** Move a BarWindow
* \param bw BarWindow pointer
* \param x X position
* \param y Y poistion
*/
void
barwin_move(BarWindow *bw, int x, int y)
{
if(bw->geo.x == x && bw->geo.y == y)
return;
XMoveWindow(dpy, bw->win, (bw->geo.x = x), (bw->geo.y = y));
return;
}
/** Resize a BarWindow
* \param bw BarWindow pointer
* \param w Width * \param w Width
* \param h Height * \param h Height
*/ */
void void
barwin_resize(BarWindow *bw, int w, int h) barwin_resize(struct barwin *b, int w, int h)
{ {
if(bw->geo.width == w && bw->geo.height == h)
return;
/* Frame */ /* Frame */
XFreePixmap(dpy, bw->dr); XFreePixmap(W->dpy, b->dr);
bw->dr = XCreatePixmap(dpy, ROOT, b->dr = XCreatePixmap(W->dpy, W->root, w, h, W->xdepth);
w - ((bw->flags & BordFlag) ? SHADH : 0),
h - ((bw->flags & BordFlag) ? SHADH : 0),
DefaultDepth(dpy, SCREEN));
bw->geo.width = w; b->geo.w = w;
bw->geo.height = h; b->geo.h = h;
XResizeWindow(dpy, bw->win, w, h); XResizeWindow(W->dpy, b->win, w, h);
/* Border */
if(bw->flags & BordFlag)
{
XResizeWindow(dpy, bw->border.left, SHADH, h);
XResizeWindow(dpy, bw->border.top, w, SHADH);
XResizeWindow(dpy, bw->border.bottom, w, SHADH);
XMoveResizeWindow(dpy, bw->border.right, w - SHADH, 0, SHADH, h);
}
return;
} }
/** Refresh the BarWindow Color /** Refresh the barwin Color
* \param bw BarWindow pointer * \param bw barwin pointer
*/ */
void void
barwin_refresh_color(BarWindow *bw) barwin_refresh_color(struct barwin *b)
{ {
XSetForeground(dpy, gc, bw->bg); XSetForeground(W->dpy, W->gc, b->bg);
XFillRectangle(dpy, bw->dr, gc, 0, 0, bw->geo.width, bw->geo.height); XFillRectangle(W->dpy, b->dr, W->gc, 0, 0, b->geo.w, b->geo.h);
if(bw->flags & StippleFlag)
{
XSetForeground(dpy, gc_stipple, bw->stipple_color);
XFillRectangle(dpy, bw->dr, gc_stipple, 3, 2, bw->geo.width - 6, bw->geo.height - 4);
}
if(bw->flags & BordFlag)
{
XSetWindowBackground(dpy, bw->border.left, bw->border.light);
XSetWindowBackground(dpy, bw->border.top, bw->border.light);
XSetWindowBackground(dpy, bw->border.bottom, bw->border.dark);
XSetWindowBackground(dpy, bw->border.right, bw->border.dark);
XClearWindow(dpy, bw->border.left);
XClearWindow(dpy, bw->border.top);
XClearWindow(dpy, bw->border.bottom);
XClearWindow(dpy, bw->border.right);
}
return;
} }

38
src/barwin.h Normal file
View File

@ -0,0 +1,38 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef BARWIN_H
#define BARWIN_H
#include "wmfs.h"
#define BARWIN_MASK \
(SubstructureRedirectMask | SubstructureNotifyMask \
| ButtonMask | MouseMask | ExposureMask | VisibilityChangeMask \
| StructureNotifyMask)
#define BARWIN_ENTERMASK (EnterWindowMask | LeaveWindowMask | FocusChangeMask)
#define BARWIN_WINCW (CWOverrideRedirect | CWBackPixmap | CWEventMask)
#define barwin_delete_subwin(b) XDestroySubwindows(W->dpy, b->win)
#define barwin_map_subwin(b) XMapSubwindows(W->dpy, b->win)
#define barwin_unmap_subwin(b) XUnmapSubwindows(W->dpy, b->win)
#define barwin_refresh(b) XCopyArea(W->dpy, b->dr, b->win, W->gc, 0, 0, b->geo.w, b->geo.h, 0, 0)
#define barwin_map(b) XMapWindow(W->dpy, b->win);
#define barwin_unmap(b) XUnmapWindow(W->dpy, b->win);
#define barwin_reparent(b, w) XReparentWindow(W->dpy, b->win, w, 0, 0);
static inline void
barwin_move(struct barwin *b, int x, int y)
{
XMoveWindow(W->dpy, b->win, (b->geo.x = x), (b->geo.y = y));
}
struct barwin* barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool entermask);
void barwin_remove(struct barwin *b);
void barwin_resize(struct barwin *b, int w, int h);
void barwin_refresh_color(struct barwin *b);
#endif /* BARWIN_H */

View File

@ -1,279 +0,0 @@
/*
* cfactor.c
* Copyright © 2011 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
#define CLIENT_RESIZE_DIR(d) \
void \
uicb_client_resize_##d(uicb_t cmd) \
{ \
CHECK(sel); \
cfactor_set(sel, d, atoi(cmd)); \
}
/* uicb_client_resize_dir() */
CLIENT_RESIZE_DIR(Right);
CLIENT_RESIZE_DIR(Left);
CLIENT_RESIZE_DIR(Top);
CLIENT_RESIZE_DIR(Bottom);
/** Clean client tile factors
*\param c Client pointer
*/
void
cfactor_clean(Client *c)
{
CHECK(c);
if(!(tags[c->screen][c->tag].flags & (SplitFlag | CleanFactFlag)))
return;
c->tilefact[Right] = c->tilefact[Left] = 0;
c->tilefact[Top] = c->tilefact[Bottom] = 0;
return;
}
/** Return new geo of client with factors applied
*\param c Client pointer
*\return geo
*/
Geo
cfactor_geo(Geo geo, int fact[4], int *err)
{
Geo cgeo = geo;
*err = 0;
/* Right factor */
cgeo.width += fact[Right];
/* Left factor */
cgeo.x -= fact[Left];
cgeo.width += fact[Left];
/* Top factor */
cgeo.y -= fact[Top];
cgeo.height += fact[Top];
/* Bottom factor */
cgeo.height += fact[Bottom];
/* Too big/small */
if(cgeo.width > sgeo[selscreen].width || cgeo.height > sgeo[selscreen].height
|| cgeo.width < (BORDH << 1) || cgeo.height < (BORDH + TBARH))
{
*err = 1;
return geo;
}
return cgeo;
}
/** Get c parents of row and resize
*\param c Client pointer
*\param p Direction of resizing
*\param fac Factor of resizing
*/
static void
_cfactor_arrange_row(Client *c, Position p, int fac)
{
Geo cgeo = c->frame_geo;
Client *cc = tiled_client(c->screen, SLIST_FIRST(&clients));
/* Travel clients to search parents of row and apply fact */
for(; cc; cc = tiled_client(c->screen, SLIST_NEXT(cc, next)))
if(CFACTOR_PARENTROW(cgeo, cc->frame_geo, p))
{
cc->tilefact[p] += fac;
client_moveresize(cc, cc->geo, (tags[cc->screen][cc->tag].flags & ResizeHintFlag));
}
return;
}
/** Get c parents of row and check geo with futur resize factor
*\param c Client pointer
*\param p Direction of resizing
*\param fac Factor of resizing
*\return False in case of error
*/
static bool
_cfactor_check_geo_row(Client *c, Position p, int fac)
{
Geo cgeo = c->frame_geo;
Client *cc = tiled_client(c->screen, SLIST_FIRST(&clients));
int e, f[4] = { 0 };
f[p] += fac;
/* Travel clients to search parents of row and check geos */
for(; cc; cc = tiled_client(c->screen, SLIST_NEXT(cc, next)))
if(CFACTOR_PARENTROW(cgeo, cc->frame_geo, p))
{
(Geo)cfactor_geo(cc->wrgeo, f, &e);
if(e)
return False;
}
return True;
}
/* Resize only 2 client with applied factor
*\param c1 Client pointer
*\param c2 Client pointer
*\param p Direction of resizing
*\param fac Facotr
*/
static void
cfactor_arrange_two(Client *c1, Client *c2, Position p, int fac)
{
c1->tilefact[p] += fac;
c2->tilefact[RPOS(p)] -= fac;
/* Needed in case of padding */
if(conf.client.padding)
{
c1->flags |= FLayFlag;
c2->flags |= FLayFlag;
}
client_moveresize(c1, c1->geo, (tags[c1->screen][c1->tag].flags & ResizeHintFlag));
client_moveresize(c2, c2->geo, (tags[c2->screen][c2->tag].flags & ResizeHintFlag));
return;
}
/** Get c parents of row and resize, exception checking same size before arranging row
*\param c Client pointer
*\param gc Client pointer
*\param p Direction of resizing
*\param fac Factor of resizing
*/
static void
cfactor_arrange_row(Client *c, Client *gc, Position p, int fac)
{
if(CFACTOR_CHECK2(c->frame_geo, gc->frame_geo, p))
cfactor_arrange_two(c, gc, p, fac);
else
{
_cfactor_arrange_row(c, p, fac);
_cfactor_arrange_row(gc, RPOS(p), -fac);
}
return;
}
/** Check future geometry of factorized client
*\param c Client pointer
*\param g Client pointer
*\param p Direction of resizing
*\param fac Factor of resizing
*/
static bool
cfactor_check_geo(Client *c, Client *g, Position p, int fac)
{
int e, ee;
int cf[4] = { 0 }, gf[4] = { 0 };
/* Check c & g first */
cf[p] += fac;
gf[RPOS(p)] -= fac;
(Geo)cfactor_geo(c->geo, cf, &e);
(Geo)cfactor_geo(g->geo, gf, &ee);
/* Size failure */
if(e || ee || !_cfactor_check_geo_row(c, p, fac)
|| !_cfactor_check_geo_row(g, RPOS(p), -fac))
return False;
return True;
}
/** Manual resizing of tiled clients
* \param c Client pointer
* \param p Direction of resizing
* \param fac Factor of resizing
*/
void
cfactor_set(Client *c, Position p, int fac)
{
Client *gc = NULL;
if(!c || !(c->flags & TileFlag) || p > Bottom)
return;
/* Get next client with direction of resize */
gc = client_get_next_with_direction(c, p);
if(!gc || c->screen != gc->screen)
return;
/* Check size */
if(!cfactor_check_geo(c, gc, p, fac))
return;
/* Arrange client and row parents */
cfactor_arrange_row(c, gc, p, fac);
/* Enable split with cfactor_enable_split option */
if(conf.cfactor_enable_split
&& !(tags[c->screen][c->tag].flags & SplitFlag))
{
tags[c->screen][c->tag].flags |= SplitFlag;
infobar_draw_layout(&infobar[c->screen]);
}
return;
}
/** Apply a complete factor array to a client
* \param c Client pointer
* \param fac factor array
*/
void
cfactor_multi_set(Client *c, int fac[4])
{
if(!c)
return;
cfactor_set(c, Right, fac[Right]);
cfactor_set(c, Left, fac[Left]);
cfactor_set(c, Top, fac[Top]);
cfactor_set(c, Bottom, fac[Bottom]);
return;
}

File diff suppressed because it is too large Load Diff

217
src/client.h Normal file
View File

@ -0,0 +1,217 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef CLIENT_H
#define CLIENT_H
#include <X11/XKBlib.h>
#include "wmfs.h"
#include "layout.h"
#include "ewmh.h"
#include "util.h"
#define TCLIENT_CHECK(C) (C->flags & CLIENT_TABBED && !(C->flags & CLIENT_TABMASTER))
/* SLIST_FOREACH for client with no free client */
#define FOREACH_NFCLIENT(V, H, F) \
SLIST_FOREACH(V, H, F) \
if(!(V->flags & CLIENT_FREE))
/* Are two clients compatibles ? (to be tabbed together) */
#define COMPCLIENT(C1, C2) ((C1->flags & CLIENT_IGNORE_TAG) == (C2->flags & CLIENT_IGNORE_TAG))
void client_configure(struct client *c);
struct client *client_gb_win(Window w);
struct client *client_gb_frame(Window w);
struct client *client_gb_pos(struct tag *t, int x, int y);
struct client *client_gb_titlebar(Window w);
struct client *client_next_with_pos(struct client *bc, enum position p);
void client_swap2(struct client *c1, struct client *c2);
void client_swap(struct client *c, enum position p);
#define CCOL(c) (c == W->client ? &c->scol : &c->ncol)
void client_frame_update(struct client *c, struct colpair *cp);
void client_tab_pull(struct client *c);
void _client_tab(struct client *c, struct client *cm);
void client_tab_focus(struct client *c);
void client_focus(struct client *c);
void uicb_client_focus_click(Uicb);
void client_get_name(struct client *c);
void client_close(struct client *c);
void uicb_client_close(Uicb cmd);
struct client *client_new(Window w, XWindowAttributes *wa, bool scan);
void client_geo_hints(struct geo *g, int *s);
void client_get_sizeh(struct client *c);
bool client_winsize(struct client *c, struct geo *geo);
void client_moveresize(struct client *c, struct geo *g);
void client_place_at_mouse(struct client *c);
void client_maximize(struct client *c);
void client_fac_resize(struct client *c, enum position p, int fac);
void client_fac_adjust(struct client *c);
void client_remove(struct client *c);
void client_free(void);
void _fac_resize(struct client *c, enum position p, int fac);
void client_apply_tgeo(struct tag *t);
#define CPROP_LOC 0x01
#define CPROP_FLAG 0x02
#define CPROP_GEO 0x04
#define CPROP_TAB 0x08
void client_update_props(struct client *c, Flags f);
void client_fac_hint(struct client *c);
void uicb_client_untab(Uicb cmd);
void uicb_client_toggle_free(Uicb cmd);
void uicb_client_toggle_ignore_tag(Uicb cmd);
void uicb_client_tab_next_opened(Uicb cmd);
/* Generated */
void uicb_client_resize_Right(Uicb);
void uicb_client_resize_Left(Uicb);
void uicb_client_resize_Top(Uicb);
void uicb_client_resize_Bottom(Uicb);
void uicb_client_focus_Right(Uicb);
void uicb_client_focus_Left(Uicb);
void uicb_client_focus_Top(Uicb);
void uicb_client_focus_Bottom(Uicb);
void uicb_client_tab_Right(Uicb);
void uicb_client_tab_Left(Uicb);
void uicb_client_tab_Top(Uicb);
void uicb_client_tab_Bottom(Uicb);
void uicb_client_swap_Right(Uicb);
void uicb_client_swap_Left(Uicb);
void uicb_client_swap_Top(Uicb);
void uicb_client_swap_Bottom(Uicb);
void uicb_client_focus_next(Uicb);
void uicb_client_focus_prev(Uicb);
void uicb_client_swapsel_next(Uicb);
void uicb_client_swapsel_prev(Uicb);
void uicb_client_focus_next_tab(Uicb);
void uicb_client_focus_prev_tab(Uicb);
static inline struct client*
client_next(struct client *c)
{
return (SLIST_NEXT(c, tnext)
? SLIST_NEXT(c, tnext)
: SLIST_FIRST(&c->tag->clients));
}
static inline struct client*
client_prev(struct client *c)
{
struct client *cc = SLIST_FIRST(&c->tag->clients);
while(SLIST_NEXT(cc, tnext) && SLIST_NEXT(cc, tnext) != c)
cc = SLIST_NEXT(cc, tnext);
return cc;
}
static inline struct client*
client_next_tab(struct client *c)
{
struct client *n = client_next(c);
if(!(c->flags & CLIENT_TABMASTER))
return NULL;
while((!(n->flags & CLIENT_TABBED) || n->tabmaster != c) && n != c)
n = client_next(n);
return n;
}
static inline struct client*
client_prev_tab(struct client *c)
{
struct client *p = client_prev(c);
if(!(c->flags & CLIENT_TABMASTER))
return NULL;
while((!(p->flags & CLIENT_TABBED) || p->tabmaster != c) && p != c)
p = client_prev(p);
return p;
}
static inline struct client*
client_tab_next(struct client *c)
{
return (c && c->tabmaster ? c->tabmaster : c);
}
static inline void
client_map(struct client *c)
{
if(!(c->flags & CLIENT_MAPPED))
{
WIN_STATE(c->frame, Map);
WIN_STATE(c->win, Map);
ewmh_set_wm_state(c->win, NormalState);
c->flags ^= CLIENT_MAPPED;
}
}
static inline void
client_unmap(struct client *c)
{
if(c->flags & CLIENT_MAPPED)
{
WIN_STATE(c->frame, Unmap);
WIN_STATE(c->win, Unmap);
ewmh_set_wm_state(c->win, IconicState);
c->flags ^= CLIENT_MAPPED;
}
}
static inline void
clients_arrange_map(void)
{
struct client *c;
SLIST_FOREACH(c, &W->h.client, next)
{
if(c->tag == c->screen->seltag && !(c->flags & CLIENT_TABBED))
client_map(c);
else
client_unmap(c);
}
}
static inline void
clients_tag_arrange_map(struct tag *t)
{
struct client *c;
void (*sfunc)(struct client*)
= (t == t->screen->seltag ? client_map : client_unmap);
SLIST_FOREACH(c, &t->clients, tnext)
sfunc(c);
}
static inline struct client*
client_get_larger(struct tag *t, bool ignoring_tag)
{
struct client *c, *lc = NULL;
int tmp, l = 0;
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
if((tmp = (c->geo.w + c->geo.h)) > l && (c->flags & CLIENT_IGNORE_TAG) == ignoring_tag)
{
l = tmp;
lc = c;
}
}
if(lc && (lc->flags & CLIENT_TABBED))
lc = lc->tabmaster;
return lc;
}
#endif /* CLIENT_H */

View File

@ -1,223 +0,0 @@
/*
* color.c
* Copyright © 2011 Brian Mock <mock.brian@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
/** Clamp a number x within the range [a, b].
* \param x the number which to clamp
* \param a the lowest possible value
* \param b the highest possible value
* \return the clamped number
*/
static double
color_clamp(double x, double a, double b)
{
if(x < a)
return a;
else if(x > b)
return b;
else
return x;
}
/** Pack a triplet of RGB values into a single uint
* \param r the red value
* \param g the green value
* \param b the blue value
* \return the packed RGB value
*/
static uint
color_pack_rgb(uint r, uint g, uint b)
{
return (r << 16) | (g << 8) | b;
}
/** Unpack an RGB uint into three separate values
* \param rgb the packed color
* \param r a pointer to a uint where the red value will be stored
* \param g a pointer to a uint where the green value will be stored
* \param b a pointer to a uint where the blue value will be stored
*/
static void
color_unpack_rgb(uint rgb, uint *r, uint *g, uint *b)
{
*r = (rgb >> 16) & 0xFF;
*g = (rgb >> 8) & 0xFF;
*b = rgb & 0xFF;
}
/** Convert unpacked RGB values into HSL, storing in the doubles referenced
* by the pointers h, s, l
*/
static void
color_rgb_to_hsl(uint xr, uint xg, uint xb, double *h, double *s, double *l)
{
double r = xr/255.0;
double g = xg/255.0;
double b = xb/255.0;
double v;
double m;
double vm;
double r2, g2, b2;
*h = 0;
*s = 0;
*l = 0;
/* v is max(r, g, b)
* m is min(r, g, b)
*/
v = r > g ? r : g;
v = v > b ? v : b;
m = r < g ? r : g;
m = m < b ? m : b;
*l = (m + v)/2.0;
if(*l <= 0.0)
return;
vm = v - m;
*s = vm;
if(*s > 0.0)
*s /= (*l <= 0.5) ? (v + m) : (2.0 - v - m);
else
return;
r2 = (v - r)/vm;
g2 = (v - g)/vm;
b2 = (v - b)/vm;
if(r == v)
*h = (g == m ? 5.0 + b2 : 1.0 - g2);
else if(g == v)
*h = (b == m ? 1.0 + r2 : 3.0 - b2);
else
*h = (r == m ? 3.0 + g2 : 5.0 - r2);
*h /= 6.0;
}
/** Convert h, s, l values to RGB and store them in the three uint
* referenced by the last three parameters.
*/
static void
color_hsl_to_rgb(double h, double sl, double l, uint *rx, uint *gx, uint *bx)
{
double v;
double r,g,b;
r = l;
g = l;
b = l;
v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
if(v > 0)
{
double m;
double sv;
int sextant;
double fract, vsf, mid1, mid2;
m = l + l - v;
sv = (v - m ) / v;
h *= 6.0;
sextant = (int) h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch(sextant)
{
case 0:
r = v;
g = mid1;
b = m;
break;
case 1:
r = mid2;
g = v;
b = m;
break;
case 2:
r = m;
g = v;
b = mid1;
break;
case 3:
r = m;
g = mid2;
b = v;
break;
case 4:
r = mid1;
g = m;
b = v;
break;
case 5:
r = v;
g = m;
b = mid2;
break;
}
}
*rx = r * 255.0;
*gx = g * 255.0;
*bx = b * 255.0;
}
/** Shades a color by the amount. This works by converting a packed RGB
* color to HSL, adding the amount to the lightness,
* and then converting back to RGB. 1.0 is max lightness, 0.0 is min lightness.
* \param shadeVal the amount to shade the lightness by.
* \return the shaded color
*/
uint
color_shade(uint rgb, double shadeVal)
{
uint r, g, b;
double h, s, l;
color_unpack_rgb(rgb, &r, &g, &b);
color_rgb_to_hsl(r, g, b, &h, &s, &l);
l += shadeVal;
l = color_clamp(l, 0, 1);
color_hsl_to_rgb(h, s, l, &r, &g, &b);
rgb = color_pack_rgb(r, g, b);
return rgb;
}

File diff suppressed because it is too large Load Diff

167
src/config.h Normal file
View File

@ -0,0 +1,167 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <string.h>
#include <X11/Xlib.h>
#include "wmfs.h"
#include "util.h"
#include "tag.h"
#include "client.h"
#include "status.h"
#include "mouse.h"
#include "screen.h"
#include "infobar.h"
#include "launcher.h"
#define THEME_DEFAULT (SLIST_FIRST(&W->h.theme))
static const struct { char *name; void (*func)(Uicb cmd); } uicb_list[] =
{
/* Sys */
{ "spawn", uicb_spawn },
{ "quit", uicb_quit },
{ "reload", uicb_reload },
/* Tag */
{ "tag_set", uicb_tag_set },
{ "tag", uicb_tag_set_with_name },
{ "tag_next", uicb_tag_next },
{ "tag_prev", uicb_tag_prev },
{ "tag_client", uicb_tag_client },
{ "tag_client_and_set", uicb_tag_client_and_set },
{ "tag_move_client_next", uicb_tag_move_client_next },
{ "tag_move_client_prev", uicb_tag_move_client_prev },
{ "tag_click", uicb_tag_click },
{ "tag_new", uicb_tag_new },
{ "tag_del", uicb_tag_del },
/* Layout */
{ "layout_vmirror", uicb_layout_vmirror },
{ "layout_hmirror", uicb_layout_hmirror },
{ "layout_rotate_left", uicb_layout_rotate_left },
{ "layout_rotate_right", uicb_layout_rotate_right },
{ "layout_prev_set", uicb_layout_prev_set },
{ "layout_next_set", uicb_layout_next_set },
{ "layout_integrate_left", uicb_layout_integrate_Left },
{ "layout_integrate_right", uicb_layout_integrate_Right },
{ "layout_integrate_top", uicb_layout_integrate_Top },
{ "layout_integrate_bottom", uicb_layout_integrate_Bottom },
/* Client */
{ "client_close", uicb_client_close },
{ "client_resize_right", uicb_client_resize_Right },
{ "client_resize_left", uicb_client_resize_Left },
{ "client_resize_top", uicb_client_resize_Top },
{ "client_resize_bottom", uicb_client_resize_Bottom },
{ "client_focus_right", uicb_client_focus_Right },
{ "client_focus_left", uicb_client_focus_Left },
{ "client_focus_top", uicb_client_focus_Top },
{ "client_focus_bottom", uicb_client_focus_Bottom },
{ "client_tab_right", uicb_client_tab_Right },
{ "client_tab_left", uicb_client_tab_Left },
{ "client_tab_top", uicb_client_tab_Top },
{ "client_tab_bottom", uicb_client_tab_Bottom },
{ "client_swap_right", uicb_client_swap_Right },
{ "client_swap_left", uicb_client_swap_Left },
{ "client_swap_top", uicb_client_swap_Top },
{ "client_swap_bottom", uicb_client_swap_Bottom },
{ "client_focus_next", uicb_client_focus_next },
{ "client_focus_prev", uicb_client_focus_prev },
{ "client_swap_next", uicb_client_swapsel_next },
{ "client_swap_prev", uicb_client_swapsel_prev },
{ "client_untab", uicb_client_untab },
{ "client_focus_next_tab", uicb_client_focus_next_tab },
{ "client_focus_prev_tab", uicb_client_focus_prev_tab },
{ "client_focus_click", uicb_client_focus_click },
{ "client_toggle_free", uicb_client_toggle_free },
{ "client_toggle_ignore_tag", uicb_client_toggle_ignore_tag },
{ "client_tab_next_opened", uicb_client_tab_next_opened },
/* Status */
{ "status" , uicb_status },
{ "status_surface", uicb_status_surface },
/* Infobar */
{ "infobar_toggle_hide", uicb_infobar_toggle_hide },
/* Mouse */
{ "mouse_resize", uicb_mouse_resize },
{ "mouse_move", uicb_mouse_move },
{ "mouse_swap", uicb_mouse_move },
{ "mouse_tab", uicb_mouse_tab },
/* Screen */
{ "screen_next", uicb_screen_next },
{ "screen_prev", uicb_screen_prev },
{ "screen_move_client_next", uicb_screen_move_client_next },
{ "screen_move_client_prev", uicb_screen_move_client_prev },
/* Launcher */
{ "launcher", uicb_launcher },
{ NULL, NULL }
};
static inline void*
uicb_name_func(Uicb name)
{
int i = 0;
for(; uicb_list[i].func; ++i)
if(!strcmp(name, uicb_list[i].name))
return uicb_list[i].func;
return NULL;
}
static const struct { const char *name; KeySym keysym; } key_list[] =
{
{"Control", ControlMask },
{"Shift", ShiftMask },
{"Lock", LockMask },
{"Alt", Mod1Mask },
{"Mod1", Mod1Mask },
{"Mod2", Mod2Mask },
{"Mod3", Mod3Mask },
{"Mod4", Mod4Mask },
{"Super", Mod4Mask },
{"Home", Mod4Mask },
{"Mod5", Mod5Mask },
{NULL, NoSymbol }
};
static inline KeySym
modkey_keysym(const char *name)
{
int i = 0;
for(; key_list[i].name; ++i)
if(!strcmp(name, key_list[i].name))
return key_list[i].keysym;
return NoSymbol;
}
static inline struct theme*
name_to_theme(const char *name)
{
struct theme *t;
SLIST_FOREACH(t, &W->h.theme, next)
if(!strcmp(t->name, name))
return t;
return THEME_DEFAULT;
}
void config_init(void);
#endif /* CONFIG_H */

View File

@ -1,285 +0,0 @@
/*
* draw.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
#ifdef HAVE_IMLIB
static int sw = 0;
/** Draw an image in a drawable
* \param dr Drawable
* \param x X position
* \param y Y position
* \param name Path of the image
*/
static void
draw_image(Drawable dr, int x, int y, int w, int h, char *name)
{
Imlib_Image image;
if(!dr)
return;
imlib_context_set_display(dpy);
imlib_context_set_visual(DefaultVisual(dpy, DefaultScreen(dpy)));
imlib_context_set_colormap(DefaultColormap(dpy, DefaultScreen(dpy)));
imlib_context_set_drawable(dr);
image = imlib_load_image(patht(name));
imlib_context_set_image(image);
if(w <= 0)
w = imlib_image_get_width();
if(h <= 0)
h = imlib_image_get_height();
if(image)
imlib_render_image_on_drawable_at_size(x, y, w, h);
else
warnx("Can't draw image: '%s'", name);
imlib_free_image();
return;
}
/** Check images blocks in str and return properties
* --> \i[x;y;w;h;name]\
*\param im ImageAttr pointer, image properties
*\param str String
*\param m Check dynamic mouse
*\return n Lenght of i
*/
static void
parse_image_block(Drawable dr, char *str, bool m)
{
ImageAttr im;
Geo area;
char as, mouse[512] = { 0 };
int i = 0, j = 0, k = 0, n;
for(; i < (int)strlen(str); ++i, ++j)
if(((n = sscanf(&str[i], "\\i[%d;%d;%d;%d;%512[^];]]%c",
&im.x, &im.y, &im.w, &im.h, im.name, &as)) == 6
|| (n = sscanf(&str[i], "\\i[%d;%d;%d;%d;%512[^;];%512[^]]]%c",
&im.x, &im.y, &im.w, &im.h, im.name, mouse, &as)) == 7)
&& as == '\\')
{
draw_image(dr, im.x - sw, im.y, im.w, im.h, im.name);
/* Etablish clickable area on image (on infobar wins only (status mouse bind) */
if(n == 7 && m)
{
area.x = im.x - sw;
area.y = im.y;
area.width = im.w;
area.height = im.h;
/* Associate drawable with window; travel infobars */
for(; k < screen_count(); ++k)
if(infobar[k].bar->dr == dr)
{
statustext_mouse(mouse, area, &infobar[k]);
break;
}
}
for(++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
}
else if(j != i)
str[j] = str[i];
for(sw = 0, k = j; k < i; str[k++] = 0);
return;
}
#endif /* HAVE_IMLIB */
/** Draw a string in a Drawable
* \param d Drawable
* \param x X position
* \param y Y position
* \param fg Foreground text color
* \param pad Text padding
* \param str String that will be draw
*/
void
draw_text(Drawable d, int x, int y, char* fg, char *str)
{
CHECK(str);
/* To draw image everywhere we can draw text */
#ifdef HAVE_IMLIB
char *ostr;
size_t textlen = 0;
if(strstr(str, "i["))
{
if(d == infobar[conf.systray.screen].bar->dr)
sw = systray_get_width();
ostr = xstrdup(str);
textlen = strlen(ostr);
parse_image_block(d, str, True);
}
#endif /* HAVE_IMLIB */
#ifdef HAVE_XFT
if(conf.use_xft)
{
XftColor xftcolor;
XftDraw *xftd;
/* Transform X Drawable -> Xft Drawable */
xftd = XftDrawCreate(dpy, d, DefaultVisual(dpy, SCREEN), DefaultColormap(dpy, SCREEN));
/* Alloc text color */
XftColorAllocName(dpy, DefaultVisual(dpy, SCREEN),
DefaultColormap(dpy, SCREEN), fg, &xftcolor);
XftDrawStringUtf8(xftd, &xftcolor, font.font, x, y, (FcChar8 *)str, strlen(str));
/* Free the text color and XftDraw */
XftColorFree(dpy, DefaultVisual(dpy, SCREEN), DefaultColormap(dpy, SCREEN), &xftcolor);
XftDrawDestroy(xftd);
}
else
#endif /* HAVE_XFT */
{
/* Use font set */
XSetForeground(dpy, gc, getcolor(fg));
XmbDrawString(dpy, d, font.fontset, gc, x, y, str, strlen(str));
}
#ifdef HAVE_IMLIB
if(textlen)
{
strncpy(str, ostr, textlen);
free(ostr);
}
#endif /* HAVE_IMLIB */
return;
}
/** Draw a Rectangle in a drawable
* \param dr Drawable
* \param x X position
* \param y Y position
* \param w Width
* \param h Height
* \param color Color of the rectangle
*/
void
draw_rectangle(Drawable dr, int x, int y, int w, int h, uint color)
{
XSetForeground(dpy, gc, color);
XFillRectangle(dpy, dr, gc, x, y, (uint)w, (uint)h);
return;
}
/** Draw a Graph in a drawable
* \param dr Drawable
* \param x X position
* \param y Y position
* \param w Width
* \param h Height
* \param color Color of the graph
* \param data Array of bytes that will be draw
*/
void
draw_graph(Drawable dr, int x, int y, int w, int h, uint color, char *data)
{
int i;
for(i = 0; i < w; ++i)
draw_rectangle(dr, x + i, y + h - data[i], 1, data[i], color);
return;
}
/** Calculates the text's size relatively to the font
* \param text Text string
* \return final text width
*/
ushort
textw(char *text)
{
Drawable d = 0;
ushort ret = 0;
if(!text)
return 0;
#ifdef HAVE_IMLIB
char *ostr;
size_t textlen = 0;
if(strstr(text, "i["))
{
ostr = xstrdup(text);
textlen = strlen(ostr);
parse_image_block(d, text, False);
}
#endif /* HAVE_IMLIB */
#ifdef HAVE_XFT
if(conf.use_xft)
{
XGlyphInfo gl;
XftTextExtentsUtf8(dpy, font.font, (FcChar8 *)text, strlen(text), &gl);
ret = gl.width + font.de;
}
else
#endif /* HAVE_XFT */
{
XRectangle r;
XmbTextExtents(font.fontset, text, strlen(text), NULL, &r);
ret = r.width;
}
#ifdef HAVE_IMLIB
if(textlen)
{
strncpy(text, ostr, textlen);
free(ostr);
}
#endif /* HAVE_IMLIB */
return ret;
}

113
src/draw.h Normal file
View File

@ -0,0 +1,113 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef DRAW_H
#define DRAW_H
#include <string.h>
#include <X11/Xlib.h>
#ifdef HAVE_IMLIB2
#include <Imlib2.h>
#endif /* HAVE_IMLIB2 */
#include "wmfs.h"
#include "config.h"
#include "screen.h"
#define TEXTY(t, w) ((t->font.height - t->font.de) + ((w - t->font.height) >> 1))
#define PAD (8)
static inline void
draw_text(Drawable d, struct theme *t, int x, int y, Color fg, const char *str)
{
XSetForeground(W->dpy, W->gc, fg);
XmbDrawString(W->dpy, d, t->font.fontset, W->gc, x, y, str, strlen(str));
}
static inline void
draw_rect(Drawable d, struct geo *g, Color bg)
{
XSetForeground(W->dpy, W->gc, bg);
XFillRectangle(W->dpy, d, W->gc, g->x, g->y, g->w, g->h);
}
#ifdef HAVE_IMLIB2
/*
* Draw image on drawable with g geo
* Require that the image was loaded with draw_image_load()
*/
static inline void
draw_image(Drawable d, struct geo *g)
{
imlib_context_set_drawable(d);
imlib_render_image_on_drawable_at_size(g->x, g->y, g->w, g->h);
imlib_free_image();
}
/*
* Load image, set it in imlib context, and return
* width & height as argument 2 & 3
*/
static inline void
draw_image_load(char *path, int *w, int *h)
{
Imlib_Image image = imlib_load_image(path);
imlib_context_set_image(image);
*w = imlib_image_get_width();
*h = imlib_image_get_height();
}
#endif /* HAVE_IMLIB2 */
/*
* For client use
*/
static inline void
draw_reversed_rect(Drawable dr, struct client *c, bool t)
{
struct geo *g = (t ? &c->tgeo : &c->geo);
struct geo *ug = &c->screen->ugeo;
int i = c->theme->client_border_width;
if(c->flags & CLIENT_FREE)
{
XDrawRectangle(W->dpy, dr, W->rgc,
ug->x + g->x + i,
ug->y + g->y + i,
g->w - (i << 1),
g->h - (i << 1));
}
else
{
XDrawRectangle(W->dpy, dr, W->rgc,
ug->x + g->x + i + (W->padding >> 2),
ug->y + g->y + i + (W->padding >> 2),
g->w - (i << 1) - (W->padding >> 1),
g->h - (i << 1) - (W->padding >> 1));
}
}
static inline void
draw_line(Drawable d, int x1, int y1, int x2, int y2)
{
XDrawLine(W->dpy, d, W->gc, x1, y1, x2, y2);
}
static inline unsigned short
draw_textw(struct theme *t, const char *str)
{
XRectangle r;
XmbTextExtents(t->font.fontset, str, strlen(str), NULL, &r);
return r.width;
}
#endif /* DRAW_H */

View File

@ -1,221 +1,98 @@
/* /*
* event.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
#define EVDPY (e->xany.display)
#define MAX_EV 256
/** Check mouse bind condition and execute associated function
*/ */
#include "event.h"
#include "ewmh.h"
#include "config.h"
#include "util.h"
#include "wmfs.h"
#include "client.h"
#include "barwin.h"
#include "screen.h"
#include "systray.h"
#include "infobar.h"
#define EVDPY(e) (e)->xany.display
#define MOUSE_DO_BIND(m) \
if(m->button == ev->button) \
if(!m->use_area || (m->use_area && INAREA(ev->x, ev->y, m->area))) \
if(m->func) \
m->func(m->cmd);
static void static void
do_mousebind(int screen, uint button, int n, MouseBinding m[]) event_buttonpress(XEvent *e)
{
int i = 0;
for(; i < n; ++i)
{
if(m[i].screen == screen || m[i].screen < 0) /* Screen */
if(m[i].tag == seltag[i] || m[i].tag < 0) /* Tag */
if(m[i].button == button) /* Button */
if(m[i].func) /* Function */
m[i].func(m[i].cmd);
}
return;
}
/** ButtonPress handle event
*/
static void
buttonpress(XEvent *e)
{ {
XButtonEvent *ev = &e->xbutton; XButtonEvent *ev = &e->xbutton;
StatusMouse *sm; struct mousebind *m;
InfoBar *ib; struct barwin *b;
Client *c; struct client *c;
int i, n;
screen_get_sel(); screen_update_sel();
status_flush_surface();
ib = &infobar[selscreen]; SLIST_FOREACH(b, &W->h.barwin, next)
if(b->win == ev->window)
/* If the mouse is on a not selected client and you click on it. */
if(((c = client_gb_win(ev->window)) || (c = client_gb_titlebar(ev->window)))
&& c != sel && ev->button >= Button1 && ev->button <= Button3)
{ {
W->last_clicked_barwin = b;
SLIST_FOREACH(m, &b->mousebinds, next)
MOUSE_DO_BIND(m);
SLIST_FOREACH(m, &b->statusmousebinds, next)
MOUSE_DO_BIND(m);
break;
}
if((c = client_gb_win(ev->window)) && c != W->client
&& ev->button == 1 && W->cfocus & CFOCUS_CLICK)
client_focus(c); client_focus(c);
client_raise(c);
return;
}
/* Titlebar */
if((c = client_gb_titlebar(ev->window)) && c == sel)
do_mousebind(selscreen, ev->button, conf.titlebar.nmouse, conf.titlebar.mouse);
/* Titlebar buttons */
if((c = client_gb_button(ev->window, &n)))
for(i = 0; i < conf.titlebar.button[n].nmouse; ++i)
if(ev->button == conf.titlebar.button[n].mouse[i].button)
if(conf.titlebar.button[n].mouse[i].func)
{
client_focus(c);
conf.titlebar.button[n].mouse[i].func(conf.titlebar.button[n].mouse[i].cmd);
}
/* Frame Resize Area */
if((c = client_gb_resize(ev->window)))
mouse_resize(c);
/* Client */
if((c = client_gb_win(ev->window)) && c == sel)
do_mousebind(selscreen, ev->button, conf.client.nmouse, conf.client.mouse);
/* Root */
if(ev->window == ROOT)
do_mousebind(selscreen, ev->button, conf.root.nmouse, conf.root.mouse);
/* Infobars */
for(i = 0; i < screen_count(); ++i)
if(ev->window == infobar[i].bar->win)
do_mousebind(i, ev->button, conf.bars.nmouse, conf.bars.mouse);
/* Selbar */
if(conf.bars.selbar && ev->window == ib->bar->win)
if(INAREA(ev->x, ev->y, ib->selbar_geo))
do_mousebind(selscreen, ev->button, conf.selbar.nmouse, conf.selbar.mouse);
/* Tags */
if(ib->tags_board)
{
for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
if(ib->tags[i] && ev->window == ib->tags[i]->win)
{
do_mousebind(selscreen, ev->button, tags[selscreen][i].nmouse, tags[selscreen][i].mouse);
/* Mouse button action on tag */
if(ev->button == conf.mouse_tag_action[TagSel])
tag_set(i);
else if(ev->button == conf.mouse_tag_action[TagTransfert])
tag_transfert(sel, i);
else if(ev->button == conf.mouse_tag_action[TagAdd])
tag_additional(selscreen, seltag[selscreen], i);
else if(ev->button == conf.mouse_tag_action[TagNext])
tag_set(seltag[selscreen] + 1);
else if(ev->button == conf.mouse_tag_action[TagPrev])
tag_set(seltag[selscreen] - 1);
}
}
/* Layout button */
if(ib->layout_button && ev->window == ib->layout_button->win && conf.nlayout > 1)
{
if(conf.layout_system && (ev->button == Button1 || ev->button == Button3)) /* True -> menu */
{
menulayout.y = spgeo[selscreen].y + ib->layout_button->geo.y + INFOBARH;
menulayout.x = ib->layout_button->geo.x + (sgeo[selscreen].x - BORDH);
if(ib->geo.y != spgeo[selscreen].y)
menulayout.y = ib->geo.y - (INFOBARH * menulayout.nitem) - SHADH;
uicb_menu("menulayout");
}
else
layoutswitch(ev->button == Button1 || ev->button == Button4);
}
/* Status mouse bindings */
SLIST_FOREACH(sm, &smhead, next)
if(sm->infobar->bar->win == ev->window && ev->button == sm->button)
if(INAREA(ev->x, ev->y, sm->area))
if(sm->func)
sm->func(sm->cmd);
return;
} }
/* ClientMessage handle event
*/
static void static void
clientmessageevent(XEvent *e) event_enternotify(XEvent *e)
{ {
XClientMessageEvent *ev = &e->xclient; XCrossingEvent *ev = &e->xcrossing;
Client *c; struct client *c;
InfoBar *ib;
Systray *sy;
int s, mess_t = 0;
Atom rt;
int rf;
ulong ir, il;
uchar *ret = NULL;
uchar *ret_cmd = NULL;
void (*func)(uicb_t);
if(ev->format != 32) if((ev->mode != NotifyNormal
|| ev->detail == NotifyInferior)
&& ev->window != W->root)
return; return;
s = screen_count(); if(ev->window == W->systray.win || systray_find(ev->window))
return;
while(mess_t < net_last + s && net_atom[mess_t] != ev->message_type) if((c = client_gb_win(ev->window))
++mess_t; || (c = client_gb_frame(ev->window)))
if(ev->window == ROOT)
{ {
/* Manage _NET_CURRENT_DESKTOP */ if(c->flags & CLIENT_IGNORE_ENTER)
if(mess_t == net_current_desktop c->flags ^= CLIENT_IGNORE_ENTER;
&& ev->data.l[0] >= 0 else if(c->tag->flags & TAG_IGNORE_ENTER)
&& ev->data.l[0] < conf.ntag[selscreen]) c->tag->flags ^= TAG_IGNORE_ENTER;
tag_set((int)(ev->data.l[0] + 1)); else if(c != W->client && !(c->flags & CLIENT_TABBED)
&& W->cfocus & CFOCUS_ENTER)
/* Manage _WMFS_SET_SCREEN */
if(mess_t == wmfs_set_screen
&& ev->data.l[0] >= 0
&& ev->data.l[0] <= s)
screen_set_sel((int)(ev->data.l[0]));
/* Manage _NET_ACTIVE_WINDOW */
else if(mess_t == net_active_window)
{
if((c = client_gb_win(ev->window)))
client_focus(c); client_focus(c);
else if((sy = systray_find(ev->data.l[0])))
XSetInputFocus(EVDPY, sy->win, RevertToNone, CurrentTime);
} }
} }
else if(ev->window == traywin)
{ static void
/* Manage _NET_WM_SYSTEM_TRAY_OPCODE */ event_clientmessageevent(XEvent *e)
if(mess_t == net_wm_system_tray_opcode) {
XClientMessageEvent *ev = &e->xclient;
struct client *c;
struct _systray *sy;
int type = 0;
while(type < net_last && W->net_atom[type] != ev->message_type)
++type;
/*
* Systray message
* _NET_WM_SYSTRAY_TRAY_OPCODE
*/
if(ev->window == W->systray.win && type == net_system_tray_opcode)
{ {
if(ev->data.l[1] == XEMBED_EMBEDDED_NOTIFY) if(ev->data.l[1] == XEMBED_EMBEDDED_NOTIFY)
{ {
@ -223,105 +100,100 @@ clientmessageevent(XEvent *e)
systray_update(); systray_update();
} }
else if(ev->data.l[1] == XEMBED_REQUEST_FOCUS) else if(ev->data.l[1] == XEMBED_REQUEST_FOCUS)
{
if((sy = systray_find(ev->data.l[2]))) if((sy = systray_find(ev->data.l[2])))
ewmh_send_message(sy->win, sy->win, "_XEMBED", ewmh_send_message(sy->win, sy->win, "_XEMBED", XEMBED_FOCUS_IN,
XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0, 0); XEMBED_FOCUS_CURRENT, 0, 0, 0);
} }
} }
else if(ev->window == W->root)
/* Manage _NET_WM_STATE */ {
if(mess_t == net_wm_state) /* WMFS message */
if((c = client_gb_win(ev->window)))
ewmh_manage_net_wm_state(ev->data.l, c);
/* Manage _NET_CLOSE_WINDOW */
if(mess_t == net_close_window)
if((c = client_gb_win(ev->window)))
client_kill(c);
/* Manage _NET_WM_DESKTOP */
if(mess_t == net_wm_desktop)
if((c = client_gb_win(ev->window)) && ev->data.l[0] != (long)0xFFFFFFFF)
tag_transfert(c, ev->data.l[0]);
if(ev->data.l[4]) if(ev->data.l[4])
{ {
/* Manage _WMFS_STATUSTEXT_x */
if(mess_t >= wmfs_statustext)
{
if(XGetWindowProperty(EVDPY, ROOT, net_atom[mess_t], 0, 4096,
False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret) == Success)
{
ib = &infobar[mess_t - wmfs_statustext];
free(ib->statustext);
ib->statustext = xstrdup((char*)ret);
_infobar_draw(ib);
XFree(ret);
}
}
/* Manage _WMFS_FUNCTION && _WMFS_CMD */ /* Manage _WMFS_FUNCTION && _WMFS_CMD */
if(mess_t == wmfs_function || mess_t == wmfs_cmd) if(type == wmfs_function || type == wmfs_cmd)
{ {
XGetWindowProperty(EVDPY, ROOT, net_atom[wmfs_function], 0, 4096, Atom rt;
False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret); int d;
XGetWindowProperty(EVDPY, ROOT, net_atom[wmfs_cmd], 0, 4096, long unsigned int len, il;
False, net_atom[utf8_string], &rt, &rf, &ir, &il, &ret_cmd); unsigned char *ret = NULL, *ret_cmd = NULL;
void (*func)(Uicb);
if((func = name_to_func((char*)ret, func_list)))
func((uicb_t)ret_cmd);
if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_function], 0, 65536,
False, W->net_atom[utf8_string], &rt, &d,
&len, &il, &ret) == Success
&& ret && ((func = uicb_name_func((char*)ret))))
{
if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_cmd], 0, 65536,
False, W->net_atom[utf8_string], &rt, &d,
&len, &il, &ret_cmd) == Success
&& len && ret_cmd)
{
func((Uicb)ret_cmd);
XFree(ret_cmd); XFree(ret_cmd);
}
else
func(NULL);
XFree(ret); XFree(ret);
} }
} }
/* Manage _WMFS_UPDATE_HINTS */
if(mess_t == wmfs_update_hints)
{
ewmh_get_number_of_desktop();
ewmh_update_current_tag_prop();
ewmh_get_client_list();
ewmh_get_desktop_names();
ewmh_set_desktop_geometry();
screen_count();
screen_get_sel();
} }
return; if(type == net_active_window)
if((sy = systray_find(ev->data.l[0])))
XSetInputFocus(W->dpy, sy->win, RevertToNone, CurrentTime);
}
switch(type)
{
/* _NET_WM_STATE */
case net_wm_state:
if((c = client_gb_win(ev->window)))
ewmh_manage_state(ev->data.l, c);
break;
/* _NET_CLOSE_WINDOW */
case net_close_window:
if((c = client_gb_win(ev->window)))
client_close(c);
break;
/* _NET_WM_DESKTOP */
case net_wm_desktop:
break;
}
} }
/** ConfigureRequesthandle events
*/
static void static void
configureevent(XEvent *e) event_configureevent(XEvent *e)
{ {
XConfigureRequestEvent *ev = &e->xconfigurerequest; XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc; XWindowChanges wc;
Client *c; struct client *c;
/* Check part */
if(((c = client_gb_win(ev->window)) || (c = client_gb_win(ev->window)))
&& (c->flags & (LMaxFlag | MaxFlag | FSSFlag)))
return;
if((c = client_gb_win(ev->window))) if((c = client_gb_win(ev->window)))
{
if(c->flags & CLIENT_FREE)
{ {
if(ev->value_mask & CWX) if(ev->value_mask & CWX)
c->geo.x = ev->x + BORDH; c->geo.x = ev->x;
if(ev->value_mask & CWY) if(ev->value_mask & CWY)
c->geo.y = ev->y + TBARH; c->geo.y = ev->y - c->tbarw - c->border - c->border;
if(ev->value_mask & CWWidth) if(ev->value_mask & CWWidth)
c->geo.width = ev->width; c->geo.w = ev->width + c->border + c->border;
if(ev->value_mask & CWHeight) if(ev->value_mask & CWHeight)
c->geo.height = ev->height; c->geo.h = ev->height + c->tbarw + c->border;
if(c->flags & FreeFlag || !(c->flags & TileFlag)) client_moveresize(c, &c->geo);
client_moveresize(c, c->geo, False); }
else else
{ {
client_configure(c); if(ev->value_mask & CWWidth)
arrange(c->screen, True); _fac_resize(c, Right, ev->width - c->wgeo.w);
if(ev->value_mask & CWHeight)
_fac_resize(c, Bottom, ev->height - c->wgeo.h);
client_apply_tgeo(c->tag);
} }
} }
else else
@ -334,383 +206,234 @@ configureevent(XEvent *e)
wc.sibling = ev->above; wc.sibling = ev->above;
wc.stack_mode = ev->detail; wc.stack_mode = ev->detail;
XConfigureWindow(EVDPY, ev->window, ev->value_mask, &wc); XConfigureWindow(EVDPY(e), ev->window, ev->value_mask, &wc);
} }
return;
} }
/** DestroyNotify handle event
*/
static void static void
destroynotify(XEvent *e) event_destroynotify(XEvent *e)
{ {
XDestroyWindowEvent *ev = &e->xdestroywindow; XDestroyWindowEvent *ev = &e->xdestroywindow;
Client *c; struct client *c;
Systray *s; struct _systray *s;
if((c = client_gb_win(ev->window))) if((c = client_gb_win(ev->window)))
{ client_remove(c);
client_unmanage(c);
XSetErrorHandler(errorhandler);
}
else if((s = systray_find(ev->window))) else if((s = systray_find(ev->window)))
{ {
setwinstate(s->win, WithdrawnState); ewmh_set_wm_state(s->win, WithdrawnState);
systray_del(s); systray_del(s);
systray_update(); systray_update();
} }
return;
} }
/** EnterNotify handle event
*/
static void static void
enternotify(XEvent *e) event_focusin(XEvent *e)
{ {
XCrossingEvent *ev = &e->xcrossing; if(W->client
Client *c; && e->xfocus.window != W->client->win
int n; && e->xfocus.window != W->client->frame)
client_focus(W->client);
}
if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) static void
&& ev->window != ROOT) event_maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
XWindowAttributes at;
struct _systray *s;
/* Which windows to manage */
if(!XGetWindowAttributes(EVDPY(e), ev->window, &at)
|| at.override_redirect
|| ewmh_manage_window_type_desktop(ev->window)
|| ewmh_manage_state_sticky(ev->window))
return; return;
if(tags[selscreen][seltag[selscreen]].flags & IgnoreEnterFlag) if(!client_gb_win(ev->window))
client_new(ev->window, &at, false);
else if((s = systray_find(ev->window)))
{ {
tags[selscreen][seltag[selscreen]].flags &= ~IgnoreEnterFlag; ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
return; XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
systray_update();
} }
/* Don't handle EnterNotify event if it's about systray */
if(systray_find(ev->window) || ev->window == traywin)
return;
if(conf.focus_fmouse)
{
if((c = client_gb_win(ev->window))
|| (c = client_gb_frame(ev->window))
|| (c = client_gb_titlebar(ev->window))
|| (c = client_gb_button(ev->window, &n)))
client_focus(c);
else
client_focus(NULL);
}
return;
} }
/** ExposeEvent handle event
*/
static void static void
expose(XEvent *e) event_mappingnotify(XEvent *e)
{
XExposeEvent *ev = &e->xexpose;
Client *c;
BarWindow *bw;
/* BarWindows */
SLIST_FOREACH(bw, &bwhead, next)
if(ev->window == bw->win)
{
barwin_refresh(bw);
break;
}
/* Client frame */
if((c = client_gb_titlebar(ev->window)))
frame_update(c);
return;
}
/** FocusChange handle event
*/
static void
focusin(XEvent *e)
{
if(sel && e->xfocus.window != sel->win)
client_focus(sel);
return;
}
/** KeyPress handle event
*/
static void
keypress(XEvent *e)
{
XKeyPressedEvent *ev = &e->xkey;
KeySym keysym;
int i;
keysym = XKeycodeToKeysym(EVDPY, (KeyCode)ev->keycode, 0);
for(i = 0; i < conf.nkeybind; ++i)
if(keysym == keys[i].keysym
&& (keys[i].mod & ~(numlockmask | LockMask))
== (ev->state & ~(numlockmask | LockMask))
&& keys[i].func)
keys[i].func(keys[i].cmd);
return;
}
/** MappingNotify handle event
*/
static void
mappingnotify(XEvent *e)
{ {
XMappingEvent *ev = &e->xmapping; XMappingEvent *ev = &e->xmapping;
XRefreshKeyboardMapping(ev); XRefreshKeyboardMapping(ev);
if(ev->request == MappingKeyboard) if(ev->request == MappingKeyboard)
grabkeys(); wmfs_grab_keys();
return;
} }
/** MapNotify handle event
*/
static void static void
mapnotify(XEvent *e) event_propertynotify(XEvent *e)
{
XMapEvent *ev = &e->xmap;
Client *c;
Systray *s;
if(ev->window != ev->event && !ev->send_event)
return;
if((c = client_gb_win(ev->window)))
setwinstate(c->win, NormalState);
else if((s = systray_find(ev->window)))
{
setwinstate(s->win, NormalState);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
}
return;
}
/** MapRequest handle event
*/
static void
maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
XWindowAttributes at;
Systray *s;
CHECK(XGetWindowAttributes(EVDPY, ev->window, &at));
CHECK(!at.override_redirect);
if((s = systray_find(ev->window)))
{
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
systray_update();
}
else if(!client_gb_win(ev->window))
client_manage(ev->window, &at, True);
return;
}
/** PropertyNotify handle event
*/
static void
propertynotify(XEvent *e)
{ {
XPropertyEvent *ev = &e->xproperty; XPropertyEvent *ev = &e->xproperty;
Client *c;
Systray *s;
Window trans;
XWMHints *h; XWMHints *h;
struct client *c;
struct _systray *s;
if(ev->state == PropertyDelete) if(ev->state == PropertyDelete)
return; return;
if((s = systray_find(ev->window)))
{
systray_state(s);
systray_update();
}
if((c = client_gb_win(ev->window))) if((c = client_gb_win(ev->window)))
{ {
switch(ev->atom) switch(ev->atom)
{ {
case XA_WM_TRANSIENT_FOR: case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(EVDPY, c->win, &trans);
if((c->flags & (TileFlag | MaxFlag)) && client_gb_win(trans))
arrange(c->screen, True);
break; break;
case XA_WM_NORMAL_HINTS: case XA_WM_NORMAL_HINTS:
client_size_hints(c); client_get_sizeh(c);
break; break;
case XA_WM_HINTS: case XA_WM_HINTS:
if((h = XGetWMHints(EVDPY, c->win)) && (h->flags & XUrgencyHint) && c != sel) if((h = XGetWMHints(EVDPY(e), c->win))
&& (h->flags & XUrgencyHint)
&& c->tag != W->screen->seltag)
{ {
client_urgent(c, True); c->tag->flags |= TAG_URGENT;
infobar_elem_screen_update(c->screen, ElemTag);
XFree(h); XFree(h);
} }
break; break;
case XA_WM_NAME:
client_get_name(c);
break;
default: default:
if(ev->atom == net_atom[net_wm_name]) if(ev->atom == XA_WM_NAME || ev->atom == W->net_atom[net_wm_name])
client_get_name(c); client_get_name(c);
break; break;
} }
} }
else if((s = systray_find(ev->window)))
return; {
} systray_state(s);
/** XReparentEvent handle event
*/
static void
reparentnotify(XEvent *ev)
{
(void)ev;
return;
}
/** SelectionClearEvent handle event
*/
static void
selectionclearevent(XEvent *ev)
{
/* Getting selection if lost it */
if(ev->xselectionclear.window == traywin)
systray_acquire();
systray_update(); systray_update();
}
return;
} }
/** UnmapNotify handle event
*/
static void static void
unmapnotify(XEvent *e) event_unmapnotify(XEvent *e)
{ {
XUnmapEvent *ev = &e->xunmap; XUnmapEvent *ev = &e->xunmap;
Client *c; struct client *c;
Systray *s; struct _systray *s;
if((c = client_gb_win(ev->window)) if((c = client_gb_win(ev->window))
&& ev->send_event && ev->send_event
&& !(c->flags & HideFlag)) && ev->event == W->root)
{ {
client_unmanage(c); Atom rt;
XSetErrorHandler(errorhandler); unsigned long n, il;
} int d;
unsigned char *ret = NULL;
if((s = systray_find(ev->window))) if(XGetWindowProperty(EVDPY(e), c->win, W->net_atom[wm_state], 0, 2,
False, W->net_atom[wm_state], &rt, &d,
&n, &il, &ret) == Success)
if(*ret == NormalState)
client_remove(c);
}
else if((s = systray_find(ev->window)))
{ {
systray_del(s); systray_del(s);
systray_update(); systray_update();
} }
return;
} }
/** XMotionNotify handle event
*/
static void static void
motionnotify(XEvent *e) event_keypress(XEvent *e)
{ {
XMotionEvent *ev = &e->xmotion; XKeyPressedEvent *ev = &e->xkey;
Client *c; KeySym keysym = XkbKeycodeToKeysym(EVDPY(e), (KeyCode)ev->keycode, 0, 0);
struct keybind *k;
if(!conf.focus_fmouse || !conf.focus_fmov) screen_update_sel();
return; status_flush_surface();
if((c = client_gb_win(ev->subwindow))) SLIST_FOREACH(k, &W->h.keybind, next)
if(c != sel) if(k->keysym == keysym && KEYPRESS_MASK(k->mod) == KEYPRESS_MASK(ev->state))
client_focus(c); if(k->func)
k->func(k->cmd);
return;
} }
/** XRandr handle event static void
*/ event_expose(XEvent *e)
#ifdef HAVE_XRANDR
void
xrandrevent(XEvent *e)
{ {
/* Update xrandr configuration */ XExposeEvent *ev = &e->xexpose;
if(!XRRUpdateConfiguration(e)) struct barwin *b;
return;
/* Reload WMFS to update the screen(s) geometry changement */ SLIST_FOREACH(b, &W->h.barwin, next)
quit(); if(b->win == ev->window)
for(; argv_global[0] && argv_global[0] == ' '; ++argv_global);
execvp(argv_global, all_argv);
}
#endif /* HAVE_XRANDR */
/** Key grabbing function
*/
void
grabkeys(void)
{
int i;
KeyCode code;
XUngrabKey(dpy, AnyKey, AnyModifier, ROOT);
for(i = 0; i < conf.nkeybind; ++i)
if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
{ {
XGrabKey(dpy, code, keys[i].mod, ROOT, True, GrabModeAsync, GrabModeAsync); barwin_refresh(b);
XGrabKey(dpy, code, keys[i].mod | LockMask, ROOT, True, GrabModeAsync, GrabModeAsync);
XGrabKey(dpy, code, keys[i].mod | numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync);
XGrabKey(dpy, code, keys[i].mod | LockMask | numlockmask, ROOT, True, GrabModeAsync, GrabModeAsync);
}
return; return;
}
}
static void
event_mapnotify(XEvent *e)
{
XMapEvent *ev = &e->xmap;
struct client *c;
struct _systray *s;
if(ev->window != ev->event && !ev->send_event)
return;
if((c = client_gb_win(ev->window)))
client_map(c);
else if((s = systray_find(ev->window)))
{
ewmh_set_wm_state(s->win, NormalState);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
}
}
static void
event_selectionclearevent(XEvent *ev)
{
/* Getting selection if lost it */
if(ev->xselectionclear.window == W->systray.win)
systray_acquire();
systray_update();
}
static void
event_dummy(XEvent *e)
{
/* printf("%d\n", e->type);*/
(void)e;
} }
/** Make event handle function pointer array
*/
void void
event_make_array(void) event_init(void)
{ {
int i = MAX_EV; int i = MAX_EV;
event_handle = xcalloc(MAX_EV, sizeof(event_handle));
/* Fill array with non-used function (do nothing) */
while(i--) while(i--)
event_handle[i] = reparentnotify; event_handle[i] = event_dummy;
event_handle[ButtonPress] = buttonpress; event_handle[ButtonPress] = event_buttonpress;
event_handle[ClientMessage] = clientmessageevent; event_handle[ClientMessage] = event_clientmessageevent;
event_handle[ConfigureRequest] = configureevent; event_handle[ConfigureRequest] = event_configureevent;
event_handle[DestroyNotify] = destroynotify; event_handle[DestroyNotify] = event_destroynotify;
event_handle[EnterNotify] = enternotify; event_handle[EnterNotify] = event_enternotify;
event_handle[Expose] = expose; event_handle[Expose] = event_expose;
event_handle[FocusIn] = focusin; event_handle[FocusIn] = event_focusin;
event_handle[KeyPress] = keypress; event_handle[KeyPress] = event_keypress;
event_handle[MapNotify] = mapnotify; event_handle[MapNotify] = event_mapnotify;
event_handle[MapRequest] = maprequest; event_handle[MapRequest] = event_maprequest;
event_handle[MappingNotify] = mappingnotify; event_handle[MappingNotify] = event_mappingnotify;
event_handle[MotionNotify] = motionnotify; event_handle[PropertyNotify] = event_propertynotify;
event_handle[PropertyNotify] = propertynotify; /*event_handle[ReparentNotify] = event_reparentnotify;*/
event_handle[ReparentNotify] = reparentnotify; event_handle[SelectionClear] = event_selectionclearevent;
event_handle[SelectionClear] = selectionclearevent; event_handle[UnmapNotify] = event_unmapnotify;
event_handle[UnmapNotify] = unmapnotify;
#ifdef HAVE_XRANDR
event_handle[xrandr_event + RRScreenChangeNotify] = xrandrevent;
#endif /* HAVE_XRANDR */
return;
} }

22
src/event.h Normal file
View File

@ -0,0 +1,22 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef EVENT_H
#define EVENT_H
#include <X11/XKBlib.h>
#include "wmfs.h"
#define MAX_EV 256
#define KEYPRESS_MASK(m) (m & ~(W->numlockmask | LockMask))
#define EVENT_HANDLE(e) event_handle[(e)->type](e);
void event_init(void);
void (*event_handle[MAX_EV])(XEvent*);
#endif /* EVENT_H */

View File

@ -1,186 +1,160 @@
/* /*
* ewmh.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h" #include "ewmh.h"
#include "util.h"
#include "screen.h"
#include "client.h"
/* Taken From standards.freedesktop.org */ /* Taken From standards.freedesktop.org */
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */ #define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
/** Init ewmh atoms
*/
void void
ewmh_init_hints(void) ewmh_init(void)
{ {
int i = 1, s, j, showing_desk = 0; int b = 1;
char rootn[] = "wmfs-"WMFS_VERSION;
char class[] = "wmfs", st[64];
long pid = (long)getpid();
char systray_atom[48];
W->net_atom = xcalloc(net_last, sizeof(Atom));
s = screen_count();
net_atom = xcalloc(net_last + s, sizeof(Atom));
/* EWMH hints */ /* EWMH hints */
net_atom[net_supported] = ATOM("_NET_SUPPORTED"); W->net_atom[wm_state] = ATOM("WM_STATE");
net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST"); W->net_atom[wm_class] = ATOM("WM_CLASS");
net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS"); W->net_atom[wm_name] = ATOM("WM_NAME");
net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS"); W->net_atom[net_supported] = ATOM("_NET_SUPPORTED");
net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP"); W->net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST");
net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES"); W->net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS");
net_atom[net_desktop_geometry] = ATOM("_NET_DESKTOP_GEOMETRY"); W->net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS");
net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW"); W->net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP");
net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW"); W->net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES");
net_atom[net_wm_name] = ATOM("_NET_WM_NAME"); W->net_atom[net_desktop_geometry] = ATOM("_NET_DESKTOP_GEOMETRY");
net_atom[net_wm_pid] = ATOM("_NET_WM_PID"); W->net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW");
net_atom[net_wm_desktop] = ATOM("_NET_WM_DESKTOP"); W->net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW");
net_atom[net_showing_desktop] = ATOM("_NET_SHOWING_DESKTOP"); W->net_atom[net_wm_name] = ATOM("_NET_WM_NAME");
net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME"); W->net_atom[net_wm_pid] = ATOM("_NET_WM_PID");
net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE"); W->net_atom[net_wm_desktop] = ATOM("_NET_WM_DESKTOP");
net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK"); W->net_atom[net_showing_desktop] = ATOM("_NET_SHOWING_DESKTOP");
net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY"); W->net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME");
net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL"); W->net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE");
net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK"); W->net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK");
net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH"); W->net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY");
net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG"); W->net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL");
net_atom[net_wm_icon] = ATOM("_NET_WM_ICON"); W->net_atom[net_wm_window_type_desktop] = ATOM("_NET_WM_WINDOW_TYPE_DESKTOP");
net_atom[net_wm_state] = ATOM("_NET_WM_STATE"); W->net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK");
net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN"); W->net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH");
net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY"); W->net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION"); W->net_atom[net_wm_icon] = ATOM("_NET_WM_ICON");
net_atom[net_wm_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE"); W->net_atom[net_wm_state] = ATOM("_NET_WM_STATE");
net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA"); W->net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN");
net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL"); W->net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY");
W->net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION");
snprintf(systray_atom, sizeof(systray_atom), "_NET_SYSTEM_TRAY_S%d", 0/*SCREEN*/); W->net_atom[net_wm_state_hidden] = ATOM("_NET_WM_STATE_HIDDEN");
net_atom[net_system_tray_s] = ATOM(systray_atom); W->net_atom[net_system_tray_s] = ATOM("_NET_SYSTEM_TRAY_S0");
W->net_atom[net_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION"); W->net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA");
net_atom[xembed] = ATOM("_XEMBED"); W->net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL");
net_atom[xembedinfo] = ATOM("_XEMBED_INFO"); W->net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION");
net_atom[manager] = ATOM("MANAGER"); W->net_atom[xembed] = ATOM("_XEMBED");
net_atom[utf8_string] = ATOM("UTF8_STRING"); W->net_atom[xembedinfo] = ATOM("_XEMBED_INFO");
W->net_atom[manager] = ATOM("MANAGER");
W->net_atom[utf8_string] = ATOM("UTF8_STRING");
/* WMFS hints */ /* WMFS hints */
net_atom[wmfs_running] = ATOM("_WMFS_RUNNING"); W->net_atom[wmfs_running] = ATOM("_WMFS_RUNNING");
net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS"); W->net_atom[wmfs_focus] = ATOM("_WMFS_FOCUS");
net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN"); W->net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS");
net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT"); W->net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN");
net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG"); W->net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT");
net_atom[wmfs_tag_list] = ATOM("_WMFS_TAG_LIST"); W->net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG");
net_atom[wmfs_current_screen] = ATOM("_WMFS_CURRENT_SCREEN"); W->net_atom[wmfs_tag_list] = ATOM("_WMFS_TAG_LIST");
net_atom[wmfs_current_layout] = ATOM("_WMFS_CURRENT_LAYOUT"); W->net_atom[wmfs_current_screen] = ATOM("_WMFS_CURRENT_SCREEN");
net_atom[wmfs_mwfact] = ATOM("_WMFS_MWFACT"); W->net_atom[wmfs_current_layout] = ATOM("_WMFS_CURRENT_LAYOUT");
net_atom[wmfs_nmaster] = ATOM("_WMFS_NMASTER"); W->net_atom[wmfs_function] = ATOM("_WMFS_FUNCTION");
net_atom[wmfs_function] = ATOM("_WMFS_FUNCTION"); W->net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
net_atom[wmfs_font] = ATOM("_WMFS_FONT");
/* Multi atom _WMFS_STATUSTEXT_<screennum> */ XChangeProperty(W->dpy, W->root, W->net_atom[net_supported], XA_ATOM, 32,
for(j = 0; j < s; ++j) PropModeReplace, (unsigned char*)W->net_atom, net_last);
{
sprintf(st, "_WMFS_STATUSTEXT_%d", j);
net_atom[wmfs_statustext + j] = ATOM(st);
}
XChangeProperty(dpy, ROOT, net_atom[net_supported], XA_ATOM, 32, XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_running], XA_CARDINAL, 32,
PropModeReplace, (uchar*)net_atom, net_last + s); PropModeReplace, (unsigned char*)&b, 1);
XChangeProperty(dpy, ROOT, net_atom[wmfs_running], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&i, 1);
/* Set _NET_SUPPORTING_WM_CHECK */ /* Set _NET_SUPPORTING_WM_CHECK */
XChangeProperty(dpy, ROOT, net_atom[net_supporting_wm_check], XA_WINDOW, 32, XChangeProperty(W->dpy, W->root, W->net_atom[net_supporting_wm_check], XA_WINDOW, 32,
PropModeReplace, (uchar*)&ROOT, 1); PropModeReplace, (unsigned char*)&W->root, 1);
XChangeProperty(dpy, ROOT, net_atom[net_wm_name], net_atom[utf8_string], 8, XChangeProperty(W->dpy, W->root, ATOM("WM_CLASS"), XA_STRING, 8,
PropModeReplace, (uchar*)&rootn, strlen(rootn)); PropModeReplace, (unsigned char*)&"wmfs", 4);
XChangeProperty(dpy, ROOT, ATOM("WM_CLASS"), XA_STRING, 8, XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
PropModeReplace, (uchar*)&class, strlen(class)); PropModeReplace, (unsigned char*)&"wmfs2", 5);
/* Set _NET_WM_PID */ /*
XChangeProperty(dpy, ROOT, net_atom[net_wm_pid], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&pid, 1);
/* Set _NET_SHOWING_DESKTOP */ * Set _NET_WM_PID
XChangeProperty(dpy, ROOT, net_atom[net_showing_desktop], XA_CARDINAL, 32, XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_pid], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&showing_desk, 1); PropModeReplace, (unsigned char*)&pid, 1);
* Set _NET_SHOWING_DESKTOP
XChangeProperty(W->dpy, W->root, W->net_atom[net_showing_desktop], XA_CARDINAL, 32,
PropModeReplace, (unsigned char*)&showing_desk, 1);
*/
return;
} }
/** Send ewmh message void
ewmh_set_wm_state(Window w, int state)
{
unsigned char d[] = { state, None };
XChangeProperty(W->dpy, w, W->net_atom[wm_state],
W->net_atom[wm_state], 32, PropModeReplace, d, 2);
}
/*
* _NET_CLIENT_LIST
*/ */
void void
ewmh_send_message(Window d, Window w, char *atom, long d0, long d1, long d2, long d3, long d4) ewmh_get_client_list(void)
{ {
Window *list;
struct client *c;
int win_n = 0;
XClientMessageEvent e; SLIST_FOREACH(c, &W->h.client, next)
++win_n;
e.type = ClientMessage; list = xcalloc(win_n, sizeof(Window));
e.message_type = ATOM(atom);
e.window = w;
e.format = 32;
e.data.l[0] = d0;
e.data.l[1] = d1;
e.data.l[2] = d2;
e.data.l[3] = d3;
e.data.l[4] = d4;
XSendEvent(dpy, d, False, StructureNotifyMask, (XEvent*)&e); win_n = 0;
XSync(dpy, False); SLIST_FOREACH(c, &W->h.client, next)
list[win_n++] = c->win;
return; XChangeProperty(W->dpy, W->root, W->net_atom[net_client_list], XA_WINDOW, 32,
PropModeReplace, (unsigned char *)list, win_n);
XFree(list);
} }
/** Get xembed state /*
* Get xembed state
*/ */
long long
ewmh_get_xembed_state(Window win) ewmh_get_xembed_state(Window win)
{ {
Atom rf; Atom rf;
int f; int f;
ulong n, il;
long ret = 0; long ret = 0;
uchar *data = NULL; unsigned long n, il;
unsigned char *data = NULL;
if(XGetWindowProperty(dpy, win, net_atom[xembedinfo], 0L, 2, False, if(XGetWindowProperty(W->dpy, win, W->net_atom[xembedinfo], 0L, 2, False,
net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success) W->net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
return 0; return 0;
if(rf == net_atom[xembedinfo] && n == 2) if(rf == W->net_atom[xembedinfo] && n == 2)
ret = (long)data[1]; ret = (long)data[1];
if(n && data) if(n && data)
@ -189,263 +163,216 @@ ewmh_get_xembed_state(Window win)
return ret; return ret;
} }
/** Get the number of desktop (tag)
*/
void void
ewmh_get_number_of_desktop(void) ewmh_update_wmfs_props(void)
{ {
int c = 0, i; struct screen *s;
int i, ns = 0;
long *cts = NULL;
for(i = 0; i < screen_count(); ++i) SLIST_FOREACH(s, &W->h.screen, next)
c += conf.ntag[i]; ++ns;
XChangeProperty(dpy, ROOT, net_atom[net_number_of_desktops], XA_CARDINAL, 32, cts = xcalloc(ns, sizeof(long));
PropModeReplace, (uchar*)&c, 1);
return; for(i = 0; i < ns; ++i)
}
/** Get the current desktop
*/
void
ewmh_update_current_tag_prop(void)
{
int t;
char s[8] = { 0 };
screen_get_sel();
t = seltag[selscreen] - 1;
/* Get current desktop (tag) */
XChangeProperty(dpy, ROOT, net_atom[net_current_desktop], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&t, 1);
/* Current tag name */
XChangeProperty(dpy, ROOT, net_atom[wmfs_current_tag], net_atom[utf8_string], 8,
PropModeReplace, (uchar*)tags[selscreen][seltag[selscreen]].name,
strlen(tags[selscreen][seltag[selscreen]].name));
sprintf(s, "%.3f", tags[selscreen][t + 1].mwfact);
/* Current tag mwfact */
XChangeProperty(dpy, ROOT, net_atom[wmfs_mwfact], XA_STRING, 8,
PropModeReplace, (uchar*)s, strlen(s));
/* Current nmaster */
XChangeProperty(dpy, ROOT, net_atom[wmfs_nmaster], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&tags[selscreen][t + 1].nmaster, 1);
/* Current layout */
XChangeProperty(dpy, ROOT, net_atom[wmfs_current_layout], net_atom[utf8_string], 8,
PropModeReplace, (uchar*)tags[selscreen][seltag[selscreen]].layout.symbol,
strlen(tags[selscreen][seltag[selscreen]].layout.symbol));
return;
}
/** Get _NET_CLIENT_LIST
*/
void
ewmh_get_client_list(void)
{
Window *list;
Client *c;
int win_n = 0;
SLIST_FOREACH(c, &clients, next)
++win_n;
list = xcalloc(win_n, sizeof(Window));
win_n = 0;
SLIST_FOREACH(c, &clients, next)
list[win_n++] = c->win;
XChangeProperty(dpy, ROOT, net_atom[net_client_list], XA_WINDOW, 32,
PropModeReplace, (uchar *)list, win_n);
XFree(list);
return;
}
/** The desktop names
*/
void
ewmh_get_desktop_names(void)
{
char *str = NULL;
int S, s, i = 0, len = 0, pos = 0;
S = screen_count();
for(s = 0 ; s < S; ++s)
for(i = 1; i < conf.ntag[s] + 1; ++i)
len += strlen(tags[s][i].name);
str = xcalloc(len + i + 1, sizeof(char*));
for(s = 0; s < S; ++s)
for(i = 1; i < conf.ntag[s] + 1; ++i, ++pos)
{ {
strncpy(str + pos, tags[s][i].name, strlen(tags[s][i].name)); s = screen_gb_id(i);
pos += strlen(tags[s][i].name); cts[i] = (s->seltag ? s->seltag->id : 0);
str[pos] = '\0';
} }
XChangeProperty(dpy, ROOT, net_atom[net_desktop_names], net_atom[utf8_string], 8, XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], XA_CARDINAL, 32,
PropModeReplace, (uchar*)str, pos); PropModeReplace, (unsigned char*)cts, ns);
for(i = 0; i < pos; ++i) if(W->client)
if(str[i] == '\0' && i < pos - 1) XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_focus], XA_WINDOW, 32,
str[i] = ' '; PropModeReplace, (unsigned char*)&W->client->win, 1);
XChangeProperty(dpy, ROOT, net_atom[wmfs_tag_list], net_atom[utf8_string], 8, free(cts);
PropModeReplace, (uchar*)str, pos);
free(str);
return;
} }
/** Manage _NET_DESKTOP_GEOMETRY
*/
void void
ewmh_set_desktop_geometry(void) ewmh_manage_state(long data[], struct client *c)
{ {
long data[2] = { MAXW, MAXH }; /* _NET_WM_STATE_FULLSCREEN */
if(data[1] == (long)W->net_atom[net_wm_state_fullscreen]
XChangeProperty(dpy, ROOT, net_atom[net_desktop_geometry], XA_CARDINAL, 32, || data[2] == (long)W->net_atom[net_wm_state_fullscreen])
PropModeReplace, (uchar*)&data, 2);
return;
}
/** Manage _NET_WM_STATE_* ewmh
*/
void
ewmh_manage_net_wm_state(long data_l[], Client *c)
{
/* Manage _NET_WM_STATE_FULLSCREEN */
if(data_l[1] == (long)net_atom[net_wm_state_fullscreen])
{ {
if(data_l[0] == _NET_WM_STATE_ADD && !(c->flags & FSSFlag)) if(data[0] == _NET_WM_STATE_ADD
|| (data[0] == _NET_WM_STATE_TOGGLE && !(c->flags & CLIENT_FULLSCREEN)))
{ {
c->screen = screen_get_with_geo(c->geo.x, c->geo.y); c->flags |= CLIENT_FULLSCREEN;
c->flags &= ~UnmapFlag;
XMapWindow(dpy, c->win);
XReparentWindow(dpy, c->win, ROOT, spgeo[c->screen].x, spgeo[c->screen].y);
XResizeWindow(dpy, c->win,
spgeo[c->screen].width,
spgeo[c->screen].height);
XChangeProperty(dpy, c->win, net_atom[net_wm_state], XA_ATOM, 32,
PropModeReplace, (uchar *)&net_atom[net_wm_state_fullscreen], 1);
c->tmp_geo = c->geo; XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
(unsigned char*)&W->net_atom[net_wm_state_fullscreen], 1);
XReparentWindow(W->dpy, c->win, W->root, c->screen->geo.x, c->screen->geo.y);
XResizeWindow(W->dpy, c->win, c->screen->geo.w, c->screen->geo.h);
if(c->flags & FreeFlag) if(c->tag)
c->ogeo = c->geo;
c->flags |= (FSSFlag | MaxFlag);
client_raise(c);
client_focus(c); client_focus(c);
XUnmapWindow(dpy, c->frame);
XRaiseWindow(W->dpy, c->win);
} }
else if(data_l[0] == _NET_WM_STATE_REMOVE && (c->flags & FSSFlag)) else
{ {
XChangeProperty(dpy, c->win, net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace, (uchar *)0, 0); c->flags &= ~CLIENT_FULLSCREEN;
c->flags &= ~(FSSFlag | MaxFlag);
client_map(c); XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
XReparentWindow(dpy, c->win, c->frame, BORDH, TBARH); (unsigned char*)0, 0);
client_moveresize(c, c->tmp_geo, False); XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y);
if(c->flags & CLIENT_FREE)
client_moveresize(c, &c->geo);
else
layout_fix_hole(c);
} }
} }
/* Manage _NET_WM_STATE_STICKY */
else if(data_l[1] == (long)net_atom[net_wm_state_sticky])
{
/* == client_ignore_tag */
c->tag = MAXTAG + 1;
arrange(c->screen, True);
}
/* Manage _NET_WM_STATE_DEMANDS_ATTENTION */
else if(data_l[1] == (long)net_atom[net_wm_state_demands_attention])
{
if(data_l[0] == _NET_WM_STATE_ADD)
client_urgent(c, True);
if(data_l[0] == _NET_WM_STATE_REMOVE)
if(c == sel)
client_focus(NULL);
}
return;
} }
bool
/** Manage the client hints ewmh_manage_state_sticky(Window win)
*\param c Client pointer
*/
void
ewmh_manage_window_type(Client *c)
{ {
Atom *atom, rf; Atom *atom, rf;
int f; int f;
ulong n, il, i; unsigned long n, il, i;
uchar *data = NULL; unsigned char *data = NULL;
long ldata[5] = { 0 }; bool is_sticky = false;
if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL, if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n) XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{ {
atom = (Atom*)data; atom = (Atom*)data;
for(i = 0; i < n; ++i) for(i = 0; i < n; ++i)
{ {
/* Manage _NET_WM_WINDOW_TYPE_DOCK & _NET_WM_WINDOW_TYPE_SPLASH */ /* manage _NET_WM_STATE_STICKY */
if(atom[i] == net_atom[net_wm_window_type_dock] if(atom[i] == W->net_atom[net_wm_state_sticky])
|| atom[i] == net_atom[net_wm_window_type_splash])
{ {
/* Unmap frame, decoration.. */ XWindowAttributes at;
client_unmap(c);
/* Map only window */ XMapWindow(W->dpy, win);
XMapWindow(dpy, c->win); XMapSubwindows(W->dpy, win);
/* Reparent it to ROOT win */ if(XGetWindowAttributes(W->dpy, win, &at))
XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y);
XRaiseWindow(dpy, c->win);
c->flags |= DockFlag;
}
/* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
else if(atom[i] == net_atom[net_wm_window_type_dialog])
{ {
c->flags |= FreeFlag; struct geo g;
c->flags &= ~(TileFlag | MaxFlag | LMaxFlag);
client_moveresize(c, c->ogeo, True); if(at.x < W->screen->ugeo.x)
client_focus(c); g.x = W->screen->ugeo.x;
layout_func(selscreen, seltag[selscreen]); else if((at.x + at.width) > W->screen->ugeo.w)
g.x = W->screen->ugeo.w - at.width;
else
g.x = at.x;
if(at.y < W->screen->ugeo.y)
g.y = W->screen->ugeo.y;
else if((at.y + at.height) > W->screen->ugeo.h)
g.y = W->screen->ugeo.h - at.height;
else
g.y = at.y;
XMoveWindow(W->dpy, win, g.x, g.y);
}
if(W->client)
{
XUngrabButton(W->dpy, AnyButton, AnyModifier, W->client->win);
XGrabButton(W->dpy, AnyButton, AnyModifier, W->client->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
client_frame_update(W->client, &W->client->ncol);
W->client = NULL;
}
XRaiseWindow(W->dpy, win);
XSetInputFocus(W->dpy, win, RevertToPointerRoot, CurrentTime);
XChangeProperty(W->dpy, W->root, W->net_atom[net_active_window], XA_WINDOW, 32,
PropModeReplace, (unsigned char *)&win, 1);
is_sticky = true;
break;
} }
} }
XFree(data); XFree(data);
} }
/* Get NET_WM_STATE set without sending client message event */ return is_sticky;
if(XGetWindowProperty(dpy, c->win, net_atom[net_wm_state], 0L, 0x7FFFFFFFL,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
ldata[0] = _NET_WM_STATE_ADD;
ldata[1] = atom[i];
ewmh_manage_net_wm_state(ldata, c);
}
XFree(data);
}
return;
} }
void
ewmh_manage_window_type(struct client *c)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
long ldata[5] = { _NET_WM_STATE_ADD };
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFFL,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
if(atom[i] == W->net_atom[net_wm_window_type_dialog])
c->flags |= CLIENT_FREE;
}
XFree(data);
}
/* _NET_WM_STATE at window mangement */
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
ldata[1] = atom[i];
ewmh_manage_state(ldata, c);
}
XFree(data);
}
}
bool
ewmh_manage_window_type_desktop(Window win)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
bool is_desktop = false;
if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFF,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* If it is a _NET_WM_WINDOW_TYPE_DESKTOP window */
if(atom[i] == W->net_atom[net_wm_window_type_desktop])
{
/* map it, but don't manage it */
XMapWindow(W->dpy, win);
XMapSubwindows(W->dpy, win);
is_desktop = true;
break;
}
}
XFree(data);
}
return is_desktop;
}

131
src/ewmh.h Normal file
View File

@ -0,0 +1,131 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef EWMH_H
#define EWMH_H
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "wmfs.h"
#include "util.h"
/* EWMH/Xembed const from freedesktop */
#define XEMBED_MAPPED (1 << 0)
#define XEMBED_EMBEDDED_NOTIFY 0
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_WINDOW_DEACTIVATE 2
#define XEMBED_REQUEST_FOCUS 3
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
#define XEMBED_FOCUS_NEXT 6
#define XEMBED_FOCUS_PREV 7
/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
#define XEMBED_MODALITY_ON 10
#define XEMBED_MODALITY_OFF 11
#define XEMBED_REGISTER_ACCELERATOR 12
#define XEMBED_UNREGISTER_ACCELERATOR 13
#define XEMBED_ACTIVATE_ACCELERATOR 14
/* Details for XEMBED_FOCUS_IN: */
#define XEMBED_FOCUS_CURRENT 0
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2
/* Ewmh hints list */
enum
{
/* ICCCM */
wm_state,
wm_class,
wm_name,
/* EWMH */
net_supported,
net_wm_name,
net_client_list,
net_frame_extents,
net_number_of_desktops,
net_current_desktop,
net_desktop_names,
net_desktop_geometry,
net_active_window,
net_close_window,
net_wm_icon_name,
net_wm_window_type,
net_wm_pid,
net_showing_desktop,
net_supporting_wm_check,
net_wm_window_opacity,
net_wm_window_type_normal,
net_wm_window_type_desktop,
net_wm_window_type_dock,
net_wm_window_type_splash,
net_wm_window_type_dialog,
net_wm_desktop,
net_wm_icon,
net_wm_state,
net_wm_state_fullscreen,
net_wm_state_sticky,
net_wm_state_demands_attention,
net_wm_state_hidden,
net_system_tray_opcode,
net_system_tray_message_data,
net_system_tray_s,
net_system_tray_visual,
net_system_tray_orientation,
xembed,
xembedinfo,
manager,
utf8_string,
/* WMFS HINTS */
wmfs_running,
wmfs_focus,
wmfs_update_hints,
wmfs_current_tag,
wmfs_current_screen,
wmfs_current_layout,
wmfs_tag_list,
wmfs_mwfact,
wmfs_nmaster,
wmfs_set_screen,
wmfs_screen_count,
wmfs_function,
wmfs_cmd,
wmfs_font,
wmfs_statustext,
net_last
};
static inline void
ewmh_send_message(Window d, Window w, char *atom, long d0, long d1, long d2, long d3, long d4)
{
XClientMessageEvent e;
e.type = ClientMessage;
e.message_type = ATOM(atom);
e.window = w;
e.format = 32;
e.data.l[0] = d0;
e.data.l[1] = d1;
e.data.l[2] = d2;
e.data.l[3] = d3;
e.data.l[4] = d4;
XSendEvent(W->dpy, d, false, StructureNotifyMask, (XEvent*)&e);
XSync(W->dpy, False);
}
void ewmh_init(void);
void ewmh_set_wm_state(Window w, int state);
void ewmh_get_client_list(void);
long ewmh_get_xembed_state(Window win);
void ewmh_update_wmfs_props(void);
void ewmh_manage_state(long data[], struct client *c);
bool ewmh_manage_state_sticky(Window win);
void ewmh_manage_window_type(struct client *c);
bool ewmh_manage_window_type_desktop(Window win);
#endif /* EWMH_H */

19
src/fifo.h Normal file
View File

@ -0,0 +1,19 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* File created by David Delassus.
* For license, see COPYING.
*/
#ifndef __FIFO_H
#define __FIFO_H
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
void fifo_init(void);
void fifo_read(void);
#endif /* __FIFO_H */

View File

@ -1,320 +0,0 @@
/*
* frame.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
/** Frame creation function, for make a
* client frame, and configure it
* \param c Client pointer
*/
void
frame_create(Client *c)
{
XSetWindowAttributes at;
int i;
at.background_pixel = conf.client.bordernormal;
at.background_pixmap = ParentRelative;
at.override_redirect = True;
at.bit_gravity = StaticGravity;
at.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
|ExposureMask|VisibilityChangeMask
|EnterWindowMask|LeaveWindowMask|FocusChangeMask
|KeyMask|ButtonMask|MouseMask;
/* Set property */
c->frame_geo.x = c->geo.x - BORDH;
c->frame_geo.y = c->geo.y - TBARH;
c->frame_geo.width = FRAMEW(c->geo.width);
c->frame_geo.height = FRAMEH(c->geo.height);
c->colors.fg = conf.titlebar.fg_normal;
c->colors.frame = conf.client.bordernormal;
c->colors.resizecorner = conf.client.resizecorner_normal;
/* Create frame window */
CWIN(c->frame, ROOT,
c->frame_geo.x,
c->frame_geo.y,
c->frame_geo.width,
c->frame_geo.height, 0,
CWOverrideRedirect | CWBackPixmap | CWEventMask,
c->colors.frame, &at);
/* Create titlebar window */
if(TBARH - BORDH)
{
c->titlebar = barwin_create(c->frame, 0, 0,
c->frame_geo.width ,
TBARH,
c->colors.frame,
c->colors.fg,
True, conf.titlebar.stipple.active, False);
/* Buttons */
if(BUTTONWH >= 1)
{
c->button = xcalloc(conf.titlebar.nbutton, sizeof(Window));
for(i = 0; i < conf.titlebar.nbutton; ++i)
{
CWIN(c->button[i], c->titlebar->win,
(c->button_last_x = (BORDH + (BUTTONWH * i) + (i << 2))),
((BUTTONWH - 1) >> 1), BUTTONWH, BUTTONWH,
1, CWEventMask|CWOverrideRedirect|CWBackPixmap,
c->colors.frame, &at);
XSetWindowBorder(dpy, c->button[i], getcolor(c->colors.fg));
}
}
}
at.event_mask &= ~(EnterWindowMask | LeaveWindowMask); /* <- Delete useless mask */
/* Create resize area */
at.cursor = cursor[CurRightResize];
CWIN(c->resize[Right], c->frame,
c->frame_geo.width - RESHW,
c->frame_geo.height - RESHW,
RESHW, RESHW, 0,
CWEventMask | CWBackPixel | CWCursor,
c->colors.resizecorner, &at);
at.cursor = cursor[CurLeftResize];
CWIN(c->resize[Left], c->frame,
0, c->frame_geo.height - RESHW,
RESHW, RESHW, 0,
CWEventMask | CWBackPixel | CWCursor,
c->colors.resizecorner, &at);
/* Border (for shadow) */
if(conf.client.border_shadow)
{
c->colors.borddark = color_shade(c->colors.frame, conf.colors.client_dark_shade);
c->colors.bordlight = color_shade(c->colors.frame, conf.colors.client_light_shade);
CWIN(c->left, c->frame, 0, 0, SHADH, c->frame_geo.height, 0, CWBackPixel, c->colors.bordlight, &at);
CWIN(c->top, c->frame, 0, 0, c->frame_geo.width, SHADH, 0, CWBackPixel, c->colors.bordlight, &at);
CWIN(c->bottom, c->frame, 0, c->frame_geo.height - SHADH, c->frame_geo.width, SHADH, 0, CWBackPixel, c->colors.borddark, &at);
CWIN(c->right, c->frame, c->frame_geo.width - SHADH, 0, SHADH, c->frame_geo.height, 0, CWBackPixel, c->colors.borddark, &at);
}
/* Reparent window with the frame */
XReparentWindow(dpy, c->win, c->frame, BORDH, TBARH);
return;
}
/** Delete a frame
* \param c The client frame
*/
void
frame_delete(Client *c)
{
/* If there is, delete the titlebar */
if(TBARH - BORDH)
{
barwin_delete_subwin(c->titlebar);
barwin_delete(c->titlebar);
}
/* Delete the frame's sub win and the frame */
XDestroySubwindows(dpy, c->frame);
XDestroyWindow(dpy, c->frame);
return;
}
/** Move a frame
* \param c The client frame
* \param geo Coordinate info for move the frame
*/
void
frame_moveresize(Client *c, Geo geo)
{
CHECK(c);
c->frame_geo.x = (geo.x) ? geo.x - BORDH : c->frame_geo.x;
c->frame_geo.y = (geo.y) ? geo.y - TBARH : c->frame_geo.y;
c->frame_geo.width = (geo.width) ? FRAMEW(geo.width) : c->frame_geo.width;
c->frame_geo.height = (geo.height) ? FRAMEH(geo.height) : c->frame_geo.height;
/* Frame */
XMoveResizeWindow(dpy, c->frame,
c->frame_geo.x,
c->frame_geo.y,
c->frame_geo.width,
c->frame_geo.height);
/* Titlebar */
if(TBARH - BORDH)
barwin_resize(c->titlebar, c->frame_geo.width, TBARH);
/* Resize area */
XMoveWindow(dpy, c->resize[Right], c->frame_geo.width - RESHW, c->frame_geo.height - RESHW);
XMoveWindow(dpy, c->resize[Left], 0, c->frame_geo.height - RESHW);
/* Border */
if(conf.client.border_shadow)
{
XResizeWindow(dpy, c->left, SHADH, c->frame_geo.height - SHADH);
XResizeWindow(dpy, c->top, c->frame_geo.width, SHADH);
XMoveResizeWindow(dpy, c->bottom, 0, c->frame_geo.height - SHADH, c->frame_geo.width, SHADH);
XMoveResizeWindow(dpy, c->right, c->frame_geo.width - SHADH, 0, SHADH, c->frame_geo.height);
}
return;
}
/** Update frame colors for focus event
*\param c Client pointer
*/
void
frame_update_color(Client *c, bool focused)
{
CHECK(c);
/* Not focused client */
if(focused)
{
c->colors.frame = conf.client.bordernormal;
c->colors.fg = conf.titlebar.fg_normal;
c->colors.resizecorner = conf.client.resizecorner_normal;
if(TBARH - BORDH)
c->titlebar->stipple_color = conf.titlebar.stipple.colors.normal;
}
/* Focused */
else
{
c->colors.frame = conf.client.borderfocus;
c->colors.fg = conf.titlebar.fg_focus;
c->colors.resizecorner = conf.client.resizecorner_focus;
if(TBARH - BORDH)
c->titlebar->stipple_color = conf.titlebar.stipple.colors.focus;
}
if(conf.client.border_shadow)
{
c->colors.borddark = color_shade(c->colors.frame, conf.colors.client_dark_shade);
c->colors.bordlight = color_shade(c->colors.frame, conf.colors.client_light_shade);
}
return;
}
/** Update the client frame; Set the new color
* and the title --> refresh
* \param c Client pointer
*/
void
frame_update(Client *c)
{
int i;
CHECK(c);
if(TBARH - BORDH)
{
c->titlebar->bg = c->colors.frame;
c->titlebar->fg = c->colors.fg;
barwin_refresh_color(c->titlebar);
/* Buttons */
if(conf.titlebar.nbutton && BUTTONWH >= 1)
{
if(conf.titlebar.stipple.active)
draw_rectangle(c->titlebar->dr, 0, 0, c->button_last_x + TBARH - (TBARH >> 2),
TBARH + (BORDH << 2), c->colors.frame);
for(i = 0; i < conf.titlebar.nbutton; ++i)
{
XSetWindowBackground(dpy, c->button[i], c->colors.frame);
XClearWindow(dpy, c->button[i]);
if((!conf.titlebar.button[i].flags)
|| ((conf.titlebar.button[i].flags & FreeFlag)
&& ((c->flags & FreeFlag) || !(c->flags & (TileFlag | LMaxFlag))))
|| ((conf.titlebar.button[i].flags & MaxFlag)
&& ((c->flags & MaxFlag) || (c->flags & LMaxFlag)))
|| ((conf.titlebar.button[i].flags & TileFlag) && (c->flags & TileFlag)))
{
XSetWindowBorder(dpy, c->button[i], getcolor(c->colors.fg));
/* Button's lines */
if(conf.titlebar.button[i].nlines)
{
XSetForeground(dpy, gc, getcolor(c->colors.fg));
XDrawSegments(dpy, c->button[i], gc,
conf.titlebar.button[i].linecoord,
conf.titlebar.button[i].nlines);
}
}
else
XSetWindowBorder(dpy, c->button[i], c->colors.frame);
}
}
}
XSetWindowBackground(dpy, c->frame, c->colors.frame);
XSetWindowBackground(dpy, c->resize[Right], c->colors.resizecorner);
XSetWindowBackground(dpy, c->resize[Left], c->colors.resizecorner);
XClearWindow(dpy, c->frame);
XClearWindow(dpy, c->resize[Right]);
XClearWindow(dpy, c->resize[Left]);
if(conf.client.border_shadow)
{
XSetWindowBackground(dpy, c->left, c->colors.bordlight);
XSetWindowBackground(dpy, c->top, c->colors.bordlight);
XSetWindowBackground(dpy, c->right, c->colors.borddark);
XSetWindowBackground(dpy, c->bottom, c->colors.borddark);
XClearWindow(dpy, c->left);
XClearWindow(dpy, c->top);
XClearWindow(dpy, c->right);
XClearWindow(dpy, c->bottom);
}
if(TBARH - BORDH)
barwin_draw_text(c->titlebar,
(c->frame_geo.width >> 1) - (textw(c->title) >> 1),
((font.height - font.de) + ((TBARH - font.height) >> 1)),
c->title);
return;
}

File diff suppressed because it is too large Load Diff

93
src/infobar.h Normal file
View File

@ -0,0 +1,93 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef INFOBAR_H
#define INFOBAR_H
#include "wmfs.h"
#include "util.h"
#include "tag.h"
enum { ElemTag = 0, ElemStatus, ElemSystray, ElemLauncher, ElemCustom, ElemLast };
struct infobar *infobar_new(struct screen *s, char *name, struct theme *theme, enum barpos pos, const char *elem);
void infobar_elem_update(struct infobar *i, int type);
void infobar_refresh(struct infobar *i);
void infobar_remove(struct infobar *i);
void infobar_free(struct screen *s);
void infobar_elem_reinit(struct infobar *i);
/* Basic placement of elements */
static inline void
infobar_elem_placement(struct element *e)
{
struct element *p = TAILQ_PREV(e, esub, next);
e->geo.y = 0;
e->geo.h = e->infobar->geo.h;
if(e->align == Left)
e->geo.x = (p ? p->geo.x + p->geo.w : 0);
else
e->geo.x = ((p = TAILQ_NEXT(e, next))
? p->geo.x - e->geo.w
: e->infobar->geo.w - e->geo.w);
}
/* Bars placement management and usable space management */
static inline bool
infobar_placement(struct infobar *i, enum barpos p)
{
i->pos = p;
i->geo = i->screen->ugeo;
i->geo.h = i->theme->bars_width;
switch(p)
{
case BarTop:
i->screen->ugeo.y += i->geo.h;
i->screen->ugeo.h -= i->geo.h;
break;
case BarBottom:
i->geo.y = (i->screen->ugeo.y + i->screen->ugeo.h) - i->geo.h;
i->screen->ugeo.h -= i->geo.h;
break;
default:
case BarHide:
return false;
}
return true;
}
static inline void
infobar_elem_screen_update(struct screen *s, int type)
{
struct infobar *i;
SLIST_FOREACH(i, &s->infobars, next)
infobar_elem_update(i, type);
}
static inline struct infobar*
infobar_gb_name(const char *name)
{
struct screen *s;
struct infobar *i;
SLIST_FOREACH(s, &W->h.screen, next)
{
SLIST_FOREACH(i, &s->infobars, next)
if(!strcmp(i->name, name))
return i;
}
return SLIST_FIRST(&s->infobars);
}
void uicb_infobar_toggle_hide(Uicb iname);
#endif /* INFOBAR_H */

View File

@ -1,227 +0,0 @@
/*
* wmfs.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
const func_name_list_t layout_list[] =
{
{"tile", tile },
{"tile_right", tile },
{"tile_left", tile_left },
{"tile_top", tile_top },
{"tile_bottom", tile_bottom },
{"tile_grid", grid_horizontal },
{"tile_grid_horizontal", grid_horizontal },
{"tile_grid_vertical", grid_vertical },
{"grid", grid_horizontal },
{"mirror_vertical", mirror_vertical },
{"tile_mirror_vertical", mirror_vertical },
{"mirror_horizontal", mirror_horizontal },
{"tile_mirror_horizontal", mirror_horizontal },
{"max", maxlayout },
{"maxlayout", maxlayout },
{"freelayout", freelayout },
{"free", freelayout },
{ NULL, NULL }
};
/** Init the font
*/
static void
init_font(void)
{
#ifdef HAVE_XFT
if(conf.use_xft)
{
if(!(font.font = XftFontOpenName(dpy, SCREEN, conf.font)))
{
warnx("WMFS Error: Cannot initialize Xft font");
font.font = XftFontOpenName(dpy, SCREEN, "sans-10");
}
font.de = font.font->descent;
font.as = font.font->ascent;
font.height = font.font->height;
}
else
#endif /* HAVE_XFT */
{
char **misschar, **names, *defstring;
int d;
XFontStruct **xfs = NULL;
/* locale support */
setlocale(LC_CTYPE, "");
if(!conf.font)
conf.font = xstrdup("fixed");
/* Using Font Set */
if(!(font.fontset = XCreateFontSet(dpy, conf.font, &misschar, &d, &defstring)))
{
warnx("Can't load font '%s'", conf.font);
font.fontset = XCreateFontSet(dpy, "fixed", &misschar, &d, &defstring);
}
XExtentsOfFontSet(font.fontset);
XFontsOfFontSet(font.fontset, &xfs, &names);
font.as = xfs[0]->max_bounds.ascent;
font.de = xfs[0]->max_bounds.descent;
font.width = xfs[0]->max_bounds.width;
font.height = font.as + font.de;
if(misschar)
XFreeStringList(misschar);
}
/* Set font in _WMFS_FONT for eventual status tools */
XChangeProperty(dpy, ROOT, net_atom[wmfs_font], net_atom[utf8_string], 8,
PropModeReplace, (uchar*)conf.font, strlen(conf.font));
return;
}
/** Init the graphic context
*/
static void
init_gc(void)
{
XGCValues gcv;
/* Bits sequences */
const char pix_bits[] =
{
0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55
};
gc = DefaultGC(dpy, SCREEN);
/* Stipple GC */
gcv.function = GXcopy;
gcv.fill_style = FillStippled;
gcv.stipple = XCreateBitmapFromData(dpy, ROOT, pix_bits, 10, 4);
gc_stipple = XCreateGC(dpy, ROOT, GCFunction | GCFillStyle | GCStipple, &gcv);
return;
}
/** Init WMFS cursor
*/
static void
init_cursor(void)
{
cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurRightResize] = XCreateFontCursor(dpy, XC_lr_angle);
cursor[CurLeftResize] = XCreateFontCursor(dpy, XC_ll_angle);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
return;
}
/** Init key modifier
*/
static void
init_key(void)
{
int i, j;
XModifierKeymap *modmap = XGetModifierMapping(dpy);
for(i = 0; i < 8; i++)
for(j = 0; j < modmap->max_keypermod; ++j)
if(modmap->modifiermap[i * modmap->max_keypermod + j]
== XKeysymToKeycode(dpy, XK_Num_Lock))
numlockmask = (1 << i);
XFreeModifiermap(modmap);
return;
}
/** Init root Window
*/
static void
init_root(void)
{
XSetWindowAttributes at;
at.event_mask = KeyMask | ButtonMask | MouseMask | PropertyChangeMask
| SubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask;
at.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, ROOT, CWEventMask | CWCursor, &at);
if(conf.root.background_command)
spawn("%s", conf.root.background_command);
ewmh_init_hints();
ewmh_get_number_of_desktop();
ewmh_get_desktop_names();
return;
}
/** Init WMFS
*/
void
init(void)
{
/* Init lists heads */
SLIST_INIT(&bwhead);
SLIST_INIT(&smhead);
SLIST_INIT(&clients);
SLIST_INIT(&trayicons);
/* First init */
ewmh_init_hints();
init_conf();
init_gc();
init_font();
init_cursor();
init_key();
init_root();
screen_init_geo();
event_make_array();
infobar_init();
systray_acquire();
ewmh_update_current_tag_prop();
grabkeys();
return;
}

View File

@ -1,127 +1,110 @@
/* /*
* launcher.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without #include <string.h>
* modification, are permitted provided that the following conditions are #include <dirent.h>
* met: #include <sys/stat.h>
* #include <X11/Xutil.h>
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h" #include "wmfs.h"
#include "event.h"
#include "util.h"
#include "infobar.h"
#include "config.h"
/* static int
* Just search command in PATH. qsort_string_compare(const void * a, const void * b)
* Return the characters to complete the command. {
*/ return (strcmp(*(char **)a, *(char **)b));
static char * }
complete_on_command(char *start, size_t hits)
static char **
complete_on_command(char *start)
{ {
char *path;
char *dirname;
char *ret = NULL;
DIR *dir;
struct dirent *content; struct dirent *content;
DIR *dir;
char **paths, *path, *p, **namelist = NULL;
int i, count;
char **namelist = NULL; if(!(path = getenv("PATH")) || !start)
int n = 0, i;
if (!getenv("PATH") || !start || hits <= 0)
return NULL; return NULL;
path = xstrdup(getenv("PATH")); /* split PATH into paths */
dirname = strtok(path, ":"); path = p = xstrdup(path);
for(count = 1, p = path; strchr(p, ':'); ++p, ++count);
paths = xcalloc(count, sizeof(*paths));
for(paths[0] = p = path, count = 1; (p = strchr(p, ':')); ++p, ++count)
{
paths[count] = p + 1;
*p = '\0';
}
paths[count] = NULL;
/* recursively open PATH */ /* recursively open PATH */
while (dirname != NULL) for(i = count = 0; paths[i]; ++i)
{ {
if ((dir = opendir(dirname))) if(!(dir = opendir(paths[i])))
continue;
while((content = readdir(dir)))
{ {
while ((content = readdir(dir))) if(strncmp(content->d_name, ".", 1)
&& !strncmp(content->d_name, start, strlen(start)))
{ {
if(strncmp(content->d_name, ".", 1)) namelist = xrealloc(namelist, ++count, sizeof(*namelist));
{ namelist[count - 1] = xstrdup(content->d_name + strlen(start));
if (!strncmp(content->d_name, start, strlen(start)))
{
namelist = xrealloc(namelist, ++n, sizeof(*namelist));
namelist[n-1] = xstrdup(content->d_name);
}
} }
} }
closedir(dir); closedir(dir);
} }
dirname = strtok(NULL, ":");
if(count)
{
qsort(namelist, count, sizeof(char *), qsort_string_compare);
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = NULL;
} }
free(paths);
free(path); free(path);
if(n > 0) return namelist;
{
qsort(namelist, n, sizeof(char *), qsort_string_compare);
ret = xstrdup(namelist[((hits > 0) ? hits - 1 : 0) % n] + strlen(start));
for(i = 0; i < n; i++)
free(namelist[i]);
free(namelist);
}
return ret;
} }
/* /*
* Complete a filename or directory name. * Complete a filename or directory name.
* works like complete_on_command. * works like complete_on_command.
*/ */
static char * static char **
complete_on_files(char *start, size_t hits) complete_on_files(char *start)
{ {
char *ret = NULL;
char *p = NULL;
char *dirname = NULL;
char *path = NULL;
char *filepath = NULL;
DIR *dir = NULL;
struct dirent *content = NULL; struct dirent *content = NULL;
struct stat st; struct stat st;
size_t count = 0; DIR *dir;
char *home, *path, *dirname = NULL;
if (!start || hits <= 0 || !(p = strrchr(start, ' '))) char **namelist = NULL, *filepath, *p = start;
return NULL; int count = 0;
/* /*
* Search the directory to open and set * Search the directory to open and set
* the beginning of file to complete on pointer 'p'. * the beginning of file to complete on pointer 'p'.
*/ */
if (*(++p) == '\0' || !strrchr(p, '/')) if(*p == '\0' || !strrchr(p, '/'))
path = xstrdup("."); path = xstrdup(".");
else else
{ {
if(!(home = getenv("HOME")))
return NULL;
/* remplace ~ by $HOME in dirname */ /* remplace ~ by $HOME in dirname */
if (!strncmp(p, "~/", 2) && getenv("HOME")) if(!strncmp(p, "~/", 2) && home)
xasprintf(&dirname, "%s%s", getenv("HOME"), p+1); xasprintf(&dirname, "%s%s", home, p+1);
else else
dirname = xstrdup(p); dirname = xstrdup(p);
@ -131,7 +114,7 @@ complete_on_files(char *start, size_t hits)
* <---- path - ---><------- p ------> * <---- path - ---><------- p ------>
*/ */
p = strrchr(dirname, '/'); p = strrchr(dirname, '/');
if (p != dirname) if(p != dirname)
{ {
*(p++) = '\0'; *(p++) = '\0';
path = xstrdup(dirname); path = xstrdup(dirname);
@ -143,242 +126,313 @@ complete_on_files(char *start, size_t hits)
} }
} }
if ((dir = opendir(path))) if((dir = opendir(path)))
{ {
while ((content = readdir(dir))) while((content = readdir(dir)))
{ {
if (!strcmp(content->d_name, ".") || !strcmp(content->d_name, "..")) if(!strcmp(content->d_name, ".")
|| !strcmp(content->d_name, "..")
|| strncmp(content->d_name, p, strlen(p)))
continue; continue;
if (!strncmp(content->d_name, p, strlen(p)) && ++count == hits)
{
/* If it's a directory append '/' to the completion */ /* If it's a directory append '/' to the completion */
xasprintf(&filepath, "%s/%s", path, content->d_name); xasprintf(&filepath, "%s/%s", path, content->d_name);
if (filepath && stat(filepath, &st) != -1) if(filepath && stat(filepath, &st) != -1)
{ {
if (S_ISDIR(st.st_mode)) namelist = xrealloc(namelist, ++count, sizeof(*namelist));
xasprintf(&ret, "%s/", content->d_name + strlen(p));
if(S_ISDIR(st.st_mode))
xasprintf(&namelist[count - 1], "%s/", content->d_name + strlen(p));
else else
ret = xstrdup(content->d_name + strlen(p)); namelist[count - 1] = xstrdup(content->d_name + strlen(p));
} }
else else
warn("%s", filepath); warnl("%s", filepath);
free(filepath); free(filepath);
break;
}
} }
closedir(dir); closedir(dir);
} }
if(count)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = NULL;
}
free(dirname); free(dirname);
free(path); free(path);
return ret; return namelist;
} }
static void static void
launcher_execute(Launcher *launcher) complete_cache_free(struct launcher_ccache *cache)
{ {
BarWindow *bw; int i;
bool found;
bool lastwastab = False; /* release memory */
bool my_guitar_gently_wheeps = True; free(cache->start);
if(cache->namelist)
{
for(i = 0; cache->namelist[i]; i++)
free(cache->namelist[i]);
free(cache->namelist);
}
/* init */
cache->hits = 0;
cache->start = NULL;
cache->namelist = NULL;
}
static char *
complete(struct launcher_ccache *cache, char *start)
{
char *p = NULL, *comp = NULL;
if(!start || !cache)
return NULL;
if((p = strrchr(start, ' ')))
p++;
else
p = start;
if(cache->start && !strcmp(cache->start, start))
{
if(cache->namelist && !cache->namelist[cache->hits])
cache->hits = 0;
}
else
{
complete_cache_free(cache);
cache->start = xstrdup(start);
if(p == start)
cache->namelist = complete_on_command(p);
else
cache->namelist = complete_on_files(p);
}
if(cache->namelist && cache->namelist[cache->hits])
comp = cache->namelist[cache->hits];
return comp;
}
#define LAUNCHER_INIT_ELEM(width) \
SLIST_FOREACH(ib, &W->screen->infobars, next) \
{ \
TAILQ_FOREACH(e, &ib->elements, next) \
if(e->type == ElemLauncher) \
{ \
e->geo.w = width; \
e->data = data; \
} \
infobar_elem_reinit(ib); \
}
static void
launcher_process(struct launcher *l)
{
struct infobar *ib;
struct element *e;
struct launcher_ccache cache = {NULL, NULL, 0};
bool loop = true, found = false, lastwastab = false;
char tmpbuf[512] = { 0 }, buf[512] = { 0 };
char tmp[32] = { 0 }; char tmp[32] = { 0 };
char buf[512] = { 0 }; char *p, *data, *arg, *end, *cmd = xstrdup(l->command);
char tmpbuf[512] = { 0 }; int i, pos = 0, histpos = 0;
char *complete; void (*func)(Uicb);
int i, pos = 0, histpos = 0, w, x = 0;
int tabhits = 0;
KeySym ks;
XEvent ev; XEvent ev;
InfobarElem *e; KeySym ks;
screen_get_sel(); W->flags |= WMFS_LAUNCHER;
STAILQ_FOREACH(e, &infobar[selscreen].elemhead, next) /* Prepare elements */
if(x < (e->geo.x + e->geo.width)) xasprintf(&data, "%s ", l->prompt);
x = e->geo.x + e->geo.width + PAD; LAUNCHER_INIT_ELEM(l->width);
XGrabKeyboard(dpy, ROOT, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabKeyboard(W->dpy, W->root, true, GrabModeAsync, GrabModeAsync, CurrentTime);
w = (launcher->width ? launcher->width : infobar[selscreen].bar->geo.width - x - 1); while(loop)
bw = barwin_create(infobar[selscreen].bar->win, x, 1, w,
/* infobar[selscreen].bar->geo.width - x - 1, */
infobar[selscreen].bar->geo.height - 2,
infobar[selscreen].bar->bg,
infobar[selscreen].bar->fg,
False, False, conf.border.bar);
barwin_map(bw);
barwin_refresh_color(bw);
/* First draw of the cursor */
XSetForeground(dpy, gc, getcolor(infobar[selscreen].bar->fg));
XDrawLine(dpy, bw->dr, gc,
1 + textw(launcher->prompt) + textw(" ") + textw(buf), 2,
1 + textw(launcher->prompt) + textw(" ") + textw(buf), INFOBARH - 4);
barwin_refresh(bw);
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher->prompt);
while(my_guitar_gently_wheeps)
{ {
if(ev.type == KeyPress) XNextEvent(W->dpy, &ev);
if(ev.type != KeyPress)
{ {
EVENT_HANDLE(&ev);
continue;
}
/* Get pressed key */
XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0); XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0);
/* Check Ctrl-c / Ctrl-d */ /* Check Ctrl-c / Ctrl-d */
if(ev.xkey.state & ControlMask) if(ev.xkey.state & ControlMask)
{ {
if(ks == XK_c || ks == XK_d) switch(ks)
{
case XK_c:
case XK_d:
ks = XK_Escape; ks = XK_Escape;
else if(ks == XK_p) break;
case XK_p:
ks = XK_Up; ks = XK_Up;
else if(ks == XK_n) break;
case XK_n:
ks = XK_Down; ks = XK_Down;
break;
}
} }
/* Check if there is a keypad */ /* Check if there is a keypad */
if(IsKeypadKey(ks) && ks == XK_KP_Enter) if(IsKeypadKey(ks) && ks == XK_KP_Enter)
ks = XK_Return; ks = XK_Return;
/* Manage pressed keys */
switch(ks) switch(ks)
{ {
case XK_Up: case XK_Up:
if(launcher->nhisto) if(l->nhisto)
{ {
if(histpos >= (int)launcher->nhisto) if(histpos >= (int)l->nhisto)
histpos = 0; histpos = 0;
strncpy(buf, launcher->histo[launcher->nhisto - ++histpos], sizeof(buf)); strncpy(buf, l->histo[l->nhisto - ++histpos], sizeof(buf));
pos = strlen(buf); pos = strlen(buf);
} }
break; break;
case XK_Down: case XK_Down:
if(launcher->nhisto && histpos > 0 && histpos < (int)launcher->nhisto) if(l->nhisto && histpos > 0 && histpos < (int)l->nhisto)
{ {
strncpy(buf, launcher->histo[launcher->nhisto - --histpos], sizeof(buf)); strncpy(buf, l->histo[l->nhisto - --histpos], sizeof(buf));
pos = strlen(buf); pos = strlen(buf);
} }
break; break;
case XK_Return: case XK_Return:
spawn("%s %s", launcher->command, buf); /* Get function name only, if cmds are added in command */
/* Histo */ arg = NULL;
if(launcher->nhisto + 1 > HISTOLEN) if((p = strchr(cmd, ' ')))
{ {
for(i = launcher->nhisto - 1; i > 1; --i) *p = '\0';
strncpy(launcher->histo[i], launcher->histo[i - 1], sizeof(launcher->histo[i])); xasprintf(&arg, "%s %s", p + 1, buf);
}
launcher->nhisto = 0; if((func = uicb_name_func(cmd)))
{
if(arg)
{
func(arg);
free(arg);
}
else
func(buf);
}
/* Histo */
if(l->nhisto + 1 > HISTOLEN)
{
for(i = l->nhisto - 1; i > 1; --i)
strncpy(l->histo[i], l->histo[i - 1], sizeof(l->histo[i]));
l->nhisto = 0;
} }
/* Store in histo array */ /* Store in histo array */
strncpy(launcher->histo[launcher->nhisto++], buf, sizeof(buf)); strncpy(l->histo[l->nhisto++], buf, sizeof(buf));
my_guitar_gently_wheeps = 0; loop = false;
break; break;
case XK_Escape: case XK_Escape:
my_guitar_gently_wheeps = 0; loop = false;
break; break;
/* Completion */
case XK_Tab: case XK_Tab:
/*
* completion
* if there is not space in buffer we
* complete the command using complete_on_command.
* Else we try to complete on filename using
* complete_on_files.
*/
buf[pos] = '\0'; buf[pos] = '\0';
if (lastwastab) if(lastwastab)
tabhits++; ++cache.hits;
else else
{ {
tabhits = 1; cache.hits = 0;
strncpy(tmpbuf, buf, sizeof(tmpbuf)); strncpy(tmpbuf, buf, sizeof(tmpbuf));
} }
if(pos && (end = complete(&cache, tmpbuf)))
if (pos)
{
if (strchr(tmpbuf, ' '))
complete = complete_on_files(tmpbuf, tabhits);
else
complete = complete_on_command(tmpbuf, tabhits);
if (complete)
{ {
strncpy(buf, tmpbuf, sizeof(buf)); strncpy(buf, tmpbuf, sizeof(buf));
strncat(buf, complete, sizeof(buf)); strncat(buf, end, sizeof(buf));
found = True; found = true;
free(complete);
}
} }
lastwastab = True; lastwastab = true;
/* start a new round of tabbing */ /* start a new round of tabbing */
if (found == False) if(!found)
tabhits = 0; cache.hits = 0;
pos = strlen(buf); pos = strlen(buf);
break; break;
case XK_BackSpace: case XK_BackSpace:
lastwastab = False; lastwastab = false;
if(pos) if(pos)
buf[--pos] = 0; buf[--pos] = '\0';
break; break;
default: default:
lastwastab = False; lastwastab = false;
strncat(buf, tmp, sizeof(tmp)); strncat(buf, tmp, sizeof(tmp));
++pos; ++pos;
break; break;
} }
barwin_refresh_color(bw); free(data);
xasprintf(&data, "%s %s", l->prompt, buf);
/* Update cursor position */ /* Update EVERY launcher element of the screen */
XSetForeground(dpy, gc, getcolor(infobar[selscreen].bar->fg)); SLIST_FOREACH(ib, &W->screen->infobars, next)
XDrawLine(dpy, bw->dr, gc, {
1 + textw(launcher->prompt) + textw(" ") + textw(buf), 2, TAILQ_FOREACH(e, &ib->elements, next)
1 + textw(launcher->prompt) + textw(" ") + textw(buf), INFOBARH - 4); {
if(e->type != ElemLauncher)
continue;
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher->prompt); e->data = data;
barwin_draw_text(bw, 1 + textw(launcher->prompt) + textw(" "), FHINFOBAR - 1, buf); e->func_update(e);
barwin_refresh(bw); }
} }
else if(ev.type < nevent && ev.type > 0)
HANDLE_EVENT(&ev);
XNextEvent(dpy, &ev);
} }
barwin_unmap(bw); XUngrabKeyboard(W->dpy, CurrentTime);
barwin_delete(bw);
infobar_draw(&infobar[selscreen]);
XUngrabKeyboard(dpy, CurrentTime); complete_cache_free(&cache);
free(cmd);
return; free(data);
/* 'Close' launcher elements */
W->flags ^= WMFS_LAUNCHER;
data = NULL;
LAUNCHER_INIT_ELEM(1);
} }
void void
uicb_launcher(uicb_t cmd) uicb_launcher(Uicb cmd)
{ {
int i; struct launcher *l;
for(i = 0; i < conf.nlauncher; ++i)
if(!strcmp(cmd, conf.launcher[i].name))
launcher_execute(&conf.launcher[i]);
if(!cmd)
return; return;
SLIST_FOREACH(l, &W->h.launcher, next)
if(!strcmp(l->name, cmd))
{
launcher_process(l);
break;
}
} }

13
src/launcher.h Normal file
View File

@ -0,0 +1,13 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef LAUNCHER_H
#define LAUNCHER_H
#include "wmfs.h"
void uicb_launcher(Uicb cmd);
#endif /* LAUNCHER_H */

File diff suppressed because it is too large Load Diff

54
src/layout.h Normal file
View File

@ -0,0 +1,54 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef LAYOUT_H
#define LAYOUT_H
#include "wmfs.h"
#include "client.h"
/* Check lateral direction (if p is Right or Left) */
#define LDIR(P) (P < Top)
/* Reverse position */
#define RPOS(P) (P & 1 ? P - 1 : P + 1)
/* geo comparaison */
#define GEO_CHECK2(g1, g2, p) (LDIR(p) ? ((g1).h == (g2).h) : ((g1).w == (g2).w))
#define GEO_CHECK_ROW(g1, g2, p) \
(LDIR(p) \
? ((g1).y >= (g2).y && ((g1).y + (g1).h) <= ((g2).y + (g2).h)) \
: ((g1).x >= (g2).x && ((g1).x + (g1).w) <= ((g2).x + (g2).w)))
#define GEO_PARENTROW(g1, g2, p) \
(LDIR(p) \
? (p == Left ? ((g1).x == (g2).x) : ((g1).x + (g1).w == (g2).x + (g2).w)) \
: (p == Top ? ((g1).y == (g2).y) : ((g1).y + (g1).h == (g2).y + (g2).h)))
/* Debug */
#define DGEO(G) printf(": %d %d %d %d\n", G.x, G.y, G.w, G.h)
void layout_save_set(struct tag *t);
void layout_free_set(struct tag *t);
void layout_split_integrate(struct client *c, struct client *sc);
void layout_split_arrange_closed(struct client *ghost);
void layout_fix_hole(struct client *c);
void layout_client(struct client *c);
void uicb_layout_vmirror(Uicb cmd);
void uicb_layout_hmirror(Uicb cmd);
void uicb_layout_rotate_left(Uicb cmd);
void uicb_layout_rotate_right(Uicb cmd);
void uicb_layout_prev_set(Uicb cmd);
void uicb_layout_next_set(Uicb cmd);
/* Generated */
void uicb_layout_integrate_Left(Uicb);
void uicb_layout_integrate_Right(Uicb);
void uicb_layout_integrate_Top(Uicb);
void uicb_layout_integrate_Bottom(Uicb);
#endif /* LAYOUT_H */

110
src/log.c Normal file
View File

@ -0,0 +1,110 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* File created by David Delassus.
* For license, see COPYING.
*/
#include "wmfs.h"
#include "util.h"
void
log_init(void)
{
char *path = NULL;
xasprintf(&path, "%s/wmfs-%s.log", P_tmpdir, DisplayString(W->dpy));
if(path)
{
/* open log */
if(!(W->log = fopen(path, "a")))
warnx("Can't open log file '%s': %s\n", path, strerror(errno));
free(path);
}
}
/** Print a warning on standard error output and in the log file
* \param format Format string (same syntax as printf)
*/
void
warnl(const char *format, ...)
{
va_list args;
if(W->log)
{
va_start(args, format);
vfprintf(W->log, format, args);
fprintf(W->log, "\n");
va_end(args);
}
va_start(args, format);
vwarn(format, args);
va_end(args);
}
/** Print an error on standard error output and in the log file
* \param eval Exit value
* \param format Format string (same syntax as printf)
*/
void
errl(int eval, const char *format, ...)
{
va_list args;
if(W->log)
{
va_start(args, format);
vfprintf(W->log, format, args);
fprintf(W->log, "\n");
va_end(args);
fclose (W->log);
}
va_start(args, format);
verr(eval, format, args);
}
/** Print a warning on standard error output and in the log file
* \param format Format string (same syntax as printf)
*/
void
warnxl(const char *format, ...)
{
va_list args;
if(W->log)
{
va_start(args, format);
vfprintf(W->log, format, args);
fprintf(W->log, "\n");
va_end(args);
}
va_start(args, format);
vwarnx(format, args);
va_end(args);
}
/** Print an error on standard error output and in the log file
* \param eval Exit value
* \param format Format string (same syntax as printf)
*/
void
errxl(int eval, const char *format, ...)
{
va_list args;
if(W->log)
{
va_start(args, format);
vfprintf(W->log, format, args);
fprintf(W->log, "\n");
va_end(args);
fclose (W->log);
}
va_start(args, format);
verrx(eval, format, args);
}

18
src/log.h Normal file
View File

@ -0,0 +1,18 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* File created by David Delassus.
* For license, see COPYING.
*/
#ifndef __LOG_H
#define __LOG_H
#include <errno.h>
void log_init(void);
void warnl(const char *format, ...);
void warnxl(const char *format, ...);
void errl(int eval, const char *format, ...);
void errxl(int eval, const char *format, ...);
#endif /* __LOG_H */

View File

@ -1,363 +0,0 @@
/*
* menu.c
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
static int
menu_get_longer_string(MenuItem *mi, int nitem)
{
int i, w, l = 0;
for(i = 0; i < nitem; ++i)
if((w = textw(mi[i].name)) > l)
l = w;
return l;
}
static bool
menu_get_checkstring_needed(MenuItem *mi, int nitem)
{
(void)mi;
(void)nitem;
return True;
}
static void
menu_draw_item_name(Menu *menu, int item, BarWindow *winitem[], int chcklen)
{
int x;
int width = menu_get_longer_string(menu->item, menu->nitem) + chcklen + PAD / 3;
switch(menu->align)
{
case MA_Left:
x = chcklen + PAD / 2;
break;
case MA_Right:
x = width - textw(menu->item[item].name) + PAD * 3 / 2;
break;
default:
case MA_Center:
x = (width - (chcklen + PAD / 3)) / 2 - textw(menu->item[item].name) / 2 + chcklen + PAD / 3;
break;
}
barwin_draw_text(winitem[item], x, FHINFOBAR, menu->item[item].name);
if(menu->item[item].check)
if(menu->item[item].check(menu->item[item].cmd))
barwin_draw_text(winitem[item], PAD / 3, FHINFOBAR, conf.selected_layout_symbol);
if(menu->item[item].submenu)
barwin_draw_text(winitem[item], width + PAD * 2, FHINFOBAR, ">");
return;
}
static bool
menu_activate_item(Menu *menu, int i)
{
int j, x, y;
int chcklen = 0;
if(menu_get_checkstring_needed(menu->item, menu->nitem))
chcklen = textw(conf.selected_layout_symbol) + PAD / 3;
if(menu->item[i].submenu)
{
for(j = 0; j < conf.nmenu; ++j)
if(!strcmp(menu->item[i].submenu, conf.menu[j].name))
{
y = menu->y + ((i - 1) * INFOBARH + PAD) - SHADH * 2;
x = menu->x + menu_get_longer_string(menu->item, menu->nitem) + chcklen + textw(">") + PAD * 3;
menu_draw(conf.menu[j], x, y);
return True;
}
}
else if(menu->item[i].func)
{
menu->item[i].func(menu->item[i].cmd);
return True;
}
return False;
}
static void
menu_focus_item(Menu *menu, int item, BarWindow *winitem[])
{
int i;
int chcklen = 0;
if(menu_get_checkstring_needed(menu->item, menu->nitem))
chcklen = textw(conf.selected_layout_symbol) + PAD / 3;
menu->focus_item = item;
if(menu->focus_item > menu->nitem - 1)
menu->focus_item = 0;
else if(menu->focus_item < 0)
menu->focus_item = menu->nitem - 1;
for(i = 0; i < menu->nitem; ++i)
{
winitem[i]->fg = ((i == menu->focus_item) ? menu->colors.focus.fg : menu->colors.normal.fg);
winitem[i]->bg = ((i == menu->focus_item) ? menu->colors.focus.bg : menu->colors.normal.bg);
barwin_refresh_color(winitem[i]);
menu_draw_item_name(menu, i, winitem, chcklen);
barwin_refresh(winitem[i]);
}
return;
}
static bool
menu_manage_event(XEvent *ev, Menu *menu, BarWindow *winitem[])
{
int i, c = 0;
KeySym ks = 0;
bool quit = False;
char acc = 0;
switch(ev->type)
{
/* Mouse events */
case ButtonPress:
/* Execute the function linked with the item */
for(i = 0; i < menu->nitem; ++i)
{
if(ev->xbutton.window == winitem[i]->win
&& (ev->xbutton.button == Button1 || ev->xbutton.button == Button2))
quit = menu_activate_item(menu, i);
else if(ev->xbutton.window != winitem[i]->win)
++c;
else if(ev->xbutton.button == Button4)
menu_focus_item(menu, menu->focus_item - 1, winitem);
else if(ev->xbutton.button == Button5)
menu_focus_item(menu, menu->focus_item + 1, winitem);
}
/* If the clicked window is not one of menu wins (items), quit. */
if(c == i)
quit = True;
break;
/* Keys */
case KeyPress:
XLookupString(&ev->xkey, NULL, 0, &ks, 0);
switch(ks)
{
case XK_Up:
menu_focus_item(menu, menu->focus_item - 1, winitem);
break;
case XK_Down:
menu_focus_item(menu, menu->focus_item + 1, winitem);
break;
case XK_Return:
quit = menu_activate_item(menu, menu->focus_item);
break;
case XK_Escape:
quit = True;
break;
}
break;
/* Focus (with mouse) management */
case EnterNotify:
/* For focus an item with the mouse */
for(i = 0; i < menu->nitem; ++i)
if(ev->xcrossing.window == winitem[i]->win)
{
acc = 1;
menu_focus_item(menu, i, winitem);
if(menu->item[i].submenu)
menu_activate_item(menu, menu->focus_item);
}
if(!acc)
{
if(ev->xcrossing.window)
XSendEvent(dpy, ev->xcrossing.window, False, StructureNotifyMask, ev);
return True;
}
break;
default:
if(ev->type < nevent && ev->type > 0)
HANDLE_EVENT(ev);
break;
}
XNextEvent(dpy, ev);
return quit;
}
void
uicb_menu(uicb_t cmd)
{
int i, d, u, x, y;
Window w;
if(!strcmp(cmd, "menulayout"))
menu_draw(menulayout, menulayout.x, menulayout.y);
for(i = 0; i < conf.nmenu; ++i)
if(!strcmp(cmd, conf.menu[i].name))
{
if(conf.menu[i].place_at_mouse)
{
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&u);
conf.menu[i].x = x;
conf.menu[i].y = y;
}
else
{
screen_get_sel();
x = conf.menu[i].x + spgeo[selscreen].x;
y = conf.menu[i].y + spgeo[selscreen].y;
}
menu_draw(conf.menu[i], x, y);
}
return;
}
void
menu_clear(Menu *menu)
{
free(menu->item);
menu->nitem = 0;
return;
}
void
menu_init(Menu *menu, char *name, int nitem, uint bg_f, char *fg_f, uint bg_n, char *fg_n)
{
/* Item */
menu->nitem = nitem;
menu->item = xcalloc(nitem, sizeof(*menu->item));
menu->name = name;
/* Colors */
menu->colors.focus.bg = bg_f;
menu->colors.focus.fg = fg_f;
menu->colors.normal.bg = bg_n;
menu->colors.normal.fg = fg_n;
return;
}
void
menu_new_item(MenuItem *mi, char *name, void *func, char *cmd)
{
mi->name = name;
mi->func = func;
mi->cmd = cmd;
return;
}
void
menu_draw(Menu menu, int x, int y)
{
int i, width, height, out;
XEvent ev;
BarWindow *item[menu.nitem];
BarWindow *frame;
int chcklen = 0;
if(menu_get_checkstring_needed(menu.item, menu.nitem))
chcklen = textw(conf.selected_layout_symbol) + PAD / 3;
width = menu_get_longer_string(menu.item, menu.nitem) + chcklen + textw(">") + PAD * 3;
height = menu.nitem * (INFOBARH - SHADH);
/* Frame barwin */
screen_get_sel();
if((out = x + width - MAXW) > 0)
x -= out;
if((out = y + height - MAXH) > 0)
y -= out;
frame = barwin_create(ROOT, x, y, width + SHADH, height + SHADH * 3,
menu.colors.normal.bg, menu.colors.normal.fg, False, False, True);
barwin_map(frame);
barwin_map_subwin(frame);
barwin_refresh_color(frame);
for(i = 0; i < menu.nitem; ++i)
{
item[i] = barwin_create(frame->win,
SHADH,
(i * (INFOBARH - SHADH) + SHADH),
width - SHADH,
INFOBARH,
menu.colors.normal.bg,
menu.colors.normal.fg,
True, False, False);
barwin_map(item[i]);
barwin_refresh_color(item[i]);
menu_draw_item_name(&menu, i, item, chcklen);
barwin_refresh(item[i]);
}
/* Select the first item */
menu_focus_item(&menu, 0, item);
XGrabKeyboard(dpy, ROOT, True, GrabModeAsync, GrabModeAsync, CurrentTime);
XNextEvent(dpy, &ev);
while(!menu_manage_event(&ev, &menu, item));
XUngrabKeyboard(dpy, CurrentTime);
for(i = 0; i < menu.nitem; ++i)
barwin_delete(item[i]);
barwin_delete(frame);
return;
}

View File

@ -1,386 +1,242 @@
/* /*
* mouse.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h" #include "wmfs.h"
#include "mouse.h"
#include "barwin.h"
#include "client.h"
#include "draw.h"
Window prevwin; #define _REV_SBORDER(c) draw_reversed_rect(W->root, c, false);
/** Draw the border when a client in dragging/resizing with mouse
*/
static void
mouse_dragborder(Geo geo, GC g)
{
XDrawRectangle(dpy, ROOT, g,
geo.x - (BORDH >> 1),
geo.y - (TBARH - (BORDH >> 1)),
geo.width + BORDH,
geo.height + TBARH);
return;
}
#define _REV_BORDER() \
do { \
FOREACH_NFCLIENT(gc, &c->tag->clients, tnext) \
draw_reversed_rect(W->root, gc, true); \
} while(/* CONSTCOND */ 0);
static void static void
mouse_cfactor_border(Client *c, int f[4], GC g) mouse_resize(struct client *c)
{ {
int e; struct client *gc;
mouse_dragborder(cfactor_geo(c->wrgeo, f, &e), g);
return;
}
/** Move a client in tile grid with the mouse
*\param c Client double pointer
*/
static void
mouse_move_tile_client(Client **c)
{
Client *sc;
Window w;
int d;
if(!((*c)->flags & (TileFlag | LMaxFlag)))
return;
XQueryPointer(dpy, ROOT, &w, &w, &d, &d, &d, &d, (uint*)&d);
if(((sc = client_gb_win(w)) || (sc = client_gb_frame(w)) || (sc = client_gb_titlebar(w)))
&& (*c)->win != sc->win && !((*c)->flags & HideFlag) && !(sc->flags & HideFlag) && (sc->flags & TileFlag))
{
client_swap(sc, *c);
client_focus(sc);
swap_ptr((void**)c, (void**)&sc);
}
return;
}
/** Move a client from one tag to another with dah mouse
*\param c client pointer
*/
static void
mouse_move_tag_client(Client *c)
{
Window w;
int i, d, s;
if(!(c->flags & (TileFlag | LMaxFlag)))
return;
s = c->screen;
XQueryPointer(dpy, infobar[selscreen].tags_board->win, &w, &w, &d, &d, &d, &d, (uint*)&d);
if(w == prevwin)
return;
prevwin = w;
for(i = 1; i < conf.ntag[selscreen] + 1; ++i)
if(infobar[selscreen].tags[i]->win == w
&& tags[selscreen][i].layout.func != freelayout)
{
tag_transfert(c, i);
if(s != c->screen)
arrange(c->screen, True);
}
return;
}
/** Move the client with the mouse
* \param c Client pointer
*/
static void
mouse_move(Client *c)
{
int ocx, ocy, mx, my;
int dint;
uint duint;
Window dw;
Geo geo = c->geo;
XGCValues xgc;
GC gci;
XEvent ev; XEvent ev;
Window w;
int d, u, ox, oy, ix, iy;
int mx, my;
if(c->flags & (MaxFlag | FSSFlag)) XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (unsigned int *)&u);
return; XGrabServer(W->dpy);
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
}
else
_REV_BORDER();
if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
c = c->tabmaster;
ix = ox;
iy = oy;
c->flags |= CLIENT_MOUSE;
do
{
XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
if(ev.type != MotionNotify)
continue;
mx = ev.xmotion.x_root;
my = ev.xmotion.y_root;
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
mx -= c->screen->ugeo.x;
my -= c->screen->ugeo.y;
c->geo.w = ((mx - c->geo.x <= c->sizeh[MINW] + c->border + c->border)
? c->sizeh[MINW] + c->border + c->border
: mx - c->geo.x);
c->geo.h = ((my - c->geo.y <= (c->sizeh[MINH] + c->tbarw + c->border))
? c->sizeh[MINH] + c->tbarw + c->border
: my - c->geo.y);
client_geo_hints(&c->geo, (int*)c->sizeh);
/* For border preview cohesion */
c->geo.h += c->tbarw + c->border;
c->geo.w += c->border + c->border;
_REV_SBORDER(c);
}
else
{
_REV_BORDER();
if(ix >= c->rgeo.x + (c->geo.w >> 1))
_fac_resize(c, Right, mx - ox);
else
_fac_resize(c, Left, ox - mx);
if(iy >= c->rgeo.y + (c->geo.h >> 1))
_fac_resize(c, Bottom, my - oy);
else
_fac_resize(c, Top, oy - my);
ox = mx;
oy = my;
_REV_BORDER();
}
XSync(W->dpy, false);
} while(ev.type != ButtonRelease);
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
client_moveresize(c, &c->geo);
}
else
{
_REV_BORDER();
client_apply_tgeo(c->tag);
layout_save_set(c->tag);
}
c->flags &= ~CLIENT_MOUSE;
XUngrabServer(W->dpy);
}
static struct tag*
mouse_drag_tag(struct client *c, Window w)
{
struct barwin *b;
struct tag *t = NULL;
Window rw;
int d, u;
XQueryPointer(W->dpy, w, &rw, &rw, &d, &d, &d, &d, (uint *)&u);
SLIST_FOREACH(b, &W->h.barwin, next)
if(b->win == rw
&& (t = (struct tag*)b->ptr)
&& t != c->tag)
return t;
return NULL;
}
void
mouse_move(struct client *c, void (*func)(struct client*, struct client*))
{
struct client *c2 = NULL, *last = c;
struct tag *t = NULL;
XEvent ev;
Window w;
int d, u, ox, oy;
int ocx, ocy;
ocx = c->geo.x; ocx = c->geo.x;
ocy = c->geo.y; ocy = c->geo.y;
if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync, if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
None, cursor[CurMove], CurrentTime) != GrabSuccess) c = c->tabmaster;
return;
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag)) XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u);
XGrabServer(dpy);
/* Set the GC for the rectangle */ _REV_SBORDER(c);
xgc.function = GXinvert;
xgc.subwindow_mode = IncludeInferiors;
xgc.line_width = BORDH;
gci = XCreateGC(dpy, ROOT, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag)) c->flags |= CLIENT_MOUSE;
mouse_dragborder(c->geo, gci);
XQueryPointer(dpy, ROOT, &dw, &dw, &mx, &my, &dint, &dint, &duint);
do do
{ {
XMaskEvent(dpy, MouseMask | SubstructureRedirectMask, &ev); XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
screen_get_sel();
if(ev.type == MotionNotify) if(ev.type != MotionNotify)
continue;
if(!func && c->flags & CLIENT_FREE)
{ {
mouse_move_tile_client(&c); _REV_SBORDER(c);
mouse_move_tag_client(c);
/* To move a client normally, in freelayout */ c->geo.x = (ocx + (ev.xmotion.x_root - ox));
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag)) c->geo.y = (ocy + (ev.xmotion.y_root - oy));
_REV_SBORDER(c);
}
else
{ {
mouse_dragborder(geo, gci); c2 = NULL;
geo.x = (ocx + (ev.xmotion.x - mx)); XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&u);
geo.y = (ocy + (ev.xmotion.y - my));
/* if((c2 = client_gb_win(w)) || (c2 = client_gb_frame(w)) || (c2 = client_gb_titlebar(w)))
* Need to draw 2 times the same rectangle because
* it is draw with the revert color; revert + revert = normal
*/
mouse_dragborder(geo, gci);
}
}
else if((ev.type == MapRequest || ev.type == ConfigureRequest))
HANDLE_EVENT(&ev);
}
while(ev.type != ButtonRelease);
/* One time again to delete all the trace on the window */
if(!(c->flags & (TileFlag | LMaxFlag)))
{ {
mouse_dragborder(geo, gci); if(c2 != last)
client_moveresize(c, geo, False); {
frame_update(c); _REV_SBORDER(last);
XUngrabServer(dpy); _REV_SBORDER(c2);
last = c2;
}
}
else
t = mouse_drag_tag(c, w);
} }
client_update_attributes(c);
XUngrabPointer(dpy, CurrentTime);
XFreeGC(dpy, gci);
return; XSync(W->dpy, false);
} while(ev.type != ButtonRelease);
if(c2)
func(c, c2);
else if(t && t != (struct tag*)c)
tag_client(t, c);
else
{
_REV_SBORDER(c);
/* No func mean free client resize */
if(!func)
client_moveresize(c, &c->geo);
}
c->flags &= ~CLIENT_MOUSE;
} }
/** Resize a client with the mouse
* \param c Client pointer
*/
void void
mouse_resize(Client *c) uicb_mouse_resize(Uicb cmd)
{
Geo geo = c->geo, ogeo = c->geo;
Position pos = Right;
XEvent ev;
Window w;
int d, u, omx, omy;
XGCValues xgc;
GC gci;
int f[4] = { 0 };
if(c->flags & (MaxFlag | LMaxFlag | FSSFlag))
return;
XQueryPointer(dpy, ROOT, &w, &w, &omx, &omy, &d, &d, (uint *)&u);
if((omx - c->geo.x) < (c->geo.width >> 1))
pos = Left;
if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync, None,
cursor[((c->flags & TileFlag) ? CurResize : ((pos == Right) ? CurRightResize : CurLeftResize))],
CurrentTime) != GrabSuccess)
return;
if(!(c->flags & TileFlag))
XGrabServer(dpy);
/* Set the GC for the rectangle */
xgc.function = GXinvert;
xgc.subwindow_mode = IncludeInferiors;
xgc.line_width = BORDH;
gci = XCreateGC(dpy, ROOT, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
if(!(c->flags & TileFlag))
{
if(pos == Right)
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->geo.width + conf.client.borderheight, c->geo.height);
else
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, 0, c->geo.height);
mouse_dragborder(c->geo, gci);
}
else
mouse_cfactor_border(c, f, gci);
do
{
XMaskEvent(dpy, MouseMask | SubstructureRedirectMask, &ev);
if(ev.type == MotionNotify)
{
/* To resize client in tile mode with cfactor */
if(c->flags & TileFlag)
{
mouse_cfactor_border(c, f, gci);
if(omx >= c->frame_geo.x + (c->frame_geo.width >> 1))
f[Right] = ev.xmotion.x_root - omx;
else
f[Left] = omx - ev.xmotion.x_root;
if(omy >= c->frame_geo.y + (c->frame_geo.height >> 1))
f[Bottom] = ev.xmotion.y_root - omy;
else
f[Top] = omy - ev.xmotion.y_root;
mouse_cfactor_border(c, f, gci);
}
/* Free mode */
else if(!(c->flags & TileFlag))
{
mouse_dragborder(geo, gci);
if(pos == Right)
{
geo.width = ((ev.xmotion.x - c->geo.x < c->minw) ? c->minw : ev.xmotion.x - c->geo.x);
geo.height = ((ev.xmotion.y - c->geo.y < c->minh) ? c->minh : ev.xmotion.y - c->geo.y);
}
else
{
geo.x = (geo.width != c->maxw) ? c->geo.x - (c->geo.x - ev.xmotion.x) : geo.x;
geo.width = ((c->geo.width + (c->geo.x - geo.x) < c->minw)
? c->minw && (geo.x = (c->geo.x + c->geo.width) - c->minw)
: c->geo.width + (c->geo.x - geo.x));
geo.height = ((ev.xmotion.y - c->geo.y <= c->minh) ? c->minh : ev.xmotion.y - c->geo.y);
}
client_geo_hints(&geo, c);
mouse_dragborder((ogeo = geo), gci);
XSync(dpy, False);
}
}
}
while(ev.type != ButtonRelease);
if(!(c->flags & TileFlag))
{
mouse_dragborder(ogeo, gci);
client_moveresize(c, geo, True);
frame_update(c);
XUngrabServer(dpy);
}
else
{
mouse_cfactor_border(c, f, gci);
cfactor_multi_set(c, f);
}
client_update_attributes(c);
XUngrabPointer(dpy, CurrentTime);
XFreeGC(dpy, gci);
return;
}
/** Grab buttons
* \param c Client pointer
* \param focused For know if c is or not focused
*/
void
mouse_grabbuttons(Client *c, bool focused)
{
size_t i = 0;
uint but[] = {Button1, Button2, Button3, Button4, Button5};
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
if(focused)
for(; i < LEN(but); ++i)
{
XGrabButton(dpy, but[i], conf.client.mod, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, but[i], conf.client.mod | LockMask, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, but[i], conf.client.mod | numlockmask, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, but[i], conf.client.mod | LockMask | numlockmask, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
}
else
XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
ButtonMask, GrabModeAsync, GrabModeSync, None, None);
return;
}
/** Move the selected client
* \param cmd uicb_t type unused
*/
void
uicb_mouse_move(uicb_t cmd)
{ {
(void)cmd; (void)cmd;
CHECK(sel);
mouse_move(sel); if(W->client && mouse_check_client(W->client))
mouse_resize(W->client);
return;
} }
/** Reisze the selected client
* \param cmd uicb_t type unused
*/
void void
uicb_mouse_resize(uicb_t cmd) uicb_mouse_move(Uicb cmd)
{ {
(void)cmd; (void)cmd;
CHECK(sel);
mouse_resize(sel); if(W->client && mouse_check_client(W->client))
mouse_move(W->client, (W->client->flags & CLIENT_FREE ? NULL : client_swap2));
return;
} }
void
uicb_mouse_tab(Uicb cmd)
{
(void)cmd;
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, _client_tab);
}

29
src/mouse.h Normal file
View File

@ -0,0 +1,29 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef MOUSE_H
#define MOUSE_H
#include "client.h"
void uicb_mouse_resize(Uicb);
void uicb_mouse_move(Uicb);
void uicb_mouse_tab(Uicb);
static inline bool
mouse_check_client(struct client *c)
{
Window w;
int d;
XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&d);
if(c == client_gb_win(w) || c == client_gb_titlebar(w) || c == client_gb_frame(w))
return true;
return false;
}
#endif /* MOUSE_H */

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org> * Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
* Copyright (c) 2011 Martin Duquesnoy <xorg62@gmail.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -34,16 +35,19 @@
#include <err.h> #include <err.h>
#include "parse.h" #include "parse.h"
#include "util.h"
extern char *__progname; extern char *__progname;
enum keyword_t { SEC_START, SEC_END, INCLUDE, WORD, EQUAL, LIST_START, LIST_END, NONE }; enum keyword_t { SEC_START, SEC_END, INCLUDE, WORD, EQUAL, LIST_START, LIST_END, NONE };
#ifdef DEBUG #ifdef DEBUG
static struct { static const struct
{
const char *name; const char *name;
enum keyword_t type; enum keyword_t type;
} kw_t_name[] = { } kw_t_name[] =
{
{"SEC_START", SEC_START}, {"SEC_START", SEC_START},
{"SEC_END", SEC_END}, {"SEC_END", SEC_END},
{"INCLUDE", INCLUDE}, {"INCLUDE", INCLUDE},
@ -55,12 +59,14 @@ static struct {
}; };
#endif #endif
struct files { struct files
{
char *name; char *name;
struct files *parent; struct files *parent;
}; };
struct keyword { struct keyword
{
enum keyword_t type; enum keyword_t type;
/* if WORD */ /* if WORD */
int line; int line;
@ -69,7 +75,8 @@ struct keyword {
struct keyword *next; struct keyword *next;
}; };
struct state { struct state
{
bool quote; bool quote;
bool comment; bool comment;
char quote_char; char quote_char;
@ -87,37 +94,38 @@ push_keyword(struct keyword *tail, enum keyword_t type, char *buf, size_t *offse
int i = 0; int i = 0;
#endif #endif
if (type == WORD && *offset == 0) if(type == WORD && *offset == 0)
return tail; return tail;
kw = zcalloc(sizeof(*kw)); kw = xcalloc(1, sizeof(*kw));
kw->type = type; kw->type = type;
kw->line = line; kw->line = line;
kw->file = file; kw->file = file;
kw->next = NULL; kw->next = NULL;
if (*offset != 0) { if(*offset)
{
buf[*offset] = '\0'; buf[*offset] = '\0';
if (!strcmp(buf, INCLUDE_CMD))
if(!strcmp(buf, INCLUDE_CMD))
kw->type = INCLUDE; kw->type = INCLUDE;
else else
kw->name = strdup(buf); kw->name = strdup(buf);
*offset = 0; *offset = 0;
} }
else else
kw->name = NULL; kw->name = NULL;
if (tail) if(tail)
tail->next = kw; tail->next = kw;
#ifdef DEBUG #ifdef DEBUG
for (i = 0; kw_t_name[i].type != NONE; i++) { for(i = 0; kw_t_name[i].type != NONE; ++i)
if (kw_t_name[i].type == kw->type) { if(kw_t_name[i].type == kw->type)
warnx("%s %s %s:%d\n", kw_t_name[i].name, warnxl("%s %s %s:%d\n", kw_t_name[i].name,
(kw->name) ? kw->name : "", (kw->name) ? kw->name : "",
kw->file->name, kw->line); kw->file->name, kw->line);
}
}
#endif #endif
return kw; return kw;
@ -130,10 +138,10 @@ syntax(struct keyword *kw, const char *fmt, ...)
fprintf(stderr, "%s:", __progname); fprintf(stderr, "%s:", __progname);
if (kw && kw->file && kw->file->name) if(kw && kw->file && kw->file->name)
fprintf(stderr, "%s:%d", kw->file->name, kw->line); fprintf(stderr, "%s:%d", kw->file->name, kw->line);
if (kw && kw->name) if(kw && kw->name)
fprintf(stderr, ", near '%s'", kw->name); fprintf(stderr, ", near '%s'", kw->name);
fprintf(stderr, ": "); fprintf(stderr, ": ");
@ -152,40 +160,43 @@ parse_keywords(const char *filename)
int fd; int fd;
struct stat st; struct stat st;
char *buf; char *buf;
struct keyword *head = NULL; struct keyword *head = NULL;
struct keyword *tail = NULL; struct keyword *tail = NULL;
struct files *file; struct files *file;
enum keyword_t type; /* keyword type to push */ enum keyword_t type; /* keyword type to push */
struct state s = { False, False, '\0'}; struct state s = { false, false, '\0'};
char *bufname; char *bufname;
char path[PATH_MAX]; char path[PATH_MAX];
size_t i, j; size_t i, j;
int line; int line;
bool error = False; bool error = false;
if (stat(filename, &st) == -1 || (fd = open(filename, O_RDONLY)) == -1) { if(stat(filename, &st) == -1 || (fd = open(filename, O_RDONLY)) == -1)
warn("%s", filename); {
warnxl("%s", filename);
return NULL; return NULL;
} }
if (st.st_size == 0) { if(!st.st_size)
warnx("%s: empty file", filename); {
warnxl("%s: empty file", filename);
close(fd); close(fd);
return NULL; return NULL;
} }
if (!realpath(filename, path)) { if(!realpath(filename, path))
warn("%s", filename); {
warnxl("%s", filename);
close(fd); close(fd);
return NULL; return NULL;
} }
buf = zmalloc(st.st_size+1); buf = xmalloc(1, st.st_size + 1);
if (read(fd, buf, st.st_size) == -1) { if(read(fd, buf, st.st_size) == -1)
warn("%s", filename); {
warnxl("%s", filename);
free(buf); free(buf);
close(fd); close(fd);
return NULL; return NULL;
@ -193,112 +204,127 @@ parse_keywords(const char *filename)
buf[st.st_size] = '\0'; buf[st.st_size] = '\0';
file = zcalloc(sizeof(*file)); file = xcalloc(1, sizeof(*file));
bufname = zcalloc(sizeof(*bufname) * BUFSIZ); bufname = xcalloc(BUFSIZ, sizeof(*bufname));
file->name = strdup(path); file->name = strdup(path);
file->parent = NULL; file->parent = NULL;
for(i = 0, j = 0, line = 1; i < (size_t)st.st_size; i++) { for(i = j = 0, line = 1; i < (size_t)st.st_size; ++i)
{
if (!head && tail) if(!head && tail)
head = tail; head = tail;
if (buf[i] == '\n' && s.comment == True) { if(buf[i] == '\n' && s.comment)
{
line++; line++;
s.comment = False; s.comment = false;
continue; continue;
} }
if (buf[i] == '#' && s.quote == False) { if(buf[i] == '#' && !s.quote)
s.comment = True; {
s.comment = true;
continue; continue;
} }
if (s.comment == True) if(s.comment)
continue; continue;
if (s.quote == True && buf[i] == s.quote_char) {
/* end of quotted string */ /* end of quotted string */
if(s.quote && buf[i] == s.quote_char)
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
s.quote = False; s.quote = false;
continue; continue;
} }
if (s.quote == False) { if(!s.quote)
if ((buf[i] == '"' || buf[i] == '\'')) { {
if((buf[i] == '"' || buf[i] == '\''))
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
/* begin quotted string */ /* begin quotted string */
s.quote_char = buf[i]; s.quote_char = buf[i];
s.quote = True; s.quote = true;
continue; continue;
} }
if (buf[i] == '[') { if(buf[i] == '[')
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
if (buf[i+1] == '/') {
i +=2; if(buf[i + 1] == '/')
{
i += 2;
type = SEC_END; type = SEC_END;
} }
else { else
i++; {
++i;
type = SEC_START; type = SEC_START;
} }
/* get section name */ /* get section name */
while (buf[i] != ']') { while(buf[i] != ']')
{
if (i >= ((size_t)st.st_size-1) || j >= (BUFSIZ-1)) { if(i >= ((size_t)st.st_size-1) || j >= (BUFSIZ-1))
{
bufname[j] = '\0'; bufname[j] = '\0';
syntax(NULL, "word too long in %s:%d near '%s'", syntax(NULL, "word too long in %s:%d near '%s'",
file->name, line, bufname); file->name, line, bufname);
error = True; error = true;
break; break;
} }
bufname[j++] = buf[i++]; bufname[j++] = buf[i++];
} }
PUSH_KEYWORD(type); PUSH_KEYWORD(type);
continue; continue;
} }
if (buf[i] == '{') { if(buf[i] == '{')
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
PUSH_KEYWORD(LIST_START); PUSH_KEYWORD(LIST_START);
continue; continue;
} }
if (buf[i] == '}') { if(buf[i] == '}')
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
PUSH_KEYWORD(LIST_END); PUSH_KEYWORD(LIST_END);
continue; continue;
} }
if (buf[i] == ',') { if(buf[i] == ',')
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
continue; continue;
} }
if (buf[i] == '=') { if(buf[i] == '=')
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
PUSH_KEYWORD(EQUAL); PUSH_KEYWORD(EQUAL);
continue; continue;
} }
if (strchr("\t\n ", buf[i])) { if(strchr("\t\n ", buf[i]))
{
PUSH_KEYWORD(WORD); PUSH_KEYWORD(WORD);
if (buf[i] == '\n') if(buf[i] == '\n')
line++; ++line;
continue; continue;
} }
} /* s.quote == False */ }
if (j >= (BUFSIZ - 1)) { if(j >= (BUFSIZ - 1))
{
bufname[j] = '\0'; bufname[j] = '\0';
syntax(NULL, "word too long in %s:%d near '%s'", syntax(NULL, "word too long in %s:%d near '%s'",
file->name, line, bufname); file->name, line, bufname);
error = True; error = true;
break; break;
} }
@ -308,7 +334,7 @@ parse_keywords(const char *filename)
free(buf); free(buf);
free(bufname); free(bufname);
close(fd); close(fd);
warnx("%s read", file->name); warnxl("%s read", file->name);
return (error ? NULL: head); return (error ? NULL: head);
} }
@ -330,22 +356,26 @@ include(struct keyword *head)
head = head->next; head = head->next;
if (!head || head->type != WORD) { if(!head || head->type != WORD)
{
syntax(head, "missing filename to include"); syntax(head, "missing filename to include");
return NULL; return NULL;
} }
/* replace ~ by user directory */ /* replace ~ by user directory */
if (head->name && head->name[0] == '~') { if(head->name && head->name[0] == '~')
if ( (user = getpwuid(getuid())) && user->pw_dir) {
xasprintf(&filename, "%s%s", user->pw_dir, head->name+1); if((user = getpwuid(getuid())) && user->pw_dir)
else if (getenv("HOME")) xasprintf(&filename, "%s%s", user->pw_dir, head->name + 1);
xasprintf(&filename, "%s%s", getenv("HOME"), head->name+1); else if(getenv("HOME"))
xasprintf(&filename, "%s%s", getenv("HOME"), head->name + 1);
else /* to warning ? */ else /* to warning ? */
filename = head->name; filename = head->name;
} }
/* relative path from parent file */ /* relative path from parent file */
else if (head->name && head->name[0] != '/') { else if(head->name && head->name[0] != '/')
{
base = strdup(head->file->name); base = strdup(head->file->name);
xasprintf(&filename, "%s/%s", dirname(base), head->name); xasprintf(&filename, "%s/%s", dirname(base), head->name);
free(base); free(base);
@ -353,10 +383,11 @@ include(struct keyword *head)
else else
filename = head->name; filename = head->name;
if (!(kw = parse_keywords(filename))) { if(!(kw = parse_keywords(filename)))
warnx("no config found in include file %s", head->name); {
warnxl("no config found in include file %s", head->name);
if (filename != head->name) if(filename != head->name)
free(filename); free(filename);
return NULL; return NULL;
@ -365,24 +396,25 @@ include(struct keyword *head)
kw->file->parent = head->file; kw->file->parent = head->file;
/* detect circular include */ /* detect circular include */
for (file = kw->file->parent; file != NULL; file = file->parent) { for(file = kw->file->parent; file != NULL; file = file->parent)
if (!strcmp(file->name, kw->file->name)) { if(!strcmp(file->name, kw->file->name))
{
syntax(kw, "circular include of %s", kw->file->name); syntax(kw, "circular include of %s", kw->file->name);
if (filename != head->name) if(filename != head->name)
free(filename); free(filename);
return NULL; return NULL;
} }
}
if (filename != head->name) if(filename != head->name)
free(filename); free(filename);
head = head->next; head = head->next;
if (kw) { if(kw)
for (tail = kw; tail->next; tail = tail->next); {
for(tail = kw; tail->next; tail = tail->next);
tail->next = head; tail->next = head;
} }
@ -403,53 +435,62 @@ get_option(struct keyword **head)
size_t j = 0; size_t j = 0;
struct keyword *kw = *head; struct keyword *kw = *head;
o = zcalloc(sizeof(*o)); o = xcalloc(1, sizeof(*o));
o->name = kw->name; o->name = kw->name;
o->used = False; o->used = false;
o->line = kw->line; o->line = kw->line;
o->filename = kw->file->name; o->filename = kw->file->name;
kw = kw->next; kw = kw->next;
if (kw->type != EQUAL) { if(kw->type != EQUAL)
{
syntax(kw, "missing '=' here"); syntax(kw, "missing '=' here");
return free_opt(o); return free_opt(o);
} }
kw = kw->next; if(!(kw = kw->next))
{
if (!kw) {
syntax(kw, "missing value"); syntax(kw, "missing value");
return free_opt(o); return free_opt(o);
} }
switch(kw->type)
switch (kw->type) { {
case INCLUDE: case INCLUDE:
if (!(kw = include(kw))) if(!(kw = include(kw)))
return free_opt(o); return free_opt(o);
break; break;
case WORD: case WORD:
o->val[0] = kw->name; o->val[0] = kw->name;
o->val[1] = NULL; o->val[1] = NULL;
kw = kw->next; kw = kw->next;
break; break;
case LIST_START: case LIST_START:
kw = kw->next; kw = kw->next;
while (kw && kw->type != LIST_END) {
switch (kw->type) { while(kw && kw->type != LIST_END)
{
switch(kw->type)
{
case WORD: case WORD:
if (j >= (PARSE_MAX_LIST - 1)) { if(j >= (PARSE_MAX_LIST - 1))
{
syntax(kw, "too much values in list"); syntax(kw, "too much values in list");
return free_opt(o); return free_opt(o);
} }
o->val[j++] = kw->name; o->val[j++] = kw->name;
kw = kw->next; kw = kw->next;
break; break;
case INCLUDE: case INCLUDE:
if (!(kw = include(kw))) if(!(kw = include(kw)))
return free_opt(o); return free_opt(o);
break; break;
default: default:
syntax(kw, "declaration into a list"); syntax(kw, "declaration into a list");
return free_opt(o); return free_opt(o);
@ -457,13 +498,15 @@ get_option(struct keyword **head)
} }
} }
if (!kw) { if(!kw)
{
syntax(kw, "list unclosed"); syntax(kw, "list unclosed");
return free_opt(o); return free_opt(o);
} }
kw = kw->next; kw = kw->next;
break; break;
default: default:
syntax(kw, "missing value"); syntax(kw, "missing value");
return free_opt(o); return free_opt(o);
@ -480,19 +523,25 @@ free_sec(struct conf_sec *sec)
struct conf_opt *o; struct conf_opt *o;
struct conf_sec *s; struct conf_sec *s;
if (sec) { if(sec)
while (!SLIST_EMPTY(&sec->optlist)) { {
while(!SLIST_EMPTY(&sec->optlist))
{
o = SLIST_FIRST(&sec->optlist); o = SLIST_FIRST(&sec->optlist);
SLIST_REMOVE_HEAD(&sec->optlist, entry); SLIST_REMOVE_HEAD(&sec->optlist, entry);
free_opt(o); free_opt(o);
} }
while (!TAILQ_EMPTY(&sec->sub)) {
while(!TAILQ_EMPTY(&sec->sub))
{
s = TAILQ_FIRST(&sec->sub); s = TAILQ_FIRST(&sec->sub);
TAILQ_REMOVE(&sec->sub, s, entry); TAILQ_REMOVE(&sec->sub, s, entry);
free_sec(s); free_sec(s);
} }
free(sec); free(sec);
} }
return NULL; return NULL;
} }
@ -504,31 +553,37 @@ get_section(struct keyword **head)
struct conf_sec *sub; struct conf_sec *sub;
struct keyword *kw = *head; struct keyword *kw = *head;
s = zcalloc(sizeof(*s)); s = xcalloc(1, sizeof(*s));
s->name = kw->name; s->name = kw->name;
TAILQ_INIT(&s->sub); TAILQ_INIT(&s->sub);
SLIST_INIT(&s->optlist); SLIST_INIT(&s->optlist);
kw = kw->next; kw = kw->next;
while (kw && kw->type != SEC_END) { while(kw && kw->type != SEC_END)
switch (kw->type) { {
switch(kw->type)
{
case INCLUDE: case INCLUDE:
if (!(kw = include(kw))) if(!(kw = include(kw)))
return free_sec(s); return free_sec(s);
break; break;
case SEC_START: case SEC_START:
if (!(sub = get_section(&kw))) if(!(sub = get_section(&kw)))
return free_sec(s); return free_sec(s);
TAILQ_INSERT_TAIL(&s->sub, sub, entry); TAILQ_INSERT_TAIL(&s->sub, sub, entry);
s->nsub++; ++s->nsub;
break; break;
case WORD: case WORD:
if (!(o = get_option(&kw))) if(!(o = get_option(&kw)))
return free_sec(s); return free_sec(s);
SLIST_INSERT_HEAD(&s->optlist, o, entry); SLIST_INSERT_HEAD(&s->optlist, o, entry);
s->nopt++; ++s->nopt;
break; break;
default: default:
syntax(kw, "syntax error"); syntax(kw, "syntax error");
return free_sec(s); return free_sec(s);
@ -536,7 +591,8 @@ get_section(struct keyword **head)
} }
} }
if (!kw || strcmp(kw->name, s->name)) { if(!kw || strcmp(kw->name, s->name))
{
syntax(kw, "missing end section %s", s->name); syntax(kw, "missing end section %s", s->name);
return free_sec(s); return free_sec(s);
} }
@ -555,7 +611,8 @@ free_conf(void)
struct files **f = NULL; struct files **f = NULL;
int i, nf = 0; int i, nf = 0;
while (!TAILQ_EMPTY(&config)) { while(!TAILQ_EMPTY(&config))
{
s = TAILQ_FIRST(&config); s = TAILQ_FIRST(&config);
TAILQ_REMOVE(&config, s, entry); TAILQ_REMOVE(&config, s, entry);
free_sec(s); free_sec(s);
@ -563,29 +620,34 @@ free_conf(void)
kw = keywords; kw = keywords;
while (kw) { while(kw)
{
nkw = kw->next; nkw = kw->next;
free(kw->name); free(kw->name);
for (i = 0; i < nf; i++) { for(i = 0; i < nf; ++i)
if (f[i] == kw->file) { if(f[i] == kw->file)
if (!(f = realloc(f, sizeof(*f) * (++i)))) {
err(EXIT_FAILURE, "realloc"); if(!(f = realloc(f, sizeof(*f) * (++i))))
f[i-1] = kw->file; errl(EXIT_FAILURE, "realloc");
}
f[i - 1] = kw->file;
} }
kw = nkw; kw = nkw;
} }
if (nf > 0) { if(nf > 0)
for (i = 0; i < nf; i++) { {
for(i = 0; i < nf; ++i)
{
free(f[i]->name); free(f[i]->name);
free(f[i]); free(f[i]);
} }
free(f); free(f);
} }
return -1; return -1;
} }
@ -595,32 +657,37 @@ get_conf(const char *filename)
struct conf_sec *s; struct conf_sec *s;
struct keyword *head, *kw; struct keyword *head, *kw;
kw = head = parse_keywords(filename); head = kw = parse_keywords(filename);
if (!head) if(!head)
return -1; /* TODO ERREUR */ return -1; /* TODO ERREUR */
keywords = head; keywords = head;
TAILQ_INIT(&config); TAILQ_INIT(&config);
while (kw) { while(kw)
switch (kw->type) { {
switch(kw->type)
{
case INCLUDE: case INCLUDE:
if (!(kw = include(kw))) if(!(kw = include(kw)))
return free_conf(); return free_conf();
break; break;
case SEC_START: case SEC_START:
if (!(s = get_section(&kw))) if(!(s = get_section(&kw)))
return free_conf(); return free_conf();
TAILQ_INSERT_TAIL(&config, s, entry); TAILQ_INSERT_TAIL(&config, s, entry);
break; break;
default: default:
syntax(kw, "out of any section"); syntax(kw, "out of any section");
return free_conf(); return free_conf();
break; break;
} }
} }
return 0; return 0;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org> * Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
* Copyright (c) 2011 Martin Duquesnoy <xorg62@gmail.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -22,7 +23,8 @@
#define INCLUDE_CMD "@include" #define INCLUDE_CMD "@include"
#define PARSE_MAX_LIST 32 #define PARSE_MAX_LIST 32
struct conf_opt { struct conf_opt
{
char *name; char *name;
char *val[PARSE_MAX_LIST]; char *val[PARSE_MAX_LIST];
size_t nval; size_t nval;
@ -32,16 +34,18 @@ struct conf_opt {
SLIST_ENTRY(conf_opt) entry; SLIST_ENTRY(conf_opt) entry;
}; };
struct conf_sec { struct conf_sec
{
char *name; char *name;
SLIST_HEAD(, conf_opt) optlist; SLIST_HEAD(, conf_opt) optlist;
TAILQ_HEAD(, conf_sec) sub; TAILQ_HEAD(cshead, conf_sec) sub;
size_t nopt; size_t nopt;
size_t nsub; size_t nsub;
TAILQ_ENTRY(conf_sec) entry; TAILQ_ENTRY(conf_sec) entry;
}; };
struct opt_type { struct opt_type
{
long int num; long int num;
float fnum; float fnum;
bool boolean; bool boolean;

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2010 Philippe Pepiot <phil@philpep.org> * Copyright (c) 2010 Philippe Pepiot <phil@philpep.org>
* Copyright (c) 2011 Martin Duquesnoy <xorg62@gmail.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -21,28 +22,29 @@
#include <stdlib.h> #include <stdlib.h>
#include <err.h> #include <err.h>
#include "wmfs.h"
#include "parse.h" #include "parse.h"
#include "util.h"
extern TAILQ_HEAD(, conf_sec) config; extern TAILQ_HEAD(, conf_sec) config;
static const struct opt_type opt_type_null = { 0, 0, False, NULL }; static const struct opt_type opt_type_null = { 0, 0, false, NULL };
static struct opt_type static struct opt_type
string_to_opt(char *s) string_to_opt(char *s)
{ {
struct opt_type ret = opt_type_null; struct opt_type ret = opt_type_null;
if (!s || !strlen(s)) if(!s || !strlen(s))
return ret; return ret;
ret.num = strtol(s, (char**)NULL, 10); ret.num = strtol(s, (char**)NULL, 10);
ret.fnum = strtod(s, NULL); ret.fnum = strtod(s, NULL);
if (!strcmp(s, "true") || !strcmp(s, "True") || ret.boolean = (!strcmp(s, "true")
!strcmp(s, "TRUE") || !strcmp(s, "1")) || !strcmp(s, "True")
ret.boolean = True; || !strcmp(s, "TRUE")
else || !strcmp(s, "1"));
ret.boolean = False;
ret.str = s; ret.str = s;
@ -56,7 +58,7 @@ print_unused(struct conf_sec *sec)
struct conf_sec *s; struct conf_sec *s;
struct conf_opt *o; struct conf_opt *o;
if (!sec) if(!sec)
{ {
TAILQ_FOREACH(s, &config, entry) TAILQ_FOREACH(s, &config, entry)
print_unused(s); print_unused(s);
@ -64,12 +66,11 @@ print_unused(struct conf_sec *sec)
} }
SLIST_FOREACH(o, &sec->optlist, entry) SLIST_FOREACH(o, &sec->optlist, entry)
if (o->used == False) if(!o->used)
warnx("%s:%d, unused param %s", warnxl("%s:%d, unused param %s", o->filename, o->line, o->name);
o->filename, o->line, o->name);
TAILQ_FOREACH(s, &sec->sub, entry) TAILQ_FOREACH(s, &sec->sub, entry)
if (!TAILQ_EMPTY(&s->sub)) if(!TAILQ_EMPTY(&s->sub))
print_unused(s); print_unused(s);
} }
@ -80,26 +81,32 @@ fetch_section(struct conf_sec *s, char *name)
struct conf_sec *sec; struct conf_sec *sec;
size_t i = 0; size_t i = 0;
if (!name) if(!name)
return NULL; return NULL;
if (!s) { if(!s)
{
ret = xcalloc(2, sizeof(struct conf_sec *)); ret = xcalloc(2, sizeof(struct conf_sec *));
TAILQ_FOREACH(sec, &config, entry) TAILQ_FOREACH(sec, &config, entry)
if (!strcmp(sec->name, name)) { if(!strcmp(sec->name, name))
{
ret[0] = sec; ret[0] = sec;
ret[1] = NULL; ret[1] = NULL;
break; break;
} }
} }
else { else
ret = xcalloc(s->nsub+1, sizeof(struct conf_sec *)); {
TAILQ_FOREACH(sec, &s->sub, entry) { ret = xcalloc(s->nsub + 1, sizeof(struct conf_sec *));
if (!strcmp(sec->name, name) && i < s->nsub)
TAILQ_FOREACH(sec, &s->sub, entry)
if(!strcmp(sec->name, name) && i < s->nsub)
ret[i++] = sec; ret[i++] = sec;
}
ret[i] = NULL; ret[i] = NULL;
} }
return ret; return ret;
} }
@ -107,26 +114,20 @@ struct conf_sec *
fetch_section_first(struct conf_sec *s, char *name) fetch_section_first(struct conf_sec *s, char *name)
{ {
struct conf_sec *sec, *ret = NULL; struct conf_sec *sec, *ret = NULL;
TAILQ_HEAD(cshead, conf_sec) *head =
(s
? (struct cshead*)&s->sub
: (struct cshead*)&config);
if (!name) if(!name)
return NULL; return NULL;
if (!s) TAILQ_FOREACH(sec, head, entry)
if(sec->name && !strcmp(sec->name, name))
{ {
TAILQ_FOREACH(sec, &config, entry)
if(sec->name && !strcmp(sec->name, name)) {
ret = sec; ret = sec;
break; break;
} }
}
else
{
TAILQ_FOREACH(sec, &s->sub, entry)
if (sec->name && !strcmp(sec->name, name)) {
ret = sec;
break;
}
}
return ret; return ret;
} }
@ -134,8 +135,11 @@ fetch_section_first(struct conf_sec *s, char *name)
size_t size_t
fetch_section_count(struct conf_sec **s) fetch_section_count(struct conf_sec **s)
{ {
size_t ret; size_t ret = 0;
for (ret = 0; s[ret]; ret++);
while(s[ret])
++ret;
return ret; return ret;
} }
@ -146,20 +150,25 @@ fetch_opt(struct conf_sec *s, char *dfl, char *name)
struct opt_type *ret; struct opt_type *ret;
size_t i = 0; size_t i = 0;
if (!name) if(!name)
return NULL; return NULL;
ret = xcalloc(10, sizeof(struct opt_type)); ret = xcalloc(10, sizeof(struct opt_type));
if (s) { if(s)
{
SLIST_FOREACH(o, &s->optlist, entry) SLIST_FOREACH(o, &s->optlist, entry)
if (!strcmp(o->name, name)) { if(!strcmp(o->name, name))
while (o->val[i]) { {
o->used = True; while(o->val[i])
{
o->used = true;
ret[i] = string_to_opt(o->val[i]); ret[i] = string_to_opt(o->val[i]);
i++; ++i;
} }
ret[i] = opt_type_null; ret[i] = opt_type_null;
return ret; return ret;
} }
} }
@ -175,22 +184,30 @@ fetch_opt_first(struct conf_sec *s, char *dfl, char *name)
{ {
struct conf_opt *o; struct conf_opt *o;
if (!name) if(!name)
return opt_type_null; return opt_type_null;
else if (s) else if(s)
{
SLIST_FOREACH(o, &s->optlist, entry) SLIST_FOREACH(o, &s->optlist, entry)
if (!strcmp(o->name, name)) { if(!strcmp(o->name, name))
o->used = True; {
o->used = true;
return string_to_opt(o->val[0]); return string_to_opt(o->val[0]);
} }
}
return string_to_opt(dfl); return string_to_opt(dfl);
} }
size_t size_t
fetch_opt_count(struct opt_type *o) fetch_opt_count(struct opt_type *o)
{ {
size_t ret; size_t ret = 0;
for(ret = 0; o[ret].str; ret++);
while(o[ret].str)
++ret;
return ret; return ret;
} }

View File

@ -1,281 +1,166 @@
/* /*
* screen.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
/** Count the screens
*\return the number of screen
*/
int
screen_count(void)
{
int n = ScreenCount(dpy);
#ifdef HAVE_XINERAMA
if(XineramaIsActive(dpy))
XineramaQueryScreens(dpy, &n);
#endif /* HAVE_XINERAMA */
/* Set _WMFS_SCREEN_COUNT */
if(net_atom)
XChangeProperty(dpy, ROOT, net_atom[wmfs_screen_count], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&n, 1);
return n;
}
/** Get screen geometry by number
*\param s Screen number
*\return Geo struct
*/
Geo
screen_get_geo(int s)
{
int barpos = tags[selscreen][seltag[selscreen]].barpos;
Geo geo;
geo.x = BORDH;
if(barpos == IB_Hide || barpos == IB_Bottom)
geo.y = TBARH;
else
geo.y = INFOBARH + TBARH;
geo.height = MAXH - INFOBARH - TBARH;
geo.width = MAXW;
#ifdef HAVE_XINERAMA
if(XineramaIsActive(dpy))
{
XineramaScreenInfo *xsi;
int n = 0;
xsi = XineramaQueryScreens(dpy, &n);
geo.x = xsi[s].x_org + BORDH;
if(barpos == IB_Hide || barpos == IB_Bottom)
geo.y = TBARH;
else
geo.y = xsi[s].y_org + INFOBARH + TBARH;
geo.height = xsi[s].height - INFOBARH - TBARH;
geo.width = xsi[s].width;
XFree(xsi);
}
#else
(void)s;
#endif /* HAVE_XINERAMA */
return geo;
}
/** Get the current screen number with
* coordinated
*\param geo Geometry for get the screen number
*\return The screen number
*/
int
screen_get_with_geo(int x, int y)
{
int i = 0;
for(; i < screen_count(); ++i)
if(INAREA(x, y, spgeo[i]))
return i;
return 0;
}
/** Set the selected screen
*\param screen Number of the wanted selected screen
*/
void
screen_set_sel(int screen)
{
if(screen < 0 || screen > screen_count() - 1)
screen = 0;
if(selscreen != screen)
prevselscreen = selscreen;
client_focus(NULL);
XWarpPointer(dpy, None, ROOT, 0, 0, 0, 0,
sgeo[screen].x + (sgeo[screen].width >> 1),
sgeo[screen].y + (sgeo[screen].height >> 1));
selscreen = screen;
return;
}
/** Get and set the selected screen
*\return The number of the selected screen
*/
int
screen_get_sel(void)
{
int os = selscreen;
selscreen = 0;
#ifdef HAVE_XINERAMA
if(XineramaIsActive(dpy))
{
/* Unused variables (except x/y) */
Window w;
int d, x, y;
XQueryPointer(dpy, ROOT, &w, &w, &x, &y, &d, &d, (uint *)&d);
selscreen = screen_get_with_geo(x, y);
}
#endif /* HAVE_XINERAMA */
/* Set _WMFS_CURRENT_SCREEN */
XChangeProperty(dpy, ROOT, net_atom[wmfs_current_screen], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&selscreen, 1);
if(os != selscreen && os != prevselscreen)
prevselscreen = os;
return selscreen;
}
/** Init screen geo
*/ */
void
screen_init_geo(void) #ifdef HAVE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* HAVE_XINERAMA */
#include "screen.h"
#include "util.h"
#include "tag.h"
#include "infobar.h"
#include "client.h"
static struct screen*
screen_new(struct geo *g, int id)
{ {
int i; struct screen *s = (struct screen*)xcalloc(1, sizeof(struct screen));
int s = screen_count();
sgeo = xcalloc(s, sizeof(Geo)); s->geo = s->ugeo = *g;
spgeo = xcalloc(s, sizeof(Geo)); s->seltag = NULL;
s->id = id;
s->flags = 0;
for(i = 0; i < s; ++i) TAILQ_INIT(&s->tags);
sgeo[i] = screen_get_geo(i); SLIST_INIT(&s->infobars);
spgeo[0].x = 0; SLIST_INSERT_HEAD(&W->h.screen, s, next);
spgeo[0].y = 0;
spgeo[0].width = MAXW; /* Set as selected screen */
spgeo[0].height = MAXH; W->screen = s;
return s;
}
void
screen_init(void)
{
struct geo g;
SLIST_INIT(&W->h.screen);
#ifdef HAVE_XINERAMA #ifdef HAVE_XINERAMA
XineramaScreenInfo *xsi; XineramaScreenInfo *xsi;
int n; int i, n = 0;
if(XineramaIsActive(dpy)) if(XineramaIsActive(W->dpy))
{ {
xsi = XineramaQueryScreens(dpy, &n); xsi = XineramaQueryScreens(W->dpy, &n);
for(i = 0; i < n; ++i) for(i = 0; i < n; ++i)
{ {
spgeo[i].x = xsi[i].x_org; g.x = xsi[i].x_org;
spgeo[i].y = xsi[i].y_org; g.y = xsi[i].y_org;
spgeo[i].width = xsi[i].width; g.w = xsi[i].width;
spgeo[i].height = xsi[i].height; g.h = xsi[i].height;
screen_new(&g, i);
} }
W->nscreen = n;
XFree(xsi); XFree(xsi);
} }
else
#endif /* HAVE_XINERAMA */
{
g.x = g.y = 0;
g.w = DisplayWidth(W->dpy, W->xscreen);
g.h = DisplayHeight(W->dpy, W->xscreen);
screen_new(&g, 0);
W->nscreen = 1;
}
}
/*
* Update selected screen with mouse location
*/
struct screen*
screen_update_sel(void)
{
#ifdef HAVE_XINERAMA
if(XineramaIsActive(W->dpy))
return (W->screen = screen_gb_mouse());
#endif /* HAVE_XINERAMA */ #endif /* HAVE_XINERAMA */
#ifdef HAVE_XRANDR return W->screen;
/* Init xrandr stuff */
int d;
XRRSelectInput(dpy, ROOT, 1);
XRRQueryExtension(dpy, &xrandr_event, &d);
#endif /* HAVE_XRANDR */
ewmh_set_desktop_geometry();
return;
} }
/** Uicb: screen select static void
* \param cmd Screen uicb_t type screen_select(struct screen *s)
*/
void
uicb_screen_select(uicb_t cmd)
{ {
screen_set_sel(atoi(cmd)); XWarpPointer(W->dpy, None, W->root, 0, 0, 0, 0,
s->ugeo.x + (s->ugeo.w >> 1),
s->ugeo.y + (s->ugeo.h >> 1));
return; W->screen = s;
} }
/** Uicb: screen next
* \param cmd Screen uicb_t type
*/
void void
uicb_screen_next(uicb_t cmd) uicb_screen_next(Uicb cmd)
{ {
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd; (void)cmd;
screen_get_sel();
if(screen_count() > 1) if(!s)
s = SLIST_FIRST(&W->h.screen);
screen_select(s);
}
void
uicb_screen_prev(Uicb cmd)
{
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
screen_select(s);
}
void
uicb_screen_move_client_next(Uicb cmd)
{
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd;
if(!s)
s = SLIST_FIRST(&W->h.screen);
if(W->client)
tag_client(s->seltag, W->client);
}
void
uicb_screen_move_client_prev(Uicb cmd)
{
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
if(W->client)
tag_client(s->seltag, W->client);
}
void
screen_free(void)
{
struct screen *s;
while(!SLIST_EMPTY(&W->h.screen))
{ {
selscreen = (selscreen + 1 > screen_count() - 1) ? 0 : selscreen + 1; s = SLIST_FIRST(&W->h.screen);
SLIST_REMOVE_HEAD(&W->h.screen, next);
screen_set_sel(selscreen); infobar_free(s);
tag_free(s);
free(s);
} }
return;
} }
/** Uicb: screen prev
* \param cmd Screen uicb_t type
*/
void
uicb_screen_prev(uicb_t cmd)
{
(void)cmd;
screen_get_sel();
selscreen = (selscreen - 1 < 0) ? screen_count() - 1 : selscreen - 1;
screen_set_sel(selscreen);
return;
}
/** Uicb: screen prev sel
* \param cmd uicb_t type unused
*/
void
uicb_screen_prev_sel(uicb_t cmd)
{
(void)cmd;
screen_get_sel();
screen_set_sel(prevselscreen);
return;
}

56
src/screen.h Normal file
View File

@ -0,0 +1,56 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef SCREEN_H
#define SCREEN_H
#include "wmfs.h"
#include "util.h"
static inline struct screen*
screen_gb_id(int id)
{
struct screen *s;
SLIST_FOREACH(s, &W->h.screen, next)
if(s->id == id)
return s;
return SLIST_FIRST(&W->h.screen);
}
static inline struct screen*
screen_gb_geo(int x, int y)
{
struct screen *s;
SLIST_FOREACH(s, &W->h.screen, next)
if(INAREA(x, y, s->geo))
return s;
return SLIST_FIRST(&W->h.screen);
}
static inline struct screen*
screen_gb_mouse(void)
{
Window w;
int d, x, y;
XQueryPointer(W->dpy, W->root, &w, &w, &x, &y, &d, &d, (unsigned int *)&d);
return screen_gb_geo(x, y);
}
void screen_init(void);
struct screen* screen_update_sel(void);
void screen_free(void);
void uicb_screen_next(Uicb cmd);
void uicb_screen_prev(Uicb cmd);
void uicb_screen_move_client_next(Uicb cmd);
void uicb_screen_move_client_prev(Uicb cmd);
#endif /* SCREEN_H */

View File

@ -1,374 +0,0 @@
/*
* split.c
* Copyright © 2011 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
#define SPLIT_CHECK_ROW(g1, g2, p) \
(LDIR(p) \
? (g1.y >= g2.y && (g1.y + g1.height) <= (g2.y + g2.height)) \
: (g1.x >= g2.x && (g1.x + g1.width) <= (g2.x + g2.width))) \
#define SPLIT_MOVE_DIR(d) \
void \
uicb_split_move_##d(uicb_t cmd) \
{ \
(void)cmd; \
CHECK(sel); \
split_move_dir(sel, d); \
}
/* uicb_split_move_dir() */
SPLIT_MOVE_DIR(Right);
SPLIT_MOVE_DIR(Left);
SPLIT_MOVE_DIR(Top);
SPLIT_MOVE_DIR(Bottom);
/** Arrange size of parent client of last closed client
*/
static void
_split_arrange_size(Geo g, Geo *cg, Position p)
{
if(LDIR(p))
cg->width += FRAMEW(g.width);
else
cg->height += FRAMEH(g.height);
if(p == Right)
cg->x -= FRAMEW(g.width);
if(p == Bottom)
cg->y -= FRAMEH(g.height);
return;
}
/** Set layout current clients to split/unsplit
*/
void
split_set_current(Client *nc, Client *ghost)
{
if(nc && (tags[nc->screen][nc->tag].flags & SplitFlag))
{
tags[nc->screen][nc->tag].layout.nc = nc;
tags[nc->screen][nc->tag].layout.flags |= IntegrationFlag;
}
if(ghost && (tags[ghost->screen][ghost->tag].flags & SplitFlag))
{
tags[ghost->screen][ghost->tag].layout.ghost = *ghost;
tags[ghost->screen][ghost->tag].layout.flags |= ArrangeFlag;
}
return;
}
/** Apply current operation about split
*/
void
split_apply_current(int screen, int tag)
{
/* Integrate in split mode */
if(tags[screen][tag].layout.flags & IntegrationFlag)
{
split_client_integrate(tags[screen][tag].layout.nc, sel, screen, tag);
tags[screen][tag].layout.flags &= ~IntegrationFlag;
}
/* Remove from split mode */
if(tags[screen][tag].layout.flags & ArrangeFlag)
{
split_arrange_closed(&tags[screen][tag].layout.ghost);
tags[screen][tag].layout.flags &= ~ArrangeFlag;
}
return;
}
/** Check if row direction is available to resize from it
*\param c Client pointer
*\param g Client pointer
*\param p Position
*\return True if available
*/
static bool
_split_check_row_dir(Client *c, Client *g, Position p)
{
int s = 0, cs;
Geo cgeo = c->frame_geo;
Client *cc = tiled_client(c->screen, SLIST_FIRST(&clients));
cs = (LDIR(p) ? g->frame_geo.height : g->frame_geo.width);
for(; cc; cc = tiled_client(c->screen, SLIST_NEXT(cc, next)))
if(CFACTOR_PARENTROW(cgeo, cc->frame_geo, RPOS(p))
&& SPLIT_CHECK_ROW(cc->frame_geo, g->frame_geo, p))
{
s += (LDIR(p) ? cc->frame_geo.height : cc->frame_geo.width);
if(s == cs)
return True;
if(s > cs)
return False;
}
return False;
}
/** Arrange clients after a client close
*\param ghost Ghost client
*/
void
split_arrange_closed(Client *ghost)
{
Position p;
bool b = False;
Geo cgeo;
Client *c, *cc;
int screen = ghost->screen;
int tag = (ghost->tag ? ghost->tag : seltag[screen]);
/* Use ghost client properties to fix holes in tile
* .--. ~ ~
* /xx \ ~ ~
* ~~\O _ (____ ~
* __.| .--'-==~ ~
* '---\ '. ~ , ~
* '. '-.___.-'/ ~
* '-.__ _.' ~
* ````` ~
*/
/* Search for single parent for easy resize
* Example case:
* ___________ ___________
* | | B | -> -> | | |
* | A |_____| -> Close -> | A | B |
* | | C | -> C -> | |v v v|
* |_____|_____| -> -> |_____|_____|
*/
for(p = Right; p < Center; ++p)
if((c = client_get_next_with_direction(ghost, p)))
if(CFACTOR_CHECK2(ghost->frame_geo, c->frame_geo, p))
{
_split_arrange_size(ghost->wrgeo, &c->wrgeo, p);
cfactor_clean(c);
client_moveresize(c, (c->pgeo = c->wrgeo), (tags[screen][tag].flags & ResizeHintFlag));
return;
}
/* Check row parents for full resize
* Example case:
* ___________ ___________
* | | B | -> -> | << B |
* | A |_____| -> Close -> |___________|
* | | C | -> A -> | << C |
* |_____|_____| -> -> |___________|
*/
for(p = Right; p < Center && !b; ++p)
if((c = client_get_next_with_direction(ghost, p)) && _split_check_row_dir(c, ghost, p))
{
for(cgeo = c->frame_geo, cc = tiled_client(c->screen, SLIST_FIRST(&clients));
cc; cc = tiled_client(c->screen, SLIST_NEXT(cc, next)))
if(CFACTOR_PARENTROW(cgeo, cc->frame_geo, RPOS(p))
&& SPLIT_CHECK_ROW(cc->frame_geo, ghost->frame_geo, p))
{
_split_arrange_size(ghost->wrgeo, &cc->wrgeo, p);
cfactor_clean(cc);
client_moveresize(cc, (cc->pgeo = cc->wrgeo), (tags[screen][tag].flags & ResizeHintFlag));
b = True;
}
}
return;
}
/** Split client hor or vert to insert another client in the new area
*\param c Client pointer
*\param p True = Vertical, False = Horizontal
*\return sgeo Geo of future integrated client
*/
Geo
split_client(Client *c, bool p)
{
Geo geo, sgeo;
if(!c || !(c->flags & TileFlag))
return c->wrgeo;
cfactor_clean(c);
c->flags &= ~(MaxFlag | LMaxFlag);
c->flags |= TileFlag;
/* Use geometry without resizehint applied on it */
geo = sgeo = c->wrgeo;
/* Vertical */
if(p)
{
geo.width >>= 1;
sgeo.x = FRAMEW(geo.x + geo.width);
sgeo.width = (sgeo.width >> 1) - (BORDH << 1);
/* Remainder */
sgeo.width += (c->wrgeo.x + c->wrgeo.width) - (sgeo.x + sgeo.width);
}
/* Horizontal */
else
{
geo.height = (geo.height >> 1) - TBARH;
sgeo.y = FRAMEH(geo.y + geo.height);
sgeo.height = (sgeo.height >> 1) - BORDH;
/* Remainder */
sgeo.height += (c->wrgeo.y + c->wrgeo.height) - (sgeo.y + sgeo.height);
}
client_moveresize(c, (c->pgeo = geo), (tags[c->screen][c->tag].flags & ResizeHintFlag));
return sgeo;
}
/** Apply new attributes to splitted client
*\param c Client pointer
*\param geo New geo
*/
void
split_client_fill(Client *c, Geo geo)
{
if(!c)
return;
c->flags &= ~(MaxFlag | LMaxFlag);
c->flags |= TileFlag;
cfactor_clean(c);
client_moveresize(c, (c->pgeo = geo), (tags[c->screen][c->tag].flags & ResizeHintFlag));
return;
}
/** Integrate client in tag
*\param c Client pointer (integrate)
*\param sc Splitted client pointer
*/
void
split_client_integrate(Client *c, Client *sc, int screen, int tag)
{
bool b = True;
Geo g;
if(!c || c->flags & FreeFlag || !(tags[screen][tag].flags & SplitFlag))
return;
/* Can't integrate in sc */
if(!sc || sc == c || !(sc->flags & TileFlag)
|| sc->screen != screen || sc->tag != tag)
{
/* Looking for first client on wanted tag */
b = False;
SLIST_FOREACH(sc, &clients, next)
if(sc != c && sc->screen == screen && sc->tag == tag
&& (sc->flags & TileFlag))
{
b = True;
break;
}
/* No client on wanted tag to integrate */
if(!b)
{
/* client_maximize check position of client
* to maximize it; so in case of transfert one client
* on a tag from another screen, we need it.
*/
c->geo.x = sgeo[screen].x;
c->geo.y = sgeo[screen].y;
client_maximize(c);
c->flags |= TileFlag;
return;
}
}
g = split_client(sc, (sc->frame_geo.height < sc->frame_geo.width));
split_client_fill(c, g);
return;
}
/** Move splitted client by re-arranging it in next by direction client
* Integrate c in next client by direction
* Example case, direction = left:
* ___________ ___________
* | | B | -> | A | |
* | A |_____| -> |_____| B |
* | |< C | -> | C |v v v|
* |_____|_____| -> |_____|_____|
*/
void
split_move_dir(Client *c, Position p)
{
Client *sc;
if(!c || !(tags[c->screen][c->tag].flags & SplitFlag))
return;
if((sc = client_get_next_with_direction(c, p)))
{
split_arrange_closed(c);
split_client_integrate(c, sc, sc->screen, sc->tag);
}
return;
}
/** Toggle split mode
*/
void
uicb_split_toggle(uicb_t cmd)
{
(void)cmd;
tags[selscreen][seltag[selscreen]].flags ^= SplitFlag;
layout_func(selscreen, seltag[selscreen]);
infobar_draw_layout(&infobar[selscreen]);
return;
}

View File

@ -1,290 +1,653 @@
/* /*
* status.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h"
/* Systray width */
static int sw = 0;
/** Parse dynamic mouse binds in str and insert it in linked list
* --> \<block>[;;;;(button;func;cmd)]\ add a mouse bind on the block object
*\param str String
*\param area Area of clicking
*\param infobar Infobar pointer
*/ */
#include "status.h"
#include "barwin.h"
#include "config.h"
#include "infobar.h"
#include "util.h"
#include "draw.h"
#include <string.h>
struct status_seq*
status_new_seq(char type, int narg, int minarg, char *args[], int *shift)
{
struct status_seq *sq = xcalloc(1, sizeof(struct status_seq));
SLIST_INIT(&sq->mousebinds);
sq->type = type;
*shift = 0;
if(narg == minarg || !strcmp(args[0], "right") || !strcmp(args[0], "left"))
sq->align = str_to_position(args[0]);
else
{
sq->align = NoAlign;
sq->geo.x = ATOI(args[0]);
sq->geo.y = ATOI(args[1]);
*shift = 1;
}
return sq;
}
struct status_ctx
status_new_ctx(struct barwin *b, struct theme *t)
{
struct status_ctx ctx = { .barwin = b, .theme = t };
SLIST_INIT(&ctx.statushead);
SLIST_INIT(&ctx.gcache);
return ctx;
}
static void
status_gcache_free(struct status_ctx *ctx)
{
struct status_gcache *gc;
while(!SLIST_EMPTY(&ctx->gcache))
{
gc = SLIST_FIRST(&ctx->gcache);
SLIST_REMOVE_HEAD(&ctx->gcache, next);
free(gc->datas);
free(gc->name);
free(gc);
}
}
void void
statustext_mouse(char *str, Geo area, InfoBar *infobar) status_free_ctx(struct status_ctx *ctx)
{ {
StatusMouse *sm = NULL; free(ctx->status);
int i = 0, button = 1, n; status_flush_list(ctx);
char cmd[256] = { 0 }; status_gcache_free(ctx);
char func[64] = { 0 };
for(; i < (int)strlen(str); ++i, sm = NULL)
if((n = sscanf(&str[i], "(%d;%64[^;];%256[^)])", &button, func, cmd) >= 2) && n < 4)
{
sm = zcalloc(sizeof(StatusMouse));
sm->button = button;
sm->func = name_to_func((char*)func, func_list);
sm->cmd = xstrdup(cmd);
sm->area = area;
sm->infobar = infobar;
SLIST_INSERT_HEAD(&smhead, sm, next);
/* Jump to the end of the sequence */
while(str[++i + 1] != ')');
}
return;
} }
/** Check rectangles blocks in str and draw it
* --> \b[x;y;width;height;#color]\
*\param ib Infobar pointer
*\param str String
*/
static void static void
statustext_rectangle(InfoBar *ib, char *str) status_graph_draw(struct status_ctx *ctx, struct status_seq *sq, struct status_gcache *gc)
{ {
StatusRec r; int max = 0;
char as, mouse[512] = { 0 }; int i, j, y;
int i = 0, j = 0, k, n; float c;
int ys = sq->geo.y + sq->geo.h - 1;
for(; i < (int)strlen(str); ++i, ++j) /* If invalid maximum, we have to compute it ourselves */
if(((n = sscanf(&str[i], "\\b[%d;%d;%d;%d;#%x]%c", if(sq->data[2] <= 0)
&r.g.x, &r.g.y, &r.g.width, &r.g.height, &r.color, &as)) == 6
|| (n = sscanf(&str[i], "\\b[%d;%d;%d;%d;#%x;%512[^]]]%c",
&r.g.x, &r.g.y, &r.g.width, &r.g.height, &r.color, mouse, &as)) == 7)
&& as == '\\')
{ {
draw_rectangle(ib->bar->dr, r.g.x - sw, r.g.y, r.g.width, r.g.height, r.color); for(i = sq->geo.x + sq->geo.w - 1, j = gc->ndata - 1;
j >= 0 && i >= sq->geo.x;
if(n == 7) --j, --i)
statustext_mouse(mouse, r.g, ib); {
if(gc->datas[j] > max)
for(++i, --j; str[i] != as || str[i - 1] != ']'; ++i); max = gc->datas[j];
} }
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = '\0');
return;
}
/** Check graphs blocks in str and draw it
* --> \g[x;y;width;height;#color;data]\
*\param ib Infobar pointer
*\param str String
*/
static void
statustext_graph(InfoBar *ib, char *str)
{
StatusGraph g;
char as, c, *p;
int i, j, k, m, w;
for(i = j = 0; i < (int)strlen(str); ++i, ++j)
if(sscanf(&str[i], "\\g[%d;%d;%d;%d;#%x;%512[^]]]%c",
&g.x, &g.y, &g.w, &g.h, &g.color, g.data, &as) == 7
&& as == '\\')
{
/* data is a list of numbers separated by ';' */
w = g.w;
p = strtok(g.data, ";");
m = 0;
for(c = atoi(p); p && m < w; ++m)
{
/* height limits */
if(c < 0)
c = 0;
if(c > (char)g.h)
c = g.h;
g.data[m] = c;
p = strtok(NULL, ";");
}
/* width limits */
for(; m < w; g.data[m++] = 0);
/* data is a array[w] of bytes now */
draw_graph(ib->bar->dr, g.x - sw, g.y, g.w, g.h, g.color, g.data);
for(++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
}
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = '\0');
return;
}
/** Check text blocks in str and draw it
* --> \s[x;y;#color;text]\
*\param ib Infobar pointer
*\param str String
*/
static void
statustext_text(InfoBar *ib, char *str)
{
StatusText s;
Geo area;
char as, mouse[512] = { 0 };
int i = 0, j = 0, k, n;
for(; i < (int)strlen(str); ++i, ++j)
if(((n = sscanf(&str[i], "\\s[%d;%d;%7[^;];%512[^];]]%c",
&s.x, &s.y, s.color, s.text, &as)) == 5
|| (n = sscanf(&str[i], "\\s[%d;%d;%7[^;];%512[^;];%512[^]]]%c",
&s.x, &s.y, s.color, s.text, mouse, &as)) == 6)
&& as == '\\')
{
draw_text(ib->bar->dr, s.x - sw, s.y, s.color, s.text);
/* Etablish clickable area on text */
if(n == 6)
{
area.height = font.height;
area.width = textw(s.text);
area.x = s.x - sw;
area.y = s.y - area.height;
statustext_mouse(mouse, area, ib);
}
for(++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
}
else if(j != i)
str[j] = str[i];
for(k = j; k < i; str[k++] = '\0');
return;
}
/** Draw normal text and colored normal text
* --> \#color\ text in color
*\param sc Screen id
*\param ib Infobar pointer
*\param str String
*/
static void
statustext_normal(InfoBar *ib, char *str)
{
char strwc[MAXSTATUS] = { 0 };
char buf[MAXSTATUS] = { 0 };
char col[8] = { 0 };
int n, i, j, k, tw;
for(i = j = n = 0; i < (int)strlen(str); ++i, ++j)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{
++n;
i += 8;
--j;
} }
else else
strwc[j] = str[i]; max = sq->data[2];
/* Draw normal text without any blocks */ XSetForeground(W->dpy, W->gc, sq->color2);
draw_text(ib->bar->dr, (sgeo[ib->screen].width - SHADH) - (textw(strwc) + sw), FHINFOBAR, ib->bar->fg, strwc);
if(n) for(i = sq->geo.x + sq->geo.w - 1, j = gc->ndata - 1;
j >= 0 && i >= sq->geo.x;
--j, --i)
{ {
strncpy(buf, strwc, sizeof(buf)); /* You divided by zero didn't you? */
if(gc->datas[j])
for(i = k = 0; i < (int)strlen(str); ++i, ++k)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{ {
tw = textw(&buf[k]); c = (float)max / (float)gc->datas[j];
y = ys - (sq->geo.h / (c > 1 ? c : 1)) + 1;
/* Store current color in col[] */ draw_line(ctx->barwin->dr, i, y, i, ys);
for(j = 0, ++i; str[i] != '\\'; col[j++] = str[i++]);
/* Draw a rectangle with the bar color to draw the text properly */
draw_rectangle(ib->bar->dr, (sgeo[ib->screen].width - SHADH) - (tw + sw),
0, INFOBARH - (sgeo[ib->screen].width - SHADH) - tw,
INFOBARH, conf.colors.bar);
/* Draw text with its color */
draw_text(ib->bar->dr, (sgeo[ib->screen].width - SHADH) - (tw + sw), FHINFOBAR, col, &buf[k]);
strncpy(buf, strwc, sizeof(buf));
++i;
} }
} }
return;
} }
/** Handle statustext and draw all things in infobar of specified screen static void
*\param sc Screen id status_graph_process(struct status_ctx *ctx, struct status_seq *sq, char *name)
*\param str String
*/
void
statustext_handle(InfoBar *ib)
{ {
char *str; int j;
StatusMouse *sm; struct status_gcache *gc;
/* Free previous linked list of mouse bind */ /* Graph already exist and have a cache */
if(!ib->screen) SLIST_FOREACH(gc, &ctx->gcache, next)
while(!SLIST_EMPTY(&smhead)) if(!strcmp(name, gc->name))
{ {
sm = SLIST_FIRST(&smhead); /* shift buffer to remove unused old value */
SLIST_REMOVE_HEAD(&smhead, next); if(gc->ndata > (sq->geo.w << 1))
free((void*)sm->cmd); for(gc->ndata /= 2, j = 0;
free(sm); j < gc->ndata;
gc->datas[j] = gc->datas[j + gc->ndata], ++j);
gc->datas[gc->ndata++] = sq->data[1];
status_graph_draw(ctx, sq, gc);
return;
} }
if(ib->screen == conf.systray.screen) if(sq->data[1] > sq->data[2])
sw = systray_get_width(); sq->data[1] = sq->data[2];
str = xstrdup(ib->statustext); /* No? Make a cache for it */
gc = xcalloc(1, sizeof(struct status_gcache));
gc->name = xstrdup(name);
gc->ndata = 1;
gc->datas = xcalloc(sq->geo.w << 2, sizeof(int));
gc->datas[0] = sq->data[1];
/* Store rectangles, located text & images properties. */ SLIST_INSERT_HEAD(&ctx->gcache, gc, next);
statustext_rectangle(ib, str);
statustext_graph(ib, str);
statustext_text(ib, str);
/* Draw normal text (and possibly colored with \#color\ blocks) */ status_graph_draw(ctx, sq, gc);
statustext_normal(ib, str); }
sw = 0; /* Parse mousebind sequence next normal sequence: \<seq>[](button;func;cmd) */
static char*
free(str); status_parse_mouse(struct status_seq *sq, char *str)
{
return; struct mousebind *m;
char *end, *arg[3] = { NULL };
int i;
if(*str != '(' || !(end = strchr(str, ')')))
return str;
i = parse_args(++str, ';', ')', 3, arg);
m = xcalloc(1, sizeof(struct mousebind));
m->use_area = true;
m->button = ATOI(arg[0]);
m->func = uicb_name_func(arg[1]);
m->cmd = (i > 1 ? xstrdup(arg[2]) : NULL);
SLIST_INSERT_HEAD(&sq->mousebinds, m, snext);
return end + 1;
}
#define STATUS_CHECK_ARGS(i, n1, n2, str, end) \
if(i != n1 && i != n2) \
{ \
str = end + 2; \
continue; \
}
void
status_parse(struct status_ctx *ctx)
{
struct status_seq *sq, *prev = NULL;
int i, tmp, shift = 0;
char *dstr = xstrdup(ctx->status), *sauv = dstr;
char type, *p, *pp, *end, *arg[10] = { NULL };
for(; *dstr; ++dstr)
{
/* Check if this is a sequence */
if(*dstr != '^' && *dstr != '\\')
continue;
p = ++dstr;
/* Search for correct end of sequence (] without \ behind) */
if((end = strchr(p, ']')))
while(*(end - 1) == '\\')
end = strchr(end + 1, ']');
if(!(strchr("sRpPig", *p)) || !end)
continue;
/* Then parse & list it */
switch((type = *p))
{
/*
* Text sequence: \s[left/right;#color;text] OR \s[x;y;#color;text]
*/
case 's':
i = parse_args(p + 2, ';', ']', 4, arg);
STATUS_CHECK_ARGS(i, 2, 3, dstr, end);
sq = status_new_seq(type, i, 2, arg, &shift);
sq->color = color_atoh(arg[1 + shift]);
sq->str = xstrdup(arg[2 + shift]);
/* Remove \ from string */
for(pp = sq->str; (pp = strchr(sq->str, '\\'));)
memmove(pp, pp + 1, strlen(pp));
break;
/*
* Rectangle sequence: \R[left/right;w;h;#color] OR \R[x;y;w;h;#color]
*/
case 'R':
i = parse_args(p + 2, ';', ']', 5, arg);
STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
sq = status_new_seq(type, i, 3, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->color = color_atoh(arg[3 + shift]);
break;
/*
* Progress bar sequence: \p[left/right;w;h;bord;val;valmax;bg;fg] OR x;y
* Position bar sequence: \P[left/right;w;h;tickbord;val;valmax;bg;fg] OR x;y
*/
case 'p':
case 'P':
i = parse_args(p + 2, ';', ']', 9, arg);
STATUS_CHECK_ARGS(i, 7, 8, dstr, end);
sq = status_new_seq(type, i, 7, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->data[0] = ATOI(arg[3 + shift]); /* Border */
sq->data[1] = ((tmp = ATOI(arg[4 + shift])) ? tmp : 1); /* Value */
sq->data[2] = ATOI(arg[5 + shift]); /* Value Max */
sq->color = color_atoh(arg[6 + shift]);
sq->color2 = color_atoh(arg[7 + shift]);
break;
/*
* Graph sequence: \g[left/right;w;h;val;valmax;bg;fg;name] OR x;y
*/
case 'g':
i = parse_args(p + 2, ';', ']', 9, arg);
STATUS_CHECK_ARGS(i, 7, 8, dstr, end);
sq = status_new_seq(type, i, 7, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->data[1] = ATOI(arg[3 + shift]); /* Value */
sq->data[2] = ATOI(arg[4 + shift]); /* Value Max */
sq->color = color_atoh(arg[5 + shift]);
sq->color2 = color_atoh(arg[6 + shift]);
sq->str = xstrdup(arg[7 + shift]);
break;
/*
* Image sequence: \i[left/right;w;h;/path/img] OR \i[x;y;w;h;/path/img]
*/
#ifdef HAVE_IMLIB2
case 'i':
i = parse_args(p + 2, ';', ']', 5, arg);
STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
sq = status_new_seq(type, i, 3, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->str = xstrdup(arg[3 + shift]);
break;
#endif /* HAVE_IMLIB2 */
}
if(sq->align == Right)
SLIST_INSERT_HEAD(&ctx->statushead, sq, next);
else
SLIST_INSERT_TAIL(&ctx->statushead, sq, next, prev);
/*
* Optional mousebind sequence(s) \<seq>[](button;func;cmd)
* Parse it while there is a mousebind sequence.
*/
dstr = end + 1;
do
dstr = status_parse_mouse(sq, dstr);
while(*dstr == '(');
--dstr;
prev = sq;
}
free(sauv);
}
#define STATUS_ALIGN(align) \
if(align == Left) \
{ \
sq->geo.x = left; \
left += sq->geo.w; \
} \
else if(align == Right) \
{ \
sq->geo.x = ctx->barwin->geo.w - right - sq->geo.w; \
right += sq->geo.w; \
}
#define STORE_MOUSEBIND() \
if(!SLIST_EMPTY(&sq->mousebinds)) \
SLIST_FOREACH(m, &sq->mousebinds, snext) \
m->area = sq->geo;
#define NOALIGN_Y() \
if(sq->align != NoAlign) \
sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
static void
status_apply_list(struct status_ctx *ctx)
{
struct status_seq *sq;
struct mousebind *m;
struct geo g;
int left = 0, right = 0, w, h;
SLIST_FOREACH(sq, &ctx->statushead, next)
{
switch(sq->type)
{
/* Text */
case 's':
sq->geo.w = draw_textw(ctx->theme, sq->str);
sq->geo.h = ctx->theme->font.height;
if(sq->align != NoAlign)
sq->geo.y = TEXTY(ctx->theme, ctx->barwin->geo.h);
STATUS_ALIGN(sq->align);
draw_text(ctx->barwin->dr, ctx->theme, sq->geo.x, sq->geo.y, sq->color, sq->str);
if(!SLIST_EMPTY(&sq->mousebinds))
SLIST_FOREACH(m, &sq->mousebinds, snext)
{
m->area = sq->geo;
m->area.y -= sq->geo.h;
}
break;
/* Rectangle */
case 'R':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
STORE_MOUSEBIND();
break;
/* Progress */
case 'p':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
/* Progress bar geo */
g.x = sq->geo.x + sq->data[0];
g.y = sq->geo.y + sq->data[0];
g.w = sq->geo.w - sq->data[0] - sq->data[0];
g.h = sq->geo.h - sq->data[0] - sq->data[0];
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
if(sq->geo.w > sq->geo.h)
g.w /= ((float)sq->data[2] / (float)sq->data[1]);
else
{
g.y += g.h;
g.h /= ((float)sq->data[2] / (float)sq->data[1]);
g.y -= g.h;
}
draw_rect(ctx->barwin->dr, &g, sq->color2);
STORE_MOUSEBIND();
break;
/* Position */
case 'P':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
g.x = sq->geo.x + ((sq->geo.w - sq->data[0]) / ((float)sq->data[2] / (float)sq->data[1]));
g.y = sq->geo.y;
g.w = sq->data[0];
g.h = sq->geo.h;
draw_rect(ctx->barwin->dr, &g, sq->color2);
STORE_MOUSEBIND();
break;
/* Graph */
case 'g':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
status_graph_process(ctx, sq, sq->str);
STORE_MOUSEBIND();
break;
/* Image */
#ifdef HAVE_IMLIB2
case 'i':
draw_image_load(sq->str, &w, &h);
if(sq->geo.w <= 0)
sq->geo.w = w;
if(sq->geo.h <= 0)
sq->geo.h = h;
if(sq->align != NoAlign)
sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
STATUS_ALIGN(sq->align);
draw_image(ctx->barwin->dr, &sq->geo);
STORE_MOUSEBIND();
break;
#endif /* HAVE_IMLIB2 */
}
}
}
/* Render current statustext of an element */
void
status_render(struct status_ctx *ctx)
{
if(!ctx->status)
return;
if(!(ctx->flags & STATUS_BLOCK_REFRESH))
barwin_refresh_color(ctx->barwin);
/* Use simple text instead sequence if no sequence found */
if(SLIST_EMPTY(&ctx->statushead))
{
int l = draw_textw(ctx->theme, ctx->status);
draw_text(ctx->barwin->dr, ctx->theme, ctx->barwin->geo.w - l,
TEXTY(ctx->theme, ctx->barwin->geo.h), ctx->barwin->fg, ctx->status);
}
else
status_apply_list(ctx);
barwin_refresh(ctx->barwin);
}
void
status_flush_list(struct status_ctx *ctx)
{
struct status_seq *sq;
struct mousebind *m;
/* Flush previous linked list of status sequences */
while(!SLIST_EMPTY(&ctx->statushead))
{
sq = SLIST_FIRST(&ctx->statushead);
SLIST_REMOVE_HEAD(&ctx->statushead, next);
while(!SLIST_EMPTY(&sq->mousebinds))
{
m = SLIST_FIRST(&sq->mousebinds);
SLIST_REMOVE_HEAD(&sq->mousebinds, snext);
free((void*)m->cmd);
free(m);
}
free(sq->str);
free(sq);
}
SLIST_INIT(&ctx->statushead);
}
void
status_copy_mousebind(struct status_ctx *ctx)
{
struct mousebind *m;
struct status_seq *sq;
if(!ctx->barwin)
return;
/* Flush barwin head of status mousebinds */
SLIST_INIT(&ctx->barwin->statusmousebinds);
SLIST_FOREACH(sq, &ctx->statushead, next)
{
SLIST_FOREACH(m, &sq->mousebinds, snext)
SLIST_INSERT_HEAD(&ctx->barwin->statusmousebinds, m, next);
}
}
/* Parse and render statustext */
void
status_manage(struct status_ctx *ctx)
{
if(!ctx->status)
return;
ctx->update = false;
status_flush_list(ctx);
status_parse(ctx);
status_render(ctx);
status_copy_mousebind(ctx);
}
void
status_flush_surface(void)
{
struct barwin *b;
while(!SLIST_EMPTY(&W->h.vbarwin))
{
b = SLIST_FIRST(&W->h.vbarwin);
SLIST_REMOVE_HEAD(&W->h.vbarwin, vnext);
barwin_remove(b);
}
}
static void
status_surface(int x, int y, int w, int h, Color bg, char *status)
{
struct barwin *b;
struct screen *s;
struct status_ctx ctx;
int d;
Window rw;
if(!status)
return;
if(x + y < 0)
XQueryPointer(W->dpy, W->root, &rw, &rw, &x, &y, &d, &d, (unsigned int *)&d);
s = screen_gb_geo(x, y);
if(x + w > s->geo.x + s->geo.w)
x -= w;
if(y + h > s->geo.y + s->geo.h)
y -= h;
b = barwin_new(W->root, x, y, w, h, 0, bg, false);
barwin_map(b);
/* Use client theme */
ctx = status_new_ctx(b, W->ctheme);
ctx.status = xstrdup(status);
SLIST_INSERT_HEAD(&W->h.vbarwin, b, vnext);
status_manage(&ctx);
status_free_ctx(&ctx);
}
void
uicb_status_surface(Uicb cmd)
{
char *p, *ccmd = xstrdup(cmd);
int s, w, h, x = -1, y = -1;
Color bg;
if(!ccmd || !(p = strchr(ccmd, ' ')))
return;
*p = '\0';
++p;
if(!(((s = sscanf(ccmd, "%d,%d,#%x", &w, &h, &bg)) == 3)
|| (s = sscanf(ccmd, "%d,%d,%d,%d,#%x", &x, &y, &w, &h, &bg)) == 5))
{
free(ccmd);
return;
}
status_surface(x, y, w, h, bg, p);
free(ccmd);
}
/* Syntax: "<infobar name> <status string>" */
void
uicb_status(Uicb cmd)
{
struct infobar *ib;
struct screen *s;
char *p;
if(!cmd || !(p = strchr(cmd, ' ')))
return;
/* Get infobar name & status */
*p = '\0';
++p;
SLIST_FOREACH(s, &W->h.screen, next)
{
SLIST_FOREACH(ib, &s->infobars, next)
if(!strcmp(cmd, ib->name))
{
free(ib->statusctx.status);
ib->statusctx.status = xstrdup(p);
ib->statusctx.update = true;
infobar_elem_screen_update(s, ElemStatus);
}
}
} }

23
src/status.h Normal file
View File

@ -0,0 +1,23 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef STATUS_H
#define STATUS_H
#include "wmfs.h"
struct status_ctx status_new_ctx(struct barwin *b, struct theme *t);
void status_free_ctx(struct status_ctx *ctx);
void status_flush_list(struct status_ctx *ctx);
void status_flush_mousebind(struct status_ctx *ctx);
void status_copy_mousebind(struct status_ctx *ctx);
void status_parse(struct status_ctx *ctx);
void status_render(struct status_ctx *ctx);
void status_manage(struct status_ctx *ctx);
void status_flush_surface(void);
void uicb_status(Uicb cmd);
void uicb_status_surface(Uicb cmd);
#endif /* STATUS_H */

View File

@ -1,620 +0,0 @@
/*
* structs.h
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef STRUCTS_H
#define STRUCTS_H
#include "wmfs.h"
#define NBUTTON 8
#define MAXTAG 36
#define NUM_OF_LAYOUT 11
#define HISTOLEN 128
/* Clients flags definition */
#define FreeFlag 0x01
#define MaxFlag 0x02
#define TileFlag 0x04
#define HideFlag 0x08
#define LMaxFlag 0x10
#define UnmapFlag 0x20
#define HintFlag 0x40
#define FSSFlag 0x80
#define AboveFlag 0x100
#define UrgentFlag 0x200
#define FLayFlag 0x400
#define DockFlag 0x800
/* Layout flags definition */
#define IntegrationFlag 0x01
#define ArrangeFlag 0x02
/* Tag flags definition */
#define TagUrgentFlag 0x01
#define ResizeHintFlag 0x02
#define RequestUpdateFlag 0x04
#define AboveFCFlag 0x08
#define CleanFactFlag 0x10
#define StayLastFlag 0x20
#define SplitFlag 0x40
#define FirstArrangeFlag 0x80
#define IgnoreEnterFlag 0x100
#define TagFlag(t) (1 << (t))
/* BarWindow flags definition */
#define MappedFlag 0x01
#define StippleFlag 0x02
#define BordFlag 0x04
/* XEMBED messages */
#define XEMBED_MAPPED (1 << 0)
#define XEMBED_EMBEDDED_NOTIFY 0
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_WINDOW_DEACTIVATE 2
#define XEMBED_REQUEST_FOCUS 3
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
#define XEMBED_FOCUS_NEXT 6
#define XEMBED_FOCUS_PREV 7
/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
#define XEMBED_MODALITY_ON 10
#define XEMBED_MODALITY_OFF 11
#define XEMBED_REGISTER_ACCELERATOR 12
#define XEMBED_UNREGISTER_ACCELERATOR 13
#define XEMBED_ACTIVATE_ACCELERATOR 14
/* Details for XEMBED_FOCUS_IN: */
#define XEMBED_FOCUS_CURRENT 0
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2
/* Typedef */
typedef const char* uicb_t;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
/* Enum */
enum { CurNormal, CurResize, CurRightResize, CurLeftResize, CurMove, CurLast };
enum { TagSel, TagTransfert, TagAdd, TagNext, TagPrev, TagActionLast };
/* Menu align */
enum { MA_Center = 0, MA_Left = 1, MA_Right = 2 };
/* Infobar position / elements */
enum { IB_Hide = 0, IB_Bottom = 1, IB_Top = 2 };
typedef enum { Right = 0, Left, Top, Bottom, Center, PositionLast } Position;
typedef enum { ElemTag, ElemLayout, ElemSelbar } IbElemType;
/* Ewmh hints list */
enum
{
net_supported,
net_wm_name,
net_client_list,
net_frame_extents,
net_number_of_desktops,
net_current_desktop,
net_desktop_names,
net_desktop_geometry,
net_active_window,
net_close_window,
net_wm_icon_name,
net_wm_window_type,
net_wm_pid,
net_showing_desktop,
net_supporting_wm_check,
net_wm_window_opacity,
net_wm_window_type_normal,
net_wm_window_type_dock,
net_wm_window_type_splash,
net_wm_window_type_dialog,
net_wm_desktop,
net_wm_icon,
net_wm_state,
net_wm_state_fullscreen,
net_wm_state_sticky,
net_wm_state_demands_attention,
net_wm_system_tray_opcode,
net_system_tray_message_data,
net_system_tray_s,
net_system_tray_visual,
net_system_tray_orientation,
xembed,
xembedinfo,
manager,
utf8_string,
/* WMFS HINTS */
wmfs_running,
wmfs_update_hints,
wmfs_current_tag,
wmfs_current_screen,
wmfs_current_layout,
wmfs_tag_list,
wmfs_mwfact,
wmfs_nmaster,
wmfs_set_screen,
wmfs_screen_count,
wmfs_function,
wmfs_cmd,
wmfs_font,
wmfs_statustext,
net_last
};
/* Geometry structure */
typedef struct
{
int x, y;
int width, height;
} Geo;
/*
* BarWindow Structure
* (titlebar, infobar..)
*/
typedef struct BarWindow
{
Window win;
Drawable dr;
struct
{
/* Border Window */
Window left, right, top, bottom;
/* Border color */
uint dark, light;
} border;
uint bg;
char *fg;
uint stipple_color;
Geo geo;
uint flags;
SLIST_ENTRY(BarWindow) next;
} BarWindow;
/* Client Structure. */
typedef struct Client
{
/* Client title */
char *title;
/* Tag num */
int tag;
int focusontag;
/* Screen */
int screen;
/* Window attribute */
Geo geo, pgeo; /* Window geo, tiling pure geo */
Geo tmp_geo, wrgeo; /* Temporary geo, without resizehint geo */
Geo frame_geo; /* Frame geo */
Geo ogeo; /* Old window attribute */
Geo split_geo, free_geo; /* Split & Free window attribute */
/* Tile size factors */
int tilefact[4];
/* For resizehint usage */
int basew, baseh, incw, inch;
int maxw, maxh, minw, minh;
int minax, maxax, minay, maxay;
/* Client composant {{{ */
Window win;
Window *button;
int button_last_x;
BarWindow *titlebar;
Window frame, resize[2];
/* Border */
Window right, left, top, bottom;
/* }}} */
struct
{
uint frame;
char *fg;
uint resizecorner;
uint bordlight, borddark;
} colors;
/* Client Information by flags */
uint flags;
/* Simply-linked list */
SLIST_ENTRY(Client) next;
} Client;
/* Keybind Structure */
typedef struct
{
uint mod;
KeySym keysym;
void (*func)(uicb_t);
uicb_t cmd;
} Key;
/* Mouse Binding Struct */
typedef struct
{
int tag;
int screen;
uint button;
void (*func)(uicb_t);
uicb_t cmd;
} MouseBinding;
/* InfoBar elements */
typedef struct InfobarElem
{
IbElemType type;
Geo geo;
STAILQ_ENTRY(InfobarElem) next;
} InfobarElem;
/* InfoBar Struct */
typedef struct
{
BarWindow *tags_board, *tags[MAXTAG];
BarWindow *layout_button;
BarWindow *bar;
STAILQ_HEAD(, InfobarElem) elemhead;
char *elemorder;
Geo geo, selbar_geo;
int screen, position;
char *statustext;
bool need_update;
} InfoBar;
/* Layout Structure */
typedef struct
{
uint flags; /* Flags */
Client *nc; /* New client needing integration */
Client ghost; /* Ghost client to arrange hole in split */
char *symbol;
char *type;
void (*func)(int screen);
} Layout;
/* Systray Structure */
typedef struct Systray
{
Window win;
Geo geo;
SLIST_ENTRY(Systray) next;
} Systray;
/* Tag Structure */
typedef struct
{
char *name;
char **clients;
int nclients;
float mwfact;
int nmaster;
uint flags;
int barpos;
int prev_barpos;
Layout layout;
uint tagad;
MouseBinding *mouse;
int nmouse;
} Tag;
/* Menu Item Struct */
typedef struct
{
char *name;
void (*func)(uicb_t);
uicb_t cmd;
bool (*check)(uicb_t);
char *submenu;
} MenuItem;
/* Menu Struct */
typedef struct
{
/* Name of the menu for call
* it in the conf (function = "menu"
* menu = "<name>").
*/
char *name;
/* Placement */
bool place_at_mouse;
int align;
int x, y;
/* Color */
struct
{
struct { uint bg; char *fg; } focus;
struct { uint bg; char *fg; } normal;
} colors;
/* Number of item */
int nitem, focus_item;
/* Item */
MenuItem *item;
} Menu;
/* Launcher struct */
typedef struct
{
char *name;
char *prompt;
char *command;
char histo[HISTOLEN][512];
uint nhisto;
int width;
} Launcher;
/* Button struct */
typedef struct
{
MouseBinding *mouse;
XSegment *linecoord;
int nlines;
int nmouse;
uint flags;
} Button;
/* Alias struct */
typedef struct
{
char *name;
char *content;
} Alias;
/* Rule struct */
typedef struct
{
char *class;
char *instance;
char *role;
char *name;
int screen;
int tag;
bool free;
bool max;
bool ignoretags;
bool follow_client;
} Rule;
/* Configuration structure */
typedef struct
{
/* Configuration file path */
char confpath[512];
/* Misc option */
char *font;
bool use_xft;
uint opacity;
bool raisefocus;
bool focus_fmouse;
bool focus_fmov;
bool focus_pclick;
bool ignore_next_client_rules;
bool tagautohide;
bool tagnamecount;
Tag default_tag;
uint pad;
char *autostart_path;
char *autostart_command;
struct
{
/*
* Only the colors will be use for text
* are 'char*' (for xprint -> XftColorAllocName)
*/
uint bar;
char *text;
char *tagselfg;
char *tagurfg;
uint tagurbg;
uint tagselbg;
uint tag_occupied_bg;
char *tag_occupied_fg;
uint tagbord;
char *layout_fg;
uint layout_bg;
float client_light_shade;
float client_dark_shade;
float bar_light_shade;
float bar_dark_shade;
} colors;
struct
{
int height;
MouseBinding *mouse;
int nmouse;
bool selbar;
char *element_order;
} bars;
struct
{
char *fg;
uint bg;
int maxlength;
MouseBinding *mouse;
int nmouse;
} selbar;
struct
{
char *background_command;
MouseBinding *mouse;
int nmouse;
} root;
struct
{
bool set_new_win_master;
bool place_at_mouse;
bool border_shadow;
bool new_client_get_mouse;
int borderheight;
char *autofree, *automax;
uint bordernormal;
uint borderfocus;
uint resizecorner_normal;
uint resizecorner_focus;
uint mod;
uint padding;
MouseBinding *mouse;
int nmouse;
uint default_open_tag;
int default_open_screen;
} client;
struct
{
int height;
char *fg_normal;
char *fg_focus;
struct
{
bool active;
struct { uint normal, focus; } colors;
} stipple;
MouseBinding *mouse;
int nmouse;
Button *button;
int nbutton;
} titlebar;
struct
{
bool bar;
bool tag;
bool layout;
} border;
struct
{
bool active;
int screen;
int spacing;
} systray;
Alias alias[256];
uint mouse_tag_action[TagActionLast];
int layout_button_width;
Layout layout[NUM_OF_LAYOUT];
Menu *menu;
Launcher *launcher;
Rule *rule;
int *ntag;
bool tag_round;
bool tag_auto_prev;
bool client_round;
bool client_auto_center;
bool client_tile_raise;
bool layout_system; /* Switch: False, Menu: True. */
bool keep_layout_geo;
bool cfactor_enable_split;
char *tag_expose_name;
char *expose_layout;
char *selected_layout_symbol;
/* Number of... */
int nkeybind;
int nlayout;
int nmenu;
int nlauncher;
int nrule;
} Conf;
typedef struct
{
int as, de, width, height;
#ifdef HAVE_XFT
XftFont *font;
#endif /* HAVE_XFT */
XFontSet fontset;
} FontStruct;
/* status.c util struct */
typedef struct
{
Geo g;
uint color;
} StatusRec;
typedef struct
{
int x, y, w, h;
uint color;
char data[512];
} StatusGraph;
typedef struct
{
int x, y;
char color[8];
char text[512];
} StatusText;
typedef struct StatusMouse
{
Geo area;
InfoBar *infobar;
uint button;
void (*func)(uicb_t);
uicb_t cmd;
SLIST_ENTRY(StatusMouse) next;
} StatusMouse;
typedef struct
{
int x, y, w, h;
char name[512];
} ImageAttr;
/* Config.c struct */
typedef struct
{
char *name;
void *func;
} func_name_list_t;
typedef struct
{
char *name;
KeySym keysym;
} key_name_list_t;
typedef struct
{
char *name;
uint button;
} name_to_uint_t;
typedef struct
{
char *cmd;
char *uicb;
} vicmd_to_uicb;
typedef struct
{
int version;
int flags;
} xembed_info;
#endif /* STRUCTS_H */

View File

@ -1,182 +1,159 @@
/* /*
* systray.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009, 2010 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h" #include "wmfs.h"
#include "systray.h"
#include "ewmh.h"
#include "infobar.h"
#define TRAY_DWIDTH (infobar[conf.systray.screen].bar->geo.height + conf.systray.spacing) #define SYSTRAY_SPACING (2)
bool void
systray_acquire(void) systray_acquire(void)
{ {
XSetWindowAttributes wattr; Window w = 0;
XSetWindowAttributes wattr =
if(!conf.systray.active || traywin)
return False;
if(XGetSelectionOwner(dpy, net_atom[net_system_tray_s]) != None)
{ {
warnx("Can't initialize system tray: owned by another process"); .event_mask = ButtonPressMask | ExposureMask,
return False; .override_redirect = true,
.background_pixmap = ParentRelative,
.background_pixel = W->systray.infobar->theme->bars.bg,
};
if(!(W->flags & WMFS_SYSTRAY) || W->systray.win)
return;
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != None)
{
warnx("Can't initialize system tray: owned by another process.");
return;
} }
/* Init traywin window */ SLIST_INIT(&W->systray.head);
wattr.event_mask = ButtonPressMask | ExposureMask;
wattr.override_redirect = True;
wattr.background_pixmap = ParentRelative;
wattr.background_pixel = conf.colors.bar;
traywin = XCreateSimpleWindow(dpy, infobar[conf.systray.screen].bar->win, -1, -1, 1, 1, 0, 0, conf.colors.bar); /* Init systray window */
w = XCreateSimpleWindow(W->dpy, W->systray.barwin->win, 0, 0,
W->systray.barwin->geo.h, W->systray.barwin->geo.h, 0, 0, 0);
XChangeWindowAttributes(dpy, traywin, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr); XChangeWindowAttributes(W->dpy, w, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr);
XSelectInput(dpy, traywin, KeyPressMask | ButtonPressMask); XSelectInput(W->dpy, w, KeyPressMask | ButtonPressMask);
XMapRaised(W->dpy, w);
XMapRaised(dpy, traywin); XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], w, CurrentTime);
XSetSelectionOwner(dpy, net_atom[net_system_tray_s], traywin, CurrentTime); if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != w)
if(XGetSelectionOwner(dpy, net_atom[net_system_tray_s]) != traywin)
{ {
warnl("System tray: can't get systray manager");
systray_freeicons(); systray_freeicons();
warnx("System tray: can't get systray manager"); return;
return False;
} }
ewmh_send_message(ROOT, ROOT, "MANAGER", CurrentTime, net_atom[net_system_tray_s], traywin, 0, 0); ewmh_send_message(W->root, W->root, "MANAGER", CurrentTime,
W->net_atom[net_system_tray_s], w, 0, 0);
XSync(dpy, False); XSync(W->dpy, false);
return True; W->systray.win = w;
} }
void void
systray_add(Window win) systray_add(Window win)
{ {
Systray *s; struct _systray *s;
if(!conf.systray.active) if(!(W->flags & WMFS_SYSTRAY))
return; return;
s = xcalloc(1, sizeof(Systray)); s = xcalloc(1, sizeof(struct _systray));
s->win = win; s->win = win;
s->geo.height = infobar[conf.systray.screen].bar->geo.height; s->geo.h = W->systray.barwin->geo.h;
s->geo.width = TRAY_DWIDTH; s->geo.w = W->systray.barwin->geo.h + SYSTRAY_SPACING;
setwinstate(s->win, WithdrawnState); ewmh_set_wm_state(s->win, NormalState);
XSelectInput(dpy, s->win, StructureNotifyMask | PropertyChangeMask| EnterWindowMask | FocusChangeMask); XSelectInput(W->dpy, s->win, StructureNotifyMask | PropertyChangeMask| EnterWindowMask | FocusChangeMask);
XReparentWindow(dpy, s->win, traywin, 0, 0); XReparentWindow(W->dpy, s->win, W->systray.win, 0, 0);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, traywin, 0); ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_EMBEDDED_NOTIFY, 0, W->systray.win, 0);
/* Attach */ SLIST_INSERT_HEAD(&W->systray.head, s, next);
SLIST_INSERT_HEAD(&trayicons, s, next);
return; W->systray.redim = true;
} }
void void
systray_del(Systray *s) systray_del(struct _systray *s)
{ {
if(!conf.systray.active) if(!(W->flags & WMFS_SYSTRAY))
return; return;
SLIST_REMOVE(&trayicons, s, Systray, next); SLIST_REMOVE(&W->systray.head, s, _systray, next);
free(s); free(s);
return; W->systray.redim = true;
} }
void void
systray_state(Systray *s) systray_state(struct _systray *s)
{ {
long flags; long flags;
int code = 0; int code = 0;
if(!(flags = ewmh_get_xembed_state(s->win)) || !conf.systray.active) if(!(W->flags & WMFS_SYSTRAY) || !(flags = ewmh_get_xembed_state(s->win)))
return; return;
if(flags & XEMBED_MAPPED) if(flags & XEMBED_MAPPED)
{ {
code = XEMBED_WINDOW_ACTIVATE; code = XEMBED_WINDOW_ACTIVATE;
XMapRaised(dpy, s->win); XMapRaised(W->dpy, s->win);
setwinstate(s->win, NormalState); ewmh_set_wm_state(s->win, NormalState);
} }
else else
{ {
code = XEMBED_WINDOW_DEACTIVATE; code = XEMBED_WINDOW_DEACTIVATE;
XUnmapWindow(dpy, s->win); XUnmapWindow(W->dpy, s->win);
setwinstate(s->win, WithdrawnState); ewmh_set_wm_state(s->win, WithdrawnState);
} }
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, code, 0, 0, 0); ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, code, 0, 0, 0);
return;
} }
void void
systray_freeicons(void) systray_freeicons(void)
{ {
Systray *i; struct _systray *i;
if(!conf.systray.active) if(!(W->flags & WMFS_SYSTRAY))
return; return;
while(!SLIST_EMPTY(&trayicons)) while(!SLIST_EMPTY(&W->systray.head))
{ {
i = SLIST_FIRST(&trayicons); i = SLIST_FIRST(&W->systray.head);
SLIST_REMOVE_HEAD(&trayicons, next); SLIST_REMOVE_HEAD(&W->systray.head, next);
XUnmapWindow(dpy, i->win); XUnmapWindow(W->dpy, i->win);
XReparentWindow(dpy, i->win, ROOT, 0, 0); XReparentWindow(W->dpy, i->win, W->root, 0, 0);
free(i); free(i);
} }
XSetSelectionOwner(dpy, net_atom[net_system_tray_s], None, CurrentTime); XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], None, CurrentTime);
XDestroyWindow(dpy, traywin); W->systray.barwin->geo.w = 0;
infobar_elem_reinit(W->systray.infobar);
XSync(dpy, 0); XSync(W->dpy, false);
return;
} }
Systray* struct _systray*
systray_find(Window win) systray_find(Window win)
{ {
Systray *i; struct _systray *i;
if(!conf.systray.active) if(!(W->flags & WMFS_SYSTRAY))
return NULL; return NULL;
SLIST_FOREACH(i, &trayicons, next) SLIST_FOREACH(i, &W->systray.head, next)
if(i->win == win) if(i->win == win)
return i; return i;
@ -186,14 +163,11 @@ systray_find(Window win)
int int
systray_get_width(void) systray_get_width(void)
{ {
int w = 0; int w = 1;
Systray *i; struct _systray *i;
if(!conf.systray.active) SLIST_FOREACH(i, &W->systray.head, next)
return 0; w += i->geo.w + SYSTRAY_SPACING;
SLIST_FOREACH(i, &trayicons, next)
w += i->geo.width + conf.systray.spacing + 1;
return w; return w;
} }
@ -201,29 +175,26 @@ systray_get_width(void)
void void
systray_update(void) systray_update(void)
{ {
Systray *i;
int x = 1; int x = 1;
struct _systray *i;
if(!conf.systray.active) if(!(W->flags & WMFS_SYSTRAY))
return; return;
if(!SLIST_FIRST(&trayicons)) if(W->systray.redim)
{ {
XMoveResizeWindow(dpy, traywin, infobar[conf.systray.screen].bar->geo.width - 1, 0, 1, 1); W->systray.redim = false;
return; infobar_elem_reinit(W->systray.infobar);
} }
SLIST_FOREACH(i, &trayicons, next) SLIST_FOREACH(i, &W->systray.head, next)
{ {
XMapWindow(dpy, i->win); XMapWindow(W->dpy, i->win);
XMoveResizeWindow(W->dpy, i->win, (i->geo.x = x), 0, i->geo.w, i->geo.h);
XMoveResizeWindow(dpy, i->win, (i->geo.x = x), 0, i->geo.width, i->geo.height); x += i->geo.w + SYSTRAY_SPACING;
x += i->geo.width + conf.systray.spacing;
} }
XMoveResizeWindow(dpy, traywin, infobar[conf.systray.screen].bar->geo.width - x,
0, x, infobar[conf.systray.screen].bar->geo.height);
return;
} }

20
src/systray.h Normal file
View File

@ -0,0 +1,20 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef SYSTRAY_H
#define SYSTRAY_H
#include "wmfs.h"
void systray_acquire(void);
void systray_add(Window win);
void systray_del(struct _systray *s);
void systray_state(struct _systray *s);
void systray_freeicons(void);
struct _systray *systray_find(Window win);
int systray_get_width(void);
void systray_update(void);
#endif /* SYSTRAY_H */

927
src/tag.c

File diff suppressed because it is too large Load Diff

39
src/tag.h Normal file
View File

@ -0,0 +1,39 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef TAG_H
#define TAG_H
#include "wmfs.h"
static inline struct tag*
tag_gb_id(struct screen *s, int id)
{
struct tag *t;
TAILQ_FOREACH(t, &s->tags, next)
if(t->id == id)
return t;
return TAILQ_FIRST(&s->tags);
}
struct tag *tag_new(struct screen *s, char *name);
void tag_screen(struct screen *s, struct tag *t);
void tag_client(struct tag *t, struct client *c);
void tag_free(struct screen *s);
void uicb_tag_set(Uicb cmd);
void uicb_tag_set_with_name(Uicb cmd);
void uicb_tag_next(Uicb cmd);
void uicb_tag_prev(Uicb cmd);
void uicb_tag_client(Uicb cmd);
void uicb_tag_client_and_set(Uicb cmd);
void uicb_tag_move_client_next(Uicb cmd);
void uicb_tag_move_client_prev(Uicb cmd);
void uicb_tag_click(Uicb cmd);
void uicb_tag_new(Uicb cmd);
void uicb_tag_del(Uicb cmd);
#endif /* TAG_H */

View File

@ -1,54 +1,31 @@
/* /*
* util.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _GNU_SOURCE #define _GNU_SOURCE /* vasprintf() */
#include "wmfs.h"
#include <stdint.h>
#include <string.h>
#include "util.h"
/** malloc with error support and size_t overflow protection /** malloc with error support and size_t overflow protection
* \param nmemb number of objects * \param nmemb number of objects
* \param size size of single object * \param size size of single object
* \return non null void pointer * \return non null void pointer
*/ */
void * void*
xmalloc(size_t nmemb, size_t size) xmalloc(size_t nmemb, size_t size)
{ {
void *ret; void *ret;
if (SIZE_MAX / nmemb < size) if(SIZE_MAX / nmemb < size)
err(EXIT_FAILURE, "xmalloc(%zu, %zu), " errl(EXIT_FAILURE, "xmalloc(%zu, %zu), "
"size_t overflow detected", nmemb, size); "size_t overflow detected", nmemb, size);
if ((ret = malloc(nmemb * size)) == NULL) if((ret = malloc(nmemb * size)) == NULL)
err(EXIT_FAILURE, "malloc(%zu)", nmemb * size); errl(EXIT_FAILURE, "malloc(%zu)", nmemb * size);
return ret; return ret;
} }
@ -58,13 +35,13 @@ xmalloc(size_t nmemb, size_t size)
* \param size size of single object * \param size size of single object
* \return non null void pointer * \return non null void pointer
*/ */
void * void*
xcalloc(size_t nmemb, size_t size) xcalloc(size_t nmemb, size_t size)
{ {
void *ret; void *ret;
if ((ret = calloc(nmemb, size)) == NULL) if((ret = calloc(nmemb, size)) == NULL)
err(EXIT_FAILURE, "calloc(%zu * %zu)", nmemb, size); errl(EXIT_FAILURE, "calloc(%zu * %zu)", nmemb, size);
return ret; return ret;
} }
@ -80,30 +57,16 @@ xrealloc(void *ptr, size_t nmemb, size_t size)
{ {
void *ret; void *ret;
if (SIZE_MAX / nmemb < size) if(SIZE_MAX / nmemb < size)
err(EXIT_FAILURE, "xrealloc(%p, %zu, %zu), " err(EXIT_FAILURE, "xrealloc(%p, %zu, %zu), "
"size_t overflow detected", ptr, nmemb, size); "size_t overflow detected", ptr, nmemb, size);
if ((ret = realloc(ptr, nmemb * size)) == NULL) if((ret = realloc(ptr, nmemb * size)) == NULL)
err(EXIT_FAILURE, "realloc(%p, %zu)", ptr, nmemb * size); err(EXIT_FAILURE, "realloc(%p, %zu)", ptr, nmemb * size);
return ret; return ret;
} }
/** strdup with error support
* \param str char pointer
* \retun non null void pointer
*/
char *
xstrdup(const char *str)
{
char *ret;
if (str == NULL || (ret = strdup(str)) == NULL)
err(EXIT_FAILURE, "strdup(%s)", str);
return ret;
}
/** asprintf wrapper /** asprintf wrapper
* \param strp target string * \param strp target string
@ -121,98 +84,27 @@ xasprintf(char **strp, const char *fmt, ...)
va_end(args); va_end(args);
if (ret == -1) if (ret == -1)
err(EXIT_FAILURE, "asprintf(%s)", fmt); errl(EXIT_FAILURE, "asprintf(%s)", fmt);
return ret; return ret;
} }
/** strdup with error support
/** Get a color with a string * \param str char pointer
* \param color Color string * \retun non null void pointer
* \return Color pixel */
*/ char *
long xstrdup(const char *str)
getcolor(char *color)
{ {
XColor xcolor; char *ret = NULL;
if(!XAllocNamedColor(dpy, DefaultColormap(dpy, SCREEN), color, &xcolor, &xcolor)) if(str == NULL || (ret = strdup(str)) == NULL)
warnx("Error: cannot allocate color \"%s\".", color); warnxl("strdup(%s)", str);
return xcolor.pixel; return ret;
} }
/** Set the window WM State /** Execute a system command
* \param win Window target
* \param state WM State
*/
void
setwinstate(Window win, long state)
{
long data[] = {state, None};
XChangeProperty(dpy, win, ATOM("WM_STATE"), ATOM("WM_STATE"), 32,
PropModeReplace, (uchar *)data, 2);
return;
}
/* The following function are for configuration
usage. {{{
*/
void*
name_to_func(char *name, const func_name_list_t *l)
{
int i;
if(name)
for(i = 0; l[i].name; ++i)
if(!strcmp(name, l[i].name))
return l[i].func;
return NULL;
}
ulong
char_to_modkey(char *name, key_name_list_t key_l[])
{
int i;
if(name)
for(i = 0; key_l[i].name; ++i)
if(!strcmp(name, key_l[i].name))
return key_l[i].keysym;
return NoSymbol;
}
uint
char_to_button(char *name, name_to_uint_t blist[])
{
int i;
if(name)
for(i = 0; blist[i].name; ++i)
if(!strcmp(name, blist[i].name))
return blist[i].button;
return 0;
}
Layout
layout_name_to_struct(Layout lt[], char *name, int n, const func_name_list_t llist[])
{
int i;
for(i = 0; i < n; ++i)
if(lt[i].func == name_to_func(name, llist))
return lt[i];
return lt[0];
}
/* }}} */
/** Execute a sh command
* \param cmd Command * \param cmd Command
* \return child pid * \return child pid
*/ */
@ -231,74 +123,45 @@ spawn(const char *format, ...)
if (len >= sizeof(cmd)) if (len >= sizeof(cmd))
{ {
warnx("command too long (> 512 bytes)"); warnxl("command too long (> 512 bytes)");
return -1; return -1;
} }
if(!(sh = getenv("SHELL"))) if(!(sh = getenv("SHELL")) || sh[0] != '/')
sh = "/bin/sh"; sh = "/bin/sh";
if((pid = fork()) == 0) if(!(pid = fork()))
{ {
if(dpy)
close(ConnectionNumber(dpy));
setsid(); setsid();
if (execl(sh, sh, "-c", cmd, (char*)NULL) == -1) if (execl(sh, sh, "-c", cmd, (char*)NULL) == -1)
warn("execl(sh -c %s)", cmd); warnl("execl(sh -c %s)", cmd);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
else if (pid == -1) else if (pid == -1)
warn("fork"); warnl("fork");
return pid; return pid;
} }
/** Swap two pointer. int
*\param x First pointer parse_args(char *str, char delim, char end, int narg, char *args[])
*\param y Second pointer
*/
void
swap_ptr(void **x, void **y)
{ {
void *t = *x; int i = 0;
*x = *y; for(args[0] = str; *str && (*str != end || *(str - 1) == '\\') && i < narg; ++str)
*y = t; if(*str == delim && i < narg - 1)
{
*str = '\0';
args[++i] = ++str;
}
return; *str = '\0';
return i;
} }
/** Execute a sh command
* \param cmd Command (uicb_t type)
*/
void void
uicb_spawn(uicb_t cmd) uicb_spawn(Uicb cmd)
{ {
spawn("%s", cmd); spawn("%s", cmd);
return;
} }
/* To use ~/ shortcut.. */
char*
patht(char *path)
{
static char ret[512];
if(!path)
return NULL;
strncpy(ret, path, sizeof(ret));
ret[sizeof(ret) - 1] = 0;
if(strstr(path, "~/"))
snprintf(ret, sizeof(ret), "%s/%s", getenv("HOME"), path + 2);
return ret;
}
int
qsort_string_compare (const void * a, const void * b)
{
return (strcmp(*(char **)a, *(char **)b));
}

99
src/util.h Normal file
View File

@ -0,0 +1,99 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef UTIL_H
#define UTIL_H
#include "wmfs.h"
#include <string.h>
/* Todo FREE_LIST(type, head, function_remove) */
#define FREE_LIST(type, head) \
do { \
struct type *Z; \
while(!SLIST_EMPTY(&head)) { \
Z = SLIST_FIRST(&head); \
SLIST_REMOVE_HEAD(&head, next); \
free(Z); /* function_remove(t)*/ \
} \
} while(/* CONSTCOND */ 0);
/* Insert at the end with SLIST */
#define SLIST_INSERT_TAIL(head, elem, field, prev) \
if(!prev) \
SLIST_INSERT_HEAD(head, elem, field); \
else \
SLIST_INSERT_AFTER(prev, elem, field);
/* t is Map or Unmap */
#define WIN_STATE(w, t) do { \
X##t##Subwindows(W->dpy, w); \
X##t##Window(W->dpy, w); \
} while( /* CONSTCOND */ 0);
#define ATOM(a) XInternAtom(W->dpy, (a), False)
#define LEN(x) (sizeof(x) / sizeof(*x))
#define FLAGINT(i) (1 << i)
#define FLAGAPPLY(f, b, m) (f |= (b ? m : 0))
#define ATOI(s) strtol(s, NULL, 10)
#define ABS(j) (j < 0 ? -j : j)
#define INAREA(i, j, a) ((i) >= (a).x && (i) <= (a).x + (a).w && (j) >= (a).y && (j) <= (a).y + (a).h)
#define GEOCMP(g1, g2) ((g1).x == (g2).x && (g1).y == (g2).y && (g1).w == (g2).w && (g1).h == (g2).h)
/*
* "#RRGGBB" -> 0xRRGGBB
*/
static inline Color
color_atoh(const char *col)
{
XColor xcolor;
if(!XAllocNamedColor(W->dpy, DefaultColormap(W->dpy, W->xscreen), col, &xcolor, &xcolor))
warnl("Error: cannot allocate color \"%s\".", col);
return xcolor.pixel;
}
static inline void
swap_ptr(void **x, void **y)
{
void *t = *x;
*x = *y;
*y = t;
}
static inline void
swap_int(int *x, int *y)
{
*y = *x ^ *y;
*x = *y ^ *x;
*y = *x ^ *y;
}
static inline enum position
str_to_position(char *str)
{
enum position i;
static const char index[PositionLast][8] = { "right", "left", "top", "bottom", "center" };
for(i = 0; i < PositionLast; ++i)
if(!strcmp(index[i], str))
return i;
return Right;
}
void *xmalloc(size_t nmemb, size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t nmemb, size_t size);
int xasprintf(char **strp, const char *fmt, ...);
char *xstrdup(const char *str);
pid_t spawn(const char *format, ...);
int parse_args(char *str, char delim, char end, int narg, char *args[]);
void uicb_spawn(Uicb cmd);
#endif /* UTIL_H */

View File

@ -1,51 +1,41 @@
/* /*
* wmfs.c * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without #include <string.h>
* modification, are permitted provided that the following conditions are #include <getopt.h>
* met: #include <signal.h>
* #include <sys/wait.h>
* * Redistributions of source code must retain the above copyright #include <X11/keysym.h>
* notice, this list of conditions and the following disclaimer. #include <X11/cursorfont.h>
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer #ifdef HAVE_IMLIB2
* in the documentation and/or other materials provided with the #include <Imlib2.h>
* distribution. #endif /* HAVE_IMLIB2 */
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "wmfs.h" #include "wmfs.h"
#include "event.h"
static volatile bool exiting = False, sig_chld = False; #include "ewmh.h"
#include "screen.h"
#include "infobar.h"
#include "util.h"
#include "config.h"
#include "client.h"
#include "layout.h"
#include "systray.h"
int int
errorhandler(Display *d, XErrorEvent *event) wmfs_error_handler(Display *d, XErrorEvent *event)
{ {
char mess[256]; char mess[256];
/* Check if there is another WM running */ /* Check if there is another WM running */
if(BadAccess == event->error_code if(event->error_code == BadAccess
&& ROOT == event->resourceid) && W->root == event->resourceid)
errx(EXIT_FAILURE, "Another Window Manager is already running."); errl(EXIT_FAILURE, "Another Window Manager is already running.");
/* Ignore focus change error for unmapped client */ /* Ignore focus change error for unmapped client
/* Too lazy to add Xproto.h so:
* 42 = X_SetInputFocus * 42 = X_SetInputFocus
* 28 = X_GrabButton * 28 = X_GrabButton
*/ */
@ -56,8 +46,9 @@ errorhandler(Display *d, XErrorEvent *event)
return 0; return 0;
XGetErrorText(d, event->error_code, mess, 128); if(XGetErrorText(d, event->error_code, mess, 128))
warnx("%s(%d) opcodes %d/%d\n resource #%lx\n", mess, warnxl("%s(%d) opcodes %d/%d\n resource #%lx\n",
mess,
event->error_code, event->error_code,
event->request_code, event->request_code,
event->minor_code, event->minor_code,
@ -67,307 +58,488 @@ errorhandler(Display *d, XErrorEvent *event)
} }
int int
errorhandlerdummy(Display *d, XErrorEvent *event) wmfs_error_handler_dummy(Display *d, XErrorEvent *event)
{ {
(void)d; (void)d;
(void)event; (void)event;
return 0; return 0;
} }
/** Clean wmfs before the exit
*/
void void
quit(void) wmfs_numlockmask(void)
{ {
size_t i, len; int i, j;
XModifierKeymap *mm = XGetModifierMapping(W->dpy);
/* Set the silent error handler */ for(i = 0; i < 8; i++)
XSetErrorHandler(errorhandlerdummy); for(j = 0; j < mm->max_keypermod; ++j)
if(mm->modifiermap[i * mm->max_keypermod + j]
== XKeysymToKeycode(W->dpy, XK_Num_Lock))
W->numlockmask = (1 << i);
/* Unmanage all clients */ XFreeModifiermap(mm);
while(!SLIST_EMPTY(&clients)) }
{
Client *c = SLIST_FIRST(&clients); void
client_unhide(c); wmfs_init_font(char *font, struct theme *t)
XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y); {
free(c); XFontStruct **xfs = NULL;
SLIST_REMOVE_HEAD(&clients, next); char **misschar, **names, *defstring;
} int d;
free(tags); if(!(t->font.fontset = XCreateFontSet(W->dpy, font, &misschar, &d, &defstring)))
free(seltag); {
warnxl("Can't load font '%s'", font);
systray_freeicons(); t->font.fontset = XCreateFontSet(W->dpy, "fixed", &misschar, &d, &defstring);
}
#ifdef HAVE_XFT
if(conf.use_xft) XExtentsOfFontSet(t->font.fontset);
XftFontClose(dpy, font.font); XFontsOfFontSet(t->font.fontset, &xfs, &names);
else
#endif /* HAVE_XFT */ t->font.as = xfs[0]->max_bounds.ascent;
XFreeFontSet(dpy, font.fontset); t->font.de = xfs[0]->max_bounds.descent;
t->font.width = xfs[0]->max_bounds.width;
for(i = 0; i < CurLast; ++i)
XFreeCursor(dpy, cursor[i]); t->font.height = t->font.as + t->font.de;
XFreeGC(dpy, gc_stipple);
infobar_destroy(); if(misschar)
XFreeStringList(misschar);
/* BarWindows */
while(!SLIST_EMPTY(&bwhead))
SLIST_REMOVE_HEAD(&bwhead, next);
free(sgeo);
free(spgeo);
free(infobar);
free(keys);
free(net_atom);
/* Clean conf alloced thing */
free(menulayout.item);
if(conf.menu)
{
len = LEN(conf.menu);
for(i = 0; i < len; ++i)
free(conf.menu[i].item);
free(conf.menu);
}
free(conf.launcher);
free(conf.rule);
free(conf.bars.mouse);
free(conf.selbar.mouse);
free(conf.titlebar.button);
free(conf.client.mouse);
free(conf.root.mouse);
free_conf();
XSync(dpy, False);
XCloseDisplay(dpy);
free(event_handle);
return;
} }
/** WMFS main loop.
*/
static void static void
mainloop(void) wmfs_xinit(void)
{ {
XEvent ev; XGCValues xgc =
{
.function = GXinvert,
.subwindow_mode = IncludeInferiors,
.line_width = 1
};
while(!exiting && !XNextEvent(dpy, &ev)) { XSetWindowAttributes at =
if (sig_chld) { {
while(waitpid(-1, NULL, WNOHANG) > 0); .event_mask = (KeyMask | ButtonMask | MouseMask
sig_chld = False; | PropertyChangeMask | SubstructureRedirectMask
} | SubstructureNotifyMask | StructureNotifyMask),
HANDLE_EVENT(&ev); .cursor = XCreateFontCursor(W->dpy, XC_left_ptr)
} };
return; /*
} * X Error handler
/** Set the exiting variable to True
* for stop the main loop
* \param cmd unused uicb_t
*/ */
void XSetErrorHandler(wmfs_error_handler);
uicb_quit(uicb_t cmd)
{
(void)cmd;
exiting = True;
return; /*
* X var
*/
W->xscreen = DefaultScreen(W->dpy);
W->xdepth = DefaultDepth(W->dpy, W->xscreen);
W->gc = DefaultGC(W->dpy, W->xscreen);
W->xmaxw = DisplayWidth(W->dpy, W->xscreen);
W->xmaxh = DisplayHeight(W->dpy, W->xscreen);
/*
* Keys
*/
wmfs_numlockmask();
/*
* Root window/cursor
*/
W->root = RootWindow(W->dpy, W->xscreen);
XChangeWindowAttributes(W->dpy, W->root, CWEventMask | CWCursor, &at);
W->rgc = XCreateGC(W->dpy, W->root, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
/*
* Locale (font encode)
*/
setlocale(LC_CTYPE, "");
/*
* Barwin linked list
*/
SLIST_INIT(&W->h.barwin);
SLIST_INIT(&W->h.vbarwin);
/*
* Optional dep init
*/
#ifdef HAVE_IMLIB2
imlib_context_set_display(W->dpy);
imlib_context_set_visual(DefaultVisual(W->dpy, W->xscreen));
imlib_context_set_colormap(DefaultColormap(W->dpy, W->xscreen));
#endif /* HAVE_IMLIB2 */
W->flags |= WMFS_RUNNING;
} }
/** Scan if there are windows on X void
* for manage it wmfs_grab_keys(void)
{
KeyCode c;
struct keybind *k;
wmfs_numlockmask();
XUngrabKey(W->dpy, AnyKey, AnyModifier, W->root);
SLIST_FOREACH(k, &W->h.keybind, next)
if((c = XKeysymToKeycode(W->dpy, k->keysym)))
{
XGrabKey(W->dpy, c, k->mod, W->root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(W->dpy, c, k->mod | LockMask, W->root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(W->dpy, c, k->mod | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(W->dpy, c, k->mod | LockMask | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
}
}
/** Scan xprops of previous session to set it back
* Check if there are windows on X (previous sessions windows)
*/ */
static void static void
scan(void) wmfs_scan(void)
{ {
uint n; struct geo g;
struct client *c, *cc, *fc;
struct screen *s;
int i, n, rf, nscreen = 0;
int tag = -1, screen = -1, flags = -1;
unsigned long ir, il;
long *ret = NULL, *tret = NULL;
bool getg = false;
XWindowAttributes wa; XWindowAttributes wa;
Window usl, usl2, *w = NULL; Window usl, usl2, *w = NULL, tm, focus;
Atom rt; Atom rt;
int s, rf, tag = -1, screen = -1, flags = -1, i;
ulong ir, il;
uchar *ret;
Client *c;
s = screen_count(); SLIST_INIT(&W->h.client);
if(XQueryTree(dpy, ROOT, &usl, &usl2, &w, &n)) W->flags |= WMFS_SCAN;
/* Get previous selected tag to apply it at the end */
if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&tret)
== Success && tret)
{
nscreen = (int)ir;
}
/* Previous focused client before reload */
if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_focus], 0, 32,
False, XA_WINDOW, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
focus = *ret;
XFree(ret);
}
if(XQueryTree(W->dpy, W->root, &usl, &usl2, &w, (unsigned int*)&n))
for(i = n - 1; i != -1; --i) for(i = n - 1; i != -1; --i)
{ {
XGetWindowAttributes(dpy, w[i], &wa); XGetWindowAttributes(W->dpy, w[i], &wa);
if(!wa.override_redirect && wa.map_state == IsViewable) if(!wa.override_redirect && wa.map_state == IsViewable)
{ {
if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_TAG"), 0, 32, if(ewmh_get_xembed_state(w[i]))
False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret) {
systray_add(w[i]);
continue;
}
if(ewmh_manage_window_type_desktop(w[i]))
continue;
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TAG"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{ {
tag = *ret; tag = *ret;
XFree(ret); XFree(ret);
} }
if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_SCREEN"), 0, 32, if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_SCREEN"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret) False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{ {
screen = *ret; screen = *ret;
XFree(ret); XFree(ret);
} }
if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_FLAGS"), 0, 32, if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_FLAGS"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret) False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{ {
flags = *ret; flags = *ret;
flags &= ~(CLIENT_TABBED | CLIENT_REMOVEALL);
XFree(ret); XFree(ret);
} }
c = client_manage(w[i], &wa, False); if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_GEO"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
g.x = ret[0];
g.y = ret[1];
g.w = ret[2];
g.h = ret[3];
getg = true;
XFree(ret);
}
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TABMASTER"), 0, 32,
False, XA_WINDOW, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
tm = *ret;
XFree(ret);
}
c = client_new(w[i], &wa, true);
if(tm != c->win)
c->tmp = tm;
tm = 0;
if(tag != -1 && tag != MAXTAG + 1)
c->tag = tag;
if(screen != -1 && screen <= s - 1)
c->screen = screen;
if(flags != -1) if(flags != -1)
c->flags = flags; c->flags |= flags;
client_update_attributes(c); if(tag != -1 && screen != -1)
}
}
/* Set update layout request */
SLIST_FOREACH(c, &clients, next)
{ {
if(c->tag > conf.ntag[c->screen]) c->screen = screen_gb_id(screen);
c->tag = conf.ntag[c->screen];
tags[c->screen][c->tag].flags |= RequestUpdateFlag; if(getg)
c->flags |= CLIENT_IGNORE_LAYOUT;
tag_client(tag_gb_id(c->screen, tag), c);
if(getg && tag <= TAILQ_LAST(&c->screen->tags, tsub)->id - 1)
client_moveresize(c, &g);
/* In a removed tag */
else
{
c->geo = g;
layout_client(c);
} }
for(i = 0; i < s; ++i) client_get_name(c);
arrange(i, True); }
}
XFree(w);
return;
}
/** Reload the WMFS with the new configuration
* file changement *TESTING*
*/
void
uicb_reload(uicb_t cmd)
{
(void)cmd;
quit();
for(; argv_global[0] && argv_global[0] == ' '; ++argv_global);
/* add -C to always load the same config file */
execvp(argv_global, all_argv);
return;
}
/** Check if wmfs is running (for functions that will be
execute when wmfs will be already running).
\return False if wmfs is not running
*/
bool
check_wmfs_running(void)
{
Atom rt;
int rf;
ulong ir, il;
uchar *ret;
XGetWindowProperty(dpy, ROOT, ATOM("_WMFS_RUNNING"), 0L, 4096,
False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret);
if(!ret)
{
XFree(ret);
warnx("Wmfs is not running. (_WMFS_RUNNING not present)");
return False;
} }
XFree(ret); if(!nscreen)
return True;
}
/** Execute an uicb function
*\param func Function name
*\param cmd Function's command
*\return 0 if there is an error
*/
void
exec_uicb_function(char *func, char *cmd)
{
/* Check if wmfs is running (this function is executed when wmfs
is already running normally...) */
if(!check_wmfs_running())
return;
XChangeProperty(dpy, ROOT, ATOM("_WMFS_FUNCTION"), ATOM("UTF8_STRING"),
8, PropModeReplace, (uchar*)func, strlen(func));
if(cmd == NULL)
cmd = "";
XChangeProperty(dpy, ROOT, ATOM("_WMFS_CMD"), ATOM("UTF8_STRING"),
8, PropModeReplace, (uchar*)cmd, strlen(cmd));
ewmh_send_message(ROOT, ROOT, "_WMFS_FUNCTION", 0, 0, 0, 0, True);
return;
}
/** Set statustext
*\param str Statustext string
*/
static void
set_statustext(int s, char *str)
{
int i;
char atom_name[64];
if(!str)
return;
if(s == -1)
{ {
for(i = 0; i < screen_count(); ++i) SLIST_FOREACH(s, &W->h.screen, next)
{ if(!TAILQ_EMPTY(&s->tags))
sprintf(atom_name, "_WMFS_STATUSTEXT_%d", i); tag_screen(s, TAILQ_FIRST(&s->tags));
XChangeProperty(dpy, ROOT, ATOM(atom_name), ATOM("UTF8_STRING"),
8, PropModeReplace, (uchar*)str, strlen(str));
ewmh_send_message(ROOT, ROOT, atom_name, 0, 0, 0, 0, True);
}
} }
else else
{ {
sprintf(atom_name, "_WMFS_STATUSTEXT_%d", s); /* Set back selected tag */
for(i = 0; i < nscreen; ++i)
XChangeProperty(dpy, ROOT, ATOM(atom_name), ATOM("UTF8_STRING"), {
8, PropModeReplace, (uchar*)str, strlen(str)); s = screen_gb_id(i);
tag_screen(s, tag_gb_id(s, tret[i]));
ewmh_send_message(ROOT, ROOT, atom_name, 0, 0, 0, 0, True); }
} }
return; /* Re-adjust tabbed clients */
SLIST_FOREACH(c, &W->h.client, next)
if((cc = client_gb_win(c->tmp)) && cc != c)
_client_tab(c, cc);
if((fc = client_gb_win(focus)) && fc != W->client)
client_focus(fc);
SLIST_FOREACH(c, &W->h.client, next)
if(c->flags & CLIENT_TILED)
layout_fix_hole(c);
W->flags &= ~WMFS_SCAN;
if(tret)
XFree(tret);
XFree(w);
XSync(W->dpy, false);
} }
/** Signal handle function static inline void
wmfs_sigchld(void)
{
if(W->flags & WMFS_SIGCHLD)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
W->flags ^= WMFS_SIGCHLD;
}
}
static void
wmfs_loop(void)
{
XEvent ev;
while((W->flags & WMFS_RUNNING) && !XNextEvent(W->dpy, &ev))
{
/* Manage SIGCHLD event here, X is not safe with it */
wmfs_sigchld();
EVENT_HANDLE(&ev);
}
}
static inline void
wmfs_init(void)
{
log_init();
wmfs_xinit();
ewmh_init();
screen_init();
event_init();
config_init();
}
void
wmfs_quit(void)
{
struct keybind *k;
struct rule *r;
struct theme *t;
struct client *c;
struct mousebind *m;
struct launcher *l;
ewmh_update_wmfs_props();
XFreeGC(W->dpy, W->rgc);
while(!SLIST_EMPTY(&W->h.client))
{
c = SLIST_FIRST(&W->h.client);
client_update_props(c, CPROP_LOC | CPROP_FLAG | CPROP_GEO);
c->flags |= (CLIENT_IGNORE_LAYOUT | CLIENT_REMOVEALL);
XMapWindow(W->dpy, c->win);
client_remove(c);
}
/* Will free:
*
* Screens -> tags
* -> Infobars -> Elements
*/
screen_free();
/* Conf stuffs */
while(!SLIST_EMPTY(&W->h.theme))
{
t = SLIST_FIRST(&W->h.theme);
SLIST_REMOVE_HEAD(&W->h.theme, next);
XFreeFontSet(W->dpy, t->font.fontset);
status_free_ctx(&t->tags_n_sl);
status_free_ctx(&t->tags_s_sl);
status_free_ctx(&t->tags_o_sl);
status_free_ctx(&t->tags_u_sl);
status_free_ctx(&t->client_n_sl);
status_free_ctx(&t->client_s_sl);
free(t);
}
while(!SLIST_EMPTY(&W->h.keybind))
{
k = SLIST_FIRST(&W->h.keybind);
SLIST_REMOVE_HEAD(&W->h.keybind, next);
free((void*)k->cmd);
free(k);
}
while(!SLIST_EMPTY(&W->h.mousebind))
{
m = SLIST_FIRST(&W->h.mousebind);
SLIST_REMOVE_HEAD(&W->h.mousebind, globnext);
free((void*)m->cmd);
free(m);
}
while(!SLIST_EMPTY(&W->h.launcher))
{
l = SLIST_FIRST(&W->h.launcher);
SLIST_REMOVE_HEAD(&W->h.launcher, next);
free((void*)l->name);
free((void*)l->prompt);
free((void*)l->command);
free(l);
}
while(!SLIST_EMPTY(&W->h.rule))
{
r = SLIST_FIRST(&W->h.rule);
SLIST_REMOVE_HEAD(&W->h.rule, next);
free(r->class);
free(r->instance);
free(r->role);
free(r->name);
free(r);
}
/* close log */
if(W->log)
fclose(W->log), W->log = NULL;
W->flags &= ~WMFS_RUNNING;
}
/** Reload WMFS binary
*/ */
void
uicb_reload(Uicb cmd)
{
(void)cmd;
W->flags &= ~WMFS_RUNNING;
W->flags |= WMFS_RELOAD;
}
void
uicb_quit(Uicb cmd)
{
(void)cmd;
W->flags &= ~WMFS_RUNNING;
}
static void
exec_uicb_function(Display *dpy, Window root, char *func, char *cmd)
{
Atom utf8s = XInternAtom(dpy, "UTF8_STRING", false);
XClientMessageEvent e = {
.type = ClientMessage,
.message_type = XInternAtom(dpy, "_WMFS_FUNCTION", false),
.window = root,
.format = 32,
.data.l[4] = true
};
XChangeProperty(dpy,root, XInternAtom(dpy, "_WMFS_FUNCTION", false), utf8s,
8, PropModeReplace, (unsigned char*)func, strlen(func));
if(!cmd)
cmd = "";
XChangeProperty(dpy, root, XInternAtom(dpy, "_WMFS_CMD", false), utf8s,
8, PropModeReplace, (unsigned char*)cmd, strlen(cmd));
XSendEvent(dpy, root, false, StructureNotifyMask, (XEvent*)&e);
XSync(dpy, False);
}
static void static void
signal_handle(int sig) signal_handle(int sig)
{ {
@ -375,89 +547,76 @@ signal_handle(int sig)
{ {
case SIGQUIT: case SIGQUIT:
case SIGTERM: case SIGTERM:
exiting = True; W->flags &= ~WMFS_RUNNING;
break; break;
case SIGCHLD: case SIGCHLD:
sig_chld = True; W->flags |= WMFS_SIGCHLD;
break; break;
} }
return;
} }
/** main function
* \param argc ?
* \param argv ?
* \return 0
*/
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int i; int i;
char *ol = "cs"; bool r;
extern char *optarg; Display *dpy;
extern int optind; char path[MAX_PATH_LEN] = { 0 };
struct sigaction sa; struct sigaction sa;
(void)argc;
argv_global = xstrdup(argv[0]); sprintf(path, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
all_argv = argv;
sprintf(conf.confpath, "%s/"DEF_CONF, getenv("HOME"));
while((i = getopt(argc, argv, "hvic:s:C:")) != -1) /* Opt */
while((i = getopt(argc, argv, "hvC:c:")) != -1)
{ {
/* For options who need WMFS running */
if(strchr(ol, i) && !(dpy = XOpenDisplay(NULL)))
errx(EXIT_FAILURE, "cannot open X server.");
switch(i) switch(i)
{ {
case 'h':
default: default:
printf("usage: %s [-ihv] [-C <file>] [-c <uicb function> <cmd> ] [-g <argument>] [-s <screen_num> <string>]\n" case 'h':
" -C <file> Load a configuration file\n" printf("usage: %s [-hv] [-c <func> <cmd] [-C <file>]\n"
" -c <uicb_function> <cmd> Execute an uicb function to control WMFS\n"
" -s <screen_num> <string> Set the bar(s) statustext\n"
" -h Show this page\n" " -h Show this page\n"
" -i Show informations\n" " -v Show WMFS version\n"
" -v Show WMFS version\n", argv[0]); " -c <func> <cmd> Execute a specified UICB function\n"
exit(EXIT_SUCCESS); " -C <file> Launch WMFS with a specified configuration file\n", argv[0]);
break;
case 'i':
printf("WMFS - Window Manager From Scratch By Martin Duquesnoy\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case 'v': case 'v':
printf("wmfs"WMFS_VERSION"\n"); printf("wmfs("WMFS_VERSION") 2 beta\n");
exit(EXIT_SUCCESS);
break;
case 'c':
if(!(dpy = XOpenDisplay(NULL)))
{
fprintf(stderr, "%s: Can't open X server\n", argv[0]);
exit(EXIT_FAILURE);
}
exec_uicb_function(dpy, DefaultRootWindow(dpy), optarg, argv[optind]);
XCloseDisplay(dpy);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case 'C': case 'C':
strncpy(conf.confpath, optarg, sizeof(conf.confpath)); strncpy(path, optarg, MAX_PATH_LEN);
break;
case 'c':
exec_uicb_function(optarg, argv[optind]);
XCloseDisplay(dpy);
exit(EXIT_SUCCESS);
break;
case 's':
if(argc > 3)
set_statustext(atoi(optarg), argv[3]);
else
set_statustext(-1, optarg);
XCloseDisplay(dpy);
exit(EXIT_SUCCESS);
break; break;
} }
} }
/* Check if WMFS can open X server */ W = (struct wmfs*)xcalloc(1, sizeof(struct wmfs));
if(!(dpy = XOpenDisplay(NULL)))
errx(EXIT_FAILURE, "cannot open X server."); /* Default path ~/.config/wmfs/wmfsrc */
W->confpath = path;
/* Get X display */
if(!(W->dpy = XOpenDisplay(NULL)))
{
fprintf(stderr, "%s: Can't open X server\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Set signal handler */ /* Set signal handler */
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
@ -467,15 +626,19 @@ main(int argc, char **argv)
sigaction(SIGTERM, &sa, NULL); sigaction(SIGTERM, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL); sigaction(SIGCHLD, &sa, NULL);
/* Check if an other WM is already running; set the error handler */ /* Core */
XSetErrorHandler(errorhandler); wmfs_init();
wmfs_scan();
wmfs_loop();
wmfs_quit();
/* Let's Go ! */ r = (W->flags & WMFS_RELOAD);
init(); free(W);
scan();
mainloop();
quit();
return 0; if(r)
execvp(argv[0], argv);
XCloseDisplay(W->dpy);
return 1;
} }

View File

@ -1,511 +1,423 @@
/* /*
* wmfs.h * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com> * For license, see COPYING.
* All rights reserved. */
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WMFS_H #ifndef WMFS_H
#define WMFS_H #define WMFS_H
/* Lib headers */ /* Standard */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdarg.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include <getopt.h>
#include <dirent.h>
#include <err.h>
#include <pthread.h>
#include <locale.h> #include <locale.h>
#include <err.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/select.h>
#include <sys/types.h> /* Xlib */
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
/* Optional dependencies */ /* Local */
#ifdef HAVE_XFT #include "log.h"
#include <X11/Xft/Xft.h>
#endif /* HAVE_XFT */
#ifdef HAVE_XINERAMA #define CONFIG_DEFAULT_PATH ".config/wmfs/wmfsrc"
#include <X11/extensions/Xinerama.h>
#endif /* HAVE_XINERAMA */
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif /* HAVE_XRANDR */
#ifdef HAVE_IMLIB
#include <Imlib2.h>
#endif /* HAVE_IMLIB */
/* Local headers */
#include "parse.h"
#include "structs.h"
/* MACRO */
#define ButtonMask (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask) #define ButtonMask (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
#define MouseMask (ButtonMask | PointerMotionMask) #define MouseMask (ButtonMask | PointerMotionMask)
#define KeyMask (KeyPressMask | KeyReleaseMask) #define KeyMask (KeyPressMask | KeyReleaseMask)
#define SCREEN DefaultScreen(dpy)
#define ROOT RootWindow(dpy, SCREEN)
#define MAXH DisplayHeight(dpy, DefaultScreen(dpy))
#define MAXW DisplayWidth(dpy, DefaultScreen(dpy))
#define INFOBARH ((conf.bars.height > 0) ? conf.bars.height : (font.height * 1.5))
#define FHINFOBAR ((font.height - font.de) + (((int)INFOBARH - font.height) >> 1))
#define SHADH (1)
#define BORDH conf.client.borderheight
#define TBARH ((conf.titlebar.height < BORDH) ? BORDH : conf.titlebar.height)
#define RESHW (6 * (BORDH))
#define BUTTONWH (TBARH >> 1)
#define DEF_CONF ".config/wmfs/wmfsrc"
#define DEF_STATUS ".config/wmfs/status.sh"
#define PAD conf.pad
#define MAXSTATUS (4096)
#define CWIN(win, parent, x, y, w, h, b, mask, col, at) \ typedef unsigned long Flags;
do { \ typedef unsigned int Color;
win = XCreateWindow(dpy, (parent), (x), (y), (w), (h), (b), CopyFromParent, \ typedef const char* Uicb;
InputOutput, CopyFromParent, (mask), (at)); \
XSetWindowBackground(dpy, win, (col)); \
} while(/* CONSTCOND */ 0)
#define HANDLE_EVENT(e) event_handle[(e)->type](e); enum barpos
#define ATOM(a) XInternAtom(dpy, (a), False) {
#define FRAMEW(w) ((w) + (BORDH << 1)) BarTop = 0,
#define FRAMEH(h) ((h) + (BORDH + TBARH)) BarBottom,
#define CHECK(x) if(!(x)) return BarHide,
#define LEN(x) (sizeof(x) / sizeof((x)[0])) BarLast
#define MAXCLIST (64) };
#define RPOS(x) (x & 1 ? x - 1 : x + 1)
#define LDIR(x) (x < Top)
#define FLAGAPPLY(v, b, f) ((b) ? (v |= (f)) : (v &= ~(f)))
#define INAREA(i, j, a) ((i) >= (a).x && (i) <= (a).x + (a).width && (j) >= (a).y && (j) <= (a).y + (a).height)
/* Cfactor define */ enum position
#define CFACTOR_CHECK2(g1, g2, p) (LDIR(p) ? (g1.height == g2.height) : (g1.width == g2.width)) {
#define CFACTOR_PARENTROW(g1, g2, p) \ Right = 0,
(LDIR(p) \ Left,
? (p == Left ? (g1.x == g2.x) : (g1.x + g1.width == g2.x + g2.width)) \ Top,
: (p == Top ? (g1.y == g2.y) : (g1.y + g1.height == g2.y + g2.height))) \ Bottom,
Center,
NoAlign,
PositionLast
};
/* Barwin define, wrappers for simple function */ enum size_hints
#define barwin_delete_subwin(bw) XDestroySubwindows(dpy, bw->win) {
#define barwin_map_subwin(bw) XMapSubwindows(dpy, bw->win) BASEW, BASEH,
#define barwin_unmap_subwin(bw) XUnmapSubwindows(dpy, bw->win) INCW, INCH,
#define barwin_refresh(bw) XCopyArea(dpy, bw->dr, bw->win, gc, 0, 0, bw->geo.width, bw->geo.height, 0, 0) MAXW, MAXH,
#define barwin_map(bw) \ MINW, MINH,
do { \ MINAX, MINAY,
XMapWindow(dpy, bw->win); \ MAXAX, MAXAY,
bw->flags |= MappedFlag; \ SHLAST
} while(/* CONSTCOND */ 0) };
#define barwin_unmap(bw) \
do { \
XUnmapWindow(dpy, bw->win); \
bw->flags &= ~MappedFlag; \
} while(/* CONSTCOND */ 0)
/* barwin.c */ /*
BarWindow *barwin_create(Window parent, * Structures
int x, int y, */
int w, int h,
uint bg, char*fg,
bool entermask,
bool stipple,
bool border);
void barwin_draw_text(BarWindow *bw, int x, int y, char *text);
void barwin_color_set(BarWindow *bw, uint bg, char *fg);
void barwin_delete(BarWindow *bw);
void barwin_move(BarWindow *bw, int x, int y);
void barwin_resize(BarWindow *bw, int w, int h);
void barwin_refresh_color(BarWindow *bw);
/* draw.c */ struct geo
void draw_text(Drawable d, int x, int y, char* fg, char *str); {
void draw_rectangle(Drawable dr, int x, int y, int w, int h, uint color); int x, y, w, h;
void draw_graph(Drawable dr, int x, int y, int w, int h, uint color, char *data); };
ushort textw(char *text); struct geo_list
{
struct geo geo;
SLIST_ENTRY(geo_list) next;
};
/* infobar.c */ struct colpair
void infobar_init(void); {
void infobar_draw_layout(InfoBar *i); Color fg, bg;
void _infobar_draw(InfoBar *i); };
void infobar_draw(InfoBar *i);
void infobar_draw_selbar(InfoBar *i);
void infobar_draw_taglist(InfoBar *i);
void infobar_update_taglist(InfoBar *i);
void infobar_destroy(void);
void infobar_set_position(int pos);
void uicb_infobar_togglepos(uicb_t);
void uicb_infobar_toggledisplay(uicb_t);
void uicb_toggle_tagautohide(uicb_t);
/* cfactor.c */ struct barwin
void cfactor_clean(Client *c); {
Geo cfactor_geo(Geo geo, int fact[4], int *err); struct geo geo;
void cfactor_set(Client *c, Position p, int fac); Window win;
void cfactor_multi_set(Client *c, int fac[4]); Drawable dr;
/* Generated with macro {{{ */ Color fg, bg;
void uicb_client_resize_Right(uicb_t cmd); void *ptr; /* Special cases */
void uicb_client_resize_Left(uicb_t cmd); SLIST_HEAD(mbhead, mousebind) mousebinds;
void uicb_client_resize_Top(uicb_t cmd); SLIST_HEAD(, mousebind) statusmousebinds;
void uicb_client_resize_Bottom(uicb_t cmd); SLIST_ENTRY(barwin) next; /* global barwin */
/* }}} */ SLIST_ENTRY(barwin) enext; /* element barwin */
SLIST_ENTRY(barwin) vnext; /* volatile barwin */
};
/* client.c */ struct status_seq
void client_attach(Client *c); {
void client_configure(Client *c); struct geo geo;
void client_detach(Client *c); enum position align;
void client_focus(Client *c); int data[4];
Client *client_get_next(void); char type;
Client *client_get_prev(void); char *str;
/* client_gb_*() {{{ */ Color color, color2;
Client* client_gb_win(Window w); SLIST_HEAD(, mousebind) mousebinds;
Client* client_gb_frame(Window w); SLIST_ENTRY(status_seq) next;
Client* client_gb_titlebar(Window w); };
Client* client_gb_resize(Window w);
Client* client_gb_button(Window w, int *n);
Client* client_gb_pos(Client *c, int x, int y);
/* }}} */
void client_get_name(Client *c);
void client_hide(Client *c);
void client_kill(Client *c);
bool ishide(Client *c, int screen);
void client_map(Client *c);
Client* client_manage(Window w, XWindowAttributes *wa, bool ar);
void client_geo_hints(Geo *geo, Client *c);
void client_moveresize(Client *c, Geo geo, bool r);
void client_maximize(Client *c);
void client_size_hints(Client *c);
void client_swap(Client *c1, Client *c2);
void client_raise(Client *c);
void client_unhide(Client *c);
void client_focus_next(Client *c);
void client_unmanage(Client *c);
void client_unmap(Client *c);
void client_update_attributes(Client *c);
void client_urgent(Client *c, bool u);
Client* client_get_next_with_direction(Client *bc, Position pos);
void uicb_client_raise(uicb_t);
/* Generated with macro {{{ */
void uicb_client_focus_next(uicb_t);
void uicb_client_focus_prev(uicb_t);
void uicb_client_swapsel_next(uicb_t);
void uicb_client_swapsel_prev(uicb_t);
void uicb_client_swapsel_Right(uicb_t);
void uicb_client_swapsel_Left(uicb_t);
void uicb_client_swapsel_Top(uicb_t);
void uicb_client_swapsel_Bottom(uicb_t);
void uicb_client_focus_Right(uicb_t cmd);
void uicb_client_focus_Left(uicb_t cmd);
void uicb_client_focus_Top(uicb_t cmd);
void uicb_client_focus_Bottom(uicb_t cmd);
/* }}} */
void uicb_client_kill(uicb_t);
void uicb_client_screen_next(uicb_t);
void uicb_client_screen_prev(uicb_t);
void uicb_client_screen_set(uicb_t);
void uicb_client_move(uicb_t cmd);
void uicb_client_resize(uicb_t cmd);
void uicb_ignore_next_client_rules(uicb_t cmd);
void uicb_clientlist(uicb_t cmd);
bool uicb_checkclist(uicb_t);
void uicb_client_ignore_tag(uicb_t);
void uicb_client_set_master(uicb_t);
/* ewmh.c */ struct status_ctx
void ewmh_init_hints(void); {
void ewmh_send_message(Window d, Window w, char *atom, long d0, long d1, long d2, long d3, long d4); struct barwin *barwin;
long ewmh_get_xembed_state(Window win); struct theme *theme;
void ewmh_get_number_of_desktop(void); #define STATUS_BLOCK_REFRESH 0x01
void ewmh_update_current_tag_prop(void); Flags flags;
void ewmh_get_client_list(void); char *status;
void ewmh_get_desktop_names(void); bool update;
void ewmh_set_desktop_geometry(void); SLIST_HEAD(, status_gcache) gcache;
void ewmh_manage_net_wm_state(long data_l[], Client *c); SLIST_HEAD(, status_seq) statushead;
void ewmh_manage_window_type(Client *c); };
/* frame.c */ struct status_gcache
void frame_create(Client *c); {
void frame_delete(Client *c); char *name;
void frame_moveresize(Client *c, Geo geo); int *datas;
void frame_update_color(Client *c, bool focused); int ndata;
void frame_update(Client *c); SLIST_ENTRY(status_gcache) next;
};
/* config.c */ struct element
void init_conf(void); {
struct geo geo;
struct infobar *infobar;
struct status_ctx *statusctx;
int type;
char *data;
enum position align;
void (*func_init)(struct element *e);
void (*func_update)(struct element *e);
SLIST_HEAD(, barwin) bars;
TAILQ_ENTRY(element) next;
};
/* color.c */ struct infobar
uint color_shade(uint, double); {
struct barwin *bar;
struct geo geo;
struct screen *screen;
struct theme *theme;
struct status_ctx statusctx;
enum barpos opos, pos;
char *elemorder;
char *name;
TAILQ_HEAD(esub, element) elements;
SLIST_ENTRY(infobar) next;
};
/* event.c */ struct screen
void grabkeys(void); {
void event_make_array(void); struct geo geo, ugeo;
struct tag *seltag;
#define SCREEN_TAG_UPDATE 0x01
Flags flags;
int id;
TAILQ_HEAD(tsub, tag) tags;
SLIST_HEAD(, infobar) infobars;
SLIST_ENTRY(screen) next;
};
#ifdef HAVE_XRANDR SLIST_HEAD(chead, client);
void xrandrevent(XEvent *e);
#endif /* HAVE_XRANDR */
/* menu.c */ struct tag
void menu_init(Menu *menu, char *name, int nitem, uint bg_f, char *fg_f, uint bg_n, char *fg_n); {
void menu_new_item(MenuItem *mi, char *name, void *func, char *cmd); struct screen *screen;
void menu_draw(Menu menu, int x, int y); struct client *sel;
void uicb_menu(uicb_t cmd); struct client *prevsel;
void menu_clear(Menu *menu); struct tag *prev;
struct status_ctx statusctx;
char *name;
int id;
#define TAG_URGENT 0x01
#define TAG_IGNORE_ENTER 0x02
Flags flags;
SLIST_HEAD(, client) clients;
TAILQ_HEAD(ssub, layout_set) sets;
TAILQ_ENTRY(tag) next;
};
/* launcher.c */ struct client
void uicb_launcher(uicb_t); {
struct tag *tag, *prevtag;
struct screen *screen;
struct barwin *titlebar;
struct geo geo, wgeo, tgeo, ttgeo, rgeo, *tbgeo;
struct colpair ncol, scol;
struct theme *theme;
struct client *tabmaster;
int sizeh[SHLAST];
char *title;
int border, tbarw;
#define CLIENT_HINT_FLAG 0x01
#define CLIENT_IGNORE_ENTER 0x02
#define CLIENT_DID_WINSIZE 0x04
#define CLIENT_FAC_APPLIED 0x08
#define CLIENT_IGNORE_LAYOUT 0x10
#define CLIENT_RULED 0x20
#define CLIENT_TABBED 0x40
#define CLIENT_TABMASTER 0x80
#define CLIENT_DYING 0x100 /* Saddest flag ever */
#define CLIENT_REMOVEALL 0x200
#define CLIENT_MAPPED 0x400
#define CLIENT_FULLSCREEN 0x800
#define CLIENT_FREE 0x1000
#define CLIENT_TILED 0x2000
#define CLIENT_MOUSE 0x4000
#define CLIENT_IGNORE_TAG 0x8000
Flags flags;
Window win, frame, tmp;
SLIST_ENTRY(client) next; /* Global list */
SLIST_ENTRY(client) tnext; /* struct tag list */
};
/* mouse.c */ struct layout_set
void mouse_resize(Client *c); {
void mouse_grabbuttons(Client *c, bool focused); int n;
void uicb_mouse_move(uicb_t); SLIST_HEAD(, geo_list) geos;
void uicb_mouse_resize(uicb_t); TAILQ_ENTRY(layout_set) next;
};
/* util.c */ struct keybind
void *xmalloc(size_t, size_t); {
void *xcalloc(size_t, size_t); unsigned int mod;
void *xrealloc(void *, size_t, size_t); void (*func)(Uicb);
/* simples wrappers for allocating only one object */ Uicb cmd;
#define zmalloc(size) xmalloc(1, (size)) KeySym keysym;
#define zcalloc(size) xcalloc(1, (size)) SLIST_ENTRY(keybind) next;
#define zrealloc(ptr, size) xrealloc((ptr), 1, (size)) };
char *xstrdup(const char *);
int xasprintf(char **, const char *, ...);
long getcolor(char *color);
void setwinstate(Window win, long state);
/* Conf usage {{{ */
void* name_to_func(char *name, const func_name_list_t *l);
ulong char_to_modkey(char *name, key_name_list_t key_l[]);
uint char_to_button(char *name, name_to_uint_t blist[]);
Layout layout_name_to_struct(Layout lt[], char *name, int n, const func_name_list_t llist[]);
/* }}} */
char *char_to_str(const char c);
pid_t spawn(const char *str, ...);
void swap_ptr(void **x, void **y);
void uicb_spawn(uicb_t);
char* patht(char *path);
int qsort_string_compare (const void * a, const void * b);
/* tag.c */ struct mousebind
void tag_set(int tag); {
void tag_transfert(Client *c, int tag); struct geo area;
void uicb_tag(uicb_t); unsigned int button;
void uicb_tag_next(uicb_t); bool use_area;
void uicb_tag_prev(uicb_t); void (*func)(Uicb);
void uicb_tag_next_visible(uicb_t); Uicb cmd;
void uicb_tag_prev_visible(uicb_t); SLIST_ENTRY(mousebind) next;
void uicb_tagtransfert(uicb_t); SLIST_ENTRY(mousebind) snext;
void uicb_tag_prev_sel(uicb_t); SLIST_ENTRY(mousebind) globnext;
void uicb_tagtransfert_next(uicb_t); };
void uicb_tagtransfert_prev(uicb_t);
void uicb_tag_urgent(uicb_t cmd);
void tag_additional(int sc, int tag, int adtag);
void uicb_tag_toggle_additional(uicb_t);
void uicb_tag_swap(uicb_t);
void uicb_tag_swap_next(uicb_t);
void uicb_tag_swap_previous(uicb_t);
void uicb_tag_new(uicb_t);
void uicb_tag_del(uicb_t);
void uicb_tag_rename(uicb_t cmd);
void uicb_tag_last(uicb_t cmd);
void uicb_tag_stay_last(uicb_t cmd);
void uicb_tag_toggle_expose(uicb_t cmd);
/* screen.c */ struct theme
int screen_count(void); {
Geo screen_get_geo(int s); char *name;
int screen_get_with_geo(int x, int y);
int screen_get_sel(void);
void screen_set_sel(int screen);
void screen_init_geo(void);
void uicb_screen_select(uicb_t);
void uicb_screen_next(uicb_t);
void uicb_screen_prev(uicb_t);
void uicb_screen_prev_sel(uicb_t);
/* status.c */ /* Font */
void statustext_mouse(char *str, Geo area, InfoBar *infobar); struct
void statustext_handle(InfoBar *ib); {
int as, de, width, height;
XFontSet fontset;
} font;
/* systray.c */ /* Bars */
bool systray_acquire(void); struct colpair bars;
void systray_add(Window win); int bars_width;
void systray_del(Systray *s);
void systray_state(Systray *s);
void systray_freeicons(void);
Systray* systray_find(Window win);
int systray_get_width(void);
void systray_update(void);
/* layout.c */ /* struct elements */
void arrange(int screen, bool update_layout); struct colpair tags_n, tags_s, tags_o, tags_u; /* normal / selected / occupied */
void layout_func(int screen, int tag); struct status_ctx tags_n_sl, tags_s_sl, tags_o_sl, tags_u_sl; /* status line */
Client *tiled_client(int screen, Client *c); int tags_border_width;
void freelayout(int screen); Color tags_border_col;
void layoutswitch(bool b);
void maxlayout(int screen);
/* tile {{{ */
void tile(int screen);
void tile_left(int screen);
void tile_top(int screen);
void tile_bottom(int screen);
void mirror_vertical(int screen);
void mirror_horizontal(int screen);
void grid_vertical(int screen);
void grid_horizontal(int screen);
/* }}} */
void uicb_togglemax(uicb_t);
void uicb_togglefree(uicb_t);
void uicb_layout_prev(uicb_t);
void uicb_layout_next(uicb_t);
void uicb_set_mwfact(uicb_t);
void uicb_set_nmaster(uicb_t);
void uicb_set_layout(uicb_t);
void uicb_toggle_resizehint(uicb_t);
void uicb_toggle_abovefc(uicb_t cmd);
void layout_set_client_master(Client *c);
void layout_split_client(Client *c, bool p);
void layout_split_apply(Client *c);
void layout_split_arrange_closed(int screen);
void uicb_split_client_vertical(uicb_t);
void uicb_split_client_horizontal(uicb_t);
bool uicb_checkmax(uicb_t);
bool uicb_checkfree(uicb_t);
bool uicb_checklayout(uicb_t);
/* init.c */ /* client / frame */
void init(void); struct colpair client_n, client_s;
struct status_ctx client_n_sl, client_s_sl, client_f_sl;
Color frame_bg;
int client_titlebar_width;
int client_border_width;
/* split.c */ SLIST_ENTRY(theme) next;
void split_store_geo(int screen, int tag); };
void split_set_current(Client *nc, Client *ghost);
void split_apply_current(int screen, int tag);
void split_arrange_closed(Client *ghost);
Geo split_client(Client *c, bool p);
void split_client_fill(Client *c, Geo geo);
void split_client_integrate(Client *c, Client *sc, int screen, int tag);
void split_move_dir(Client *c, Position p);
void uicb_split_toggle(uicb_t cmd);
/* Generated with macro {{{ */
void uicb_split_move_Right(uicb_t);
void uicb_split_move_Left(uicb_t);
void uicb_split_move_Top(uicb_t);
void uicb_split_move_Bottom(uicb_t);
/* }}} */
/* wmfs.c */ struct rule
int errorhandler(Display *d, XErrorEvent *event); {
int errorhandlerdummy(Display *d, XErrorEvent *event); struct theme *theme;
void quit(void); char *class;
void *thread_process(void *arg); char *instance;
bool check_wmfs_running(void); char *role;
void exec_uicb_function(char *func, char *cmd); char *name;
void handle_signal(int signum); int tag, screen;
void uicb_quit(uicb_t); #define RULE_FREE 0x01
void uicb_reload(uicb_t); #define RULE_TAB 0x02
#define RULE_IGNORE_TAG 0x04
Flags flags;
SLIST_ENTRY(rule) next;
};
/* Variables */ struct launcher
{
char *name;
char *prompt;
char *command;
#define HISTOLEN 64
char histo[HISTOLEN][256];
int nhisto;
int width;
SLIST_ENTRY(launcher) next;
};
/* Main */ struct launcher_ccache
Display *dpy; {
GC gc, gc_stipple; char *start;
int selscreen; char **namelist;
int prevselscreen; size_t hits;
Conf conf; };
Key *keys;
Geo *sgeo;
Geo *spgeo;
Cursor cursor[CurLast];
char *argv_global;
char **all_argv;
int xrandr_event;
uint timing;
/* Fonts */ struct _systray
FontStruct font; {
struct geo geo;
Window win;
SLIST_ENTRY(_systray) next;
};
/* Atoms list */ #define MAX_PATH_LEN 8192
Atom *net_atom;
Atom trayatom;
/* InfoBar/Tags */ struct wmfs
InfoBar *infobar; {
Tag **tags; /* X11 stuffs */
int *seltag; Display *dpy;
int *prevseltag; Window root;
Menu menulayout; int xscreen, xdepth;
int xmaxw, xmaxh;
int nscreen;
unsigned int client_mod;
Flags numlockmask;
#define WMFS_SCAN 0x001
#define WMFS_RUNNING 0x002
#define WMFS_RELOAD 0x004
#define WMFS_SYSTRAY 0x008
#define WMFS_LOG 0x010
#define WMFS_LAUNCHER 0x020
#define WMFS_SIGCHLD 0x040
#define WMFS_TABNOC 0x080 /* tab next opened client */
#define WMFS_TAGCIRC 0x100 /* tab_next on last tag -> go to first tag / tab_prev on first tag -> go to last tag */
#define WMFS_AUTOFOCUS 0x200
Flags flags;
GC gc, rgc;
Atom *net_atom;
char **argv;
char *confpath;
struct barwin *last_clicked_barwin;
struct theme *ctheme;
#define CFOCUS_ENTER 0x01
#define CFOCUS_CLICK 0x02
Flags cfocus; /* Focus configuration, can be set to 0, CFOCUS_ENTER or CFOCUS_CLICK*/
/* ClientList */ int padding;
Menu clientlist;
struct clndx {
char key[4];
Client *client;
} clist_index[MAXCLIST];
/* Client */ /* Log file */
SLIST_HEAD(, Client) clients; FILE *log;
Client *sel;
/* Event */ /* Lists heads */
int nevent; struct
void (**event_handle)(XEvent*); {
extern const func_name_list_t func_list[]; SLIST_HEAD(, screen) screen;
extern const func_name_list_t layout_list[]; SLIST_HEAD(, client) client;
uint numlockmask; SLIST_HEAD(, keybind) keybind;
SLIST_HEAD(, barwin) barwin;
SLIST_HEAD(, theme) theme;
SLIST_HEAD(, rule) rule;
SLIST_HEAD(, mousebind) mousebind;
SLIST_HEAD(, launcher) launcher;
SLIST_HEAD(, barwin) vbarwin;
} h;
/* Systray */ /*
SLIST_HEAD(, Systray) trayicons; * Temporary head of mousebind list from config
Window traywin; * Will be copied in barwin of clickable drawable
int tray_width; * later in code
*/
struct
{
struct mbhead tag;
struct mbhead client;
struct mbhead root;
} tmp_head;
/* BarWindow */ /*
SLIST_HEAD(, BarWindow) bwhead; * Because there is only one systray per display,
* set struct there
*/
struct
{
struct barwin *barwin;
struct infobar *infobar;
bool redim;
Window win;
SLIST_HEAD(, _systray) head;
} systray;
/* Status */ /*
SLIST_HEAD(, StatusMouse) smhead; * Selected screen, client
*/
struct screen *screen;
struct client *client;
};
int wmfs_error_handler(Display *d, XErrorEvent *event);
int wmfs_error_handler_dummy(Display *d, XErrorEvent *event);
void wmfs_grab_keys(void);
void wmfs_numlockmask(void);
void wmfs_init_font(char *font, struct theme *t);
void wmfs_quit(void);
void uicb_reload(Uicb cmd);
void uicb_quit(Uicb cmd);
/* Single global variable */
struct wmfs *W;
#endif /* WMFS_H */ #endif /* WMFS_H */

731
wmfs.1
View File

@ -1,11 +1,8 @@
.\" Title: wmfs .\" title: wmfs
.\" Author: .\" dev: xorg62
.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/> .\" man: arpinux
.\" Date: 04/22/2009
.\" Manual: manual of wmfs
.\" Source: wmfs 0.1rc4 (On The Run)
.\" .\"
.TH "WMFS" "1" "04/22/2009" "wmfs 0\&.1rc4 (On The Run)" "manual of wmfs" .TH "WMFS" "1" "2012/05/02" "wmfs" "manual of wmfs"
.\" disable hyphenation .\" disable hyphenation
.nh .nh
.\" disable justification (adjust text to left margin only) .\" disable justification (adjust text to left margin only)
@ -13,10 +10,10 @@
.SH "NAME" .SH "NAME"
wmfs \- Window Manager From Scratch wmfs \- Window Manager From Scratch
.SH "SYNOPSIS" .SH "SYNOPSIS"
\fBwmfs\fR [\fB\-ihvS\fR] [\fB\-C <file>\fR] [\fB\-c <uicb_function> <cmd>\fR] [\fB\-g <argument>\fR] [\fB\-s <screen_num> <string>\fR] [\fB\-V <viwmfs cmd>\fR] \fBwmfs\fR [\fB\-hv\fR] [\fB\-C <file>\fR] [\fB\-c <uicb_function> <cmd>\fR]
.sp .sp
.SH "DESCRIPTION" .SH "DESCRIPTION"
\fBWMFS\fR is a basic, lightweight and dynamic tiling windows manager for X\&. \fBWMFS\fR is a lightweight and highly configurable tiling window manager for X written in C\&.
.sp .sp
.SH "OPTIONS" .SH "OPTIONS"
.PP .PP
@ -30,26 +27,6 @@ Load a configuration file\&.
Execute an uicb function to control WMFS\&. Execute an uicb function to control WMFS\&.
.RE .RE
.PP .PP
\fB\-g <argument>\fR
.RS 4
Show information about wmfs status\&.
.RE
.PP
\fB\-s <screen_num> <string>\fR
.RS 4
Set the bar(s) statustext. If the screen number is not specified, the string will be show on all screens bars\&.
.RE
.PP
\fB\-V <viwmfs cmd>\fR
.RS 4
Manage WMFS with vi-like command\&.
.RE
.PP
\fB\-S\fR
.RS 4
Update status script\&.
.RE
.PP
\fB\-v\fR \fB\-v\fR
.RS 4 .RS 4
Print version information to standard output, then exit\&. Print version information to standard output, then exit\&.
@ -59,11 +36,6 @@ Print version information to standard output, then exit\&.
.RS 4 .RS 4
Print help information, then exit\&. Print help information, then exit\&.
.RE .RE
.PP
\fB\-i\fR
.RS 4
Print WMFS information
.RE
.SH "DEFAULT KEY BINDINGS" .SH "DEFAULT KEY BINDINGS"
.PP .PP
\fBControl\-Alt + r\fR \fBControl\-Alt + r\fR
@ -71,29 +43,34 @@ Print WMFS information
Reload WMFS binary Reload WMFS binary
.RE .RE
.PP .PP
\fBControl + Return\fR \fBSuper + Return\fR
.RS 4 .RS 4
Run a terminal (urxvt by default) Run a terminal (urxvt by default)
.RE .RE
.PP .PP
\fBAlt + q\fR \fBSuper + q\fR
.RS 4 .RS 4
Quit the selected client Quit the selected client
.RE .RE
.PP .PP
\fBControl\-Alt\-Shift + q\fR \fBControl\-Alt + q\fR
.RS 4 .RS 4
Exit WMFS Exit WMFS
.RE .RE
.PP .PP
\fBAlt + m \fR \fBSuper + f \fR
.RS 4 .RS 4
Toggle maximize the selected client Toggle free the selected client
.RE .RE
.PP .PP
\fBAlt + b \fR \fBSuper + Shift + f \fR
.RS 4 .RS 4
Toggle the bar position between top, hide and bottom Toggle ignore_tag the selected client
.RE
.PP
\fBSuper + Shift + h \fR
.RS 4
Toggle infobar visibility
.RE .RE
.PP .PP
\fBAlt + Tab\fR \fBAlt + Tab\fR
@ -106,6 +83,121 @@ Give the focus to the next client
Give the focus to the previous client Give the focus to the previous client
.RE .RE
.PP .PP
\fBAlt + h\fR
.RS 4
Give the focus to the client on the left
.RE
.PP
\fBAlt + l\fR
.RS 4
Give the focus to the client on the right
.RE
.PP
\fBAlt + k\fR
.RS 4
Give the focus to the client on the top
.RE
.PP
\fBAlt + j\fR
.RS 4
Give the focus to the client on the bottom
.RE
.PP
\fBSuper + Tab\fR
.RS 4
Give the focus to the next tabbed client
.RE
.PP
\fBSuper\-Shift + Tab\fR
.RS 4
Give the focus to the previous tabbed client
.RE
.PP
\fBControl\-Shift + h\fR
.RS 4
Swap with the client on the left
.RE
.PP
\fBControl\-Shift + l\fR
.RS 4
Swap with the client on the right
.RE
.PP
\fBControl\-Shift + k\fR
.RS 4
Swap with the client on the top
.RE
.PP
\fBControl\-Shift + j\fR
.RS 4
Swap with the client on the bottom
.RE
.PP
\fBAlt\-Shift + h\fR
.RS 4
Tab in the client on the left
.RE
.PP
\fBAlt\-Shift + l\fR
.RS 4
Tab in the client on the right
.RE
.PP
\fBAlt\-Shift + k\fR
.RS 4
Tab in the client on the top
.RE
.PP
\fBAlt\-Shift + j\fR
.RS 4
Tab in the client on the bottom
.RE
.PP
\fBAlt\-Shift + u\fR
.RS 4
Untab the client
.RE
.PP
\fBSuper + h\fR
.RS 4
Increase the client to the left
.RE
.PP
\fBSuper + l\fR
.RS 4
Decrease the client from the left
.RE
.PP
\fBSuper + k\fR
.RS 4
Increase the client to the top
.RE
.PP
\fBSuper + j\fR
.RS 4
Decrease the client from the top
.RE
.PP
\fBSuper\-Control + h\fR
.RS 4
Decrease the client from the right
.RE
.PP
\fBSuper\-Control + l\fR
.RS 4
Increase the client to the right
.RE
.PP
\fBSuper\-Control + k\fR
.RS 4
Decrease the client from the bottom
.RE
.PP
\fBSuper\-Control + j\fR
.RS 4
Increase the client to the bottom
.RE
.PP
\fBControl + Right\fR \fBControl + Right\fR
.RS 4 .RS 4
Next tag Next tag
@ -116,88 +208,581 @@ Next tag
Previous tag Previous tag
.RE .RE
.PP .PP
\fBAlt + Space\fR \fBControl + Up\fR
.RS 4 .RS 4
Next layout Next screen
.RE .RE
.PP .PP
\fBAlt\-Shift + Space\fR \fBControl + Down\fR
.RS 4 .RS 4
Previous layout Previous screen
.RE .RE
.PP .PP
\fBAlt + l\fR \fBSuper + m\fR
.RS 4 .RS 4
Increase the mwfact (+0\&.025) Vertical mirror layout
.RE .RE
.PP .PP
\fBAlt + h\fR \fBSuper\-Shift + m\fR
.RS 4 .RS 4
Decrease the mwfact (\-0\&.025) Horizontal mirror layout
.RE .RE
.PP .PP
\fBAlt + d\fR \fBSuper + r\fR
.RS 4 .RS 4
Increase the nmaster (+1)\fR Rotate layout right
.RE .RE
.PP .PP
\fBAlt\-Shift + d\fR \fBSuper\-Shift + r\fR
.RS 4 .RS 4
Decrease the nmaster (\-1)\fR Rotate layout left
.RE .RE
.PP .PP
\fBAlt + t\fR \fBSuper\-Control\-Alt + h\fR
.RS 4 .RS 4
Swap the current client with the next\fR Integrate client in left layout
.RE .RE
.PP .PP
\fBAlt\-Shift + t\fR \fBSuper\-Control\-Alt + j\fR
.RS 4 .RS 4
Swap the current client with the previous\fR Integrate client in bottom layout
.RE .RE
.PP .PP
\fBAlt + p\fR \fBSuper\-Control\-Alt + k\fR
.RS 4 .RS 4
Make a launcher in the infobar to run an unix command\fR Integrate client in top layout
.RE .RE
.PP .PP
\fBAlt + Escape\fR \fBSuper\-Control\-Alt + l\fR
.RS 4 .RS 4
Set WMFS in ViWMFS mode. (see wmfs \-V)\fR Integrate client in right layout
.RE .RE
.PP .PP
\fBAlt\-Shift + p\fR \fBSuper + o\fR
.RS 4 .RS 4
Make a launcher in the infobar to run an ssh session\fR Restore previous layout
.RE .RE
.PP .PP
\fBAlt + F[1\&.\&.9]\fR \fBSuper\-Shift + o\fR
.RS 4
Restore next layout
.RE
.PP
\fBSuper + p\fR
.RS 4
Display a launcher in the statusbar to run an unix command\fR
.RE
.PP
\fBSuper + F[1\&.\&.9]\fR
.RS 4 .RS 4
Change tag view Change tag view
.RE .RE
.PP .PP
\fBControl\-Shift +F[1\&.\&.9]\fR \fBSuper\-Shift + F[1\&.\&.9]\fR
.RS 4 .RS 4
Transfert the selected client to the wanted tag Transfert the selected client to the wanted tag
.RE .RE
.PP
\fBSuper + -\fR
.RS 4
Delete current tag\fR
.RE
.PP
\fBSuper\-Shift + -\fR
.RS 4
Add current tag\fR
.RE
.SH "CONFIGURATION" .SH "CONFIGURATION"
WMFS is configured by \fI$HOME/\&.config/wmfs/wmfsrc\fR\&. WMFS is configured by \fI$HOME/\&.config/wmfs/wmfsrc\fR\&.
.RE
.PP
\fB\ include:\fR
wmfsrc supports ”@include” to split configuration file by section\&.
.RS 2
\fB\ Usage:\fR "@include ~/.config/wmfs/wmfs_themes"\&.
.RE
.PP
\fB\ [themes]\fR
wmfsrc supports themes for client and statusbar\&.
.RS 2
\fB Misc\fR
.RS 2
\fB\ name:\fR
theme name, will be used in next sections\&.
.PP
\fB\ font:\fR
theme font in XLFD format\&.
.PP
.RE
\fB\ Bars\fR
.RS 2
\fB\ bars_width:\fR
bar height in pixels\&.
.PP
\fB\ bars_fg/bg:\fR
statusbar text/background color\&.
.PP
.RE
\fB\ Tags\fR
.RS 2
\fB\ tags_normal_fg/bg:\fR
normal tag text/button color\&.
.PP
\fB\ tags_normal_statusline:\fR
normal tag statusline\&.
.PP
\fB\ tags_sel_fg/bg:\fR
selected tag text/button color\&.
.PP
\fB\ tags_sel_statusline:\fR
selected tag statusline\&.
.PP
\fB\ tags_occupied_fg/bg:\fR
occupied tag text/button color\&.
.PP
\fB\ tags_occupied_statusline:\fR
occupied tag statusline\&.
.PP
\fB\ tags_urgent_fg/bg:\fR
urgent tag text/button color\&.
.PP
\fB\ tags_urgent_statusline:\fR
urgent tag statusline\&.
.PP
\fB\ tags_border_color:\fR
tag button border color\&.
.PP
\fB\ tags_border_width:\fR
tag button border width\&.
.PP
.RE
\fB\ Clients\fR
.RS 2
\fB\ client_normal_fg/bg:\fR
normal client titlebar text/background color\&.
.PP
\fB\ client_normal_statusline:\fR
normal client statusline\&.
.PP
\fB\ client_sel_fg/bg:\fR
selected client titlebar text/background color\&.
.PP
\fB\ client_sel_statusline:\fR
selected client statusline\&.
.PP
\fB\ frame_bg:\fR
client border color\&.
.PP
\fB\ client_titlebar_width:\fR
client titlebar height in pixels\&.
.PP
\fB\ client_border_width:\fR
client border height in pixels\&.
.RE
.PP
.RE
\fB\ [bars]\fR
.RS 2
\fB\ position:\fR
statusbar position on screen (0=Top; 1=Bottom, 2=Hide)\&.
.PP
\fB\ screen:\fR
screen to display statusbar (start ar 0), set to\fB -1\fR to display on every screen\&.
.PP
\fB\ elements:\fR
ordered statusbar elements t=Tags, s=Statustext, y=Systray, l=Launcher\&.
.PP
\fB\ theme:\fR
names of the statusbar theme\&.
.RE
.PP
.RE
\fB\ [tags]\fR
.RS 2
\fB\ circular:\fR
enable tag wrapping. default is true\&.
.PP
\fB\ screen:\fR
screen to display tag. use no screen option or screen =\fB -1\fR to set tag on each screen\&.
.PP
\fB\ name:\fR
display tagname\&.
.PP
\fB\ statusline:\fR
draw a custom statusline in the specific tag (can display any sequences)\&.
.PP
\fB\ mousebinds:\fR
mouse actions on the tag buttons\&.
.RE
.PP
.RE
\fB\ [client]\fR
.RS 2
\fB\ theme:\fR
apply theme to client by default\&.
.PP
\fB\ key_modifier:\fR
key modifier to perform actions on clients\&.
.PP
\fB\ focus:\fR
select the focus mouse options; enter=focus follow mouse, click=click to focus, everything-else=disable focus mouse support\&.
.PP
\fB\ mousebinds:\fR
mouse actions on client\&.
.PP
\fB\ padding:\fR
enable padding between clients. default is 0\&.
.PP
\fB\ autofocus:\fR
give focus to new created clients. default is false\&.
.RE
.PP
.RE
\fB\ [rules]\fR
specific rules for clients: to identify an application, use xprop\&.
.RS 2
\fB\ instance:\fR
first part of WM_CLASS\&.
.PP
\fB\ class:\fR
second part of WM_CLASS\&.
.PP
\fB\ role:\fR
WM_WINDOW_ROLE\&.
.PP
\fB\ name:\fR
_NET_WM_NAME\&.
.PP
\fB\ theme:\fR
apply theme to client\&.
.PP
\fB\ tag:\fR
specify a tag to display client (start at 0)\&.
.PP
\fB\ screen:\fR
display client on a specific screen\&.
.PP
\fB\ free:\fR
client in auto-free mode (true/false)\&.
.PP
\fB\ tab:\fR
open client in a tab (true/false)\&.
.PP
\fB\ ignore_tag:\fR
specify to client to ignore tags (client is displayed on every tag)\&.
.RE
.PP
.RE
\fB\ [launchers]\fR
.RS 2
\fB\ name:\fR
launcher-name, will be used in the [keys] section\&.
.PP
\fB\ prompt:\fR
display text at the beginning of the prompt\&.
.PP
\fB\ command:\fR
command used by the launcher. can be an uicb function or an uicb function + extension\&.
.RE
.PP
.RE
\fB\ [keys]\fR
.RS 2
each line is contained within\fB\ [key]...[/key]\fR
.PP
\fB\ mod:\fR
key modifier (Alt, Control, Shift, Super)\&.
.PP
\fB\ key:\fR
key to press, you can identify it with "xev"\&.
.PP
\fB\ func:\fR
uicb function to launch\&.
.PP
\fB\ cmd:\fR
if\fB\ func = "spawn"\fR set the external command to launch\&.
.sp
.SH "STATUS"
statusbars, tags, surfaces and titlebars support sequences to display text, images bars and graphs through the\fB\ wmfs -c status\fR command.
.PP
\fB\ Syntax\fR
.PP
.RS 4
\fB\ position:\fR “left/right” (relative) or “x;y” (absolute)\&.
.PP
\fB\ dimension:\fR “ww;hh” for width;height of the rectangle or the image, to display an image at its original size, set it to “0;0”\&.
.PP
\fB\ color:\fR ”#rrggbb”\&.
.PP
\fB\ imagepath:\fR absolute path for the image\&.
.PP
\fB\ border:\fR width of the progressbar border in pixels\&.
.PP
\fB\ curser:\fR width of the curser in the positionbar\&.
.PP
\fB\ value:\fR a variable, to draw progressbar\&.
.PP
\fB\ valuemax:\fR maximum value of the value used in the progressbar\&.
.RE
.PP
\fB\ basic usage:\fR
wmfs -c status "<barname> TEXT visible on 'barname'"\&.
.PP
\fB\ display colors:\fR
wmfs -c status "<barname> ^s[<position>;<color>;<text>]"\&.
.PP
\fB\ display rectangles:\fR
wmfs -c status "<barname> ^R[<position>;<dimensions>;<color>]"\&.
.PP
\fB\ display images:\fR
wmfs -c status "<barname> ^i[<position>;<dimensions>;<imagepath>]"\&.
.PP
\fB\ display progressbars:\fR
wmfs -c status "<barname> ^p[<position>;<dimensions>;<border>;<value>;<valuemax>;<bgcolor>;<fgcolor>]"\&.
.PP
\fB\ display positionbars:\fR
wmfs -c status "<barname> ^P[<position>;<dimensions>;<curser>;<value>;<valuemax>;<bgcolor>;<fgcolor>]"\&.
.PP
\fB\ display graph:\fR
wmfs -c status "<barname> ^g[<position>;<dimensions>;<value>;<valuemax>;<bgcolor>;<fgcolor>;<name>]"\&.
.RE
.PP
\fB\ mousebinds:\fR
sequences supports mousebinds with format\fB\ (<key>;<uicb-function>)\fR or\fB\ (<key>;<spawn>;<command>)\fR
.RE
.PP
\fB\ surfaces:\fR
you can display popups from the statusbar with the mousebind\fB\ (<key>;status_surface;<position>,<dimension>,<color> <datas>)\fR
.PP
.sp
.SH "UICB Functions"
UICB functions list. for “User Interface Call Backs”\&.
.PP
\fB\ usage in the wmfsrc:\fR func = "tag_next"\fB\ or\fR func = "spawn" cmd = "urxvt -e vim"\&.
.RE
\fB\ usage in the status.sh:\fR wmfs -c status "<barname> ^s[<position>;<color>;next](1;tag_next)"\&.
.RE
\fB\ usage in your terminal:\fR wmfs -c tag_next\&.
.PP
\fB\ spawn\fR
.RS 4
launch a command. ex: func = "spawn" cmd = "urxvtc -e screen irssi"\&.
.RE
.PP
\fB\ quit\fR
.RS 4
quit wmfs\&.
.RE
.PP
\fB\ reload\fR
.RS 4
reload wmfs\&.
.RE
.PP
\fB\ tag_set\fR
.RS 4
set tag by number\&.
.RE
.PP
\fB\ tag\fR
.RS 4
set tag by name\&.
.RE
.PP
\fB\ tag_next/prev\fR
.RS 4
set next/previous tag\&.
.RE
.PP
\fB\ tag_client\fR
.RS 4
tag the client\&.
.RE
.PP
\fB\ tag_client_and_set\fR
.RS 4
teg the client and set the tag\&.
.RE
.PP
\fB\ tag_move_client_next/prev\fR
.RS 4
tag the client with next/previous tag\&.
.RE
.PP
\fB\ tag_click\fR
.RS 4
display tag with a clic on tag button\&.
.RE
.PP
\fB\ tag_new/del\fR
.RS 4
add/delete a tag\&.
.RE
.PP
\fB infobar_toggle_hide\fR
.RS 4
toggle specific infobar visibility (infobar_name as cmd)\&.
.RE
.PP
\fB\ layout_vmirror\fR
.RS 4
vertical mirror tiling\&.
.RE
.PP
\fB\ layout_hmirror\fR
.RS 4
horizontal mirror tiling\&.
.RE
.PP
\fB\ layout_rotate_left\fR
.RS 4
tiling rotate anti/clockwise\&.
.RE
.PP
\fB\ layout_prev_set\fR
.RS 4
back to previous set layout\&.
.RE
.PP
\fB\ layout_next_set\fR
.RS 4
go to next set layout\&.
.RE
.PP
\fB\ layout_integrate_left/right/top/bottom\fR
.RS 4
client integration in the client zone by direction\&.
.RE
.PP
\fB\ client_close\fR
.RS 4
close the client\&.
.RE
.PP
\fB\ client_resize_right/left/top/bottom\fR
.RS 4
resize client with direction\&.
.RE
.PP
\fB\ client_focus_right/left/top/bottom\fR
.RS 4
focus client with direction\&.
.RE
.PP
\fB\ client_tab_right/left/top/bottom\fR
.RS 4
tab client with direction\&.
.RE
.PP
\fB\ client_swap_right/left/top/bottom\fR
.RS 4
swap client with direction\&.
.RE
.PP
\fB\ client_focus_next/prev\fR
.RS 4
move focus to the next/previous client\&.
.RE
.PP
\fB\ client_swap_next/prev\fR
.RS 4
swap with the next/previous client\&.
.RE
.PP
\fB\ client_untab\fR
.RS 4
untab the client\&.
.RE
.PP
\fB\ client_focus_next_tab\fR
.RS 4
move focus to next tab-client\&.
.RE
.PP
\fB\ client_focus_prev_tab\fR
.RS 4
move focus to previous tab-client\&.
.RE
.PP
\fB\ client_focus_click\fR
.RS 4
give focus to client with a clic\&.
.RE
.PP
\fB\ client_toggle_free\fR
.RS 4
toggle free the selected client\&.
.RE
.PP
\fB\ client_toggle_ignore_tag\fR
.RS 4
toggle ignore_tag the selected client\&.
.RE
.PP
\fB\ client_tab_next_opened\fR
.RS 4
open the client in a tab\&.
.RE
.PP
\fB\ status\fR
.RS 4
display the argument text in the statusbar\&.
.RE
.PP
\fB\ status_surface\fR
.RS 4
display a surface. can contain sequences\&.
.RE
.PP
\fB\ mouse_resize\fR
.RS 4
resize the client\&.
.RE
.PP
\fB\ mouse_move\fR
.RS 4
move the client\&.
.RE
.PP
\fB\ mouse_swap\fR
.RS 4
swap the client\&.
.RE
.PP
\fB\ mouse_tab\fR
.RS 4
tab the client\&.
.RE
.PP
\fB\ screen_next/prev\fR
.RS 4
go to next/previous screen\&.
.RE
.PP
\fB\ screen_move_client_next/prev\fR
.RS 4
move the client to next/previous screen\&.
.RE
.PP
\fB\ launcher\fR
.RS 4
native prompt. ex:\fB\ func = "launcher" cmd = "exec"\fR display the “exec” launcher\&.
.RE
.PP
.sp .sp
.SH "BUGS" .SH "BUGS"
WMFS isn\'t stable for now\&. So it certainly contains some bugs\&. WMFS isn\'t stable for now\&. So it certainly contains some bugs\&.
.sp .sp
.SH "AUTHORS" .SH "AUTHOR"
Martin Duquesnoy <\fIxorg62@gmail\&.com\fR\&[1]>\&. Martin Duquesnoy <\fIxorg62@gmail\&.com\fR\&[1]>\&.
.sp .sp
.SH "WWW" .SH "WWW"
Main site: \fIhttp://wmfs\&.info\fR Bug tracker: \fIhttp://bugs\&.wmfs\&.info\fR Main site: \fIhttps://github\&.com/xorg62/wmfs\fR
.PP
Wiki: \fIhttps://github\&.com/xorg62/wmfs/wiki\fR
.PP
Bug tracker: \fIhttps://github\&.com/xorg62/wmfs/issues\fR
.sp .sp
.SH "COPYING" .SH "COPYING"
WMFS is under the BSD license\&. See COPYING for more information\&. WMFS is under the BSD license\&. See COPYING for more information\&.
.sp
.SH "NOTES"
.IP " 1." 4
xorg62@gmail.com
.RS 4
\%mailto:xorg62@gmail.com
.RE .RE

View File

@ -1,5 +1,7 @@
[Desktop Entry] [Desktop Entry]
Encoding=UTF-8 Encoding=UTF-8
Type=Application
Name=wmfs Name=wmfs
Comment=Window Manager From Scratch Comment=Window Manager From Scratch
Exec=ck-launch-session wmfs TryExec=wmfs
Exec=wmfs

View File

@ -1,242 +0,0 @@
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = WMFS
PROJECT_NUMBER = devel
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = src
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \
*.h \
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor...
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references...
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool...
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
MSCGEN_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = YES
TEMPLATE_RELATIONS = YeS
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = YES
CALLER_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine...
#---------------------------------------------------------------------------
SEARCHENGINE = NO

619
wmfsrc
View File

@ -1,436 +1,228 @@
# #
# This is the default wmfs config file, copy it to # WMFS2 configuration file
# ~/.config/wmfs/wmfsrc and edit it.
# #
# Include file to split configuration # Possible file inclusion:
# @include "~/.config/wmfs/menu-wmfsrc" # @include "file"
[misc] # Multi theme section
use_xft = true [themes]
font = "dejavu-10"
raisefocus = true
focus_follow_mouse = true
focus_follow_movement = true
opacity = 255
# focus_pointer_click: click on unfocused client area: [theme]
# true -- default, set focus # No name mean default
# false -- click go to client; including dockapps # name = "default"
focus_pointer_click = true
[/misc]
[bar] font = "fixed"
bg = "#191919"
fg = "#D4D4D4"
border = true
#height = "-1"
light_shade = 0.10 # Bars
dark_shade = -0.10 bars_width = 14
bars_fg = "#AABBAA"
bars_bg = "#223322"
# Order of infobar elements: # Element tags
# t = Tag list tags_normal_fg = "#AABBAA"
# l = Layout button tags_normal_bg = "#223322"
# s = Selbar # tags_normal_statusline = ""
elements_order = "tls"
[systray] tags_sel_fg = "#223322"
# Enable/disable systray tags_sel_bg = "#AABBAA"
active = true # tags_sel_statusline = ""
# Screen of systray tags_occupied_fg = "#AABBAA"
tags_occupied_bg = "#445544"
tags_occupied_statusline = "\R[0;0;100;1;#AABBAA]"
tags_urgent_fg = "#223322"
tags_urgent_bg = "#CC5544"
# tags_urgent_statusline = ""
tags_border_color = "#112211"
tags_border_width = 1
# Frame / Client
client_normal_fg = "#AABBAA"
client_normal_bg = "#223322"
client_normal_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
client_sel_fg = "#223322"
client_sel_bg = "#AABBAA"
client_sel_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
# client_free_statusline = ""
frame_bg = "#555555"
client_titlebar_width = 12
client_border_width = 1
[/theme]
[/themes]
[bars]
# Position:
#
# 0 Top
# 1 Bottom
# 2 Hide
# Element type:
#
# t Tags
# s Statustext (will take available space)
# y Systray (can be set only ONE time among all element)
# l Launcher (will be expended at launcher use)
[bar]
position = 0
screen = 0 screen = 0
elements = "tlsy" # element order in bar
theme = "default"
[/bar]
# Spacing between tray icons # [bar]
spacing = 3 # position = 0
[/systray] # screen = 1
# elements = "ts"
# theme = "default"
# [/bar]
# Remove this section to disable the selbar. [/bars]
[selbar]
bg = "#191919"
fg = "#D4D4ff"
# Cut title length
# max_length = 25
[mouse] button = "3" func = "clientlist" [/mouse]
[mouse] button = "4" func = "client_next" [/mouse]
[mouse] button = "5" func = "client_prev" [/mouse]
[/selbar]
[/bar]
[layouts]
fg = "#191919"
bg = "#7E89A2"
# Border around the layout button.
border = true
# Value menu or switch.
system = "menu"
# Keep layout geo for free layout
keep_layout_geo = false
# Enable split mode with client_resize_<direction>
cfactor_enable_split = true
# Symbol displayed for the selected layout in the list
selected_layout_symbol = "*"
# Width of layout button
# layout_button_width = x
# Tiling layouts.
[layout] type = "tile_right" symbol = "RIGHT" [/layout]
[layout] type = "tile_left" symbol = "LEFT" [/layout]
[layout] type = "tile_top" symbol = "TOP" [/layout]
[layout] type = "tile_bottom" symbol = "BOTTOM" [/layout]
[layout] type = "tile_grid" symbol = "GRID_H" [/layout]
[layout] type = "tile_grid_vertical" symbol = "GRID_V" [/layout]
[layout] type = "mirror_vertical" symbol = "MIRROR_V" [/layout]
[layout] type = "mirror_horizontal" symbol = "MIRROR_H" [/layout]
# Other layouts.
[layout] type = "max" symbol = "MAX" [/layout]
[layout] type = "free" symbol = "FREE" [/layout]
[/layouts]
[tags] [tags]
[default_tag]
name = "new tag"
mwfact = 0.5
nmaster = 1
layout = "tile"
resizehint = false
infobar_position = "top"
split = false
[/default_tag]
# whether client_next on the last tag will send you on the first # Tag wrapping navigation
# and client_prev on the first tag will send you on the last one circular = false
tag_round = false
# Going twice on the same tag will bring you back on the previous one
tag_auto_prev = true
occupied_bg = "#003366"
occupied_fg = "#D4D4D4"
sel_fg = "#191919"
sel_bg = "#7E89A2"
urgent_bg = "#DD1111"
urgent_fg = "#000000"
# If true, number of the tag will be used for name
name_count = false
#default_name = "new tag" # deprecated, use [default_tag] instead
#default_layout = "tile_right" # deprecated, use [default_tag] instead
expose_name = "EXPOSE"
expose_layout = "tile_left"
# Border around the tag buttons.
border = true
# Hide empty tags in tag list
autohide = false
# Mouse buttons action on tag.
mouse_button_tag_sel = "1"
mouse_button_tag_transfert = "2"
mouse_button_tag_add = "3"
mouse_button_tag_next = "4"
mouse_button_tag_prev = "5"
# Use no screen option or screen = -1 to set tag on each screen
[tag] [tag]
name = "one" screen = -1
screen = 0 name = "1"
mwfact = 0.65 # statusline=""
nmaster = 1
layout = "tile_right"
resizehint = false
infobar_position = "top"
above_fc = false
split = false
#[mouse] [/mouse] Possible multi mouse section
[/tag] [/tag]
[tag] name = "two" [/tag] [tag] name = "2" [/tag]
[tag] name = "three" [/tag] [tag] name = "3" [/tag]
[tag] name = "four" [/tag] [tag] name = "4" [/tag]
[tag] name = "five" [/tag] [tag] name = "5" [/tag]
[tag] name = "six" [/tag] [tag] name = "6" [/tag]
[tag] name = "seven" [/tag] [tag] name = "7" [/tag]
[tag] name = "eight" [/tag]
[tag] name = "nine" [/tag]
[/tags]
[root]
# Command you can execute to set the background.
background_command = "xsetroot -solid black"
# Mousebinds associated to Tags element button
[mouse] button = "1" func = "tag_click" [/mouse]
[mouse] button = "4" func = "tag_next" [/mouse] [mouse] button = "4" func = "tag_next" [/mouse]
[mouse] button = "5" func = "tag_prev" [/mouse] [mouse] button = "5" func = "tag_prev" [/mouse]
[mouse] button = "3" func = "menu" cmd = "rootmenu" [/mouse]
[/root]
[/tags]
[client] [client]
client_round = true
client_auto_center = false
border_height = 3
border_shadow = true
border_normal = "#191919"
border_focus = "#003366"
place_at_mouse = false
resize_corner_normal = "#191919"
resize_corner_focus = "#003366"
set_new_win_master = true
client_tile_raise = false
new_client_get_mouse = false
# send all client that have no tag rule in this default tag # Padding between clients (default: 0) :
#default_open_tag = 4 #padding = 75
# same as above but for the screen
#default_open_screen = 1
# Space between tiled clients (px) # Give focus to new created client (default = false)
padding = 0 autofocus = false
# Modifier for mouse use theme = "default"
modifier = "Alt" key_modifier = "Super"
light_shade = 0.10 # Focus type:
dark_shade = -0.10 # enter : focus follow mouse (default)
# click : click to focus
# everything-else : disable mouse focus support
focus = enter
# *DEPRECATED* but works, see [rules] section [mouse] button = "1" func = "client_focus_click" [/mouse]
# Set automatic free or max client [mouse] button = "1" func = "mouse_swap" [/mouse]
# autofree = "xterm|MPlayer" [mouse] button = "2" func = "mouse_tab" [/mouse]
# automax = "Navigator"
[mouse] button = "1" func = "client_raise" [/mouse]
[mouse] button = "1" func = "mouse_move" [/mouse]
[mouse] button = "3" func = "client_raise" [/mouse]
[mouse] button = "3" func = "mouse_resize" [/mouse] [mouse] button = "3" func = "mouse_resize" [/mouse]
[mouse] button = "4" func = "client_focus_next_tab" [/mouse]
[mouse] button = "5" func = "client_focus_prev_tab" [/mouse]
# Remove this section to delete the titlebar.
[titlebar]
stipple = false
height = 12
fg_normal = "#7E89A2"
fg_focus = "#9F9AB3"
[mouse] button = "1" func = "client_raise" [/mouse]
[mouse] button = "1" func = "mouse_move" [/mouse]
[mouse] button = "3" func = "client_raise" [/mouse]
[mouse] button = "3" func = "mouse_resize" [/mouse]
[button]
# Available "free", "max", "tile" flags or button.
flags = "free,max,tile"
[mouse] button = "1" func = "client_kill" [/mouse]
[mouse] button = "3" func = "menu" cmd = "clientmenu" [/mouse]
[line] coord = {1, 1, 4, 1} [/line]
[line] coord = {1, 1, 1, 4} [/line]
[line] coord = {1, 4, 4, 4} [/line]
[/button]
[/titlebar]
[/client] [/client]
[rules] [rules]
# Example of rule for MPlayer
[rule] [rule]
instance = "xv" # First part of WM_CLASS # use instance = "*" for a all-clients rule
class = "MPlayer" # Seconf part of WM_CLASS, not needed if first part is correct instance = "chromium"
# role = "" # WM_WINDOW_ROLE
screen = 0 # Screen to use # role = ""
tag = 2 # Tag number of apps # name = ""
free = true # Set automatic free client # theme = "default"
max = false # Set automatic maximized client
follow_client = false # follow the client tag = 1 # 2nd tag
ignore_tags = false # ignore tag (free mode) screen = 0
free = false
tab = false
ignore_tag = false
[/rule] [/rule]
[/rules] [/rules]
[menu] [launchers]
# Default menu, binded on the root window, button 3.
[set_menu]
name = "rootmenu"
# place_at_mouse = false # command can be an uicb function or an uicb function + extension (see example)
# x = 40 y = 50 [launcher]
name = "exec"
prompt = "Run:"
# Available "center", "left", "right" menu align. Default: "center". # Example of uicb + ext:
align = "left" # command = "spawn xterm -e"
command = "spawn"
fg_focus = "#191919" bg_focus = "#7E89A2" width = 150
fg_normal = "#9F9AB3" bg_normal = "#191919" [/launcher]
[item] name = "Terminal" func = "spawn" cmd = "urxvt || xterm || gnome-terminal" [/item] [/launchers]
[item] name = "Applications" submenu = "appmenu" [/item]
[item] name = "Next tag" func = "tag_next" [/item]
[item] name = "Previous tag" func = "tag_prev" [/item]
[item] name = "Next layout" func = "layout_next" [/item]
[item] name = "Previous layout" func = "layout_prev" [/item]
[item] name = "Toggle infobar" func = "toggle_infobar_position" [/item]
[item] name = "Quit WMFS" func = "quit" [/item]
[/set_menu]
[set_menu]
name = "appmenu"
align = "left"
fg_focus = "#191919" bg_focus = "#7E89A2"
fg_normal = "#9F9AB3" bg_normal = "#191919"
[item] name = "Browser" func = "spawn" cmd = "firefox" [/item]
[item] name = "Calculator" func = "spawn" cmd = "xcalc" [/item]
[/set_menu]
[set_menu]
name = "clientmenu"
fg_focus = "#D4D4D4" bg_focus = "#003366"
fg_normal = "#D4D4D4" bg_normal = "#191919"
# Check items: possible 'check_max' or 'check_free'.
[item] name = "Close" func = "client_kill" [/item]
[item] name = "Maximize" func = "toggle_max" check = "check_max" [/item]
[item] name = "Free" func = "toggle_free" check = "check_free" [/item]
[/set_menu]
[/menu]
[launcher]
[set_launcher]
# Limit size of the launcher window (px)
width_limit = 300
name = "launcher_exec"
prompt = "Exec: "
command = "exec"
[/set_launcher]
[/launcher]
[keys] [keys]
# Reload the configuration of wmfs.
[key] mod = {"Alt", "Control"} key = "r" func = "reload" [/key]
# Open a terminal. [key] mod = {"Super"} key = "Return" func = "spawn" cmd = "urxvt || xterm" [/key]
[key] mod = {"Control"} key = "Return" func = "spawn" cmd = "xterm" [/key]
# Kill the selected client. [key] mod = {"Control", "Alt"} key = "q" func = "quit" [/key]
[key] mod = {"Alt"} key = "q" func = "client_kill" [/key] [key] mod = {"Control", "Alt"} key = "r" func = "reload" [/key]
# Quit wmfs. # Tag manipulation
[key] mod = {"Control", "Alt", "Shift"} key = "q" func = "quit" [/key] [key] mod = {"Super"} key = "F1" func = "tag_set" cmd = "0" [/key]
[key] mod = {"Super"} key = "F2" func = "tag_set" cmd = "1" [/key]
[key] mod = {"Super"} key = "F3" func = "tag_set" cmd = "2" [/key]
[key] mod = {"Super"} key = "F4" func = "tag_set" cmd = "3" [/key]
[key] mod = {"Super"} key = "F5" func = "tag_set" cmd = "4" [/key]
[key] mod = {"Super"} key = "F6" func = "tag_set" cmd = "5" [/key]
[key] mod = {"Super"} key = "F7" func = "tag_set" cmd = "6" [/key]
[key] mod = {"Super"} key = "F8" func = "tag_set" cmd = "7" [/key]
# Swap current client with the next. [key] mod = {"Super", "Shift"} key = "F1" func = "tag_client" cmd = "0" [/key]
[key] mod = {"Alt"} key = "t" func = "client_swap_next" [/key] [key] mod = {"Super", "Shift"} key = "F2" func = "tag_client" cmd = "1" [/key]
[key] mod = {"Super", "Shift"} key = "F3" func = "tag_client" cmd = "2" [/key]
[key] mod = {"Super", "Shift"} key = "F4" func = "tag_client" cmd = "3" [/key]
[key] mod = {"Super", "Shift"} key = "F5" func = "tag_client" cmd = "4" [/key]
[key] mod = {"Super", "Shift"} key = "F6" func = "tag_client" cmd = "5" [/key]
[key] mod = {"Super", "Shift"} key = "F7" func = "tag_client" cmd = "6" [/key]
[key] mod = {"Super", "Shift"} key = "F8" func = "tag_client" cmd = "7" [/key]
# Swap current client with the previous. [key] mod = {"Super"} key = "minus" func = "tag_del" [/key]
[key] mod = {"Alt", "Shift"} key = "t" func = "client_swap_prev" [/key] [key] mod = {"Super", "Shift"} key = "minus" func = "tag_new" [/key]
# Set the selected client as Master # tag function: cmd = nameofthetag
[key] mod = {"Control"} key = "m" func = "client_set_master" [/key] #[key] mod = {"Super"} key = "z" func = "tag" cmd = "2" [/key]
# Toggle maximum the selected client
[key] mod = {"Alt"} key = "m" func = "toggle_max" [/key]
# Toggle free the selected client.
[key] mod = {"Alt"} key = "f" func = "toggle_free" [/key]
# Toggle the position of the infobar.
[key] mod = {"Alt"} key = "b" func = "toggle_infobar_position" [/key]
[key] mod = {"Alt", "Shift"} key = "b" func = "toggle_infobar_display" [/key]
# Toggle the resizehint of the current tag/screen
[key] mod = {"Shift", "Control"} key = "r" func = "toggle_resizehint" [/key]
# Toggle the tag_autohide mode
[key] mod = {"Shift", "Control"} key = "t" func = "toggle_tagautohide" [/key]
# Select the next client.
[key] mod = {"Alt"} key = "Tab" func = "client_next" [/key]
# Select the previous client.
[key] mod = {"Alt","Shift"} key = "Tab" func = "client_prev" [/key]
# Select the next tag.
[key] mod = {"Control"} key = "Right" func = "tag_next" [/key] [key] mod = {"Control"} key = "Right" func = "tag_next" [/key]
# Select the previous tag.
[key] mod = {"Control"} key = "Left" func = "tag_prev" [/key] [key] mod = {"Control"} key = "Left" func = "tag_prev" [/key]
# Select the next visible tag. [key] mod = {"Control"} key = "Up" func = "screen_next" [/key]
[key] mod = {"Control","Alt"} key = "Right" func = "tag_next_visible" [/key] [key] mod = {"Control"} key = "Down" func = "screen_prev" [/key]
# Select the previous visible tag. [key] mod = {"Super"} key = "q" func = "client_close" [/key]
[key] mod = {"Control","Alt"} key = "Left" func = "tag_prev_visible" [/key]
# Set the next layout. # Focus next / prev client and next / prev tabbed client
[key] mod = {"Alt"} key = "space" func = "layout_next" [/key] [key] mod = { "Alt" } key = "Tab" func = "client_focus_next" [/key]
[key] mod = { "Alt", "Shift" } key = "Tab" func = "client_focus_prev" [/key]
# Set the previous layout. [key] mod = { "Super" } key = "Tab" func = "client_focus_next_tab" [/key]
[key] mod = {"Alt", "Shift"} key = "space" func = "layout_prev" [/key] [key] mod = { "Super", "Shift" } key = "Tab" func = "client_focus_prev_tab" [/key]
# Increase nmaster.
[key] mod = {"Alt"} key = "d" func = "set_nmaster" cmd = "+1" [/key]
# Decease nmaster.
[key] mod = {"Alt", "Shift"} key = "d" func = "set_nmaster" cmd = "-1" [/key]
#Launcher.
[key] mod = {"Alt"} key = "p" func = "launcher" cmd = "launcher_exec" [/key]
# Set the tag x.
[key] mod = {"Alt"} key = "F1" func = "tag" cmd = "1" [/key]
[key] mod = {"Alt"} key = "F2" func = "tag" cmd = "2" [/key]
[key] mod = {"Alt"} key = "F3" func = "tag" cmd = "3" [/key]
[key] mod = {"Alt"} key = "F4" func = "tag" cmd = "4" [/key]
[key] mod = {"Alt"} key = "F5" func = "tag" cmd = "5" [/key]
[key] mod = {"Alt"} key = "F6" func = "tag" cmd = "6" [/key]
[key] mod = {"Alt"} key = "F7" func = "tag" cmd = "7" [/key]
[key] mod = {"Alt"} key = "F8" func = "tag" cmd = "8" [/key]
[key] mod = {"Alt"} key = "F9" func = "tag" cmd = "9" [/key]
# Transfert selected client to x.
[key] mod = {"Alt", "Shift"} key = "F1" func = "tag_transfert" cmd ="1" [/key]
[key] mod = {"Alt", "Shift"} key = "F2" func = "tag_transfert" cmd ="2" [/key]
[key] mod = {"Alt", "Shift"} key = "F3" func = "tag_transfert" cmd ="3" [/key]
[key] mod = {"Alt", "Shift"} key = "F4" func = "tag_transfert" cmd ="4" [/key]
[key] mod = {"Alt", "Shift"} key = "F5" func = "tag_transfert" cmd ="5" [/key]
[key] mod = {"Alt", "Shift"} key = "F6" func = "tag_transfert" cmd ="6" [/key]
[key] mod = {"Alt", "Shift"} key = "F7" func = "tag_transfert" cmd ="7" [/key]
[key] mod = {"Alt", "Shift"} key = "F8" func = "tag_transfert" cmd ="8" [/key]
[key] mod = {"Alt", "Shift"} key = "F9" func = "tag_transfert" cmd ="9" [/key]
# Toggle additional tags (x) on the current tag
[key] mod = {"Alt", "Super"} key = "F1" func = "tag_toggle_additional" cmd ="1" [/key]
[key] mod = {"Alt", "Super"} key = "F2" func = "tag_toggle_additional" cmd ="2" [/key]
[key] mod = {"Alt", "Super"} key = "F3" func = "tag_toggle_additional" cmd ="3" [/key]
[key] mod = {"Alt", "Super"} key = "F4" func = "tag_toggle_additional" cmd ="4" [/key]
[key] mod = {"Alt", "Super"} key = "F5" func = "tag_toggle_additional" cmd ="5" [/key]
[key] mod = {"Alt", "Super"} key = "F6" func = "tag_toggle_additional" cmd ="6" [/key]
[key] mod = {"Alt", "Super"} key = "F7" func = "tag_toggle_additional" cmd ="7" [/key]
[key] mod = {"Alt", "Super"} key = "F8" func = "tag_toggle_additional" cmd ="8" [/key]
[key] mod = {"Alt", "Super"} key = "F9" func = "tag_toggle_additional" cmd ="9" [/key]
# change screen
[key] mod = {"Super"} key = "Tab" func = "screen_next" [/key]
[key] mod = {"Super", "Shift"} key = "Tab" func = "screen_prev" [/key]
# swap client in the next/prev screen
[key] mod = {"Super", "Shift"} key = "a" func = "client_screen_next" [/key]
[key] mod = {"Super", "Shift"} key = "z" func = "client_screen_prev" [/key]
# Toggle tag explose
[key] mod = {"Alt"} key = "e" func = "toggle_tag_expose" [/key]
# Toggle split mode
[key] mod = {"Alt"} key = "s" func = "split_toggle" [/key]
# Focus next client with direction # Focus next client with direction
[key] mod = {"Alt"} key = "h" func = "client_focus_left" [/key] [key] mod = {"Alt"} key = "h" func = "client_focus_left" [/key]
@ -438,38 +230,55 @@
[key] mod = {"Alt"} key = "k" func = "client_focus_top" [/key] [key] mod = {"Alt"} key = "k" func = "client_focus_top" [/key]
[key] mod = {"Alt"} key = "j" func = "client_focus_bottom" [/key] [key] mod = {"Alt"} key = "j" func = "client_focus_bottom" [/key]
# Swap next client with direction # swap next client with direction:
[key] mod = {"Control"} key = "h" func = "client_swap_left" [/key] [key] mod = {"Control", "Shift"} key = "h" func = "client_swap_left" [/key]
[key] mod = {"Control"} key = "l" func = "client_swap_right" [/key] [key] mod = {"Control", "Shift"} key = "l" func = "client_swap_right" [/key]
[key] mod = {"Control"} key = "k" func = "client_swap_top" [/key] [key] mod = {"Control", "Shift"} key = "k" func = "client_swap_top" [/key]
[key] mod = {"Control"} key = "j" func = "client_swap_bottom" [/key] [key] mod = {"Control", "Shift"} key = "j" func = "client_swap_bottom" [/key]
# Move next splitted client with direction
[key] mod = {"Control", "Shift"} key = "h" func = "split_move_left" [/key]
[key] mod = {"Control", "Shift"} key = "l" func = "split_move_right" [/key]
[key] mod = {"Control", "Shift"} key = "k" func = "split_move_top" [/key]
[key] mod = {"Control", "Shift"} key = "j" func = "split_move_bottom" [/key]
# Resize selected tiled client with direction # Resize selected tiled client with direction
[key] mod = {"Super"} key = "h" func = "client_resize_left" cmd = "20" [/key] [key] mod = {"Super"} key = "h" func = "client_resize_left" cmd = "20" [/key]
[key] mod = {"Super"} key = "l" func = "client_resize_right" cmd = "20" [/key] [key] mod = {"Super"} key = "l" func = "client_resize_left" cmd = "-20" [/key]
[key] mod = {"Super"} key = "k" func = "client_resize_top" cmd = "20" [/key] [key] mod = {"Super"} key = "k" func = "client_resize_top" cmd = "20" [/key]
[key] mod = {"Super"} key = "j" func = "client_resize_bottom" cmd = "20" [/key] [key] mod = {"Super"} key = "j" func = "client_resize_top" cmd = "-20" [/key]
[key] mod = { "Super", "Control"} key = "h" func = "client_resize_right" cmd = "-20" [/key] [key] mod = {"Super", "Control"} key = "h" func = "client_resize_right" cmd = "-20" [/key]
[key] mod = { "Super", "Control"} key = "l" func = "client_resize_left" cmd = "-20" [/key] [key] mod = {"Super", "Control"} key = "l" func = "client_resize_right" cmd = "20" [/key]
[key] mod = { "Super", "Control"} key = "k" func = "client_resize_bottom" cmd = "-20" [/key] [key] mod = {"Super", "Control"} key = "k" func = "client_resize_bottom" cmd = "-20" [/key]
[key] mod = { "Super", "Control"} key = "j" func = "client_resize_top" cmd = "-20" [/key] [key] mod = {"Super", "Control"} key = "j" func = "client_resize_bottom" cmd = "20" [/key]
# Tabbing command
[key] mod = {"Alt", "Shift"} key = "h" func = "client_tab_left" [/key]
[key] mod = {"Alt", "Shift"} key = "l" func = "client_tab_right" [/key]
[key] mod = {"Alt", "Shift"} key = "k" func = "client_tab_top" [/key]
[key] mod = {"Alt", "Shift"} key = "j" func = "client_tab_bottom" [/key]
[key] mod = {"Alt", "Shift"} key = "u" func = "client_untab" [/key]
[key] mod = {"Super"} key = "t" func = "client_tab_next_opened" [/key]
# Layout manipulation
[key] mod = {"Super"} key = "m" func = "layout_vmirror" [/key]
[key] mod = {"Super", "Shift"} key = "m" func = "layout_hmirror" [/key]
[key] mod = {"Super"} key = "r" func = "layout_rotate_right" [/key]
[key] mod = {"Super", "Shift"} key = "r" func = "layout_rotate_left" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "h" func = "layout_integrate_left" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "j" func = "layout_integrate_bottom" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "k" func = "layout_integrate_top" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "l" func = "layout_integrate_right" [/key]
# Layout set historic travelling function (TESTING)
[key] mod = {"Super"} key = "o" func = "layout_prev_set" [/key]
[key] mod = {"Super", "Shift"} key = "o" func = "layout_next_set" [/key]
# Toggle client free/tile
[key] mod = {"Super"} key = "f" func = "client_toggle_free" [/key]
# Toggle client ignore_tag
[key] mod = {"Super", "Shift"} key = "f" func = "client_toggle_ignore_tag" [/key]
# Toggle infobar visibility
[key] mod = {"Super", "Shift"} key = "h" func = "infobar_toggle_hide" cmd = "default" [/key]
# Launcher
[key] mod = {"Super"} key = "p" func = "launcher" cmd = "exec" [/key]
# unlisted fonctions that can be used in [key] func = ""
# client_ignore_tag # Toggle the client in ignore_tag (display the client on all tags)
# tag_prev_sel # go back to the previous selected tag
# tag_transfert_{next, prev}
# tag_urgent # go to the urgent tag
# tag_swap_{next, prev} # swap tag with the previous/next one
# tag_last # go to the last tag
# tag_stay_last # toggle the current tag as the last one
# toggle_abovefc
# screen_prev_sel # go to the previous screen selected
# set_layout # set layout. need to be called with cmd = "<layout_name>"
# ignore_next_client_rules # ignore the rule the next time a rule is called
[/keys] [/keys]