Compare commits

...

No commits in common. "gh-pages" and "master" have entirely different histories.

94 changed files with 11194 additions and 349 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Makefile
wmfs
src/*.o

1
CNAME
View File

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

26
COPYING Normal file
View File

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

77
Makefile.in Normal file
View File

@ -0,0 +1,77 @@
PROG=wmfs
# 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
# flags
CFLAGS+= -DXDG_CONFIG_DIR=\"${XDG_CONFIG_DIR}\"
CFLAGS+= -DWMFS_VERSION=\"${VERSION}\"
CFLAGS+= -Wall -Wextra
OBJS= ${SRCS:.c=.o}
all: ${PROG}
${PROG}: ${OBJS}
${CC} -o $@ ${OBJS} ${LDFLAGS}
.c.o:
${CC} -c ${CFLAGS} $< -o $@
.PHONY: all clean distclean install uninstall dist
clean:
rm -f ${OBJS} wmfs
distclean: clean
rm -f Makefile
install: all
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
mkdir -p ${DESTDIR}${PREFIX}/bin
install ${PROG} ${DESTDIR}${PREFIX}/bin
@echo installing xsession file to ${DESTDIR}${PREFIX}/share/xsessions
mkdir -p ${DESTDIR}${PREFIX}/share/xsessions
install -m 444 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 xsession file from ${DESTDIR}${PREFIX}/share/xsessions
@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"
git archive --format=tar --prefix=wmfs-`date +%Y%m`/ master | gzip -c > wmfs-`date +%Y%m`.tar.gz

1
README Normal file
View File

@ -0,0 +1 @@
next WMFS dev branch.

107
configure vendored Executable file
View File

@ -0,0 +1,107 @@
#!/bin/sh
LIBS="x11"
USE_XINERAMA="xinerama"
USE_XRANDR="xrandr"
USE_IMLIB2="imlib2"
USE_XFT="xft freetype2"
OS=`uname -s`
PREFIX=/usr/local
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]
--without-xinerama : compile without xinerama support
--without-imlib2 : compile without imlib2 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
done
LIBS="$LIBS $USE_XINERAMA $USE_IMLIB2"
which pkg-config > /dev/null 2>&1
if [ $? -eq 0 ];
then
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
LDFLAGS="$LDFLAGS -lX11"
[ -n "$USE_XINERAMA" ] && LDFLAGS="$LDFLAGS -lXinerama"
[ -n "$USE_IMLIB2" ] && LDFLAGS="$LDFLAGS -lImlib2"
fi
[ -n "$USE_XINERAMA" ] && CFLAGS="$CFLAGS -DHAVE_XINERAMA"
[ -n "$USE_IMLIB2" ] && CFLAGS="$CFLAGS -DHAVE_IMLIB2"
# Debian hardening options http://wiki.debian.org/Hardening
which dpkg-buildflags > /dev/null 2>&1
if [ $? -eq 0 ];
then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 `dpkg-buildflags --get CFLAGS`"
LDFLAGS="$LDFLAGS `dpkg-buildflags --get LDFLAGS`"
fi
cat > Makefile << EOF
PREFIX=$PREFIX
XDG_CONFIG_DIR=$XDG_CONFIG_DIR
MANPREFIX=$MANPREFIX
CFLAGS+=$CFLAGS
LDFLAGS+=$LDFLAGS
EOF
cat Makefile.in >> Makefile
echo "Compilation resume:
OS=$OS
CFLAGS=$CFLAGS
LDFLAGS=$LDFLAGS
PREFIX=$PREFIX
MANPREFIX=$MANPREFIX
XDG_CONFIG_DIR=$XDG_CONFIG_DIR
You can run 'make' now :-)
"

45
debian/changelog vendored Normal file
View File

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

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
8

16
debian/control vendored Normal file
View File

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

54
debian/copyright vendored Normal file
View File

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

1
debian/docs vendored Normal file
View File

@ -0,0 +1 @@
README

16
debian/rules vendored Executable file
View File

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

1
debian/source/format vendored Normal file
View File

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

1
debian/wmfs.install vendored Normal file
View File

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

1
debian/wmfs.manpages vendored Normal file
View File

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

1
debian/wmfs.wm vendored Normal file
View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View File

@ -1,77 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="style.css" type="text/css" />
<link rel="Shortcut Icon" href="favicon-basic.ico" type="image/x-icon" />
<!-- Page Title -->
<title>WMFS - Window Manager From Scratch</title>
</head>
<body>
<div id="container">
<div id="header">
<h1><span>window manager from scratch by <a href="https://github.com/xorg62" title ="who is...">xorg62</a></span><a href="https://github.com/xorg62/wmfs" title="go to github">WMFS2</a></h1>
<h2><a href="https://github.com/xorg62/wmfs" title="go to git repository">git</a> | <a href="https://github.com/xorg62/wmfs/wiki" title="visit wmfs wiki eng/fr">wiki</a> | <a href="https://github.com/xorg62/wmfs/tarball/master" title="download wmfs as tgz">download</a> | <a href="mailto:xorg62@gmail.com" title="mail to xorg62">contact</a> | <a href="irc.html" title="chan #wmfs on freenode">irc</a></h2>
</div>
<div id="links">
<div class="categorie">
<img src="images/logo-snap2.png" alt="wmfs2"/>
<h2> - what ?</h2>
<p>WMFS2 is a lightweight and highly configurable tiling window manager for X written in C. wmfs2 is a free software distributed under the <a href="http://en.wikipedia.org/wiki/BSD_licenses">BSD license</a>. it can be drive from keyboard or mouse and it's configuration stands in one text file easily understandable</p>
<h2> - where ?</h2>
<p>You can download this project either in <a href="https://github.com/xorg62/wmfs/zipball/master">zip</a> or <a href="https://github.com/xorg62/wmfs/tarball/master">tar</a> formats. You can also clone the project with <a href="http://git-scm.com">Git</a> by running: <pre>$ git clone git://github.com/xorg62/wmfs.git</pre></p>
<h2> - look</h2>
<p>wmfs2 supports themable statusbars and clients</p>
<div class="slider-wrapper theme-default">
<div id="slider" class="nivoSlider">
<a href="shots/wmfs2_shots_01.png"><img src="images/wmfs2_thmb_01.png" alt=""/></a>
<a href="shots/wmfs2_shots_02.png"><img src="images/wmfs2_thmb_01.png" alt=""/></a>
<a href="shots/wmfs2_shots_03.png"><img src="images/wmfs2_thmb_03.png" alt=""/></a>
<a href="shots/wmfs2_shots_04.png"><img src="images/wmfs2_thmb_04.png" alt=""/></a>
<a href="shots/wmfs2_shots_05.png"><img src="images/wmfs2_thmb_05.png" alt=""/></a>
<a href="shots/wmfs2_shots_06.png"><img src="images/wmfs2_thmb_06.png" alt=""/></a>
<a href="shots/wmfs2_shots_07.png"><img src="images/wmfs2_thmb_07.png" alt=""/></a>
<a href="shots/wmfs2_shots_08.png"><img src="images/wmfs2_thmb_08.png" alt=""/></a>
<a href="shots/wmfs2_shots_09.png"><img src="images/wmfs2_thmb_09.png" alt=""/></a>
<a href="shots/wmfs2_shots_10.png"><img src="images/wmfs2_thmb_10.png" alt=""/></a>
</div>
<h2> - support</h2>
<a href="https://github.com/xorg62/wmfs/wiki">the wiki</a> is a good place to find answers to common questions.<br/>
need more help ? the best way to get direct support is to join our IRC channel, <a href="irc.html" title="wmfs on freenode">#wmfs on freenode</a>.
<h2> - authors</h2>
<p>Martin Duquesnoy (xorg62@gmail.com)<br />
David Delassus (david.jose.delassus@gmail.com)<br />
Paul Fariello (fariello@archos.com)<br />
Hobbestigrou (hobbestigrou@erakis.im)<br />
Philippe Pepiot (phil@philpep.org)<br />
m-r-r (raybaudroigm@gmail.com)<br />
6pi (c.sipieter@gmail.com)<br />
Jeremy Anger (angerj.dev@gmail.com)<br />
arnault (contact@arpinux.org)<br />
Romain Porte (microjoe@mailoo.org)</p>
</div>
<script type="text/javascript" src="scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="scripts/jquery.nivo.slider.pack.js"></script>
<script type="text/javascript">
$(window).load(function() {
$('#slider').nivoSlider({
effect: 'fade',
pauseTime: 5000,
controlNav: false,
randomStart: true
});
});
</script>
</div>
</div>
<div id="footer">
<p>:: theme by <a href="http://arpinux.org">arpinux</a> inspired by <a href="http://wiscot.deviantart.com">wiscot</a> :: slider by <a href="license.txt">dev7</a> :: arpinux 2012 :: license <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">cc BY-NC-SA</a> :: <a href="http://validator.w3.org/check/referer" title="Valid XHTML 1.0">XHTML</a> :: <!--a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS">CSS</a--></p>
</div>
</div>
</body>
</html>
<!-- cc BY-NC-SA License :: arpinux :: 2012 :: http://arpinux.org -->

View File

@ -1,31 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="style.css" type="text/css" />
<link rel="Shortcut Icon" href="favicon-basic.ico" type="image/x-icon" />
<!-- Page Title -->
<title>WMFS on freenode</title>
</head>
<body>
<div id="container">
<div id="header">
<h1><span>window manager from scratch by <a href="https://github.com/xorg62" title ="who is...">xorg62</a></span><a href="https://github.com/xorg62/wmfs" title="go to github">WMFS2</a></h1>
<h2><a href="https://github.com/xorg62/wmfs" title="go to git repository">git</a> | <a href="https://github.com/xorg62/wmfs/wiki" title="visit wmfs wiki eng/fr">wiki</a> | <a href="https://github.com/xorg62/wmfs/tarball/master" title="download wmfs as tgz">download</a> | <a href="mailto:xorg62@gmail.com" title="mail to xorg62">contact</a> | <a href="irc.html" title="chan #wmfs on freenode">irc</a></h2>
</div>
<div id="links">
<div class="categorie">
<iframe src="http://webchat.freenode.net?channels=wmfs" frameborder="0" width="100%" height="400"><p>your browser does not support iframes. please use an irc client like irssi, weechat or pidgin.</p></iframe>
</div>
</div>
<div id="footer">
<p>:: theme by arpinux inspired by <a href="http://wiscot.deviantart.com">wiscot</a> :: irc by <a href="http://www.qwebirc.org/">qwebirc</a> :: arpinux 2012 :: license <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/">cc BY-NC-SA</a> :: <!--a href="http://validator.w3.org/check/referer" title="Valid XHTML 1.0">XHTML</a> :: <a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS">CSS</a--></p>
</div>
</div>
</body>
</html>
<!-- cc BY-NC-SA License :: arpinux :: 2011 :: http://arpinux.org -->

View File

@ -1,25 +0,0 @@
Nivo Slider is "The Most Awesome jQuery Image Slider".
See http://nivo.dev7studios.com for more info.
Copyright (c) 2011 Gilbert Pellegrom
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

64
scripts/keybind_help.sh Executable file
View File

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

75
scripts/setlocalversion Executable file
View File

@ -0,0 +1,75 @@
#!/bin/sh
# Print additional version information for non-release trees.
usage() {
echo "Usage: $0 [srctree]" >&2
exit 1
}
cd "${1:-.}" || usage
# Check for git and a git repo.
if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
# Do we have an untagged version?
if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then
if tag=`git describe 2>/dev/null`; then
echo $tag | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
else
printf '%s%s' -g $head
fi
fi
# Is this git on svn?
if git config --get svn-remote.svn.url >/dev/null; then
printf -- '-svn%s' "`git svn find-rev $head`"
fi
# Are there uncommitted changes?
git update-index --refresh --unmerged > /dev/null
if git diff-index --name-only HEAD | grep -v "^scripts/package" \
| read dummy; then
printf '%s' -dirty
fi
# All done with git
exit
fi
# Check for mercurial and a mercurial repo.
if hgid=`hg id 2>/dev/null`; then
tag=`printf '%s' "$hgid" | cut -d' ' -f2`
# Do we have an untagged version?
if [ -z "$tag" -o "$tag" = tip ]; then
id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
printf '%s%s' -hg "$id"
fi
# Are there uncommitted changes?
# These are represented by + after the changeset id.
case "$hgid" in
*+|*+\ *) printf '%s' -dirty ;;
esac
# All done with mercurial
exit
fi
# Check for svn and a svn repo.
if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then
rev=`echo $rev | awk '{print $NF}'`
changes=`svn status 2>/dev/null | grep '^[AMD]' | wc -l`
# Are there uncommitted changes?
if [ $changes != 0 ]; then
printf -- '-svn%s%s' "$rev" -dirty
else
printf -- '-svn%s' "$rev"
fi
# All done with svn
exit
fi
# default version
printf -- '-%s' "`date +%Y%m`"

17
scripts/status.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
#WMFS status.sh example file
TIMING=10
statustext()
{
# Syntax : status <bar name> <data>
# possible sequences as data: \s[] \R[] \i[]
wmfs -c status "default `date`"
}
while true;
do
statustext
sleep $TIMING
done

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

107
src/barwin.c Normal file
View File

@ -0,0 +1,107 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "wmfs.h"
#include "barwin.h"
#include "util.h"
/** Create a barwin
* \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 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)
{
struct barwin *b = (struct barwin*)xcalloc(1, sizeof(struct barwin));
XSetWindowAttributes at =
{
.override_redirect = true,
.background_pixmap = ParentRelative,
.event_mask = BARWIN_MASK
};
if(entermask)
at.event_mask |= BARWIN_ENTERMASK;
/* Create window */
b->win = XCreateWindow(W->dpy, parent,
x, y, w, h,
0, W->xdepth,
CopyFromParent,
DefaultVisual(W->dpy, W->xscreen),
BARWIN_WINCW,
&at);
b->dr = XCreatePixmap(W->dpy, parent, w, h, W->xdepth);
/* 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);
/* Attach */
SLIST_INSERT_HEAD(&W->h.barwin, b, next);
return b;
}
/** Delete a barwin
* \param bw barwin pointer
*/
void
barwin_remove(struct barwin *b)
{
SLIST_REMOVE(&W->h.barwin, b, barwin, next);
XSelectInput(W->dpy, b->win, NoEventMask);
XDestroyWindow(W->dpy, b->win);
XFreePixmap(W->dpy, b->dr);
free(b);
}
/** Resize a barwin
* \param bw barwin pointer
* \param w Width
* \param h Height
*/
void
barwin_resize(struct barwin *b, int w, int h)
{
/* Frame */
XFreePixmap(W->dpy, b->dr);
b->dr = XCreatePixmap(W->dpy, W->root, w, h, W->xdepth);
b->geo.w = w;
b->geo.h = h;
XResizeWindow(W->dpy, b->win, w, h);
}
/** Refresh the barwin Color
* \param bw barwin pointer
*/
void
barwin_refresh_color(struct barwin *b)
{
XSetForeground(W->dpy, W->gc, b->bg);
XFillRectangle(W->dpy, b->dr, W->gc, 0, 0, b->geo.w, b->geo.h);
}

38
src/barwin.h Normal file
View File

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

1533
src/client.c Normal file

File diff suppressed because it is too large Load Diff

217
src/client.h Normal file
View File

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

422
src/config.c Normal file
View File

@ -0,0 +1,422 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "config.h"
#include "wmfs.h"
#include "parse.h"
#include "tag.h"
#include "screen.h"
#include "infobar.h"
#include "util.h"
#include "status.h"
#define ISTRDUP(t, s) \
do { \
if((tmp = s)) \
t = xstrdup(tmp); \
} while(/* CONSTCOND */ 0);
static void
config_mouse_section(struct mbhead *mousebinds, struct conf_sec **sec)
{
struct mousebind *m;
int i = 0;
char *p;
SLIST_INIT(mousebinds);
for(; sec[i]; ++i)
{
m = xcalloc(1, sizeof(struct mousebind));
m->button = fetch_opt_first(sec[i], "1", "button").num;
m->func = uicb_name_func(fetch_opt_first(sec[i], "", "func").str);
if((p = fetch_opt_first(sec[i], "", "cmd").str))
m->cmd = xstrdup(p);
m->use_area = false;
SLIST_INSERT_HEAD(mousebinds, m, next);
SLIST_INSERT_HEAD(&W->h.mousebind, m, globnext);
}
}
static void
config_theme(void)
{
struct theme *t, *p = NULL;
size_t i, n;
struct conf_sec *sec, **ks;
char *tmp;
/* [themes] */
sec = fetch_section_first(NULL, "themes");
ks = fetch_section(sec, "theme");
/* No theme section? Make one with default value anyway. */
if(!(n = fetch_section_count(ks)))
++n;
SLIST_INIT(&W->h.theme);
/* [theme]*/
for(i = 0; i < n; ++i)
{
t = (struct theme*)xcalloc(1, sizeof(struct theme));
t->name = fetch_opt_first(ks[i], "default", "name").str;
wmfs_init_font(fetch_opt_first(ks[i], "fixed", "font").str, t);
/* bars */
t->bars.fg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "bars_fg").str);
t->bars.bg = color_atoh(fetch_opt_first(ks[i], "#222222", "bars_bg").str);
t->bars_width = fetch_opt_first(ks[i], "12", "bars_width").num;
/*
* Elements
*/
t->tags_n.fg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "tags_normal_fg").str);
t->tags_n.bg = color_atoh(fetch_opt_first(ks[i], "#222222", "tags_normal_bg").str);
t->tags_s.fg = color_atoh(fetch_opt_first(ks[i], "#222222", "tags_sel_fg").str);
t->tags_s.bg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "tags_sel_bg").str);
t->tags_o.fg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "tags_occupied_fg").str);
t->tags_o.bg = color_atoh(fetch_opt_first(ks[i], "#444444", "tags_occupied_bg").str);
t->tags_u.fg = color_atoh(fetch_opt_first(ks[i], "#444444", "tags_urgent_fg").str);
t->tags_u.bg = color_atoh(fetch_opt_first(ks[i], "#CC4444", "tags_urgent_bg").str);
t->tags_border_col = color_atoh(fetch_opt_first(ks[i], "#888888", "tags_border_color").str);
t->tags_border_width = fetch_opt_first(ks[i], "0", "tags_border_width").num;
/* status line */
t->tags_n_sl = status_new_ctx(NULL, t);
t->tags_s_sl = status_new_ctx(NULL, t);
t->tags_o_sl = status_new_ctx(NULL, t);
t->tags_u_sl = status_new_ctx(NULL, t);
ISTRDUP(t->tags_n_sl.status, fetch_opt_first(ks[i], "", "tags_normal_statusline").str);
ISTRDUP(t->tags_s_sl.status, fetch_opt_first(ks[i], "", "tags_sel_statusline").str);
ISTRDUP(t->tags_o_sl.status, fetch_opt_first(ks[i], "", "tags_occupied_statusline").str);
ISTRDUP(t->tags_u_sl.status, fetch_opt_first(ks[i], "", "tags_urgent_statusline").str);
if(t->tags_n_sl.status)
status_parse(&t->tags_n_sl);
if(t->tags_s_sl.status)
status_parse(&t->tags_s_sl);
if(t->tags_o_sl.status)
status_parse(&t->tags_o_sl);
if(t->tags_u_sl.status)
status_parse(&t->tags_u_sl);
/* Client / frame */
t->client_n.fg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "client_normal_fg").str);
t->client_n.bg = color_atoh(fetch_opt_first(ks[i], "#222222", "client_normal_bg").str);
t->client_s.fg = color_atoh(fetch_opt_first(ks[i], "#222222", "client_sel_fg").str);
t->client_s.bg = color_atoh(fetch_opt_first(ks[i], "#CCCCCC", "client_sel_bg").str);
t->frame_bg = color_atoh(fetch_opt_first(ks[i], "#555555", "frame_bg").str);
t->client_titlebar_width = fetch_opt_first(ks[i], "12", "client_titlebar_width").num;
t->client_border_width = fetch_opt_first(ks[i], "1", "client_border_width").num;
/* status line */
t->client_n_sl = status_new_ctx(NULL, t);
t->client_s_sl = status_new_ctx(NULL, t);
t->client_f_sl = status_new_ctx(NULL, t);
ISTRDUP(t->client_n_sl.status, fetch_opt_first(ks[i], "", "client_normal_statusline").str);
ISTRDUP(t->client_s_sl.status, fetch_opt_first(ks[i], "", "client_sel_statusline").str);
ISTRDUP(t->client_f_sl.status, fetch_opt_first(ks[i], "", "client_free_statusline").str);
if(t->client_n_sl.status)
status_parse(&t->client_n_sl);
if(t->client_s_sl.status)
status_parse(&t->client_s_sl);
if(t->client_f_sl.status)
status_parse(&t->client_f_sl);
SLIST_INSERT_TAIL(&W->h.theme, t, next, p);
p = t;
}
free(ks);
}
static void
config_bars(void)
{
struct screen *s;
struct theme *t;
size_t i, n;
struct conf_sec *sec, **ks;
int screenid;
char *name, *elem;
enum barpos pos = BarTop;
/* [bars] */
sec = fetch_section_first(NULL, "bars");
ks = fetch_section(sec, "bar");
n = fetch_section_count(ks);
/* [bar] */
for(i = 0; i < n; ++i)
{
name = fetch_opt_first(ks[i], "default", "name").str;
elem = fetch_opt_first(ks[i], "", "elements").str;
screenid = fetch_opt_first(ks[i], "-1", "screen").num;
t = name_to_theme(fetch_opt_first(ks[i], "default", "theme").str);
pos = fetch_opt_first(ks[i], "0", "position").num;
SLIST_FOREACH(s, &W->h.screen, next)
if(screenid == s->id || screenid == -1)
infobar_new(s, name, t, pos, elem);
}
free(ks);
}
static void
config_tag(void)
{
struct screen *s;
struct tag *t;
size_t i, n;
struct conf_sec *sec, **ks, **mb;
char *name, *tmp;
int screenid;
/* [tags] */
sec = fetch_section_first(NULL, "tags");
ks = fetch_section(sec, "tag");
n = fetch_section_count(ks);
if (fetch_opt_first(sec, "1", "circular").boolean)
W->flags |= WMFS_TAGCIRC;
/* [mouse] */
if((mb = fetch_section(sec, "mouse")))
{
config_mouse_section(&W->tmp_head.tag, mb);
free(mb);
}
/* [tag] */
for(i = 0; i < n; ++i)
{
name = fetch_opt_first(ks[i], "tag", "name").str;
screenid = fetch_opt_first(ks[i], "-1", "screen").num;
SLIST_FOREACH(s, &W->h.screen, next)
if(screenid == s->id || screenid == -1)
{
t = tag_new(s, name);
t->statusctx = status_new_ctx(NULL, NULL);
ISTRDUP(t->statusctx.status, fetch_opt_first(ks[i], "", "statusline").str);
if(t->statusctx.status)
status_parse(&t->statusctx);
}
}
/* If no tag at all on a screen, add one anyway */
SLIST_FOREACH(s, &W->h.screen, next)
if(TAILQ_EMPTY(&s->tags))
tag_new(s, "tag");
free(ks);
}
static void
config_client(void)
{
struct conf_sec *sec, **mb;
char *tmp;
/* [client] */
sec = fetch_section_first(NULL, "client");
W->padding = fetch_opt_first(sec, "0", "padding").num;
W->client_mod = modkey_keysym(fetch_opt_first(sec, "Super", "key_modifier").str);
if(fetch_opt_first(sec, "0", "autofocus").boolean)
W->flags |= WMFS_AUTOFOCUS;
/* Get theme */
tmp = fetch_opt_first(sec, "default", "theme").str;
W->ctheme = name_to_theme(tmp);
/* Get focus configuration */
W->cfocus = 0;
tmp = fetch_opt_first(sec, "enter", "focus").str;
if(strstr(tmp, "enter"))
W->cfocus |= CFOCUS_ENTER;
if(strstr(tmp, "click"))
W->cfocus |= CFOCUS_CLICK;
/* [mouse] */
/* for client frame AND titlebar */
if((mb = fetch_section(sec, "mouse")))
{
config_mouse_section(&W->tmp_head.client, mb);
free(mb);
}
}
static void
config_rule(void)
{
int i, n;
struct conf_sec *sec, **ks;
struct rule *r;
char *tn, *tmp;
/* [rules] */
sec = fetch_section_first(NULL, "rules");
ks = fetch_section(sec, "rule");
n = fetch_section_count(ks);
SLIST_INIT(&W->h.rule);
/* [rule] */
for(i = 0; i < n; ++i)
{
r = (struct rule*)xcalloc(1, sizeof(struct rule));
ISTRDUP(r->class, fetch_opt_first(ks[i], "", "class").str);
ISTRDUP(r->instance, fetch_opt_first(ks[i], "", "instance").str);
ISTRDUP(r->role, fetch_opt_first(ks[i], "", "role").str);
ISTRDUP(r->name , fetch_opt_first(ks[i], "", "name").str);
r->screen = fetch_opt_first(ks[i], "-1", "screen").num;
r->tag = fetch_opt_first(ks[i], "-1", "tag").num;
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "free").boolean, RULE_FREE);
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "tab").boolean, RULE_TAB);
FLAGAPPLY(r->flags, fetch_opt_first(ks[i], "false", "ignore_tag").boolean, RULE_IGNORE_TAG);
if((tn = fetch_opt_first(ks[i], "", "theme").str))
r->theme = name_to_theme(tn);
else
r->theme = W->ctheme;
SLIST_INSERT_HEAD(&W->h.rule, r, next);
}
free(ks);
}
static void
config_launcher(void)
{
struct conf_sec *sec, **ks;
struct launcher *l;
int n, i;
/* [launchers] */
sec = fetch_section_first(NULL, "launchers");
ks = fetch_section(sec, "launcher");
n = fetch_section_count(ks);
SLIST_INIT(&W->h.launcher);
/* [launcher] */
for(i = 0; i < n; ++i)
{
l = xcalloc(1, sizeof(struct launcher));
l->name = xstrdup(fetch_opt_first(ks[i], "default", "name").str);
l->prompt = xstrdup(fetch_opt_first(ks[i], ":", "prompt").str);
l->command = xstrdup(fetch_opt_first(ks[i], "spawn", "command").str);
if((l->width = fetch_opt_first(ks[i], "150", "width").num) <= 0)
l->width = 150;
SLIST_INSERT_HEAD(&W->h.launcher, l, next);
}
free(ks);
}
static void
config_keybind(void)
{
int i, n;
size_t j;
struct conf_sec *sec, **ks;
struct opt_type *opt;
char *cmd;
struct keybind *k;
/* [keys] */
sec = fetch_section_first(NULL, "keys");
ks = fetch_section(sec, "key");
n = fetch_section_count(ks);
SLIST_INIT(&W->h.keybind);
/* [key] */
for(i = 0; i < n; ++i)
{
k = (struct keybind*)xcalloc(1, sizeof(struct keybind));
/* mod = {} */
opt = fetch_opt(ks[i], "", "mod");
for(j = k->mod = 0; j < fetch_opt_count(opt); ++j)
k->mod |= modkey_keysym(opt[j].str);
free(opt);
/* key = */
k->keysym = XStringToKeysym(fetch_opt_first(ks[i], "None", "key").str);
/* func = */
if(!(k->func = uicb_name_func(fetch_opt_first(ks[i], "", "func").str)))
{
warnxl("configuration: Unknown Function \"%s\".",
fetch_opt_first(ks[i], "", "func").str);
k->func = uicb_spawn;
}
/* cmd = */
if((cmd = fetch_opt_first(ks[i], "", "cmd").str))
k->cmd = xstrdup(cmd);
SLIST_INSERT_HEAD(&W->h.keybind, k, next);
}
wmfs_grab_keys();
free(ks);
}
void
config_init(void)
{
if(get_conf(W->confpath) == -1)
{
warnl("parsing configuration file (%s) failed.", W->confpath);
sprintf(W->confpath, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
if(get_conf(W->confpath) == -1)
{
warnxl("parsing default configuration file (%s) failed.", W->confpath);
sprintf(W->confpath, "%s/wmfs/wmfsrc", XDG_CONFIG_DIR);
if(get_conf(W->confpath) == -1)
errxl(1, "parsing system configuration file (%s) failed.", W->confpath);
}
}
config_theme();
config_keybind();
config_tag();
config_client();
config_bars();
config_rule();
config_launcher();
free_conf();
}

167
src/config.h Normal file
View File

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

113
src/draw.h Normal file
View File

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

439
src/event.c Normal file
View File

@ -0,0 +1,439 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "event.h"
#include "ewmh.h"
#include "config.h"
#include "util.h"
#include "wmfs.h"
#include "client.h"
#include "barwin.h"
#include "screen.h"
#include "systray.h"
#include "infobar.h"
#define EVDPY(e) (e)->xany.display
#define MOUSE_DO_BIND(m) \
if(m->button == ev->button) \
if(!m->use_area || (m->use_area && INAREA(ev->x, ev->y, m->area))) \
if(m->func) \
m->func(m->cmd);
static void
event_buttonpress(XEvent *e)
{
XButtonEvent *ev = &e->xbutton;
struct mousebind *m;
struct barwin *b;
struct client *c;
screen_update_sel();
status_flush_surface();
SLIST_FOREACH(b, &W->h.barwin, next)
if(b->win == ev->window)
{
W->last_clicked_barwin = b;
SLIST_FOREACH(m, &b->mousebinds, next)
MOUSE_DO_BIND(m);
SLIST_FOREACH(m, &b->statusmousebinds, next)
MOUSE_DO_BIND(m);
break;
}
if((c = client_gb_win(ev->window)) && c != W->client
&& ev->button == 1 && W->cfocus & CFOCUS_CLICK)
client_focus(c);
}
static void
event_enternotify(XEvent *e)
{
XCrossingEvent *ev = &e->xcrossing;
struct client *c;
if((ev->mode != NotifyNormal
|| ev->detail == NotifyInferior)
&& ev->window != W->root)
return;
if(ev->window == W->systray.win || systray_find(ev->window))
return;
if((c = client_gb_win(ev->window))
|| (c = client_gb_frame(ev->window)))
{
if(c->flags & CLIENT_IGNORE_ENTER)
c->flags ^= CLIENT_IGNORE_ENTER;
else if(c->tag->flags & TAG_IGNORE_ENTER)
c->tag->flags ^= TAG_IGNORE_ENTER;
else if(c != W->client && !(c->flags & CLIENT_TABBED)
&& W->cfocus & CFOCUS_ENTER)
client_focus(c);
}
}
static void
event_clientmessageevent(XEvent *e)
{
XClientMessageEvent *ev = &e->xclient;
struct client *c;
struct _systray *sy;
int type = 0;
while(type < net_last && W->net_atom[type] != ev->message_type)
++type;
/*
* Systray message
* _NET_WM_SYSTRAY_TRAY_OPCODE
*/
if(ev->window == W->systray.win && type == net_system_tray_opcode)
{
if(ev->data.l[1] == XEMBED_EMBEDDED_NOTIFY)
{
systray_add(ev->data.l[2]);
systray_update();
}
else if(ev->data.l[1] == XEMBED_REQUEST_FOCUS)
{
if((sy = systray_find(ev->data.l[2])))
ewmh_send_message(sy->win, sy->win, "_XEMBED", XEMBED_FOCUS_IN,
XEMBED_FOCUS_CURRENT, 0, 0, 0);
}
}
else if(ev->window == W->root)
{
/* WMFS message */
if(ev->data.l[4])
{
/* Manage _WMFS_FUNCTION && _WMFS_CMD */
if(type == wmfs_function || type == wmfs_cmd)
{
Atom rt;
int d;
long unsigned int len, il;
unsigned char *ret = NULL, *ret_cmd = NULL;
void (*func)(Uicb);
if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_function], 0, 65536,
False, W->net_atom[utf8_string], &rt, &d,
&len, &il, &ret) == Success
&& ret && ((func = uicb_name_func((char*)ret))))
{
if(XGetWindowProperty(EVDPY(e), W->root, W->net_atom[wmfs_cmd], 0, 65536,
False, W->net_atom[utf8_string], &rt, &d,
&len, &il, &ret_cmd) == Success
&& len && ret_cmd)
{
func((Uicb)ret_cmd);
XFree(ret_cmd);
}
else
func(NULL);
XFree(ret);
}
}
}
if(type == net_active_window)
if((sy = systray_find(ev->data.l[0])))
XSetInputFocus(W->dpy, sy->win, RevertToNone, CurrentTime);
}
switch(type)
{
/* _NET_WM_STATE */
case net_wm_state:
if((c = client_gb_win(ev->window)))
ewmh_manage_state(ev->data.l, c);
break;
/* _NET_CLOSE_WINDOW */
case net_close_window:
if((c = client_gb_win(ev->window)))
client_close(c);
break;
/* _NET_WM_DESKTOP */
case net_wm_desktop:
break;
}
}
static void
event_configureevent(XEvent *e)
{
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc;
struct client *c;
if((c = client_gb_win(ev->window)))
{
if(c->flags & CLIENT_FREE)
{
if(ev->value_mask & CWX)
c->geo.x = ev->x;
if(ev->value_mask & CWY)
c->geo.y = ev->y - c->tbarw - c->border - c->border;
if(ev->value_mask & CWWidth)
c->geo.w = ev->width + c->border + c->border;
if(ev->value_mask & CWHeight)
c->geo.h = ev->height + c->tbarw + c->border;
client_moveresize(c, &c->geo);
}
else
{
if(ev->value_mask & CWWidth)
_fac_resize(c, Right, ev->width - c->wgeo.w);
if(ev->value_mask & CWHeight)
_fac_resize(c, Bottom, ev->height - c->wgeo.h);
client_apply_tgeo(c->tag);
}
}
else
{
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
wc.height = ev->height;
wc.border_width = ev->border_width;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
XConfigureWindow(EVDPY(e), ev->window, ev->value_mask, &wc);
}
}
static void
event_destroynotify(XEvent *e)
{
XDestroyWindowEvent *ev = &e->xdestroywindow;
struct client *c;
struct _systray *s;
if((c = client_gb_win(ev->window)))
client_remove(c);
else if((s = systray_find(ev->window)))
{
ewmh_set_wm_state(s->win, WithdrawnState);
systray_del(s);
systray_update();
}
}
static void
event_focusin(XEvent *e)
{
if(W->client
&& e->xfocus.window != W->client->win
&& e->xfocus.window != W->client->frame)
client_focus(W->client);
}
static void
event_maprequest(XEvent *e)
{
XMapRequestEvent *ev = &e->xmaprequest;
XWindowAttributes at;
struct _systray *s;
/* Which windows to manage */
if(!XGetWindowAttributes(EVDPY(e), ev->window, &at)
|| at.override_redirect
|| ewmh_manage_window_type_desktop(ev->window)
|| ewmh_manage_state_sticky(ev->window))
return;
if(!client_gb_win(ev->window))
client_new(ev->window, &at, false);
else if((s = systray_find(ev->window)))
{
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
systray_update();
}
}
static void
event_mappingnotify(XEvent *e)
{
XMappingEvent *ev = &e->xmapping;
XRefreshKeyboardMapping(ev);
if(ev->request == MappingKeyboard)
wmfs_grab_keys();
}
static void
event_propertynotify(XEvent *e)
{
XPropertyEvent *ev = &e->xproperty;
XWMHints *h;
struct client *c;
struct _systray *s;
if(ev->state == PropertyDelete)
return;
if((c = client_gb_win(ev->window)))
{
switch(ev->atom)
{
case XA_WM_TRANSIENT_FOR:
break;
case XA_WM_NORMAL_HINTS:
client_get_sizeh(c);
break;
case XA_WM_HINTS:
if((h = XGetWMHints(EVDPY(e), c->win))
&& (h->flags & XUrgencyHint)
&& c->tag != W->screen->seltag)
{
c->tag->flags |= TAG_URGENT;
infobar_elem_screen_update(c->screen, ElemTag);
XFree(h);
}
break;
default:
if(ev->atom == XA_WM_NAME || ev->atom == W->net_atom[net_wm_name])
client_get_name(c);
break;
}
}
else if((s = systray_find(ev->window)))
{
systray_state(s);
systray_update();
}
}
static void
event_unmapnotify(XEvent *e)
{
XUnmapEvent *ev = &e->xunmap;
struct client *c;
struct _systray *s;
if((c = client_gb_win(ev->window))
&& ev->send_event
&& ev->event == W->root)
{
Atom rt;
unsigned long n, il;
int d;
unsigned char *ret = NULL;
if(XGetWindowProperty(EVDPY(e), c->win, W->net_atom[wm_state], 0, 2,
False, W->net_atom[wm_state], &rt, &d,
&n, &il, &ret) == Success)
if(*ret == NormalState)
client_remove(c);
}
else if((s = systray_find(ev->window)))
{
systray_del(s);
systray_update();
}
}
static void
event_keypress(XEvent *e)
{
XKeyPressedEvent *ev = &e->xkey;
KeySym keysym = XkbKeycodeToKeysym(EVDPY(e), (KeyCode)ev->keycode, 0, 0);
struct keybind *k;
screen_update_sel();
status_flush_surface();
SLIST_FOREACH(k, &W->h.keybind, next)
if(k->keysym == keysym && KEYPRESS_MASK(k->mod) == KEYPRESS_MASK(ev->state))
if(k->func)
k->func(k->cmd);
}
static void
event_expose(XEvent *e)
{
XExposeEvent *ev = &e->xexpose;
struct barwin *b;
SLIST_FOREACH(b, &W->h.barwin, next)
if(b->win == ev->window)
{
barwin_refresh(b);
return;
}
}
static void
event_mapnotify(XEvent *e)
{
XMapEvent *ev = &e->xmap;
struct client *c;
struct _systray *s;
if(ev->window != ev->event && !ev->send_event)
return;
if((c = client_gb_win(ev->window)))
client_map(c);
else if((s = systray_find(ev->window)))
{
ewmh_set_wm_state(s->win, NormalState);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
}
}
static void
event_selectionclearevent(XEvent *ev)
{
/* Getting selection if lost it */
if(ev->xselectionclear.window == W->systray.win)
systray_acquire();
systray_update();
}
static void
event_dummy(XEvent *e)
{
/* printf("%d\n", e->type);*/
(void)e;
}
void
event_init(void)
{
int i = MAX_EV;
while(i--)
event_handle[i] = event_dummy;
event_handle[ButtonPress] = event_buttonpress;
event_handle[ClientMessage] = event_clientmessageevent;
event_handle[ConfigureRequest] = event_configureevent;
event_handle[DestroyNotify] = event_destroynotify;
event_handle[EnterNotify] = event_enternotify;
event_handle[Expose] = event_expose;
event_handle[FocusIn] = event_focusin;
event_handle[KeyPress] = event_keypress;
event_handle[MapNotify] = event_mapnotify;
event_handle[MapRequest] = event_maprequest;
event_handle[MappingNotify] = event_mappingnotify;
event_handle[PropertyNotify] = event_propertynotify;
/*event_handle[ReparentNotify] = event_reparentnotify;*/
event_handle[SelectionClear] = event_selectionclearevent;
event_handle[UnmapNotify] = event_unmapnotify;
}

22
src/event.h Normal file
View File

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

378
src/ewmh.c Normal file
View File

@ -0,0 +1,378 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "ewmh.h"
#include "util.h"
#include "screen.h"
#include "client.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 */
void
ewmh_init(void)
{
int b = 1;
W->net_atom = xcalloc(net_last, 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");
/* 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");
XChangeProperty(W->dpy, W->root, W->net_atom[net_supported], XA_ATOM, 32,
PropModeReplace, (unsigned char*)W->net_atom, net_last);
XChangeProperty(W->dpy, W->root, W->net_atom[wmfs_running], XA_CARDINAL, 32,
PropModeReplace, (unsigned char*)&b, 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(W->dpy, W->root, ATOM("WM_CLASS"), XA_STRING, 8,
PropModeReplace, (unsigned char*)&"wmfs", 4);
XChangeProperty(W->dpy, W->root, W->net_atom[net_wm_name], W->net_atom[utf8_string], 8,
PropModeReplace, (unsigned char*)&"wmfs2", 5);
/*
* 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);
*/
}
void
ewmh_set_wm_state(Window w, int state)
{
unsigned char d[] = { state, None };
XChangeProperty(W->dpy, w, W->net_atom[wm_state],
W->net_atom[wm_state], 32, PropModeReplace, d, 2);
}
/*
* _NET_CLIENT_LIST
*/
void
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
*/
long
ewmh_get_xembed_state(Window win)
{
Atom rf;
int f;
long ret = 0;
unsigned long n, il;
unsigned char *data = NULL;
if(XGetWindowProperty(W->dpy, win, W->net_atom[xembedinfo], 0L, 2, False,
W->net_atom[xembedinfo], &rf, &f, &n, &il, &data) != Success)
return 0;
if(rf == W->net_atom[xembedinfo] && n == 2)
ret = (long)data[1];
if(n && data)
XFree(data);
return ret;
}
void
ewmh_update_wmfs_props(void)
{
struct screen *s;
int i, ns = 0;
long *cts = NULL;
SLIST_FOREACH(s, &W->h.screen, next)
++ns;
cts = xcalloc(ns, sizeof(long));
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);
}
void
ewmh_manage_state(long data[], struct client *c)
{
/* _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;
XChangeProperty(W->dpy, c->win, W->net_atom[net_wm_state], XA_ATOM, 32, PropModeReplace,
(unsigned char*)&W->net_atom[net_wm_state_fullscreen], 1);
XReparentWindow(W->dpy, c->win, W->root, c->screen->geo.x, c->screen->geo.y);
XResizeWindow(W->dpy, c->win, c->screen->geo.w, c->screen->geo.h);
if(c->tag)
client_focus(c);
XRaiseWindow(W->dpy, c->win);
}
else
{
c->flags &= ~CLIENT_FULLSCREEN;
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);
if(c->flags & CLIENT_FREE)
client_moveresize(c, &c->geo);
else
layout_fix_hole(c);
}
}
}
bool
ewmh_manage_state_sticky(Window win)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
bool is_sticky = false;
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,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* MANAGE _NET_WM_WINDOW_TYPE_DIALOG */
if(atom[i] == W->net_atom[net_wm_window_type_dialog])
c->flags |= CLIENT_FREE;
}
XFree(data);
}
/* _NET_WM_STATE at window mangement */
if(XGetWindowProperty(W->dpy, c->win, W->net_atom[net_wm_state], 0L, 0x7FFFFFFFL, false,
XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
ldata[1] = atom[i];
ewmh_manage_state(ldata, c);
}
XFree(data);
}
}
bool
ewmh_manage_window_type_desktop(Window win)
{
Atom *atom, rf;
int f;
unsigned long n, il, i;
unsigned char *data = NULL;
bool is_desktop = false;
if(XGetWindowProperty(W->dpy, win, W->net_atom[net_wm_window_type], 0L, 0x7FFFFFFF,
False, XA_ATOM, &rf, &f, &n, &il, &data) == Success && n)
{
atom = (Atom*)data;
for(i = 0; i < n; ++i)
{
/* If it is a _NET_WM_WINDOW_TYPE_DESKTOP window */
if(atom[i] == W->net_atom[net_wm_window_type_desktop])
{
/* map it, but don't manage it */
XMapWindow(W->dpy, win);
XMapSubwindows(W->dpy, win);
is_desktop = true;
break;
}
}
XFree(data);
}
return is_desktop;
}

131
src/ewmh.h Normal file
View File

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

19
src/fifo.h Normal file
View File

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

564
src/infobar.c Normal file
View File

@ -0,0 +1,564 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "wmfs.h"
#include "draw.h"
#include "infobar.h"
#include "barwin.h"
#include "util.h"
#include "tag.h"
#include "status.h"
#include "systray.h"
#include "client.h"
#define ELEM_FREE_BARWIN(e) \
while(!SLIST_EMPTY(&e->bars)) \
{ \
b = SLIST_FIRST(&e->bars); \
SLIST_REMOVE_HEAD(&e->bars, enext); \
barwin_remove(b); \
}
static void infobar_elem_tag_init(struct element *e);
static void infobar_elem_tag_update(struct element *e);
static void infobar_elem_status_init(struct element *e);
static void infobar_elem_status_update(struct element *e);
static void infobar_elem_systray_init(struct element *e);
static void infobar_elem_systray_update(struct element *e);
static void infobar_elem_launcher_init(struct element *e);
static void infobar_elem_launcher_update(struct element *e);
const struct elem_funcs
{
char c;
void (*func_init)(struct element *e);
void (*func_update)(struct element *e);
} elem_funcs[] =
{
{ 't', infobar_elem_tag_init, infobar_elem_tag_update },
{ 's', infobar_elem_status_init, infobar_elem_status_update },
{ 'y', infobar_elem_systray_init, infobar_elem_systray_update },
{ 'l', infobar_elem_launcher_init, infobar_elem_launcher_update },
{ '\0', NULL, NULL }
};
static void
infobar_elem_tag_init(struct element *e)
{
struct tag *t;
struct barwin *b, *prev = NULL;
int s, j;
/* Get final size before to use in placement */
e->geo.w = e->infobar->theme->tags_border_width << 1;
TAILQ_FOREACH(t, &e->infobar->screen->tags, next)
e->geo.w += draw_textw(e->infobar->theme, t->name) + PAD;
infobar_elem_placement(e);
j = e->geo.x;
e->geo.h -= (e->infobar->theme->tags_border_width << 1);
e->statusctx = &e->infobar->theme->tags_n_sl;
e->statusctx->flags |= STATUS_BLOCK_REFRESH;
if(SLIST_EMPTY(&e->bars) || (e->infobar->screen->flags & SCREEN_TAG_UPDATE))
{
if((e->infobar->screen->flags & SCREEN_TAG_UPDATE))
{
ELEM_FREE_BARWIN(e);
SLIST_INIT(&e->bars);
}
TAILQ_FOREACH(t, &e->infobar->screen->tags, next)
{
s = draw_textw(e->infobar->theme, t->name) + PAD;
/* Init barwin */
b = barwin_new(e->infobar->bar->win, j, 0, s, e->geo.h, 0, 0, false);
/* Status doesn't have theme yet */
t->statusctx.theme = e->infobar->theme;
t->statusctx.flags |= STATUS_BLOCK_REFRESH;
/* Set border */
if(e->infobar->theme->tags_border_width)
{
XSetWindowBorder(W->dpy, b->win, e->infobar->theme->tags_border_col);
XSetWindowBorderWidth(W->dpy, b->win, e->infobar->theme->tags_border_width);
}
b->ptr = (void*)t;
barwin_map(b);
b->mousebinds = W->tmp_head.tag;
SLIST_INSERT_TAIL(&e->bars, b, enext, prev);
prev = b;
j += s;
}
}
else
{
SLIST_FOREACH(b, &e->bars, enext)
{
barwin_move(b, j, 0);
j += b->geo.w;
}
}
}
static void
infobar_elem_tag_update(struct element *e)
{
struct tag *t, *sel = e->infobar->screen->seltag;
struct barwin *b;
SLIST_FOREACH(b, &e->bars, enext)
{
t = (struct tag*)b->ptr;
/* Selected */
if(t == sel)
{
b->fg = e->infobar->theme->tags_s.fg;
b->bg = e->infobar->theme->tags_s.bg;
e->statusctx = &e->infobar->theme->tags_s_sl;
}
else
{
/* Normal tag */
if(SLIST_EMPTY(&t->clients))
{
b->fg = e->infobar->theme->tags_n.fg;
b->bg = e->infobar->theme->tags_n.bg;
e->statusctx = &e->infobar->theme->tags_n_sl;
}
/* Urgent tag */
else if(t->flags & TAG_URGENT)
{
b->fg = e->infobar->theme->tags_u.fg;
b->bg = e->infobar->theme->tags_u.bg;
e->statusctx = &e->infobar->theme->tags_u_sl;
}
/* Occupied tag */
else
{
b->fg = e->infobar->theme->tags_o.fg;
b->bg = e->infobar->theme->tags_o.bg;
e->statusctx = &e->infobar->theme->tags_o_sl;
}
}
barwin_refresh_color(b);
/* Manage status line */
e->statusctx->barwin = b;
status_copy_mousebind(e->statusctx);
status_render(e->statusctx);
t->statusctx.barwin = b;
status_copy_mousebind(&t->statusctx);
status_render(&t->statusctx);
draw_text(b->dr, e->infobar->theme, (PAD >> 1),
TEXTY(e->infobar->theme, e->geo.h), b->fg, t->name);
barwin_refresh(b);
}
}
static void
infobar_elem_status_init(struct element *e)
{
struct element *en = TAILQ_NEXT(e, next);
struct barwin *b;
infobar_elem_placement(e);
e->geo.w = e->infobar->geo.w - e->geo.x - (en ? e->infobar->geo.w - en->geo.x : 0);
if(!(b = SLIST_FIRST(&e->bars)))
{
b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
barwin_refresh_color(b);
SLIST_INSERT_HEAD(&e->bars, b, enext);
e->infobar->statusctx = status_new_ctx(b, e->infobar->theme);
e->infobar->statusctx.status = strdup("wmfs2");
e->infobar->statusctx.update = true;
}
else
{
barwin_move(b, e->geo.x, e->geo.y);
barwin_resize(b, e->geo.w, e->geo.h);
}
b->fg = e->infobar->theme->bars.fg;
b->bg = e->infobar->theme->bars.bg;
barwin_map(b);
}
static void
infobar_elem_status_update(struct element *e)
{
if(e->infobar->statusctx.update)
status_manage(&e->infobar->statusctx);
else
{
status_render(&e->infobar->statusctx);
status_copy_mousebind(&e->infobar->statusctx);
}
}
static void
infobar_elem_systray_init(struct element *e)
{
struct barwin *b;
/* Activate systray mask; no more systray element allowed now */
W->flags |= WMFS_SYSTRAY;
W->systray.infobar = e->infobar;
e->geo.w = systray_get_width();
infobar_elem_placement(e);
if(!(b = SLIST_FIRST(&e->bars)))
{
b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
XFreePixmap(W->dpy, b->dr);
SLIST_INSERT_HEAD(&e->bars, b, enext);
W->systray.barwin = b;
systray_acquire();
}
else
{
barwin_move(b, e->geo.x, e->geo.y);
barwin_resize(b, e->geo.w, e->geo.h);
}
XMoveResizeWindow(W->dpy, W->systray.win, 0, 0, e->geo.w, e->geo.h);
}
static void
infobar_elem_systray_update(struct element *e)
{
(void)e;
systray_update();
}
static void
infobar_elem_launcher_init(struct element *e)
{
struct barwin *b;
if(!(W->flags & WMFS_LAUNCHER))
e->geo.w = 1;
infobar_elem_placement(e);
if(!(b = SLIST_FIRST(&e->bars)))
{
b = barwin_new(e->infobar->bar->win, e->geo.x, 0, e->geo.w, e->geo.h, 0, 0, false);
b->fg = e->infobar->theme->bars.fg;
b->bg = e->infobar->theme->bars.bg;
SLIST_INSERT_HEAD(&e->bars, b, enext);
}
else
{
barwin_move(b, e->geo.x, e->geo.y);
barwin_resize(b, e->geo.w, e->geo.h);
}
barwin_refresh_color(b);
barwin_refresh(b);
}
static void
infobar_elem_launcher_update(struct element *e)
{
struct barwin *b = SLIST_FIRST(&e->bars);
int l;
if(!(W->flags & WMFS_LAUNCHER))
return;
barwin_refresh_color(b);
l = draw_textw(e->infobar->theme, e->data) + 2;
draw_text(b->dr, e->infobar->theme, 1, TEXTY(e->infobar->theme, e->geo.h), b->fg, e->data);
/* Cursor */
XDrawLine(W->dpy, b->dr, W->gc, l, 2, l, e->geo.h - 4);
barwin_refresh(b);
}
#define ELEM_INIT(a) \
do { \
e = xcalloc(1, sizeof(struct element)); \
SLIST_INIT(&e->bars); \
e->infobar = i; \
e->type = j; \
e->data = NULL; \
e->align = a; \
e->func_init = elem_funcs[j].func_init; \
e->func_update = elem_funcs[j].func_update; \
} while(/* CONSTCOND */ 0);
static void
infobar_elem_init(struct infobar *i)
{
struct element *e, *es = NULL;
int n, j, k, l = (int)strlen(i->elemorder);
bool s = false;
TAILQ_INIT(&i->elements);
for(n = 0; n < l; ++n)
{
/* Element status found, manage other element from the end */
if(i->elemorder[n] == 's')
{
s = true;
++n;
break;
}
/* Only one systray element in a wmfs session */
if(i->elemorder[n] == 'y' && W->flags & WMFS_SYSTRAY)
continue;
for(j = 0; j < (int)LEN(elem_funcs); ++j)
if(elem_funcs[j].c == i->elemorder[n])
{
ELEM_INIT(Left);
TAILQ_INSERT_TAIL(&i->elements, e, next);
e->func_init(e);
es = e;
break;
}
}
/* Status make next elements aligning to the right */
if(s)
{
/* Manage element from the end */
for(k = l - 1; k >= n; --k)
{
/* Only one status */
if(i->elemorder[k] == 's' || (i->elemorder[n] == 'y' && W->flags & WMFS_SYSTRAY))
continue;
for(j = 0; j < (int)LEN(elem_funcs); ++j)
if(elem_funcs[j].c == i->elemorder[k])
{
ELEM_INIT(Right);
if(es)
TAILQ_INSERT_AFTER(&i->elements, es, e, next);
else
TAILQ_INSERT_HEAD(&i->elements, e, next);
e->func_init(e);
break;
}
}
/* Init status at the end */
j = ElemStatus;
ELEM_INIT(Left);
if(es)
TAILQ_INSERT_AFTER(&i->elements, es, e, next);
else
TAILQ_INSERT_HEAD(&i->elements, e, next);
e->func_init(e);
}
}
void
infobar_elem_update(struct infobar *i, int type)
{
struct element *e;
TAILQ_FOREACH(e, &i->elements, next)
if(type == e->type || type == -1)
e->func_update(e);
}
void
infobar_elem_reinit(struct infobar *i)
{
struct element *e;
barwin_refresh_color(i->bar);
TAILQ_FOREACH(e, &i->elements, next)
{
/* Status element found, scan from the tail now */
if(e->type == ElemStatus)
{
struct element *ee;
TAILQ_FOREACH_REVERSE(ee, &i->elements, esub, next)
{
if(e == ee)
break;
ee->func_init(ee);
ee->func_update(ee);
}
e->func_init(e);
e->func_update(e);
return;
}
e->func_init(e);
e->func_update(e);
}
barwin_refresh(i->bar);
}
struct infobar*
infobar_new(struct screen *s, char *name, struct theme *theme, enum barpos pos, const char *elem)
{
bool map;
struct infobar *i = (struct infobar*)xcalloc(1, sizeof(struct infobar));
i->screen = s;
i->theme = theme;
i->elemorder = xstrdup(elem);
i->name = xstrdup(name);
map = infobar_placement(i, pos);
/* struct barwin create */
i->bar = barwin_new(W->root, i->geo.x, i->geo.y, i->geo.w, i->geo.h,
theme->bars.fg, theme->bars.bg, false);
SLIST_INSERT_HEAD(&s->infobars, i, next);
/* struct elements */
infobar_elem_init(i);
/* Render, only if pos is Top or Bottom */
if(!map)
return i;
barwin_map(i->bar);
barwin_map_subwin(i->bar);
barwin_refresh_color(i->bar);
infobar_refresh(i);
return i;
}
void
infobar_refresh(struct infobar *i)
{
infobar_elem_update(i, -1);
barwin_refresh(i->bar);
}
void
infobar_remove(struct infobar *i)
{
struct element *e;
struct barwin *b;
free(i->elemorder);
free(i->name);
if(i == W->systray.infobar)
systray_freeicons();
while(!TAILQ_EMPTY(&i->elements))
{
e = TAILQ_FIRST(&i->elements);
TAILQ_REMOVE(&i->elements, e, next);
ELEM_FREE_BARWIN(e);
free(e);
}
barwin_remove(i->bar);
SLIST_REMOVE(&i->screen->infobars, i, infobar, next);
free(i);
}
void
infobar_free(struct screen *s)
{
struct infobar *i;
while(!SLIST_EMPTY(&s->infobars))
{
i = SLIST_FIRST(&s->infobars);
/* SLIST_REMOVE is done by infobar_remove */
infobar_remove(i);
}
}
void
uicb_infobar_toggle_hide(Uicb iname)
{
struct client *c;
struct infobar *i;
if(iname)
i = infobar_gb_name(iname);
else
i = SLIST_FIRST(&W->screen->infobars);
if(i->pos == BarHide)
{
i->pos = i->opos;
if(infobar_placement(i, i->pos))
{
barwin_map(i->bar);
barwin_map_subwin(i->bar);
barwin_refresh_color(i->bar);
infobar_refresh(i);
}
}
else
{
i->opos = i->pos;
i->pos = BarHide;
barwin_unmap_subwin(i->bar);
barwin_unmap(i->bar);
switch(i->opos)
{
case BarTop:
i->screen->ugeo.y -= i->geo.h;
case BarBottom:
i->screen->ugeo.h += i->geo.h;
case BarHide:
default:
break;
}
}
SLIST_FOREACH(c, &W->h.client, next)
layout_fix_hole(c);
}

93
src/infobar.h Normal file
View File

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

438
src/launcher.c Normal file
View File

@ -0,0 +1,438 @@
/*
* 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>
#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)
{
return (strcmp(*(char **)a, *(char **)b));
}
static char **
complete_on_command(char *start)
{
struct dirent *content;
DIR *dir;
char **paths, *path, *p, **namelist = NULL;
int i, count;
if(!(path = getenv("PATH")) || !start)
return NULL;
/* split PATH into paths */
path = p = xstrdup(path);
for(count = 1, p = path; strchr(p, ':'); ++p, ++count);
paths = xcalloc(count, sizeof(*paths));
for(paths[0] = p = path, count = 1; (p = strchr(p, ':')); ++p, ++count)
{
paths[count] = p + 1;
*p = '\0';
}
paths[count] = NULL;
/* recursively open PATH */
for(i = count = 0; paths[i]; ++i)
{
if(!(dir = opendir(paths[i])))
continue;
while((content = readdir(dir)))
{
if(strncmp(content->d_name, ".", 1)
&& !strncmp(content->d_name, start, strlen(start)))
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = xstrdup(content->d_name + strlen(start));
}
}
closedir(dir);
}
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;
}
/*
* Complete a filename or directory name.
* works like complete_on_command.
*/
static char **
complete_on_files(char *start)
{
struct dirent *content = NULL;
struct stat st;
DIR *dir;
char *home, *path, *dirname = NULL;
char **namelist = NULL, *filepath, *p = start;
int count = 0;
/*
* Search the directory to open and set
* the beginning of file to complete on pointer '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);
else
dirname = xstrdup(p);
/* Set p to filename to be complete
* and path the directory containing the file
* /foooooo/baaaaaar/somethinglikethis<tab>
* <---- path - ---><------- p ------>
*/
p = strrchr(dirname, '/');
if(p != dirname)
{
*(p++) = '\0';
path = xstrdup(dirname);
}
else
{
path = xstrdup("/");
p++;
}
}
if((dir = opendir(path)))
{
while((content = readdir(dir)))
{
if(!strcmp(content->d_name, ".")
|| !strcmp(content->d_name, "..")
|| strncmp(content->d_name, p, strlen(p)))
continue;
/* If it's a directory append '/' to the completion */
xasprintf(&filepath, "%s/%s", path, content->d_name);
if(filepath && stat(filepath, &st) != -1)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
if(S_ISDIR(st.st_mode))
xasprintf(&namelist[count - 1], "%s/", content->d_name + strlen(p));
else
namelist[count - 1] = xstrdup(content->d_name + strlen(p));
}
else
warnl("%s", filepath);
free(filepath);
}
closedir(dir);
}
if(count)
{
namelist = xrealloc(namelist, ++count, sizeof(*namelist));
namelist[count - 1] = NULL;
}
free(dirname);
free(path);
return namelist;
}
static void
complete_cache_free(struct launcher_ccache *cache)
{
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 };
char tmp[32] = { 0 };
char *p, *data, *arg, *end, *cmd = xstrdup(l->command);
int i, pos = 0, histpos = 0;
void (*func)(Uicb);
XEvent ev;
KeySym ks;
W->flags |= WMFS_LAUNCHER;
/* Prepare elements */
xasprintf(&data, "%s ", l->prompt);
LAUNCHER_INIT_ELEM(l->width);
XGrabKeyboard(W->dpy, W->root, true, GrabModeAsync, GrabModeAsync, CurrentTime);
while(loop)
{
XNextEvent(W->dpy, &ev);
if(ev.type != KeyPress)
{
EVENT_HANDLE(&ev);
continue;
}
/* Get pressed key */
XLookupString(&ev.xkey, tmp, sizeof(tmp), &ks, 0);
/* 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)
{
func(arg);
free(arg);
}
else
func(buf);
}
/* Histo */
if(l->nhisto + 1 > HISTOLEN)
{
for(i = l->nhisto - 1; i > 1; --i)
strncpy(l->histo[i], l->histo[i - 1], sizeof(l->histo[i]));
l->nhisto = 0;
}
/* Store in histo array */
strncpy(l->histo[l->nhisto++], buf, sizeof(buf));
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;
}
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);
}
}
}
XUngrabKeyboard(W->dpy, CurrentTime);
complete_cache_free(&cache);
free(cmd);
free(data);
/* 'Close' launcher elements */
W->flags ^= WMFS_LAUNCHER;
data = NULL;
LAUNCHER_INIT_ELEM(1);
}
void
uicb_launcher(Uicb cmd)
{
struct launcher *l;
if(!cmd)
return;
SLIST_FOREACH(l, &W->h.launcher, next)
if(!strcmp(l->name, cmd))
{
launcher_process(l);
break;
}
}

13
src/launcher.h Normal file
View File

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

644
src/layout.c Normal file
View File

@ -0,0 +1,644 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include "layout.h"
#include "config.h"
#include "client.h"
#include "draw.h"
#include "event.h"
#include "util.h"
/* Shift in client split to keep clients's parent at close arrange */
static int shiftv = 1, shifth = 1;
void
layout_save_set(struct tag *t)
{
struct client *c;
struct layout_set *l;
struct geo_list *g, *gp;
int n = 1;
l = xcalloc(1, sizeof(struct layout_set));
SLIST_INIT(&l->geos);
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
g = xcalloc(1, sizeof(struct geo_list));
g->geo = c->geo;
if(!SLIST_FIRST(&l->geos))
SLIST_INSERT_HEAD(&l->geos, g, next);
else
SLIST_INSERT_AFTER(gp, g, next);
++n;
gp = g;
}
l->n = n;
TAILQ_INSERT_TAIL(&t->sets, l, next);
}
static void
layout_apply_set(struct tag *t, struct layout_set *l)
{
struct geo_list *g;
struct client *c;
int nc = 1;
FOREACH_NFCLIENT(c, &t->clients, tnext)
++nc;
/* TODO: Adapt different client number case */
if(l->n != nc)
return;
for(g = SLIST_FIRST(&l->geos), c = SLIST_FIRST(&t->clients);
c; c = SLIST_NEXT(c, tnext))
{
if(g)
{
client_moveresize(c, &g->geo);
g = SLIST_NEXT(g, next);
}
/* TODO
* Not enough geos in the set;
* then integrate remains of client
*
else
layout_split_integrate(c, SLIST_FIRST(&t->clients));
*/
}
/* TODO
* Not enough clients for geos in set;
* arrange clients with not set geo.
*
if((g = SLIST_NEXT(g, next)))
for(cc.tag = t; g; g = SLIST_NEXT(g, next))
{
cc.geo = g->geo;
layout_split_arrange_closed(&cc);
}
*/
/* Re-insert set in historic */
layout_save_set(t);
}
void
layout_free_set(struct tag *t)
{
struct layout_set *l;
while(!TAILQ_EMPTY(&t->sets))
{
l = TAILQ_FIRST(&t->sets);
TAILQ_REMOVE(&t->sets, l, next);
FREE_LIST(geo_list, l->geos);
free(l);
}
}
#define _REV_BORDER() \
SLIST_FOREACH(g, &l->geos, next) { \
cd.geo = g->geo; \
draw_reversed_rect(W->root, &cd, false); \
}
static void
_historic_set(struct tag *t, bool prev)
{
struct keybind *k;
struct layout_set *l;
struct geo_list *g;
struct client cd = { .screen = t->screen, .theme = THEME_DEFAULT };
bool b = true;
XEvent ev;
KeySym keysym;
if(TAILQ_EMPTY(&t->sets))
return;
l = TAILQ_LAST(&t->sets, ssub);
if(prev)
l = TAILQ_PREV(l, ssub, next);
if(!l)
return;
/* TODO
if(option_simple_manual_resize)
{
layout_set_apply(l);
return;
*/
XGrabKeyboard(W->dpy, W->root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
_REV_BORDER();
do
{
XMaskEvent(W->dpy, KeyPressMask, &ev);
if(ev.type == KeyPress)
{
XKeyPressedEvent *ke = &ev.xkey;
keysym = XkbKeycodeToKeysym(W->dpy, (KeyCode)ke->keycode, 0, 0);
_REV_BORDER();
SLIST_FOREACH(k, &W->h.keybind, next)
if(k->keysym == keysym && KEYPRESS_MASK(k->mod) == KEYPRESS_MASK(ke->state)
&& k->func)
{
if(k->func == uicb_layout_prev_set)
{
if(!(l = TAILQ_PREV(l, ssub, next)))
l = TAILQ_LAST(&t->sets, ssub);
}
else if(k->func == uicb_layout_next_set)
{
if(!(l = TAILQ_NEXT(l, next)))
l = TAILQ_FIRST(&t->sets);
}
else
{
k->func(k->cmd);
keysym = XK_Escape;
}
}
if(!l)
l = TAILQ_LAST(&t->sets, ssub);
_REV_BORDER();
/* Gtfo of this loop */
if(keysym == XK_Return)
break;
else if(keysym == XK_Escape)
{
b = false;
break;
}
XSync(W->dpy, False);
}
XNextEvent(W->dpy, &ev);
} while(ev.type != KeyPress);
_REV_BORDER();
if(b)
layout_apply_set(t, l);
XUngrabServer(W->dpy);
XUngrabKeyboard(W->dpy, CurrentTime);
}
void
uicb_layout_prev_set(Uicb cmd)
{
(void)cmd;
_historic_set(W->screen->seltag, true);
}
void
uicb_layout_next_set(Uicb cmd)
{
(void)cmd;
_historic_set(W->screen->seltag, false);
}
static struct geo
layout_split(struct client *c, bool vertical)
{
struct geo og, geo;
geo = og = c->geo;
if(vertical)
{
c->geo.w >>= 1;
c->geo.w += shiftv;
geo.x = c->geo.x + c->geo.w;
geo.w >>= 1;
/* Remainder */
geo.w += (og.x + og.w) - (geo.x + geo.w);
shiftv = -shiftv;
}
else
{
c->geo.h >>= 1;
c->geo.h += shifth;
geo.y = c->geo.y + c->geo.h;
geo.h >>= 1;
/* Remainder */
geo.h += (og.y + og.h) - (geo.y + geo.h);
shifth = -shifth;
}
return geo;
}
static inline void
layout_split_arrange_size(struct geo *g, struct client *c, enum position p)
{
if(LDIR(p))
{
c->geo.w += g->w;
if(p == Right)
c->geo.x = g->x;
}
else
{
c->geo.h += g->h;
if(p == Bottom)
c->geo.y = g->y;
}
client_moveresize(c, &c->geo);
}
static inline bool
layout_split_check_row_dir(struct client *c, struct client *g, enum position p)
{
struct geo cgeo = c->geo;
struct client *cc;
int s = 0, cs = (LDIR(p) ? g->geo.h : g->geo.w);
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(cgeo, cc->geo, RPOS(p))
&& GEO_CHECK_ROW(cc->geo, g->geo, p))
{
s += (LDIR(p) ? cc->geo.h : cc->geo.w);
if(s == cs)
return true;
if(s > cs)
return false;
}
return false;
}
/* Use ghost client properties to fix holes in tile
*
* ~ .--. ~ ~
*_____ ~ /xx \ ~ ~
* |>>| ~\O _ (____ ~
* | |__.| .--'-==~ ~
* |>>'---\ '. ~ , ~
*__|__| '. '-.___.-'/ ~
* '-.__ _.' ~
* ````` ~
*/
#define _ARRANGE_SINGLE_PARENT(p) \
do { \
if((c = client_next_with_pos(ghost, p))) \
if(GEO_CHECK2(ghost->geo, c->geo, p)) \
{ \
layout_split_arrange_size(&ghost->geo, c, p); \
layout_save_set(ghost->tag); \
return; \
} \
} while(/* CONSTCOND */ 0);
void
layout_split_arrange_closed(struct client *ghost)
{
struct client *c, *cc;
struct geo g;
bool b = false;
enum position p;
if(!(ghost->flags & CLIENT_TILED))
return;
/* Search for single parent for easy resize
* Example case:
* ___________ ___________
* | | B | -> -> | | |
* | A |_____| -> Close -> | A | B |
* | | C | -> C -> | |v v v|
* |_____|_____| -> -> |_____|_____|
*/
_ARRANGE_SINGLE_PARENT(Right);
_ARRANGE_SINGLE_PARENT(Left);
_ARRANGE_SINGLE_PARENT(Top);
_ARRANGE_SINGLE_PARENT(Bottom);
/* 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_next_with_pos(ghost, p))
&& layout_split_check_row_dir(c, ghost, p))
{
g = c->geo;
FOREACH_NFCLIENT(cc, &c->tag->clients, tnext)
if(GEO_PARENTROW(g, cc->geo, RPOS(p))
&& GEO_CHECK_ROW(cc->geo, ghost->geo, p))
{
layout_split_arrange_size(&ghost->geo, cc, p);
b = true;
}
}
}
layout_save_set(ghost->tag);
}
/*
* Integrate a client in split layout:
* - Check if there is no sc
* - Check if sc is on a different tag than c
* - Check if sc is not in free mode
*
* So from there, sc is not compatible, so we will integrate
* c in the larger tiled client of c tag:
* - Check if the larger client is correct
*
* Checks all failed? Get first tiled client of the tag to integrate in.
* Still no client, it means that c is the first tiled client of the tag, then maximize it.
*/
void
layout_split_integrate(struct client *c, struct client *sc)
{
struct geo g;
bool f = false;
/* No sc or not compatible, get the largest of the tag */
if(!sc
|| sc == c
|| sc->tag != c->tag
|| (sc->flags & CLIENT_FREE)
|| !COMPCLIENT(c, sc))
sc = client_get_larger(c->tag, c->flags & CLIENT_IGNORE_TAG);
/* Largest not correct */
if(!sc || sc == c)
{
FOREACH_NFCLIENT(sc, &c->tag->clients, tnext)
if(sc != c && !(sc->flags & CLIENT_TABBED))
{
f = true;
break;
}
/* Ok there is no client to integrate in */
if(!f)
{
client_maximize(c);
c->flags |= CLIENT_TILED;
W->flags &= ~WMFS_TABNOC;
return;
}
}
/* Tab Next Opened Client option */
if(W->flags & WMFS_TABNOC && COMPCLIENT(c, sc))
{
W->flags ^= WMFS_TABNOC;
_client_tab(c, sc);
return;
}
/* If there are clients but we can tab with them, split the screen. */
c->flags |= CLIENT_TILED;
g = layout_split(sc, (sc->geo.h < sc->geo.w));
client_moveresize(c, &g);
client_moveresize(sc, &sc->geo);
client_fac_hint(c);
client_fac_hint(sc);
layout_save_set(c->tag);
W->flags &= ~WMFS_TABNOC;
}
/* Arrange inter-clients holes:
* ___________ ___________
* | || | -> | | |
* | A || B | -> | A >| B |
* | || | -> | >| |
* |_____||____| -> |______|____|
* ^ void
*
* and client-screen edge holes
* ___________ ___________
* | | || -> | | |
* | A | B || -> | A | B >|
* | | || -> | | >|
* |_____|----'| -> |_____|__v__|
* ^^^ void
*/
void
layout_fix_hole(struct client *c)
{
struct client *cr = client_next_with_pos(c, Right);
struct client *cb = client_next_with_pos(c, Bottom);
c->geo.w += (cr ? cr->geo.x : c->screen->ugeo.w) - (c->geo.x + c->geo.w);
c->geo.h += (cb ? cb->geo.y : c->screen->ugeo.h) - (c->geo.y + c->geo.h);
client_moveresize(c, &c->geo);
}
/* Layout rotation: Rotate 90° all client to right or left.
* Avoid if(left) condition in layout_rotate loop; use func ptr
*
* Right rotation
* ____________ ____________
* | | B | -> | | A |
* | A |_______| -> |__|_________|
* |____| C | D | -> |_____| B |
* |____|___|___| -> |_____|______|
*
* Left rotation
* ____________ ____________
* | | B | -> | B |_____|
* | A |_______| -> |______|_____|
* |____| C | D | -> | A | |
* |____|___|___| -> |_________|__|
*
*/
static inline void
_pos_rotate_left(struct geo *g, struct geo *ug, struct geo *og)
{
g->x = (ug->h - (og->y + og->h));
g->y = og->x;
}
static inline void
_pos_rotate_right(struct geo *g, struct geo *ug, struct geo *og)
{
g->x = og->y;
g->y = (ug->w - (og->x + og->w));
}
static void
layout_rotate(struct tag *t, void (*pfunc)(struct geo*, struct geo*, struct geo*))
{
struct client *c;
struct geo g, *ug = &t->screen->ugeo;
float f1 = (float)t->screen->ugeo.w / (float)t->screen->ugeo.h;
float f2 = 1 / f1;
FOREACH_NFCLIENT(c, &t->clients, tnext)
{
pfunc(&g, ug, &c->geo);
g.x *= f1;
g.y *= f2;
g.w = c->geo.h * f1;
g.h = c->geo.w * f2;
client_moveresize(c, &g);
}
/* Rotate sometimes do not set back perfect size.. */
FOREACH_NFCLIENT(c, &t->clients, tnext)
layout_fix_hole(c);
layout_save_set(t);
}
void
uicb_layout_rotate_left(Uicb cmd)
{
(void)cmd;
layout_rotate(W->screen->seltag, _pos_rotate_left);
}
void
uicb_layout_rotate_right(Uicb cmd)
{
(void)cmd;
layout_rotate(W->screen->seltag, _pos_rotate_right);
}
/*
* Really simple functions, don't need static no-uicb backend
* so we avoid the use of if(vertical) .. else
*
* Vertical mirror
* ____________ ____________
* | | B | -> | B | |
* | A |_______| -> |_______| A |
* | | C | D | -> | D | C | |
* |____|___|___| -> |___|___|____|
*
* Horizontal mirror
* ____________ ____________
* | | B | -> | | C | D |
* | A |_______| -> | A |___|___|
* | | C | D | -> | | B |
* |____|___|___| -> |____|_______|
*/
void
uicb_layout_vmirror(Uicb cmd)
{
(void)cmd;
struct client *c;
FOREACH_NFCLIENT(c, &W->screen->seltag->clients, tnext)
{
c->geo.x = W->screen->ugeo.w - (c->geo.x + c->geo.w);
client_moveresize(c, &c->geo);
}
layout_save_set(W->screen->seltag);
}
void
uicb_layout_hmirror(Uicb cmd)
{
(void)cmd;
struct client *c;
FOREACH_NFCLIENT(c, &W->screen->seltag->clients, tnext)
{
c->geo.y = W->screen->ugeo.h - (c->geo.y + c->geo.h);
client_moveresize(c, &c->geo);
}
layout_save_set(W->screen->seltag);
}
#define LAYOUT_INTEGRATE_DIR(D) \
void uicb_layout_integrate_##D(Uicb cmd) \
{ \
(void)cmd; \
if(W->client) \
layout_integrate(W->client, D); \
}
static void
layout_integrate(struct client *c, enum position p)
{
struct client *n;
struct client ghost = *c;
if(!(c->flags & CLIENT_TILED))
return;
if((n = client_next_with_pos(c, p))
&& (n->flags & CLIENT_TILED))
{
layout_split_integrate(c, n);
layout_split_arrange_closed(&ghost);
}
}
LAYOUT_INTEGRATE_DIR(Left);
LAYOUT_INTEGRATE_DIR(Right);
LAYOUT_INTEGRATE_DIR(Top);
LAYOUT_INTEGRATE_DIR(Bottom);
void
layout_client(struct client *c)
{
if(c->flags & (CLIENT_IGNORE_LAYOUT | CLIENT_FULLSCREEN))
{
c->flags &= ~CLIENT_IGNORE_LAYOUT;
return;
}
if(c->flags & CLIENT_FREE)
{
layout_split_arrange_closed(c);
c->flags ^= CLIENT_TILED;
client_moveresize(c, &c->geo);
XRaiseWindow(W->dpy, c->frame);
}
else if(!(c->flags & CLIENT_TABBED))
layout_split_integrate(c, c->tag->sel);
}

54
src/layout.h Normal file
View File

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

110
src/log.c Normal file
View File

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

18
src/log.h Normal file
View File

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

242
src/mouse.c Normal file
View File

@ -0,0 +1,242 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#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);
#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)
{
struct client *gc;
XEvent ev;
Window w;
int d, u, ox, oy, ix, iy;
int mx, my;
XQueryPointer(W->dpy, W->root, &w, &w, &ox, &oy, &d, &d, (unsigned int *)&u);
XGrabServer(W->dpy);
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
}
else
_REV_BORDER();
if(c->flags & CLIENT_TABBED && !(c->flags & CLIENT_TABMASTER))
c = c->tabmaster;
ix = ox;
iy = oy;
c->flags |= CLIENT_MOUSE;
do
{
XMaskEvent(W->dpy, MouseMask | SubstructureRedirectMask, &ev);
if(ev.type != MotionNotify)
continue;
mx = ev.xmotion.x_root;
my = ev.xmotion.y_root;
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
mx -= c->screen->ugeo.x;
my -= c->screen->ugeo.y;
c->geo.w = ((mx - c->geo.x <= c->sizeh[MINW] + c->border + c->border)
? c->sizeh[MINW] + c->border + c->border
: mx - c->geo.x);
c->geo.h = ((my - c->geo.y <= (c->sizeh[MINH] + c->tbarw + c->border))
? c->sizeh[MINH] + c->tbarw + c->border
: my - c->geo.y);
client_geo_hints(&c->geo, (int*)c->sizeh);
/* For border preview cohesion */
c->geo.h += c->tbarw + c->border;
c->geo.w += c->border + c->border;
_REV_SBORDER(c);
}
else
{
_REV_BORDER();
if(ix >= c->rgeo.x + (c->geo.w >> 1))
_fac_resize(c, Right, mx - ox);
else
_fac_resize(c, Left, ox - mx);
if(iy >= c->rgeo.y + (c->geo.h >> 1))
_fac_resize(c, Bottom, my - oy);
else
_fac_resize(c, Top, oy - my);
ox = mx;
oy = my;
_REV_BORDER();
}
XSync(W->dpy, false);
} while(ev.type != ButtonRelease);
if(c->flags & CLIENT_FREE)
{
_REV_SBORDER(c);
client_moveresize(c, &c->geo);
}
else
{
_REV_BORDER();
client_apply_tgeo(c->tag);
layout_save_set(c->tag);
}
c->flags &= ~CLIENT_MOUSE;
XUngrabServer(W->dpy);
}
static struct tag*
mouse_drag_tag(struct client *c, Window w)
{
struct barwin *b;
struct tag *t = NULL;
Window rw;
int d, u;
XQueryPointer(W->dpy, w, &rw, &rw, &d, &d, &d, &d, (uint *)&u);
SLIST_FOREACH(b, &W->h.barwin, next)
if(b->win == rw
&& (t = (struct tag*)b->ptr)
&& t != c->tag)
return t;
return NULL;
}
void
mouse_move(struct client *c, void (*func)(struct client*, struct client*))
{
struct client *c2 = NULL, *last = c;
struct tag *t = NULL;
XEvent ev;
Window w;
int d, u, ox, oy;
int ocx, ocy;
ocx = c->geo.x;
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)))
{
if(c2 != last)
{
_REV_SBORDER(last);
_REV_SBORDER(c2);
last = c2;
}
}
else
t = mouse_drag_tag(c, w);
}
XSync(W->dpy, false);
} while(ev.type != ButtonRelease);
if(c2)
func(c, c2);
else if(t && t != (struct tag*)c)
tag_client(t, c);
else
{
_REV_SBORDER(c);
/* No func mean free client resize */
if(!func)
client_moveresize(c, &c->geo);
}
c->flags &= ~CLIENT_MOUSE;
}
void
uicb_mouse_resize(Uicb cmd)
{
(void)cmd;
if(W->client && mouse_check_client(W->client))
mouse_resize(W->client);
}
void
uicb_mouse_move(Uicb cmd)
{
(void)cmd;
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, (W->client->flags & CLIENT_FREE ? NULL : client_swap2));
}
void
uicb_mouse_tab(Uicb cmd)
{
(void)cmd;
if(W->client && mouse_check_client(W->client))
mouse_move(W->client, _client_tab);
}

29
src/mouse.h Normal file
View File

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

693
src/parse.c Normal file
View File

@ -0,0 +1,693 @@
/*
* 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <libgen.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/param.h>
#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
{
const char *name;
enum keyword_t type;
} 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},
};
#endif
struct files
{
char *name;
struct files *parent;
};
struct keyword
{
enum keyword_t type;
/* if WORD */
int line;
struct files *file;
char *name;
struct keyword *next;
};
struct state
{
bool quote;
bool comment;
char quote_char;
};
/* TO REMOVE (use a identifier for config and fallback XDG in api functions) */
TAILQ_HEAD(, conf_sec) config;
static struct keyword *keywords = NULL;
static struct keyword *
push_keyword(struct keyword *tail, enum keyword_t type, char *buf, size_t *offset, struct files *file, int line)
{
struct keyword *kw;
#ifdef DEBUG
int i = 0;
#endif
if(type == WORD && *offset == 0)
return tail;
kw = xcalloc(1, sizeof(*kw));
kw->type = type;
kw->line = line;
kw->file = file;
kw->next = NULL;
if(*offset)
{
buf[*offset] = '\0';
if(!strcmp(buf, INCLUDE_CMD))
kw->type = INCLUDE;
else
kw->name = strdup(buf);
*offset = 0;
}
else
kw->name = NULL;
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,
(kw->name) ? kw->name : "",
kw->file->name, kw->line);
#endif
return kw;
}
static void
syntax(struct keyword *kw, const char *fmt, ...)
{
va_list args;
fprintf(stderr, "%s:", __progname);
if(kw && kw->file && kw->file->name)
fprintf(stderr, "%s:%d", kw->file->name, kw->line);
if(kw && kw->name)
fprintf(stderr, ", near '%s'", kw->name);
fprintf(stderr, ": ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
}
#define PUSH_KEYWORD(type) tail = push_keyword(tail, type, bufname, &j, file, line)
static struct keyword *
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'};
char *bufname;
char path[PATH_MAX];
size_t i, j;
int line;
bool error = false;
if(stat(filename, &st) == -1 || (fd = open(filename, O_RDONLY)) == -1)
{
warnxl("%s", filename);
return NULL;
}
if(!st.st_size)
{
warnxl("%s: empty file", filename);
close(fd);
return NULL;
}
if(!realpath(filename, path))
{
warnxl("%s", filename);
close(fd);
return NULL;
}
buf = xmalloc(1, st.st_size + 1);
if(read(fd, buf, st.st_size) == -1)
{
warnxl("%s", filename);
free(buf);
close(fd);
return NULL;
}
buf[st.st_size] = '\0';
file = xcalloc(1, sizeof(*file));
bufname = xcalloc(BUFSIZ, sizeof(*bufname));
file->name = strdup(path);
file->parent = NULL;
for(i = j = 0, line = 1; i < (size_t)st.st_size; ++i)
{
if(!head && tail)
head = tail;
if(buf[i] == '\n' && s.comment)
{
line++;
s.comment = false;
continue;
}
if(buf[i] == '#' && !s.quote)
{
s.comment = true;
continue;
}
if(s.comment)
continue;
/* end of quotted string */
if(s.quote && buf[i] == s.quote_char)
{
PUSH_KEYWORD(WORD);
s.quote = false;
continue;
}
if(!s.quote)
{
if((buf[i] == '"' || buf[i] == '\''))
{
PUSH_KEYWORD(WORD);
/* begin quotted string */
s.quote_char = buf[i];
s.quote = true;
continue;
}
if(buf[i] == '[')
{
PUSH_KEYWORD(WORD);
if(buf[i + 1] == '/')
{
i += 2;
type = SEC_END;
}
else
{
++i;
type = SEC_START;
}
/* get section name */
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;
break;
}
bufname[j++] = buf[i++];
}
PUSH_KEYWORD(type);
continue;
}
if(buf[i] == '{')
{
PUSH_KEYWORD(WORD);
PUSH_KEYWORD(LIST_START);
continue;
}
if(buf[i] == '}')
{
PUSH_KEYWORD(WORD);
PUSH_KEYWORD(LIST_END);
continue;
}
if(buf[i] == ',')
{
PUSH_KEYWORD(WORD);
continue;
}
if(buf[i] == '=')
{
PUSH_KEYWORD(WORD);
PUSH_KEYWORD(EQUAL);
continue;
}
if(strchr("\t\n ", buf[i]))
{
PUSH_KEYWORD(WORD);
if(buf[i] == '\n')
++line;
continue;
}
}
if(j >= (BUFSIZ - 1))
{
bufname[j] = '\0';
syntax(NULL, "word too long in %s:%d near '%s'",
file->name, line, bufname);
error = true;
break;
}
bufname[j++] = buf[i];
}
free(buf);
free(bufname);
close(fd);
warnxl("%s read", file->name);
return (error ? NULL: head);
}
/*
* return NULL on failure and head->next if
* no config found (of file doesn't exist)
* NOTE to devs: head->name is the file to include
*/
static struct keyword *
include(struct keyword *head)
{
struct keyword *kw;
struct keyword *tail;
struct files *file;
struct passwd *user;
char *filename = NULL;
char *base = NULL;
head = head->next;
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);
else /* to warning ? */
filename = head->name;
}
/* relative path from parent file */
else if(head->name && head->name[0] != '/')
{
base = strdup(head->file->name);
xasprintf(&filename, "%s/%s", dirname(base), head->name);
free(base);
}
else
filename = head->name;
if(!(kw = parse_keywords(filename)))
{
warnxl("no config found in include file %s", head->name);
if(filename != head->name)
free(filename);
return NULL;
}
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))
{
syntax(kw, "circular include of %s", kw->file->name);
if(filename != head->name)
free(filename);
return NULL;
}
if(filename != head->name)
free(filename);
head = head->next;
if(kw)
{
for(tail = kw; tail->next; tail = tail->next);
tail->next = head;
}
return kw;
}
static void *
free_opt(struct conf_opt *o)
{
free(o);
return NULL;
}
static struct conf_opt *
get_option(struct keyword **head)
{
struct conf_opt *o;
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->filename = kw->file->name;
kw = kw->next;
if(kw->type != EQUAL)
{
syntax(kw, "missing '=' here");
return free_opt(o);
}
if(!(kw = kw->next))
{
syntax(kw, "missing value");
return free_opt(o);
}
switch(kw->type)
{
case INCLUDE:
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)
{
case WORD:
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)))
return free_opt(o);
break;
default:
syntax(kw, "declaration into a list");
return free_opt(o);
break;
}
}
if(!kw)
{
syntax(kw, "list unclosed");
return free_opt(o);
}
kw = kw->next;
break;
default:
syntax(kw, "missing value");
return free_opt(o);
break;
}
*head = kw;
return o;
}
static void *
free_sec(struct conf_sec *sec)
{
struct conf_opt *o;
struct conf_sec *s;
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))
{
s = TAILQ_FIRST(&sec->sub);
TAILQ_REMOVE(&sec->sub, s, entry);
free_sec(s);
}
free(sec);
}
return NULL;
}
static struct conf_sec *
get_section(struct keyword **head)
{
struct conf_sec *s;
struct conf_opt *o;
struct conf_sec *sub;
struct keyword *kw = *head;
s = xcalloc(1, 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)
{
case INCLUDE:
if(!(kw = include(kw)))
return free_sec(s);
break;
case SEC_START:
if(!(sub = get_section(&kw)))
return free_sec(s);
TAILQ_INSERT_TAIL(&s->sub, sub, entry);
++s->nsub;
break;
case WORD:
if(!(o = get_option(&kw)))
return free_sec(s);
SLIST_INSERT_HEAD(&s->optlist, o, entry);
++s->nopt;
break;
default:
syntax(kw, "syntax error");
return free_sec(s);
break;
}
}
if(!kw || strcmp(kw->name, s->name))
{
syntax(kw, "missing end section %s", s->name);
return free_sec(s);
}
kw = kw->next;
*head = kw;
return s;
}
int
free_conf(void)
{
struct conf_sec *s;
struct keyword *kw, *nkw;
struct files **f = NULL;
int i, nf = 0;
while(!TAILQ_EMPTY(&config))
{
s = TAILQ_FIRST(&config);
TAILQ_REMOVE(&config, s, entry);
free_sec(s);
}
kw = keywords;
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;
}
kw = nkw;
}
if(nf > 0)
{
for(i = 0; i < nf; ++i)
{
free(f[i]->name);
free(f[i]);
}
free(f);
}
return -1;
}
int
get_conf(const char *filename)
{
struct conf_sec *s;
struct keyword *head, *kw;
head = kw = parse_keywords(filename);
if(!head)
return -1; /* TODO ERREUR */
keywords = head;
TAILQ_INIT(&config);
while(kw)
{
switch(kw->type)
{
case INCLUDE:
if(!(kw = include(kw)))
return free_conf();
break;
case SEC_START:
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;
}

118
src/parse.h Normal file
View File

@ -0,0 +1,118 @@
/*
* 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef PARSE_H
#define PARSE_H
#include "wmfs.h"
#define INCLUDE_CMD "@include"
#define PARSE_MAX_LIST 32
struct conf_opt
{
char *name;
char *val[PARSE_MAX_LIST];
size_t nval;
bool used;
int line;
char *filename;
SLIST_ENTRY(conf_opt) entry;
};
struct conf_sec
{
char *name;
SLIST_HEAD(, conf_opt) optlist;
TAILQ_HEAD(cshead, conf_sec) sub;
size_t nopt;
size_t nsub;
TAILQ_ENTRY(conf_sec) entry;
};
struct opt_type
{
long int num;
float fnum;
bool boolean;
char *str;
};
/*
* Create config from file
* return -1 on failure
*/
int get_conf(const char *);
/*
* Print unused option name from section s (and subsections).
* If s == NULL print unused option name for all config struct.
*/
void print_unused(struct conf_sec *s);
/*
* Free the config struct.
* WARNING: This make all string
* returned by fetch_(opt|section)(_first) unusable.
*/
int free_conf(void);
/*
* Get all subsection matching the given name on the given
* section.
* If section == NULL, return subsections from root section.
* Return a NULL terminated array.
* Subsections are returned in order as they are in config file
* WARNING : This MUST be free() after use.
*/
struct conf_sec **fetch_section(struct conf_sec *, char *);
/*
* Get first subsection matching the given name
* on the given section. (first found on the file)
*/
struct conf_sec *fetch_section_first(struct conf_sec *, char *);
/*
* Count member of a conf_sec **
*/
size_t fetch_section_count(struct conf_sec **);
/*
* Return all options matching the given name on the given subsection.
* If none match or section == NULL return opt_type build with the
* given default param.
* WARNING: This MUST be free() after use.
* WARNING: The string member is directly taken from the config struct.
* WARNING: Returned in reverse order as they are in config file.
* (I think the last option MUST overwrite all others)
*/
struct opt_type fetch_opt_first(struct conf_sec *, char *, char *);
/*
* Get first (last in config file) option matching the given name
* on the given section.
* WARNING: The string member is directly taken from the config struct.
*/
struct opt_type *fetch_opt(struct conf_sec *, char *, char *);
/*
* Count member of a opt_type *
*/
size_t fetch_opt_count(struct opt_type *);
#endif /* PARSE_H */

214
src/parse_api.c Normal file
View File

@ -0,0 +1,214 @@
/*
* 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#include <string.h>
#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 struct opt_type
string_to_opt(char *s)
{
struct opt_type ret = opt_type_null;
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"));
ret.str = s;
return ret;
}
void
print_unused(struct conf_sec *sec)
{
struct conf_sec *s;
struct conf_opt *o;
if(!sec)
{
TAILQ_FOREACH(s, &config, entry)
print_unused(s);
return;
}
SLIST_FOREACH(o, &sec->optlist, entry)
if(!o->used)
warnxl("%s:%d, unused param %s", o->filename, o->line, o->name);
TAILQ_FOREACH(s, &sec->sub, entry)
if(!TAILQ_EMPTY(&s->sub))
print_unused(s);
}
struct conf_sec **
fetch_section(struct conf_sec *s, char *name)
{
struct conf_sec **ret;
struct conf_sec *sec;
size_t i = 0;
if(!name)
return NULL;
if(!s)
{
ret = xcalloc(2, sizeof(struct conf_sec *));
TAILQ_FOREACH(sec, &config, entry)
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)
ret[i++] = sec;
ret[i] = NULL;
}
return ret;
}
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)
return NULL;
TAILQ_FOREACH(sec, head, entry)
if(sec->name && !strcmp(sec->name, name))
{
ret = sec;
break;
}
return ret;
}
size_t
fetch_section_count(struct conf_sec **s)
{
size_t ret = 0;
while(s[ret])
++ret;
return ret;
}
struct opt_type *
fetch_opt(struct conf_sec *s, char *dfl, char *name)
{
struct conf_opt *o;
struct opt_type *ret;
size_t i = 0;
if(!name)
return NULL;
ret = xcalloc(10, sizeof(struct opt_type));
if(s)
{
SLIST_FOREACH(o, &s->optlist, entry)
if(!strcmp(o->name, name))
{
while(o->val[i])
{
o->used = true;
ret[i] = string_to_opt(o->val[i]);
++i;
}
ret[i] = opt_type_null;
return ret;
}
}
ret[0] = string_to_opt(dfl);
ret[1] = opt_type_null;
return ret;
}
struct opt_type
fetch_opt_first(struct conf_sec *s, char *dfl, char *name)
{
struct conf_opt *o;
if(!name)
return opt_type_null;
else if(s)
{
SLIST_FOREACH(o, &s->optlist, entry)
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;
return ret;
}

166
src/screen.c Normal file
View File

@ -0,0 +1,166 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifdef HAVE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* HAVE_XINERAMA */
#include "screen.h"
#include "util.h"
#include "tag.h"
#include "infobar.h"
#include "client.h"
static struct screen*
screen_new(struct geo *g, int id)
{
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;
}
void
screen_init(void)
{
struct geo g;
SLIST_INIT(&W->h.screen);
#ifdef HAVE_XINERAMA
XineramaScreenInfo *xsi;
int i, n = 0;
if(XineramaIsActive(W->dpy))
{
xsi = XineramaQueryScreens(W->dpy, &n);
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;
screen_new(&g, i);
}
W->nscreen = n;
XFree(xsi);
}
else
#endif /* HAVE_XINERAMA */
{
g.x = g.y = 0;
g.w = DisplayWidth(W->dpy, W->xscreen);
g.h = DisplayHeight(W->dpy, W->xscreen);
screen_new(&g, 0);
W->nscreen = 1;
}
}
/*
* Update selected screen with mouse location
*/
struct screen*
screen_update_sel(void)
{
#ifdef HAVE_XINERAMA
if(XineramaIsActive(W->dpy))
return (W->screen = screen_gb_mouse());
#endif /* HAVE_XINERAMA */
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;
}
void
uicb_screen_next(Uicb cmd)
{
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd;
if(!s)
s = SLIST_FIRST(&W->h.screen);
screen_select(s);
}
void
uicb_screen_prev(Uicb cmd)
{
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
screen_select(s);
}
void
uicb_screen_move_client_next(Uicb cmd)
{
struct screen *s = SLIST_NEXT(W->screen, next);
(void)cmd;
if(!s)
s = SLIST_FIRST(&W->h.screen);
if(W->client)
tag_client(s->seltag, W->client);
}
void
uicb_screen_move_client_prev(Uicb cmd)
{
struct screen *s = SLIST_FIRST(&W->h.screen);
(void)cmd;
while(SLIST_NEXT(s, next) && SLIST_NEXT(s, next) != s)
s = SLIST_NEXT(s, next);
if(W->client)
tag_client(s->seltag, W->client);
}
void
screen_free(void)
{
struct screen *s;
while(!SLIST_EMPTY(&W->h.screen))
{
s = SLIST_FIRST(&W->h.screen);
SLIST_REMOVE_HEAD(&W->h.screen, next);
infobar_free(s);
tag_free(s);
free(s);
}
}

56
src/screen.h Normal file
View File

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

653
src/status.c Normal file
View File

@ -0,0 +1,653 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#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)
{
free(ctx->status);
status_flush_list(ctx);
status_gcache_free(ctx);
}
static void
status_graph_draw(struct status_ctx *ctx, struct status_seq *sq, struct status_gcache *gc)
{
int max = 0;
int i, j, y;
float c;
int ys = sq->geo.y + sq->geo.h - 1;
/* 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])
{
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);
}
}
}
static void
status_graph_process(struct status_ctx *ctx, struct status_seq *sq, char *name)
{
int j;
struct status_gcache *gc;
/* Graph already exist and have a cache */
SLIST_FOREACH(gc, &ctx->gcache, next)
if(!strcmp(name, gc->name))
{
/* 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);
gc->datas[gc->ndata++] = sq->data[1];
status_graph_draw(ctx, sq, gc);
return;
}
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
/* 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);
}
/* Parse mousebind sequence next normal sequence: \<seq>[](button;func;cmd) */
static char*
status_parse_mouse(struct status_seq *sq, char *str)
{
struct mousebind *m;
char *end, *arg[3] = { NULL };
int i;
if(*str != '(' || !(end = strchr(str, ')')))
return str;
i = parse_args(++str, ';', ')', 3, arg);
m = xcalloc(1, sizeof(struct mousebind));
m->use_area = true;
m->button = ATOI(arg[0]);
m->func = uicb_name_func(arg[1]);
m->cmd = (i > 1 ? xstrdup(arg[2]) : NULL);
SLIST_INSERT_HEAD(&sq->mousebinds, m, snext);
return end + 1;
}
#define STATUS_CHECK_ARGS(i, n1, n2, str, end) \
if(i != n1 && i != n2) \
{ \
str = end + 2; \
continue; \
}
void
status_parse(struct status_ctx *ctx)
{
struct status_seq *sq, *prev = NULL;
int i, tmp, shift = 0;
char *dstr = xstrdup(ctx->status), *sauv = dstr;
char type, *p, *pp, *end, *arg[10] = { NULL };
for(; *dstr; ++dstr)
{
/* Check if this is a sequence */
if(*dstr != '^' && *dstr != '\\')
continue;
p = ++dstr;
/* Search for correct end of sequence (] without \ behind) */
if((end = strchr(p, ']')))
while(*(end - 1) == '\\')
end = strchr(end + 1, ']');
if(!(strchr("sRpPig", *p)) || !end)
continue;
/* Then parse & list it */
switch((type = *p))
{
/*
* Text sequence: \s[left/right;#color;text] OR \s[x;y;#color;text]
*/
case 's':
i = parse_args(p + 2, ';', ']', 4, arg);
STATUS_CHECK_ARGS(i, 2, 3, dstr, end);
sq = status_new_seq(type, i, 2, arg, &shift);
sq->color = color_atoh(arg[1 + shift]);
sq->str = xstrdup(arg[2 + shift]);
/* Remove \ from string */
for(pp = sq->str; (pp = strchr(sq->str, '\\'));)
memmove(pp, pp + 1, strlen(pp));
break;
/*
* Rectangle sequence: \R[left/right;w;h;#color] OR \R[x;y;w;h;#color]
*/
case 'R':
i = parse_args(p + 2, ';', ']', 5, arg);
STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
sq = status_new_seq(type, i, 3, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->color = color_atoh(arg[3 + shift]);
break;
/*
* Progress bar sequence: \p[left/right;w;h;bord;val;valmax;bg;fg] OR x;y
* Position bar sequence: \P[left/right;w;h;tickbord;val;valmax;bg;fg] OR x;y
*/
case 'p':
case 'P':
i = parse_args(p + 2, ';', ']', 9, arg);
STATUS_CHECK_ARGS(i, 7, 8, dstr, end);
sq = status_new_seq(type, i, 7, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->data[0] = ATOI(arg[3 + shift]); /* Border */
sq->data[1] = ((tmp = ATOI(arg[4 + shift])) ? tmp : 1); /* Value */
sq->data[2] = ATOI(arg[5 + shift]); /* Value Max */
sq->color = color_atoh(arg[6 + shift]);
sq->color2 = color_atoh(arg[7 + shift]);
break;
/*
* Graph sequence: \g[left/right;w;h;val;valmax;bg;fg;name] OR x;y
*/
case 'g':
i = parse_args(p + 2, ';', ']', 9, arg);
STATUS_CHECK_ARGS(i, 7, 8, dstr, end);
sq = status_new_seq(type, i, 7, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->data[1] = ATOI(arg[3 + shift]); /* Value */
sq->data[2] = ATOI(arg[4 + shift]); /* Value Max */
sq->color = color_atoh(arg[5 + shift]);
sq->color2 = color_atoh(arg[6 + shift]);
sq->str = xstrdup(arg[7 + shift]);
break;
/*
* Image sequence: \i[left/right;w;h;/path/img] OR \i[x;y;w;h;/path/img]
*/
#ifdef HAVE_IMLIB2
case 'i':
i = parse_args(p + 2, ';', ']', 5, arg);
STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
sq = status_new_seq(type, i, 3, arg, &shift);
sq->geo.w = ATOI(arg[1 + shift]);
sq->geo.h = ATOI(arg[2 + shift]);
sq->str = xstrdup(arg[3 + shift]);
break;
#endif /* HAVE_IMLIB2 */
}
if(sq->align == Right)
SLIST_INSERT_HEAD(&ctx->statushead, sq, next);
else
SLIST_INSERT_TAIL(&ctx->statushead, sq, next, prev);
/*
* Optional mousebind sequence(s) \<seq>[](button;func;cmd)
* Parse it while there is a mousebind sequence.
*/
dstr = end + 1;
do
dstr = status_parse_mouse(sq, dstr);
while(*dstr == '(');
--dstr;
prev = sq;
}
free(sauv);
}
#define STATUS_ALIGN(align) \
if(align == Left) \
{ \
sq->geo.x = left; \
left += sq->geo.w; \
} \
else if(align == Right) \
{ \
sq->geo.x = ctx->barwin->geo.w - right - sq->geo.w; \
right += sq->geo.w; \
}
#define STORE_MOUSEBIND() \
if(!SLIST_EMPTY(&sq->mousebinds)) \
SLIST_FOREACH(m, &sq->mousebinds, snext) \
m->area = sq->geo;
#define NOALIGN_Y() \
if(sq->align != NoAlign) \
sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
static void
status_apply_list(struct status_ctx *ctx)
{
struct status_seq *sq;
struct mousebind *m;
struct geo g;
int left = 0, right = 0, w, h;
SLIST_FOREACH(sq, &ctx->statushead, next)
{
switch(sq->type)
{
/* Text */
case 's':
sq->geo.w = draw_textw(ctx->theme, sq->str);
sq->geo.h = ctx->theme->font.height;
if(sq->align != NoAlign)
sq->geo.y = TEXTY(ctx->theme, ctx->barwin->geo.h);
STATUS_ALIGN(sq->align);
draw_text(ctx->barwin->dr, ctx->theme, sq->geo.x, sq->geo.y, sq->color, sq->str);
if(!SLIST_EMPTY(&sq->mousebinds))
SLIST_FOREACH(m, &sq->mousebinds, snext)
{
m->area = sq->geo;
m->area.y -= sq->geo.h;
}
break;
/* Rectangle */
case 'R':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
STORE_MOUSEBIND();
break;
/* Progress */
case 'p':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
/* Progress bar geo */
g.x = sq->geo.x + sq->data[0];
g.y = sq->geo.y + sq->data[0];
g.w = sq->geo.w - sq->data[0] - sq->data[0];
g.h = sq->geo.h - sq->data[0] - sq->data[0];
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
if(sq->geo.w > sq->geo.h)
g.w /= ((float)sq->data[2] / (float)sq->data[1]);
else
{
g.y += g.h;
g.h /= ((float)sq->data[2] / (float)sq->data[1]);
g.y -= g.h;
}
draw_rect(ctx->barwin->dr, &g, sq->color2);
STORE_MOUSEBIND();
break;
/* Position */
case 'P':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
if(sq->data[1] > sq->data[2])
sq->data[1] = sq->data[2];
g.x = sq->geo.x + ((sq->geo.w - sq->data[0]) / ((float)sq->data[2] / (float)sq->data[1]));
g.y = sq->geo.y;
g.w = sq->data[0];
g.h = sq->geo.h;
draw_rect(ctx->barwin->dr, &g, sq->color2);
STORE_MOUSEBIND();
break;
/* Graph */
case 'g':
NOALIGN_Y();
STATUS_ALIGN(sq->align);
draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
status_graph_process(ctx, sq, sq->str);
STORE_MOUSEBIND();
break;
/* Image */
#ifdef HAVE_IMLIB2
case 'i':
draw_image_load(sq->str, &w, &h);
if(sq->geo.w <= 0)
sq->geo.w = w;
if(sq->geo.h <= 0)
sq->geo.h = h;
if(sq->align != NoAlign)
sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
STATUS_ALIGN(sq->align);
draw_image(ctx->barwin->dr, &sq->geo);
STORE_MOUSEBIND();
break;
#endif /* HAVE_IMLIB2 */
}
}
}
/* Render current statustext of an element */
void
status_render(struct status_ctx *ctx)
{
if(!ctx->status)
return;
if(!(ctx->flags & STATUS_BLOCK_REFRESH))
barwin_refresh_color(ctx->barwin);
/* Use simple text instead sequence if no sequence found */
if(SLIST_EMPTY(&ctx->statushead))
{
int l = draw_textw(ctx->theme, ctx->status);
draw_text(ctx->barwin->dr, ctx->theme, ctx->barwin->geo.w - l,
TEXTY(ctx->theme, ctx->barwin->geo.h), ctx->barwin->fg, ctx->status);
}
else
status_apply_list(ctx);
barwin_refresh(ctx->barwin);
}
void
status_flush_list(struct status_ctx *ctx)
{
struct status_seq *sq;
struct mousebind *m;
/* Flush previous linked list of status sequences */
while(!SLIST_EMPTY(&ctx->statushead))
{
sq = SLIST_FIRST(&ctx->statushead);
SLIST_REMOVE_HEAD(&ctx->statushead, next);
while(!SLIST_EMPTY(&sq->mousebinds))
{
m = SLIST_FIRST(&sq->mousebinds);
SLIST_REMOVE_HEAD(&sq->mousebinds, snext);
free((void*)m->cmd);
free(m);
}
free(sq->str);
free(sq);
}
SLIST_INIT(&ctx->statushead);
}
void
status_copy_mousebind(struct status_ctx *ctx)
{
struct mousebind *m;
struct status_seq *sq;
if(!ctx->barwin)
return;
/* Flush barwin head of status mousebinds */
SLIST_INIT(&ctx->barwin->statusmousebinds);
SLIST_FOREACH(sq, &ctx->statushead, next)
{
SLIST_FOREACH(m, &sq->mousebinds, snext)
SLIST_INSERT_HEAD(&ctx->barwin->statusmousebinds, m, next);
}
}
/* Parse and render statustext */
void
status_manage(struct status_ctx *ctx)
{
if(!ctx->status)
return;
ctx->update = false;
status_flush_list(ctx);
status_parse(ctx);
status_render(ctx);
status_copy_mousebind(ctx);
}
void
status_flush_surface(void)
{
struct barwin *b;
while(!SLIST_EMPTY(&W->h.vbarwin))
{
b = SLIST_FIRST(&W->h.vbarwin);
SLIST_REMOVE_HEAD(&W->h.vbarwin, vnext);
barwin_remove(b);
}
}
static void
status_surface(int x, int y, int w, int h, Color bg, char *status)
{
struct barwin *b;
struct screen *s;
struct status_ctx ctx;
int d;
Window rw;
if(!status)
return;
if(x + y < 0)
XQueryPointer(W->dpy, W->root, &rw, &rw, &x, &y, &d, &d, (unsigned int *)&d);
s = screen_gb_geo(x, y);
if(x + w > s->geo.x + s->geo.w)
x -= w;
if(y + h > s->geo.y + s->geo.h)
y -= h;
b = barwin_new(W->root, x, y, w, h, 0, bg, false);
barwin_map(b);
/* Use client theme */
ctx = status_new_ctx(b, W->ctheme);
ctx.status = xstrdup(status);
SLIST_INSERT_HEAD(&W->h.vbarwin, b, vnext);
status_manage(&ctx);
status_free_ctx(&ctx);
}
void
uicb_status_surface(Uicb cmd)
{
char *p, *ccmd = xstrdup(cmd);
int s, w, h, x = -1, y = -1;
Color bg;
if(!ccmd || !(p = strchr(ccmd, ' ')))
return;
*p = '\0';
++p;
if(!(((s = sscanf(ccmd, "%d,%d,#%x", &w, &h, &bg)) == 3)
|| (s = sscanf(ccmd, "%d,%d,%d,%d,#%x", &x, &y, &w, &h, &bg)) == 5))
{
free(ccmd);
return;
}
status_surface(x, y, w, h, bg, p);
free(ccmd);
}
/* Syntax: "<infobar name> <status string>" */
void
uicb_status(Uicb cmd)
{
struct infobar *ib;
struct screen *s;
char *p;
if(!cmd || !(p = strchr(cmd, ' ')))
return;
/* Get infobar name & status */
*p = '\0';
++p;
SLIST_FOREACH(s, &W->h.screen, next)
{
SLIST_FOREACH(ib, &s->infobars, next)
if(!strcmp(cmd, ib->name))
{
free(ib->statusctx.status);
ib->statusctx.status = xstrdup(p);
ib->statusctx.update = true;
infobar_elem_screen_update(s, ElemStatus);
}
}
}

23
src/status.h Normal file
View File

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

200
src/systray.c Normal file
View File

@ -0,0 +1,200 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include "wmfs.h"
#include "systray.h"
#include "ewmh.h"
#include "infobar.h"
#define SYSTRAY_SPACING (2)
void
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,
};
if(!(W->flags & WMFS_SYSTRAY) || W->systray.win)
return;
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != None)
{
warnx("Can't initialize system tray: owned by another process.");
return;
}
SLIST_INIT(&W->systray.head);
/* Init systray window */
w = XCreateSimpleWindow(W->dpy, W->systray.barwin->win, 0, 0,
W->systray.barwin->geo.h, W->systray.barwin->geo.h, 0, 0, 0);
XChangeWindowAttributes(W->dpy, w, CWEventMask | CWOverrideRedirect | CWBackPixel, &wattr);
XSelectInput(W->dpy, w, KeyPressMask | ButtonPressMask);
XMapRaised(W->dpy, w);
XSetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s], w, CurrentTime);
if(XGetSelectionOwner(W->dpy, W->net_atom[net_system_tray_s]) != w)
{
warnl("System tray: can't get systray manager");
systray_freeicons();
return;
}
ewmh_send_message(W->root, W->root, "MANAGER", CurrentTime,
W->net_atom[net_system_tray_s], w, 0, 0);
XSync(W->dpy, false);
W->systray.win = w;
}
void
systray_add(Window win)
{
struct _systray *s;
if(!(W->flags & WMFS_SYSTRAY))
return;
s = xcalloc(1, sizeof(struct _systray));
s->win = win;
s->geo.h = W->systray.barwin->geo.h;
s->geo.w = W->systray.barwin->geo.h + SYSTRAY_SPACING;
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);
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime,
XEMBED_EMBEDDED_NOTIFY, 0, W->systray.win, 0);
SLIST_INSERT_HEAD(&W->systray.head, s, next);
W->systray.redim = true;
}
void
systray_del(struct _systray *s)
{
if(!(W->flags & WMFS_SYSTRAY))
return;
SLIST_REMOVE(&W->systray.head, s, _systray, next);
free(s);
W->systray.redim = true;
}
void
systray_state(struct _systray *s)
{
long flags;
int code = 0;
if(!(W->flags & WMFS_SYSTRAY) || !(flags = ewmh_get_xembed_state(s->win)))
return;
if(flags & XEMBED_MAPPED)
{
code = XEMBED_WINDOW_ACTIVATE;
XMapRaised(W->dpy, s->win);
ewmh_set_wm_state(s->win, NormalState);
}
else
{
code = XEMBED_WINDOW_DEACTIVATE;
XUnmapWindow(W->dpy, s->win);
ewmh_set_wm_state(s->win, WithdrawnState);
}
ewmh_send_message(s->win, s->win, "_XEMBED", CurrentTime, code, 0, 0, 0);
}
void
systray_freeicons(void)
{
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
return;
while(!SLIST_EMPTY(&W->systray.head))
{
i = SLIST_FIRST(&W->systray.head);
SLIST_REMOVE_HEAD(&W->systray.head, next);
XUnmapWindow(W->dpy, i->win);
XReparentWindow(W->dpy, i->win, W->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);
}
struct _systray*
systray_find(Window win)
{
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
return NULL;
SLIST_FOREACH(i, &W->systray.head, next)
if(i->win == win)
return i;
return NULL;
}
int
systray_get_width(void)
{
int w = 1;
struct _systray *i;
SLIST_FOREACH(i, &W->systray.head, next)
w += i->geo.w + SYSTRAY_SPACING;
return w;
}
void
systray_update(void)
{
int x = 1;
struct _systray *i;
if(!(W->flags & WMFS_SYSTRAY))
return;
if(W->systray.redim)
{
W->systray.redim = false;
infobar_elem_reinit(W->systray.infobar);
}
SLIST_FOREACH(i, &W->systray.head, next)
{
XMapWindow(W->dpy, i->win);
XMoveResizeWindow(W->dpy, i->win, (i->geo.x = x), 0, i->geo.w, i->geo.h);
x += i->geo.w + SYSTRAY_SPACING;
}
}

20
src/systray.h Normal file
View File

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

302
src/tag.c Normal file
View File

@ -0,0 +1,302 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include <X11/Xutil.h> /* IconicState / NormalState */
#include "tag.h"
#include "util.h"
#include "infobar.h"
#include "client.h"
#include "config.h"
#include "barwin.h"
#include "ewmh.h"
#include "layout.h"
struct tag*
tag_new(struct screen *s, char *name)
{
struct tag *t, *l;
t = xcalloc(1, sizeof(struct tag));
t->screen = s;
t->flags = 0;
t->id = 0;
t->sel = NULL;
t->prev = NULL;
if((l = TAILQ_LAST(&s->tags, tsub)))
t->id = l->id + 1;
if(!name || !strlen(name))
xasprintf(&t->name, "%d", t->id + 1);
else
t->name = xstrdup(name);
SLIST_INIT(&t->clients);
TAILQ_INIT(&t->sets);
TAILQ_INSERT_TAIL(&s->tags, t, next);
return t;
}
void
tag_screen(struct screen *s, struct tag *t)
{
struct client *c;
/* Return to the previous tag */
if(t == s->seltag && TAILQ_NEXT(TAILQ_FIRST(&s->tags), next))
t = t->prev;
if(!t)
t = TAILQ_FIRST(&s->tags);
/* Move clients which ignore tags */
SLIST_FOREACH(c, &W->h.client, next)
if (c->flags & CLIENT_IGNORE_TAG)
tag_client(t, c);
t->prev = s->seltag;
s->seltag = t;
clients_arrange_map();
/* Update focus */
if(!SLIST_EMPTY(&t->clients) && !(W->flags & WMFS_SCAN))
client_focus( client_tab_next(t->sel));
t->flags &= ~TAG_URGENT;
infobar_elem_screen_update(s, ElemTag);
ewmh_update_wmfs_props();
}
/* Set t to NULL to untag c from c->tag */
void
tag_client(struct tag *t, struct client *c)
{
/* Remove client from its previous tag */
if(c->tag && !(c->flags & CLIENT_RULED))
{
if(c->tag == t)
return;
if(!(c->flags & (CLIENT_IGNORE_LAYOUT | CLIENT_FREE)))
layout_split_arrange_closed(c);
if(!(c->flags & CLIENT_REMOVEALL))
{
SLIST_REMOVE(&c->tag->clients, c, client, tnext);
if(c->tag->sel == c || W->client == c)
client_focus( client_tab_next( client_next(c)));
}
}
c->flags &= ~CLIENT_RULED;
/* Client remove */
if(!t)
{
infobar_elem_screen_update(c->screen, ElemTag);
return;
}
c->prevtag = c->tag;
c->tag = t;
c->screen = t->screen;
client_update_props(c, CPROP_LOC);
SLIST_INSERT_HEAD(&t->clients, c, tnext);
infobar_elem_screen_update(c->screen, ElemTag);
if(c->flags & CLIENT_TABMASTER && c->prevtag)
{
struct client *cc;
SLIST_FOREACH(cc, &c->prevtag->clients, tnext)
if(cc->tabmaster == c)
{
cc->flags |= CLIENT_IGNORE_LAYOUT;
tag_client(t, cc);
}
}
layout_client(c);
if(t != c->screen->seltag || c->flags & CLIENT_TABBED)
client_unmap(c);
}
void
uicb_tag_set(Uicb cmd)
{
int i = 0, n = ATOI(cmd);
struct tag *t;
TAILQ_FOREACH(t, &W->screen->tags, next)
if(i++ == n)
{
tag_screen(W->screen, t);
return;
}
}
void
uicb_tag_set_with_name(Uicb cmd)
{
struct tag *t;
TAILQ_FOREACH(t, &W->screen->tags, next)
if(!strcmp(cmd, t->name))
{
tag_screen(W->screen, t);
return;
}
}
void
uicb_tag_next(Uicb cmd)
{
(void)cmd;
struct tag *t;
if((t = TAILQ_NEXT(W->screen->seltag, next)))
tag_screen(W->screen, t);
else if(W->flags & WMFS_TAGCIRC)
tag_screen(W->screen, TAILQ_FIRST(&W->screen->tags));
}
void
uicb_tag_prev(Uicb cmd)
{
(void)cmd;
struct tag *t;
if((t = TAILQ_PREV(W->screen->seltag, tsub, next)))
tag_screen(W->screen, t);
else if(W->flags & WMFS_TAGCIRC)
tag_screen(W->screen, TAILQ_LAST(&W->screen->tags, tsub));
}
void
uicb_tag_client(Uicb cmd)
{
struct tag *t;
int id = ATOI(cmd);
if(W->client && (t = tag_gb_id(W->screen, id)))
tag_client(t, W->client);
}
void
uicb_tag_client_and_set(Uicb cmd)
{
uicb_tag_client(cmd);
uicb_tag_set(cmd);
}
void
uicb_tag_move_client_next(Uicb cmd)
{
(void)cmd;
struct tag *t;
if(!W->client)
return;
if((t = TAILQ_NEXT(W->screen->seltag, next)))
tag_client(t, W->client);
else if(W->flags & WMFS_TAGCIRC)
tag_client(TAILQ_FIRST(&W->screen->tags), W->client);
}
void
uicb_tag_move_client_prev(Uicb cmd)
{
(void)cmd;
struct tag *t;
if(!W->client)
return;
if((t = TAILQ_PREV(W->screen->seltag, tsub, next)))
tag_client(t, W->client);
else if(W->flags & WMFS_TAGCIRC)
tag_client(TAILQ_LAST(&W->screen->tags, tsub), W->client);
}
void
uicb_tag_click(Uicb cmd)
{
(void)cmd;
struct tag *t;
if((t = (struct tag*)W->last_clicked_barwin->ptr)
&& t->screen == W->screen)
tag_screen(W->screen, t);
}
static void
tag_remove(struct tag *t)
{
TAILQ_REMOVE(&t->screen->tags, t, next);
free(t->name);
layout_free_set(t);
free(t);
}
void
uicb_tag_new(Uicb cmd)
{
struct screen *s = W->screen;
struct infobar *i;
tag_new(s, (char*)cmd);
s->flags |= SCREEN_TAG_UPDATE;
SLIST_FOREACH(i, &s->infobars, next)
infobar_elem_reinit(i);
s->flags ^= SCREEN_TAG_UPDATE;
}
void
uicb_tag_del(Uicb cmd)
{
struct infobar *i;
struct tag *t = W->screen->seltag;
(void)cmd;
if(SLIST_EMPTY(&t->clients)
&& TAILQ_NEXT(TAILQ_FIRST(&W->screen->tags), next))
{
tag_screen(W->screen, TAILQ_NEXT(t, next));
tag_remove(t);
W->screen->flags |= SCREEN_TAG_UPDATE;
SLIST_FOREACH(i, &W->screen->infobars, next)
infobar_elem_reinit(i);
W->screen->flags ^= SCREEN_TAG_UPDATE;
}
}
void
tag_free(struct screen *s)
{
while(!TAILQ_EMPTY(&s->tags))
tag_remove(TAILQ_FIRST(&s->tags));
}

39
src/tag.h Normal file
View File

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

167
src/util.c Normal file
View File

@ -0,0 +1,167 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#define _GNU_SOURCE /* vasprintf() */
#include <stdint.h>
#include <string.h>
#include "util.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*
xmalloc(size_t nmemb, size_t size)
{
void *ret;
if(SIZE_MAX / nmemb < size)
errl(EXIT_FAILURE, "xmalloc(%zu, %zu), "
"size_t overflow detected", nmemb, size);
if((ret = malloc(nmemb * size)) == NULL)
errl(EXIT_FAILURE, "malloc(%zu)", nmemb * size);
return ret;
}
/** calloc with error support
* \param nmemb Number of objects
* \param size size of single object
* \return non null void pointer
*/
void*
xcalloc(size_t nmemb, size_t size)
{
void *ret;
if((ret = calloc(nmemb, size)) == NULL)
errl(EXIT_FAILURE, "calloc(%zu * %zu)", nmemb, size);
return ret;
}
/** realloc with error support and size_t overflow check
* \param ptr old pointer
* \param nmemb number of objects
* \param size size of single object
* \return non null void pointer
*/
void *
xrealloc(void *ptr, size_t nmemb, size_t size)
{
void *ret;
if(SIZE_MAX / nmemb < size)
err(EXIT_FAILURE, "xrealloc(%p, %zu, %zu), "
"size_t overflow detected", ptr, nmemb, size);
if((ret = realloc(ptr, nmemb * size)) == NULL)
err(EXIT_FAILURE, "realloc(%p, %zu)", ptr, nmemb * size);
return ret;
}
/** asprintf wrapper
* \param strp target string
* \param fmt format
* \return non zero integer
*/
int
xasprintf(char **strp, const char *fmt, ...)
{
int ret;
va_list args;
va_start(args, fmt);
ret = vasprintf(strp, fmt, args);
va_end(args);
if (ret == -1)
errl(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)
{
char *ret = NULL;
if(str == NULL || (ret = strdup(str)) == NULL)
warnxl("strdup(%s)", str);
return ret;
}
/** Execute a system command
* \param cmd Command
* \return child pid
*/
pid_t
spawn(const char *format, ...)
{
char *sh = NULL;
char cmd[512];
va_list ap;
pid_t pid;
size_t len;
va_start(ap, format);
len = vsnprintf(cmd, sizeof(cmd), format, ap);
va_end(ap);
if (len >= sizeof(cmd))
{
warnxl("command too long (> 512 bytes)");
return -1;
}
if(!(sh = getenv("SHELL")) || sh[0] != '/')
sh = "/bin/sh";
if(!(pid = fork()))
{
setsid();
if (execl(sh, sh, "-c", cmd, (char*)NULL) == -1)
warnl("execl(sh -c %s)", cmd);
exit(EXIT_FAILURE);
}
else if (pid == -1)
warnl("fork");
return pid;
}
int
parse_args(char *str, char delim, char end, int narg, char *args[])
{
int i = 0;
for(args[0] = str; *str && (*str != end || *(str - 1) == '\\') && i < narg; ++str)
if(*str == delim && i < narg - 1)
{
*str = '\0';
args[++i] = ++str;
}
*str = '\0';
return i;
}
void
uicb_spawn(Uicb cmd)
{
spawn("%s", cmd);
}

99
src/util.h Normal file
View File

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

644
src/wmfs.c Normal file
View File

@ -0,0 +1,644 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#include <string.h>
#include <getopt.h>
#include <signal.h>
#include <sys/wait.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#ifdef HAVE_IMLIB2
#include <Imlib2.h>
#endif /* HAVE_IMLIB2 */
#include "wmfs.h"
#include "event.h"
#include "ewmh.h"
#include "screen.h"
#include "infobar.h"
#include "util.h"
#include "config.h"
#include "client.h"
#include "layout.h"
#include "systray.h"
int
wmfs_error_handler(Display *d, XErrorEvent *event)
{
char mess[256];
/* Check if there is another WM running */
if(event->error_code == BadAccess
&& W->root == event->resourceid)
errl(EXIT_FAILURE, "Another Window Manager is already running.");
/* Ignore focus change error for unmapped client
* 42 = X_SetInputFocus
* 28 = X_GrabButton
*/
if(client_gb_win(event->resourceid))
if(event->error_code == BadWindow
|| event->request_code == 42
|| event->request_code == 28)
return 0;
if(XGetErrorText(d, event->error_code, mess, 128))
warnxl("%s(%d) opcodes %d/%d\n resource #%lx\n",
mess,
event->error_code,
event->request_code,
event->minor_code,
event->resourceid);
return 1;
}
int
wmfs_error_handler_dummy(Display *d, XErrorEvent *event)
{
(void)d;
(void)event;
return 0;
}
void
wmfs_numlockmask(void)
{
int i, j;
XModifierKeymap *mm = XGetModifierMapping(W->dpy);
for(i = 0; i < 8; i++)
for(j = 0; j < mm->max_keypermod; ++j)
if(mm->modifiermap[i * mm->max_keypermod + j]
== XKeysymToKeycode(W->dpy, XK_Num_Lock))
W->numlockmask = (1 << i);
XFreeModifiermap(mm);
}
void
wmfs_init_font(char *font, struct theme *t)
{
XFontStruct **xfs = NULL;
char **misschar, **names, *defstring;
int d;
if(!(t->font.fontset = XCreateFontSet(W->dpy, font, &misschar, &d, &defstring)))
{
warnxl("Can't load font '%s'", font);
t->font.fontset = XCreateFontSet(W->dpy, "fixed", &misschar, &d, &defstring);
}
XExtentsOfFontSet(t->font.fontset);
XFontsOfFontSet(t->font.fontset, &xfs, &names);
t->font.as = xfs[0]->max_bounds.ascent;
t->font.de = xfs[0]->max_bounds.descent;
t->font.width = xfs[0]->max_bounds.width;
t->font.height = t->font.as + t->font.de;
if(misschar)
XFreeStringList(misschar);
}
static void
wmfs_xinit(void)
{
XGCValues xgc =
{
.function = GXinvert,
.subwindow_mode = IncludeInferiors,
.line_width = 1
};
XSetWindowAttributes at =
{
.event_mask = (KeyMask | ButtonMask | MouseMask
| PropertyChangeMask | SubstructureRedirectMask
| SubstructureNotifyMask | StructureNotifyMask),
.cursor = XCreateFontCursor(W->dpy, XC_left_ptr)
};
/*
* X Error handler
*/
XSetErrorHandler(wmfs_error_handler);
/*
* X var
*/
W->xscreen = DefaultScreen(W->dpy);
W->xdepth = DefaultDepth(W->dpy, W->xscreen);
W->gc = DefaultGC(W->dpy, W->xscreen);
W->xmaxw = DisplayWidth(W->dpy, W->xscreen);
W->xmaxh = DisplayHeight(W->dpy, W->xscreen);
/*
* Keys
*/
wmfs_numlockmask();
/*
* Root window/cursor
*/
W->root = RootWindow(W->dpy, W->xscreen);
XChangeWindowAttributes(W->dpy, W->root, CWEventMask | CWCursor, &at);
W->rgc = XCreateGC(W->dpy, W->root, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
/*
* Locale (font encode)
*/
setlocale(LC_CTYPE, "");
/*
* Barwin linked list
*/
SLIST_INIT(&W->h.barwin);
SLIST_INIT(&W->h.vbarwin);
/*
* Optional dep init
*/
#ifdef HAVE_IMLIB2
imlib_context_set_display(W->dpy);
imlib_context_set_visual(DefaultVisual(W->dpy, W->xscreen));
imlib_context_set_colormap(DefaultColormap(W->dpy, W->xscreen));
#endif /* HAVE_IMLIB2 */
W->flags |= WMFS_RUNNING;
}
void
wmfs_grab_keys(void)
{
KeyCode c;
struct keybind *k;
wmfs_numlockmask();
XUngrabKey(W->dpy, AnyKey, AnyModifier, W->root);
SLIST_FOREACH(k, &W->h.keybind, next)
if((c = XKeysymToKeycode(W->dpy, k->keysym)))
{
XGrabKey(W->dpy, c, k->mod, W->root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(W->dpy, c, k->mod | LockMask, W->root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(W->dpy, c, k->mod | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(W->dpy, c, k->mod | LockMask | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
}
}
/** Scan xprops of previous session to set it back
* Check if there are windows on X (previous sessions windows)
*/
static void
wmfs_scan(void)
{
struct geo g;
struct client *c, *cc, *fc;
struct screen *s;
int i, n, rf, nscreen = 0;
int tag = -1, screen = -1, flags = -1;
unsigned long ir, il;
long *ret = NULL, *tret = NULL;
bool getg = false;
XWindowAttributes wa;
Window usl, usl2, *w = NULL, tm, focus;
Atom rt;
SLIST_INIT(&W->h.client);
W->flags |= WMFS_SCAN;
/* Get previous selected tag to apply it at the end */
if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&tret)
== Success && tret)
{
nscreen = (int)ir;
}
/* Previous focused client before reload */
if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_focus], 0, 32,
False, XA_WINDOW, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
focus = *ret;
XFree(ret);
}
if(XQueryTree(W->dpy, W->root, &usl, &usl2, &w, (unsigned int*)&n))
for(i = n - 1; i != -1; --i)
{
XGetWindowAttributes(W->dpy, w[i], &wa);
if(!wa.override_redirect && wa.map_state == IsViewable)
{
if(ewmh_get_xembed_state(w[i]))
{
systray_add(w[i]);
continue;
}
if(ewmh_manage_window_type_desktop(w[i]))
continue;
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TAG"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
tag = *ret;
XFree(ret);
}
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_SCREEN"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
screen = *ret;
XFree(ret);
}
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_FLAGS"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
flags = *ret;
flags &= ~(CLIENT_TABBED | CLIENT_REMOVEALL);
XFree(ret);
}
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_GEO"), 0, 32,
False, XA_CARDINAL, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
g.x = ret[0];
g.y = ret[1];
g.w = ret[2];
g.h = ret[3];
getg = true;
XFree(ret);
}
if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TABMASTER"), 0, 32,
False, XA_WINDOW, &rt, &rf, &ir, &il,
(unsigned char**)&ret)
== Success && ret)
{
tm = *ret;
XFree(ret);
}
c = client_new(w[i], &wa, true);
if(tm != c->win)
c->tmp = tm;
tm = 0;
if(flags != -1)
c->flags |= flags;
if(tag != -1 && screen != -1)
{
c->screen = screen_gb_id(screen);
if(getg)
c->flags |= CLIENT_IGNORE_LAYOUT;
tag_client(tag_gb_id(c->screen, tag), c);
if(getg && tag <= TAILQ_LAST(&c->screen->tags, tsub)->id - 1)
client_moveresize(c, &g);
/* In a removed tag */
else
{
c->geo = g;
layout_client(c);
}
client_get_name(c);
}
}
}
if(!nscreen)
{
SLIST_FOREACH(s, &W->h.screen, next)
if(!TAILQ_EMPTY(&s->tags))
tag_screen(s, TAILQ_FIRST(&s->tags));
}
else
{
/* Set back selected tag */
for(i = 0; i < nscreen; ++i)
{
s = screen_gb_id(i);
tag_screen(s, tag_gb_id(s, tret[i]));
}
}
/* Re-adjust tabbed clients */
SLIST_FOREACH(c, &W->h.client, next)
if((cc = client_gb_win(c->tmp)) && cc != c)
_client_tab(c, cc);
if((fc = client_gb_win(focus)) && fc != W->client)
client_focus(fc);
SLIST_FOREACH(c, &W->h.client, next)
if(c->flags & CLIENT_TILED)
layout_fix_hole(c);
W->flags &= ~WMFS_SCAN;
if(tret)
XFree(tret);
XFree(w);
XSync(W->dpy, false);
}
static inline void
wmfs_sigchld(void)
{
if(W->flags & WMFS_SIGCHLD)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
W->flags ^= WMFS_SIGCHLD;
}
}
static void
wmfs_loop(void)
{
XEvent ev;
while((W->flags & WMFS_RUNNING) && !XNextEvent(W->dpy, &ev))
{
/* Manage SIGCHLD event here, X is not safe with it */
wmfs_sigchld();
EVENT_HANDLE(&ev);
}
}
static inline void
wmfs_init(void)
{
log_init();
wmfs_xinit();
ewmh_init();
screen_init();
event_init();
config_init();
}
void
wmfs_quit(void)
{
struct keybind *k;
struct rule *r;
struct theme *t;
struct client *c;
struct mousebind *m;
struct launcher *l;
ewmh_update_wmfs_props();
XFreeGC(W->dpy, W->rgc);
while(!SLIST_EMPTY(&W->h.client))
{
c = SLIST_FIRST(&W->h.client);
client_update_props(c, CPROP_LOC | CPROP_FLAG | CPROP_GEO);
c->flags |= (CLIENT_IGNORE_LAYOUT | CLIENT_REMOVEALL);
XMapWindow(W->dpy, c->win);
client_remove(c);
}
/* Will free:
*
* Screens -> tags
* -> Infobars -> Elements
*/
screen_free();
/* Conf stuffs */
while(!SLIST_EMPTY(&W->h.theme))
{
t = SLIST_FIRST(&W->h.theme);
SLIST_REMOVE_HEAD(&W->h.theme, next);
XFreeFontSet(W->dpy, t->font.fontset);
status_free_ctx(&t->tags_n_sl);
status_free_ctx(&t->tags_s_sl);
status_free_ctx(&t->tags_o_sl);
status_free_ctx(&t->tags_u_sl);
status_free_ctx(&t->client_n_sl);
status_free_ctx(&t->client_s_sl);
free(t);
}
while(!SLIST_EMPTY(&W->h.keybind))
{
k = SLIST_FIRST(&W->h.keybind);
SLIST_REMOVE_HEAD(&W->h.keybind, next);
free((void*)k->cmd);
free(k);
}
while(!SLIST_EMPTY(&W->h.mousebind))
{
m = SLIST_FIRST(&W->h.mousebind);
SLIST_REMOVE_HEAD(&W->h.mousebind, globnext);
free((void*)m->cmd);
free(m);
}
while(!SLIST_EMPTY(&W->h.launcher))
{
l = SLIST_FIRST(&W->h.launcher);
SLIST_REMOVE_HEAD(&W->h.launcher, next);
free((void*)l->name);
free((void*)l->prompt);
free((void*)l->command);
free(l);
}
while(!SLIST_EMPTY(&W->h.rule))
{
r = SLIST_FIRST(&W->h.rule);
SLIST_REMOVE_HEAD(&W->h.rule, next);
free(r->class);
free(r->instance);
free(r->role);
free(r->name);
free(r);
}
/* close log */
if(W->log)
fclose(W->log), W->log = NULL;
W->flags &= ~WMFS_RUNNING;
}
/** Reload WMFS binary
*/
void
uicb_reload(Uicb cmd)
{
(void)cmd;
W->flags &= ~WMFS_RUNNING;
W->flags |= WMFS_RELOAD;
}
void
uicb_quit(Uicb cmd)
{
(void)cmd;
W->flags &= ~WMFS_RUNNING;
}
static void
exec_uicb_function(Display *dpy, Window root, char *func, char *cmd)
{
Atom utf8s = XInternAtom(dpy, "UTF8_STRING", false);
XClientMessageEvent e = {
.type = ClientMessage,
.message_type = XInternAtom(dpy, "_WMFS_FUNCTION", false),
.window = root,
.format = 32,
.data.l[4] = true
};
XChangeProperty(dpy,root, XInternAtom(dpy, "_WMFS_FUNCTION", false), utf8s,
8, PropModeReplace, (unsigned char*)func, strlen(func));
if(!cmd)
cmd = "";
XChangeProperty(dpy, root, XInternAtom(dpy, "_WMFS_CMD", false), utf8s,
8, PropModeReplace, (unsigned char*)cmd, strlen(cmd));
XSendEvent(dpy, root, false, StructureNotifyMask, (XEvent*)&e);
XSync(dpy, False);
}
static void
signal_handle(int sig)
{
switch (sig)
{
case SIGQUIT:
case SIGTERM:
W->flags &= ~WMFS_RUNNING;
break;
case SIGCHLD:
W->flags |= WMFS_SIGCHLD;
break;
}
}
int
main(int argc, char **argv)
{
int i;
bool r;
Display *dpy;
char path[MAX_PATH_LEN] = { 0 };
struct sigaction sa;
(void)argc;
sprintf(path, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
/* Opt */
while((i = getopt(argc, argv, "hvC:c:")) != -1)
{
switch(i)
{
default:
case 'h':
printf("usage: %s [-hv] [-c <func> <cmd] [-C <file>]\n"
" -h Show this page\n"
" -v Show WMFS version\n"
" -c <func> <cmd> Execute a specified UICB function\n"
" -C <file> Launch WMFS with a specified configuration file\n", argv[0]);
exit(EXIT_SUCCESS);
break;
case 'v':
printf("wmfs("WMFS_VERSION") 2 beta\n");
exit(EXIT_SUCCESS);
break;
case 'c':
if(!(dpy = XOpenDisplay(NULL)))
{
fprintf(stderr, "%s: Can't open X server\n", argv[0]);
exit(EXIT_FAILURE);
}
exec_uicb_function(dpy, DefaultRootWindow(dpy), optarg, argv[optind]);
XCloseDisplay(dpy);
exit(EXIT_SUCCESS);
break;
case 'C':
strncpy(path, optarg, MAX_PATH_LEN);
break;
}
}
W = (struct wmfs*)xcalloc(1, sizeof(struct wmfs));
/* Default path ~/.config/wmfs/wmfsrc */
W->confpath = path;
/* Get X display */
if(!(W->dpy = XOpenDisplay(NULL)))
{
fprintf(stderr, "%s: Can't open X server\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Set signal handler */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handle;
sigemptyset(&sa.sa_mask);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
/* Core */
wmfs_init();
wmfs_scan();
wmfs_loop();
wmfs_quit();
r = (W->flags & WMFS_RELOAD);
free(W);
if(r)
execvp(argv[0], argv);
XCloseDisplay(W->dpy);
return 1;
}

423
src/wmfs.h Normal file
View File

@ -0,0 +1,423 @@
/*
* wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
* For license, see COPYING.
*/
#ifndef WMFS_H
#define WMFS_H
/* Standard */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <locale.h>
#include <err.h>
#include <sys/queue.h>
/* Xlib */
#include <X11/Xlib.h>
#include <X11/Xatom.h>
/* Local */
#include "log.h"
#define CONFIG_DEFAULT_PATH ".config/wmfs/wmfsrc"
#define ButtonMask (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask)
#define MouseMask (ButtonMask | PointerMotionMask)
#define KeyMask (KeyPressMask | KeyReleaseMask)
typedef unsigned long Flags;
typedef unsigned int Color;
typedef const char* Uicb;
enum barpos
{
BarTop = 0,
BarBottom,
BarHide,
BarLast
};
enum position
{
Right = 0,
Left,
Top,
Bottom,
Center,
NoAlign,
PositionLast
};
enum size_hints
{
BASEW, BASEH,
INCW, INCH,
MAXW, MAXH,
MINW, MINH,
MINAX, MINAY,
MAXAX, MAXAY,
SHLAST
};
/*
* Structures
*/
struct geo
{
int x, y, w, h;
};
struct geo_list
{
struct geo geo;
SLIST_ENTRY(geo_list) next;
};
struct colpair
{
Color fg, bg;
};
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 */
};
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;
};
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;
};
struct status_gcache
{
char *name;
int *datas;
int ndata;
SLIST_ENTRY(status_gcache) next;
};
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;
};
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;
};
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;
};
SLIST_HEAD(chead, client);
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;
};
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 */
};
struct layout_set
{
int n;
SLIST_HEAD(, geo_list) geos;
TAILQ_ENTRY(layout_set) next;
};
struct keybind
{
unsigned int mod;
void (*func)(Uicb);
Uicb cmd;
KeySym keysym;
SLIST_ENTRY(keybind) next;
};
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;
};
struct theme
{
char *name;
/* Font */
struct
{
int as, de, width, height;
XFontSet fontset;
} font;
/* Bars */
struct colpair bars;
int bars_width;
/* 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;
/* 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;
SLIST_ENTRY(theme) next;
};
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;
};
struct launcher
{
char *name;
char *prompt;
char *command;
#define HISTOLEN 64
char histo[HISTOLEN][256];
int nhisto;
int width;
SLIST_ENTRY(launcher) next;
};
struct launcher_ccache
{
char *start;
char **namelist;
size_t hits;
};
struct _systray
{
struct geo geo;
Window win;
SLIST_ENTRY(_systray) next;
};
#define MAX_PATH_LEN 8192
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*/
int padding;
/* Log file */
FILE *log;
/* 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;
/*
* 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;
/*
* 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;
/*
* Selected screen, client
*/
struct screen *screen;
struct client *client;
};
int wmfs_error_handler(Display *d, XErrorEvent *event);
int wmfs_error_handler_dummy(Display *d, XErrorEvent *event);
void wmfs_grab_keys(void);
void wmfs_numlockmask(void);
void wmfs_init_font(char *font, struct theme *t);
void wmfs_quit(void);
void uicb_reload(Uicb cmd);
void uicb_quit(Uicb cmd);
/* Single global variable */
struct wmfs *W;
#endif /* WMFS_H */

199
style.css
View File

@ -1,199 +0,0 @@
/* options -----------------------------------------------------------*/
* { padding:0; margin:0; }
a { color: #ccc; text-decoration: none; }
a:hover { color: #aaa; }
pre { color: #ccc; }
/* body --------------------------------------------------------------*/
body {
font: 12px/18px sans-serif;
color: #aaa;
background-color: #0F0F0F;
}
/* container ---------------------------------------------------------*/
#container {
width: 100%;
height: 100%;
margin: 0px auto;
background-color: #A8A8A8;
overflow: hidden;
}
/* header ------------------------------------------------------------*/
#header {
position: fixed;
top: 0px;
z-index: 10;
width: 100%;
padding: 3px 5px 5px 2px;
background-color: #2B2B2B;
}
#header h1 {
font: 30px sans-serif;
text-align: right;
margin-right: 20px;
}
#header h1 span {
margin-right: 40px;
font-size: 13px;
}
#header h2 {
position: absolute;
font: 18px sans-serif;
left: 20px;
top: 10px;
}
/* links -------------------------------------------------------------*/
#links {
display: block;
margin: 60px auto 5px auto;
width: 100%;
}
.categorie {
padding: 0 10px 15px 25px;
margin: 0 auto 10px auto;
position: relative;
width: 90%;
background-color: #525252;
-webkit-box-shadow: 1px 1px 12px #000;
-moz-box-shadow: 1px 1px 12px #000;
box-shadow: 1px 1px 12px #000;
}
.categorie a { text-decoration: underline ; }
.categorie h2 { padding: 15px 0 5px 10px; }
/* iframe for irc ----------------------------------------------------*/
iframe {
opacity: 0.9;
-moz-opacity : 0.9;
-ms-filter: "alpha(opacity=90)";
margin: 15px auto 0 -10px;
-webkit-box-shadow: 1px 1px 12px #000;
-moz-box-shadow: 1px 1px 12px #000;
box-shadow: 1px 1px 12px #000;
}
/* footer ------------------------------------------------------------*/
#footer {
margin: 20px auto 0px auto;
display: block;
width: 100%;
padding: 0px 5px 0px 5px;
background-color: #2B2B2B;
font-size: 10px;
text-align: center;
-webkit-box-shadow: 1px 1px 12px #000;
-moz-box-shadow: 1px 1px 12px #000;
box-shadow: 1px 1px 12px #000;
}
/* cc BY-NC-SA License :: arpinux :: 2011 :: http://arpinux.org */
/* slideshow */
/*
Skin Name: Nivo Slider Default Theme
Skin URI: http://nivo.dev7studios.com
Skin Type: flexible
Description: The default skin for the Nivo Slider.
Version: 1.0
Author: Gilbert Pellegrom
Author URI: http://dev7studios.com
*/
.theme-default .nivoSlider {
position:relative;
background:#444 url(icons/loading.gif) no-repeat 50% 50%;
margin-bottom:20px;
-webkit-box-shadow: 1px 1px 12px #000;
-moz-box-shadow: 1px 1px 12px #000;
box-shadow: 1px 1px 12px #000;
}
.theme-default .nivoSlider img {
position:absolute;
top:0px;
left:0px;
display:none;
}
.theme-default .nivo-controlNav {
position:absolute;
left:5%;
bottom:-42px;
margin-left:-40px; /* Tweak this to center bullets */
}
.theme-default .nivo-directionNav a {
display:block;
width:30px;
height:30px;
background:url(icons/arrows.png) no-repeat;
text-indent:-9999px;
border:0;
}
.theme-default a.nivo-nextNav {
background-position:-30px 0;
right:15px;
}
.theme-default a.nivo-prevNav {
left:15px;
}
table {
border-collapse:separate;
border-spacing:0;
}
.theme-default #slider {
margin: 20px auto 20px auto;
width:800px; /* Make sure your images are the same size */
height:345px; /* Make sure your images are the same size */
}
.clear {
clear:both;
}
/*
* jQuery Nivo Slider v2.7.1
* http://nivo.dev7studios.com
*
* Copyright 2011, Gilbert Pellegrom
* Free to use and abuse under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* March 2010
*/
/* The Nivo Slider styles */
.nivoSlider {
position:relative;
}
.nivoSlider img {
position:absolute;
top:0px;
left:0px;
}
/* The slices and boxes in the Slider */
.nivo-slice {
display:block;
position:absolute;
z-index:5;
height:100%;
}
.nivo-box {
display:block;
position:absolute;
z-index:5;
}
/* Direction nav styles (e.g. Next & Prev) */
.nivo-directionNav a {
position:absolute;
top:45%;
z-index:9;
cursor:pointer;
}
.nivo-prevNav {
left:0px;
}
.nivo-nextNav {
right:0px;
}

788
wmfs.1 Normal file
View File

@ -0,0 +1,788 @@
.\" title: wmfs
.\" dev: xorg62
.\" man: arpinux
.\"
.TH "WMFS" "1" "2012/05/02" "wmfs" "manual of wmfs"
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.SH "NAME"
wmfs \- Window Manager From Scratch
.SH "SYNOPSIS"
\fBwmfs\fR [\fB\-hv\fR] [\fB\-C <file>\fR] [\fB\-c <uicb_function> <cmd>\fR]
.sp
.SH "DESCRIPTION"
\fBWMFS\fR is a lightweight and highly configurable tiling window manager for X written in C\&.
.sp
.SH "OPTIONS"
.PP
\fB\-C <file>\fR
.RS 4
Load a configuration file\&.
.RE
.PP
\fB\-c <uicb_function> <cmd>\fR
.RS 4
Execute an uicb function to control WMFS\&.
.RE
.PP
\fB\-v\fR
.RS 4
Print version information to standard output, then exit\&.
.RE
.PP
\fB\-h\fR
.RS 4
Print help information, then exit\&.
.RE
.SH "DEFAULT KEY BINDINGS"
.PP
\fBControl\-Alt + r\fR
.RS 4
Reload WMFS binary
.RE
.PP
\fBSuper + Return\fR
.RS 4
Run a terminal (urxvt by default)
.RE
.PP
\fBSuper + q\fR
.RS 4
Quit the selected client
.RE
.PP
\fBControl\-Alt + q\fR
.RS 4
Exit WMFS
.RE
.PP
\fBSuper + f \fR
.RS 4
Toggle free the selected client
.RE
.PP
\fBSuper + Shift + f \fR
.RS 4
Toggle ignore_tag the selected client
.RE
.PP
\fBSuper + Shift + h \fR
.RS 4
Toggle infobar visibility
.RE
.PP
\fBAlt + Tab\fR
.RS 4
Give the focus to the next client
.RE
.PP
\fBAlt\-Shift + Tab\fR
.RS 4
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
.RE
.PP
\fBControl + Left\fR
.RS 4
Previous tag
.RE
.PP
\fBControl + Up\fR
.RS 4
Next screen
.RE
.PP
\fBControl + Down\fR
.RS 4
Previous screen
.RE
.PP
\fBSuper + m\fR
.RS 4
Vertical mirror layout
.RE
.PP
\fBSuper\-Shift + m\fR
.RS 4
Horizontal mirror layout
.RE
.PP
\fBSuper + r\fR
.RS 4
Rotate layout right
.RE
.PP
\fBSuper\-Shift + r\fR
.RS 4
Rotate layout left
.RE
.PP
\fBSuper\-Control\-Alt + h\fR
.RS 4
Integrate client in left layout
.RE
.PP
\fBSuper\-Control\-Alt + j\fR
.RS 4
Integrate client in bottom layout
.RE
.PP
\fBSuper\-Control\-Alt + k\fR
.RS 4
Integrate client in top layout
.RE
.PP
\fBSuper\-Control\-Alt + l\fR
.RS 4
Integrate client in right layout
.RE
.PP
\fBSuper + o\fR
.RS 4
Restore previous layout
.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
.RS 4
Change tag view
.RE
.PP
\fBSuper\-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"
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
.sp
.SH "COPYING"
WMFS is under the BSD license\&. See COPYING for more information\&.
.RE

7
wmfs.desktop Normal file
View File

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

284
wmfsrc Normal file
View File

@ -0,0 +1,284 @@
#
# WMFS2 configuration file
#
# Possible file inclusion:
# @include "file"
# Multi theme section
[themes]
[theme]
# No name mean default
# name = "default"
font = "fixed"
# Bars
bars_width = 14
bars_fg = "#AABBAA"
bars_bg = "#223322"
# Element tags
tags_normal_fg = "#AABBAA"
tags_normal_bg = "#223322"
# tags_normal_statusline = ""
tags_sel_fg = "#223322"
tags_sel_bg = "#AABBAA"
# tags_sel_statusline = ""
tags_occupied_fg = "#AABBAA"
tags_occupied_bg = "#445544"
tags_occupied_statusline = "\R[0;0;100;1;#AABBAA]"
tags_urgent_fg = "#223322"
tags_urgent_bg = "#CC5544"
# tags_urgent_statusline = ""
tags_border_color = "#112211"
tags_border_width = 1
# Frame / Client
client_normal_fg = "#AABBAA"
client_normal_bg = "#223322"
client_normal_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
client_sel_fg = "#223322"
client_sel_bg = "#AABBAA"
client_sel_statusline = "\s[3;9;#121212;x] \s[2;8;#ff0000;x](1;client_close)"
# client_free_statusline = ""
frame_bg = "#555555"
client_titlebar_width = 12
client_border_width = 1
[/theme]
[/themes]
[bars]
# Position:
#
# 0 Top
# 1 Bottom
# 2 Hide
# Element type:
#
# t Tags
# s Statustext (will take available space)
# y Systray (can be set only ONE time among all element)
# l Launcher (will be expended at launcher use)
[bar]
position = 0
screen = 0
elements = "tlsy" # element order in bar
theme = "default"
[/bar]
# [bar]
# position = 0
# screen = 1
# elements = "ts"
# theme = "default"
# [/bar]
[/bars]
[tags]
# Tag wrapping navigation
circular = false
# Use no screen option or screen = -1 to set tag on each screen
[tag]
screen = -1
name = "1"
# statusline=""
[/tag]
[tag] name = "2" [/tag]
[tag] name = "3" [/tag]
[tag] name = "4" [/tag]
[tag] name = "5" [/tag]
[tag] name = "6" [/tag]
[tag] name = "7" [/tag]
# 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]
[/tags]
[client]
# Padding between clients (default: 0) :
#padding = 75
# Give focus to new created client (default = false)
autofocus = false
theme = "default"
key_modifier = "Super"
# Focus type:
# enter : focus follow mouse (default)
# click : click to focus
# everything-else : disable mouse focus support
focus = enter
[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]
[/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]
[/rules]
[launchers]
# command can be an uicb function or an uicb function + extension (see example)
[launcher]
name = "exec"
prompt = "Run:"
# Example of uicb + ext:
# command = "spawn xterm -e"
command = "spawn"
width = 150
[/launcher]
[/launchers]
[keys]
[key] mod = {"Super"} key = "Return" func = "spawn" cmd = "urxvt || xterm" [/key]
[key] mod = {"Control", "Alt"} key = "q" func = "quit" [/key]
[key] mod = {"Control", "Alt"} key = "r" func = "reload" [/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]
[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]
[key] mod = {"Super"} key = "minus" func = "tag_del" [/key]
[key] mod = {"Super", "Shift"} key = "minus" func = "tag_new" [/key]
# tag function: cmd = nameofthetag
#[key] mod = {"Super"} key = "z" func = "tag" cmd = "2" [/key]
[key] mod = {"Control"} key = "Right" func = "tag_next" [/key]
[key] mod = {"Control"} key = "Left" func = "tag_prev" [/key]
[key] mod = {"Control"} key = "Up" func = "screen_next" [/key]
[key] mod = {"Control"} key = "Down" func = "screen_prev" [/key]
[key] mod = {"Super"} key = "q" func = "client_close" [/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]
# 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", "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]
# 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]
# Tabbing command
[key] mod = {"Alt", "Shift"} key = "h" func = "client_tab_left" [/key]
[key] mod = {"Alt", "Shift"} key = "l" func = "client_tab_right" [/key]
[key] mod = {"Alt", "Shift"} key = "k" func = "client_tab_top" [/key]
[key] mod = {"Alt", "Shift"} key = "j" func = "client_tab_bottom" [/key]
[key] mod = {"Alt", "Shift"} key = "u" func = "client_untab" [/key]
[key] mod = {"Super"} key = "t" func = "client_tab_next_opened" [/key]
# Layout manipulation
[key] mod = {"Super"} key = "m" func = "layout_vmirror" [/key]
[key] mod = {"Super", "Shift"} key = "m" func = "layout_hmirror" [/key]
[key] mod = {"Super"} key = "r" func = "layout_rotate_right" [/key]
[key] mod = {"Super", "Shift"} key = "r" func = "layout_rotate_left" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "h" func = "layout_integrate_left" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "j" func = "layout_integrate_bottom" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "k" func = "layout_integrate_top" [/key]
[key] mod = {"Control", "Super", "Alt"} key = "l" func = "layout_integrate_right" [/key]
# Layout set historic travelling function (TESTING)
[key] mod = {"Super"} key = "o" func = "layout_prev_set" [/key]
[key] mod = {"Super", "Shift"} key = "o" func = "layout_next_set" [/key]
# Toggle client free/tile
[key] mod = {"Super"} key = "f" func = "client_toggle_free" [/key]
# Toggle client ignore_tag
[key] mod = {"Super", "Shift"} key = "f" func = "client_toggle_ignore_tag" [/key]
# Toggle infobar visibility
[key] mod = {"Super", "Shift"} key = "h" func = "infobar_toggle_hide" cmd = "default" [/key]
# Launcher
[key] mod = {"Super"} key = "p" func = "launcher" cmd = "exec" [/key]
[/keys]