Compare commits

...

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

68 changed files with 11486 additions and 8622 deletions

12
.gitignore vendored
View File

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

134
CMakeLists.txt Normal file
View File

@ -0,0 +1,134 @@
#
# 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,3 +24,4 @@
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.

View File

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

44
README
View File

@ -1 +1,43 @@
next WMFS dev branch.
ABOUT :
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 Normal file
View File

@ -0,0 +1,24 @@
,
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

114
configure vendored
View File

@ -11,77 +11,81 @@ MANPREFIX="$PREFIX/man"
XDG_CONFIG_DIR="$PREFIX/etc/xdg"
while true; do
case "$1" in
--without-xinerama)
USE_XINERAMA=""; shift;;
--without-imlib2)
USE_IMLIB2=""; shift;;
--prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1
PREFIX=$2; shift 2;;
--man-prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1
MANPREFIX=$2; shift 2;;
--xdg-config-dir)
[ -z "$2" ] && echo "Missing argument" && exit 1
XDG_CONFIG_DIR=$2; shift 2;;
--help|-h)
echo "Usage: ./configure [options]
case "$1" in
--without-xinerama)
USE_XINERAMA=""; shift;;
--without-xrandr)
USE_XRANDR=""; shift;;
--without-imlib2)
USE_IMLIB2=""; shift;;
--without-xft)
USE_XFT=""; shift;;
--prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1
PREFIX=$2; shift 2;;
--xdg-config-dir)
[ -z "$2" ] && echo "Missing argument" && exit 1
XDG_CONFIG_DIR=$2; shift 2;;
--man-prefix)
[ -z "$2" ] && echo "Missing argument" && exit 1
MANPREFIX=$2; shift 2;;
--help|-h)
echo "Usage: ./configure [options]
--without-imlib2 : compile without imlib2 support
--without-xrandr : compile without xrandr support
--without-xinerama : compile without xinerama support
--without-imlib2 : compile without imlib2 support
--without-xft : compile without xft support
--prefix DIRECTORY : install binary with specified prefix (default $PREFIX)
--man-prefix DIRECTORY : install binary with specified prefix (default $PREFIX)
--xdg-config-dir DIRECTORY : install configuration to specified directory (default $XDG_CONFIG_DIR)"
exit 0;;
*) break;;
esac
--xdg-config-dir DIRECTORY : install configuration to specified directory (default $XDG_CONFIG_DIR)
--man-prefix DIRECTORY : install man page to specified prefix (default $MANPREFIX)"
exit 0;;
*) break;;
esac
done
LIBS="$LIBS $USE_XINERAMA $USE_IMLIB2"
LIBS="$LIBS $USE_XINERAMA $USE_XRANDR $USE_IMLIB2 $USE_XFT"
which pkg-config > /dev/null 2>&1
which pkg-config >/dev/null 2>&1
if [ $? -eq 0 ];
then
CFLAGS=`pkg-config --cflags-only-I $LIBS`
LDFLAGS=`pkg-config --libs $LIBS`
CFLAGS=`pkg-config --cflags-only-I $LIBS`
LDFLAGS=`pkg-config --libs $LIBS`
else
# Try to use some known paths
case $OS in
FreeBSD)
CFLAGS="-I/usr/local/include"
LDFLAGS="-L/usr/local/lib";;
OpenBSD)
CFLAGS="-I/usr/X11R6/include -I/usr/local/include"
LDFLAGS="-L/usr/X11R6/lib -L/usr/local/lib";;
NetBSD)
CFLAGS="-I/usr/X11R7/include -I/usr/pkg/include"
LDFLAGS="-L/usr/X11R7/lib -L/usr/pkg/lib";;
Linux)
CFLAGS=""
LDFLAGS=""
;;
*)
echo "No default CFLAGS and LDFLAGS found for your OS, feel free to contribute or install pkg-config :)"
exit 1;;
esac
case $OS in
FreeBSD)
CFLAGS="-I/usr/local/include -I/usr/local/include/freetype2"
LDFLAGS="-L/usr/local/lib";;
OpenBSD)
CFLAGS="-I/usr/X11R6/include -I/usr/X11R6/include/freetype2 -I/usr/local/include"
LDFLAGS="-L/usr/X11R6/lib -L/usr/local/lib";;
NetBSD)
CFLAGS="-I/usr/X11R7/include -I/usr/X11R7/include/freetype2 -I/usr/local/include"
LDFLAGS="-L/usr/X11R7/lib -L/usr/local/lib";;
Linux)
CFLAGS="-I/usr/include/freetype2"
LDFLAGS=""
;;
*)
echo "No default CFLAGS and LDFLAGS found for your OS, feel free to contribute or install pkg-config :)"
exit 1;;
esac
LDFLAGS="$LDFLAGS -lX11"
LDFLAGS="$LDFLAGS -lX11"
[ -n "$USE_XINERAMA" ] && LDFLAGS="$LDFLAGS -lXinerama"
[ -n "$USE_IMLIB2" ] && LDFLAGS="$LDFLAGS -lImlib2"
[ -n "$USE_XINERAMA" ] && LDFLAGS="$LDFLAGS -lXinerama"
[ -n "$USE_XRANDR" ] && LDFLAGS="$LDFLAGS -lXrandr"
[ -n "$USE_IMLIB2" ] && LDFLAGS="$LDFLAGS -lImlib2"
[ -n "$USE_XFT" ] && LDFLAGS="$LDFLAGS -lXft -lfreetype"
fi
[ -n "$USE_XINERAMA" ] && CFLAGS="$CFLAGS -DHAVE_XINERAMA"
[ -n "$USE_IMLIB2" ] && CFLAGS="$CFLAGS -DHAVE_IMLIB2"
[ -n "$USE_XRANDR" ] && CFLAGS="$CFLAGS -DHAVE_XRANDR"
[ -n "$USE_IMLIB2" ] && CFLAGS="$CFLAGS -DHAVE_IMLIB"
[ -n "$USE_XFT" ] && CFLAGS="$CFLAGS -DHAVE_XFT"
# 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
LDFLAGS="$LDFLAGS -lpthread"
cat > Makefile << EOF
PREFIX=$PREFIX

45
debian/changelog vendored
View File

@ -1,45 +0,0 @@
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
View File

@ -1 +0,0 @@
8

16
debian/control vendored
View File

@ -1,16 +0,0 @@
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
View File

@ -1,54 +0,0 @@
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
View File

@ -1 +0,0 @@
README

16
debian/rules vendored
View File

@ -1,16 +0,0 @@
#!/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 $@

View File

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

1
debian/wmfs.install vendored
View File

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

View File

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

1
debian/wmfs.wm vendored
View File

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

View File

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

View File

@ -1,107 +1,241 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* barwin.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"
#include "barwin.h"
#include "util.h"
/** Create a barwin
/** Create a BarWindow
* \param parent Parent window of the BarWindow
* \param x X position
* \param y Y position
* \param w barwin Width
* \param h barwin Height
* \param color barwin color
* \param w BarWindow Width
* \param h BarWindow Height
* \param color BarWindow color
* \param entermask bool for know if the EnterMask mask is needed
* \return The BarWindow pointer
*/
struct barwin*
barwin_new(Window parent, int x, int y, int w, int h, Color fg, Color bg, bool entermask)
BarWindow*
barwin_create(Window parent,
int x,
int y,
int w,
int h,
uint bg,
char *fg,
bool entermask,
bool stipple,
bool border)
{
struct barwin *b = (struct barwin*)xcalloc(1, sizeof(struct barwin));
XSetWindowAttributes at =
{
.override_redirect = true,
.background_pixmap = ParentRelative,
.event_mask = BARWIN_MASK
};
XSetWindowAttributes at;
BarWindow *bw;
/* Allocate memory */
bw = zcalloc(sizeof(*bw));
/* Barwin attributes */
at.override_redirect = True;
at.background_pixmap = ParentRelative;
at.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
|ButtonMask|MouseMask
|ExposureMask|VisibilityChangeMask
|StructureNotifyMask|SubstructureRedirectMask;
if(entermask)
at.event_mask |= BARWIN_ENTERMASK;
at.event_mask |= EnterWindowMask|LeaveWindowMask|FocusChangeMask;
/* Create window */
b->win = XCreateWindow(W->dpy, parent,
x, y, w, h,
0, W->xdepth,
CopyFromParent,
DefaultVisual(W->dpy, W->xscreen),
BARWIN_WINCW,
&at);
bw->win = XCreateWindow(dpy, parent, x, y, w, h, 0, DefaultDepth(dpy, SCREEN),
CopyFromParent, DefaultVisual(dpy, SCREEN),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &at);
bw->dr = XCreatePixmap(dpy, parent, w, h, DefaultDepth(dpy, SCREEN));
b->dr = XCreatePixmap(W->dpy, parent, w, h, W->xdepth);
/* His border */
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 */
b->geo.x = x;
b->geo.y = y;
b->geo.w = w;
b->geo.h = h;
b->bg = bg;
b->fg = fg;
SLIST_INIT(&b->mousebinds);
SLIST_INIT(&b->statusmousebinds);
bw->geo.x = x;
bw->geo.y = y;
bw->geo.width = w;
bw->geo.height = h;
bw->bg = bg;
bw->fg = fg;
FLAGAPPLY(bw->flags, stipple, StippleFlag);
bw->stipple_color = 0xffffffff;
/* Attach */
SLIST_INSERT_HEAD(&W->h.barwin, b, next);
SLIST_INSERT_HEAD(&bwhead, bw, next);
return b;
return bw;
}
/** Delete a barwin
* \param bw barwin pointer
/** Draw text in a Barwindow
*/
void
barwin_remove(struct barwin *b)
barwin_draw_text(BarWindow *bw, int x, int y, char *text)
{
SLIST_REMOVE(&W->h.barwin, b, barwin, next);
/* Background color of the text if there is stipple */
if(bw->flags & StippleFlag)
draw_rectangle(bw->dr, x - 4, 0, textw(text) + 8, bw->geo.height, bw->bg);
XSelectInput(W->dpy, b->win, NoEventMask);
XDestroyWindow(W->dpy, b->win);
XFreePixmap(W->dpy, b->dr);
/* Draw text */
draw_text(bw->dr, x, y, bw->fg, text);
free(b);
barwin_refresh(bw);
return;
}
/** Resize a barwin
* \param bw barwin pointer
void
barwin_color_set(BarWindow *bw, uint bg, char *fg)
{
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 h Height
*/
void
barwin_resize(struct barwin *b, int w, int h)
barwin_resize(BarWindow *bw, int w, int h)
{
if(bw->geo.width == w && bw->geo.height == h)
return;
/* Frame */
XFreePixmap(W->dpy, b->dr);
XFreePixmap(dpy, bw->dr);
b->dr = XCreatePixmap(W->dpy, W->root, w, h, W->xdepth);
bw->dr = XCreatePixmap(dpy, ROOT,
w - ((bw->flags & BordFlag) ? SHADH : 0),
h - ((bw->flags & BordFlag) ? SHADH : 0),
DefaultDepth(dpy, SCREEN));
b->geo.w = w;
b->geo.h = h;
bw->geo.width = w;
bw->geo.height = h;
XResizeWindow(W->dpy, b->win, w, h);
XResizeWindow(dpy, bw->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 barwin Color
* \param bw barwin pointer
/** Refresh the BarWindow Color
* \param bw BarWindow pointer
*/
void
barwin_refresh_color(struct barwin *b)
barwin_refresh_color(BarWindow *bw)
{
XSetForeground(W->dpy, W->gc, b->bg);
XFillRectangle(W->dpy, b->dr, W->gc, 0, 0, b->geo.w, b->geo.h);
XSetForeground(dpy, gc, bw->bg);
XFillRectangle(dpy, bw->dr, gc, 0, 0, bw->geo.width, bw->geo.height);
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;
}

View File

@ -1,38 +0,0 @@
/*
* 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 */

279
src/cfactor.c Normal file
View File

@ -0,0 +1,279 @@
/*
* 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

View File

@ -1,217 +0,0 @@
/*
* 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 */

223
src/color.c Normal file
View File

@ -0,0 +1,223 @@
/*
* 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

View File

@ -1,167 +0,0 @@
/*
* 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 */

285
src/draw.c Normal file
View File

@ -0,0 +1,285 @@
/*
* 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;
}

View File

@ -1,113 +0,0 @@
/*
* 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 */

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
/*
* 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,160 +1,186 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* ewmh.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 "ewmh.h"
#include "util.h"
#include "screen.h"
#include "client.h"
#include "wmfs.h"
/* Taken From standards.freedesktop.org */
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
/** Init ewmh atoms
*/
void
ewmh_init(void)
ewmh_init_hints(void)
{
int b = 1;
int i = 1, s, j, showing_desk = 0;
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 */
W->net_atom[wm_state] = ATOM("WM_STATE");
W->net_atom[wm_class] = ATOM("WM_CLASS");
W->net_atom[wm_name] = ATOM("WM_NAME");
W->net_atom[net_supported] = ATOM("_NET_SUPPORTED");
W->net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST");
W->net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS");
W->net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS");
W->net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP");
W->net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES");
W->net_atom[net_desktop_geometry] = ATOM("_NET_DESKTOP_GEOMETRY");
W->net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW");
W->net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW");
W->net_atom[net_wm_name] = ATOM("_NET_WM_NAME");
W->net_atom[net_wm_pid] = ATOM("_NET_WM_PID");
W->net_atom[net_wm_desktop] = ATOM("_NET_WM_DESKTOP");
W->net_atom[net_showing_desktop] = ATOM("_NET_SHOWING_DESKTOP");
W->net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME");
W->net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE");
W->net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK");
W->net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY");
W->net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL");
W->net_atom[net_wm_window_type_desktop] = ATOM("_NET_WM_WINDOW_TYPE_DESKTOP");
W->net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK");
W->net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH");
W->net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
W->net_atom[net_wm_icon] = ATOM("_NET_WM_ICON");
W->net_atom[net_wm_state] = ATOM("_NET_WM_STATE");
W->net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN");
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");
W->net_atom[net_wm_state_hidden] = ATOM("_NET_WM_STATE_HIDDEN");
W->net_atom[net_system_tray_s] = ATOM("_NET_SYSTEM_TRAY_S0");
W->net_atom[net_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
W->net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA");
W->net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL");
W->net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION");
W->net_atom[xembed] = ATOM("_XEMBED");
W->net_atom[xembedinfo] = ATOM("_XEMBED_INFO");
W->net_atom[manager] = ATOM("MANAGER");
W->net_atom[utf8_string] = ATOM("UTF8_STRING");
net_atom[net_supported] = ATOM("_NET_SUPPORTED");
net_atom[net_client_list] = ATOM("_NET_CLIENT_LIST");
net_atom[net_frame_extents] = ATOM("_NET_FRAME_EXTENTS");
net_atom[net_number_of_desktops] = ATOM("_NET_NUMBER_OF_DESKTOPS");
net_atom[net_current_desktop] = ATOM("_NET_CURRENT_DESKTOP");
net_atom[net_desktop_names] = ATOM("_NET_DESKTOP_NAMES");
net_atom[net_desktop_geometry] = ATOM("_NET_DESKTOP_GEOMETRY");
net_atom[net_active_window] = ATOM("_NET_ACTIVE_WINDOW");
net_atom[net_close_window] = ATOM("_NET_CLOSE_WINDOW");
net_atom[net_wm_name] = ATOM("_NET_WM_NAME");
net_atom[net_wm_pid] = ATOM("_NET_WM_PID");
net_atom[net_wm_desktop] = ATOM("_NET_WM_DESKTOP");
net_atom[net_showing_desktop] = ATOM("_NET_SHOWING_DESKTOP");
net_atom[net_wm_icon_name] = ATOM("_NET_WM_ICON_NAME");
net_atom[net_wm_window_type] = ATOM("_NET_WM_WINDOW_TYPE");
net_atom[net_supporting_wm_check] = ATOM("_NET_SUPPORTING_WM_CHECK");
net_atom[net_wm_window_opacity] = ATOM("_NET_WM_WINDOW_OPACITY");
net_atom[net_wm_window_type_normal] = ATOM("_NET_WM_WINDOW_TYPE_NORMAL");
net_atom[net_wm_window_type_dock] = ATOM("_NET_WM_WINDOW_TYPE_DOCK");
net_atom[net_wm_window_type_splash] = ATOM("_NET_WM_WINDOW_TYPE_SPLASH");
net_atom[net_wm_window_type_dialog] = ATOM("_NET_WM_WINDOW_TYPE_DIALOG");
net_atom[net_wm_icon] = ATOM("_NET_WM_ICON");
net_atom[net_wm_state] = ATOM("_NET_WM_STATE");
net_atom[net_wm_state_fullscreen] = ATOM("_NET_WM_STATE_FULLSCREEN");
net_atom[net_wm_state_sticky] = ATOM("_NET_WM_STATE_STICKY");
net_atom[net_wm_state_demands_attention] = ATOM("_NET_WM_STATE_DEMANDS_ATTENTION");
net_atom[net_wm_system_tray_opcode] = ATOM("_NET_SYSTEM_TRAY_OPCODE");
net_atom[net_system_tray_message_data] = ATOM("_NET_SYSTEM_TRAY_MESSAGE_DATA");
net_atom[net_system_tray_visual] = ATOM("_NET_SYSTEM_TRAY_VISUAL");
snprintf(systray_atom, sizeof(systray_atom), "_NET_SYSTEM_TRAY_S%d", 0/*SCREEN*/);
net_atom[net_system_tray_s] = ATOM(systray_atom);
net_atom[net_system_tray_orientation] = ATOM("_NET_SYSTEM_TRAY_ORIENTATION");
net_atom[xembed] = ATOM("_XEMBED");
net_atom[xembedinfo] = ATOM("_XEMBED_INFO");
net_atom[manager] = ATOM("MANAGER");
net_atom[utf8_string] = ATOM("UTF8_STRING");
/* WMFS hints */
W->net_atom[wmfs_running] = ATOM("_WMFS_RUNNING");
W->net_atom[wmfs_focus] = ATOM("_WMFS_FOCUS");
W->net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS");
W->net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN");
W->net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT");
W->net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG");
W->net_atom[wmfs_tag_list] = ATOM("_WMFS_TAG_LIST");
W->net_atom[wmfs_current_screen] = ATOM("_WMFS_CURRENT_SCREEN");
W->net_atom[wmfs_current_layout] = ATOM("_WMFS_CURRENT_LAYOUT");
W->net_atom[wmfs_function] = ATOM("_WMFS_FUNCTION");
W->net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
net_atom[wmfs_running] = ATOM("_WMFS_RUNNING");
net_atom[wmfs_update_hints] = ATOM("_WMFS_UPDATE_HINTS");
net_atom[wmfs_set_screen] = ATOM("_WMFS_SET_SCREEN");
net_atom[wmfs_screen_count] = ATOM("_WMFS_SCREEN_COUNT");
net_atom[wmfs_current_tag] = ATOM("_WMFS_CURRENT_TAG");
net_atom[wmfs_tag_list] = ATOM("_WMFS_TAG_LIST");
net_atom[wmfs_current_screen] = ATOM("_WMFS_CURRENT_SCREEN");
net_atom[wmfs_current_layout] = ATOM("_WMFS_CURRENT_LAYOUT");
net_atom[wmfs_mwfact] = ATOM("_WMFS_MWFACT");
net_atom[wmfs_nmaster] = ATOM("_WMFS_NMASTER");
net_atom[wmfs_function] = ATOM("_WMFS_FUNCTION");
net_atom[wmfs_cmd] = ATOM("_WMFS_CMD");
net_atom[wmfs_font] = ATOM("_WMFS_FONT");
XChangeProperty(W->dpy, W->root, W->net_atom[net_supported], XA_ATOM, 32,
PropModeReplace, (unsigned char*)W->net_atom, net_last);
/* Multi atom _WMFS_STATUSTEXT_<screennum> */
for(j = 0; j < s; ++j)
{
sprintf(st, "_WMFS_STATUSTEXT_%d", j);
net_atom[wmfs_statustext + j] = ATOM(st);
}
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_running], XA_CARDINAL, 32,
PropModeReplace, (unsigned char*)&b, 1);
XChangeProperty(dpy, ROOT, net_atom[net_supported], XA_ATOM, 32,
PropModeReplace, (uchar*)net_atom, net_last + s);
XChangeProperty(dpy, ROOT, net_atom[wmfs_running], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&i, 1);
/* Set _NET_SUPPORTING_WM_CHECK */
XChangeProperty(W->dpy, W->root, W->net_atom[net_supporting_wm_check], XA_WINDOW, 32,
PropModeReplace, (unsigned char*)&W->root, 1);
XChangeProperty(dpy, ROOT, net_atom[net_supporting_wm_check], XA_WINDOW, 32,
PropModeReplace, (uchar*)&ROOT, 1);
XChangeProperty(W->dpy, W->root, ATOM("WM_CLASS"), XA_STRING, 8,
PropModeReplace, (unsigned char*)&"wmfs", 4);
XChangeProperty(dpy, ROOT, net_atom[net_wm_name], net_atom[utf8_string], 8,
PropModeReplace, (uchar*)&rootn, strlen(rootn));
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
PropModeReplace, (unsigned char*)&"wmfs2", 5);
XChangeProperty(dpy, ROOT, ATOM("WM_CLASS"), XA_STRING, 8,
PropModeReplace, (uchar*)&class, strlen(class));
/*
/* Set _NET_WM_PID */
XChangeProperty(dpy, ROOT, net_atom[net_wm_pid], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&pid, 1);
* Set _NET_WM_PID
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_pid], XA_CARDINAL, 32,
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);
*/
/* Set _NET_SHOWING_DESKTOP */
XChangeProperty(dpy, ROOT, net_atom[net_showing_desktop], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&showing_desk, 1);
return;
}
/** Send ewmh message
*/
void
ewmh_set_wm_state(Window w, int state)
ewmh_send_message(Window d, Window w, char *atom, long d0, long d1, long d2, long d3, long d4)
{
unsigned char d[] = { state, None };
XChangeProperty(W->dpy, w, W->net_atom[wm_state],
W->net_atom[wm_state], 32, PropModeReplace, d, 2);
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(dpy, d, False, StructureNotifyMask, (XEvent*)&e);
XSync(dpy, False);
return;
}
/*
* _NET_CLIENT_LIST
*/
void
ewmh_get_client_list(void)
{
Window *list;
struct client *c;
int win_n = 0;
SLIST_FOREACH(c, &W->h.client, next)
++win_n;
list = xcalloc(win_n, sizeof(Window));
win_n = 0;
SLIST_FOREACH(c, &W->h.client, next)
list[win_n++] = c->win;
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
ewmh_get_xembed_state(Window win)
{
Atom rf;
int f;
ulong n, il;
long ret = 0;
unsigned long n, il;
unsigned char *data = NULL;
uchar *data = NULL;
if(XGetWindowProperty(W->dpy, win, W->net_atom[xembedinfo], 0L, 2, False,
W->net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
if(XGetWindowProperty(dpy, win, net_atom[xembedinfo], 0L, 2, False,
net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
return 0;
if(rf == W->net_atom[xembedinfo] && n == 2)
if(rf == net_atom[xembedinfo] && n == 2)
ret = (long)data[1];
if(n && data)
@ -163,216 +189,263 @@ ewmh_get_xembed_state(Window win)
return ret;
}
/** Get the number of desktop (tag)
*/
void
ewmh_update_wmfs_props(void)
ewmh_get_number_of_desktop(void)
{
struct screen *s;
int i, ns = 0;
long *cts = NULL;
int c = 0, i;
SLIST_FOREACH(s, &W->h.screen, next)
++ns;
for(i = 0; i < screen_count(); ++i)
c += conf.ntag[i];
cts = xcalloc(ns, sizeof(long));
XChangeProperty(dpy, ROOT, net_atom[net_number_of_desktops], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&c, 1);
for(i = 0; i < ns; ++i)
{
s = screen_gb_id(i);
cts[i] = (s->seltag ? s->seltag->id : 0);
}
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], XA_CARDINAL, 32,
PropModeReplace, (unsigned char*)cts, ns);
if(W->client)
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_focus], XA_WINDOW, 32,
PropModeReplace, (unsigned char*)&W->client->win, 1);
free(cts);
return;
}
/** Get the current desktop
*/
void
ewmh_manage_state(long data[], struct client *c)
ewmh_update_current_tag_prop(void)
{
/* _NET_WM_STATE_FULLSCREEN */
if(data[1] == (long)W->net_atom[net_wm_state_fullscreen]
|| data[2] == (long)W->net_atom[net_wm_state_fullscreen])
{
if(data[0] == _NET_WM_STATE_ADD
|| (data[0] == _NET_WM_STATE_TOGGLE && !(c->flags & CLIENT_FULLSCREEN)))
{
c->flags |= CLIENT_FULLSCREEN;
int t;
char s[8] = { 0 };
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);
screen_get_sel();
t = seltag[selscreen] - 1;
if(c->tag)
client_focus(c);
/* Get current desktop (tag) */
XChangeProperty(dpy, ROOT, net_atom[net_current_desktop], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&t, 1);
XRaiseWindow(W->dpy, c->win);
}
else
{
c->flags &= ~CLIENT_FULLSCREEN;
/* 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));
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
(unsigned char*)0, 0);
XReparentWindow(W->dpy, c->win, c->frame, c->wgeo.x, c->wgeo.y);
sprintf(s, "%.3f", tags[selscreen][t + 1].mwfact);
if(c->flags & CLIENT_FREE)
client_moveresize(c, &c->geo);
else
layout_fix_hole(c);
}
}
/* 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;
}
bool
ewmh_manage_state_sticky(Window win)
/** 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));
pos += strlen(tags[s][i].name);
str[pos] = '\0';
}
XChangeProperty(dpy, ROOT, net_atom[net_desktop_names], net_atom[utf8_string], 8,
PropModeReplace, (uchar*)str, pos);
for(i = 0; i < pos; ++i)
if(str[i] == '\0' && i < pos - 1)
str[i] = ' ';
XChangeProperty(dpy, ROOT, net_atom[wmfs_tag_list], net_atom[utf8_string], 8,
PropModeReplace, (uchar*)str, pos);
free(str);
return;
}
/** Manage _NET_DESKTOP_GEOMETRY
*/
void
ewmh_set_desktop_geometry(void)
{
long data[2] = { MAXW, MAXH };
XChangeProperty(dpy, ROOT, net_atom[net_desktop_geometry], XA_CARDINAL, 32,
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))
{
c->screen = screen_get_with_geo(c->geo.x, c->geo.y);
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;
if(c->flags & FreeFlag)
c->ogeo = c->geo;
c->flags |= (FSSFlag | MaxFlag);
client_raise(c);
client_focus(c);
XUnmapWindow(dpy, c->frame);
}
else if(data_l[0] == _NET_WM_STATE_REMOVE && (c->flags & FSSFlag))
{
XChangeProperty(dpy, c->win, net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace, (uchar *)0, 0);
c->flags &= ~(FSSFlag | MaxFlag);
client_map(c);
XReparentWindow(dpy, c->win, c->frame, BORDH, TBARH);
client_moveresize(c, c->tmp_geo, False);
}
}
/* 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;
}
/** Manage the client hints
*\param c Client pointer
*/
void
ewmh_manage_window_type(Client *c)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
bool is_sticky = false;
ulong n, il, i;
uchar *data = NULL;
long ldata[5] = { 0 };
if(XGetWindowProperty(W->dpy, 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)
{
/* manage _NET_WM_STATE_STICKY */
if(atom[i] == W->net_atom[net_wm_state_sticky])
{
XWindowAttributes at;
XMapWindow(W->dpy, win);
XMapSubwindows(W->dpy, win);
if(XGetWindowAttributes(W->dpy, win, &at))
{
struct geo g;
if(at.x < W->screen->ugeo.x)
g.x = W->screen->ugeo.x;
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);
}
return is_sticky;
}
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,
if(XGetWindowProperty(dpy, c->win, 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_DOCK & _NET_WM_WINDOW_TYPE_SPLASH */
if(atom[i] == net_atom[net_wm_window_type_dock]
|| atom[i] == net_atom[net_wm_window_type_splash])
{
/* Unmap frame, decoration.. */
client_unmap(c);
/* Map only window */
XMapWindow(dpy, c->win);
/* Reparent it to ROOT win */
XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y);
XRaiseWindow(dpy, c->win);
c->flags |= DockFlag;
}
/* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
if(atom[i] == W->net_atom[net_wm_window_type_dialog])
c->flags |= CLIENT_FREE;
else if(atom[i] == net_atom[net_wm_window_type_dialog])
{
c->flags |= FreeFlag;
c->flags &= ~(TileFlag | MaxFlag | LMaxFlag);
client_moveresize(c, c->ogeo, True);
client_focus(c);
layout_func(selscreen, seltag[selscreen]);
}
}
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,
/* Get NET_WM_STATE set without sending client message event */
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)
{
/* 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;
}
ldata[0] = _NET_WM_STATE_ADD;
ldata[1] = atom[i];
ewmh_manage_net_wm_state(ldata, c);
}
XFree(data);
}
return is_desktop;
return;
}

View File

@ -1,131 +0,0 @@
/*
* 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 */

View File

@ -1,19 +0,0 @@
/*
* 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 */

320
src/frame.c Normal file
View File

@ -0,0 +1,320 @@
/*
* 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

View File

@ -1,93 +0,0 @@
/*
* 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 */

227
src/init.c Normal file
View File

@ -0,0 +1,227 @@
/*
* 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,110 +1,127 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <X11/Xutil.h>
* launcher.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"
#include "event.h"
#include "util.h"
#include "infobar.h"
#include "config.h"
static int
qsort_string_compare(const void * a, const void * b)
/*
* Just search command in PATH.
* Return the characters to complete the command.
*/
static char *
complete_on_command(char *start, size_t hits)
{
return (strcmp(*(char **)a, *(char **)b));
}
static char **
complete_on_command(char *start)
{
struct dirent *content;
char *path;
char *dirname;
char *ret = NULL;
DIR *dir;
char **paths, *path, *p, **namelist = NULL;
int i, count;
struct dirent *content;
if(!(path = getenv("PATH")) || !start)
return NULL;
char **namelist = NULL;
int n = 0, i;
/* split PATH into paths */
path = p = xstrdup(path);
if (!getenv("PATH") || !start || hits <= 0)
return NULL;
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;
path = xstrdup(getenv("PATH"));
dirname = strtok(path, ":");
/* recursively open PATH */
for(i = count = 0; paths[i]; ++i)
while (dirname != NULL)
{
if(!(dir = opendir(paths[i])))
continue;
while((content = readdir(dir)))
if ((dir = opendir(dirname)))
{
if(strncmp(content->d_name, ".", 1)
&& !strncmp(content->d_name, start, strlen(start)))
while ((content = readdir(dir)))
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = xstrdup(content->d_name + strlen(start));
if(strncmp(content->d_name, ".", 1))
{
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);
return namelist;
if(n > 0)
{
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.
* works like complete_on_command.
*/
static char **
complete_on_files(char *start)
static char *
complete_on_files(char *start, size_t hits)
{
char *ret = NULL;
char *p = NULL;
char *dirname = NULL;
char *path = NULL;
char *filepath = NULL;
DIR *dir = NULL;
struct dirent *content = NULL;
struct stat st;
DIR *dir;
char *home, *path, *dirname = NULL;
char **namelist = NULL, *filepath, *p = start;
int count = 0;
size_t count = 0;
if (!start || hits <= 0 || !(p = strrchr(start, ' ')))
return NULL;
/*
* Search the directory to open and set
* the beginning of file to complete on pointer 'p'.
*/
if(*p == '\0' || !strrchr(p, '/'))
if (*(++p) == '\0' || !strrchr(p, '/'))
path = xstrdup(".");
else
{
if(!(home = getenv("HOME")))
return NULL;
/* remplace ~ by $HOME in dirname */
if(!strncmp(p, "~/", 2) && home)
xasprintf(&dirname, "%s%s", home, p+1);
if (!strncmp(p, "~/", 2) && getenv("HOME"))
xasprintf(&dirname, "%s%s", getenv("HOME"), p+1);
else
dirname = xstrdup(p);
@ -114,7 +131,7 @@ complete_on_files(char *start)
* <---- path - ---><------- p ------>
*/
p = strrchr(dirname, '/');
if(p != dirname)
if (p != dirname)
{
*(p++) = '\0';
path = xstrdup(dirname);
@ -126,313 +143,242 @@ complete_on_files(char *start)
}
}
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, "..")
|| strncmp(content->d_name, p, strlen(p)))
if (!strcmp(content->d_name, ".") || !strcmp(content->d_name, ".."))
continue;
/* If it's a directory append '/' to the completion */
xasprintf(&filepath, "%s/%s", path, content->d_name);
if(filepath && stat(filepath, &st) != -1)
if (!strncmp(content->d_name, p, strlen(p)) && ++count == hits)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
/* If it's a directory append '/' to the completion */
xasprintf(&filepath, "%s/%s", path, content->d_name);
if(S_ISDIR(st.st_mode))
xasprintf(&namelist[count - 1], "%s/", content->d_name + strlen(p));
if (filepath && stat(filepath, &st) != -1)
{
if (S_ISDIR(st.st_mode))
xasprintf(&ret, "%s/", content->d_name + strlen(p));
else
ret = xstrdup(content->d_name + strlen(p));
}
else
namelist[count - 1] = xstrdup(content->d_name + strlen(p));
}
else
warnl("%s", filepath);
warn("%s", filepath);
free(filepath);
free(filepath);
break;
}
}
closedir(dir);
}
if(count)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = NULL;
}
free(dirname);
free(path);
return namelist;
return ret;
}
static void
complete_cache_free(struct launcher_ccache *cache)
launcher_execute(Launcher *launcher)
{
int i;
/* release memory */
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 };
BarWindow *bw;
bool found;
bool lastwastab = False;
bool my_guitar_gently_wheeps = True;
char tmp[32] = { 0 };
char *p, *data, *arg, *end, *cmd = xstrdup(l->command);
int i, pos = 0, histpos = 0;
void (*func)(Uicb);
XEvent ev;
char buf[512] = { 0 };
char tmpbuf[512] = { 0 };
char *complete;
int i, pos = 0, histpos = 0, w, x = 0;
int tabhits = 0;
KeySym ks;
XEvent ev;
InfobarElem *e;
W->flags |= WMFS_LAUNCHER;
screen_get_sel();
/* Prepare elements */
xasprintf(&data, "%s ", l->prompt);
LAUNCHER_INIT_ELEM(l->width);
STAILQ_FOREACH(e, &infobar[selscreen].elemhead, next)
if(x < (e->geo.x + e->geo.width))
x = e->geo.x + e->geo.width + PAD;
XGrabKeyboard(W->dpy, W->root, true, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabKeyboard(dpy, ROOT, True, GrabModeAsync, GrabModeAsync, CurrentTime);
while(loop)
w = (launcher->width ? launcher->width : infobar[selscreen].bar->geo.width - x - 1);
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)
{
XNextEvent(W->dpy, &ev);
if(ev.type != KeyPress)
if(ev.type == KeyPress)
{
EVENT_HANDLE(&ev);
continue;
}
XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0);
/* Get pressed key */
XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0);
/* Check Ctrl-c / Ctrl-d */
if(ev.xkey.state & ControlMask)
{
if(ks == XK_c || ks == XK_d)
ks = XK_Escape;
else if(ks == XK_p)
ks = XK_Up;
else if(ks == XK_n)
ks = XK_Down;
}
/* Check if there is a keypad */
if(IsKeypadKey(ks) && ks == XK_KP_Enter)
ks = XK_Return;
/* Check Ctrl-c / Ctrl-d */
if(ev.xkey.state & ControlMask)
{
switch(ks)
{
case XK_c:
case XK_d:
ks = XK_Escape;
break;
case XK_p:
ks = XK_Up;
break;
case XK_n:
ks = XK_Down;
break;
}
}
/* Check if there is a keypad */
if(IsKeypadKey(ks) && ks == XK_KP_Enter)
ks = XK_Return;
/* Manage pressed keys */
switch(ks)
{
case XK_Up:
if(l->nhisto)
{
if(histpos >= (int)l->nhisto)
histpos = 0;
strncpy(buf, l->histo[l->nhisto - ++histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Down:
if(l->nhisto && histpos > 0 && histpos < (int)l->nhisto)
{
strncpy(buf, l->histo[l->nhisto - --histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Return:
/* Get function name only, if cmds are added in command */
arg = NULL;
if((p = strchr(cmd, ' ')))
{
*p = '\0';
xasprintf(&arg, "%s %s", p + 1, buf);
}
if((func = uicb_name_func(cmd)))
{
if(arg)
case XK_Up:
if(launcher->nhisto)
{
func(arg);
free(arg);
if(histpos >= (int)launcher->nhisto)
histpos = 0;
strncpy(buf, launcher->histo[launcher->nhisto - ++histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Down:
if(launcher->nhisto && histpos > 0 && histpos < (int)launcher->nhisto)
{
strncpy(buf, launcher->histo[launcher->nhisto - --histpos], sizeof(buf));
pos = strlen(buf);
}
break;
case XK_Return:
spawn("%s %s", launcher->command, buf);
/* Histo */
if(launcher->nhisto + 1 > HISTOLEN)
{
for(i = launcher->nhisto - 1; i > 1; --i)
strncpy(launcher->histo[i], launcher->histo[i - 1], sizeof(launcher->histo[i]));
launcher->nhisto = 0;
}
/* Store in histo array */
strncpy(launcher->histo[launcher->nhisto++], buf, sizeof(buf));
my_guitar_gently_wheeps = 0;
break;
case XK_Escape:
my_guitar_gently_wheeps = 0;
break;
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';
if (lastwastab)
tabhits++;
else
func(buf);
{
tabhits = 1;
strncpy(tmpbuf, buf, sizeof(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));
strncat(buf, complete, sizeof(buf));
found = True;
free(complete);
}
}
lastwastab = True;
/* start a new round of tabbing */
if (found == False)
tabhits = 0;
pos = strlen(buf);
break;
case XK_BackSpace:
lastwastab = False;
if(pos)
buf[--pos] = 0;
break;
default:
lastwastab = False;
strncat(buf, tmp, sizeof(tmp));
++pos;
break;
}
/* 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]));
barwin_refresh_color(bw);
l->nhisto = 0;
}
/* Store in histo array */
strncpy(l->histo[l->nhisto++], buf, sizeof(buf));
/* Update cursor position */
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);
loop = false;
break;
case XK_Escape:
loop = false;
break;
/* Completion */
case XK_Tab:
buf[pos] = '\0';
if(lastwastab)
++cache.hits;
else
{
cache.hits = 0;
strncpy(tmpbuf, buf, sizeof(tmpbuf));
}
if(pos && (end = complete(&cache, tmpbuf)))
{
strncpy(buf, tmpbuf, sizeof(buf));
strncat(buf, end, sizeof(buf));
found = true;
}
lastwastab = true;
/* start a new round of tabbing */
if(!found)
cache.hits = 0;
pos = strlen(buf);
break;
case XK_BackSpace:
lastwastab = false;
if(pos)
buf[--pos] = '\0';
break;
default:
lastwastab = false;
strncat(buf, tmp, sizeof(tmp));
++pos;
break;
barwin_draw_text(bw, 1, FHINFOBAR - 1, launcher->prompt);
barwin_draw_text(bw, 1 + textw(launcher->prompt) + textw(" "), FHINFOBAR - 1, buf);
barwin_refresh(bw);
}
else if(ev.type < nevent && ev.type > 0)
HANDLE_EVENT(&ev);
free(data);
xasprintf(&data, "%s %s", l->prompt, buf);
/* Update EVERY launcher element of the screen */
SLIST_FOREACH(ib, &W->screen->infobars, next)
{
TAILQ_FOREACH(e, &ib->elements, next)
{
if(e->type != ElemLauncher)
continue;
e->data = data;
e->func_update(e);
}
}
XNextEvent(dpy, &ev);
}
XUngrabKeyboard(W->dpy, CurrentTime);
barwin_unmap(bw);
barwin_delete(bw);
infobar_draw(&infobar[selscreen]);
complete_cache_free(&cache);
free(cmd);
free(data);
XUngrabKeyboard(dpy, CurrentTime);
return;
/* 'Close' launcher elements */
W->flags ^= WMFS_LAUNCHER;
data = NULL;
LAUNCHER_INIT_ELEM(1);
}
void
uicb_launcher(Uicb cmd)
uicb_launcher(uicb_t cmd)
{
struct launcher *l;
int i;
if(!cmd)
return;
for(i = 0; i < conf.nlauncher; ++i)
if(!strcmp(cmd, conf.launcher[i].name))
launcher_execute(&conf.launcher[i]);
SLIST_FOREACH(l, &W->h.launcher, next)
if(!strcmp(l->name, cmd))
{
launcher_process(l);
break;
}
return;
}

View File

@ -1,13 +0,0 @@
/*
* 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

View File

@ -1,54 +0,0 @@
/*
* 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
View File

@ -1,110 +0,0 @@
/*
* 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);
}

View File

@ -1,18 +0,0 @@
/*
* 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 */

363
src/menu.c Normal file
View File

@ -0,0 +1,363 @@
/*
* 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,242 +1,386 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* mouse.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"
#include "mouse.h"
#include "barwin.h"
#include "client.h"
#include "draw.h"
#define _REV_SBORDER(c) draw_reversed_rect(W->root, c, false);
Window prevwin;
/** 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
mouse_resize(struct client *c)
mouse_cfactor_border(Client *c, int f[4], GC g)
{
struct client *gc;
XEvent ev;
int e;
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, u, ox, oy, ix, iy;
int mx, my;
int d;
XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (unsigned int *)&u);
XGrabServer(W->dpy);
if(!((*c)->flags & (TileFlag | LMaxFlag)))
return;
if(c->flags & CLIENT_FREE)
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))
{
_REV_SBORDER(c);
client_swap(sc, *c);
client_focus(sc);
swap_ptr((void**)c, (void**)&sc);
}
else
_REV_BORDER();
if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
c = c->tabmaster;
return;
ix = ox;
iy = oy;
}
c->flags |= CLIENT_MOUSE;
/** 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;
if(c->flags & (MaxFlag | FSSFlag))
return;
ocx = c->geo.x;
ocy = c->geo.y;
if(XGrabPointer(dpy, ROOT, False, MouseMask, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag))
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) && !(c->flags & LMaxFlag))
mouse_dragborder(c->geo, gci);
XQueryPointer(dpy, ROOT, &dw, &dw, &mx, &my, &dint, &dint, &duint);
do
{
XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
XMaskEvent(dpy, MouseMask | SubstructureRedirectMask, &ev);
screen_get_sel();
if(ev.type != MotionNotify)
continue;
mx = ev.xmotion.x_root;
my = ev.xmotion.y_root;
if(c->flags & CLIENT_FREE)
if(ev.type == MotionNotify)
{
_REV_SBORDER(c);
mouse_move_tile_client(&c);
mouse_move_tag_client(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;
ocy = c->geo.y;
if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
c = c->tabmaster;
XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (uint *)&u);
_REV_SBORDER(c);
c->flags |= CLIENT_MOUSE;
do
{
XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
if(ev.type != MotionNotify)
continue;
if(!func && c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
c->geo.x = (ocx + (ev.xmotion.x_root - ox));
c->geo.y = (ocy + (ev.xmotion.y_root - oy));
_REV_SBORDER(c);
}
else
{
c2 = NULL;
XQueryPointer(W->dpy, W->root, &w, &w, &d, &d, &d, &d, (uint *)&u);
if((c2 = client_gb_win(w)) || (c2 = client_gb_frame(w)) || (c2 = client_gb_titlebar(w)))
/* To move a client normally, in freelayout */
if(!(c->flags & TileFlag) && !(c->flags & LMaxFlag))
{
if(c2 != last)
{
_REV_SBORDER(last);
_REV_SBORDER(c2);
last = c2;
}
mouse_dragborder(geo, gci);
geo.x = (ocx + (ev.xmotion.x - mx));
geo.y = (ocy + (ev.xmotion.y - my));
/*
* Need to draw 2 times the same rectangle because
* it is draw with the revert color; revert + revert = normal
*/
mouse_dragborder(geo, gci);
}
else
t = mouse_drag_tag(c, w);
}
else if((ev.type == MapRequest || ev.type == ConfigureRequest))
HANDLE_EVENT(&ev);
}
while(ev.type != ButtonRelease);
XSync(W->dpy, false);
/* One time again to delete all the trace on the window */
if(!(c->flags & (TileFlag | LMaxFlag)))
{
mouse_dragborder(geo, gci);
client_moveresize(c, geo, False);
frame_update(c);
XUngrabServer(dpy);
}
client_update_attributes(c);
XUngrabPointer(dpy, CurrentTime);
XFreeGC(dpy, gci);
} while(ev.type != ButtonRelease);
return;
}
if(c2)
func(c, c2);
else if(t && t != (struct tag*)c)
tag_client(t, c);
/** Resize a client with the mouse
* \param c Client pointer
*/
void
mouse_resize(Client *c)
{
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
{
_REV_SBORDER(c);
/* No func mean free client resize */
if(!func)
client_moveresize(c, &c->geo);
mouse_cfactor_border(c, f, gci);
cfactor_multi_set(c, f);
}
c->flags &= ~CLIENT_MOUSE;
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
uicb_mouse_resize(Uicb cmd)
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;
CHECK(sel);
if(W->client && mouse_check_client(W->client))
mouse_resize(W->client);
mouse_move(sel);
return;
}
/** Reisze the selected client
* \param cmd uicb_t type unused
*/
void
uicb_mouse_move(Uicb cmd)
uicb_mouse_resize(uicb_t cmd)
{
(void)cmd;
CHECK(sel);
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, (W->client->flags & CLIENT_FREE ? NULL : client_swap2));
mouse_resize(sel);
return;
}
void
uicb_mouse_tab(Uicb cmd)
{
(void)cmd;
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, _client_tab);
}

View File

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

View File

@ -1,6 +1,5 @@
/*
* 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
* purpose with or without fee is hereby granted, provided that the above
@ -23,8 +22,7 @@
#define INCLUDE_CMD "@include"
#define PARSE_MAX_LIST 32
struct conf_opt
{
struct conf_opt {
char *name;
char *val[PARSE_MAX_LIST];
size_t nval;
@ -34,18 +32,16 @@ struct conf_opt
SLIST_ENTRY(conf_opt) entry;
};
struct conf_sec
{
struct conf_sec {
char *name;
SLIST_HEAD(, conf_opt) optlist;
TAILQ_HEAD(cshead, conf_sec) sub;
TAILQ_HEAD(, conf_sec) sub;
size_t nopt;
size_t nsub;
TAILQ_ENTRY(conf_sec) entry;
};
struct opt_type
{
struct opt_type {
long int num;
float fnum;
bool boolean;

View File

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

View File

@ -1,166 +1,281 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* screen.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"
/** Count the screens
*\return the number of screen
*/
int
screen_count(void)
{
int n = ScreenCount(dpy);
#ifdef HAVE_XINERAMA
#include <X11/extensions/Xinerama.h>
if(XineramaIsActive(dpy))
XineramaQueryScreens(dpy, &n);
#endif /* HAVE_XINERAMA */
#include "screen.h"
#include "util.h"
#include "tag.h"
#include "infobar.h"
#include "client.h"
/* Set _WMFS_SCREEN_COUNT */
if(net_atom)
XChangeProperty(dpy, ROOT, net_atom[wmfs_screen_count], XA_CARDINAL, 32,
PropModeReplace, (uchar*)&n, 1);
static struct screen*
screen_new(struct geo *g, int id)
{
struct screen *s = (struct screen*)xcalloc(1, sizeof(struct screen));
s->geo = s->ugeo = *g;
s->seltag = NULL;
s->id = id;
s->flags = 0;
TAILQ_INIT(&s->tags);
SLIST_INIT(&s->infobars);
SLIST_INSERT_HEAD(&W->h.screen, s, next);
/* Set as selected screen */
W->screen = s;
return s;
return n;
}
void
screen_init(void)
/** Get screen geometry by number
*\param s Screen number
*\return Geo struct
*/
Geo
screen_get_geo(int s)
{
struct geo g;
int barpos = tags[selscreen][seltag[selscreen]].barpos;
Geo geo;
SLIST_INIT(&W->h.screen);
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
XineramaScreenInfo *xsi;
int i, n = 0;
if(XineramaIsActive(W->dpy))
if(XineramaIsActive(dpy))
{
xsi = XineramaQueryScreens(W->dpy, &n);
XineramaScreenInfo *xsi;
int n = 0;
for(i = 0; i < n; ++i)
{
g.x = xsi[i].x_org;
g.y = xsi[i].y_org;
g.w = xsi[i].width;
g.h = xsi[i].height;
xsi = XineramaQueryScreens(dpy, &n);
screen_new(&g, i);
}
W->nscreen = 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
#else
(void)s;
#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;
}
return geo;
}
/*
* Update selected screen with mouse location
*/
struct screen*
screen_update_sel(void)
/** 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(W->dpy))
return (W->screen = screen_gb_mouse());
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 */
return W->screen;
}
static void
screen_select(struct screen *s)
{
XWarpPointer(W->dpy, None, W->root, 0, 0, 0, 0,
s->ugeo.x + (s->ugeo.w >> 1),
s->ugeo.y + (s->ugeo.h >> 1));
W->screen = s;
/* 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
uicb_screen_next(Uicb cmd)
screen_init_geo(void)
{
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd;
int i;
int s = screen_count();
if(!s)
s = SLIST_FIRST(&W->h.screen);
sgeo = xcalloc(s, sizeof(Geo));
spgeo = xcalloc(s, sizeof(Geo));
screen_select(s);
}
for(i = 0; i < s; ++i)
sgeo[i] = screen_get_geo(i);
void
uicb_screen_prev(Uicb cmd)
{
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
spgeo[0].x = 0;
spgeo[0].y = 0;
spgeo[0].width = MAXW;
spgeo[0].height = MAXH;
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
#ifdef HAVE_XINERAMA
XineramaScreenInfo *xsi;
int n;
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))
if(XineramaIsActive(dpy))
{
s = SLIST_FIRST(&W->h.screen);
SLIST_REMOVE_HEAD(&W->h.screen, next);
infobar_free(s);
tag_free(s);
free(s);
xsi = XineramaQueryScreens(dpy, &n);
for(i = 0; i < n; ++i)
{
spgeo[i].x = xsi[i].x_org;
spgeo[i].y = xsi[i].y_org;
spgeo[i].width = xsi[i].width;
spgeo[i].height = xsi[i].height;
}
XFree(xsi);
}
#endif /* HAVE_XINERAMA */
#ifdef HAVE_XRANDR
/* 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
* \param cmd Screen uicb_t type
*/
void
uicb_screen_select(uicb_t cmd)
{
screen_set_sel(atoi(cmd));
return;
}
/** Uicb: screen next
* \param cmd Screen uicb_t type
*/
void
uicb_screen_next(uicb_t cmd)
{
(void)cmd;
screen_get_sel();
if(screen_count() > 1)
{
selscreen = (selscreen + 1 > screen_count() - 1) ? 0 : selscreen + 1;
screen_set_sel(selscreen);
}
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;
}

View File

@ -1,56 +0,0 @@
/*
* 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 */

374
src/split.c Normal file
View File

@ -0,0 +1,374 @@
/*
* 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,653 +1,290 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
* status.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"
/* 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
status_free_ctx(struct status_ctx *ctx)
statustext_mouse(char *str, Geo area, InfoBar *infobar)
{
free(ctx->status);
status_flush_list(ctx);
status_gcache_free(ctx);
StatusMouse *sm = NULL;
int i = 0, button = 1, n;
char cmd[256] = { 0 };
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
status_graph_draw(struct status_ctx *ctx, struct status_seq *sq, struct status_gcache *gc)
statustext_rectangle(InfoBar *ib, char *str)
{
int max = 0;
int i, j, y;
float c;
int ys = sq->geo.y + sq->geo.h - 1;
StatusRec r;
char as, mouse[512] = { 0 };
int i = 0, j = 0, k, n;
/* If invalid maximum, we have to compute it ourselves */
if(sq->data[2] <= 0)
{
for(i = sq->geo.x + sq->geo.w - 1, j = gc->ndata - 1;
j >= 0 && i >= sq->geo.x;
--j, --i)
{
if(gc->datas[j] > max)
max = gc->datas[j];
}
}
else
max = sq->data[2];
XSetForeground(W->dpy, W->gc, sq->color2);
for(i = sq->geo.x + sq->geo.w - 1, j = gc->ndata - 1;
j >= 0 && i >= sq->geo.x;
--j, --i)
{
/* You divided by zero didn't you? */
if(gc->datas[j])
for(; i < (int)strlen(str); ++i, ++j)
if(((n = sscanf(&str[i], "\\b[%d;%d;%d;%d;#%x]%c",
&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 == '\\')
{
c = (float)max / (float)gc->datas[j];
y = ys - (sq->geo.h / (c > 1 ? c : 1)) + 1;
draw_line(ctx->barwin->dr, i, y, i, ys);
draw_rectangle(ib->bar->dr, r.g.x - sw, r.g.y, r.g.width, r.g.height, r.color);
if(n == 7)
statustext_mouse(mouse, r.g, 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;
}
/** Check graphs blocks in str and draw it
* --> \g[x;y;width;height;#color;data]\
*\param ib Infobar pointer
*\param str String
*/
static void
status_graph_process(struct status_ctx *ctx, struct status_seq *sq, char *name)
statustext_graph(InfoBar *ib, char *str)
{
int j;
struct status_gcache *gc;
StatusGraph g;
char as, c, *p;
int i, j, k, m, w;
/* Graph already exist and have a cache */
SLIST_FOREACH(gc, &ctx->gcache, next)
if(!strcmp(name, gc->name))
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 == '\\')
{
/* shift buffer to remove unused old value */
if(gc->ndata > (sq->geo.w << 1))
for(gc->ndata /= 2, j = 0;
j < gc->ndata;
gc->datas[j] = gc->datas[j + gc->ndata], ++j);
/* data is a list of numbers separated by ';' */
w = g.w;
p = strtok(g.data, ";");
m = 0;
gc->datas[gc->ndata++] = sq->data[1];
status_graph_draw(ctx, sq, gc);
return;
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];
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
for(k = j; k < i; str[k++] = '\0');
/* 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];
SLIST_INSERT_HEAD(&ctx->gcache, gc, next);
status_graph_draw(ctx, sq, gc);
return;
}
/* Parse mousebind sequence next normal sequence: \<seq>[](button;func;cmd) */
static char*
status_parse_mouse(struct status_seq *sq, char *str)
/** 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)
{
struct mousebind *m;
char *end, *arg[3] = { NULL };
int i;
StatusText s;
Geo area;
char as, mouse[512] = { 0 };
int i = 0, j = 0, k, n;
if(*str != '(' || !(end = strchr(str, ')')))
return str;
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);
i = parse_args(++str, ';', ')', 3, arg);
/* 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;
m = xcalloc(1, sizeof(struct mousebind));
statustext_mouse(mouse, area, ib);
}
m->use_area = true;
m->button = ATOI(arg[0]);
m->func = uicb_name_func(arg[1]);
m->cmd = (i > 1 ? xstrdup(arg[2]) : NULL);
for(++i, --j; str[i] != as || str[i - 1] != ']'; ++i);
}
else if(j != i)
str[j] = str[i];
SLIST_INSERT_HEAD(&sq->mousebinds, m, snext);
for(k = j; k < i; str[k++] = '\0');
return end + 1;
return;
}
#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)
/** 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)
{
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 };
char strwc[MAXSTATUS] = { 0 };
char buf[MAXSTATUS] = { 0 };
char col[8] = { 0 };
int n, i, j, k, tw;
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))
for(i = j = n = 0; i < (int)strlen(str); ++i, ++j)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{
/*
* 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 */
++n;
i += 8;
--j;
}
if(sq->align == Right)
SLIST_INSERT_HEAD(&ctx->statushead, sq, next);
else
SLIST_INSERT_TAIL(&ctx->statushead, sq, next, prev);
strwc[j] = str[i];
/*
* Optional mousebind sequence(s) \<seq>[](button;func;cmd)
* Parse it while there is a mousebind sequence.
*/
dstr = end + 1;
/* Draw normal text without any blocks */
draw_text(ib->bar->dr, (sgeo[ib->screen].width - SHADH) - (textw(strwc) + sw), FHINFOBAR, ib->bar->fg, strwc);
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)
if(n)
{
switch(sq->type)
{
/* Text */
case 's':
sq->geo.w = draw_textw(ctx->theme, sq->str);
sq->geo.h = ctx->theme->font.height;
strncpy(buf, strwc, sizeof(buf));
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
for(i = k = 0; i < (int)strlen(str); ++i, ++k)
if(str[i] == '\\' && str[i + 1] == '#' && str[i + 8] == '\\')
{
g.y += g.h;
g.h /= ((float)sq->data[2] / (float)sq->data[1]);
g.y -= g.h;
}
tw = textw(&buf[k]);
draw_rect(ctx->barwin->dr, &g, sq->color2);
/* Store current color in col[] */
for(j = 0, ++i; str[i] != '\\'; col[j++] = str[i++]);
STORE_MOUSEBIND();
/* 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);
break;
/* Draw text with its color */
draw_text(ib->bar->dr, (sgeo[ib->screen].width - SHADH) - (tw + sw), FHINFOBAR, col, &buf[k]);
/* 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);
strncpy(buf, strwc, sizeof(buf));
++i;
}
}
return;
}
/** Handle statustext and draw all things in infobar of specified screen
*\param sc Screen id
*\param str String
*/
void
statustext_handle(InfoBar *ib)
{
char *str;
StatusMouse *sm;
/* Free previous linked list of mouse bind */
if(!ib->screen)
while(!SLIST_EMPTY(&smhead))
{
sm = SLIST_FIRST(&smhead);
SLIST_REMOVE_HEAD(&smhead, next);
free((void*)sm->cmd);
free(sm);
}
if(ib->screen == conf.systray.screen)
sw = systray_get_width();
str = xstrdup(ib->statustext);
/* Store rectangles, located text & images properties. */
statustext_rectangle(ib, str);
statustext_graph(ib, str);
statustext_text(ib, str);
/* Draw normal text (and possibly colored with \#color\ blocks) */
statustext_normal(ib, str);
sw = 0;
free(str);
return;
}

View File

@ -1,23 +0,0 @@
/*
* 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 */

620
src/structs.h Normal file
View File

@ -0,0 +1,620 @@
/*
* 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,159 +1,182 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* systray.c
* Copyright © 2008, 2009, 2010 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"
#include "systray.h"
#include "ewmh.h"
#include "infobar.h"
#define SYSTRAY_SPACING (2)
#define TRAY_DWIDTH (infobar[conf.systray.screen].bar->geo.height + conf.systray.spacing)
void
bool
systray_acquire(void)
{
Window w = 0;
XSetWindowAttributes wattr =
{
.event_mask = ButtonPressMask | ExposureMask,
.override_redirect = true,
.background_pixmap = ParentRelative,
.background_pixel = W->systray.infobar->theme->bars.bg,
};
XSetWindowAttributes wattr;
if(!(W->flags & WMFS_SYSTRAY) || W->systray.win)
return;
if(!conf.systray.active || traywin)
return False;
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != None)
if(XGetSelectionOwner(dpy, net_atom[net_system_tray_s]) != None)
{
warnx("Can't initialize system tray: owned by another process.");
return;
warnx("Can't initialize system tray: owned by another process");
return False;
}
SLIST_INIT(&W->systray.head);
/* Init traywin window */
wattr.event_mask = ButtonPressMask | ExposureMask;
wattr.override_redirect = True;
wattr.background_pixmap = ParentRelative;
wattr.background_pixel = 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);
traywin = XCreateSimpleWindow(dpy, infobar[conf.systray.screen].bar->win, -1, -1, 1, 1, 0, 0, conf.colors.bar);
XChangeWindowAttributes(W->dpy, w, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr);
XSelectInput(W->dpy, w, KeyPressMask | ButtonPressMask);
XMapRaised(W->dpy, w);
XChangeWindowAttributes(dpy, traywin, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr);
XSelectInput(dpy, traywin, KeyPressMask | ButtonPressMask);
XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], w, CurrentTime);
XMapRaised(dpy, traywin);
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != w)
XSetSelectionOwner(dpy, net_atom[net_system_tray_s], traywin, CurrentTime);
if(XGetSelectionOwner(dpy, net_atom[net_system_tray_s]) != traywin)
{
warnl("System tray: can't get systray manager");
systray_freeicons();
return;
warnx("System tray: can't get systray manager");
return False;
}
ewmh_send_message(W->root, W->root, "MANAGER", CurrentTime,
W->net_atom[net_system_tray_s], w, 0, 0);
ewmh_send_message(ROOT, ROOT, "MANAGER", CurrentTime, net_atom[net_system_tray_s], traywin, 0, 0);
XSync(W->dpy, false);
XSync(dpy, False);
W->systray.win = w;
return True;
}
void
systray_add(Window win)
{
struct _systray *s;
Systray *s;
if(!(W->flags & WMFS_SYSTRAY))
if(!conf.systray.active)
return;
s = xcalloc(1, sizeof(struct _systray));
s = xcalloc(1, sizeof(Systray));
s->win = win;
s->geo.h = W->systray.barwin->geo.h;
s->geo.w = W->systray.barwin->geo.h + SYSTRAY_SPACING;
s->geo.height = infobar[conf.systray.screen].bar->geo.height;
s->geo.width = TRAY_DWIDTH;
ewmh_set_wm_state(s->win, NormalState);
XSelectInput(W->dpy, s->win, StructureNotifyMask | PropertyChangeMask| EnterWindowMask | FocusChangeMask);
XReparentWindow(W->dpy, s->win, W->systray.win, 0, 0);
setwinstate(s->win, WithdrawnState);
XSelectInput(dpy, s->win, StructureNotifyMask | PropertyChangeMask| EnterWindowMask | FocusChangeMask);
XReparentWindow(dpy, s->win, traywin, 0, 0);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_EMBEDDED_NOTIFY, 0, W->systray.win, 0);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, traywin, 0);
SLIST_INSERT_HEAD(&W->systray.head, s, next);
/* Attach */
SLIST_INSERT_HEAD(&trayicons, s, next);
W->systray.redim = true;
return;
}
void
systray_del(struct _systray *s)
systray_del(Systray *s)
{
if(!(W->flags & WMFS_SYSTRAY))
if(!conf.systray.active)
return;
SLIST_REMOVE(&W->systray.head, s, _systray, next);
SLIST_REMOVE(&trayicons, s, Systray, next);
free(s);
W->systray.redim = true;
return;
}
void
systray_state(struct _systray *s)
systray_state(Systray *s)
{
long flags;
int code = 0;
if(!(W->flags & WMFS_SYSTRAY) || !(flags = ewmh_get_xembed_state(s->win)))
if(!(flags = ewmh_get_xembed_state(s->win)) || !conf.systray.active)
return;
if(flags & XEMBED_MAPPED)
{
code = XEMBED_WINDOW_ACTIVATE;
XMapRaised(W->dpy, s->win);
ewmh_set_wm_state(s->win, NormalState);
XMapRaised(dpy, s->win);
setwinstate(s->win, NormalState);
}
else
{
code = XEMBED_WINDOW_DEACTIVATE;
XUnmapWindow(W->dpy, s->win);
ewmh_set_wm_state(s->win, WithdrawnState);
XUnmapWindow(dpy, s->win);
setwinstate(s->win, WithdrawnState);
}
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, code, 0, 0, 0);
return;
}
void
systray_freeicons(void)
{
struct _systray *i;
Systray *i;
if(!(W->flags & WMFS_SYSTRAY))
if(!conf.systray.active)
return;
while(!SLIST_EMPTY(&W->systray.head))
while(!SLIST_EMPTY(&trayicons))
{
i = SLIST_FIRST(&W->systray.head);
SLIST_REMOVE_HEAD(&W->systray.head, next);
i = SLIST_FIRST(&trayicons);
SLIST_REMOVE_HEAD(&trayicons, next);
XUnmapWindow(W->dpy, i->win);
XReparentWindow(W->dpy, i->win, W->root, 0, 0);
XUnmapWindow(dpy, i->win);
XReparentWindow(dpy, i->win, ROOT, 0, 0);
free(i);
}
XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], None, CurrentTime);
W->systray.barwin->geo.w = 0;
infobar_elem_reinit(W->systray.infobar);
XSync(W->dpy, false);
XSetSelectionOwner(dpy, net_atom[net_system_tray_s], None, CurrentTime);
XDestroyWindow(dpy, traywin);
XSync(dpy, 0);
return;
}
struct _systray*
Systray*
systray_find(Window win)
{
struct _systray *i;
Systray *i;
if(!(W->flags & WMFS_SYSTRAY))
if(!conf.systray.active)
return NULL;
SLIST_FOREACH(i, &W->systray.head, next)
SLIST_FOREACH(i, &trayicons, next)
if(i->win == win)
return i;
@ -163,11 +186,14 @@ systray_find(Window win)
int
systray_get_width(void)
{
int w = 1;
struct _systray *i;
int w = 0;
Systray *i;
SLIST_FOREACH(i, &W->systray.head, next)
w += i->geo.w + SYSTRAY_SPACING;
if(!conf.systray.active)
return 0;
SLIST_FOREACH(i, &trayicons, next)
w += i->geo.width + conf.systray.spacing + 1;
return w;
}
@ -175,26 +201,29 @@ systray_get_width(void)
void
systray_update(void)
{
Systray *i;
int x = 1;
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
if(!conf.systray.active)
return;
if(W->systray.redim)
if(!SLIST_FIRST(&trayicons))
{
W->systray.redim = false;
infobar_elem_reinit(W->systray.infobar);
XMoveResizeWindow(dpy, traywin, infobar[conf.systray.screen].bar->geo.width - 1, 0, 1, 1);
return;
}
SLIST_FOREACH(i, &W->systray.head, next)
SLIST_FOREACH(i, &trayicons, next)
{
XMapWindow(W->dpy, i->win);
XMoveResizeWindow(W->dpy, i->win, (i->geo.x = x), 0, i->geo.w, i->geo.h);
XMapWindow(dpy, i->win);
x += i->geo.w + SYSTRAY_SPACING;
XMoveResizeWindow(dpy, i->win, (i->geo.x = x), 0, i->geo.width, i->geo.height);
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;
}

View File

@ -1,20 +0,0 @@
/*
* 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 */

1009
src/tag.c

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
/*
* 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,31 +1,54 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* util.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.
*/
#define _GNU_SOURCE /* vasprintf() */
#include <stdint.h>
#include <string.h>
#include "util.h"
#define _GNU_SOURCE
#include "wmfs.h"
/** malloc with error support and size_t overflow protection
* \param nmemb number of objects
* \param size size of single object
* \return non null void pointer
*/
void*
void *
xmalloc(size_t nmemb, size_t size)
{
void *ret;
if(SIZE_MAX / nmemb < size)
errl(EXIT_FAILURE, "xmalloc(%zu, %zu), "
if (SIZE_MAX / nmemb < size)
err(EXIT_FAILURE, "xmalloc(%zu, %zu), "
"size_t overflow detected", nmemb, size);
if((ret = malloc(nmemb * size)) == NULL)
errl(EXIT_FAILURE, "malloc(%zu)", nmemb * size);
if ((ret = malloc(nmemb * size)) == NULL)
err(EXIT_FAILURE, "malloc(%zu)", nmemb * size);
return ret;
}
@ -35,13 +58,13 @@ xmalloc(size_t nmemb, size_t size)
* \param size size of single object
* \return non null void pointer
*/
void*
void *
xcalloc(size_t nmemb, size_t size)
{
void *ret;
if((ret = calloc(nmemb, size)) == NULL)
errl(EXIT_FAILURE, "calloc(%zu * %zu)", nmemb, size);
if ((ret = calloc(nmemb, size)) == NULL)
err(EXIT_FAILURE, "calloc(%zu * %zu)", nmemb, size);
return ret;
}
@ -57,16 +80,30 @@ xrealloc(void *ptr, size_t nmemb, size_t size)
{
void *ret;
if(SIZE_MAX / nmemb < size)
if (SIZE_MAX / nmemb < size)
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);
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
* \param strp target string
@ -84,27 +121,98 @@ xasprintf(char **strp, const char *fmt, ...)
va_end(args);
if (ret == -1)
errl(EXIT_FAILURE, "asprintf(%s)", fmt);
err(EXIT_FAILURE, "asprintf(%s)", fmt);
return ret;
}
/** strdup with error support
* \param str char pointer
* \retun non null void pointer
*/
char *
xstrdup(const char *str)
/** Get a color with a string
* \param color Color string
* \return Color pixel
*/
long
getcolor(char *color)
{
char *ret = NULL;
XColor xcolor;
if(str == NULL || (ret = strdup(str)) == NULL)
warnxl("strdup(%s)", str);
if(!XAllocNamedColor(dpy, DefaultColormap(dpy, SCREEN), color, &xcolor, &xcolor))
warnx("Error: cannot allocate color \"%s\".", color);
return ret;
return xcolor.pixel;
}
/** Execute a system command
/** Set the window WM State
* \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
* \return child pid
*/
@ -123,45 +231,74 @@ spawn(const char *format, ...)
if (len >= sizeof(cmd))
{
warnxl("command too long (> 512 bytes)");
warnx("command too long (> 512 bytes)");
return -1;
}
if(!(sh = getenv("SHELL")) || sh[0] != '/')
if(!(sh = getenv("SHELL")))
sh = "/bin/sh";
if(!(pid = fork()))
if((pid = fork()) == 0)
{
if(dpy)
close(ConnectionNumber(dpy));
setsid();
if (execl(sh, sh, "-c", cmd, (char*)NULL) == -1)
warnl("execl(sh -c %s)", cmd);
warn("execl(sh -c %s)", cmd);
exit(EXIT_FAILURE);
}
else if (pid == -1)
warnl("fork");
warn("fork");
return pid;
}
int
parse_args(char *str, char delim, char end, int narg, char *args[])
/** Swap two pointer.
*\param x First pointer
*\param y Second pointer
*/
void
swap_ptr(void **x, void **y)
{
int i = 0;
void *t = *x;
for(args[0] = str; *str && (*str != end || *(str - 1) == '\\') && i < narg; ++str)
if(*str == delim && i < narg - 1)
{
*str = '\0';
args[++i] = ++str;
}
*x = *y;
*y = t;
*str = '\0';
return i;
return;
}
/** Execute a sh command
* \param cmd Command (uicb_t type)
*/
void
uicb_spawn(Uicb cmd)
uicb_spawn(uicb_t 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));
}

View File

@ -1,99 +0,0 @@
/*
* 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 */

File diff suppressed because it is too large Load Diff

View File

@ -1,423 +1,511 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
* wmfs.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 WMFS_H
#define WMFS_H
/* Standard */
/* Lib headers */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <locale.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 <sys/queue.h>
/* Xlib */
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
/* Local */
#include "log.h"
/* Optional dependencies */
#ifdef HAVE_XFT
#include <X11/Xft/Xft.h>
#endif /* HAVE_XFT */
#define CONFIG_DEFAULT_PATH ".config/wmfs/wmfsrc"
#ifdef HAVE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* HAVE_XINERAMA */
#define ButtonMask (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
#define MouseMask (ButtonMask | PointerMotionMask)
#define KeyMask (KeyPressMask | KeyReleaseMask)
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif /* HAVE_XRANDR */
typedef unsigned long Flags;
typedef unsigned int Color;
typedef const char* Uicb;
#ifdef HAVE_IMLIB
#include <Imlib2.h>
#endif /* HAVE_IMLIB */
enum barpos
{
BarTop = 0,
BarBottom,
BarHide,
BarLast
};
/* Local headers */
#include "parse.h"
#include "structs.h"
enum position
{
Right = 0,
Left,
Top,
Bottom,
Center,
NoAlign,
PositionLast
};
/* MACRO */
#define ButtonMask (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
#define MouseMask (ButtonMask | PointerMotionMask)
#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)
enum size_hints
{
BASEW, BASEH,
INCW, INCH,
MAXW, MAXH,
MINW, MINH,
MINAX, MINAY,
MAXAX, MAXAY,
SHLAST
};
#define CWIN(win, parent, x, y, w, h, b, mask, col, at) \
do { \
win = XCreateWindow(dpy, (parent), (x), (y), (w), (h), (b), CopyFromParent, \
InputOutput, CopyFromParent, (mask), (at)); \
XSetWindowBackground(dpy, win, (col)); \
} while(/* CONSTCOND */ 0)
/*
* Structures
*/
#define HANDLE_EVENT(e) event_handle[(e)->type](e);
#define ATOM(a) XInternAtom(dpy, (a), False)
#define FRAMEW(w) ((w) + (BORDH << 1))
#define FRAMEH(h) ((h) + (BORDH + TBARH))
#define CHECK(x) if(!(x)) return
#define LEN(x) (sizeof(x) / sizeof((x)[0]))
#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)
struct geo
{
int x, y, w, h;
};
/* Cfactor define */
#define CFACTOR_CHECK2(g1, g2, p) (LDIR(p) ? (g1.height == g2.height) : (g1.width == g2.width))
#define CFACTOR_PARENTROW(g1, g2, p) \
(LDIR(p) \
? (p == Left ? (g1.x == g2.x) : (g1.x + g1.width == g2.x + g2.width)) \
: (p == Top ? (g1.y == g2.y) : (g1.y + g1.height == g2.y + g2.height))) \
struct geo_list
{
struct geo geo;
SLIST_ENTRY(geo_list) next;
};
/* Barwin define, wrappers for simple function */
#define barwin_delete_subwin(bw) XDestroySubwindows(dpy, bw->win)
#define barwin_map_subwin(bw) XMapSubwindows(dpy, bw->win)
#define barwin_unmap_subwin(bw) XUnmapSubwindows(dpy, bw->win)
#define barwin_refresh(bw) XCopyArea(dpy, bw->dr, bw->win, gc, 0, 0, bw->geo.width, bw->geo.height, 0, 0)
#define barwin_map(bw) \
do { \
XMapWindow(dpy, bw->win); \
bw->flags |= MappedFlag; \
} while(/* CONSTCOND */ 0)
#define barwin_unmap(bw) \
do { \
XUnmapWindow(dpy, bw->win); \
bw->flags &= ~MappedFlag; \
} while(/* CONSTCOND */ 0)
struct colpair
{
Color fg, bg;
};
/* barwin.c */
BarWindow *barwin_create(Window parent,
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);
struct barwin
{
struct geo geo;
Window win;
Drawable dr;
Color fg, bg;
void *ptr; /* Special cases */
SLIST_HEAD(mbhead, mousebind) mousebinds;
SLIST_HEAD(, mousebind) statusmousebinds;
SLIST_ENTRY(barwin) next; /* global barwin */
SLIST_ENTRY(barwin) enext; /* element barwin */
SLIST_ENTRY(barwin) vnext; /* volatile barwin */
};
/* draw.c */
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);
void draw_graph(Drawable dr, int x, int y, int w, int h, uint color, char *data);
struct status_seq
{
struct geo geo;
enum position align;
int data[4];
char type;
char *str;
Color color, color2;
SLIST_HEAD(, mousebind) mousebinds;
SLIST_ENTRY(status_seq) next;
};
ushort textw(char *text);
struct status_ctx
{
struct barwin *barwin;
struct theme *theme;
#define STATUS_BLOCK_REFRESH 0x01
Flags flags;
char *status;
bool update;
SLIST_HEAD(, status_gcache) gcache;
SLIST_HEAD(, status_seq) statushead;
};
/* infobar.c */
void infobar_init(void);
void infobar_draw_layout(InfoBar *i);
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);
struct status_gcache
{
char *name;
int *datas;
int ndata;
SLIST_ENTRY(status_gcache) next;
};
/* cfactor.c */
void cfactor_clean(Client *c);
Geo cfactor_geo(Geo geo, int fact[4], int *err);
void cfactor_set(Client *c, Position p, int fac);
void cfactor_multi_set(Client *c, int fac[4]);
/* Generated with macro {{{ */
void uicb_client_resize_Right(uicb_t cmd);
void uicb_client_resize_Left(uicb_t cmd);
void uicb_client_resize_Top(uicb_t cmd);
void uicb_client_resize_Bottom(uicb_t cmd);
/* }}} */
struct element
{
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;
};
/* client.c */
void client_attach(Client *c);
void client_configure(Client *c);
void client_detach(Client *c);
void client_focus(Client *c);
Client *client_get_next(void);
Client *client_get_prev(void);
/* client_gb_*() {{{ */
Client* client_gb_win(Window w);
Client* client_gb_frame(Window w);
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);
struct infobar
{
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;
};
/* ewmh.c */
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);
long ewmh_get_xembed_state(Window win);
void ewmh_get_number_of_desktop(void);
void ewmh_update_current_tag_prop(void);
void ewmh_get_client_list(void);
void ewmh_get_desktop_names(void);
void ewmh_set_desktop_geometry(void);
void ewmh_manage_net_wm_state(long data_l[], Client *c);
void ewmh_manage_window_type(Client *c);
struct screen
{
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;
};
/* frame.c */
void frame_create(Client *c);
void frame_delete(Client *c);
void frame_moveresize(Client *c, Geo geo);
void frame_update_color(Client *c, bool focused);
void frame_update(Client *c);
SLIST_HEAD(chead, client);
/* config.c */
void init_conf(void);
struct tag
{
struct screen *screen;
struct client *sel;
struct client *prevsel;
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;
};
/* color.c */
uint color_shade(uint, double);
struct client
{
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 */
};
/* event.c */
void grabkeys(void);
void event_make_array(void);
struct layout_set
{
int n;
SLIST_HEAD(, geo_list) geos;
TAILQ_ENTRY(layout_set) next;
};
#ifdef HAVE_XRANDR
void xrandrevent(XEvent *e);
#endif /* HAVE_XRANDR */
struct keybind
{
unsigned int mod;
void (*func)(Uicb);
Uicb cmd;
KeySym keysym;
SLIST_ENTRY(keybind) next;
};
/* menu.c */
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);
void menu_draw(Menu menu, int x, int y);
void uicb_menu(uicb_t cmd);
void menu_clear(Menu *menu);
struct mousebind
{
struct geo area;
unsigned int button;
bool use_area;
void (*func)(Uicb);
Uicb cmd;
SLIST_ENTRY(mousebind) next;
SLIST_ENTRY(mousebind) snext;
SLIST_ENTRY(mousebind) globnext;
};
/* launcher.c */
void uicb_launcher(uicb_t);
struct theme
{
char *name;
/* mouse.c */
void mouse_resize(Client *c);
void mouse_grabbuttons(Client *c, bool focused);
void uicb_mouse_move(uicb_t);
void uicb_mouse_resize(uicb_t);
/* Font */
struct
{
int as, de, width, height;
XFontSet fontset;
} font;
/* util.c */
void *xmalloc(size_t, size_t);
void *xcalloc(size_t, size_t);
void *xrealloc(void *, size_t, size_t);
/* simples wrappers for allocating only one object */
#define zmalloc(size) xmalloc(1, (size))
#define zcalloc(size) xcalloc(1, (size))
#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);
/* Bars */
struct colpair bars;
int bars_width;
/* tag.c */
void tag_set(int tag);
void tag_transfert(Client *c, int tag);
void uicb_tag(uicb_t);
void uicb_tag_next(uicb_t);
void uicb_tag_prev(uicb_t);
void uicb_tag_next_visible(uicb_t);
void uicb_tag_prev_visible(uicb_t);
void uicb_tagtransfert(uicb_t);
void uicb_tag_prev_sel(uicb_t);
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);
/* struct elements */
struct colpair tags_n, tags_s, tags_o, tags_u; /* normal / selected / occupied */
struct status_ctx tags_n_sl, tags_s_sl, tags_o_sl, tags_u_sl; /* status line */
int tags_border_width;
Color tags_border_col;
/* screen.c */
int screen_count(void);
Geo screen_get_geo(int s);
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);
/* client / frame */
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;
/* status.c */
void statustext_mouse(char *str, Geo area, InfoBar *infobar);
void statustext_handle(InfoBar *ib);
SLIST_ENTRY(theme) next;
};
/* systray.c */
bool systray_acquire(void);
void systray_add(Window win);
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);
struct rule
{
struct theme *theme;
char *class;
char *instance;
char *role;
char *name;
int tag, screen;
#define RULE_FREE 0x01
#define RULE_TAB 0x02
#define RULE_IGNORE_TAG 0x04
Flags flags;
SLIST_ENTRY(rule) next;
};
/* layout.c */
void arrange(int screen, bool update_layout);
void layout_func(int screen, int tag);
Client *tiled_client(int screen, Client *c);
void freelayout(int screen);
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);
struct launcher
{
char *name;
char *prompt;
char *command;
#define HISTOLEN 64
char histo[HISTOLEN][256];
int nhisto;
int width;
SLIST_ENTRY(launcher) next;
};
/* init.c */
void init(void);
struct launcher_ccache
{
char *start;
char **namelist;
size_t hits;
};
/* split.c */
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);
/* }}} */
struct _systray
{
struct geo geo;
Window win;
SLIST_ENTRY(_systray) next;
};
/* wmfs.c */
int errorhandler(Display *d, XErrorEvent *event);
int errorhandlerdummy(Display *d, XErrorEvent *event);
void quit(void);
void *thread_process(void *arg);
bool check_wmfs_running(void);
void exec_uicb_function(char *func, char *cmd);
void handle_signal(int signum);
void uicb_quit(uicb_t);
void uicb_reload(uicb_t);
#define MAX_PATH_LEN 8192
/* Variables */
struct wmfs
{
/* X11 stuffs */
Display *dpy;
Window root;
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*/
/* Main */
Display *dpy;
GC gc, gc_stipple;
int selscreen;
int prevselscreen;
Conf conf;
Key *keys;
Geo *sgeo;
Geo *spgeo;
Cursor cursor[CurLast];
char *argv_global;
char **all_argv;
int xrandr_event;
uint timing;
int padding;
/* Fonts */
FontStruct font;
/* Log file */
FILE *log;
/* Atoms list */
Atom *net_atom;
Atom trayatom;
/* Lists heads */
struct
{
SLIST_HEAD(, screen) screen;
SLIST_HEAD(, client) client;
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;
/* InfoBar/Tags */
InfoBar *infobar;
Tag **tags;
int *seltag;
int *prevseltag;
Menu menulayout;
/*
* Temporary head of mousebind list from config
* Will be copied in barwin of clickable drawable
* later in code
*/
struct
{
struct mbhead tag;
struct mbhead client;
struct mbhead root;
} tmp_head;
/* ClientList */
Menu clientlist;
struct clndx {
char key[4];
Client *client;
} clist_index[MAXCLIST];
/*
* 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;
/* Client */
SLIST_HEAD(, Client) clients;
Client *sel;
/*
* Selected screen, client
*/
struct screen *screen;
struct client *client;
/* Event */
int nevent;
void (**event_handle)(XEvent*);
extern const func_name_list_t func_list[];
extern const func_name_list_t layout_list[];
uint numlockmask;
};
/* Systray */
SLIST_HEAD(, Systray) trayicons;
Window traywin;
int tray_width;
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);
/* BarWindow */
SLIST_HEAD(, BarWindow) bwhead;
/* Single global variable */
struct wmfs *W;
/* Status */
SLIST_HEAD(, StatusMouse) smhead;
#endif /* WMFS_H */

731
wmfs.1
View File

@ -1,8 +1,11 @@
.\" title: wmfs
.\" dev: xorg62
.\" man: arpinux
.\" Title: wmfs
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
.\" Date: 04/22/2009
.\" Manual: manual of wmfs
.\" Source: wmfs 0.1rc4 (On The Run)
.\"
.TH "WMFS" "1" "2012/05/02" "wmfs" "manual of wmfs"
.TH "WMFS" "1" "04/22/2009" "wmfs 0\&.1rc4 (On The Run)" "manual of wmfs"
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
@ -10,10 +13,10 @@
.SH "NAME"
wmfs \- Window Manager From Scratch
.SH "SYNOPSIS"
\fBwmfs\fR [\fB\-hv\fR] [\fB\-C <file>\fR] [\fB\-c <uicb_function> <cmd>\fR]
\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]
.sp
.SH "DESCRIPTION"
\fBWMFS\fR is a lightweight and highly configurable tiling window manager for X written in C\&.
\fBWMFS\fR is a basic, lightweight and dynamic tiling windows manager for X\&.
.sp
.SH "OPTIONS"
.PP
@ -27,6 +30,26 @@ Load a configuration file\&.
Execute an uicb function to control WMFS\&.
.RE
.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
.RS 4
Print version information to standard output, then exit\&.
@ -36,6 +59,11 @@ Print version information to standard output, then exit\&.
.RS 4
Print help information, then exit\&.
.RE
.PP
\fB\-i\fR
.RS 4
Print WMFS information
.RE
.SH "DEFAULT KEY BINDINGS"
.PP
\fBControl\-Alt + r\fR
@ -43,34 +71,29 @@ Print help information, then exit\&.
Reload WMFS binary
.RE
.PP
\fBSuper + Return\fR
\fBControl + Return\fR
.RS 4
Run a terminal (urxvt by default)
.RE
.PP
\fBSuper + q\fR
\fBAlt + q\fR
.RS 4
Quit the selected client
.RE
.PP
\fBControl\-Alt + q\fR
\fBControl\-Alt\-Shift + q\fR
.RS 4
Exit WMFS
.RE
.PP
\fBSuper + f \fR
\fBAlt + m \fR
.RS 4
Toggle free the selected client
Toggle maximize the selected client
.RE
.PP
\fBSuper + Shift + f \fR
\fBAlt + b \fR
.RS 4
Toggle ignore_tag the selected client
.RE
.PP
\fBSuper + Shift + h \fR
.RS 4
Toggle infobar visibility
Toggle the bar position between top, hide and bottom
.RE
.PP
\fBAlt + Tab\fR
@ -83,121 +106,6 @@ Give the focus to the next client
Give the focus to the previous client
.RE
.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
.RS 4
Next tag
@ -208,581 +116,88 @@ Next tag
Previous tag
.RE
.PP
\fBControl + Up\fR
\fBAlt + Space\fR
.RS 4
Next screen
Next layout
.RE
.PP
\fBControl + Down\fR
\fBAlt\-Shift + Space\fR
.RS 4
Previous screen
Previous layout
.RE
.PP
\fBSuper + m\fR
\fBAlt + l\fR
.RS 4
Vertical mirror layout
Increase the mwfact (+0\&.025)
.RE
.PP
\fBSuper\-Shift + m\fR
\fBAlt + h\fR
.RS 4
Horizontal mirror layout
Decrease the mwfact (\-0\&.025)
.RE
.PP
\fBSuper + r\fR
\fBAlt + d\fR
.RS 4
Rotate layout right
Increase the nmaster (+1)\fR
.RE
.PP
\fBSuper\-Shift + r\fR
\fBAlt\-Shift + d\fR
.RS 4
Rotate layout left
Decrease the nmaster (\-1)\fR
.RE
.PP
\fBSuper\-Control\-Alt + h\fR
\fBAlt + t\fR
.RS 4
Integrate client in left layout
Swap the current client with the next\fR
.RE
.PP
\fBSuper\-Control\-Alt + j\fR
\fBAlt\-Shift + t\fR
.RS 4
Integrate client in bottom layout
Swap the current client with the previous\fR
.RE
.PP
\fBSuper\-Control\-Alt + k\fR
\fBAlt + p\fR
.RS 4
Integrate client in top layout
Make a launcher in the infobar to run an unix command\fR
.RE
.PP
\fBSuper\-Control\-Alt + l\fR
\fBAlt + Escape\fR
.RS 4
Integrate client in right layout
Set WMFS in ViWMFS mode. (see wmfs \-V)\fR
.RE
.PP
\fBSuper + o\fR
\fBAlt\-Shift + p\fR
.RS 4
Restore previous layout
Make a launcher in the infobar to run an ssh session\fR
.RE
.PP
\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
\fBAlt + F[1\&.\&.9]\fR
.RS 4
Change tag view
.RE
.PP
\fBSuper\-Shift + F[1\&.\&.9]\fR
\fBControl\-Shift +F[1\&.\&.9]\fR
.RS 4
Transfert the selected client to the wanted tag
.RE
.PP
\fBSuper + -\fR
.RS 4
Delete current tag\fR
.RE
.PP
\fBSuper\-Shift + -\fR
.RS 4
Add current tag\fR
.RE
.SH "CONFIGURATION"
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
.SH "BUGS"
WMFS isn\'t stable for now\&. So it certainly contains some bugs\&.
.sp
.SH "AUTHOR"
.SH "AUTHORS"
Martin Duquesnoy <\fIxorg62@gmail\&.com\fR\&[1]>\&.
.sp
.SH "WWW"
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
Main site: \fIhttp://wmfs\&.info\fR Bug tracker: \fIhttp://bugs\&.wmfs\&.info\fR
.sp
.SH "COPYING"
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

View File

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

242
wmfs.doxygen Normal file
View File

@ -0,0 +1,242 @@
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

609
wmfsrc
View File

@ -1,284 +1,475 @@
#
# WMFS2 configuration file
# This is the default wmfs config file, copy it to
# ~/.config/wmfs/wmfsrc and edit it.
#
# Possible file inclusion:
# @include "file"
# Include file to split configuration
# @include "~/.config/wmfs/menu-wmfsrc"
# Multi theme section
[themes]
[misc]
use_xft = true
font = "dejavu-10"
raisefocus = true
focus_follow_mouse = true
focus_follow_movement = true
opacity = 255
[theme]
# No name mean default
# name = "default"
# focus_pointer_click: click on unfocused client area:
# true -- default, set focus
# false -- click go to client; including dockapps
focus_pointer_click = true
[/misc]
font = "fixed"
[bar]
bg = "#191919"
fg = "#D4D4D4"
border = true
#height = "-1"
# Bars
bars_width = 14
bars_fg = "#AABBAA"
bars_bg = "#223322"
light_shade = 0.10
dark_shade = -0.10
# Element tags
tags_normal_fg = "#AABBAA"
tags_normal_bg = "#223322"
# tags_normal_statusline = ""
# Order of infobar elements:
# t = Tag list
# l = Layout button
# s = Selbar
elements_order = "tls"
tags_sel_fg = "#223322"
tags_sel_bg = "#AABBAA"
# tags_sel_statusline = ""
[systray]
# Enable/disable systray
active = true
tags_occupied_fg = "#AABBAA"
tags_occupied_bg = "#445544"
tags_occupied_statusline = "\R[0;0;100;1;#AABBAA]"
# Screen of systray
screen = 0
tags_urgent_fg = "#223322"
tags_urgent_bg = "#CC5544"
# tags_urgent_statusline = ""
# Spacing between tray icons
spacing = 3
[/systray]
tags_border_color = "#112211"
tags_border_width = 1
# Remove this section to disable the selbar.
[selbar]
bg = "#191919"
fg = "#D4D4ff"
# 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)"
# Cut title length
# max_length = 25
client_sel_fg = "#223322"
client_sel_bg = "#AABBAA"
client_sel_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
[mouse] button = "3" func = "clientlist" [/mouse]
[mouse] button = "4" func = "client_next" [/mouse]
[mouse] button = "5" func = "client_prev" [/mouse]
[/selbar]
# client_free_statusline = ""
[/bar]
frame_bg = "#555555"
client_titlebar_width = 12
client_border_width = 1
[layouts]
fg = "#191919"
bg = "#7E89A2"
[/theme]
# Border around the layout button.
border = true
[/themes]
# Value menu or switch.
system = "menu"
[bars]
# Keep layout geo for free layout
keep_layout_geo = false
# Position:
#
# 0 Top
# 1 Bottom
# 2 Hide
# Enable split mode with client_resize_<direction>
cfactor_enable_split = true
# 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)
# Symbol displayed for the selected layout in the list
selected_layout_symbol = "*"
[bar]
position = 0
screen = 0
elements = "tlsy" # element order in bar
theme = "default"
[/bar]
# Width of layout button
# layout_button_width = x
# [bar]
# position = 0
# screen = 1
# elements = "ts"
# theme = "default"
# [/bar]
# 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]
[/bars]
# Other layouts.
[layout] type = "max" symbol = "MAX" [/layout]
[layout] type = "free" symbol = "FREE" [/layout]
[/layouts]
[tags]
[default_tag]
name = "new tag"
mwfact = 0.5
nmaster = 1
layout = "tile"
resizehint = false
infobar_position = "top"
split = false
[/default_tag]
# Tag wrapping navigation
circular = false
# whether client_next on the last tag will send you on the first
# and client_prev on the first tag will send you on the last one
tag_round = false
# Use no screen option or screen = -1 to set tag on each screen
[tag]
screen = -1
name = "1"
# statusline=""
[/tag]
# Going twice on the same tag will bring you back on the previous one
tag_auto_prev = true
[tag] name = "2" [/tag]
[tag] name = "3" [/tag]
[tag] name = "4" [/tag]
[tag] name = "5" [/tag]
[tag] name = "6" [/tag]
[tag] name = "7" [/tag]
occupied_bg = "#003366"
occupied_fg = "#D4D4D4"
sel_fg = "#191919"
sel_bg = "#7E89A2"
urgent_bg = "#DD1111"
urgent_fg = "#000000"
# Mousebinds associated to Tags element button
[mouse] button = "1" func = "tag_click" [/mouse]
[mouse] button = "4" func = "tag_next" [/mouse]
[mouse] button = "5" func = "tag_prev" [/mouse]
# 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"
[tag]
name = "one"
screen = 0
mwfact = 0.65
nmaster = 1
layout = "tile_right"
resizehint = false
infobar_position = "top"
above_fc = false
split = false
#[mouse] [/mouse] Possible multi mouse section
[/tag]
[tag] name = "two" [/tag]
[tag] name = "three" [/tag]
[tag] name = "four" [/tag]
[tag] name = "five" [/tag]
[tag] name = "six" [/tag]
[tag] name = "seven" [/tag]
[tag] name = "eight" [/tag]
[tag] name = "nine" [/tag]
[/tags]
[root]
# Command you can execute to set the background.
background_command = "xsetroot -solid black"
[mouse] button = "4" func = "tag_next" [/mouse]
[mouse] button = "5" func = "tag_prev" [/mouse]
[mouse] button = "3" func = "menu" cmd = "rootmenu" [/mouse]
[/root]
[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
# Padding between clients (default: 0) :
#padding = 75
# send all client that have no tag rule in this default tag
#default_open_tag = 4
# same as above but for the screen
#default_open_screen = 1
# Give focus to new created client (default = false)
autofocus = false
# Space between tiled clients (px)
padding = 0
theme = "default"
key_modifier = "Super"
# Modifier for mouse use
modifier = "Alt"
# Focus type:
# enter : focus follow mouse (default)
# click : click to focus
# everything-else : disable mouse focus support
focus = enter
light_shade = 0.10
dark_shade = -0.10
[mouse] button = "1" func = "client_focus_click" [/mouse]
[mouse] button = "1" func = "mouse_swap" [/mouse]
[mouse] button = "2" func = "mouse_tab" [/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]
# *DEPRECATED* but works, see [rules] section
# Set automatic free or max client
# autofree = "xterm|MPlayer"
# 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]
# 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]
[rules]
[rule]
# use instance = "*" for a all-clients rule
instance = "chromium"
# role = ""
# name = ""
# theme = "default"
tag = 1 # 2nd tag
screen = 0
free = false
tab = false
ignore_tag = false
[/rule]
# Example of rule for MPlayer
[rule]
instance = "xv" # First part of WM_CLASS
class = "MPlayer" # Seconf part of WM_CLASS, not needed if first part is correct
# role = "" # WM_WINDOW_ROLE
screen = 0 # Screen to use
tag = 2 # Tag number of apps
free = true # Set automatic free client
max = false # Set automatic maximized client
follow_client = false # follow the client
ignore_tags = false # ignore tag (free mode)
[/rule]
[/rules]
[launchers]
[menu]
# Default menu, binded on the root window, button 3.
[set_menu]
name = "rootmenu"
# command can be an uicb function or an uicb function + extension (see example)
[launcher]
name = "exec"
prompt = "Run:"
# place_at_mouse = false
# x = 40 y = 50
# Example of uicb + ext:
# command = "spawn xterm -e"
command = "spawn"
# Available "center", "left", "right" menu align. Default: "center".
align = "left"
width = 150
[/launcher]
fg_focus = "#191919" bg_focus = "#7E89A2"
fg_normal = "#9F9AB3" bg_normal = "#191919"
[/launchers]
[item] name = "Terminal" func = "spawn" cmd = "urxvt || xterm || gnome-terminal" [/item]
[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]
# Reload the configuration of wmfs.
[key] mod = {"Alt", "Control"} key = "r" func = "reload" [/key]
[key] mod = {"Super"} key = "Return" func = "spawn" cmd = "urxvt || xterm" [/key]
# Open a terminal.
[key] mod = {"Control"} key = "Return" func = "spawn" cmd = "xterm" [/key]
[key] mod = {"Control", "Alt"} key = "q" func = "quit" [/key]
[key] mod = {"Control", "Alt"} key = "r" func = "reload" [/key]
# Kill the selected client.
[key] mod = {"Alt"} key = "q" func = "client_kill" [/key]
# Tag manipulation
[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]
# Quit wmfs.
[key] mod = {"Control", "Alt", "Shift"} key = "q" func = "quit" [/key]
[key] mod = {"Super", "Shift"} key = "F1" func = "tag_client" cmd = "0" [/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 next.
[key] mod = {"Alt"} key = "t" func = "client_swap_next" [/key]
[key] mod = {"Super"} key = "minus" func = "tag_del" [/key]
[key] mod = {"Super", "Shift"} key = "minus" func = "tag_new" [/key]
# Swap current client with the previous.
[key] mod = {"Alt", "Shift"} key = "t" func = "client_swap_prev" [/key]
# tag function: cmd = nameofthetag
#[key] mod = {"Super"} key = "z" func = "tag" cmd = "2" [/key]
# Set the selected client as Master
[key] mod = {"Control"} key = "m" func = "client_set_master" [/key]
[key] mod = {"Control"} key = "Right" func = "tag_next" [/key]
[key] mod = {"Control"} key = "Left" func = "tag_prev" [/key]
# Toggle maximum the selected client
[key] mod = {"Alt"} key = "m" func = "toggle_max" [/key]
[key] mod = {"Control"} key = "Up" func = "screen_next" [/key]
[key] mod = {"Control"} key = "Down" func = "screen_prev" [/key]
# Toggle free the selected client.
[key] mod = {"Alt"} key = "f" func = "toggle_free" [/key]
[key] mod = {"Super"} key = "q" func = "client_close" [/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]
# Focus next / prev client and next / prev tabbed client
[key] mod = { "Alt" } key = "Tab" func = "client_focus_next" [/key]
[key] mod = { "Alt", "Shift" } key = "Tab" func = "client_focus_prev" [/key]
[key] mod = { "Super" } key = "Tab" func = "client_focus_next_tab" [/key]
[key] mod = { "Super", "Shift" } key = "Tab" func = "client_focus_prev_tab" [/key]
# Toggle the resizehint of the current tag/screen
[key] mod = {"Shift", "Control"} key = "r" func = "toggle_resizehint" [/key]
# Focus next client with direction
[key] mod = {"Alt"} key = "h" func = "client_focus_left" [/key]
[key] mod = {"Alt"} key = "l" func = "client_focus_right" [/key]
[key] mod = {"Alt"} key = "k" func = "client_focus_top" [/key]
[key] mod = {"Alt"} key = "j" func = "client_focus_bottom" [/key]
# Toggle the tag_autohide mode
[key] mod = {"Shift", "Control"} key = "t" func = "toggle_tagautohide" [/key]
# swap next client with direction:
[key] mod = {"Control", "Shift"} key = "h" func = "client_swap_left" [/key]
[key] mod = {"Control", "Shift"} key = "l" func = "client_swap_right" [/key]
[key] mod = {"Control", "Shift"} key = "k" func = "client_swap_top" [/key]
[key] mod = {"Control", "Shift"} key = "j" func = "client_swap_bottom" [/key]
# Select the next client.
[key] mod = {"Alt"} key = "Tab" func = "client_next" [/key]
# Resize selected tiled client with direction
[key] mod = {"Super"} key = "h" func = "client_resize_left" 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 = "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 = "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 = "j" func = "client_resize_bottom" cmd = "20" [/key]
# Select the previous client.
[key] mod = {"Alt","Shift"} key = "Tab" func = "client_prev" [/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]
# Select the next tag.
[key] mod = {"Control"} key = "Right" func = "tag_next" [/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]
# Select the previous tag.
[key] mod = {"Control"} key = "Left" func = "tag_prev" [/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]
# Select the next visible tag.
[key] mod = {"Control","Alt"} key = "Right" func = "tag_next_visible" [/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]
# Select the previous visible tag.
[key] mod = {"Control","Alt"} key = "Left" func = "tag_prev_visible" [/key]
# Toggle client free/tile
[key] mod = {"Super"} key = "f" func = "client_toggle_free" [/key]
# Set the next layout.
[key] mod = {"Alt"} key = "space" func = "layout_next" [/key]
# Toggle client ignore_tag
[key] mod = {"Super", "Shift"} key = "f" func = "client_toggle_ignore_tag" [/key]
# Set the previous layout.
[key] mod = {"Alt", "Shift"} key = "space" func = "layout_prev" [/key]
# Toggle infobar visibility
[key] mod = {"Super", "Shift"} key = "h" func = "infobar_toggle_hide" cmd = "default" [/key]
# Increase nmaster.
[key] mod = {"Alt"} key = "d" func = "set_nmaster" cmd = "+1" [/key]
# Launcher
[key] mod = {"Super"} key = "p" func = "launcher" cmd = "exec" [/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
[key] mod = {"Alt"} key = "h" func = "client_focus_left" [/key]
[key] mod = {"Alt"} key = "l" func = "client_focus_right" [/key]
[key] mod = {"Alt"} key = "k" func = "client_focus_top" [/key]
[key] mod = {"Alt"} key = "j" func = "client_focus_bottom" [/key]
# Swap next client with direction
[key] mod = {"Control"} key = "h" func = "client_swap_left" [/key]
[key] mod = {"Control"} key = "l" func = "client_swap_right" [/key]
[key] mod = {"Control"} key = "k" func = "client_swap_top" [/key]
[key] mod = {"Control"} 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
[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 = "k" func = "client_resize_top" cmd = "20" [/key]
[key] mod = {"Super"} key = "j" func = "client_resize_bottom" 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 = "k" func = "client_resize_bottom" cmd = "-20" [/key]
[key] mod = { "Super", "Control"} key = "j" func = "client_resize_top" cmd = "-20" [/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]