From 0d42fe0647179cbc154cc6ded62787a9cc54bbad Mon Sep 17 00:00:00 2001 From: Robert McLeod Date: Tue, 1 Sep 2015 17:26:04 +1200 Subject: [PATCH 001/205] Converted the README to markdown merged from the google code wiki This seems much nicer to me. A single pretty file from which to get all the information you need to install and operate skippy-xd. --- README.asciidoc | 6 --- README.md | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 6 deletions(-) delete mode 100644 README.asciidoc create mode 100644 README.md diff --git a/README.asciidoc b/README.asciidoc deleted file mode 100644 index ac9b8dc..0000000 --- a/README.asciidoc +++ /dev/null @@ -1,6 +0,0 @@ -link:https://code.google.com/p/skippy-xd/[Skippy-XD] -- a full-screen task-switcher for X11. - -This GitHub repo hosts the code of a fork from the original 0.5.0 release (2004), initially maintained by Nick Watts (2011) and now by Richard Grenville (2013). The project's home page, downloads and wiki are hosted at link:https://code.google.com/p/skippy-xd/[Skippy-XD on Google Code]. An Ubuntu PPA for daily builds is available at link:https://launchpad.net/~landronimirc/+archive/skippy-xd-daily/[Skippy-XD PPA (daily)]. - - -image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/richardgv/skippy-xd?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6a4829 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# Skippy-XD + +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/richardgv/skippy-xd) + +A full-screen expose-style task-switcher for X11. + +Originally mirrored from [the Google Code project](https://code.google.com/p/skippy-xd/) this GitHub repo hosts the code of a fork from the original 0.5.0 release (2004). That fork was initially maintained by Nick Watts (2011) and is now maintained by [Richard Grenville](https://github.com/richardgv) (2013). + +## Installation + +If you're using Ubuntu, you may simply install via the [Skippy-XD PPA.](https://launchpad.net/~landronimirc/+archive/skippy-xd) (or the [daily PPA](https://launchpad.net/~landronimirc/+archive/skippy-xd-daily/)). + +```sh +sudo add-apt-repository ppa:landronimirc/skippy-xd +sudo apt-get update +sudo apt-get install skippy-xd +``` + +### From Source + +To compile Skippy-XD from source you need to install the following development packages: + +```sh +apt-get install libimlib2-dev libfontconfig1-dev libfreetype6-dev libx11-dev libxext-dev libxft-dev +libxrender-dev zlib1g-dev libxinerama-dev libxcomposite-dev libxdamage-dev libxfixes-dev libxmu-dev +``` + +Now get the source, build and install: + +```sh +git clone https://github.com/richardgv/skippy-xd.git +cd skippy-xd +make +make install +``` + +## Usage + +### Config file + +Download the original `skippy-xd.rc-default` config file and copy it to `~/.config/skippy-xd/skippy-xd.rc` and edit it to your liking. + +### Command Line + +Once Skippy-XD is installed, you can run it by entering `skippy-xd` at the command line. This will start the program, activate the window picker once, then exit. However, starting the program produces a brief flicker, so its better to keep the application running in the background as a daemon and just activate it when you want to use the window picker. + +To run the daemon, use the following command: + +```sh +skippy-xd --start-daemon +``` + +If for whatever reason you need to cleanly stop the running daemon, do this: + +``` +skippy-xd --stop-daemon +``` + +Once the daemon is running you can use the following command to activate it: + +``` +skippy-xd --activate-window-picker +``` + +However, sometimes pressing the Return key to run this last command also causes the window to be selected, so it is probably more effective in testing to do this: + +``` +sleep 1 && skippy-xd --activate-window-picker +This will wait 1 second, then activate the picker. +``` + +### Keyboard Shortcuts + +Typically, it is helpful to set up keyboard shortcuts for skippy-xd. It is up to you to figure out how to set up keyboard shortcuts for your own window manager (it would be crazy to cover them all here). However, to get you started, here's some links: + +Xfce: http://wiki.xfce.org/faq#keyboard +Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse +Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file + +A good method is to set `skippy-xd --start-daemon` to be run after login, and bind a key (like **SUPER_L** [windows key] or **F9**) to `skippy-xd --activate-window-picker`. Then the flicker mentioned above only happens when starting the daemon on login, and you are free to use the hotkey you bound to open skippy-xd. + +## Troubleshooting + +Admittedly, skippy-xd is not yet perfect. I find that sometimes it will just stop working. I'm not sure why yet (or else I'd fix it!), but it doesn't seem to be a crash (`ps aux | grep skippy` shows the daemon is still running). To work around it I currently have a script in my home folder called `restart-skippy-xd.sh` that contains this: + +``` +#!/bin/sh +killall skippy-xd +rm /tmp/skippy-xd-fifo +skippy-xd --start-daemon +``` + +Next, I bind this script to **CTRL+SHIFT+F9**. This means that when skippy-xd occasionally stops working, a quick **CTRL+SHIFT+F9**, then **F9** again and its back. + +If you installed it from the Skippy-XD PPA, then you're advised to use skippy-xd-activate to activate the task-switcher (if the daemon is already running); the simple bash script will introduce a small delay before calling Skippy-XD, and this tends to increase reliability. If the plugin has already crashed, then use a different keyboard shortcut for skippy-xd-restart, another simple script that will clean up and restart Skippy-XD daemon (the same as `restart-skippy-xd.sh` above). + +## See Also + +* [Skippy-XD on Ubuntu Wiki](https://wiki.ubuntu.com/Skippy) +* [Skippy-XD on Google Code](https://code.google.com/p/skippy-xd/) From 2a9663e82e8f32b2a723b17025289594af90d5c2 Mon Sep 17 00:00:00 2001 From: Robert McLeod Date: Tue, 1 Sep 2015 18:23:12 +1200 Subject: [PATCH 002/205] forgot to bullet point the keybinding howtos --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a6a4829..5b070ba 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,9 @@ This will wait 1 second, then activate the picker. Typically, it is helpful to set up keyboard shortcuts for skippy-xd. It is up to you to figure out how to set up keyboard shortcuts for your own window manager (it would be crazy to cover them all here). However, to get you started, here's some links: -Xfce: http://wiki.xfce.org/faq#keyboard -Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse -Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file +* Xfce: http://wiki.xfce.org/faq#keyboard +* Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse +* Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file A good method is to set `skippy-xd --start-daemon` to be run after login, and bind a key (like **SUPER_L** [windows key] or **F9**) to `skippy-xd --activate-window-picker`. Then the flicker mentioned above only happens when starting the daemon on login, and you are free to use the hotkey you bound to open skippy-xd. From 33b4de5a84604c6bfd3a27efdb8f9b439f551061 Mon Sep 17 00:00:00 2001 From: Robert McLeod Date: Tue, 1 Sep 2015 18:34:50 +1200 Subject: [PATCH 003/205] Added some missing stuff Namely, a couple of links I missed, the blurb from the main google code project page, a link to the downloads page on the Google Code project and the youtube demo link. I tried to convert the Youtube video into a gif so we can embed it straight into the README on Github but my computer was playing silly buggers. --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b070ba..6ab2d6b 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,14 @@ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/richardgv/skippy-xd) -A full-screen expose-style task-switcher for X11. +A full-screen expose-style task-switcher for X11. You know that thing Mac OS X, Gnome 3, Compiz and KWin do where you press a hotkey and suddenly you see miniature versions of all your windows at once? Skippy-XD does just that. It's most commonly known by Mac OS X's name for it - **Exposé**. **You can see a demo on [YouTube](http://www.youtube.com/watch?v=gVRPCd7OS38).** Originally mirrored from [the Google Code project](https://code.google.com/p/skippy-xd/) this GitHub repo hosts the code of a fork from the original 0.5.0 release (2004). That fork was initially maintained by Nick Watts (2011) and is now maintained by [Richard Grenville](https://github.com/richardgv) (2013). +So why do I want Skippy-XD instead of Mac OS X, Compiz or KWin? Well many Linux users prefer a lightweight, speedy desktop environment like Xfce, LXDE or their own Openbox-based hodge podge. Many even appreciate that these environments don't have compositing because it can degrade performance in some applications (especially 3D applications). + +Skippy-XD is a standalone application for providing a window picker with live previews (including live video) on Linux desktops that run an X server with compositing support. That means it's not baked into the window manager, and the compositing is not being used all the time. So the performance of you're window manager isn't degraded, but you still get a window picker that's every bit as pretty as OSX's Exposé or KWin's "Present Windows", with all the desktop-navigational efficiency. Compositing only takes effect when you press the hotkey to display the window picker. + ## Installation If you're using Ubuntu, you may simply install via the [Skippy-XD PPA.](https://launchpad.net/~landronimirc/+archive/skippy-xd) (or the [daily PPA](https://launchpad.net/~landronimirc/+archive/skippy-xd-daily/)). @@ -16,6 +20,8 @@ sudo apt-get update sudo apt-get install skippy-xd ``` +You can also check the [downloads page at the Google Code project](https://code.google.com/p/skippy-xd/downloads/list). + ### From Source To compile Skippy-XD from source you need to install the following development packages: @@ -98,3 +104,5 @@ If you installed it from the Skippy-XD PPA, then you're advised to use skippy-xd * [Skippy-XD on Ubuntu Wiki](https://wiki.ubuntu.com/Skippy) * [Skippy-XD on Google Code](https://code.google.com/p/skippy-xd/) +* [Original home of Skippy-XD](http://thegraveyard.org/skippy.html) +* [Skippy-XD on freecode](http://freecode.com/projects/skippy) From 4f121ad05ab25bbaefa740df9e8d056302104bad Mon Sep 17 00:00:00 2001 From: Antonio Malcolm Date: Mon, 21 Dec 2015 21:26:16 -0800 Subject: [PATCH 004/205] fixed compiler flags and added a toggle script for improved stability --- Makefile | 2 ++ skippy-xd-toggle | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100755 skippy-xd-toggle diff --git a/Makefile b/Makefile index 751a692..9d13508 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PREFIX ?= /usr BINDIR ?= ${PREFIX}/bin CC ?= gcc +CPPFLAGS += -std=c99 -Wall -I/usr/include/freetype2 SRCS_RAW = skippy wm dlist mainwin clientwin layout focus config tooltip img img-xlib PACKAGES = x11 xft xrender xcomposite xdamage xfixes @@ -71,6 +72,7 @@ install: ${BINS} skippy-xd.sample.rc install -d "${DESTDIR}${BINDIR}/" "${DESTDIR}/etc/xdg/" install -m 755 ${BINS} "${DESTDIR}${BINDIR}/" install -m 644 skippy-xd.sample.rc "${DESTDIR}/etc/xdg/skippy-xd.rc" + install -m 755 skippy-xd-toggle "${DESTDIR}${BINDIR}/" uninstall: # Should configuration file be removed? diff --git a/skippy-xd-toggle b/skippy-xd-toggle new file mode 100755 index 0000000..e24cfc2 --- /dev/null +++ b/skippy-xd-toggle @@ -0,0 +1,42 @@ +#!/bin/sh + +killSkippyXd() { + + killall 'skippy-xd' + + if [ -f '/tmp/skippy-xd-fifo' ] + then + rm /tmp/skippy-xd-fifo + fi + +} + +toggleSkippyXd() { + + skippyConfig="$1" + psSkippyOut=`ps aux | grep '[s]kippy-xd '` + psSkippyActivateOut=`ps aux | grep '[s]kippy-xd --activate-window-picker'` + psSkippyToggleOut=`ps aux | grep '[s]kippy-xd --toggle-window-picker'` + + ## IF, when calling skippy-xd, to start the window picker, + ## a process to do so already exists, then skippy-xd is stuck, + ## so we must clear its queue and restart its daemon. + ## ELSE, if the skippy-xd daemon has not been started, + ## we should start it. + + if [ ! -z "$psSkippyActivateOut" ] || [ ! -z "$psSkippyToggleOut" ] + then + killSkippyXd + skippy-xd --start-daemon --config "$skippyConfig" & + elif [ -z "$psSkippyOut" ] + then + skippy-xd --start-daemon --config "$skippyConfig" & + fi + + skippy-xd --toggle-window-picker + + exit $? + +} + +(toggleSkippyXd "$@") From 10eb0f70475548dd496e23f541c6fc462d089e3f Mon Sep 17 00:00:00 2001 From: Antonio Malcolm Date: Mon, 21 Dec 2015 21:53:25 -0800 Subject: [PATCH 005/205] README update --- README.md | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6ab2d6b..6f4481e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # Skippy-XD -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/richardgv/skippy-xd) - -A full-screen expose-style task-switcher for X11. You know that thing Mac OS X, Gnome 3, Compiz and KWin do where you press a hotkey and suddenly you see miniature versions of all your windows at once? Skippy-XD does just that. It's most commonly known by Mac OS X's name for it - **Exposé**. **You can see a demo on [YouTube](http://www.youtube.com/watch?v=gVRPCd7OS38).** +...is a full-screen, expose-style, task-switcher for X11. You know that thing Mac OS X, Gnome 3, Compiz and KWin do where you press a hotkey and suddenly you see miniature versions of all your windows at once? Skippy-XD does just that. Originally mirrored from [the Google Code project](https://code.google.com/p/skippy-xd/) this GitHub repo hosts the code of a fork from the original 0.5.0 release (2004). That fork was initially maintained by Nick Watts (2011) and is now maintained by [Richard Grenville](https://github.com/richardgv) (2013). -So why do I want Skippy-XD instead of Mac OS X, Compiz or KWin? Well many Linux users prefer a lightweight, speedy desktop environment like Xfce, LXDE or their own Openbox-based hodge podge. Many even appreciate that these environments don't have compositing because it can degrade performance in some applications (especially 3D applications). +Skippy-XD is a standalone application for providing a window picker with live previews (including live video) on Linux desktops that run an X server with compositing support. That means it's not baked into the window manager, and compositing is used only when the window picker is active. + +The performance of your window manager isn't degraded, and you get a window picker that's every bit as elegant as OSX's Exposé or KWin's "Present Windows", with all the desktop-navigational efficiency. -Skippy-XD is a standalone application for providing a window picker with live previews (including live video) on Linux desktops that run an X server with compositing support. That means it's not baked into the window manager, and the compositing is not being used all the time. So the performance of you're window manager isn't degraded, but you still get a window picker that's every bit as pretty as OSX's Exposé or KWin's "Present Windows", with all the desktop-navigational efficiency. Compositing only takes effect when you press the hotkey to display the window picker. +**You can see a demo on [YouTube](http://www.youtube.com/watch?v=gVRPCd7OS38).** ## Installation @@ -20,8 +20,6 @@ sudo apt-get update sudo apt-get install skippy-xd ``` -You can also check the [downloads page at the Google Code project](https://code.google.com/p/skippy-xd/downloads/list). - ### From Source To compile Skippy-XD from source you need to install the following development packages: @@ -75,30 +73,42 @@ sleep 1 && skippy-xd --activate-window-picker This will wait 1 second, then activate the picker. ``` +Alternatively, you can use the included toggle script, which starts the daemon, if it isn't already started, and activates the window picker: + +``` +skippy-xd-toggle +``` + +or, with the path to your configuration file: + +``` +skippy-xd-toggle /PATH/TO/YOUR/CONFIG +``` + ### Keyboard Shortcuts -Typically, it is helpful to set up keyboard shortcuts for skippy-xd. It is up to you to figure out how to set up keyboard shortcuts for your own window manager (it would be crazy to cover them all here). However, to get you started, here's some links: +Typically, it is helpful to set up keyboard shortcuts for skippy-xd. To get you started, here are some links: * Xfce: http://wiki.xfce.org/faq#keyboard * Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse * Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file -A good method is to set `skippy-xd --start-daemon` to be run after login, and bind a key (like **SUPER_L** [windows key] or **F9**) to `skippy-xd --activate-window-picker`. Then the flicker mentioned above only happens when starting the daemon on login, and you are free to use the hotkey you bound to open skippy-xd. +A good method is to set `skippy-xd --start-daemon` to be run after login, and bind a key (like **SUPER_L** [windows key] or **F9**) to , `skippy-xd --toggle-window-picker`, or `skippy-xd-toggle`. ## Troubleshooting -Admittedly, skippy-xd is not yet perfect. I find that sometimes it will just stop working. I'm not sure why yet (or else I'd fix it!), but it doesn't seem to be a crash (`ps aux | grep skippy` shows the daemon is still running). To work around it I currently have a script in my home folder called `restart-skippy-xd.sh` that contains this: +Admittedly, skippy-xd is not yet perfect. Sometimes it will just stop working, but it doesn't seem to be a crash (`ps aux | grep skippy` shows the daemon is still running). +To avoid this, your best option is to use the included toggle script: ``` -#!/bin/sh -killall skippy-xd -rm /tmp/skippy-xd-fifo -skippy-xd --start-daemon +skippy-xd-toggle ``` -Next, I bind this script to **CTRL+SHIFT+F9**. This means that when skippy-xd occasionally stops working, a quick **CTRL+SHIFT+F9**, then **F9** again and its back. +or, with the path to your configuration file: -If you installed it from the Skippy-XD PPA, then you're advised to use skippy-xd-activate to activate the task-switcher (if the daemon is already running); the simple bash script will introduce a small delay before calling Skippy-XD, and this tends to increase reliability. If the plugin has already crashed, then use a different keyboard shortcut for skippy-xd-restart, another simple script that will clean up and restart Skippy-XD daemon (the same as `restart-skippy-xd.sh` above). +``` +skippy-xd-toggle /PATH/TO/YOUR/CONFIG +``` ## See Also From 53d2d132cceae0a23ba3fc72bc4de07d86f17555 Mon Sep 17 00:00:00 2001 From: Antonio Malcolm Date: Mon, 21 Dec 2015 21:57:11 -0800 Subject: [PATCH 006/205] README update --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6f4481e..5e1a7a7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ...is a full-screen, expose-style, task-switcher for X11. You know that thing Mac OS X, Gnome 3, Compiz and KWin do where you press a hotkey and suddenly you see miniature versions of all your windows at once? Skippy-XD does just that. -Originally mirrored from [the Google Code project](https://code.google.com/p/skippy-xd/) this GitHub repo hosts the code of a fork from the original 0.5.0 release (2004). That fork was initially maintained by Nick Watts (2011) and is now maintained by [Richard Grenville](https://github.com/richardgv) (2013). +Originally mirrored from [the Google Code project](https://code.google.com/p/skippy-xd/) this GitHub repo hosts the code of a fork from the original 0.5.0 release (2004), initially maintained by Nick Watts (2011) and Richard Grenville (2013). Skippy-XD is a standalone application for providing a window picker with live previews (including live video) on Linux desktops that run an X server with compositing support. That means it's not baked into the window manager, and compositing is used only when the window picker is active. @@ -56,21 +56,20 @@ skippy-xd --start-daemon If for whatever reason you need to cleanly stop the running daemon, do this: -``` +```sh skippy-xd --stop-daemon ``` Once the daemon is running you can use the following command to activate it: -``` +```sh skippy-xd --activate-window-picker ``` However, sometimes pressing the Return key to run this last command also causes the window to be selected, so it is probably more effective in testing to do this: -``` -sleep 1 && skippy-xd --activate-window-picker -This will wait 1 second, then activate the picker. +```sh +sleep 0.5 && skippy-xd --activate-window-picker ``` Alternatively, you can use the included toggle script, which starts the daemon, if it isn't already started, and activates the window picker: From d0a11f4b02b9af3181249ed8025823da95b11b6c Mon Sep 17 00:00:00 2001 From: Antonio Malcolm Date: Tue, 22 Dec 2015 04:28:12 -0800 Subject: [PATCH 007/205] version fix for Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9d13508..89ee6b0 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ INCS = $(shell pkg-config --cflags $(PACKAGES)) LIBS += -lm $(shell pkg-config --libs $(PACKAGES)) # === Version string === -SKIPPYXD_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1 --date=short --pretty=format:%cd) +SKIPPYXD_VERSION = "2015.12.21" CPPFLAGS += -DSKIPPYXD_VERSION="\"${SKIPPYXD_VERSION}\"" # === Recipes === From 893d3c857e44f4d7855d5667f127a9070c968879 Mon Sep 17 00:00:00 2001 From: Antonio Malcolm Date: Wed, 19 Oct 2016 23:13:20 -0700 Subject: [PATCH 008/205] skippy-xd-toggle executable update --- skippy-xd-toggle | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/skippy-xd-toggle b/skippy-xd-toggle index e24cfc2..e7e65e8 100755 --- a/skippy-xd-toggle +++ b/skippy-xd-toggle @@ -7,16 +7,26 @@ killSkippyXd() { if [ -f '/tmp/skippy-xd-fifo' ] then rm /tmp/skippy-xd-fifo + touch /tmp/skippy-xd-fifo fi + exit $? + } toggleSkippyXd() { + skippyDaemonStartCommand="skippy-xd --start-daemon" + psSkippyOut="`pgrep 'skippy-xd '`" + psSkippyActivateOut="`pgrep 'skippy-xd --activate-window-picker'`" + psSkippyToggleOut="`pgrep 'skippy-xd --toggle-window-picker'`" + skippyConfig="$1" - psSkippyOut=`ps aux | grep '[s]kippy-xd '` - psSkippyActivateOut=`ps aux | grep '[s]kippy-xd --activate-window-picker'` - psSkippyToggleOut=`ps aux | grep '[s]kippy-xd --toggle-window-picker'` + + if [ -f "$skippyConfig" ] + then + skippyDaemonStartCommand="$skippyDaemonStartCommand --config $skippyConfig" + fi ## IF, when calling skippy-xd, to start the window picker, ## a process to do so already exists, then skippy-xd is stuck, @@ -27,10 +37,10 @@ toggleSkippyXd() { if [ ! -z "$psSkippyActivateOut" ] || [ ! -z "$psSkippyToggleOut" ] then killSkippyXd - skippy-xd --start-daemon --config "$skippyConfig" & + $skippyDaemonStartCommand & elif [ -z "$psSkippyOut" ] then - skippy-xd --start-daemon --config "$skippyConfig" & + $skippyDaemonStartCommand & fi skippy-xd --toggle-window-picker From 72d1ddffa4923a36ae0eb7eaa95f3059eb9a346c Mon Sep 17 00:00:00 2001 From: Antonio Malcolm Date: Thu, 20 Oct 2016 01:25:34 -0700 Subject: [PATCH 009/205] skippy-xd-toggle executable update --- skippy-xd-toggle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skippy-xd-toggle b/skippy-xd-toggle index e7e65e8..d438c14 100755 --- a/skippy-xd-toggle +++ b/skippy-xd-toggle @@ -17,9 +17,9 @@ killSkippyXd() { toggleSkippyXd() { skippyDaemonStartCommand="skippy-xd --start-daemon" - psSkippyOut="`pgrep 'skippy-xd '`" - psSkippyActivateOut="`pgrep 'skippy-xd --activate-window-picker'`" - psSkippyToggleOut="`pgrep 'skippy-xd --toggle-window-picker'`" + psSkippyOut="`pgrep -f 'skippy-xd '`" + psSkippyActivateOut="`pgrep -f 'skippy-xd --activate-window-picker'`" + psSkippyToggleOut="`pgrep -f 'skippy-xd --toggle-window-picker'`" skippyConfig="$1" From ced016eeaeb0e8d0c2e72342697ebc5d8d0accc2 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 20:07:47 +0100 Subject: [PATCH 010/205] keybindings: helper functions --- src/skippy.h | 583 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 582 insertions(+), 1 deletion(-) diff --git a/src/skippy.h b/src/skippy.h index 36fe45e..1eac5f3 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -597,15 +597,48 @@ str_startswithwordi(const char *haystick, const char *needle) { && isspace0(haystick[needle_len]); } +/** + * @brief Convert a string into an integer. + */ +static inline int +str_to_int(const char *s) +{ + return (int)strtol(s,NULL,0); +} + +/** + * @brief Count the number of words in a string. + */ +static inline int +str_count_words(const char *s) +{ + if (!s) return 0; + + int count = 0; + while (*s != '\0') + { + while (*s != '\0' && isspace(*s)) // remove all spaces between words + s++; + + if(*s != '\0') + count++; + + while (*s != '\0' && !isspace(*s)) // loop past the found word + s++; + } + return count; +} + /** * @brief Get first word. * - * @param dest place to store pointer to a copy of the first word + * @param dest place to store pointer to a copy of the word * @return start of next word */ static inline const char * str_get_word(const char *s, char **dest) { *dest = NULL; + if (!s) return NULL; int i = 0; while (isspace(s[i])) ++i; int start = i; @@ -617,6 +650,81 @@ str_get_word(const char *s, char **dest) { return &s[i]; } +/** + * @brief Get first alphanumeric word [a-zA-Z0-9] only. + * everything else is treated as a word boundary (space) + * + * @param dest place to store pointer to a copy of the word + * @return start of next word + */ +static inline const char * +str_get_word_alnum(const char *s, char **dest) { + *dest = NULL; + if (!s) return NULL; + + // advance until we hit an alnum + int i = 0; + while (s[i] && !isalnum(s[i])) ++i; + + // set start of word + int start = i; + + // advance until we no longer are alnum + while (s[i] && isalnum(s[i])) ++i; + + // if we advanced any chars + if (i - start) + // then copy into a new null terminated string + *dest = mstrncpy(s + start, i - start); + + // keep advancing to the next word, while we are no longer alnum + while (s[i] && !isalnum(s[i])) ++i; + + // return NULL if the next char is null + if (!s[i]) return NULL; + + // otherwise return the pointer position, for the beginning of the next word + return &s[i]; +} + +/** + * @brief Get first alphanumeric word [a-zA-Z0-9_] including underscores. + * everything else is treated as a word boundary (space) + * This function INDLUDES _ underscores as being part of the words + * i.e. it does not break, when encountering underscores + * Otherwise the same as str_get_word_alnum() function (above) + * + * @param dest place to store pointer to a copy of the word + * @return start of next word + */ +static inline const char * +str_get_word_alnum_(const char *s, char **dest) { + *dest = NULL; + if (!s) return NULL; + + // advance until we hit an alnum + int i = 0; + while (s[i] && !isalnum(s[i]) && s[i] != '_') ++i; + + // set start of word + int start = i; + + // advance until we no longer are alnum + while (s[i] && (isalnum(s[i]) || s[i] == '_')) ++i; + + // if we advanced any chars + if (i - start) + // then copy into a new null terminated string + *dest = mstrncpy(s + start, i - start); + + // keep advancing to the next word, while we are no longer alnum + while (s[i] && !isalnum(s[i]) && s[i] != '_') ++i; + + // return NULL if the next char is null + if (!s[i]) return NULL; + return &s[i]; +} + /** * @brief Destroy a Pixmap. */ @@ -709,6 +817,264 @@ ev_key_str(XKeyEvent *ev) { return XKeysymToString(XLookupKeysym(ev, 0)); } +/** + * @brief Convert a string into a KeySym. + */ +static inline KeySym +key_str_sym(char *str) { + return XStringToKeysym(str); +} + +/** + * @brief Print an error message for each word in the string that is not recognized as a valid keysym + * + * @param str_err_prefix1 filename of the user's config file, where the setting is written + * @param str_err_prefix2 [section] of the rc config file where the setting is (ini format) + * @param str_syms a list of words, each word is suppsed to represent a valid KeySym + */ +static inline void +check_keysyms(const char *str_err_prefix1, const char *str_err_prefix2, const char *str_syms) +{ + if (!str_syms) return; + int count = str_count_words(str_syms); + + const char* next = str_syms; + for (int i = 0; i < count; i++) + { + char *word = NULL; + next = str_get_word(next, &word); + + if (!word) + break; + + KeySym keysym = key_str_sym(word); + + if (!keysym) + printfef("(): %s%s \"%s\" was not recognized as a valid KeySym. Run the program 'xev' to find the correct value.", str_err_prefix1, str_err_prefix2, word); + + free(word); + } +} + +/** + * @brief convert a string of words into an array of KeySyms + * if a word in the string is not recognized as a valid KeySym, + * then skip over it. Finally write 0x00 to the last array entry (+1) + * which denotes the end of the array of KeySyms + * + * @param s the string of words to parse / split / convert + * @param dest place to store pointer to the new array of KeySyms + * @return size of the array + */ +static inline int +keys_str_syms(const char *s, KeySym **dest) +{ + *dest = NULL; + if (!s) return 0; + + int num_words = str_count_words(s); + if(num_words == 0) return 0; + + KeySym *arr_keysyms = (KeySym *)malloc(sizeof(KeySym)*(num_words+1)); + memset(arr_keysyms, 0, sizeof(KeySym)*(num_words+1)); + + int count = 0; + for (int i = 0; i < num_words; i++) + { + char *word = NULL; + + s = str_get_word(s, &word); + // s = str_get_word_alnum_(s, &word); + + if (!word) + break; + + KeySym keysym = key_str_sym(word); + + // only increment the array counter if the keysym is valid + if(keysym) + { + arr_keysyms[count] = keysym; + count++; + } + free(word); + + if (!s) + break; + } + + *dest = arr_keysyms; + return count; +} + +/** + * @brief Count the number of KeySyms, in an array of KeySyms + */ +static inline int +arr_keysyms_size(KeySym *arr_keysyms) +{ + if (!arr_keysyms) return 0; + + int count = 0; + while(arr_keysyms[count] != 0x00) + count++; + + return count; +} + +/** + * @brief convert an array of KeySyms into an array of KeyCodes + * if a KeySym in the array is not recognized as a valid KeyCode, + * then skip over it. Finally write 0x00 to the last array entry (+1) + * which denotes the end of the array of KeyCodes + * + * @param keysyms the input array of KeySyms + * @param dest place to store pointer to the new array of KeyCodes + * @return size of the new array + */ +static inline int +keysyms_arr_keycodes(Display *display, KeySym *keysyms, KeyCode **dest) +{ + // fputs("keysyms_arr_keycodes(Display *display, KeySym *keysyms, KeyCode **dest)\n", stdout); fflush(stdout); + *dest = NULL; + if (!display) return 0; + if (!keysyms) return 0; + + int num_keysyms = arr_keysyms_size(keysyms); + if (num_keysyms == 0) return 0; + + KeyCode *arr_keycodes = (KeyCode *)malloc(sizeof(KeyCode)*(num_keysyms+1)); + memset(arr_keycodes, 0, sizeof(KeyCode)*(num_keysyms+1)); + + int count = 0; + for (int i = 0; i < num_keysyms; i++) + { + arr_keycodes[i] = XKeysymToKeycode(display, keysyms[i]); + // fprintf(stdout, "i=%i, keysym=%i, keycode=(0x%02lx)\n", i, keysyms[i], arr_keycodes[i]); + count++; + } + // fputs("\n", stdout); fflush(stdout); + + *dest = arr_keycodes; + return count; +} + +/** + * @brief Count the number of KeyCodes, in an array of KeyCodes + */ +static inline int +arr_keycodes_size(KeyCode *arr_keycodes) +{ + int count = 0; + if (!arr_keycodes) return 0; + + while (arr_keycodes[count] != 0x00) + count++; + + return count; +} + +/** + * @brief Check to see if there is a specific KeyCode in an array of KeyCodes + */ +static inline bool +arr_keycodes_includes(KeyCode *arr_keycodes, KeyCode keycode) +{ + if (!arr_keycodes) return false; + if (!keycode) return false; + + int count = 0; + while (arr_keycodes[count] != 0x00) + { + if (arr_keycodes[count] == keycode) + return true; + count++; + } + return false; +} + +/** + * @brief take 2 arrays of KeySyms, and generate a new array + * containing only the KeySyms that exist in both arrays + * Finally write 0x00 to the last array entry (+1) + * which denotes the end of the array of KeyCodes + * + * @param arr1 the 1st input array of KeySyms + * @param arr2 the 2nd input array of KeySyms + * @param dest place to store pointer to the new array of KeyCodes + * @return size of the new array + */ +static inline int +keysyms_arr_intersect(KeySym *arr1, KeySym *arr2, KeySym **dest) +{ + *dest = NULL; + if (!arr1) return 0; + if (!arr2) return 0; + + int arr1_size = arr_keysyms_size(arr1); + int arr2_size = arr_keysyms_size(arr2); + + int dest_size = MIN(arr1_size, arr2_size) + 1; + if (dest_size == 1) return 0; + + KeySym *intersect = (KeySym *)malloc(sizeof(KeySym)*dest_size); + memset(intersect, 0, sizeof(KeySym)*dest_size); + + int count = 0; + for (int i = 0; i < arr1_size; i++) + { + for (int j = 0; j < arr2_size; j++) + { + if (arr1[i] == arr2[j]) + { + KeySym keysym = arr1[i]; + intersect[count] = keysym; + count++; + } + } + } + *dest = intersect; + return count; +} + +/** + * @brief Print an error message each time the same KeySym is found in 2 different keybindings settings + * + * @param config_path filename of the user's config file, where the setting is written + * @param arr1_str the name of the 1st config setting + * @param arr1 the 1st input array of KeySyms + * @param arr2 the 2nd input array of KeySyms + * @param arr2_str name of the 2nd config setting + * @return true if any keybindings conflicts were found + */ +static inline bool +check_keybindings_conflict(const char *config_path, const char *arr1_str, KeySym *arr1, const char *arr2_str, KeySym *arr2) +{ + if (!arr1) return false; + if (!arr2) return false; + + KeySym *conflicts = NULL; + int num_conflicts = keysyms_arr_intersect(arr1, arr2, &conflicts); + + if (num_conflicts) + { + for (int i = 0; i < num_conflicts; i++) + { + KeySym keysym = conflicts[i]; + printfef("(): %s: [bindings] Conflict detected. Remove the duplicate setting. Keybinding: '%s' found in both '%s' and '%s'.", config_path, XKeysymToString(keysym), arr1_str, arr2_str); + // fprintf(stdout, "%s (0x%02lx)\n", XKeysymToString(keysym), keysym); + // fputs("\n", stdout); + } + free(conflicts); + return true; + } + return false; +} + +#define report_key(ev) \ + printfef("(): Key %u (%s) occured.", (ev)->xkey.keycode, \ + ev_key_str(&(ev)->xkey)) + #define report_key_ignored(ev) \ printfef("(): KeyRelease %u (%s) ignored.", (ev)->xkey.keycode, \ ev_key_str(&(ev)->xkey)) @@ -717,6 +1083,221 @@ ev_key_str(XKeyEvent *ev) { printfef("(): KeyRelease %u (%s) not binded to anything.", \ (ev)->xkey.keycode, ev_key_str(&(ev)->xkey)) + +/** + * @brief Checks if a key event matches particular key and modifier combination. + */ +static inline bool +ev_key_modifier(XKeyEvent *ev, int key_modifier) +{ + return ev->state & key_modifier; +} + +/** + * @brief A static lookup table of enums for X modifier key masks declared in /usr/include/X11/X.h + */ +static const int ev_modifier_mask[] = \ +{ + ShiftMask, + LockMask, + ControlMask, + Mod1Mask, + Mod2Mask, + Mod3Mask, + Mod4Mask, + Mod5Mask, + Button1Mask, + Button2Mask, + Button3Mask, + Button4Mask, + Button5Mask, + AnyModifier, + 0x00 +}; + +/** + * @brief A static lookup table of strings for X modifier key masks declared in /usr/include/X11/X.h + */ +static const char *ev_modifier_mask_str[] = \ +{ + "ShiftMask", + "LockMask", + "ControlMask", + "Mod1Mask", + "Mod2Mask", + "Mod3Mask", + "Mod4Mask", + "Mod5Mask", + "Button1Mask", + "Button2Mask", + "Button3Mask", + "Button4Mask", + "Button5Mask", + "AnyModifier", + 0x00 +}; + +/** + * @brief Convert a modifier key mask (enum / bitmask) into a string representation + */ +static inline const char * +int_key_modifier_str(unsigned int key_modifier) +{ + if (!key_modifier) return NULL; + + int i = 0; + while (ev_modifier_mask[i]) + { + if (key_modifier == ev_modifier_mask[i]) + return ev_modifier_mask_str[i]; + i++; + } + return NULL; +} + +/** + * @brief Convert a string representation of a modifier key mask into an enum / bitmask + */ +static inline unsigned int +str_key_modifier_int(char *str) +{ + if (!str) return 0; + + int i = 0; + while (ev_modifier_mask_str[i]) + { + if (strcmp(str, ev_modifier_mask_str[i]) == 0) + return ev_modifier_mask[i]; + i++; + } + return 0x00; +} + +/** + * @brief Print an error message if a word in the string is not recognized as a valid X Modifier Key Mask + */ +static inline void +check_modmasks(const char *str_err_prefix1, const char *str_err_prefix2, const char *str_modkeymasks) +{ + // fputs("str_check_modkeymasks(const char *str_err_prefix1, const char *str_err_prefix2, const char *str_modkeymasks)\n", stdout); + if (!str_modkeymasks) return; + + int count = str_count_words(str_modkeymasks); + const char* next = str_modkeymasks; + + for (int i = 0; i < count; i++) + { + char *word = NULL; + next = str_get_word(next, &word); + + if (!word) + break; + + int modkeymask = str_key_modifier_int(word); + // fprintf(stdout, "%s %i (0x%02lx)\n", word, modkeymask, modkeymask); + + if (!modkeymask) + printfef("(): %s%s \"%s\" not recognized as a Modifier Key Mask. See: /usr/include/X11/X.h", str_err_prefix1, str_err_prefix2, word); + + free(word); + } + // fputs("\n", stdout); +} + +/** + * @brief convert a string of words into an array modifier key bitmasks + * if a word in the string is not recognized as a valid modifier key bitmask + * then skip over it. Finally write 0x00 to the last array entry (+1) + * which denotes the end of the array of modifier key bitmasks + * + * @param s the string of words to parse / split / convert + * @param dest place to store pointer to the new array of modifier key bitmasks + * @return size of the array + */ +static inline int +modkeymasks_str_enums(const char *s, int** dest) +{ + // fputs("modkeymasks_str_enums(char *str, int** dest)\n", stdout); + *dest = NULL; + if (!s) return 0; + + int num_words = str_count_words(s); + if(num_words == 0) return 0; + + int *arr_modkeymasks = (int *)malloc(sizeof(int)*(num_words+1)); + memset(arr_modkeymasks, 0, sizeof(int)*(num_words+1)); + + int count = 0; + for (int i = 0; i < num_words; i++) + { + char *word = NULL; + + s = str_get_word(s, &word); + // s = str_get_word_alnum_(s, &word); + + if (!word) + break; + + int modkeymask = str_key_modifier_int(word); + // fprintf(stdout, "%s %i (0x%02lx)\n", word, modkeymask, modkeymask); + + // only increment the array counter if the modifier key mask is valid + if(modkeymask) + { + arr_modkeymasks[count] = modkeymask; + count++; + } + free(word); + + if (!s) + break; + } + *dest = arr_modkeymasks; + return count; +} + +/** + * @brief Check to see if there is a specific modifier key bitmask in an array of modifier key bitmasks + */ +static inline bool +arr_modkeymasks_includes(int *arr_modkeymasks, int modkeymask) +{ + // fputs("arr_keycodes_includes(KeyCode *arr_keycodes, KeyCode keycode)\n", stdout); + if (!arr_modkeymasks) return false; + if (!modkeymask) return false; + + int i = 0; + while (arr_modkeymasks[i] != 0x00) + { + if (arr_modkeymasks[i] & modkeymask) + return true; + i++; + } + + return false; +} + +/** + * @brief Print a log message if the keyboard event has a modifier key held down + */ +static inline int +report_key_modifiers(XKeyEvent *evk) +{ + // fputs("report_key_modifiers(XKeyEvent *evk)\n", stdout); + if (!evk) return 0; + + int result = 0; + int i = 0; + while (ev_modifier_mask[i]) + { + if (evk->state & ev_modifier_mask[i]) + result = printfef("(): Key modifier (%s) is held for key (%s).", ev_modifier_mask_str[i], ev_key_str(evk)); + i++; + } + // fputs("\n", stdout); + return result; +} + #include "img.h" #include "wm.h" #include "mainwin.h" From 4ca15bacb2618572f6844472ba3cf783fec696f3 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 20:39:54 +0100 Subject: [PATCH 011/205] keybindings: main commit. implements custom user keybindings --- CHANGELOG | 4 ++ README.md | 83 ++++++++++++++++++++++++++- skippy-xd.sample.rc | 17 +++++- src/clientwin.c | 135 ++++++++++++++++++++++++++++---------------- src/mainwin.c | 87 +++++++++++++++++++++++----- src/mainwin.h | 24 ++++++-- src/skippy.c | 42 ++++++++++---- src/skippy.h | 9 +++ 8 files changed, 321 insertions(+), 80 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6bab7a5..f16e37e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ Skippy-XD changelog +0.5.2~pre -- "Puzzlebox" (09 Sept 2018) ~/dreamcat4 + - Fully customizable keybindings, and documentation for configuring them + - Default keybindings settings made consistent with 'Alt-Tab' behaviour + 0.5.1~hg -- "No codename" (23 Dec 2011) - Correctly auto-detect 32 or 64-bit system and compile appropriately. - Removed X11-based hotkey activation code (skippy now displays once on diff --git a/README.md b/README.md index 5e1a7a7..9605235 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ libxrender-dev zlib1g-dev libxinerama-dev libxcomposite-dev libxdamage-dev libxf Now get the source, build and install: ```sh -git clone https://github.com/richardgv/skippy-xd.git +git clone https://github.com/dreamcat4/skippy-xd.git cd skippy-xd make make install @@ -86,13 +86,90 @@ skippy-xd-toggle /PATH/TO/YOUR/CONFIG ### Keyboard Shortcuts -Typically, it is helpful to set up keyboard shortcuts for skippy-xd. To get you started, here are some links: +There are 2 types of keyboard shortcuts. Global keyboard shortcuts, and the program's own keyboard shortcuts. + + +#### Global keyboard shortcuts + +Firstly, there are global keyboard shortcuts, to be configured for invoking / launching Skippy. How to setup a global keyboard shortcut depends entirely on your chosen window manager. So we cannot provide you with specific instructions in that regard. But here are some links for a few of them: * Xfce: http://wiki.xfce.org/faq#keyboard * Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse * Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file -A good method is to set `skippy-xd --start-daemon` to be run after login, and bind a key (like **SUPER_L** [windows key] or **F9**) to , `skippy-xd --toggle-window-picker`, or `skippy-xd-toggle`. +It is recommended (best way) to set `skippy-xd --start-daemon` to be run after login. By adding it to the Startup Applications of your window manager. Then you should bind `skippy-xd --toggle-window-picker`, or `skippy-xd-toggle` to your preferred global keyboard shortcut. For most people, that will be `Alt+Tab` or `Super+Tab`. + +Quite a few window managers already assign `Alt+Tab` (or `Super+Tab`) to something else. Like their own built-in Alt-Tab feature. So you might also need to figure out how to un-bind those pre-existing shortcuts, before you can re-assign them to Skippy-XD instead. + +#### Program Keyboard Shortcuts + +Once skippy is launched, it then has it's own set of keyboard shortcuts. These are fully configurable. You can specify your own values in your `skippy-xd.rc` configuration file. Should you need to override any of the defaults. To find the right key symbol names (keysyms) for regular keypress and/or key release events. For all the keybindings settings. Please use the program `xev` to probe for them. By typing / pressing the keys on your keyboard. Which is explained in the next section. + +The sample config file `skippy-xd.sample.rc` shows all the default keyboard shortcuts. They in the `[bindings]` section, at the bottom of the file. + +Normally, you will want them to be consistent with your chosen Global Keyboard Shortcut(s). As was described earlier (for invoking skippy). The default values have already been chosen to match program invocation via `Alt+Tab` and/or `Super+Tab`. This includes releasing the `Alt` key, or the `Super` key. Which will to select the currently highlighed item. As is consistent with `Alt-Tab` behaviour on other platforms. + +Along with the above Key Bindings, there finally also a setting for specifying certain modifier keys. Which will reverse the direction od Alt-Tabbing. These can only be one of the special modifiers listed below. Rather than just any arbitrary key. Normally this function is mapped to either `Shift` and/or the `Control` modifier key. So those are the default. For example `Shift+Alt+Tab` will make skippy cycle backwards through the open windows. Again, the default value is chosen to be consistent with the expected Alt-Tabbing behaviour, as it is on other platforms. + +However if you need to change it, then the masks which Skippy knows about / recognizes are listed near the bottom of `src/skippy.h` in a pair of lookup tables named `ev_modifier_mask` and `ev_modifier_mask_str`. Which were taken out from the original X windows header file `/usr/include/X11/X.h`. The current version of skippy knows about these X modifiers: + +```c +static const int ev_modifier_mask[] = // { ... holds the lookup values } + +static const char *ev_modifier_mask_str[] = \ +{ + "ShiftMask", + "LockMask", + "ControlMask", + "Mod1Mask", + "Mod2Mask", + "Mod3Mask", + "Mod4Mask", + "Mod5Mask", + "Button1Mask", + "Button2Mask", + "Button3Mask", + "Button4Mask", + "Button5Mask", + "AnyModifier", + 0x00 +}; +``` + +As it turns out, it's possible hold down a mouse button istead. As another type of modifier key. This is just to reverse the tabbing direction in skippy. If you wish to configure custom direction modifier(s), then you can just append them to the relevant setting `modifierKeyMasksReverseDirection`. Which is in the `[bindings]` section of your Skippy RC file. + +#### How to identify keysyms with xev + +Run the program `xev` in a terminal window. Then press the keys you are interested in. Observe the output. + +***Example:*** + +Here is the name of the keysym on my keyboard for the Right Alt key. It is `ISO_Level3_Shift`. But it may be different for your keyboard. + +```sh +KeyPress event, serial 38, synthetic NO, window 0x6000001, + root 0x1e7, subw 0x0, time 29447789, (159,-18), root:(311,152), + state 0x0, keycode 108 (keysym 0xfe03, ISO_Level3_Shift), same_screen YES, + XKeysymToKeycode returns keycode: 92 + XLookupString gives 0 bytes: + XmbLookupString gives 0 bytes: + XFilterEvent returns: False + +KeyRelease event, serial 38, synthetic NO, window 0x6000001, + root 0x1e7, subw 0x0, time 29447853, (159,-18), root:(311,152), + state 0x80, keycode 108 (keysym 0xfe03, ISO_Level3_Shift), same_screen YES, + XKeysymToKeycode returns keycode: 92 + XLookupString gives 0 bytes: + XFilterEvent returns: False +``` + +***Note 1:*** + +Key strings are case sensitive. So `alt_l` will not work - it will no match anything at all. You need to use the exact capitalization as it appears in the output from the `xev` program. For example `Alt_L` is a valid key name. + +***Note 2:*** + +Be sure to separate with ` ` spaces each keybinding in a given setting. Like `keysLeft = Left b a h B A H` for example. You cannot use commas `, ; :` or other special characters in the keybindings settings in the `[bindings]` section of the skippy rc file. Otherwise it won't work. ## Troubleshooting diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 6292615..713b8c8 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -31,11 +31,17 @@ # background = 500x400 tile right mid #FF0000 /home/richard/screenshots/256.png # background = orig mid mid #FF000080 # -# - Bindings in [bindings] section can bind to "no" (do nothing), "focus" +# - [bindings] for miwMouse[1,2,3] can bind to "no" (do nothing), "focus" # (focus to window), "iconify", "shade-ewmh" (toggle window shade state), # "close-icccm" (close window with ICCCM method), "close-ewmh" (close # window with EWMH method), or "destroy" (forcefully destroy the window). # +# - [bindings] key* = is a list of valid XWindows KeySym identifiers, case +# sensitive and seperated list. Run the program 'xev' to find them. +# +# - [bindings] modifierKeyMasks* = is a list of valid XWindows modifier key +# bitmask identifiers, as defined in the /usr/include/X11/X.h header file. +# [general] distance = 50 @@ -90,3 +96,12 @@ font = fixed-11:weight=bold miwMouse1 = focus miwMouse2 = close-ewmh miwMouse3 = iconify +keysUp = Up w +keysDown = Down s +keysLeft = Left b a +keysRight = Right Tab f d +keysExitCancelOnPress = Escape BackSpace x q +keysExitCancelOnRelease = +keysExitSelectOnPress = Return space +keysExitSelectOnRelease = Super_L Super_R Alt_L Alt_R ISO_Level3_Shift +modifierKeyMasksReverseDirection = ShiftMask ControlMask diff --git a/src/clientwin.c b/src/clientwin.c index 1b8ed96..0eba3b5 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -472,10 +472,94 @@ childwin_focus(ClientWin *cw) { int clientwin_handle(ClientWin *cw, XEvent *ev) { + // printfef("(): "); + + if (! cw) + return 1; + MainWin *mw = cw->mainwin; session_t *ps = mw->ps; + XKeyEvent * const evk = &ev->xkey; + + + if (ev->type == KeyPress) + { + report_key(ev); + report_key_modifiers(evk); + fputs("\n", stdout); + + bool reverse_direction = false; + + if (arr_modkeymasks_includes(cw->mainwin->modifierKeyMasks_ReverseDirection, evk->state)) + reverse_direction = true; + + if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) + { + if(reverse_direction) + focus_miniw_prev(ps, cw); + else + focus_miniw_next(ps, cw); + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_Left, evk->keycode)) + { + if(reverse_direction) + focus_miniw_next(ps, cw); + else + focus_miniw_prev(ps, cw); + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) + { + focus_down(cw); + } - if (ev->type == ButtonRelease) { + else if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) + { + focus_up(cw); + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) + { + printfef("(): Quitting."); + mw->client_to_focus = NULL; + return 1; + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnPress, evk->keycode)) + { + mw->client_to_focus = cw; + return 1; + } + } + else if (ev->type == KeyRelease) + { + // report_key(ev); + + report_key(ev); + report_key_modifiers(evk); + fputs("\n", stdout); + + if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode)) + { + mw->client_to_focus = cw; + return 1; + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnRelease, evk->keycode)) + { + printfef("(): Quitting."); + return 1; + } + } + + else if (ev->type == ButtonPress) { + cw->mainwin->pressed_mouse = true; + /* if (ev->xbutton.button == 1) + cw->mainwin->pressed = cw; */ + } + else if (ev->type == ButtonRelease) { + // printfef("(): else if (ev->type == ButtonRelease) {"); const unsigned button = ev->xbutton.button; if (cw->mainwin->pressed_mouse) { if (button < MAX_MOUSE_BUTTONS) { @@ -489,55 +573,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } else printfef("(): ButtonRelease %u ignored.", button); - } else if (ev->type == KeyRelease) { - XKeyEvent * const evk = &ev->xkey; - if (cw->mainwin->pressed_key) { - const keydef_t KEY_NEXT = { - .key = XKeysymToKeycode(ps->dpy, XK_Tab), - .mod = KEYMOD_CTRL, - }; - const keydef_t KEY_PREV = { - .key = XKeysymToKeycode(ps->dpy, XK_Tab), - .mod = KEYMOD_CTRL | KEYMOD_SHIFT, - }; - - if (evk->keycode == cw->mainwin->key_up || - evk->keycode == cw->mainwin->key_k) - focus_up(cw); - else if (evk->keycode == cw->mainwin->key_down || - evk->keycode == cw->mainwin->key_j) - focus_down(cw); - else if (evk->keycode == cw->mainwin->key_left || - evk->keycode == cw->mainwin->key_h) - focus_left(cw); - else if (evk->keycode == cw->mainwin->key_right || - evk->keycode == cw->mainwin->key_l) - focus_right(cw); - else if (evk->keycode == cw->mainwin->key_enter - || evk->keycode == cw->mainwin->key_space) { - mw->client_to_focus = cw; - return 1; - } - else if (ev_iskey(evk, &KEY_NEXT)) { - focus_miniw_next(ps, cw); - } - else if (ev_iskey(evk, &KEY_PREV)) { - focus_miniw_prev(ps, cw); - } - else - report_key_unbinded(ev); - } - else - report_key_ignored(ev); - } - else if (ev->type == ButtonPress) { - cw->mainwin->pressed_mouse = true; - /* if (ev->xbutton.button == 1) - cw->mainwin->pressed = cw; */ - } - else if (KeyPress == ev->type) { - cw->mainwin->pressed_key = true; } + else if (ev->type == FocusIn) { cw->focused = true; clientwin_render(cw); diff --git a/src/mainwin.c b/src/mainwin.c index 85f2bd1..ba3f632 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -91,19 +91,60 @@ mainwin_create(session_t *ps) { mw->pressed = mw->focus = 0; mw->tooltip = 0; mw->cod = 0; - mw->key_up = XKeysymToKeycode(dpy, XK_Up); - mw->key_down = XKeysymToKeycode(dpy, XK_Down); - mw->key_left = XKeysymToKeycode(dpy, XK_Left); - mw->key_right = XKeysymToKeycode(dpy, XK_Right); - mw->key_h = XKeysymToKeycode(dpy, XK_h); - mw->key_j = XKeysymToKeycode(dpy, XK_j); - mw->key_k = XKeysymToKeycode(dpy, XK_k); - mw->key_l = XKeysymToKeycode(dpy, XK_l); - mw->key_enter = XKeysymToKeycode(dpy, XK_Return); - mw->key_space = XKeysymToKeycode(dpy, XK_space); - mw->key_escape = XKeysymToKeycode(dpy, XK_Escape); - mw->key_q = XKeysymToKeycode(dpy, XK_q); - + + // convert the keybindings settings strings into arrays of KeySyms + keys_str_syms(ps->o.bindings_keysUp, &mw->keysyms_Up); + keys_str_syms(ps->o.bindings_keysDown, &mw->keysyms_Down); + keys_str_syms(ps->o.bindings_keysLeft, &mw->keysyms_Left); + keys_str_syms(ps->o.bindings_keysRight, &mw->keysyms_Right); + keys_str_syms(ps->o.bindings_keysExitCancelOnPress, &mw->keysyms_ExitCancelOnPress); + keys_str_syms(ps->o.bindings_keysExitCancelOnRelease, &mw->keysyms_ExitCancelOnRelease); + keys_str_syms(ps->o.bindings_keysExitSelectOnPress, &mw->keysyms_ExitSelectOnPress); + keys_str_syms(ps->o.bindings_keysExitSelectOnRelease, &mw->keysyms_ExitSelectOnRelease); + + // convert the modifier key masks settings strings into arrays of enums + modkeymasks_str_enums(ps->o.bindings_modifierKeyMasksReverseDirection, &mw->modifierKeyMasks_ReverseDirection); + + // convert the arrays of KeySyms into arrays of KeyCodes, for this specific Display + keysyms_arr_keycodes(dpy, mw->keysyms_Up, &mw->keycodes_Up); + keysyms_arr_keycodes(dpy, mw->keysyms_Down, &mw->keycodes_Down); + keysyms_arr_keycodes(dpy, mw->keysyms_Left, &mw->keycodes_Left); + keysyms_arr_keycodes(dpy, mw->keysyms_Right, &mw->keycodes_Right); + keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnPress, &mw->keycodes_ExitCancelOnPress); + keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnRelease, &mw->keycodes_ExitCancelOnRelease); + keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnPress, &mw->keycodes_ExitSelectOnPress); + keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnRelease, &mw->keycodes_ExitSelectOnRelease); + + // we check all possible pairs, one pair at a time. This is in a specific order, to give a more helpful error msg + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysDown", mw->keysyms_Down); + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysLeft", mw->keysyms_Left); + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysRight", mw->keysyms_Right); + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysDown", mw->keysyms_Down, "keysLeft", mw->keysyms_Left); + check_keybindings_conflict(ps->o.config_path, "keysDown", mw->keysyms_Down, "keysRight", mw->keysyms_Right); + check_keybindings_conflict(ps->o.config_path, "keysDown", mw->keysyms_Down, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysDown", mw->keysyms_Down, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysDown", mw->keysyms_Down, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysDown", mw->keysyms_Down, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysRight", mw->keysyms_Right); + check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + XGetWindowAttributes(dpy, ps->root, &rootattr); mw->x = mw->y = 0; mw->width = rootattr.width; @@ -354,6 +395,26 @@ mainwin_destroy(MainWin *mw) { XFree(mw->xin_info); #endif /* CFG_XINERAMA */ + free(mw->keysyms_Up); + free(mw->keysyms_Down); + free(mw->keysyms_Left); + free(mw->keysyms_Right); + free(mw->keysyms_ExitCancelOnPress); + free(mw->keysyms_ExitCancelOnRelease); + free(mw->keysyms_ExitSelectOnPress); + free(mw->keysyms_ExitSelectOnRelease); + + free(mw->modifierKeyMasks_ReverseDirection); + + free(mw->keycodes_Up); + free(mw->keycodes_Down); + free(mw->keycodes_Left); + free(mw->keycodes_Right); + free(mw->keycodes_ExitCancelOnPress); + free(mw->keycodes_ExitCancelOnRelease); + free(mw->keycodes_ExitSelectOnPress); + free(mw->keycodes_ExitSelectOnRelease); + free(mw); } diff --git a/src/mainwin.h b/src/mainwin.h index a022edd..70ec70d 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -51,10 +51,26 @@ struct _mainwin_t { dlist *cod; struct _Tooltip *tooltip; - KeyCode key_act, key_up, key_down, key_left, key_right, - key_h, key_j, key_k, key_l, - key_enter, key_space, key_q, key_escape; - + KeySym *keysyms_Up; + KeySym *keysyms_Down; + KeySym *keysyms_Left; + KeySym *keysyms_Right; + KeySym *keysyms_ExitCancelOnPress; + KeySym *keysyms_ExitCancelOnRelease; + KeySym *keysyms_ExitSelectOnPress; + KeySym *keysyms_ExitSelectOnRelease; + + int *modifierKeyMasks_ReverseDirection; + + KeyCode *keycodes_Up; + KeyCode *keycodes_Down; + KeyCode *keycodes_Left; + KeyCode *keycodes_Right; + KeyCode *keycodes_ExitCancelOnPress; + KeyCode *keycodes_ExitCancelOnRelease; + KeyCode *keycodes_ExitSelectOnPress; + KeyCode *keycodes_ExitSelectOnRelease; + #ifdef CFG_XINERAMA int xin_screens; XineramaScreenInfo *xin_info, *xin_active; diff --git a/src/skippy.c b/src/skippy.c index a2d37da..f7a4b30 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -728,16 +728,6 @@ mainloop(session_t *ps, bool activate_on_start) { } } - else if (KeyRelease == ev.type && (mw->key_q == ev.xkey.keycode - || mw->key_escape == ev.xkey.keycode)) { - if (mw->pressed_key) { - die = true; - if (mw->key_escape == ev.xkey.keycode) - refocus = true; - } - else - report_key_ignored(&ev); - } else if (wid == mw->window) die = mainwin_handle(mw, &ev); else if (PropertyNotify == ev.type) { @@ -1206,6 +1196,29 @@ int main(int argc, char *argv[]) { ps->o.tooltip_text = mstrdup(config_get(config, "tooltip", "text", "#e0e0e0")); ps->o.tooltip_textShadow = mstrdup(config_get(config, "tooltip", "textShadow", "black")); ps->o.tooltip_font = mstrdup(config_get(config, "tooltip", "font", "fixed-11:weight=bold")); + + // load keybindings settings + ps->o.bindings_keysUp = mstrdup(config_get(config, "bindings", "keysUp", "Up w")); + ps->o.bindings_keysDown = mstrdup(config_get(config, "bindings", "keysDown", "Down s")); + ps->o.bindings_keysLeft = mstrdup(config_get(config, "bindings", "keysLeft", "Left b a")); + ps->o.bindings_keysRight = mstrdup(config_get(config, "bindings", "keysRight", "Right Tab f d")); + ps->o.bindings_keysExitCancelOnPress = mstrdup(config_get(config, "bindings", "keysExitOnPress", "Escape BackSpace x q")); + ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitOnRelease", "")); + ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitOnPress", "Return space")); + ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); + ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); + + // print an error message for any key bindings that aren't recognized + check_keysyms(ps->o.config_path, ": [bindings] keysUp =", ps->o.bindings_keysUp); + check_keysyms(ps->o.config_path, ": [bindings] keysDown =", ps->o.bindings_keysDown); + check_keysyms(ps->o.config_path, ": [bindings] keysLeft =", ps->o.bindings_keysLeft); + check_keysyms(ps->o.config_path, ": [bindings] keysRight =", ps->o.bindings_keysRight); + check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnPress =", ps->o.bindings_keysExitCancelOnPress); + check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); + check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); + check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnRelease =", ps->o.bindings_keysExitSelectOnRelease); + check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); + if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) @@ -1392,6 +1405,15 @@ int main(int argc, char *argv[]) { free_pictw(ps, &ps->o.iconDefault); free_pictspec(ps, &ps->o.iconFillSpec); free_pictspec(ps, &ps->o.fillSpec); + free(ps->o.bindings_keysUp); + free(ps->o.bindings_keysDown); + free(ps->o.bindings_keysLeft); + free(ps->o.bindings_keysRight); + free(ps->o.bindings_keysExitCancelOnPress); + free(ps->o.bindings_keysExitCancelOnRelease); + free(ps->o.bindings_keysExitSelectOnPress); + free(ps->o.bindings_keysExitSelectOnRelease); + free(ps->o.bindings_modifierKeyMasksReverseDirection); } if (ps->fd_pipe >= 0) diff --git a/src/skippy.h b/src/skippy.h index 1eac5f3..4195691 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -253,6 +253,15 @@ typedef struct { char *tooltip_font; enum cliop bindings_miwMouse[MAX_MOUSE_BUTTONS]; + char *bindings_keysUp; + char *bindings_keysDown; + char *bindings_keysLeft; + char *bindings_keysRight; + char *bindings_keysExitCancelOnPress; + char *bindings_keysExitCancelOnRelease; + char *bindings_keysExitSelectOnPress; + char *bindings_keysExitSelectOnRelease; + char *bindings_modifierKeyMasksReverseDirection; } options_t; #define OPTIONST_INIT { \ From ae6fab2b544ff65f39af0a893eda1c6ef4ad708d Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 20:46:01 +0100 Subject: [PATCH 012/205] makefile: multiple improvements, and other developer features. see CHANGELOG --- .valgrind.suppressions | 671 +++++++++++++++++++++++++++++++++++++++++ CHANGELOG | 6 + Makefile | 23 +- README.md | 12 + src/skippy.c | 32 +- 5 files changed, 740 insertions(+), 4 deletions(-) create mode 100644 .valgrind.suppressions diff --git a/.valgrind.suppressions b/.valgrind.suppressions new file mode 100644 index 0000000..d11fb62 --- /dev/null +++ b/.valgrind.suppressions @@ -0,0 +1,671 @@ +# ============================================ +# valgrind - usage instructions +# ============================================ +# +# +# First compile skippy-xd, then launch the executable, and do a test run through valgrind. Something like this: +# +# make && valgrind --suppressions=.valgrind.suppressions --leak-check=full ./skippy-xd +# +# +# +# To generate a supression rule, to ignore, then add it to this file: +# +# make && valgrind --suppressions=.valgrind.suppressions --gen-suppressions=all --leak-check=full ./skippy-xd +# +# +# + + + + + +# ============================================ +# skippy-xd supression rules + +{ + Because of char* XKeysymToString(), is in some static table of constants, somewhere in Xlib + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:check_keybindings_conflict + fun:mainwin_create + fun:main +} + + + + + + + + +# ============================================ +# Suppressions file from webkit project + + +# There are three kinds of suppressions in this file. +# 1. Third party leaks we have no control over. +# +# 2. Intentional unit test errors, false positives +# in our own code, or leaks that are so trivial they are not worth fixing. +# +# 3. Suppressions for real WebKit bugs that are not yet fixed. +# These should all be in webkit's bug tracking system +# Periodically we should sweep this file and the bug tracker clean by +# running overnight and removing outdated bugs/suppressions. +#----------------------------------------------------------------------- + +# 1. Third party leaks we have no control over. +{ + # GTK developers don't like cleaning up one-time leaks. + # See http://mail.gnome.org/archives/gtk-devel-list/2004-April/msg00230.html. + gtk_init_check (Third Party) + Memcheck:Leak + ... + fun:gtk_init_check +} + +{ + FcConfigParseAndLoad (Third Party) + Memcheck:Leak + ... + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad +} + +{ + FcConfigAppFontAddFile (Third Party) + Memcheck:Leak + ... + fun:FcConfigAppFontAddFile +} + +{ + # See also http://www.gnome.org/~johan/gtk.suppression + # (which has a smattering of similar pango suppressions). + FcFontRenderPrepare 1 (Third Party) + Memcheck:Leak + ... + fun:FcFontRenderPrepare + obj:* + fun:pango_font_map_load_fontset +} + +{ + FcFontRenderPrepare 2 (Third Party) + Memcheck:Leak + ... + fun:FcFontRenderPrepare + ... + fun:pango_itemize_with_base_dir +} + +{ + FcFontRenderPrepare 3 (Third Party) + Memcheck:Leak + ... + fun:FcFontRenderPrepare + ... + fun:pango_ot_buffer_output +} + +{ + FcFontRenderPrepare 4 (Third Party) + Memcheck:Leak + ... + fun:FcFontRenderPrepare + ... + fun:pango_context_get_metrics +} + +{ + FcDefaultSubstitute (Third Party) + Memcheck:Leak + ... + fun:FcDefaultSubstitute + ... + fun:pango_itemize_with_base_dir +} + +{ + # Reported in https://bugs.freedesktop.org/show_bug.cgi?id=8215. + FcPatternObjectInsertElt 1 (Third Party) + Memcheck:Leak + fun:malloc + fun:FcPatternObjectInsertElt + fun:FcPatternObjectAddWithBinding +} + +{ + # See https://bugs.freedesktop.org/show_bug.cgi?id=8428. + # and http://www.gnome.org/~johan/gtk.suppression. + FcPatternObjectInsertElt 2 (Third Party) + Memcheck:Leak + ... + fun:realloc + fun:FcPatternObjectInsertElt +} + +{ + FcConfigValues (Third Party) + Memcheck:Leak + ... + fun:malloc + fun:FcConfigValues + fun:FcConfigValues + ... + fun:FcConfigValues + fun:FcConfigValues +} + +{ + FcCharSetSort (Third Party) + Memcheck:Leak + ... + fun:FcFontSetSort + fun:FcFontSort +} + +{ + FcCharSetAddChar (Third Party) + Memcheck:Leak + ... + fun:FcCharSetFindLeafCreate + fun:FcCharSetAddChar +} + +{ + pango_script_get_sample_language (Third Party) + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:pango_script_get_sample_language + ... + fun:pango_font_get_metrics +} + +{ + # See http://sourceware.org/bugzilla/show_bug.cgi?id=12878. + dlopen (Third Party) + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 +} + +{ + # See also http://sources.redhat.com/bugzilla/show_bug.cgi?id=2451. + _dl_map_object_from_fd (Third Party) + Memcheck:Leak + fun:malloc + fun:_dl_map_object_from_fd +} + +{ + # See http://sources.redhat.com/bugzilla/show_bug.cgi?id=5171 + pthread_create (Third Party) + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +{ + # See http://sourceware.org/bugzilla/show_bug.cgi?id=14015. + dlsym (Third Party) + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlsym +} + +{ + g_object_add_weak_pointer (Third Party) + Memcheck:Leak + ... + fun:g_object_weak_ref + fun:g_object_add_weak_pointer +} + +{ + g_build_filename (Third Party) + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_string_maybe_expand + fun:g_string_insert_len + fun:g_build_path_va + fun:g_build_filename + fun:_ZL15initializeFontsPKc +} + +{ + gtk_im_context_set_client_window (Third Party) + Memcheck:Leak + ... + fun:malloc + fun:g_malloc + fun:g_strdup + fun:gtk_im_multicontext_get_slave + fun:gtk_im_multicontext_set_client_window + fun:gtk_im_context_set_client_window +} + +{ + gtk_css_provider_load_from_data (Third Party) + Memcheck:Leak + fun:realloc + fun:g_realloc + fun:g_string_maybe_expand + fun:g_string_insert_c + fun:_gtk_css_parser_read_char + fun:_gtk_css_parser_try_ident + fun:bindings_value_parse_one + fun:_gtk_css_array_value_parse + fun:gtk_css_provider_load_internal + fun:gtk_css_provider_load_from_data +} + +{ + # GTK leaks an X11 window. + gdk_x11_drawable_get_xid (Third Party) + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:g_type_create_instance + fun:g_object_constructor + fun:g_object_newv + fun:g_object_new + fun:_gdk_window_impl_new + fun:gdk_window_ensure_native + fun:gdk_x11_drawable_get_xid +} + +{ + # GTK leaks a cairo context (large leak) + gtk_window_realize (Third Party) + Memcheck:Leak + fun:malloc + fun:_cairo_default_context_create + fun:set_grip_shape + fun:resize_grip_create_window + fun:gtk_window_realize +} + +{ + g_quark_from_static_string (Third party) + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_quark_from_static_string + fun:gobject_init_ctor + fun:call_init.part.0 + fun:_dl_init + obj:/lib/x86_64-linux-gnu/ld-2.15.so + obj:* + obj:* + obj:* +} + +{ + /bin/bash (Third Party) + Memcheck:Leak + ... + obj:/bin/bash +} + +{ + libenchant.so new (Third party) + Memcheck:Leak + fun:_Znw* + ... + obj:*/libenchant.so.1.6.0 + fun:enchant_broker_dict_exists +} + +{ + libenchant.so malloc (Third party) + Memcheck:Leak + fun:*alloc + ... + obj:*/libenchant.so.1.6.0 + fun:enchant_broker_dict_exists +} + +{ + # Cairo leaks a pattern_t* in cairo_set_source_surface + cairo_set_source_surface (Third Party) + Memcheck:Leak + fun:malloc + fun:cairo_pattern_create_for_surface + fun:_cairo_default_context_set_source_surface + fun:cairo_set_source_surface +} + +{ + XRRFindDisplay (Third Party) + Memcheck:Leak + fun:malloc + fun:XRRFindDisplay +} +{ + libflashplayer.so (Third Party) + Memcheck:Leak + ... + obj:/usr/lib/flashplugin-installer/libflashplayer.so +} + +{ + gdk_init (Third Party) + Memcheck:Leak + fun:malloc + ... + fun:_nl_find_domain + fun:__dcigettext + fun:gdk_screen_class_intern_init + fun:g_type_class_ref + fun:g_type_class_ref + fun:g_object_newv + fun:g_object_new + fun:_gdk_x11_screen_new + fun:gdk_display_open + fun:gdk_display_open_default_libgtk_only + fun:gdk_init_check + fun:gdk_init +} + +{ + XKeysymToString (Third Party) + Memcheck:Leak + fun:malloc + fun:XKeysymToString +} + +{ + g_thread_proxy (Third Party) + Memcheck:Leak + fun:*alloc + ... + fun:g_thread_proxy +} + +{ + JNI_CreateJavaVM (Third party) + Memcheck:Leak + ... + fun:JNI_CreateJavaVM + fun:JavaMain +} + +{ + _ZL10java_startP6Thread (Third party) + Memcheck:Leak + ... + fun:_ZN8VMThread3runEv + fun:_ZL10java_startP6Thread + ... + +} + +{ + /bin/java (OpenJDK) (Third party) + Memcheck:Leak + ... + obj:/usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java + ... +} + +{ + libGL.so (Third party) + Memcheck:Leak + ... + obj:*/libGL.so.* + ... +} + +{ + _cairo_xlib_shm_surface_create.isra.11 (Third Party) + Memcheck:Leak + fun:malloc + fun:_pixman_image_allocate + fun:pixman_image_create_bits + fun:_cairo_xlib_shm_surface_create.isra.11 +} + +{ + __nss_database_lookup (Third Party) + Memcheck:Leak + fun:malloc + fun:nss_parse_service_list + fun:__nss_database_lookup + obj:* +} + +{ + gst_init_check (Third Party) + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_intern_string + fun:_priv_gst_registry_chunks_load_plugin + fun:exchange_packets + fun:plugin_loader_load + fun:gst_registry_scan_plugin_file + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_internal + fun:gst_update_registry + fun:init_post + fun:g_option_context_parse + fun:gst_init_check + +} + +{ + g_task_run_in_thread (Third Party) + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:g_system_thread_new + fun:g_thread_new_internal + fun:g_thread_pool_start_thread + fun:g_thread_pool_push + fun:g_task_start_task_thread + fun:g_task_run_in_thread +} + +{ + # Large leak in cairo_image_surface_create + _cairo_image_surface_create_with_pixman_format (Third Party) + Memcheck:Leak + fun:malloc + fun:_cairo_image_surface_create_for_pixman_image + fun:_cairo_image_surface_create_with_pixman_format + fun:_ZN7WebCore21copyCairoImageSurfaceEP14_cairo_surface +} + + +#----------------------------------------------------------------------- +# 2. Intentional unit test errors, false positives +# in our own code, or leaks that are so trivial they are not worth fixing. + +{ + # According to dglazkov, these are one-time leaks and intentional. + # They may go away if the change to move these off the heap lands. + WebCore::SVGNames::init (Intentional) + Memcheck:Leak + ... + fun:_ZN7WebCore8SVGNames4initEv +} + +{ + # This is an on demand initialization which is done and then intentionally + # kept around (not freed) while the process is running. + WebCore::XMLNames::init (Intentional) + Memcheck:Leak + ... + fun:_ZN7WebCore8XMLNames4initEv +} + +{ + # This is WebKit wide theading initialization which is intentionally kept + # around (not freed) while the process is running. + WTF::ThreadIdentifierData::initialize() (Intentional) + Memcheck:Leak + ... + fun:_ZN3WTF20ThreadIdentifierData10initializeEj +} + +{ + # This is WebKit wide theading initialization which is intentionally kept + # around (not freed) while the process is running. + WTF::ThreadData (Intentional) + Memcheck:Leak + ... + fun:_ZN3WTF13wtfThreadDataEv +} + +{ + WTF::BitVector (Intentional) + Memcheck:Leak + fun:malloc + fun:_ZN3WTF10fastMallocEm + fun:_ZN3WTF9BitVector13OutOfLineBits6createEm + fun:_ZN3WTF9BitVector15resizeOutOfLineEm + fun:_ZN3WTF9BitVector10ensureSizeEm + fun:_ZN3WTF9BitVectorC1Em +} + +{ + # WTF::ThreadSpecific leaks a few bytes at a time. + WTF::ThreadSpecific::set() (Intentional) + Memcheck:Leak + fun:_Znw* + fun:_ZN3WTF14ThreadSpecificIbE3setEPb + fun:_ZN3WTF14ThreadSpecificIbEcvPbEv + fun:_ZN3WTF14ThreadSpecificIbEdeEv + fun:_ZN3WTF16registerGCThreadEv + fun:_ZN3JSC8GCThread12gcThreadMainEv + fun:_ZN3JSC8GCThread17gcThreadStartFuncEPv + fun:_ZN3WTFL16threadEntryPointEPv +} + +{ + # DOMObjectCache memory is not freed. + webkit_dom_document_get_default_view (Intentional) + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:_ZN6WebKit14DOMObjectCache3putEPvS1_ + fun:_ZL33webkit_dom_dom_window_constructormjP22_GObjectConstructParam + fun:g_object_newv + fun:g_object_new_valist + fun:g_object_new + fun:_ZN6WebKit13wrapDOMWindowEPN7WebCore9DOMWindowE + fun:webkit_dom_document_get_default_view + } + +#----------------------------------------------------------------------- +# 3. Suppressions for real webkit bugs that are not yet fixed. +# These should all be in webkit's bug tracking system (but a few aren't yet). + +{ + # AtkProperty is cached but not released (see https://bugs.webkit.org/show_bug.cgi?id=118567#c2). + cacheAndReturnAtkProperty + Memcheck:Leak + fun:malloc + fun:_ZN3WTF10fastMallocEm + fun:_ZN3WTF13CStringBuffer19createUninitializedEm + fun:_ZN3WTF7CString4initEPKcm + fun:_ZN3WTF7CStringC1EPKcm + fun:_ZNK3WTF6String4utf8ENS0_14ConversionModeE + fun:cacheAndReturnAtkProperty +} + +{ + # AtkRelationSet is never freed because the target AtkObject is + # cached. See https://bugs.webkit.org/show_bug.cgi?id=118567. + AccessibilityUIElement::title() + Memcheck:Leak + fun:malloc + ... + fun:g_object_weak_ref + fun:atk_relation_set_property + fun:g_object_newv + fun:g_object_new_valist + fun:g_object_new + fun:atk_relation_new + fun:atk_relation_set_add_relation_by_type + fun:_ZL31setAtkRelationSetFromCoreObjectPN7WebCore19AccessibilityObjectEP15_AtkRelationSet + fun:_ZL30webkitAccessibleRefRelationSetP10_AtkObject + fun:_ZN22AccessibilityUIElement14titleUIElementEv +} + +{ + # Leak in webkitAccessibleNew https://bugs.webkit.org/show_bug.cgi?id=118382 + webkitAccessibleNew + Memcheck:Leak + fun:*alloc + ... + fun:webkitAccessibleNew +} + +{ + # Leak ATK text https://bugs.webkit.org/show_bug.cgi?id=118385 + webkitAccessibleTextGetText + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:_ZL27webkitAccessibleTextGetTextP8_AtkTextii + fun:_ZL23webkitAccessibleGetNameP10_AtkObject +} + +{ + # Leak PluginObject in exceptional circumstances https://bugs.webkit.org/show_bug.cgi?id=118528 + WebCore::PluginView::start() + Memcheck:Leak + fun:malloc + fun:_ZL14pluginAllocateP4_NPPP7NPClass + fun:_NPN_CreateObject + fun:NPP_New + fun:_ZN7WebCore10PluginView5startEv +} + +{ + Memcheck:Leak + fun:malloc + fun:_ZN3WTF10fastMallocEm + fun:_ZN3WTF10fastStrDupEPKc + fun:_ZN7WebCore12TextCodecICU14registerCodecsEPFvPKcPFN3WTF10PassOwnPtrINS_9TextCodecEEERKNS_12TextEncodingEPKvESB_E +} + +{ + # DumpRenderTree WebKitWebView is leaked + webViewCreate + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_slist_prepend + fun:_ZL13webViewCreateP14_WebKitWebViewP15_WebKitWebFrame + fun:webkit_marshal_OBJECT__OBJECT + fun:g_closure_invoke + fun:signal_emit_unlocked_R + fun:g_signal_emit_valist + fun:g_signal_emit_by_name + fun:_ZN6WebKit12ChromeClient12createWindowEPN7WebCore5FrameERKNS1_16FrameLoadRequestERKNS1_14WindowFeaturesERKNS1_16NavigationActionE + fun:_ZNK7WebCore6Chrome12createWindowEPNS_5FrameERKNS_16FrameLoadRequestERKNS_14WindowFeaturesERKNS_16NavigationActionE + fun:_ZN7WebCore12createWindowEPNS_5FrameES1_RKNS_16FrameLoadRequestERKNS_14WindowFeaturesERb + fun:_ZN7WebCore9DOMWindow12createWindowERKN3WTF6StringERKNS1_12AtomicStringERKNS_14WindowFeaturesEPS0_PNS_5FrameESD_PFvSB_PvESE_ + fun:_ZN7WebCore9DOMWindow4openERKN3WTF6StringERKNS1_12AtomicStringES4_PS0_S8_ + fun:_ZN7WebCore11JSDOMWindow4openEPN3JSC9ExecStateE + fun:_ZN7WebCore32jsDOMWindowPrototypeFunctionOpenEPN3JSC9ExecStateE + } diff --git a/CHANGELOG b/CHANGELOG index f16e37e..2381855 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,12 @@ Skippy-XD changelog 0.5.2~pre -- "Puzzlebox" (09 Sept 2018) ~/dreamcat4 - Fully customizable keybindings, and documentation for configuring them - Default keybindings settings made consistent with 'Alt-Tab' behaviour + - Valgrind - added .valgrind.supressions file + - Makefile - prefer clang over gcc, if clang is present on the system + - Makefile - a slight improvment to the handling of compiler warnings + - Makefile - added 'install-check' build target, informational + - Version string - changed format, and now includes the version number + - Readme - new section for developers / maintainers / contributors 0.5.1~hg -- "No codename" (23 Dec 2011) - Correctly auto-detect 32 or 64-bit system and compile appropriately. diff --git a/Makefile b/Makefile index 89ee6b0..237e645 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,12 @@ PREFIX ?= /usr BINDIR ?= ${PREFIX}/bin -CC ?= gcc +ifeq ($(shell command -v clang 2>&1 | grep -c "clang"), 1) + CC = clang +else + CC ?= gcc +endif + CPPFLAGS += -std=c99 -Wall -I/usr/include/freetype2 SRCS_RAW = skippy wm dlist mainwin clientwin layout focus config tooltip img img-xlib @@ -33,6 +38,12 @@ endif ifeq "$(CFG_DEV)" "" CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 + + ifeq "$(CC)" "clang" + CPPFLAGS += -Wno-unused-function + else # gcc + CPPFLAGS += -Wno-unused-but-set-variable + endif else CC = clang CFLAGS += -ggdb -Wshadow -Weverything -Wno-unused-parameter -Wno-conversion -Wno-sign-conversion -Wno-gnu -Wno-disabled-macro-expansion -Wno-padded -Wno-c11-extensions -Wno-sign-compare -Wno-vla -Wno-cast-align @@ -47,8 +58,8 @@ INCS = $(shell pkg-config --cflags $(PACKAGES)) LIBS += -lm $(shell pkg-config --libs $(PACKAGES)) # === Version string === -SKIPPYXD_VERSION = "2015.12.21" -CPPFLAGS += -DSKIPPYXD_VERSION="\"${SKIPPYXD_VERSION}\"" +SKIPPYXD_VERSION = "v0.5.2~pre (2018.09.09) - \\\"Puzzlebox\\\" Edition" +CPPFLAGS += -DSKIPPYXD_VERSION=\"${SKIPPYXD_VERSION}\" # === Recipes === EXESUFFIX = @@ -68,6 +79,12 @@ skippy-xd${EXESUFFIX}: ${OBJS} clean: rm -f ${BINS} ${OBJS} src/.clang_complete +install-check: + @echo "'make install' target folders:" + @echo "PREFIX=${PREFIX} DESTDIR=${DESTDIR} BINDIR=${BINDIR}" + @echo "skippy executables will be installed into: ${DESTDIR}${BINDIR}" + @echo "skippy's config file will be installed to: ${DESTDIR}/etc/xdg/skippy-xd.rc" + install: ${BINS} skippy-xd.sample.rc install -d "${DESTDIR}${BINDIR}/" "${DESTDIR}/etc/xdg/" install -m 755 ${BINS} "${DESTDIR}${BINDIR}/" diff --git a/README.md b/README.md index 9605235..16133b0 100644 --- a/README.md +++ b/README.md @@ -192,3 +192,15 @@ skippy-xd-toggle /PATH/TO/YOUR/CONFIG * [Skippy-XD on Google Code](https://code.google.com/p/skippy-xd/) * [Original home of Skippy-XD](http://thegraveyard.org/skippy.html) * [Skippy-XD on freecode](http://freecode.com/projects/skippy) + +## Maintainership / Contributions + +The last 'stable maintiner' of this software was [richardgv](https://github.com/richardgv). And that is where the vast majority of Skippy issues are raised / the bug tracker is still on his [fork over there](https://github.com/richardgv/skippy-xd/issues). However at this time, it looks like Richard really does not have time anymore to continue to maintain this software anymore (since 2015). And neither do I as a matter of fact. + +This project is definately in need of a new maintainer. In the meantime, best thing we can do is to just fork based off the latest / most reaonable commits. And add whatever feature(s) or bugfixes ontop of that version. A top priority (very important) is not to be super-picky about this but: make safe changes to the code. Do not do anything that is *too risky* or over-extend yourself. Definately play on the safe side. Here are 3 basic safeguard mechanisms you can use in this project: + +1) Uncomment the `--test` developer test mode. And use it as a temporary sandbox to test any new library functions that you need to add. Throw bad input at all your new funtions. Specifically try to catch errors regarding the memory management. Bad pointers, not checking for null, etc. And when such a bug is found, try to use that as a reason for justifying a further scrutinyg / enhancement of your error handling, in your new code. Spend the vast majority of your developer time just writing the parts of the code that does the error handling. I estimate that I spend something like around 75% of my time doing that, and catching errors. With the remaining 25% of my time (or even less than that) on the actual 'doing stuff' new code that not library functinos. I.e. working in the existing skippy code paths / where I was actually trying to implement the new feature. That 'felt right' (for me) in C. Particularly because C has is no garbage collection / pointer safety, etc. And a large percentage of my bugs (perhaps about half of them!) were almost completely hidden to me, unless the code was actually exercised with bad input. In order to exercise those non-critical code paths. + +2) Run the program `valgrind` on the executable. To check for memory leaks. Try to exercise all of the code pathways that your change touches. To make sure nothing is missed. The results of `valgrind` should also help you to guage whether your error checking and code quality practices in step 1) were thorough enough (or not, in which case, go back to step 1). For those people who don't like valgrind, for the leak testing, then (on `clang` compiler) you can add some flags like `-fsanitize=address` to enable the clang address sanitizer. This will create a debug version of the binary. Note that: I have not tried that myself. It requires some further changes to skippy's `Makefile`... More information about how to setup the clang address sanitizer (aka `asan`), can be found [on this wiki page here](https://github.com/google/sanitizers/wiki/AddressSanitizer). + +3) Compile in developer mode. Which switches on all of the compiler warnings. There is a lot of noise / output. But you can save the output before and after. Then use the `diff` program to filter out and see which new warnings were due to your new code changes. Compile in dev mode like this: `make clean && CFG_DEV=true make`. Dev mode is also the way to produce a debug binary, with gdb symbols, etc. diff --git a/src/skippy.c b/src/skippy.c index f7a4b30..4d3b793 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -935,7 +935,7 @@ xerror(Display *dpy, XErrorEvent *ev) { static void show_help() { - fputs("skippy-xd (" SKIPPYXD_VERSION ")\n" + fputs("skippy-xd " SKIPPYXD_VERSION "\n" "Usage: skippy-xd [command]\n\n" "The available commands are:\n" " --config - Read the specified configuration file.\n" @@ -944,6 +944,7 @@ show_help() { " --activate-window-picker - tells the daemon to show the window picker.\n" " --deactivate-window-picker - tells the daemon to hide the window picker.\n" " --toggle-window-picker - tells the daemon to toggle the window picker.\n" + // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" " -S - Synchronize X operation (debugging).\n" @@ -953,6 +954,31 @@ show_help() { #endif } +// static void +// developer_tests() { +// fputs("skippy-xd (" SKIPPYXD_VERSION ")\n", stdout); +// fputs("Running: developer tests\n", stdout); +// fputs("\n", stdout); + +// char *str = "one two three four,five six!!!!"; +// fprintf(stdout, "testing str_count_words(), str=\"%s\"\n", str); + +// int num_words = str_count_words(str); +// fprintf(stdout, "num_words=%i\n", num_words); + +// fputs("done.\n", stdout); +// fputs("\n", stdout); + +// fputs("sleep(0.3);\n", stdout); +// usleep(0.3 *1000000); +// fputs("done.\n", stdout); + + +// fputs("\n", stdout); +// fputs("Finished. Exiting.\n" +// , stdout); +// } + static inline bool init_xexts(session_t *ps) { Display * const dpy = ps->dpy; @@ -1077,6 +1103,7 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "toggle-window-picker", no_argument, NULL, OPT_TOGGLE_PICKER }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, + // { "test", no_argument, NULL, 't' }, { NULL, no_argument, NULL, 0 } }; @@ -1092,6 +1119,9 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { ps->o.config_path = mstrdup(optarg); break; T_CASEBOOL('S', synchronize); + // case 't': + // developer_tests(); + // exit('t' == o ? RET_SUCCESS: RET_BADARG); case '?': case 'h': show_help(); From 2368949246df1b07876337257cd2d4255e58c714 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 20:51:24 +0100 Subject: [PATCH 013/205] dlist: improve the safety of dlist helper functions --- src/dlist.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/dlist.c b/src/dlist.c index 5e916cd..a4ffbc8 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -22,6 +22,9 @@ dlist * dlist_last(dlist *l) { + if (! l) + return NULL; + while(l && l->next) l = l->next; return l; @@ -70,7 +73,7 @@ dlist_remove(dlist *l) dlist *n = 0; if(! l) - return 0; + return NULL; if(l->prev) { n = l->prev; @@ -107,6 +110,9 @@ dlist_remove_nth_free_data(dlist *l, unsigned int n) int dlist_same(dlist *l1, dlist *l2) { + if (! l2) + return 0; + l1 = dlist_first(l1); while(l1) { if(l1 == l2) @@ -119,6 +125,9 @@ dlist_same(dlist *l1, dlist *l2) void dlist_reverse(dlist *l) { + if (! l) + return; + dlist *iter1 = dlist_first(l), *iter2 = dlist_last(l); @@ -134,6 +143,9 @@ dlist_reverse(dlist *l) dlist * dlist_free(dlist *l) { + if (! l) + return NULL; + l = dlist_first(l); while(l) { @@ -142,13 +154,16 @@ dlist_free(dlist *l) free(c); } - return 0; + return NULL; } dlist * dlist_dup(dlist *l) { - dlist *n = 0; + if (! l) + return NULL; + + dlist *n = NULL; l = dlist_first(l); while(l) { @@ -175,6 +190,12 @@ dlist_join(dlist *l, dlist *l2) { dlist * dlist_find_all(dlist *l, dlist_match_func match, void *data) { + if (! l) + return NULL; + + if (! data) + return NULL; + dlist *n = 0; l = dlist_first(l); @@ -190,6 +211,12 @@ dlist_find_all(dlist *l, dlist_match_func match, void *data) dlist * dlist_find(dlist *l, dlist_match_func func, void *data) { + if (! l) + return NULL; + + if (! data) + return NULL; + for(l = dlist_first(l); l; l = l->next) if(func(l, data)) break; @@ -231,7 +258,7 @@ dlist_free_with_data(dlist *l) free(c); } - return 0; + return NULL; } dlist * @@ -247,7 +274,7 @@ dlist_free_with_func(dlist *l, dlist_free_func func) free(c); } - return 0; + return NULL; } unsigned int @@ -280,6 +307,12 @@ dlist_nth(dlist *l, unsigned int n) void dlist_swap(dlist *l1, dlist *l2) { + if (! l1) + return; + + if (! l2) + return; + void *tmp = l1->data; l1->data = l2->data; l2->data = tmp; From 82ec50c847815615fd7f62ef7bf36f9bb1e0e143 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 20:56:44 +0100 Subject: [PATCH 014/205] wm: helper functions, to aid debugging of X Events --- src/skippy.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 4 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 4d3b793..3fbe4b5 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -32,6 +32,8 @@ enum pipe_cmd_t { PIPECMD_EXIT_RUNNING_DAEMON, PIPECMD_DEACTIVATE_WINDOW_PICKER, PIPECMD_TOGGLE_WINDOW_PICKER, + PIPECMD_QUEUE_FI_PREV, + PIPECMD_QUEUE_FI_NEXT, }; session_t *ps_g = NULL; @@ -309,6 +311,8 @@ parse_client_disp_mode(session_t *ps, const char *s) { static dlist * update_clients(MainWin *mw, dlist *clients, Bool *touched) { + // printfef("(): getting clients"); + dlist *stack = dlist_first(wm_get_stack(mw->ps)); clients = dlist_first(clients); @@ -316,6 +320,7 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { *touched = False; // Terminate clients that are no longer managed + // printfef("(): weeding dead clients"); for (dlist *iter = clients; iter; ) { ClientWin *cw = (ClientWin *) iter->data; if (dlist_find_data(stack, (void *) cw->src.window) @@ -334,6 +339,7 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { XFlush(mw->ps->dpy); // Add new clients + // printfef("(): adding new clients"); foreach_dlist (stack) { ClientWin *cw = (ClientWin *) dlist_find(clients, clientwin_cmp_func, iter->data); @@ -354,12 +360,15 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { static dlist * do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { + + printfef("(): "); session_t * const ps = mw->ps; long desktop = wm_get_current_desktop(ps); float factor; /* Update the client table, pick the ones we want and sort them */ + // printfef("(): updating dl list of clients"); clients = update_clients(mw, clients, 0); if (!clients) { printfef("(): No client windows found."); @@ -416,10 +425,50 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { // Get the currently focused window and select which mini-window to focus { dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) focus); + + // check if the user specified --prev or --next on the cmdline + if(ps->o.focus_initial) + { + + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; + + + if(ps->o.focus_initial == FI_PREV) + { + // here, mw->cod is the first (dlist*) item in the list + if (iter == mw->cod) + iter = dlist_last(mw->cod); + else + { + dlist *i = mw->cod; + for (; i != NULL; i = i->next) + if (i->next && i->next == iter) + break; + iter = i; + } + } + else if(ps->o.focus_initial == FI_NEXT) + iter = iter->next; + + } + + + // then clear this flag, so daemon not remember on its next activation + ps->o.focus_initial = 0; + if (!iter) iter = mw->cod; - mw->focus = (ClientWin *) iter->data; - mw->focus->focused = 1; + + // mw->focus = (ClientWin *) iter->data; + mw->client_to_focus = (ClientWin *) iter->data; + // mw->focus->focused = 1; + + + mw->client_to_focus->focused = 1; + // focus_miniw(ps, mw->client_to_focus); + } // Map the client windows @@ -428,7 +477,9 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { } // Unfortunately it does not work... - focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); + // focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); + focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); + // clientwin_render(mw->client_to_focus); return clients; } @@ -536,9 +587,16 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { static bool skippy_run_init(MainWin *mw, Window leader) { session_t *ps = mw->ps; + // printfef("(): "); + // printfef("(): "); // Do this window before main window gets mapped mw->revert_focus_win = wm_get_focused(ps); + // printfef("(): mainwin_update(mw);"); + + // printfef("(): "); + // printfef("(): sleep(3);"); + // sleep(3); // Update the main window's geometry (and Xinerama info if applicable) mainwin_update(mw); @@ -547,22 +605,35 @@ skippy_run_init(MainWin *mw, Window leader) { mw->xin_active = 0; #endif /* CFG_XINERAMA */ + // printfef("(): sleep(3) part 2;"); + // sleep(3); + // Map the main window and run our event loop if (ps->o.lazyTrans) { + // printfef("(if (ps->o.lazyTrans) {): "); + // printfef("(): mainwin_map(mw);"); mainwin_map(mw); XFlush(ps->dpy); } mw->client_to_focus = NULL; + // fputs("\n"); + // printfef("(): mw->clients = do_layout(mw, mw->clients, mw->revert_focus_win, leader);"); mw->clients = do_layout(mw, mw->clients, mw->revert_focus_win, leader); if (!mw->cod) { printfef("(): Failed to build layout."); return false; } + // printfef("(): sleep(3);"); + // sleep(3); + /* Map the main window and run our event loop */ if (!ps->o.lazyTrans) + // printfef("(): map here"); + // printfef("(): if (!ps->o.lazyTrans)"); + // printfef("(): mainwin_map(mw);"); mainwin_map(mw); XFlush(ps->dpy); @@ -618,9 +689,13 @@ mainloop(session_t *ps, bool activate_on_start) { // Activation goes first, so that it won't be delayed by poll() if (!mw && activate) { +printfef("(): if (!mw && activate) {"); + assert(ps->mainwin); activate = false; if (skippy_run_init(ps->mainwin, None)) { +printfef("(): if (skippy_run_init(ps->mainwin, None)) {"); +printfef("(): was in skippy_run_init"); last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; @@ -652,6 +727,8 @@ mainloop(session_t *ps, bool activate_on_start) { mw->cod = 0; if (refocus && mw->revert_focus_win) { + // printfef("(): if (refocus && mw->revert_focus_win) {"); + // printfef("(): wm_activate_window(ps, mw->revert_focus_win);"); // No idea why. Plain XSetInputFocus() no longer works after ungrabbing. wm_activate_window(ps, mw->revert_focus_win); refocus = false; @@ -684,13 +761,28 @@ mainloop(session_t *ps, bool activate_on_start) { const Window wid = ev_window(ps, &ev); if (MotionNotify == ev.type) { + + // the mouse has moved + // refocus enable + // mw->ignore_next_refocus = 0; + + // we also need to refocus here + if(mw->client_to_focus != mw->cw_tooltip) + { + focus_miniw(ps, mw->cw_tooltip); + clientwin_render(mw->client_to_focus); + } + + if (mw->tooltip && ps->o.tooltip_followsMouse) tooltip_move(mw->tooltip, ev.xmotion.x_root, ev.xmotion.y_root); } else if (ev.type == DestroyNotify || ev.type == UnmapNotify) { + // printfef("(): else if (ev.type == DestroyNotify || ev.type == UnmapNotify) {"); dlist *iter = (wid ? dlist_find(mw->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { + // printfef("(): if (iter) {"); ClientWin *cw = (ClientWin *) iter->data; if (DestroyNotify != ev.type) cw->mode = clientwin_get_disp_mode(ps, cw); @@ -707,6 +799,8 @@ mainloop(session_t *ps, bool activate_on_start) { } } else { + // printfef("(): else {"); + // printfef("(): do: clientwin_render(cw);"); free_pixmap(ps, &cw->cpixmap); free_picture(ps, &cw->origin); free_damage(ps, &cw->damage); @@ -722,7 +816,10 @@ mainloop(session_t *ps, bool activate_on_start) { pending_damage = true; if (iter) { if (!mw->poll_time) + { + // printfef("(): if (!mw->poll_time)"); clientwin_repair((ClientWin *)iter->data); + } else ((ClientWin *)iter->data)->damaged = true; } @@ -731,9 +828,17 @@ mainloop(session_t *ps, bool activate_on_start) { else if (wid == mw->window) die = mainwin_handle(mw, &ev); else if (PropertyNotify == ev.type) { + + // printfef("(): else if (PropertyNotify == ev.type) {"); + if (!ps->o.background && (ESETROOT_PMAP_ID == ev.xproperty.atom || _XROOTPMAP_ID == ev.xproperty.atom)) { + + // printfef("(): if (!ps->o.background && ..."); + // printfef("(): mainwin_update_background(mw);"); + // printfef("(): REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod);"); + mainwin_update_background(mw); REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod); } @@ -744,6 +849,9 @@ mainloop(session_t *ps, bool activate_on_start) { for (dlist *iter = mw->cod; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { +// printfef("(): die = clientwin_handle(cw, &ev);"); +if (!(POLLIN & r_fd[1].revents)) + // we handle key events in here die = clientwin_handle(cw, &ev); break; } @@ -758,7 +866,11 @@ mainloop(session_t *ps, bool activate_on_start) { pending_damage = false; foreach_dlist(mw->cod) { if (((ClientWin *) iter->data)->damaged) + { + // printfef("(): if (((ClientWin *) iter->data)->damaged)"); clientwin_repair(iter->data); + // fputs("\n", stdout); + } } last_rendered = now; } @@ -787,9 +899,62 @@ mainloop(session_t *ps, bool activate_on_start) { else { assert(1 == read_ret); printfdf("(): Received pipe command: %d", piped_input); + + // printfef("(): sleep(3);"); + // sleep(3); switch (piped_input) { + case PIPECMD_QUEUE_FI_PREV: + ps->o.focus_initial = FI_PREV; + // printfdf("(): Received focus initial: %i", ps->o.focus_initial); + // usleep(10000); // we must pause slightly, otherwise will miss next read() call in this loop() + break; + case PIPECMD_QUEUE_FI_NEXT: + ps->o.focus_initial = FI_NEXT; + // printfdf("(): Received focus initial: %i", ps->o.focus_initial); + // usleep(10000); // we must pause slightly, otherwise will miss next read() call in this loop() + break; case PIPECMD_ACTIVATE_WINDOW_PICKER: - activate = true; + printfef("(): case PIPECMD_ACTIVATE_WINDOW_PICKER:"); + if (ps->mainwin->mapped) + { + printfef("(): if (ps->mainwin->mapped)"); + fflush(stdout);fflush(stderr); + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; + + // There is a glitch whereby calling focus_miniw_prev() or focus_miniw_next() + // does not trigger an Xev to focus-out and un-highlight the focus of the + // 1st highlighted win, so we manually unfocus it here first, before moving on + // to focus and highlight the next window... it's probably because we miss the Xev + // since we are not in the right place in the main loop, cant unwind the call stack + mw->client_to_focus->focused = 0; + clientwin_render(mw->client_to_focus); + + if (ps->o.focus_initial == FI_PREV) + { + printfef("(): focus_miniw_prev(ps, mw->client_to_focus);"); + // focus_miniw_prev(ps, mw->focus); + focus_miniw_prev(ps, mw->client_to_focus); + // clientwin_render(mw->client_to_focus); + } + + else if (ps->o.focus_initial == FI_NEXT) + { + printfef("(): focus_miniw_next(ps, mw->client_to_focus);"); + // focus_miniw_next(ps, mw->focus); + focus_miniw_next(ps, mw->client_to_focus); + // clientwin_render(mw->client_to_focus); + } + clientwin_render(mw->client_to_focus); + + + } + else + { + printfef("(): activate = true;"); + activate = true; + } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: if (mw) @@ -840,6 +1005,18 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { return true; } +static inline bool +queue_initial_focus_prev(const char *pipePath) { + printfdf("(): Set initial focus to previous selection..."); + return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_PREV, pipePath); +} + +static inline bool +queue_initial_focus_next(const char *pipePath) { + printfdf("(): Set initial focus to next selection..."); + return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_NEXT, pipePath); +} + static inline bool activate_window_picker(const char *pipePath) { printfdf("(): Activating window picker..."); @@ -944,6 +1121,8 @@ show_help() { " --activate-window-picker - tells the daemon to show the window picker.\n" " --deactivate-window-picker - tells the daemon to hide the window picker.\n" " --toggle-window-picker - tells the daemon to toggle the window picker.\n" + " --prev - launch initially focussed to previous selection.\n" + " --next - launch initially focussed to next selection.\n" // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" @@ -1093,6 +1272,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { OPT_TOGGLE_PICKER, OPT_DM_START, OPT_DM_STOP, + OPT_PREV, + OPT_NEXT, }; static const char * opts_short = "hS"; static const struct option opts_long[] = { @@ -1103,6 +1284,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "toggle-window-picker", no_argument, NULL, OPT_TOGGLE_PICKER }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, + { "prev", no_argument, NULL, OPT_PREV }, + { "next", no_argument, NULL, OPT_NEXT }, // { "test", no_argument, NULL, 't' }, { NULL, no_argument, NULL, 0 } }; @@ -1118,6 +1301,14 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG: ps->o.config_path = mstrdup(optarg); break; + case OPT_PREV: + ps->o.focus_initial = FI_PREV; + fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + break; + case OPT_NEXT: + ps->o.focus_initial = FI_NEXT; + fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + break; T_CASEBOOL('S', synchronize); // case 't': // developer_tests(); @@ -1138,6 +1329,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { switch (o) { case 'S': break; case OPT_CONFIG: break; + case OPT_PREV: break; + case OPT_NEXT: break; case OPT_ACTV_PICKER: ps->o.mode = PROGMODE_ACTV_PICKER; break; @@ -1166,6 +1359,7 @@ int main(int argc, char *argv[]) { /* Set program locale */ setlocale (LC_ALL, ""); + // printfef("(): chirp a"); // Initialize session structure { @@ -1174,6 +1368,7 @@ int main(int argc, char *argv[]) { memcpy(ps, &SESSIONT_DEF, sizeof(session_t)); gettimeofday(&ps->time_start, NULL); } + // printfef("(): chirp b"); // First pass parse_args(ps, argc, argv, true); @@ -1196,11 +1391,14 @@ int main(int argc, char *argv[]) { ps->root = RootWindow(dpy, ps->screen); wm_get_atoms(ps); + // printfef("(): chirp c"); // Load configuration file { + // printfef("(): chirp d"); dlist *config = NULL; { + // printfef("(): chirp e"); bool user_specified_config = ps->o.config_path; if (!ps->o.config_path) ps->o.config_path = get_cfg_path(); @@ -1208,8 +1406,13 @@ int main(int argc, char *argv[]) { config = config_load(ps->o.config_path); else printfef("(): WARNING: No configuration file found."); + + // printfef("(): chirp f"); + if (!config && user_specified_config) return 1; + + // printfef("(): chirp g"); } char *lc_numeric_old = mstrdup(setlocale(LC_NUMERIC, NULL)); @@ -1336,10 +1539,15 @@ int main(int argc, char *argv[]) { free(lc_numeric_old); config_free(config); } + // printfef("(): chirp 0"); // Second pass parse_args(ps, argc, argv, false); + // fprintf(stdout, "after 2nd pass: ps->o.focus_initial = %i\n", ps->o.focus_initial); + // printfef("(): chirp 1"); + + const char* pipePath = ps->o.pipePath; // Handle special modes @@ -1347,12 +1555,33 @@ int main(int argc, char *argv[]) { case PROGMODE_NORMAL: break; case PROGMODE_ACTV_PICKER: + if(ps->o.focus_initial) + { + if(ps->o.focus_initial == FI_PREV) + queue_initial_focus_prev(pipePath); + + else if(ps->o.focus_initial == FI_NEXT) + queue_initial_focus_next(pipePath); + + // we must pause slightly, otherwise will miss next read() call in this loop() + usleep(1000); + } activate_window_picker(pipePath); goto main_end; case PROGMODE_DEACTV_PICKER: deactivate_window_picker(pipePath); goto main_end; case PROGMODE_TOGGLE_PICKER: + if(ps->o.focus_initial) + { + if(ps->o.focus_initial == FI_PREV) + queue_initial_focus_prev(pipePath); + else if(ps->o.focus_initial == FI_NEXT) + queue_initial_focus_next(pipePath); + + // we must pause slightly, otherwise will miss next read() call in this loop() + usleep(1000); + } toggle_window_picker(pipePath); goto main_end; case PROGMODE_DM_STOP: @@ -1364,6 +1593,7 @@ int main(int argc, char *argv[]) { /* ret = 1; goto main_end; */ } + // printfef("(): chirp 2"); // Main branch MainWin *mw = mainwin_create(ps); @@ -1373,6 +1603,7 @@ int main(int argc, char *argv[]) { goto main_end; } ps->mainwin = mw; + // printfef("(): chirp 3"); XSelectInput(ps->dpy, ps->root, PropertyChangeMask); From 2314d09a4ddd1d4710cca31b38eb95e219df60d2 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 20:57:12 +0100 Subject: [PATCH 015/205] suppress compiler warning --- src/layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout.c b/src/layout.c index 63a758a..7399a74 100644 --- a/src/layout.c +++ b/src/layout.c @@ -22,7 +22,7 @@ void layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { - session_t *ps = mw->ps; + // session_t *ps = mw->ps; int sum_w = 0, max_h = 0, max_w = 0; From 3807361622d126405da185f1a9e75581ca8a26c7 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 21:06:10 +0100 Subject: [PATCH 016/205] Revert "wm: helper functions, to aid debugging of X Events" This reverts commit 82ec50c847815615fd7f62ef7bf36f9bb1e0e143. --- src/skippy.c | 239 +-------------------------------------------------- 1 file changed, 4 insertions(+), 235 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 3fbe4b5..4d3b793 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -32,8 +32,6 @@ enum pipe_cmd_t { PIPECMD_EXIT_RUNNING_DAEMON, PIPECMD_DEACTIVATE_WINDOW_PICKER, PIPECMD_TOGGLE_WINDOW_PICKER, - PIPECMD_QUEUE_FI_PREV, - PIPECMD_QUEUE_FI_NEXT, }; session_t *ps_g = NULL; @@ -311,8 +309,6 @@ parse_client_disp_mode(session_t *ps, const char *s) { static dlist * update_clients(MainWin *mw, dlist *clients, Bool *touched) { - // printfef("(): getting clients"); - dlist *stack = dlist_first(wm_get_stack(mw->ps)); clients = dlist_first(clients); @@ -320,7 +316,6 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { *touched = False; // Terminate clients that are no longer managed - // printfef("(): weeding dead clients"); for (dlist *iter = clients; iter; ) { ClientWin *cw = (ClientWin *) iter->data; if (dlist_find_data(stack, (void *) cw->src.window) @@ -339,7 +334,6 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { XFlush(mw->ps->dpy); // Add new clients - // printfef("(): adding new clients"); foreach_dlist (stack) { ClientWin *cw = (ClientWin *) dlist_find(clients, clientwin_cmp_func, iter->data); @@ -360,15 +354,12 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { static dlist * do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { - - printfef("(): "); session_t * const ps = mw->ps; long desktop = wm_get_current_desktop(ps); float factor; /* Update the client table, pick the ones we want and sort them */ - // printfef("(): updating dl list of clients"); clients = update_clients(mw, clients, 0); if (!clients) { printfef("(): No client windows found."); @@ -425,50 +416,10 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { // Get the currently focused window and select which mini-window to focus { dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) focus); - - // check if the user specified --prev or --next on the cmdline - if(ps->o.focus_initial) - { - - // ps->mainwin->ignore_next_refocus = 1; - // ps->mainwin->ignore_next_refocus = 2; - // ps->mainwin->ignore_next_refocus = 4; - - - if(ps->o.focus_initial == FI_PREV) - { - // here, mw->cod is the first (dlist*) item in the list - if (iter == mw->cod) - iter = dlist_last(mw->cod); - else - { - dlist *i = mw->cod; - for (; i != NULL; i = i->next) - if (i->next && i->next == iter) - break; - iter = i; - } - } - else if(ps->o.focus_initial == FI_NEXT) - iter = iter->next; - - } - - - // then clear this flag, so daemon not remember on its next activation - ps->o.focus_initial = 0; - if (!iter) iter = mw->cod; - - // mw->focus = (ClientWin *) iter->data; - mw->client_to_focus = (ClientWin *) iter->data; - // mw->focus->focused = 1; - - - mw->client_to_focus->focused = 1; - // focus_miniw(ps, mw->client_to_focus); - + mw->focus = (ClientWin *) iter->data; + mw->focus->focused = 1; } // Map the client windows @@ -477,9 +428,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { } // Unfortunately it does not work... - // focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); - focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); - // clientwin_render(mw->client_to_focus); + focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); return clients; } @@ -587,16 +536,9 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { static bool skippy_run_init(MainWin *mw, Window leader) { session_t *ps = mw->ps; - // printfef("(): "); - // printfef("(): "); // Do this window before main window gets mapped mw->revert_focus_win = wm_get_focused(ps); - // printfef("(): mainwin_update(mw);"); - - // printfef("(): "); - // printfef("(): sleep(3);"); - // sleep(3); // Update the main window's geometry (and Xinerama info if applicable) mainwin_update(mw); @@ -605,35 +547,22 @@ skippy_run_init(MainWin *mw, Window leader) { mw->xin_active = 0; #endif /* CFG_XINERAMA */ - // printfef("(): sleep(3) part 2;"); - // sleep(3); - // Map the main window and run our event loop if (ps->o.lazyTrans) { - // printfef("(if (ps->o.lazyTrans) {): "); - // printfef("(): mainwin_map(mw);"); mainwin_map(mw); XFlush(ps->dpy); } mw->client_to_focus = NULL; - // fputs("\n"); - // printfef("(): mw->clients = do_layout(mw, mw->clients, mw->revert_focus_win, leader);"); mw->clients = do_layout(mw, mw->clients, mw->revert_focus_win, leader); if (!mw->cod) { printfef("(): Failed to build layout."); return false; } - // printfef("(): sleep(3);"); - // sleep(3); - /* Map the main window and run our event loop */ if (!ps->o.lazyTrans) - // printfef("(): map here"); - // printfef("(): if (!ps->o.lazyTrans)"); - // printfef("(): mainwin_map(mw);"); mainwin_map(mw); XFlush(ps->dpy); @@ -689,13 +618,9 @@ mainloop(session_t *ps, bool activate_on_start) { // Activation goes first, so that it won't be delayed by poll() if (!mw && activate) { -printfef("(): if (!mw && activate) {"); - assert(ps->mainwin); activate = false; if (skippy_run_init(ps->mainwin, None)) { -printfef("(): if (skippy_run_init(ps->mainwin, None)) {"); -printfef("(): was in skippy_run_init"); last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; @@ -727,8 +652,6 @@ printfef("(): was in skippy_run_init"); mw->cod = 0; if (refocus && mw->revert_focus_win) { - // printfef("(): if (refocus && mw->revert_focus_win) {"); - // printfef("(): wm_activate_window(ps, mw->revert_focus_win);"); // No idea why. Plain XSetInputFocus() no longer works after ungrabbing. wm_activate_window(ps, mw->revert_focus_win); refocus = false; @@ -761,28 +684,13 @@ printfef("(): was in skippy_run_init"); const Window wid = ev_window(ps, &ev); if (MotionNotify == ev.type) { - - // the mouse has moved - // refocus enable - // mw->ignore_next_refocus = 0; - - // we also need to refocus here - if(mw->client_to_focus != mw->cw_tooltip) - { - focus_miniw(ps, mw->cw_tooltip); - clientwin_render(mw->client_to_focus); - } - - if (mw->tooltip && ps->o.tooltip_followsMouse) tooltip_move(mw->tooltip, ev.xmotion.x_root, ev.xmotion.y_root); } else if (ev.type == DestroyNotify || ev.type == UnmapNotify) { - // printfef("(): else if (ev.type == DestroyNotify || ev.type == UnmapNotify) {"); dlist *iter = (wid ? dlist_find(mw->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { - // printfef("(): if (iter) {"); ClientWin *cw = (ClientWin *) iter->data; if (DestroyNotify != ev.type) cw->mode = clientwin_get_disp_mode(ps, cw); @@ -799,8 +707,6 @@ printfef("(): was in skippy_run_init"); } } else { - // printfef("(): else {"); - // printfef("(): do: clientwin_render(cw);"); free_pixmap(ps, &cw->cpixmap); free_picture(ps, &cw->origin); free_damage(ps, &cw->damage); @@ -816,10 +722,7 @@ printfef("(): was in skippy_run_init"); pending_damage = true; if (iter) { if (!mw->poll_time) - { - // printfef("(): if (!mw->poll_time)"); clientwin_repair((ClientWin *)iter->data); - } else ((ClientWin *)iter->data)->damaged = true; } @@ -828,17 +731,9 @@ printfef("(): was in skippy_run_init"); else if (wid == mw->window) die = mainwin_handle(mw, &ev); else if (PropertyNotify == ev.type) { - - // printfef("(): else if (PropertyNotify == ev.type) {"); - if (!ps->o.background && (ESETROOT_PMAP_ID == ev.xproperty.atom || _XROOTPMAP_ID == ev.xproperty.atom)) { - - // printfef("(): if (!ps->o.background && ..."); - // printfef("(): mainwin_update_background(mw);"); - // printfef("(): REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod);"); - mainwin_update_background(mw); REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod); } @@ -849,9 +744,6 @@ printfef("(): was in skippy_run_init"); for (dlist *iter = mw->cod; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { -// printfef("(): die = clientwin_handle(cw, &ev);"); -if (!(POLLIN & r_fd[1].revents)) - // we handle key events in here die = clientwin_handle(cw, &ev); break; } @@ -866,11 +758,7 @@ if (!(POLLIN & r_fd[1].revents)) pending_damage = false; foreach_dlist(mw->cod) { if (((ClientWin *) iter->data)->damaged) - { - // printfef("(): if (((ClientWin *) iter->data)->damaged)"); clientwin_repair(iter->data); - // fputs("\n", stdout); - } } last_rendered = now; } @@ -899,62 +787,9 @@ if (!(POLLIN & r_fd[1].revents)) else { assert(1 == read_ret); printfdf("(): Received pipe command: %d", piped_input); - - // printfef("(): sleep(3);"); - // sleep(3); switch (piped_input) { - case PIPECMD_QUEUE_FI_PREV: - ps->o.focus_initial = FI_PREV; - // printfdf("(): Received focus initial: %i", ps->o.focus_initial); - // usleep(10000); // we must pause slightly, otherwise will miss next read() call in this loop() - break; - case PIPECMD_QUEUE_FI_NEXT: - ps->o.focus_initial = FI_NEXT; - // printfdf("(): Received focus initial: %i", ps->o.focus_initial); - // usleep(10000); // we must pause slightly, otherwise will miss next read() call in this loop() - break; case PIPECMD_ACTIVATE_WINDOW_PICKER: - printfef("(): case PIPECMD_ACTIVATE_WINDOW_PICKER:"); - if (ps->mainwin->mapped) - { - printfef("(): if (ps->mainwin->mapped)"); - fflush(stdout);fflush(stderr); - // ps->mainwin->ignore_next_refocus = 1; - // ps->mainwin->ignore_next_refocus = 2; - // ps->mainwin->ignore_next_refocus = 4; - - // There is a glitch whereby calling focus_miniw_prev() or focus_miniw_next() - // does not trigger an Xev to focus-out and un-highlight the focus of the - // 1st highlighted win, so we manually unfocus it here first, before moving on - // to focus and highlight the next window... it's probably because we miss the Xev - // since we are not in the right place in the main loop, cant unwind the call stack - mw->client_to_focus->focused = 0; - clientwin_render(mw->client_to_focus); - - if (ps->o.focus_initial == FI_PREV) - { - printfef("(): focus_miniw_prev(ps, mw->client_to_focus);"); - // focus_miniw_prev(ps, mw->focus); - focus_miniw_prev(ps, mw->client_to_focus); - // clientwin_render(mw->client_to_focus); - } - - else if (ps->o.focus_initial == FI_NEXT) - { - printfef("(): focus_miniw_next(ps, mw->client_to_focus);"); - // focus_miniw_next(ps, mw->focus); - focus_miniw_next(ps, mw->client_to_focus); - // clientwin_render(mw->client_to_focus); - } - clientwin_render(mw->client_to_focus); - - - } - else - { - printfef("(): activate = true;"); - activate = true; - } + activate = true; break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: if (mw) @@ -1005,18 +840,6 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { return true; } -static inline bool -queue_initial_focus_prev(const char *pipePath) { - printfdf("(): Set initial focus to previous selection..."); - return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_PREV, pipePath); -} - -static inline bool -queue_initial_focus_next(const char *pipePath) { - printfdf("(): Set initial focus to next selection..."); - return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_NEXT, pipePath); -} - static inline bool activate_window_picker(const char *pipePath) { printfdf("(): Activating window picker..."); @@ -1121,8 +944,6 @@ show_help() { " --activate-window-picker - tells the daemon to show the window picker.\n" " --deactivate-window-picker - tells the daemon to hide the window picker.\n" " --toggle-window-picker - tells the daemon to toggle the window picker.\n" - " --prev - launch initially focussed to previous selection.\n" - " --next - launch initially focussed to next selection.\n" // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" @@ -1272,8 +1093,6 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { OPT_TOGGLE_PICKER, OPT_DM_START, OPT_DM_STOP, - OPT_PREV, - OPT_NEXT, }; static const char * opts_short = "hS"; static const struct option opts_long[] = { @@ -1284,8 +1103,6 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "toggle-window-picker", no_argument, NULL, OPT_TOGGLE_PICKER }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, - { "prev", no_argument, NULL, OPT_PREV }, - { "next", no_argument, NULL, OPT_NEXT }, // { "test", no_argument, NULL, 't' }, { NULL, no_argument, NULL, 0 } }; @@ -1301,14 +1118,6 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG: ps->o.config_path = mstrdup(optarg); break; - case OPT_PREV: - ps->o.focus_initial = FI_PREV; - fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); - break; - case OPT_NEXT: - ps->o.focus_initial = FI_NEXT; - fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); - break; T_CASEBOOL('S', synchronize); // case 't': // developer_tests(); @@ -1329,8 +1138,6 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { switch (o) { case 'S': break; case OPT_CONFIG: break; - case OPT_PREV: break; - case OPT_NEXT: break; case OPT_ACTV_PICKER: ps->o.mode = PROGMODE_ACTV_PICKER; break; @@ -1359,7 +1166,6 @@ int main(int argc, char *argv[]) { /* Set program locale */ setlocale (LC_ALL, ""); - // printfef("(): chirp a"); // Initialize session structure { @@ -1368,7 +1174,6 @@ int main(int argc, char *argv[]) { memcpy(ps, &SESSIONT_DEF, sizeof(session_t)); gettimeofday(&ps->time_start, NULL); } - // printfef("(): chirp b"); // First pass parse_args(ps, argc, argv, true); @@ -1391,14 +1196,11 @@ int main(int argc, char *argv[]) { ps->root = RootWindow(dpy, ps->screen); wm_get_atoms(ps); - // printfef("(): chirp c"); // Load configuration file { - // printfef("(): chirp d"); dlist *config = NULL; { - // printfef("(): chirp e"); bool user_specified_config = ps->o.config_path; if (!ps->o.config_path) ps->o.config_path = get_cfg_path(); @@ -1406,13 +1208,8 @@ int main(int argc, char *argv[]) { config = config_load(ps->o.config_path); else printfef("(): WARNING: No configuration file found."); - - // printfef("(): chirp f"); - if (!config && user_specified_config) return 1; - - // printfef("(): chirp g"); } char *lc_numeric_old = mstrdup(setlocale(LC_NUMERIC, NULL)); @@ -1539,15 +1336,10 @@ int main(int argc, char *argv[]) { free(lc_numeric_old); config_free(config); } - // printfef("(): chirp 0"); // Second pass parse_args(ps, argc, argv, false); - // fprintf(stdout, "after 2nd pass: ps->o.focus_initial = %i\n", ps->o.focus_initial); - // printfef("(): chirp 1"); - - const char* pipePath = ps->o.pipePath; // Handle special modes @@ -1555,33 +1347,12 @@ int main(int argc, char *argv[]) { case PROGMODE_NORMAL: break; case PROGMODE_ACTV_PICKER: - if(ps->o.focus_initial) - { - if(ps->o.focus_initial == FI_PREV) - queue_initial_focus_prev(pipePath); - - else if(ps->o.focus_initial == FI_NEXT) - queue_initial_focus_next(pipePath); - - // we must pause slightly, otherwise will miss next read() call in this loop() - usleep(1000); - } activate_window_picker(pipePath); goto main_end; case PROGMODE_DEACTV_PICKER: deactivate_window_picker(pipePath); goto main_end; case PROGMODE_TOGGLE_PICKER: - if(ps->o.focus_initial) - { - if(ps->o.focus_initial == FI_PREV) - queue_initial_focus_prev(pipePath); - else if(ps->o.focus_initial == FI_NEXT) - queue_initial_focus_next(pipePath); - - // we must pause slightly, otherwise will miss next read() call in this loop() - usleep(1000); - } toggle_window_picker(pipePath); goto main_end; case PROGMODE_DM_STOP: @@ -1593,7 +1364,6 @@ int main(int argc, char *argv[]) { /* ret = 1; goto main_end; */ } - // printfef("(): chirp 2"); // Main branch MainWin *mw = mainwin_create(ps); @@ -1603,7 +1373,6 @@ int main(int argc, char *argv[]) { goto main_end; } ps->mainwin = mw; - // printfef("(): chirp 3"); XSelectInput(ps->dpy, ps->root, PropertyChangeMask); From 1e741f4c9af56946e7368ba9a268bf837dbd050c Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 21:09:43 +0100 Subject: [PATCH 017/205] wm: helper functions, to aid debugging of X Events (commit fixed) --- src/focus.h | 37 +++++++++++++++++++++++++++++++++++++ src/tooltip.c | 3 +++ src/wm.c | 18 ++++++++++++++++++ src/wm.h | 1 + 4 files changed, 59 insertions(+) diff --git a/src/focus.h b/src/focus.h index 1f6c02b..f3492a7 100644 --- a/src/focus.h +++ b/src/focus.h @@ -20,6 +20,43 @@ #ifndef SKIPPY_FOCUS_H #define SKIPPY_FOCUS_H +static inline void +printfefXFocusChangeEvent(session_t *ps, XFocusChangeEvent *evf) +{ + printfefWindowName(ps, "(): event window = ", evf->window); + printfef("(): event window id = %#010lx", evf->window); + + if(evf->mode == NotifyNormal) + printfef("(): evf->mode = NotifyNormal"); + else if(evf->mode == NotifyGrab) + printfef("(): evf->mode = NotifyGrab"); + else if(evf->mode == NotifyUngrab) + printfef("(): evf->mode = NotifyUngrab"); + else if(evf->mode == NotifyWhileGrabbed) + printfef("(): evf->mode = NotifyWhileGrabbed"); + else + printfef("(): evf->mode = %i (not recognized)", evf->mode); + + if(evf->detail == NotifyAncestor) + printfef("(): evf->detail = NotifyAncestor"); + else if(evf->detail == NotifyVirtual) + printfef("(): evf->detail = NotifyVirtual"); + else if(evf->detail == NotifyInferior) + printfef("(): evf->detail = NotifyInferior"); + else if(evf->detail == NotifyNonlinear) + printfef("(): evf->detail = NotifyNonlinear"); + else if(evf->detail == NotifyNonlinearVirtual) + printfef("(): evf->detail = NotifyNonlinearVirtual"); + else if(evf->detail == NotifyPointer) + printfef("(): evf->detail = NotifyPointer"); + else if(evf->detail == NotifyPointerRoot) + printfef("(): evf->detail = NotifyPointerRoot"); + else if(evf->detail == NotifyDetailNone) + printfef("(): evf->detail = NotifyDetailNone"); + else + printfef("(): evf->detail = %i (not recognized)", evf->detail); +} + /** * @brief Focus the mini window of a client window. */ diff --git a/src/tooltip.c b/src/tooltip.c index b4490d2..dcb7e71 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -190,6 +190,9 @@ tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y) { + + // printfdf("(): x=%i y=%i",mouse_x,mouse_y); + session_t *ps = tt->mainwin->ps; int x = ps->o.tooltip_offsetX, y = ps->o.tooltip_offsetY; if (ps->o.tooltip_followsMouse) { diff --git a/src/wm.c b/src/wm.c index b83dc7d..8107c41 100644 --- a/src/wm.c +++ b/src/wm.c @@ -470,6 +470,24 @@ wm_get_window_title(session_t *ps, Window wid, int *length_return) { return (FcChar8 *) ret; } +void +printfefWindowName(session_t *ps, char *prefix_str, Window wid) +{ + int win_title_len = 0; + FcChar8 *win_title = wm_get_window_title(ps, wid, &win_title_len); + + if (! win_title) + return; + + if (prefix_str) + printfef("%s%s", prefix_str, win_title); + + else + printfef("%s", win_title); + + free(win_title); +} + Window wm_get_group_leader(Display *dpy, Window window) { diff --git a/src/wm.h b/src/wm.h index f85154c..8b1234c 100644 --- a/src/wm.h +++ b/src/wm.h @@ -84,6 +84,7 @@ dlist *wm_get_stack(session_t *ps); Pixmap wm_get_root_pmap(Display *dpy); long wm_get_current_desktop(session_t *ps); FcChar8 *wm_get_window_title(session_t *ps, Window wid, int *length_return); +void printfefWindowName(session_t *ps, char *prefix_str, Window wid); Window wm_get_group_leader(Display *dpy, Window window); void wm_set_fullscreen(session_t *ps, Window window, int x, int y, unsigned width, unsigned height); From 1c786d0ea11600fde12c99ad5fb2fc884e014e19 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 21:50:14 +0100 Subject: [PATCH 018/205] alt-tab: implement --prev and --next, while skippy is activated --- src/clientwin.c | 49 ++++++++++++- src/focus.h | 26 +++++++ src/mainwin.c | 5 +- src/mainwin.h | 4 + src/skippy.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++-- src/skippy.h | 7 ++ 6 files changed, 272 insertions(+), 8 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 0eba3b5..25cafc8 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -344,6 +344,12 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) { // Tinting { + // here the client window is being tinted + // if (cw->focused) + // printfef("(): *tint = &cw->mainwin->highlightTint"); + // else + // printfef("(): *tint = &cw->mainwin->normalTint"); + XRenderColor *tint = (cw->focused ? &cw->mainwin->highlightTint : &cw->mainwin->normalTint); if (tint->alpha) @@ -576,16 +582,53 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } else if (ev->type == FocusIn) { - cw->focused = true; + printfef("(): else if (ev->type == FocusIn) {"); + XFocusChangeEvent *evf = &ev->xfocus; + + // for debugging XEvents + // see: https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html + printfef("(): main window id = %#010lx", cw->mainwin->window); + printfefWindowName(ps, "(): client window = ", cw->mainwin->window); + printfef("(): client window id = %#010lx", cw->wid_client); + printfefXFocusChangeEvent(ps, evf); + + // printfef("(): usleep(10000);"); + // usleep(10000); + + // here + + if (evf->detail == NotifyWhileGrabbed) + cw->focused = true; + clientwin_render(cw); + fputs("\n", stdout); XFlush(ps->dpy); + } else if (ev->type == FocusOut) { - cw->focused = false; + printfef("(): else if (ev->type == FocusOut) {"); + XFocusChangeEvent *evf = &ev->xfocus; + + // for debugging XEvents + // see: https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html + printfef("(): main window id = %#010lx", cw->mainwin->window); + printfefWindowName(ps, "(): client window = ", cw->mainwin->window); + printfef("(): client window id = %#010lx", cw->wid_client); + printfefXFocusChangeEvent(ps, evf); + + // printfef("(): usleep(10000);"); + // usleep(10000); + + if (evf->detail == NotifyWhileGrabbed) + cw->focused = false; + clientwin_render(cw); + fputs("\n", stdout); XFlush(ps->dpy); + } else if(ev->type == EnterNotify) { XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); if (cw->mainwin->tooltip) { + cw->mainwin->cw_tooltip = cw; int win_title_len = 0; FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); if (win_title) { @@ -597,6 +640,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } } else if(ev->type == LeaveNotify) { // XSetInputFocus(ps->dpy, mw->window, RevertToParent, CurrentTime); + cw->mainwin->cw_tooltip = NULL; if(cw->mainwin->tooltip) tooltip_unmap(cw->mainwin->tooltip); } @@ -613,6 +657,7 @@ clientwin_action(ClientWin *cw, enum cliop action) { case CLIENTOP_NO: break; case CLIENTOP_FOCUS: + printfef("(): case CLIENTOP_FOCUS:"); mw->client_to_focus = cw; return 1; case CLIENTOP_ICONIFY: diff --git a/src/focus.h b/src/focus.h index f3492a7..5dfe00e 100644 --- a/src/focus.h +++ b/src/focus.h @@ -57,18 +57,44 @@ printfefXFocusChangeEvent(session_t *ps, XFocusChangeEvent *evf) printfef("(): evf->detail = %i (not recognized)", evf->detail); } +static inline void +clear_focus_all(dlist *cod) +{ + foreach_dlist (cod) + { + ClientWin *cw = (ClientWin *)iter->data; + cw->focused = 0; + } + +} + /** * @brief Focus the mini window of a client window. */ static inline void focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { + // printfef("(): "); + clear_focus_all(cw->mainwin->cod); + + printfefWindowName(ps, "(): window = ", cw->wid_client); + if (unlikely(!cw)) + { + // printfef("(): if (unlikely(!cw))"); return; + } assert(cw->mini.window); if (move_ptr) + { + // printfef("(): if (move_ptr)"); XWarpPointer(ps->dpy, None, cw->mini.window, 0, 0, 0, 0, cw->mini.width / 2, cw->mini.height / 2); + } XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); XFlush(ps->dpy); + + ps->mainwin->client_to_focus = cw; + ps->mainwin->client_to_focus->focused = 1; + } static inline void diff --git a/src/mainwin.c b/src/mainwin.c index ba3f632..f765fc8 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -88,7 +88,8 @@ mainwin_create(session_t *ps) { mw->xin_screens = 0; #endif /* CFG_XINERAMA */ - mw->pressed = mw->focus = 0; + // mw->pressed = mw->focus = 0; + mw->pressed = mw->client_to_focus = 0; mw->tooltip = 0; mw->cod = 0; @@ -344,6 +345,7 @@ mainwin_map(MainWin *mw) { if (Success != ret) printfef("(): Failed to grab keyboard (%d), troubles ahead.", ret); } */ + mw->mapped = true; } void @@ -358,6 +360,7 @@ mainwin_unmap(MainWin *mw) } XUngrabKeyboard(mw->ps->dpy, CurrentTime); XUnmapWindow(mw->ps->dpy, mw->window); + mw->mapped = false; } void diff --git a/src/mainwin.h b/src/mainwin.h index 70ec70d..5b689f0 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -71,6 +71,8 @@ struct _mainwin_t { KeyCode *keycodes_ExitSelectOnPress; KeyCode *keycodes_ExitSelectOnRelease; + bool mapped; + #ifdef CFG_XINERAMA int xin_screens; XineramaScreenInfo *xin_info, *xin_active; @@ -80,6 +82,8 @@ struct _mainwin_t { Window revert_focus_win; /// @brief The client window to eventually focus. ClientWin *client_to_focus; + // int ignore_next_refocus; + ClientWin *cw_tooltip; }; MainWin *mainwin_create(session_t *ps); diff --git a/src/skippy.c b/src/skippy.c index 4d3b793..7fe038e 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -32,6 +32,8 @@ enum pipe_cmd_t { PIPECMD_EXIT_RUNNING_DAEMON, PIPECMD_DEACTIVATE_WINDOW_PICKER, PIPECMD_TOGGLE_WINDOW_PICKER, + PIPECMD_QUEUE_FI_PREV, + PIPECMD_QUEUE_FI_NEXT, }; session_t *ps_g = NULL; @@ -360,6 +362,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { float factor; /* Update the client table, pick the ones we want and sort them */ + // printfef("(): updating dl list of clients"); clients = update_clients(mw, clients, 0); if (!clients) { printfef("(): No client windows found."); @@ -416,10 +419,50 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { // Get the currently focused window and select which mini-window to focus { dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) focus); + + // check if the user specified --prev or --next on the cmdline + if(ps->o.focus_initial) + { + + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; + + + if(ps->o.focus_initial == FI_PREV) + { + // here, mw->cod is the first (dlist*) item in the list + if (iter == mw->cod) + iter = dlist_last(mw->cod); + else + { + dlist *i = mw->cod; + for (; i != NULL; i = i->next) + if (i->next && i->next == iter) + break; + iter = i; + } + } + else if(ps->o.focus_initial == FI_NEXT) + iter = iter->next; + + } + + + // then clear this flag, so daemon not remember on its next activation + ps->o.focus_initial = 0; + if (!iter) iter = mw->cod; - mw->focus = (ClientWin *) iter->data; - mw->focus->focused = 1; + + // mw->focus = (ClientWin *) iter->data; + mw->client_to_focus = (ClientWin *) iter->data; + // mw->focus->focused = 1; + + + mw->client_to_focus->focused = 1; + // focus_miniw(ps, mw->client_to_focus); + } // Map the client windows @@ -428,7 +471,9 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { } // Unfortunately it does not work... - focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); + // focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); + focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); + // clientwin_render(mw->client_to_focus); return clients; } @@ -618,9 +663,13 @@ mainloop(session_t *ps, bool activate_on_start) { // Activation goes first, so that it won't be delayed by poll() if (!mw && activate) { + // printfef("(): if (!mw && activate) {"); + assert(ps->mainwin); activate = false; if (skippy_run_init(ps->mainwin, None)) { + // printfef("(): if (skippy_run_init(ps->mainwin, None)) {"); + // printfef("(): was in skippy_run_init"); last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; @@ -652,6 +701,8 @@ mainloop(session_t *ps, bool activate_on_start) { mw->cod = 0; if (refocus && mw->revert_focus_win) { + // printfef("(): if (refocus && mw->revert_focus_win) {"); + // printfef("(): wm_activate_window(ps, mw->revert_focus_win);"); // No idea why. Plain XSetInputFocus() no longer works after ungrabbing. wm_activate_window(ps, mw->revert_focus_win); refocus = false; @@ -684,13 +735,28 @@ mainloop(session_t *ps, bool activate_on_start) { const Window wid = ev_window(ps, &ev); if (MotionNotify == ev.type) { + + // the mouse has moved + // refocus enable + // mw->ignore_next_refocus = 0; + + // we also need to refocus here + if(mw->client_to_focus != mw->cw_tooltip) + { + focus_miniw(ps, mw->cw_tooltip); + clientwin_render(mw->client_to_focus); + } + + if (mw->tooltip && ps->o.tooltip_followsMouse) tooltip_move(mw->tooltip, ev.xmotion.x_root, ev.xmotion.y_root); } else if (ev.type == DestroyNotify || ev.type == UnmapNotify) { + // printfef("(): else if (ev.type == DestroyNotify || ev.type == UnmapNotify) {"); dlist *iter = (wid ? dlist_find(mw->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { + // printfef("(): if (iter) {"); ClientWin *cw = (ClientWin *) iter->data; if (DestroyNotify != ev.type) cw->mode = clientwin_get_disp_mode(ps, cw); @@ -707,6 +773,8 @@ mainloop(session_t *ps, bool activate_on_start) { } } else { + // printfef("(): else {"); + // printfef("(): do: clientwin_render(cw);"); free_pixmap(ps, &cw->cpixmap); free_picture(ps, &cw->origin); free_damage(ps, &cw->damage); @@ -722,7 +790,10 @@ mainloop(session_t *ps, bool activate_on_start) { pending_damage = true; if (iter) { if (!mw->poll_time) + { + // printfef("(): if (!mw->poll_time)"); clientwin_repair((ClientWin *)iter->data); + } else ((ClientWin *)iter->data)->damaged = true; } @@ -731,9 +802,17 @@ mainloop(session_t *ps, bool activate_on_start) { else if (wid == mw->window) die = mainwin_handle(mw, &ev); else if (PropertyNotify == ev.type) { + + // printfef("(): else if (PropertyNotify == ev.type) {"); + if (!ps->o.background && (ESETROOT_PMAP_ID == ev.xproperty.atom || _XROOTPMAP_ID == ev.xproperty.atom)) { + + // printfef("(): if (!ps->o.background && ..."); + // printfef("(): mainwin_update_background(mw);"); + // printfef("(): REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod);"); + mainwin_update_background(mw); REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod); } @@ -744,7 +823,12 @@ mainloop(session_t *ps, bool activate_on_start) { for (dlist *iter = mw->cod; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { - die = clientwin_handle(cw, &ev); + if (!(POLLIN & r_fd[1].revents)) + { + // we handle key events in here + // printfef("(): die = clientwin_handle(cw, &ev);"); + die = clientwin_handle(cw, &ev); + } break; } } @@ -758,7 +842,11 @@ mainloop(session_t *ps, bool activate_on_start) { pending_damage = false; foreach_dlist(mw->cod) { if (((ClientWin *) iter->data)->damaged) + { + // printfef("(): if (((ClientWin *) iter->data)->damaged)"); clientwin_repair(iter->data); + // fputs("\n", stdout); + } } last_rendered = now; } @@ -787,9 +875,49 @@ mainloop(session_t *ps, bool activate_on_start) { else { assert(1 == read_ret); printfdf("(): Received pipe command: %d", piped_input); + switch (piped_input) { + case PIPECMD_QUEUE_FI_PREV: + ps->o.focus_initial = FI_PREV; + break; + case PIPECMD_QUEUE_FI_NEXT: + ps->o.focus_initial = FI_NEXT; + break; case PIPECMD_ACTIVATE_WINDOW_PICKER: - activate = true; + printfef("(): case PIPECMD_ACTIVATE_WINDOW_PICKER:"); + if (ps->mainwin->mapped) + { + printfef("(): if (ps->mainwin->mapped)"); + fflush(stdout);fflush(stderr); + + // There is a glitch whereby calling focus_miniw_prev() or focus_miniw_next() + // does not trigger an Xev to focus-out and un-highlight the focus of the + // 1st highlighted win, so we manually unfocus it here first, before moving on + // to focus and highlight the next window... it's probably because we miss the Xev + // since we are not in the right place in the main loop, cant unwind the call stack + mw->client_to_focus->focused = 0; + clientwin_render(mw->client_to_focus); + + if (ps->o.focus_initial == FI_PREV) + { + printfef("(): focus_miniw_prev(ps, mw->client_to_focus);"); + focus_miniw_prev(ps, mw->client_to_focus); + } + + else if (ps->o.focus_initial == FI_NEXT) + { + printfef("(): focus_miniw_next(ps, mw->client_to_focus);"); + focus_miniw_next(ps, mw->client_to_focus); + } + clientwin_render(mw->client_to_focus); + + + } + else + { + printfef("(): activate = true;"); + activate = true; + } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: if (mw) @@ -840,6 +968,18 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { return true; } +static inline bool +queue_initial_focus_prev(const char *pipePath) { + printfdf("(): Set initial focus to previous selection..."); + return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_PREV, pipePath); +} + +static inline bool +queue_initial_focus_next(const char *pipePath) { + printfdf("(): Set initial focus to next selection..."); + return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_NEXT, pipePath); +} + static inline bool activate_window_picker(const char *pipePath) { printfdf("(): Activating window picker..."); @@ -944,6 +1084,8 @@ show_help() { " --activate-window-picker - tells the daemon to show the window picker.\n" " --deactivate-window-picker - tells the daemon to hide the window picker.\n" " --toggle-window-picker - tells the daemon to toggle the window picker.\n" + " --prev - launch initially focussed to previous selection.\n" + " --next - launch initially focussed to next selection.\n" // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" @@ -1093,6 +1235,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { OPT_TOGGLE_PICKER, OPT_DM_START, OPT_DM_STOP, + OPT_PREV, + OPT_NEXT, }; static const char * opts_short = "hS"; static const struct option opts_long[] = { @@ -1103,6 +1247,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "toggle-window-picker", no_argument, NULL, OPT_TOGGLE_PICKER }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, + { "prev", no_argument, NULL, OPT_PREV }, + { "next", no_argument, NULL, OPT_NEXT }, // { "test", no_argument, NULL, 't' }, { NULL, no_argument, NULL, 0 } }; @@ -1118,6 +1264,14 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG: ps->o.config_path = mstrdup(optarg); break; + case OPT_PREV: + ps->o.focus_initial = FI_PREV; + // fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + break; + case OPT_NEXT: + ps->o.focus_initial = FI_NEXT; + // fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + break; T_CASEBOOL('S', synchronize); // case 't': // developer_tests(); @@ -1138,6 +1292,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { switch (o) { case 'S': break; case OPT_CONFIG: break; + case OPT_PREV: break; + case OPT_NEXT: break; case OPT_ACTV_PICKER: ps->o.mode = PROGMODE_ACTV_PICKER; break; @@ -1340,6 +1496,8 @@ int main(int argc, char *argv[]) { // Second pass parse_args(ps, argc, argv, false); + // fprintf(stdout, "after 2nd pass: ps->o.focus_initial = %i\n", ps->o.focus_initial); + const char* pipePath = ps->o.pipePath; // Handle special modes @@ -1347,12 +1505,33 @@ int main(int argc, char *argv[]) { case PROGMODE_NORMAL: break; case PROGMODE_ACTV_PICKER: + if(ps->o.focus_initial) + { + if(ps->o.focus_initial == FI_PREV) + queue_initial_focus_prev(pipePath); + + else if(ps->o.focus_initial == FI_NEXT) + queue_initial_focus_next(pipePath); + + // we must pause slightly, otherwise will miss next read() call in this loop() + usleep(1000); + } activate_window_picker(pipePath); goto main_end; case PROGMODE_DEACTV_PICKER: deactivate_window_picker(pipePath); goto main_end; case PROGMODE_TOGGLE_PICKER: + if(ps->o.focus_initial) + { + if(ps->o.focus_initial == FI_PREV) + queue_initial_focus_prev(pipePath); + else if(ps->o.focus_initial == FI_NEXT) + queue_initial_focus_next(pipePath); + + // we must pause slightly, otherwise will miss next read() call in this loop() + usleep(1000); + } toggle_window_picker(pipePath); goto main_end; case PROGMODE_DM_STOP: diff --git a/src/skippy.h b/src/skippy.h index 4195691..6e7a31e 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -195,12 +195,19 @@ typedef enum { CLIDISP_THUMBNAIL_ICON, } client_disp_mode_t; +typedef enum { + FI_PREV = -1, + FI_CURR = 0, + FI_NEXT = +1, +} focus_initial; + /// @brief Option structure. typedef struct { char *config_path; enum progmode mode; bool runAsDaemon; bool synchronize; + int focus_initial; int distance; bool useNetWMFullscreen; From cdf23cb77a2a6564df7d0ac3874024cb904432be Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 21:55:00 +0100 Subject: [PATCH 019/205] mainwin: pass keypress events to currently focussed client window --- src/mainwin.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/mainwin.c b/src/mainwin.c index f765fc8..d8af807 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -437,6 +437,7 @@ mainwin_transform(MainWin *mw, float f) int mainwin_handle(MainWin *mw, XEvent *ev) { + // printfef("(): "); session_t *ps = mw->ps; switch(ev->type) { @@ -444,13 +445,19 @@ mainwin_handle(MainWin *mw, XEvent *ev) { XSetInputFocus(ps->dpy, mw->window, RevertToParent, CurrentTime); break; case KeyPress: - mw->pressed_key = true; - break; case KeyRelease: - if (mw->pressed_key) - report_key_unbinded(ev); - else - report_key_ignored(ev); + // printfef("(): KeyPress or KeyRelease"); + // if(mw->client_to_focus) + // { + // printfef("(): clientwin_handle(mw->client_to_focus, ev);"); + if(clientwin_handle(mw->client_to_focus, ev)) + return 1; + + // } + // else + // { + // printfef("(): mw->client_to_focus == NULL"); + // } break; case ButtonPress: mw->pressed_mouse = true; From 597bc1720d1662e1ce1787a1c3ff704e0c9fe1d2 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sat, 22 Sep 2018 21:59:01 +0100 Subject: [PATCH 020/205] config: show application thumbnails and icons --- skippy-xd.sample.rc | 2 +- src/skippy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 713b8c8..b34d30f 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -61,7 +61,7 @@ allowUpscale = true showAllDesktops = false showUnmapped = true preferredIconSize = 48 -clientDisplayModes = thumbnail icon filled none +clientDisplayModes = thumbnail-icon thumbnail icon filled none iconFillSpec = orig mid mid #00FFFF fillSpec = orig mid mid #FFFFFF background = diff --git a/src/skippy.c b/src/skippy.c index 7fe038e..9d2d3a6 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1448,7 +1448,7 @@ int main(int argc, char *argv[]) { return RET_BADARG; if (!ps->o.clientDisplayModes) { static const client_disp_mode_t DEF_CLIDISPM[] = { - CLIDISP_THUMBNAIL, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE }; ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); From cbd8634f28a46efaf2d02d1500e62f07ba16c2a6 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 24 Sep 2018 10:59:51 +0100 Subject: [PATCH 021/205] fix: when exiting on key release, dont overwrite the currently focused client window --- src/clientwin.c | 15 +++++++++------ src/focus.h | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 25cafc8..a2de488 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -544,11 +544,14 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { report_key(ev); report_key_modifiers(evk); - fputs("\n", stdout); + // fputs("\n", stdout); fflush(stdout); if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode)) { - mw->client_to_focus = cw; + // printfef("(): if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode))"); + // printfef("(): client_to_focus = %p", (uintptr_t)ps->mainwin->client_to_focus); + // mw->client_to_focus = cw; + // printfef("(): client_to_focus = %p", (uintptr_t)ps->mainwin->client_to_focus); return 1; } @@ -595,9 +598,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { // printfef("(): usleep(10000);"); // usleep(10000); - // here - - if (evf->detail == NotifyWhileGrabbed) + // if (evf->detail == NotifyWhileGrabbed) + if (evf->detail == NotifyNonlinear) cw->focused = true; clientwin_render(cw); @@ -618,7 +620,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { // printfef("(): usleep(10000);"); // usleep(10000); - if (evf->detail == NotifyWhileGrabbed) + // if (evf->detail == NotifyWhileGrabbed) + if (evf->detail == NotifyNonlinear) cw->focused = false; clientwin_render(cw); diff --git a/src/focus.h b/src/focus.h index 5dfe00e..8c69d1a 100644 --- a/src/focus.h +++ b/src/focus.h @@ -95,6 +95,8 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { ps->mainwin->client_to_focus = cw; ps->mainwin->client_to_focus->focused = 1; + // printfef("(): "); + // printfef("(): client_to_focus = %p", (uintptr_t)ps->mainwin->client_to_focus); } static inline void From 75480c6ef6dc5966522f8e56c9b5fee35abd5de4 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 24 Sep 2018 11:04:11 +0100 Subject: [PATCH 022/205] keybindings: improvement, way to select which keys will reverse direction --- skippy-xd.sample.rc | 1 + src/clientwin.c | 15 +++++++++++---- src/mainwin.c | 4 ++++ src/mainwin.h | 2 ++ src/skippy.c | 3 +++ src/skippy.h | 1 + 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index b34d30f..5019af0 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -104,4 +104,5 @@ keysExitCancelOnPress = Escape BackSpace x q keysExitCancelOnRelease = keysExitSelectOnPress = Return space keysExitSelectOnRelease = Super_L Super_R Alt_L Alt_R ISO_Level3_Shift +keysReverseDirection = Tab modifierKeyMasksReverseDirection = ShiftMask ControlMask diff --git a/src/clientwin.c b/src/clientwin.c index a2de488..0c16a81 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -492,12 +492,13 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { { report_key(ev); report_key_modifiers(evk); - fputs("\n", stdout); + fputs("\n", stdout); fflush(stdout); bool reverse_direction = false; if (arr_modkeymasks_includes(cw->mainwin->modifierKeyMasks_ReverseDirection, evk->state)) - reverse_direction = true; + if(arr_keycodes_includes(cw->mainwin->keycodes_ReverseDirection, evk->keycode)) + reverse_direction = true; if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) { @@ -517,12 +518,18 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) { - focus_down(cw); + if(reverse_direction) + focus_up(cw); + else + focus_down(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) { - focus_up(cw); + if(reverse_direction) + focus_down(cw); + else + focus_up(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) diff --git a/src/mainwin.c b/src/mainwin.c index d8af807..c71d5c9 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -102,6 +102,7 @@ mainwin_create(session_t *ps) { keys_str_syms(ps->o.bindings_keysExitCancelOnRelease, &mw->keysyms_ExitCancelOnRelease); keys_str_syms(ps->o.bindings_keysExitSelectOnPress, &mw->keysyms_ExitSelectOnPress); keys_str_syms(ps->o.bindings_keysExitSelectOnRelease, &mw->keysyms_ExitSelectOnRelease); + keys_str_syms(ps->o.bindings_keysReverseDirection, &mw->keysyms_ReverseDirection); // convert the modifier key masks settings strings into arrays of enums modkeymasks_str_enums(ps->o.bindings_modifierKeyMasksReverseDirection, &mw->modifierKeyMasks_ReverseDirection); @@ -115,6 +116,7 @@ mainwin_create(session_t *ps) { keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnRelease, &mw->keycodes_ExitCancelOnRelease); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnPress, &mw->keycodes_ExitSelectOnPress); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnRelease, &mw->keycodes_ExitSelectOnRelease); + keysyms_arr_keycodes(dpy, mw->keysyms_ReverseDirection, &mw->keycodes_ReverseDirection); // we check all possible pairs, one pair at a time. This is in a specific order, to give a more helpful error msg check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysDown", mw->keysyms_Down); @@ -406,6 +408,7 @@ mainwin_destroy(MainWin *mw) { free(mw->keysyms_ExitCancelOnRelease); free(mw->keysyms_ExitSelectOnPress); free(mw->keysyms_ExitSelectOnRelease); + free(mw->keysyms_ReverseDirection); free(mw->modifierKeyMasks_ReverseDirection); @@ -417,6 +420,7 @@ mainwin_destroy(MainWin *mw) { free(mw->keycodes_ExitCancelOnRelease); free(mw->keycodes_ExitSelectOnPress); free(mw->keycodes_ExitSelectOnRelease); + free(mw->keycodes_ReverseDirection); free(mw); } diff --git a/src/mainwin.h b/src/mainwin.h index 5b689f0..401b567 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -59,6 +59,7 @@ struct _mainwin_t { KeySym *keysyms_ExitCancelOnRelease; KeySym *keysyms_ExitSelectOnPress; KeySym *keysyms_ExitSelectOnRelease; + KeySym *keysyms_ReverseDirection; int *modifierKeyMasks_ReverseDirection; @@ -70,6 +71,7 @@ struct _mainwin_t { KeyCode *keycodes_ExitCancelOnRelease; KeyCode *keycodes_ExitSelectOnPress; KeyCode *keycodes_ExitSelectOnRelease; + KeyCode *keycodes_ReverseDirection; bool mapped; diff --git a/src/skippy.c b/src/skippy.c index 9d2d3a6..4cd9da3 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1392,6 +1392,7 @@ int main(int argc, char *argv[]) { ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitOnRelease", "")); ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitOnPress", "Return space")); ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); + ps->o.bindings_keysReverseDirection = mstrdup(config_get(config, "bindings", "keysReverseDirection", "Tab")); ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); // print an error message for any key bindings that aren't recognized @@ -1403,6 +1404,7 @@ int main(int argc, char *argv[]) { check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnRelease =", ps->o.bindings_keysExitSelectOnRelease); + check_keysyms(ps->o.config_path, ": [bindings] keysReverseDirection =", ps->o.bindings_keysReverseDirection); check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) @@ -1622,6 +1624,7 @@ int main(int argc, char *argv[]) { free(ps->o.bindings_keysExitCancelOnRelease); free(ps->o.bindings_keysExitSelectOnPress); free(ps->o.bindings_keysExitSelectOnRelease); + free(ps->o.bindings_keysReverseDirection); free(ps->o.bindings_modifierKeyMasksReverseDirection); } diff --git a/src/skippy.h b/src/skippy.h index 6e7a31e..044b927 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -268,6 +268,7 @@ typedef struct { char *bindings_keysExitCancelOnRelease; char *bindings_keysExitSelectOnPress; char *bindings_keysExitSelectOnRelease; + char *bindings_keysReverseDirection; char *bindings_modifierKeyMasksReverseDirection; } options_t; From 14d0394acdf0e309d03e8d5d9fca1695e4362a37 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 24 Sep 2018 13:41:24 +0100 Subject: [PATCH 023/205] daemon: increase inter-command sending delay, from 1ms to 10ms --- src/skippy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 4cd9da3..1bf2b68 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1516,7 +1516,7 @@ int main(int argc, char *argv[]) { queue_initial_focus_next(pipePath); // we must pause slightly, otherwise will miss next read() call in this loop() - usleep(1000); + usleep(10000); } activate_window_picker(pipePath); goto main_end; @@ -1532,7 +1532,7 @@ int main(int argc, char *argv[]) { queue_initial_focus_next(pipePath); // we must pause slightly, otherwise will miss next read() call in this loop() - usleep(1000); + usleep(10000); } toggle_window_picker(pipePath); goto main_end; From ce096bed5a9881a85e4517bd005253bddd637d43 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 1 Oct 2018 19:01:14 +0100 Subject: [PATCH 024/205] dlist: improvements to dlist library functions --- src/dlist.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/dlist.h | 28 ++++++ 2 files changed, 282 insertions(+), 2 deletions(-) diff --git a/src/dlist.c b/src/dlist.c index a4ffbc8..36a0b55 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -67,12 +67,204 @@ dlist_prepend(dlist *l, void *d) return new_elem; } +dlist * +dlist_insert_before(dlist *elem, dlist *new_elem) +{ + if (!elem) + return NULL; + + dlist *first_elem = dlist_first(elem); + + if (!new_elem) + return first_elem; + + dlist *prev = elem->prev; + if (prev) + { + prev->next = new_elem; + new_elem->prev = prev; + } + else + { + new_elem->prev = 0; + first_elem = new_elem; + } + new_elem->next = elem; + elem->prev = new_elem; + + return first_elem; +} + +dlist * +dlist_insert_after(dlist *elem, dlist *new_elem) +{ + if (!elem) + return NULL; + + dlist *first_elem = dlist_first(elem); + + if (!new_elem) + return first_elem; + + dlist *next = elem->next; + if (next) + { + next->prev = new_elem; + new_elem->next = next; + } + else + { + new_elem->next = 0; + } + new_elem->prev = elem; + elem->next = new_elem; + + return first_elem; +} + +dlist * +dlist_insert_nth(dlist *l, dlist *new_elem, unsigned int n) +{ + if (!l) + return NULL; + + if (!new_elem) + return l; + + dlist *first_elem = dlist_first(l); + dlist *nth = dlist_nth(l, n); + + if (nth) + { + first_elem = dlist_insert_before(nth, new_elem); + } + else + { + // there is no nth element + printfef("(%p,%p,%i): list has fewer than %i elements. appending as the last element.", l, new_elem, n, n); + first_elem = dlist_insert_after( dlist_last(l), new_elem); + } + + return first_elem; +} + +dlist * +dlist_cycle_prev(dlist *l) +{ + if (! l) + return NULL; + + dlist *first_elem = dlist_first(l); + dlist *last_elem = dlist_last(l); + dlist *prev = last_elem->prev; + + if (dlist_len(first_elem) == 1) + return first_elem; + + if (prev) + prev->next = NULL; + + first_elem->prev = last_elem; + last_elem->prev = NULL; + last_elem->next = first_elem; + + first_elem = last_elem; + return first_elem; +} + +dlist * +dlist_cycle_next(dlist *l) +{ + if (! l) + return NULL; + + dlist *first_elem = dlist_first(l); + dlist *last_elem = dlist_last(l); + dlist *next = first_elem->next; + + if (dlist_len(first_elem) == 1) + return first_elem; + + if (next) + next->prev = NULL; + + last_elem->next = first_elem; + first_elem->prev = last_elem; + first_elem->next = NULL; + + first_elem = next; + return first_elem; +} + +dlist * +dlist_cycle(dlist *l, int n) +{ + if (! l) + return NULL; + + dlist *first_elem = dlist_first(l); + + if (n < 0) + { + while (n != 0) + { + first_elem = dlist_cycle_prev(first_elem); + n++; + } + } + + if (n > 0) + { + while (n != 0) + { + first_elem = dlist_cycle_next(first_elem); + n--; + } + } + return first_elem; +} + +dlist * +dlist_extract(dlist *elem) +{ + if (! elem) + return NULL; + + dlist *first_elem = dlist_first(elem); + + dlist *prev = elem->prev; + dlist *next = elem->next; + + if (prev) + { + if (next) + { + prev->next = next; + next->prev = prev; + } + else + { + prev->next = NULL; + } + } + else if (next) + { + next->prev = NULL; + first_elem = next; + } + + elem->prev = NULL; + elem->next = NULL; + + return first_elem; +} + dlist * dlist_remove(dlist *l) { dlist *n = 0; - if(! l) + if (! l) return NULL; if(l->prev) { @@ -174,17 +366,77 @@ dlist_dup(dlist *l) return n; } +dlist * +dlist_split_nth(dlist *l, unsigned int n) +{ + dlist *first_elem = dlist_first(l); + dlist *dlist_n = dlist_nth(first_elem, n); + + if (! dlist_n) + return NULL; + + dlist *prev = dlist_n->prev; + if (prev) + { + prev->next = NULL; + dlist_n->prev = NULL; + } + + return dlist_n; +} + dlist * dlist_join(dlist *l, dlist *l2) { if (!l) return l2; if (!l2) return l; + if (l == l2) return NULL; + dlist *first = dlist_first(l); dlist *last = dlist_last(l); dlist *first2 = dlist_first(l2); + + + // check that no elements are the same + l = first; l2 = first2; + while (l) + { + while (l2) + { + if (l == l2) + return NULL; + + l2 = l2->next; + } + l = l->next; + } + last->next = first2; first2->prev = last; + return first; +} - return l; +int +dlist_index_of(dlist *l, dlist *elem) +{ + if (! l) + return -1; + + if (! elem) + return -1; + + int n = 0; + dlist *nth_elem = dlist_first(l); + + while ((nth_elem) && (nth_elem != elem)) + { + nth_elem = nth_elem->next; + n++; + } + + if (!nth_elem) + return -1; + + return n; } dlist * diff --git a/src/dlist.h b/src/dlist.h index 05c40ec..a6c686c 100644 --- a/src/dlist.h +++ b/src/dlist.h @@ -40,6 +40,27 @@ dlist *dlist_add(dlist *, void *); /* add element to the start of the list, returns new element (and thus, start of list) */ dlist *dlist_prepend(dlist *, void *); +/* returns the list's new head element, after being updated with 'new_elem' inserted before 'elem' */ +dlist *dlist_insert_before(dlist *elem, dlist *new_elem); + +/* returns the list's new head element, after being updated with 'new_elem' inserted after 'elem' */ +dlist *dlist_insert_after(dlist *elem, dlist *new_elem); + +/* returns the list's new head element, after being updated with 'new_elem' inserted as the nth element of it */ +dlist * dlist_insert_nth(dlist *l, dlist *new_elem, unsigned int n); + +/* returns the list's new head element, after the elements being cycled around by -1 steps */ +dlist *dlist_cycle_prev(dlist *l); + +/* returns the list's new head element, after the elements being cycled around by +1 steps */ +dlist *dlist_cycle_next(dlist *l); + +/* returns the list's new head element, after the elements being cycled around by 'n' steps */ +dlist *dlist_cycle(dlist *l, int n); + +/* returns the list's new head element, after being updated with the specified element removed from it */ +dlist *dlist_extract(dlist *elem); + /* remove an element from the list, returns another element in the list or 0 */ dlist *dlist_remove(dlist *); dlist *dlist_remove_free_data(dlist *); @@ -71,8 +92,15 @@ void dlist_reverse(dlist *); /* duplicate the list (not the data), returns new end */ dlist *dlist_dup(dlist *); +/* split the dlist l, and return the 2nd dlist, from the nth element. Or 0, if 'n' is out of bounds */ +dlist *dlist_split_nth(dlist *l, unsigned int n); + +/* join l and l2 together, appending l2 to the end of l1. return NULL if they share any common elements */ dlist * dlist_join(dlist *l, dlist *l2); +/* find the absoloute index position of elem, from start of list, or '-1' if an input error, or out of bounds */ +int dlist_index_of(dlist *l, dlist *elem); + /* find all matching elements (returns new list or 0) */ typedef int (*dlist_match_func)(dlist*, void *); dlist *dlist_find_all(dlist *, dlist_match_func, void *); From 950985d14af7f9e1c3c636a1f76dce17c296857a Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 1 Oct 2018 19:04:26 +0100 Subject: [PATCH 025/205] because preprocessor macros are evil --- src/focus.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/focus.h b/src/focus.h index 8c69d1a..c153647 100644 --- a/src/focus.h +++ b/src/focus.h @@ -60,12 +60,14 @@ printfefXFocusChangeEvent(session_t *ps, XFocusChangeEvent *evf) static inline void clear_focus_all(dlist *cod) { - foreach_dlist (cod) + dlist *elem = dlist_first(cod); + while (elem) { - ClientWin *cw = (ClientWin *)iter->data; - cw->focused = 0; + ClientWin *cw = (ClientWin *)elem->data; + if (cw) + cw->focused = 0; + elem = elem->next; } - } /** From 5b3d33666ada631f911779eb03527f147c1c0e46 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 1 Oct 2018 19:13:42 +0100 Subject: [PATCH 026/205] another 'more sane' default setting. make the update frequency 60 fps --- skippy-xd.sample.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 5019af0..1b55bbd 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -18,7 +18,7 @@ # # - if the update frequency is a negative value, the mini-windows will only # be updated when they're explicitly rendered (like, when they gain or -# lose focus). +# lose focus). otherwise updateFreq is how many updates per second (fps) # # - the 'shadowText' option can be a color or 'none', in which case the # drop-shadow effect is disabled @@ -47,7 +47,7 @@ distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true -updateFreq = 10.0 +updateFreq = 60.0 lazyTrans = false pipePath = /tmp/skippy-xd-fifo movePointerOnStart = true From 72584db08121d14f9a38b89d9e020d1e44b57d26 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 1 Oct 2018 23:50:42 +0100 Subject: [PATCH 027/205] changelog: clarify the pre-release status msg --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2381855..0c27001 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ Skippy-XD changelog 0.5.2~pre -- "Puzzlebox" (09 Sept 2018) ~/dreamcat4 + ===== + - This is a pre-release version. Certain features are not fully complete. + When the release is ready, this msg + the '~pre' tag will be removed. + ===== - Fully customizable keybindings, and documentation for configuring them - Default keybindings settings made consistent with 'Alt-Tab' behaviour - Valgrind - added .valgrind.supressions file From e1882c9eb001f7a2d2b937063315d0f9a6946918 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Tue, 2 Oct 2018 12:35:43 +0100 Subject: [PATCH 028/205] Update README && rewrite wrapper shell script --- Makefile | 2 +- README.md | 75 ++++++++++--------------- skippy-xd-runner | 139 +++++++++++++++++++++++++++++++++++++++++++++++ skippy-xd-toggle | 52 ------------------ 4 files changed, 169 insertions(+), 99 deletions(-) create mode 100755 skippy-xd-runner delete mode 100755 skippy-xd-toggle diff --git a/Makefile b/Makefile index 237e645..06ceaf1 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ install: ${BINS} skippy-xd.sample.rc install -d "${DESTDIR}${BINDIR}/" "${DESTDIR}/etc/xdg/" install -m 755 ${BINS} "${DESTDIR}${BINDIR}/" install -m 644 skippy-xd.sample.rc "${DESTDIR}/etc/xdg/skippy-xd.rc" - install -m 755 skippy-xd-toggle "${DESTDIR}${BINDIR}/" + install -m 755 skippy-xd-runner "${DESTDIR}${BINDIR}/" uninstall: # Should configuration file be removed? diff --git a/README.md b/README.md index 16133b0..722ddfe 100644 --- a/README.md +++ b/README.md @@ -46,47 +46,41 @@ Download the original `skippy-xd.rc-default` config file and copy it to `~/.conf ### Command Line -Once Skippy-XD is installed, you can run it by entering `skippy-xd` at the command line. This will start the program, activate the window picker once, then exit. However, starting the program produces a brief flicker, so its better to keep the application running in the background as a daemon and just activate it when you want to use the window picker. - -To run the daemon, use the following command: +Once Skippy-XD is installed, you can run it by entering `skippy-xd` at the command line. This will start the program, activate the window picker once, then exit. However it is far better to keep the application running in the background as a daemon and just activate it when you want to use the window picker. ```sh -skippy-xd --start-daemon -``` +skippy-xd --help +skippy-xd v0.5.2~pre (2018.09.09) - "Puzzlebox" Edition +Usage: skippy-xd [command] -If for whatever reason you need to cleanly stop the running daemon, do this: +The available commands are: + --config - Read the specified configuration file. + --start-daemon - starts the daemon running. + --stop-daemon - stops the daemon running. + --activate-window-picker - tells the daemon to show the window picker. + --deactivate-window-picker - tells the daemon to hide the window picker. + --toggle-window-picker - tells the daemon to toggle the window picker. + --prev - launch initially focussed to previous selection. + --next - launch initially focussed to next selection. -```sh -skippy-xd --stop-daemon -``` - -Once the daemon is running you can use the following command to activate it: - -```sh -skippy-xd --activate-window-picker + --help - show this message. + -S - Synchronize X operation (debugging). +PNG support: Yes + Compiled with libpng 1.6.34, using 1.6.34. + Compiled with zlib 1.2.11, using 1.2.11. ``` -However, sometimes pressing the Return key to run this last command also causes the window to be selected, so it is probably more effective in testing to do this: +### skippy-xd-runner -```sh -sleep 0.5 && skippy-xd --activate-window-picker -``` - -Alternatively, you can use the included toggle script, which starts the daemon, if it isn't already started, and activates the window picker: - -``` -skippy-xd-toggle -``` +However, sometimes skippy won't activate properly. This can either be because it launches too quickly, and receives the last Return key press event, that was used to launch it by. Or because when bound to a global key binding, and when the key is being held down. Then the key repeats and skippy will be activated far too much, causing the daemon to lock up. Because it is getting many more requests than it can actually handle. Over it's simple FIFO buffer loop. -or, with the path to your configuration file: +To try to address those kinds of problems, we now include the wrapper script `skippy-xd-runner`. However it is not an ideal solution and introduces new problems of it's own. Ideally we should prefer to upgrade or replace the FIFO queue (file socket) / polling of `read()`. With someting a bit less dumb. -``` -skippy-xd-toggle /PATH/TO/YOUR/CONFIG -``` +Anyhow, for the time being `skippy-xd-runner` is a useful safeguard. To prevent lockups of your window manager (or whatever your parent process) that is activating skippy. Those types of background usage / invokation of skippy are discussed in more detail in the next sections. ### Keyboard Shortcuts -There are 2 types of keyboard shortcuts. Global keyboard shortcuts, and the program's own keyboard shortcuts. +There are 2 types of keyboard shortcuts. Global keyboard shortcuts, and skippy's own keyboard shortcuts, for when the skippy window picker becomes activated. #### Global keyboard shortcuts @@ -97,7 +91,7 @@ Firstly, there are global keyboard shortcuts, to be configured for invoking / la * Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse * Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file -It is recommended (best way) to set `skippy-xd --start-daemon` to be run after login. By adding it to the Startup Applications of your window manager. Then you should bind `skippy-xd --toggle-window-picker`, or `skippy-xd-toggle` to your preferred global keyboard shortcut. For most people, that will be `Alt+Tab` or `Super+Tab`. +It is recommended (best way) to set `skippy-xd --start-daemon` to be run after login. By adding it to the Startup Applications of your window manager. Then you should bind `skippy-xd-runner --toggle`, or `skippy-xd-runner --activate` to your preferred global keyboard shortcut. For most people, that will be `Alt+Tab` or `Super+Tab`. Quite a few window managers already assign `Alt+Tab` (or `Super+Tab`) to something else. Like their own built-in Alt-Tab feature. So you might also need to figure out how to un-bind those pre-existing shortcuts, before you can re-assign them to Skippy-XD instead. @@ -171,21 +165,6 @@ Key strings are case sensitive. So `alt_l` will not work - it will no match anyt Be sure to separate with ` ` spaces each keybinding in a given setting. Like `keysLeft = Left b a h B A H` for example. You cannot use commas `, ; :` or other special characters in the keybindings settings in the `[bindings]` section of the skippy rc file. Otherwise it won't work. -## Troubleshooting - -Admittedly, skippy-xd is not yet perfect. Sometimes it will just stop working, but it doesn't seem to be a crash (`ps aux | grep skippy` shows the daemon is still running). -To avoid this, your best option is to use the included toggle script: - -``` -skippy-xd-toggle -``` - -or, with the path to your configuration file: - -``` -skippy-xd-toggle /PATH/TO/YOUR/CONFIG -``` - ## See Also * [Skippy-XD on Ubuntu Wiki](https://wiki.ubuntu.com/Skippy) @@ -197,7 +176,11 @@ skippy-xd-toggle /PATH/TO/YOUR/CONFIG The last 'stable maintiner' of this software was [richardgv](https://github.com/richardgv). And that is where the vast majority of Skippy issues are raised / the bug tracker is still on his [fork over there](https://github.com/richardgv/skippy-xd/issues). However at this time, it looks like Richard really does not have time anymore to continue to maintain this software anymore (since 2015). And neither do I as a matter of fact. -This project is definately in need of a new maintainer. In the meantime, best thing we can do is to just fork based off the latest / most reaonable commits. And add whatever feature(s) or bugfixes ontop of that version. A top priority (very important) is not to be super-picky about this but: make safe changes to the code. Do not do anything that is *too risky* or over-extend yourself. Definately play on the safe side. Here are 3 basic safeguard mechanisms you can use in this project: +This project is definately in need of a new maintainer. In the meantime, best thing we can do is to just fork based off the latest / most reaonable commits. And add whatever feature(s) or bugfixes ontop of that version. A top priority (very important) is not to be super-picky about this but: make safe changes to the code. Do not do anything that is *too risky* or over-extend yourself. Definately play on the safe side. For some pointers see next section + +## Developer notes + +Here are 3 basic safeguard mechanisms you can use in this project: 1) Uncomment the `--test` developer test mode. And use it as a temporary sandbox to test any new library functions that you need to add. Throw bad input at all your new funtions. Specifically try to catch errors regarding the memory management. Bad pointers, not checking for null, etc. And when such a bug is found, try to use that as a reason for justifying a further scrutinyg / enhancement of your error handling, in your new code. Spend the vast majority of your developer time just writing the parts of the code that does the error handling. I estimate that I spend something like around 75% of my time doing that, and catching errors. With the remaining 25% of my time (or even less than that) on the actual 'doing stuff' new code that not library functinos. I.e. working in the existing skippy code paths / where I was actually trying to implement the new feature. That 'felt right' (for me) in C. Particularly because C has is no garbage collection / pointer safety, etc. And a large percentage of my bugs (perhaps about half of them!) were almost completely hidden to me, unless the code was actually exercised with bad input. In order to exercise those non-critical code paths. diff --git a/skippy-xd-runner b/skippy-xd-runner new file mode 100755 index 0000000..3d811a1 --- /dev/null +++ b/skippy-xd-runner @@ -0,0 +1,139 @@ +#!/bin/sh +# +# skippy-xd-runner +# +# A wrapper script to deal with too many requests / locks up skippy +# When skippy is bound to a global keybinding, and held keys repeat +# +# Functions: +# * Restart skippy daemon if stuck / unresponsive (> 1 sec) +# * Don't overload skippy with any simultaneous requests +# * Auto-start daemon for --activate and --toggle commands +# +# Usage: +# +# skippy-xd-runner +# +# The available commands are: +# --config - Read the specified configuration file. +# --start-daemon - starts the daemon running. +# --stop-daemon - stops the daemon running. +# --activate-window-picker - tells the daemon to show the window picker. +# --deactivate-window-picker - tells the daemon to hide the window picker. +# --toggle-window-picker - tells the daemon to toggle the window picker. +# --prev - launch initially focussed to previous selection. +# --next - launch initially focussed to next selection. +# --help - show this message. +# -S - Synchronize X operation (debugging). +# +# +# + +_kill_skippy() { + + killall 'skippy-xd' + + if [ -f '/tmp/skippy-xd-fifo' ]; then + rm /tmp/skippy-xd-fifo + touch /tmp/skippy-xd-fifo + fi + + exit $? +} + + +_parse_args() +{ + while [ "$1" ]; do + arg="$1" + + case $arg in + + --config) shift && _config="$1" ;; + --start-daemon|--start) _start_daemon=true ;; + --stop-daemon|--stop) _stop_daemon=true ;; + --activate-window-picker|--activate) _activate=true ;; + --deactivate-window-picker|--deactivate) _deactivate=true ;; + --toggle-window-picker|--toggle) _toggle=true ;; + --prev) _prev=true ;; + --next) _next=true ;; + --help|-h) _help=true ;; + -S) _sync=true ;; + + esac + + shift + done + + unset _first_arg + if [ "$_activate" ]; then + _first_arg="--activate" + fi + + if [ "$_deactivate" ]; then + _first_arg="--deactivate" + fi + + if [ "$_toggle" ]; then + _first_arg="--toggle" + fi + + if [ "$_first_arg" ]; then + unset _start_daemon + fi +} + +_main() +{ + lastActivationTimeoutSeconds=1 + + psSkippyActivateOut="`pgrep -f 'skippy-xd --activate'`" + psSkippyDeactivateOut="`pgrep -f 'skippy-xd --deactivate'`" + psSkippyToggleOut="`pgrep -f 'skippy-xd --toggle'`" + + _other_clients=0 + for pid in $psSkippyActivateOut $psSkippyDeactivateOut $psSkippyToggleOut; do + ptime="$(ps -o etimes= -p "$pid")" + if [ "$ptime" -ge "$lastActivationTimeoutSeconds" ]; then + _killall=true + break + fi + _other_clients="$(expr $i + 1)" + done + + + if [ "$_other_clients" -gt "1" ]; then + _killall=true + fi + + # if a process to activate skippy already exists, with a runtime that is too long + # (> 1sec). Then assume skippy-xd is stuck, so we must kill its all of its locked processess + if [ "$_killall" ]; then + _kill_skippy; + + # if the skippy-xd daemon is busy, and servicing only 1 other recent request (< 1 sec old) + # then we assume the alt-tab key is being held down. so we must skip / omit our extra + # requests such as this one, since too many requests will lock up the skippy daemon + elif [ "$_first_arg" ] && [ "$_other_clients" -eq "1" ]; then + echo "refused. skippy is still busy servicing the previous client request" + exit 1 + fi + + # if the action requires the skippy-xd daemon, but it is not already running, we should start it + if [ "$_first_arg" ] && [ ! "$_deactivate" ] && [ ! "$(pgrep -f 'skippy-xd ')" ]; then + if [ "$_config" ]; then + skippy-xd --start-daemon --config "$_config" & + else + skippy-xd --start-daemon & + fi + fi + + # pass all arguments onto skippy unmodified. but repeat $first_arg up front, to show up in pgrep -f output + skippy-xd $_first_arg "$@" + exit $? +} + +( + _parse_args "$@"; + _main "$@" +) diff --git a/skippy-xd-toggle b/skippy-xd-toggle deleted file mode 100755 index d438c14..0000000 --- a/skippy-xd-toggle +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -killSkippyXd() { - - killall 'skippy-xd' - - if [ -f '/tmp/skippy-xd-fifo' ] - then - rm /tmp/skippy-xd-fifo - touch /tmp/skippy-xd-fifo - fi - - exit $? - -} - -toggleSkippyXd() { - - skippyDaemonStartCommand="skippy-xd --start-daemon" - psSkippyOut="`pgrep -f 'skippy-xd '`" - psSkippyActivateOut="`pgrep -f 'skippy-xd --activate-window-picker'`" - psSkippyToggleOut="`pgrep -f 'skippy-xd --toggle-window-picker'`" - - skippyConfig="$1" - - if [ -f "$skippyConfig" ] - then - skippyDaemonStartCommand="$skippyDaemonStartCommand --config $skippyConfig" - fi - - ## IF, when calling skippy-xd, to start the window picker, - ## a process to do so already exists, then skippy-xd is stuck, - ## so we must clear its queue and restart its daemon. - ## ELSE, if the skippy-xd daemon has not been started, - ## we should start it. - - if [ ! -z "$psSkippyActivateOut" ] || [ ! -z "$psSkippyToggleOut" ] - then - killSkippyXd - $skippyDaemonStartCommand & - elif [ -z "$psSkippyOut" ] - then - $skippyDaemonStartCommand & - fi - - skippy-xd --toggle-window-picker - - exit $? - -} - -(toggleSkippyXd "$@") From 2242f0772214f60a691b8470feef680850ff1656 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Tue, 2 Oct 2018 12:40:43 +0100 Subject: [PATCH 029/205] changelog: updated --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 0c27001..c715c37 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ Skippy-XD changelog ===== - Fully customizable keybindings, and documentation for configuring them - Default keybindings settings made consistent with 'Alt-Tab' behaviour + - (Alt-Tab) New --prev and --next args for --activate and --toggle modes + - Replaced wrapper script skippy-xd-toggle --> skippy-xd-runner - Valgrind - added .valgrind.supressions file - Makefile - prefer clang over gcc, if clang is present on the system - Makefile - a slight improvment to the handling of compiler warnings From f244db3fecea68f5214ef3649eea3a84a6480a43 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Tue, 2 Oct 2018 19:41:19 +0100 Subject: [PATCH 030/205] log: print which config file is loading --- src/config.c | 4 ++++ src/skippy.c | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/config.c b/src/config.c index 0bdbe5e..af8515c 100644 --- a/src/config.c +++ b/src/config.c @@ -128,6 +128,10 @@ config_load(const char *path) fprintf(stderr, "WARNING: Couldn't load config file '%s'.\n", path); return 0; } + else + { + printfef("(): config file found. using \"%s\"", path); + } fseek(fin, 0, SEEK_END); flen = ftell(fin); diff --git a/src/skippy.c b/src/skippy.c index 1bf2b68..738f294 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1201,15 +1201,16 @@ get_cfg_path(void) { free(path); path = NULL; } - // Check $XDG_CONFIG_DIRS - if (!((dir = getenv("XDG_CONFIG_DIRS")) && strlen(dir))) - dir = PATH_CONFIG_SYS; + + // Look in env $XDG_CONFIG_DIRS + if ((dir = getenv("XDG_CONFIG_DIRS"))) { char *dir_free = mstrdup(dir); char *part = strtok(dir_free, ":"); while (part) { path = mstrjoin(part, PATH_CONFIG_SYS_SUFFIX); - if (fexists(path)) { + if (fexists(path)) + { free(dir_free); goto get_cfg_path_found; } @@ -1220,6 +1221,16 @@ get_cfg_path(void) { free(dir_free); } + // Use the default location if env var not set + { + dir = PATH_CONFIG_SYS; + path = mstrjoin(dir, PATH_CONFIG_SYS_SUFFIX); + if (fexists(path)) + goto get_cfg_path_found; + free(path); + path = NULL; + } + return NULL; get_cfg_path_found: From c936bdefd005ed90584feaa3e66f021f6a328994 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 15 Oct 2018 17:09:00 +0100 Subject: [PATCH 031/205] readme: add link to instructions for ubuntu budgie users --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 722ddfe..a59e7e1 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ There are 2 types of keyboard shortcuts. Global keyboard shortcuts, and skippy's Firstly, there are global keyboard shortcuts, to be configured for invoking / launching Skippy. How to setup a global keyboard shortcut depends entirely on your chosen window manager. So we cannot provide you with specific instructions in that regard. But here are some links for a few of them: +* Budgie: https://gist.github.com/dreamcat4/bc4d6e6b6959901bf641f03b3c18462e * Xfce: http://wiki.xfce.org/faq#keyboard * Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse * Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file From 0458b33e4b4acfa123635ef640e4614b79af00a4 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Wed, 28 Nov 2018 16:52:33 +0000 Subject: [PATCH 032/205] fix: bug where previous mini window is not un-highlighted on focus_up() and focus_down() --- src/focus.c | 4 ++++ src/focus.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/focus.c b/src/focus.c index 8af02a1..0e4dbca 100644 --- a/src/focus.c +++ b/src/focus.c @@ -43,6 +43,10 @@ focus_miniw_dir(ClientWin *cw, match_func match, dist_func func) { } } + clear_focus_all(cw->mainwin->cod); + clientwin_render(cw); + XFlush(ps->dpy); + focus_miniw(ps, candidate); dlist_free(candidates); } diff --git a/src/focus.h b/src/focus.h index c153647..7520ef9 100644 --- a/src/focus.h +++ b/src/focus.h @@ -86,6 +86,9 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { return; } assert(cw->mini.window); + + clientwin_render(cw); + if (move_ptr) { // printfef("(): if (move_ptr)"); From 6d411638eddf9697d94337e0bca48856a37f34c9 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Wed, 28 Nov 2018 18:29:08 +0000 Subject: [PATCH 033/205] fix: improve performance / responsiveness of updates, whilst moving the mouse ...by discarding contiguous blocks of MotionNotify events, and only updating on the last MotionNotify event in the event queue --- src/skippy.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 738f294..39d0a9a 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -726,15 +726,36 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) { // Process X events + int num_events = 0; XEvent ev = { }; - while (XEventsQueued(ps->dpy, QueuedAfterReading)) { + while ((num_events = XEventsQueued(ps->dpy, QueuedAfterReading))) + { XNextEvent(ps->dpy, &ev); + #ifdef DEBUG_EVENTS ev_dump(ps, mw, &ev); #endif - const Window wid = ev_window(ps, &ev); + Window wid = ev_window(ps, &ev); + + if (MotionNotify == ev.type) + { + // Speed up responsiveness when the user is moving the mouse around + // The queue gets filled up with consquetive MotionNotify events + // discard all except the last MotionNotify event in a contiguous block of MotionNotify events + + XEvent ev_next = { }; + while(num_events > 0) + { + XPeekEvent(ps->dpy, &ev_next); + + if(ev_next.type != MotionNotify) + break; - if (MotionNotify == ev.type) { + XNextEvent(ps->dpy, &ev); + wid = ev_window(ps, &ev); + + num_events--; + } // the mouse has moved // refocus enable From 060cfbf7e8490b79e27df6c34400f7e3f6498e26 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Sun, 9 Dec 2018 18:56:49 +0000 Subject: [PATCH 034/205] fix: dont quit after killing zombie tasks, continue processing the request --- skippy-xd-runner | 1 - 1 file changed, 1 deletion(-) diff --git a/skippy-xd-runner b/skippy-xd-runner index 3d811a1..f1af1ad 100755 --- a/skippy-xd-runner +++ b/skippy-xd-runner @@ -38,7 +38,6 @@ _kill_skippy() { touch /tmp/skippy-xd-fifo fi - exit $? } From 8a5723b2e995414d8fc73c38bde044bac42378d3 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 14 Jan 2019 20:24:51 +0000 Subject: [PATCH 035/205] Fix: segfault in focus_mini_window_adv() - no pointer check --- src/focus.h | 4 ++++ src/skippy.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/focus.h b/src/focus.h index 7520ef9..f6a3f6d 100644 --- a/src/focus.h +++ b/src/focus.h @@ -76,6 +76,10 @@ clear_focus_all(dlist *cod) static inline void focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { // printfef("(): "); + + if (!cw || !ps) + return; + clear_focus_all(cw->mainwin->cod); printfefWindowName(ps, "(): window = ", cw->wid_client); diff --git a/src/skippy.c b/src/skippy.c index 39d0a9a..efdc533 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -762,7 +762,7 @@ mainloop(session_t *ps, bool activate_on_start) { // mw->ignore_next_refocus = 0; // we also need to refocus here - if(mw->client_to_focus != mw->cw_tooltip) + if(mw->cw_tooltip && (mw->cw_tooltip != mw->client_to_focus)) { focus_miniw(ps, mw->cw_tooltip); clientwin_render(mw->client_to_focus); From 960dffe75fca6e880656ff691c75d46a70dd7e69 Mon Sep 17 00:00:00 2001 From: stuffo Date: Tue, 10 Sep 2019 17:29:50 -0400 Subject: [PATCH 036/205] fixed keysExit* config entries not getting used --- src/skippy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index efdc533..0d9105a 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1420,10 +1420,10 @@ int main(int argc, char *argv[]) { ps->o.bindings_keysDown = mstrdup(config_get(config, "bindings", "keysDown", "Down s")); ps->o.bindings_keysLeft = mstrdup(config_get(config, "bindings", "keysLeft", "Left b a")); ps->o.bindings_keysRight = mstrdup(config_get(config, "bindings", "keysRight", "Right Tab f d")); - ps->o.bindings_keysExitCancelOnPress = mstrdup(config_get(config, "bindings", "keysExitOnPress", "Escape BackSpace x q")); - ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitOnRelease", "")); - ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitOnPress", "Return space")); - ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); + ps->o.bindings_keysExitCancelOnPress = mstrdup(config_get(config, "bindings", "keysExitCancelOnPress", "Escape BackSpace x q")); + ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitCancelOnRelease", "")); + ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitSelectOnPress", "Return space")); + ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitSelectOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); ps->o.bindings_keysReverseDirection = mstrdup(config_get(config, "bindings", "keysReverseDirection", "Tab")); ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); From d0eb15877c9c151b9cfbc3ae8b13a0e5e6d5531a Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 11 Apr 2020 21:37:54 +0200 Subject: [PATCH 037/205] tooltip: limit width to preview width --- src/clientwin.c | 2 +- src/tooltip.c | 4 +++- src/tooltip.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 0c16a81..ec3feae 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -642,7 +642,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { int win_title_len = 0; FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); if (win_title) { - tooltip_map(cw->mainwin->tooltip, + tooltip_map(cw->mainwin->tooltip, cw->mini.width, ev->xcrossing.x_root, ev->xcrossing.y_root, win_title, win_title_len); free(win_title); diff --git a/src/tooltip.c b/src/tooltip.c index dcb7e71..bb6c867 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -163,7 +163,7 @@ tooltip_create(MainWin *mw) { } void -tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, +tooltip_map(Tooltip *tt, int mini_width, int mouse_x, int mouse_y, const FcChar8 *text, int len) { session_t * const ps = tt->mainwin->ps; @@ -172,6 +172,8 @@ tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, XftTextExtentsUtf8(ps->dpy, tt->font, text, len, &tt->extents); tt->width = tt->extents.width + 8; + if (tt->width > mini_width) + tt->width = mini_width; tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0); XResizeWindow(ps->dpy, tt->window, tt->width, tt->height); tooltip_move(tt, mouse_x, mouse_y); diff --git a/src/tooltip.h b/src/tooltip.h index 2d1e5e1..829a6d8 100644 --- a/src/tooltip.h +++ b/src/tooltip.h @@ -39,7 +39,7 @@ typedef struct _Tooltip Tooltip; Tooltip *tooltip_create(MainWin *mw); void tooltip_destroy(Tooltip *); -void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, +void tooltip_map(Tooltip *tt, int mini_width, int mouse_x, int mouse_y, const FcChar8 *text, int len); void tooltip_unmap(Tooltip *); void tooltip_handle(Tooltip *, XEvent *); From cfd8a03701d2c677e3a4952d4d18bd70b9555525 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sun, 12 Apr 2020 15:37:03 +0200 Subject: [PATCH 038/205] tooltip: limit width relative to main window Truncating at preview width cuts off too much text from the window title for small previews. Instead of using preview width, calculate the width relative to the main window width. --- src/clientwin.c | 2 +- src/tooltip.c | 10 ++++++---- src/tooltip.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index ec3feae..0c16a81 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -642,7 +642,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { int win_title_len = 0; FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); if (win_title) { - tooltip_map(cw->mainwin->tooltip, cw->mini.width, + tooltip_map(cw->mainwin->tooltip, ev->xcrossing.x_root, ev->xcrossing.y_root, win_title, win_title_len); free(win_title); diff --git a/src/tooltip.c b/src/tooltip.c index bb6c867..048fa85 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -163,17 +163,19 @@ tooltip_create(MainWin *mw) { } void -tooltip_map(Tooltip *tt, int mini_width, int mouse_x, int mouse_y, - const FcChar8 *text, int len) { +tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, + const FcChar8 *text, int len) +{ session_t * const ps = tt->mainwin->ps; + unsigned int max_width = tt->mainwin->width * 0.3; XUnmapWindow(ps->dpy, tt->window); XftTextExtentsUtf8(ps->dpy, tt->font, text, len, &tt->extents); tt->width = tt->extents.width + 8; - if (tt->width > mini_width) - tt->width = mini_width; + if (tt->width > max_width) + tt->width = max_width; tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0); XResizeWindow(ps->dpy, tt->window, tt->width, tt->height); tooltip_move(tt, mouse_x, mouse_y); diff --git a/src/tooltip.h b/src/tooltip.h index 829a6d8..2d1e5e1 100644 --- a/src/tooltip.h +++ b/src/tooltip.h @@ -39,7 +39,7 @@ typedef struct _Tooltip Tooltip; Tooltip *tooltip_create(MainWin *mw); void tooltip_destroy(Tooltip *); -void tooltip_map(Tooltip *tt, int mini_width, int mouse_x, int mouse_y, +void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, const FcChar8 *text, int len); void tooltip_unmap(Tooltip *); void tooltip_handle(Tooltip *, XEvent *); From fe005496a6e1e2cc8875a21f6493948da508a991 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 13 Apr 2020 17:21:28 +0200 Subject: [PATCH 039/205] tooltip: truncate text if it does not fit in max width --- src/tooltip.c | 15 ++++++++++++--- src/tooltip.h | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tooltip.c b/src/tooltip.c index 048fa85..b63b9d6 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -164,18 +164,27 @@ tooltip_create(MainWin *mw) { void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, - const FcChar8 *text, int len) + FcChar8 *text, int len) { session_t * const ps = tt->mainwin->ps; unsigned int max_width = tt->mainwin->width * 0.3; + FcChar8 *ptr; XUnmapWindow(ps->dpy, tt->window); XftTextExtentsUtf8(ps->dpy, tt->font, text, len, &tt->extents); + while (tt->extents.width > max_width) { + ptr = text + len - 1; + *ptr-- = '\0'; + *ptr-- = '.'; + *ptr-- = '.'; + *ptr-- = '.'; + len--; + XftTextExtentsUtf8(ps->dpy, tt->font, text, len, &tt->extents); + } + tt->width = tt->extents.width + 8; - if (tt->width > max_width) - tt->width = max_width; tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0); XResizeWindow(ps->dpy, tt->window, tt->width, tt->height); tooltip_move(tt, mouse_x, mouse_y); diff --git a/src/tooltip.h b/src/tooltip.h index 2d1e5e1..33fa53e 100644 --- a/src/tooltip.h +++ b/src/tooltip.h @@ -40,7 +40,7 @@ typedef struct _Tooltip Tooltip; Tooltip *tooltip_create(MainWin *mw); void tooltip_destroy(Tooltip *); void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, - const FcChar8 *text, int len); + FcChar8 *text, int len); void tooltip_unmap(Tooltip *); void tooltip_handle(Tooltip *, XEvent *); void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y); From 90509426c78b636f28fe40585077bc79b935635c Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 6 Feb 2023 21:44:15 -0800 Subject: [PATCH 040/205] skippy-xd animation --- Makefile | 2 +- skippy-xd.sample.rc | 3 ++- src/anime.c | 58 +++++++++++++++++++++++++++++++++++++++++++++ src/anime.h | 33 ++++++++++++++++++++++++++ src/clientwin.c | 19 +++++++++++---- src/clientwin.h | 2 +- src/skippy.c | 41 +++++++++++++++++++++++++------- src/skippy.h | 4 +++- 8 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 src/anime.c create mode 100644 src/anime.h diff --git a/Makefile b/Makefile index 751a692..d1016b0 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ BINDIR ?= ${PREFIX}/bin CC ?= gcc -SRCS_RAW = skippy wm dlist mainwin clientwin layout focus config tooltip img img-xlib +SRCS_RAW = skippy wm dlist mainwin clientwin layout focus config tooltip img img-xlib anime PACKAGES = x11 xft xrender xcomposite xdamage xfixes # === Options === diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 6292615..92d46b8 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -41,7 +41,8 @@ distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true -updateFreq = 10.0 +updateFreq = 60.0 +animationDuration = 200 lazyTrans = false pipePath = /tmp/skippy-xd-fifo movePointerOnStart = true diff --git a/src/anime.c b/src/anime.c new file mode 100644 index 0000000..17e34c2 --- /dev/null +++ b/src/anime.c @@ -0,0 +1,58 @@ +/* Skippy - Seduces Kids Into Perversion + * + * Copyright (C) 2004 Hyriand + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "anime.h" +#include "skippy.h" + +void anime( + MainWin *mw, + dlist *clients, + float timeslice +) { + clients = dlist_first(clients); + mw->clients = animate_layout(mw, mw->clients, mw->revert_focus_win, None, timeslice); + if (!mw->cod) { + printfef("(): Failed to build layout."); + return; + } +} + +dlist * +animate_layout(MainWin *mw, dlist *clients, Window focus, Window leader, float timeslice) { + wm_get_current_desktop(mw->ps); + + unsigned int width = 0, height = 0; + layout_run(mw, mw->cod, &width, &height); + float factor = (float) (mw->width - (2 * mw->distance)) / width; + if (factor * height > mw->height - (2 * mw->distance)) + factor = (float) (mw->height - (2 * mw->distance)) / height; + if (!mw->ps->o.allowUpscale) + factor = MIN(factor, 1.0f); + + int xoff = (mw->width - (float) width * factor) / 2; + int yoff = (mw->height - (float) height * factor) / 2; + float modified_factor = 1.0 + timeslice * (factor - 1.0); + mainwin_transform(mw, modified_factor); + foreach_dlist (mw->cod) { + clientwin_move((ClientWin *) iter->data, factor, xoff, yoff, timeslice); + clientwin_map((ClientWin*)iter->data); + } + + return clients; +} diff --git a/src/anime.h b/src/anime.h new file mode 100644 index 0000000..8978163 --- /dev/null +++ b/src/anime.h @@ -0,0 +1,33 @@ +/* Skippy - Seduces Kids Into Perversion + * + * Copyright (C) 2004 Hyriand + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ANIME_H +#define ANIME_H + +#include "skippy.h" + +/** + * @brief Perform animation from existing window position to layout positions + */ + +void anime(MainWin *mw, dlist *clients, float timeslice); +int* get_window_positions(MainWin *mw); +dlist * animate_layout(MainWin *mw, dlist *clients, Window focus, Window leader, float fudge); + +#endif /* ANIME_H */ diff --git a/src/clientwin.c b/src/clientwin.c index 1b8ed96..c4bfa47 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -395,12 +395,12 @@ clientwin_schedule_repair(ClientWin *cw, XRectangle *area) } void -clientwin_move(ClientWin *cw, float f, int x, int y) +clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) { /* int border = MAX(1, (double)DISTANCE(cw->mainwin) * f * 0.25); */ int border = 0; XSetWindowBorderWidth(cw->mainwin->ps->dpy, cw->mini.window, border); - + cw->factor = f; cw->mini.x = x + (int)cw->x * f; cw->mini.y = y + (int)cw->y * f; @@ -409,8 +409,19 @@ clientwin_move(ClientWin *cw, float f, int x, int y) cw->mini.x += cw->mainwin->x; cw->mini.y += cw->mainwin->y; } - cw->mini.width = MAX(1, cw->src.width * f); - cw->mini.height = MAX(1, cw->src.height * f); + + { + // animate window by changing these in time linearly: + // here, cw->mini has destination coordinates, cw->src has original coordinates + + cw->mini.x = cw->src.x + (cw->mini.x - cw->src.x) * timeslice; + cw->mini.y = cw->src.y + (cw->mini.y - cw->src.y) * timeslice; + + float ff = 1.0/f + timeslice * (1 - 1.0/f); + cw->mini.width = MAX(1, cw->src.width * f) * ff; + cw->mini.height = MAX(1, cw->src.height * f) * ff; + } + XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); if(cw->pixmap) diff --git a/src/clientwin.h b/src/clientwin.h index 22fbfbe..72c4a41 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -110,7 +110,7 @@ int clientwin_validate_func(dlist *, void *); int clientwin_sort_func(dlist *, dlist *, void *); ClientWin *clientwin_create(MainWin *, Window); void clientwin_destroy(ClientWin *, bool destroyed); -void clientwin_move(ClientWin *, float, int, int); +void clientwin_move(ClientWin *, float, int, int, float); void clientwin_map(ClientWin *); void clientwin_unmap(ClientWin *); int clientwin_handle(ClientWin *, XEvent *); diff --git a/src/skippy.c b/src/skippy.c index a2d37da..6698762 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -18,6 +18,7 @@ */ #include "skippy.h" +#include "anime.h" #include #include #include @@ -390,7 +391,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { return clients; dlist_sort(mw->cod, clientwin_sort_func, 0); - + /* Move the mini windows around */ { unsigned int width = 0, height = 0; @@ -405,7 +406,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { int yoff = (mw->height - (float) height * factor) / 2; mainwin_transform(mw, factor); foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, factor, xoff, yoff); + clientwin_move((ClientWin *) iter->data, factor, xoff, yoff, 1); } } @@ -422,11 +423,6 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { mw->focus->focused = 1; } - // Map the client windows - foreach_dlist (mw->cod) { - clientwin_map((ClientWin*)iter->data); - } - // Unfortunately it does not work... focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); @@ -508,8 +504,8 @@ ev_window(session_t *ps, const XEvent *ev) { case SelectionNotify: return ev->xselection.requestor; } #undef T_SETWID - if (ps->xinfo.damage_ev_base + XDamageNotify == ev->type) - return ((XDamageNotifyEvent *) ev)->drawable; + if (ps->xinfo.damage_ev_base + XDamageNotify == ev->type) + return ((XDamageNotifyEvent *) ev)->drawable; printf("(): Failed to find window for event type %d. Troubles ahead.", ev->type); @@ -599,6 +595,9 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; + bool animating = true; + long first_animated = 0L; + long last_animated = 0L; struct pollfd r_fd[2] = { { @@ -620,12 +619,18 @@ mainloop(session_t *ps, bool activate_on_start) { if (!mw && activate) { assert(ps->mainwin); activate = false; + if (skippy_run_init(ps->mainwin, None)) { last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; pending_damage = false; } + + first_animated = time_in_millis(); + if (ps->o.animationDuration <= 0) { + ps->o.animationDuration = 1; + } } if (mw) activate = false; @@ -668,6 +673,23 @@ mainloop(session_t *ps, bool activate_on_start) { if (activate_on_start && !mw) return; + // animation! + if (animating) { + if(time_in_millis() - last_animated > mw->poll_time) { + last_animated = time_in_millis(); + long timeslice = time_in_millis() - first_animated; + anime(ps->mainwin, ps->mainwin->clients, + ((float)timeslice)/(float)ps->o.animationDuration); + if ( timeslice >= ps->o.animationDuration) { + XSync(ps->dpy, False); + animating = false; + last_rendered = time_in_millis(); + } + + } + continue; // while animating, do not allow user actions + } + // Poll for events int timeout = (pending_damage && mw && mw->poll_time > 0 ? MAX(0, mw->poll_time + last_rendered - time_in_millis()): -1); @@ -1216,6 +1238,7 @@ int main(int argc, char *argv[]) { config_get_bool_wrap(config, "general", "acceptOvRedir", &ps->o.acceptOvRedir); config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); + config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); config_get_bool_wrap(config, "general", "useNameWindowPixmap", &ps->o.useNameWindowPixmap); config_get_bool_wrap(config, "general", "forceNameWindowPixmap", &ps->o.forceNameWindowPixmap); diff --git a/src/skippy.h b/src/skippy.h index 36fe45e..ee5e412 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -208,6 +208,7 @@ typedef struct { bool acceptOvRedir; bool acceptWMWin; double updateFreq; + int animationDuration;; bool lazyTrans; bool useNameWindowPixmap; bool forceNameWindowPixmap; @@ -266,7 +267,8 @@ typedef struct { .ignoreSkipTaskbar = false, \ .acceptOvRedir = false, \ .acceptWMWin = false, \ - .updateFreq = 10.0, \ + .updateFreq = 60.0, \ + .animationDuration = 200, \ .lazyTrans = false, \ .useNameWindowPixmap = false, \ .forceNameWindowPixmap = false, \ From f0ecfc7414b174721f37d73e4c83ff8b87fc2f91 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 10 Feb 2023 14:28:11 -0800 Subject: [PATCH 041/205] Add comment to config file --- skippy-xd.sample.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 55cae96..5a9a4a4 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -48,7 +48,7 @@ distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true updateFreq = 60.0 -animationDuration = 200 +animationDuration = 200 # set = 0 to switch off animations lazyTrans = false pipePath = /tmp/skippy-xd-fifo movePointerOnStart = true From 224eb3185358264632feedfa290a7f3aec7f0dfd Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 10 Feb 2023 16:30:48 -0800 Subject: [PATCH 042/205] layout_run(), do_layout() is called only in init --- src/anime.c | 32 +++++++------------------------- src/anime.h | 2 -- src/clientwin.c | 6 ++---- src/mainwin.h | 6 ++++-- src/skippy.c | 28 +++++++++++++++++----------- 5 files changed, 30 insertions(+), 44 deletions(-) diff --git a/src/anime.c b/src/anime.c index 17e34c2..c6bc6df 100644 --- a/src/anime.c +++ b/src/anime.c @@ -26,33 +26,15 @@ void anime( float timeslice ) { clients = dlist_first(clients); - mw->clients = animate_layout(mw, mw->clients, mw->revert_focus_win, None, timeslice); - if (!mw->cod) { - printfef("(): Failed to build layout."); - return; - } -} - -dlist * -animate_layout(MainWin *mw, dlist *clients, Window focus, Window leader, float timeslice) { wm_get_current_desktop(mw->ps); - - unsigned int width = 0, height = 0; - layout_run(mw, mw->cod, &width, &height); - float factor = (float) (mw->width - (2 * mw->distance)) / width; - if (factor * height > mw->height - (2 * mw->distance)) - factor = (float) (mw->height - (2 * mw->distance)) / height; - if (!mw->ps->o.allowUpscale) - factor = MIN(factor, 1.0f); - - int xoff = (mw->width - (float) width * factor) / 2; - int yoff = (mw->height - (float) height * factor) / 2; - float modified_factor = 1.0 + timeslice * (factor - 1.0); - mainwin_transform(mw, modified_factor); + float multiplier = 1.0 + timeslice * (mw->multiplier - 1.0); + mainwin_transform(mw, multiplier); foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, factor, xoff, yoff, timeslice); + clientwin_move((ClientWin *) iter->data, multiplier, mw->xoff, mw->yoff, timeslice); clientwin_map((ClientWin*)iter->data); } - - return clients; + if (!mw->cod) { + printfef("(): Failed to build layout."); + return; + } } diff --git a/src/anime.h b/src/anime.h index 8978163..ca536bf 100644 --- a/src/anime.h +++ b/src/anime.h @@ -27,7 +27,5 @@ */ void anime(MainWin *mw, dlist *clients, float timeslice); -int* get_window_positions(MainWin *mw); -dlist * animate_layout(MainWin *mw, dlist *clients, Window focus, Window leader, float fudge); #endif /* ANIME_H */ diff --git a/src/clientwin.c b/src/clientwin.c index 2c0ba1e..270df42 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -422,10 +422,8 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) cw->mini.x = cw->src.x + (cw->mini.x - cw->src.x) * timeslice; cw->mini.y = cw->src.y + (cw->mini.y - cw->src.y) * timeslice; - - float ff = 1.0/f + timeslice * (1 - 1.0/f); - cw->mini.width = MAX(1, cw->src.width * f) * ff; - cw->mini.height = MAX(1, cw->src.height * f) * ff; + cw->mini.width = cw->src.width * f; + cw->mini.height = cw->src.height * f; } XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); diff --git a/src/mainwin.h b/src/mainwin.h index 401b567..5889dfd 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -38,8 +38,10 @@ struct _mainwin_t { Window window; Picture background; Pixmap bg_pixmap; - int x, y; - unsigned int width, height, distance; + int x, y, xoff, yoff; + unsigned int width, height, newwidth, newheight, distance; + float multiplier; + XRenderPictFormat *format; XTransform transform; diff --git a/src/skippy.c b/src/skippy.c index 907d915..0e21e04 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -360,7 +360,6 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { session_t * const ps = mw->ps; long desktop = wm_get_current_desktop(ps); - float factor; /* Update the client table, pick the ones we want and sort them */ // printfef("(): updating dl list of clients"); @@ -397,19 +396,26 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { /* Move the mini windows around */ { - unsigned int width = 0, height = 0; - layout_run(mw, mw->cod, &width, &height); - factor = (float) (mw->width - 100) / width; - if (factor * height > mw->height - 100) - factor = (float) (mw->height - 100) / height; + unsigned int newwidth = 0, newheight = 0; + layout_run(mw, mw->cod, &newwidth, &newheight); + float multiplier = (float) (mw->width - 100) / newwidth; + if (multiplier * newheight > mw->height - 100) + multiplier = (float) (mw->height - 100) / newheight; if (!ps->o.allowUpscale) - factor = MIN(factor, 1.0f); + multiplier = MIN(multiplier, 1.0f); - int xoff = (mw->width - (float) width * factor) / 2; - int yoff = (mw->height - (float) height * factor) / 2; - mainwin_transform(mw, factor); + int xoff = (mw->width - (float) newwidth * multiplier) / 2; + int yoff = (mw->height - (float) newheight * multiplier) / 2; + + mw->multiplier = multiplier; + mw->xoff = xoff; + mw->yoff = yoff; + mw->newwidth = newwidth; + mw->newheight = newheight; + + mainwin_transform(mw, multiplier); foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, factor, xoff, yoff, 1); + clientwin_move((ClientWin *) iter->data, multiplier, xoff, yoff, 0); } } From a9adf00dd0fd47487c0ed7b1293638aeb3ad40da Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 11 Feb 2023 18:22:26 -0800 Subject: [PATCH 043/205] New "Boxy" layout, still needs improvement --- src/clientwin.c | 1 + src/clientwin.h | 1 + src/layout.c | 563 +++++++++++++++++++++++++++++++++++++++++++++++- src/layout.h | 7 + src/skippy.c | 6 +- 5 files changed, 572 insertions(+), 6 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 270df42..fcf91c4 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -91,6 +91,7 @@ clientwin_create(MainWin *mw, Window client) { memcpy(cw, &CLIENTWT_DEF, sizeof(ClientWin)); } + cw->slots = 0; cw->mainwin = mw; cw->wid_client = client; if (ps->o.includeFrame) diff --git a/src/clientwin.h b/src/clientwin.h index 72c4a41..5fdb3a2 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -55,6 +55,7 @@ struct _clientwin_t { /* These are virtual positions set by the layout routine */ int x, y; + int slots; }; #define CLIENTWT_INIT { \ diff --git a/src/layout.c b/src/layout.c index 7399a74..a71f64f 100644 --- a/src/layout.c +++ b/src/layout.c @@ -19,11 +19,18 @@ #include "skippy.h" -void -layout_run(MainWin *mw, dlist *windows, +void layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { - // session_t *ps = mw->ps; + layout_boxy(mw, windows, total_width, total_height); +} +// original legacy layout +// +// +void +layout_xd(MainWin *mw, dlist *windows, + unsigned int *total_width, unsigned int *total_height) +{ int sum_w = 0, max_h = 0, max_w = 0; dlist *slots = NULL; @@ -121,3 +128,553 @@ layout_run(MainWin *mw, dlist *windows, dlist_free(rows); } + +// new layout algorithm +// +// +// design principles: +// +// 0. there are non-unique ways to put windows into a screen without overlapping +// 1. for user intuition, we want the layout to be close to the original +// window positions +// 2. when two windows hold identical positions, then we have tradeoffs +// 3. screens are often either long (when rotated 90) or wide, +// and layouts should capitalize on that +// 4. sizes of windows will enlarge/shrink by the same factor, +// since size is an important visual cue to identify windows +// 5. the screen size aspect ratio, +// the windows orignal total occupied screen space aspect ratio, +// (and windows may be overlapping or hold identical spaces, +// and the final occupied screen aspect ratio +// do not have to be the same +// 6. boxy layout slots are more screen efficient, +// as well as being easier for user's eyes +// +// algorithmic concept: +// +// 1. find smallest window size as slot size, +// although rounder aspect ratio is preferred to dramatic aspect ratios +// ( windows are naturally wider than taller) +// 2. form slots that the windows occupy +// *. windows with dramatic aspect ratio are excluded from this +// 3. for all slots with collision, +// if there exists neighbouring empty slot, move it there +// otherwise, insert new row/columns based on screen aspect ratio +// 4. insert to begin/end row/column for dramatic aspect ratio windows +// +// +// algorithm: +// +// 0. exclude windows with dramatic aspect ratios +// 1. scan through windows to find the smallest window size, +// this forms the slot size +// 2. LOOP: +// create 2D array of slots, +// where each element holds the number of windows in that slot, +// map each slot to the occupying windows, +// 3. if there are any empty rows/columns, remove and go to start of loop +// 3. a. expand: +// loop slots right->left, bottom->top, for each slot with collision, +// insert right/below new row/columns based on screen aspect ratio +// move windows to right/down, sorted by "affinity": +// which is the number of slots in that direction minus those +// in opposite direction, times the windows' number of slots +// so the the higher the affinity, the further from the original slot +// b. contract: +// loop slots left->right, top->bottom, for each free slot, +// compare window below, window rightside, window below and right side +// to current slot, sorted by affinity, +// and whether current slots can fit the window +// +// +// +// +// +// +// 4. move windows to slots, to calculate new used screen aspect ratio +// 5. END LOOP when no windows have been moved +// 4. insert begin/end row/column for dramatic aspect ratio windows +// 5. remove empty rows/columns +// +// +// normal window has aspect ratio around (2.5,1) +// dramatic aspect ratio defined as aspect ratio bigger than 10 +// so aspect ratio of (25,1) or (1,4) + +void +layout_boxy(MainWin *mw, dlist *windows, + unsigned int *total_width, unsigned int *total_height) +{ + // ignore dramatic aspect ratioed window for now + // for all desktop searches, + // need to first offset windows by their virtual desktop id + + // find screen aspect ratio + // + float screen_aspect = (float) mw->width / (float) mw->height; + + // find slot size + // also initialize destination position as source position + // + int slot_width=INT_MAX, slot_height=INT_MAX; + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + + slot_width = MIN(slot_width, cw->src.width); + slot_height = MIN(slot_height, cw->src.height); + + cw->x = cw->src.x; + cw->y = cw->src.y; + } + // minimal slot size required, + // otherwise windows too small create round-off issus + if (slot_width < mw->width/5) + slot_width = mw->width/5; + if (slot_height < mw->height/5) + slot_height = mw->height/5; + + printfdf("(): slot size: (%d,%d)", slot_width, slot_height); + + // array declaration + // properly allocated in the beginning of each iteration of the loop + // and freed at the end of the loop + // we declare it here because the final coordinate calculations + // use this 2D array + dlist** slot2cw; + int* slot2n; + int slot_minx=INT_MAX, slot_miny=INT_MAX, + slot_maxx=INT_MIN, slot_maxy=INT_MIN; + +// main calculation loop +bool recalculate = true; +do +{ + recalculate = false; + + // create 2D arrays of slots: + // + // 1. a list of pointers of windows that occupy the slot + // 2. the number of windows on that slot + // + + slot_minx=INT_MAX; slot_miny=INT_MAX; + slot_maxx=INT_MIN; slot_maxy=INT_MIN; + // first do a pass to find the min/max slots, + // so that we can declare the 2D array with the right dimensions + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + + int slotx = round((float) cw->x / (float) slot_width); + int sloty = round((float) cw->y / (float) slot_height); + int slotxx = round((float) (cw->x + cw->src.width) / (float) slot_width); + int slotyy = round((float) (cw->y + cw->src.height) / (float) slot_height); + if (slotxx == slotx) + slotxx++; + if (slotyy == sloty) + slotyy++; + + printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->x, cw->y, cw->src.width, cw->src.height); + printfdf("(): window %p slot: (%d,%d) (%d,%d)", cw, slotx, sloty, slotxx, slotyy); + slot_minx = MIN(slot_minx, slotx); + slot_miny = MIN(slot_miny, sloty); + slot_maxx = MAX(slot_maxx, slotxx); + slot_maxy = MAX(slot_maxy, slotyy); + } + + //printfdf("(): slot maxes: (%d,%d) (%d,%d)", slot_minx, slot_miny, slot_maxx, slot_maxy); + int number_of_slots = (slot_maxx -slot_minx) * (slot_maxy -slot_miny); + + printfdf("(): slot layout: %dx%d, %d slots", + slot_maxx-slot_minx, slot_maxy-slot_miny, number_of_slots); + + // allocate and initailize 2D arrays + // + slot2cw = malloc(number_of_slots * sizeof(dlist*)); + for (int j=slot_miny; jdata; + if (!cw->mode) continue; + + cw->slots = 0; // reset + + int slotx = round((float) cw->x / (float) slot_width); + int sloty = round((float) cw->y / (float) slot_height); + int slotxx = round((float) (cw->x + (float) cw->src.width) / (float) slot_width); + int slotyy = round((float) (cw->y + (float) cw->src.height) / (float) slot_height); + if (slotxx == slotx) + slotxx++; + if (slotyy == sloty) + slotyy++; + + for (int j=sloty; jslots++; + } + } + } + + printf("Slot occupancy:\n"); + for (int j=slot_miny; j 0) + row_empty = false; + } + if (row_empty) { + printfdf("(): prune row %d",j); + foreach_dlist (windows) { + ClientWin *cw = iter->data; + int sloty = round((float) cw->y / (float) slot_height); + if (sloty >= j) + cw->y -= slot_height; + } + recalculate = true; + } + } for (int i=slot_minx; i 0) + column_empty = false; + } + if (column_empty) { + printfdf("(): prune column %d",i); + foreach_dlist (windows) { + ClientWin *cw = iter->data; + int slotx = round((float) cw->x / (float) slot_width); + if (slotx >= i) + cw->x -= slot_width; + } + recalculate = true; + } + } + + // expansion: + // + // loop slots right->left, bottom->top, for each slot with collision, + // insert right/below new row/columns based on screen aspect ratio + // move windows to right/down, sorted by affinity + // + for (int j=slot_maxy-1; !recalculate && j>=slot_miny; j--) { + for (int i=slot_maxx-1; !recalculate && i>=slot_minx; i--) { + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 1) { + recalculate = true; + printfdf("(): Collision on slot (%d,%d) with %d windows", + i, j, slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); + + // insert new row or column + // based on estimated used screen aspect ratio + // we favour adding new row below current slot + int ii = i, jj = j + 1; + float estimated_aspect = (float) (slot_width * slot_maxx) + / (float) (slot_height * slot_maxy); + if (estimated_aspect < screen_aspect * 1.4) { + ii = i + 1; + jj = j; + } + + // find window with highest affinity to neighbouring slot + ClientWin *moving_window = NULL;//dlist_first(slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); + int max_affinity = INT_MIN; + foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { + ClientWin *slotw = (ClientWin*) iter->data; + int affinity = boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j); + max_affinity = MAX(max_affinity, affinity); + printfdf("(): window %p has affinity %d", slotw, affinity); + } + printfdf("(): affinity: %d", max_affinity); + + // move window to right/down + foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { + ClientWin *slotw = (ClientWin*) iter->data; + if (boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j) + == max_affinity) { + moving_window = slotw; + + printfdf("(): moving window %p: (%d,%d) -> (%d,%d)", slotw, i, j, ii, jj); + moving_window->x += (ii - i) * slot_width; + moving_window->y += (jj - j) * slot_height; + goto move_window; + } + } +move_window: + // move all windows right/down of move_window + foreach_dlist (windows) { + ClientWin *cw = (ClientWin*) iter->data; + int cw_slotx = round((float) cw->x / (float) slot_width); + int cw_sloty = round((float) cw->y / (float) slot_height); + if (cw != moving_window) { + + if (ii > i && cw_slotx > i) { + printfdf("(): expand window %p to right: (%d,%d) -> (%d,%d)", cw, i, j, ii, jj); + cw->x += slot_width; + } + else if (jj > j && cw_sloty > j) { + printfdf("(): moving window %p to down: (%d,%d) -> (%d,%d)", cw, i, j, ii, jj); + cw->y += slot_height; + } + } + } + } + } + } + + // contract: + // + // loop slots left->right, top->bottom, for each free slot, + // compare window below, window rightside, window below and right side + // to current slot, sorted by affinity, + // and whether current slots can fit the window + // + for (int j=slot_miny; !recalculate && j 0; + if (slot_occupied[k]) + cw[k] = dlist_first(slot2cw[index])->data; + } + + printfdf("(): windows E(%d) %p S(%d) %p SE(%d) %p", slot_occupied[0], cw[0], slot_occupied[1], cw[1], slot_occupied[2], cw[2]); + + int affinity_e = INT_MIN, + affinity_s = INT_MIN, + affinity_se = INT_MIN; + + if (slot_occupied[0]) + affinity_e = boxy_affinity( cw[0], + slot_width, slot_height, i, j, -ii[0], -jj[0]); + if (slot_occupied[1]) + affinity_s = boxy_affinity( cw[1], + slot_width, slot_height, i, j, -ii[1], -jj[1]); + if (slot_occupied[2]) + affinity_se = boxy_affinity( cw[2], + slot_width, slot_height, i, j, -ii[2], -jj[2]); + + int affinity[3] = {0,0,0}; + affinity[0] = MAX(MAX(affinity_e, affinity_s), affinity_se); + affinity[1] = middleOfThree(affinity_e, affinity_s, affinity_se); + affinity[2] = MIN(MIN(affinity_e, affinity_s), affinity_se); + + printfdf("(): affinities %d %d %d", affinity[0], affinity[1], affinity[2]); + for (int k=0; !recalculate && k<3; k++) { // affinity score + for (int l=0; !recalculate && l<3; l++) { // direction: e, s, se + if (cw[l] && affinity[k] == boxy_affinity( cw[l], + slot_width, slot_height, i, j, -ii[l], -jj[l])) { + + if (ii[l]==0 && jj[l]==0) + continue; + + int slotx = round((float) cw[l]->x / (float) slot_width); + int sloty = round((float) cw[l]->y / (float) slot_height); + int slotxx = round((float) (cw[l]->x + (float) cw[l]->src.width) / (float) slot_width); + int slotyy = round((float) (cw[l]->y + (float) cw[l]->src.height) / (float) slot_height); + bool window_at_ij = slotx==i+ii[l] && sloty==j+jj[l]; + + bool colliding = false; + if (l==0) { // e + for (int yy=j+1; window_at_ij && !colliding + && yyx -= ii[l] * slot_width; + cw[l]->y -= jj[l] * slot_height; + recalculate = true; + } + } + } + } + } + } + } + + if (recalculate) { + free(slot2cw); + free(slot2n); + } +} while (recalculate); + + // move windows to slots, + // from the 2D array calculate the centre of window and move + // + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + cw->x = -cw->src.width / 2 - slot_minx * slot_width; + cw->y = -cw->src.height / 2 - slot_miny * slot_height; + } + for (int j=slot_miny; jdata; + if (!cw->mode) continue; + + cw->x += i * (slot_width + mw->distance) / cw->slots; + cw->y += j * (slot_height + mw->distance) / cw->slots; + } + } + } + + // and finally, calculate new total used screen dimension + // + int minx=INT_MAX, miny=INT_MAX, maxx=INT_MIN, maxy=INT_MIN; + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + //printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->x, cw->y, cw->x+cw->src.width, cw->y+cw->src.height); + + minx = MIN(minx, cw->x); + miny = MIN(miny, cw->y); + maxx = MAX(maxx, cw->x + cw->src.width); + maxy = MAX(maxy, cw->y + cw->src.height); + } + + if (minx < 0) { + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + cw->x -= minx; + } + maxx -= minx; + minx = 0; + } + + if (miny < 0) { + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + cw->y -= miny; + } + maxy -= miny; + miny = 0; + } + + *total_width = maxx - minx; + *total_height = maxy - miny; + + free(slot2cw); + free(slot2n); +} + +int boxy_affinity( + ClientWin *cw, int slot_width, int slot_height, int x, int y, int ii, int jj + // x, y is coordinate the window asks for + // ii, jj is direction of potential move + ) +{ + // cw->src.x cw->src.y should be taken into account also + int slotx = round((float) cw->x / (float) slot_width); + int sloty = round((float) cw->y / (float) slot_height); + int slotxx = round((float) (cw->x + cw->src.width) / (float) slot_width); + int slotyy = round((float) (cw->y + cw->src.height) / (float) slot_height); + + /*if (ii!=0 && ii * slotx < x) + return INT_MIN; + if (jj!=0 && jj * sloty < y) + return INT_MIN;*/ + printfdf("(): affinity for window %p (%d,%d)->(%d,%d) (%d,%d,%d,%d)", + cw, x,y,x+ii,y+jj,slotx,sloty,slotxx,slotyy); + return cw->slots * (ii * (slotxx - x - x + slotx) + + jj * (slotyy - y - y + sloty)); +} + +int middleOfThree(int a, int b, int c) +{ + // x is positive if a is greater than b. + // x is negative if b is greater than a. + int x = a - b; + + int y = b - c; // Similar to x + int z = a - c; // Similar to x and y. + + // Checking if b is middle (x and y both + // are positive) + if (x * y > 0) + return b; + + // Checking if c is middle (x and z both + // are positive) + else if (x * z > 0) + return c; + else + return a; +} diff --git a/src/layout.h b/src/layout.h index 36469ea..1e90909 100644 --- a/src/layout.h +++ b/src/layout.h @@ -20,6 +20,13 @@ #ifndef SKIPPY_LAYOUT_H #define SKIPPY_LAYOUT_H +// calculate and populate windows destination positions +// switches to different layout algorithms based on user/default config void layout_run(MainWin *, dlist *, unsigned int *, unsigned int *); +void layout_xd(MainWin *, dlist *, unsigned int *, unsigned int *); +void layout_boxy(MainWin *, dlist *, unsigned int *, unsigned int *); +int boxy_affinity(ClientWin *, int, int, int, int, int, int); + +int middleOfThree(int a, int b, int c); #endif /* SKIPPY_LAYOUT_H */ diff --git a/src/skippy.c b/src/skippy.c index 0e21e04..78ba238 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -398,9 +398,9 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { { unsigned int newwidth = 0, newheight = 0; layout_run(mw, mw->cod, &newwidth, &newheight); - float multiplier = (float) (mw->width - 100) / newwidth; - if (multiplier * newheight > mw->height - 100) - multiplier = (float) (mw->height - 100) / newheight; + float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; + if (multiplier * newheight > mw->height - 2 * mw->distance) + multiplier = (float) (mw->height - 2 * mw->distance) / newheight; if (!ps->o.allowUpscale) multiplier = MIN(multiplier, 1.0f); From 2620bf06ec188ccdaff1f62e8a85242c6b65bfdf Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 17 Feb 2023 02:10:11 -0800 Subject: [PATCH 044/205] Layout offset for virtual desktops --- src/layout.c | 64 ++++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/src/layout.c b/src/layout.c index a71f64f..52ca5dc 100644 --- a/src/layout.c +++ b/src/layout.c @@ -146,26 +146,12 @@ layout_xd(MainWin *mw, dlist *windows, // the windows orignal total occupied screen space aspect ratio, // (and windows may be overlapping or hold identical spaces, // and the final occupied screen aspect ratio -// do not have to be the same +// do not have to be identical // 6. boxy layout slots are more screen efficient, // as well as being easier for user's eyes // -// algorithmic concept: -// -// 1. find smallest window size as slot size, -// although rounder aspect ratio is preferred to dramatic aspect ratios -// ( windows are naturally wider than taller) -// 2. form slots that the windows occupy -// *. windows with dramatic aspect ratio are excluded from this -// 3. for all slots with collision, -// if there exists neighbouring empty slot, move it there -// otherwise, insert new row/columns based on screen aspect ratio -// 4. insert to begin/end row/column for dramatic aspect ratio windows -// -// // algorithm: // -// 0. exclude windows with dramatic aspect ratios // 1. scan through windows to find the smallest window size, // this forms the slot size // 2. LOOP: @@ -185,16 +171,8 @@ layout_xd(MainWin *mw, dlist *windows, // compare window below, window rightside, window below and right side // to current slot, sorted by affinity, // and whether current slots can fit the window -// -// -// -// -// -// -// 4. move windows to slots, to calculate new used screen aspect ratio -// 5. END LOOP when no windows have been moved -// 4. insert begin/end row/column for dramatic aspect ratio windows -// 5. remove empty rows/columns +// 4. END LOOP when no windows have been moved +// 5. move windows to slots // // // normal window has aspect ratio around (2.5,1) @@ -205,16 +183,13 @@ void layout_boxy(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { - // ignore dramatic aspect ratioed window for now - // for all desktop searches, - // need to first offset windows by their virtual desktop id - // find screen aspect ratio // float screen_aspect = (float) mw->width / (float) mw->height; // find slot size - // also initialize destination position as source position + // offset window positions by virtual desktop + // initialize destination position as source position // int slot_width=INT_MAX, slot_height=INT_MAX; foreach_dlist (windows) { @@ -224,6 +199,10 @@ layout_boxy(MainWin *mw, dlist *windows, slot_width = MIN(slot_width, cw->src.width); slot_height = MIN(slot_height, cw->src.height); + CARD32 desktop = wm_get_window_desktop(mw->ps, cw->wid_client) + - wm_get_current_desktop(mw->ps); + cw->src.x += desktop * mw->width; + cw->x = cw->src.x; cw->y = cw->src.y; } @@ -525,32 +504,39 @@ do bool colliding = false; if (l==0) { // e for (int yy=j+1; window_at_ij && !colliding - && yy Date: Fri, 17 Feb 2023 23:59:32 -0800 Subject: [PATCH 045/205] Fixed pointer and live preview after animation. Potentially related: when I press escape, no window is focused? Shouldn't behaviour be to focus on previously focused window? --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 78ba238..3d953e9 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -738,9 +738,9 @@ mainloop(session_t *ps, bool activate_on_start) { anime(ps->mainwin, ps->mainwin->clients, ((float)timeslice)/(float)ps->o.animationDuration); if ( timeslice >= ps->o.animationDuration) { - XSync(ps->dpy, False); animating = false; last_rendered = time_in_millis(); + focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); } } From 37eaeb82e2195a316685982566d1ab44f0c9bf64 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 17 Feb 2023 23:59:32 -0800 Subject: [PATCH 046/205] Fixed pointer and live preview after animation. Potentially related: when I press escape, no window is focused? Shouldn't behaviour be to focus on previously focused window? --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 0e21e04..3be1537 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -738,9 +738,9 @@ mainloop(session_t *ps, bool activate_on_start) { anime(ps->mainwin, ps->mainwin->clients, ((float)timeslice)/(float)ps->o.animationDuration); if ( timeslice >= ps->o.animationDuration) { - XSync(ps->dpy, False); animating = false; last_rendered = time_in_millis(); + focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); } } From 2129b6a921377401e46090576ef1b0d065fc3ef1 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 18 Feb 2023 00:11:04 -0800 Subject: [PATCH 047/205] Fix white space --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 3be1537..10eb2f8 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -740,7 +740,7 @@ mainloop(session_t *ps, bool activate_on_start) { if ( timeslice >= ps->o.animationDuration) { animating = false; last_rendered = time_in_millis(); - focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); + focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); } } From b3198b2b8194a674a03e3c9125bcde5427c19cb8 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 18 Feb 2023 00:26:01 -0800 Subject: [PATCH 048/205] Fixed white space --- src/skippy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 10eb2f8..16a2203 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -740,7 +740,8 @@ mainloop(session_t *ps, bool activate_on_start) { if ( timeslice >= ps->o.animationDuration) { animating = false; last_rendered = time_in_millis(); - focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); + focus_miniw_adv(ps, mw->client_to_focus, + ps->o.movePointerOnStart); } } From 67fd456d4ca29be0269bd5e833c5e7321e100003 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 18 Feb 2023 01:35:35 -0800 Subject: [PATCH 049/205] Focus on first focused window on cancel event --- src/clientwin.c | 2 +- src/mainwin.h | 2 ++ src/skippy.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/clientwin.c b/src/clientwin.c index 270df42..a766b86 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -544,7 +544,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) { printfef("(): Quitting."); - mw->client_to_focus = NULL; + mw->client_to_focus = mw->client_to_focus_on_cancel; return 1; } diff --git a/src/mainwin.h b/src/mainwin.h index 5889dfd..b3b9557 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -84,6 +84,8 @@ struct _mainwin_t { /// @brief Window ID to revert focus to when the main window is unmapped. Window revert_focus_win; + /// @brief the originally focused window + ClientWin *client_to_focus_on_cancel; /// @brief The client window to eventually focus. ClientWin *client_to_focus; // int ignore_next_refocus; diff --git a/src/skippy.c b/src/skippy.c index 0e21e04..1cbbca7 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -464,6 +464,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { // mw->focus = (ClientWin *) iter->data; mw->client_to_focus = (ClientWin *) iter->data; + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; // mw->focus->focused = 1; From 6558e431ffa3a322e1d7cd0e5fb259d407002d15 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 18 Feb 2023 14:40:31 -0800 Subject: [PATCH 050/205] Differentiate between focus left/right, prev/next --- skippy-xd.sample.rc | 6 ++++-- src/clientwin.c | 38 +++++++++++++++++++++++++++----------- src/mainwin.c | 22 ++++++++++++++++++---- src/mainwin.h | 4 ++++ src/skippy.c | 10 ++++++++-- src/skippy.h | 2 ++ 6 files changed, 63 insertions(+), 19 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 5a9a4a4..ccfdd05 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -99,8 +99,10 @@ miwMouse2 = close-ewmh miwMouse3 = iconify keysUp = Up w keysDown = Down s -keysLeft = Left b a -keysRight = Right Tab f d +keysLeft = Left a +keysRight = Right d +keysPrev = p b +keysNext = n f keysExitCancelOnPress = Escape BackSpace x q keysExitCancelOnRelease = keysExitSelectOnPress = Return space diff --git a/src/clientwin.c b/src/clientwin.c index 270df42..5777112 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -509,36 +509,52 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if(arr_keycodes_includes(cw->mainwin->keycodes_ReverseDirection, evk->keycode)) reverse_direction = true; - if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) + if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) { if(reverse_direction) - focus_miniw_prev(ps, cw); + focus_down(cw); else - focus_miniw_next(ps, cw); + focus_up(cw); + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) + { + if(reverse_direction) + focus_up(cw); + else + focus_down(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Left, evk->keycode)) { if(reverse_direction) - focus_miniw_next(ps, cw); + focus_right(cw); else - focus_miniw_prev(ps, cw); + focus_left(cw); } - else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) + else if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) { if(reverse_direction) - focus_up(cw); + focus_left(cw); else - focus_down(cw); + focus_right(cw); } - else if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) + else if (arr_keycodes_includes(cw->mainwin->keycodes_Prev, evk->keycode)) { if(reverse_direction) - focus_down(cw); + focus_miniw_next(ps, cw); else - focus_up(cw); + focus_miniw_prev(ps, cw); + } + + else if (arr_keycodes_includes(cw->mainwin->keycodes_Next, evk->keycode)) + { + if(reverse_direction) + focus_miniw_prev(ps, cw); + else + focus_miniw_next(ps, cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) diff --git a/src/mainwin.c b/src/mainwin.c index c71d5c9..fcfb61e 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -98,6 +98,8 @@ mainwin_create(session_t *ps) { keys_str_syms(ps->o.bindings_keysDown, &mw->keysyms_Down); keys_str_syms(ps->o.bindings_keysLeft, &mw->keysyms_Left); keys_str_syms(ps->o.bindings_keysRight, &mw->keysyms_Right); + keys_str_syms(ps->o.bindings_keysPrev, &mw->keysyms_Prev); + keys_str_syms(ps->o.bindings_keysNext, &mw->keysyms_Next); keys_str_syms(ps->o.bindings_keysExitCancelOnPress, &mw->keysyms_ExitCancelOnPress); keys_str_syms(ps->o.bindings_keysExitCancelOnRelease, &mw->keysyms_ExitCancelOnRelease); keys_str_syms(ps->o.bindings_keysExitSelectOnPress, &mw->keysyms_ExitSelectOnPress); @@ -112,6 +114,8 @@ mainwin_create(session_t *ps) { keysyms_arr_keycodes(dpy, mw->keysyms_Down, &mw->keycodes_Down); keysyms_arr_keycodes(dpy, mw->keysyms_Left, &mw->keycodes_Left); keysyms_arr_keycodes(dpy, mw->keysyms_Right, &mw->keycodes_Right); + keysyms_arr_keycodes(dpy, mw->keysyms_Prev, &mw->keycodes_Prev); + keysyms_arr_keycodes(dpy, mw->keysyms_Next, &mw->keycodes_Next); keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnPress, &mw->keycodes_ExitCancelOnPress); keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnRelease, &mw->keycodes_ExitCancelOnRelease); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnPress, &mw->keycodes_ExitSelectOnPress); @@ -137,10 +141,18 @@ mainwin_create(session_t *ps) { check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); check_keybindings_conflict(ps->o.config_path, "keysLeft", mw->keysyms_Left, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); - check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); - check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); - check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); - check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Right, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Prev, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Prev, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Prev, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysRight", mw->keysyms_Prev, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysPrev", mw->keysyms_Prev, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysPrev", mw->keysyms_Prev, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysPrev", mw->keysyms_Prev, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysPrev", mw->keysyms_Prev, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysNext", mw->keysyms_Next, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress); + check_keybindings_conflict(ps->o.config_path, "keysNext", mw->keysyms_Next, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); + check_keybindings_conflict(ps->o.config_path, "keysNext", mw->keysyms_Next, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); + check_keybindings_conflict(ps->o.config_path, "keysNext", mw->keysyms_Next, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease); check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnPress", mw->keysyms_ExitCancelOnPress, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); @@ -416,6 +428,8 @@ mainwin_destroy(MainWin *mw) { free(mw->keycodes_Down); free(mw->keycodes_Left); free(mw->keycodes_Right); + free(mw->keycodes_Prev); + free(mw->keycodes_Next); free(mw->keycodes_ExitCancelOnPress); free(mw->keycodes_ExitCancelOnRelease); free(mw->keycodes_ExitSelectOnPress); diff --git a/src/mainwin.h b/src/mainwin.h index 5889dfd..f7234f2 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -57,6 +57,8 @@ struct _mainwin_t { KeySym *keysyms_Down; KeySym *keysyms_Left; KeySym *keysyms_Right; + KeySym *keysyms_Prev; + KeySym *keysyms_Next; KeySym *keysyms_ExitCancelOnPress; KeySym *keysyms_ExitCancelOnRelease; KeySym *keysyms_ExitSelectOnPress; @@ -69,6 +71,8 @@ struct _mainwin_t { KeyCode *keycodes_Down; KeyCode *keycodes_Left; KeyCode *keycodes_Right; + KeyCode *keycodes_Prev; + KeyCode *keycodes_Next; KeyCode *keycodes_ExitCancelOnPress; KeyCode *keycodes_ExitCancelOnRelease; KeyCode *keycodes_ExitSelectOnPress; diff --git a/src/skippy.c b/src/skippy.c index 0e21e04..dfb5935 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1446,8 +1446,10 @@ int main(int argc, char *argv[]) { // load keybindings settings ps->o.bindings_keysUp = mstrdup(config_get(config, "bindings", "keysUp", "Up w")); ps->o.bindings_keysDown = mstrdup(config_get(config, "bindings", "keysDown", "Down s")); - ps->o.bindings_keysLeft = mstrdup(config_get(config, "bindings", "keysLeft", "Left b a")); - ps->o.bindings_keysRight = mstrdup(config_get(config, "bindings", "keysRight", "Right Tab f d")); + ps->o.bindings_keysLeft = mstrdup(config_get(config, "bindings", "keysLeft", "Left a")); + ps->o.bindings_keysRight = mstrdup(config_get(config, "bindings", "keysRight", "Right Tab d")); + ps->o.bindings_keysPrev = mstrdup(config_get(config, "bindings", "keysPrev", "p b")); + ps->o.bindings_keysNext = mstrdup(config_get(config, "bindings", "keysNext", "n f")); ps->o.bindings_keysExitCancelOnPress = mstrdup(config_get(config, "bindings", "keysExitCancelOnPress", "Escape BackSpace x q")); ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitCancelOnRelease", "")); ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitSelectOnPress", "Return space")); @@ -1460,6 +1462,8 @@ int main(int argc, char *argv[]) { check_keysyms(ps->o.config_path, ": [bindings] keysDown =", ps->o.bindings_keysDown); check_keysyms(ps->o.config_path, ": [bindings] keysLeft =", ps->o.bindings_keysLeft); check_keysyms(ps->o.config_path, ": [bindings] keysRight =", ps->o.bindings_keysRight); + check_keysyms(ps->o.config_path, ": [bindings] keysPrev =", ps->o.bindings_keysPrev); + check_keysyms(ps->o.config_path, ": [bindings] keysNext =", ps->o.bindings_keysNext); check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnPress =", ps->o.bindings_keysExitCancelOnPress); check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); @@ -1681,6 +1685,8 @@ int main(int argc, char *argv[]) { free(ps->o.bindings_keysDown); free(ps->o.bindings_keysLeft); free(ps->o.bindings_keysRight); + free(ps->o.bindings_keysPrev); + free(ps->o.bindings_keysNext); free(ps->o.bindings_keysExitCancelOnPress); free(ps->o.bindings_keysExitCancelOnRelease); free(ps->o.bindings_keysExitSelectOnPress); diff --git a/src/skippy.h b/src/skippy.h index 27a458a..5e1d20f 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -265,6 +265,8 @@ typedef struct { char *bindings_keysDown; char *bindings_keysLeft; char *bindings_keysRight; + char *bindings_keysPrev; + char *bindings_keysNext; char *bindings_keysExitCancelOnPress; char *bindings_keysExitCancelOnRelease; char *bindings_keysExitSelectOnPress; From 28c1fe53f7dbd14d418812d899f094f5b60cf5b1 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 18 Feb 2023 21:19:15 -0800 Subject: [PATCH 051/205] Prev/Next window selection ordering --- src/skippy.c | 5 +++++ src/skippy.h | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/skippy.c b/src/skippy.c index dfb5935..e961be2 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -398,6 +398,11 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { { unsigned int newwidth = 0, newheight = 0; layout_run(mw, mw->cod, &newwidth, &newheight); + + // ordering of client windows list + // is important for prev/next window selection + dlist_sort(mw->cod, sort_cw_by_pos, 0); + float multiplier = (float) (mw->width - 100) / newwidth; if (multiplier * newheight > mw->height - 100) multiplier = (float) (mw->height - 100) / newheight; diff --git a/src/skippy.h b/src/skippy.h index 5e1d20f..a197bc3 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1340,6 +1340,23 @@ report_key_modifiers(XKeyEvent *evk) #include "img-gif.h" #endif +static inline int +sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) +{ + ClientWin *cw1 = (ClientWin *) dlist1->data; + ClientWin *cw2 = (ClientWin *) dlist2->data; + if (cw1->y < cw2->y) + return -1; + else if (cw1->y > cw2->y) + return 1; + else if (cw1->x < cw2->x) + return -1; + else if (cw1->x > cw2->x) + return 1; + else + return 0; +} + extern session_t *ps_g; #endif /* SKIPPY_H */ From 2f41d67bb6ee189828c7c0844cb97a5e35128ecb Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 18 Feb 2023 21:19:15 -0800 Subject: [PATCH 052/205] Prev/Next window selection ordering --- src/skippy.c | 5 +++++ src/skippy.h | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/skippy.c b/src/skippy.c index 3d953e9..989c948 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -398,6 +398,11 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { { unsigned int newwidth = 0, newheight = 0; layout_run(mw, mw->cod, &newwidth, &newheight); + + // ordering of client windows list + // is important for prev/next window selection + dlist_sort(mw->cod, sort_cw_by_pos, 0); + float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; if (multiplier * newheight > mw->height - 2 * mw->distance) multiplier = (float) (mw->height - 2 * mw->distance) / newheight; diff --git a/src/skippy.h b/src/skippy.h index 27a458a..229768f 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1338,6 +1338,23 @@ report_key_modifiers(XKeyEvent *evk) #include "img-gif.h" #endif +static inline int +sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) +{ + ClientWin *cw1 = (ClientWin *) dlist1->data; + ClientWin *cw2 = (ClientWin *) dlist2->data; + if (cw1->y < cw2->y) + return -1; + else if (cw1->y > cw2->y) + return 1; + else if (cw1->x < cw2->x) + return -1; + else if (cw1->x > cw2->x) + return 1; + else + return 0; +} + extern session_t *ps_g; #endif /* SKIPPY_H */ From 506044a4307604d9d3cdc052d0fef7e3769c4eda Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 16:45:48 -0800 Subject: [PATCH 053/205] Fix slot off-by-one error --- src/layout.c | 94 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/src/layout.c b/src/layout.c index 52ca5dc..7566b8b 100644 --- a/src/layout.c +++ b/src/layout.c @@ -19,6 +19,24 @@ #include "skippy.h" +// this is the "abstract" function to determine exposd window layout +// if you want to introduce new layout algorithm/implementation, +// do it here +// by introducing new function and hook here +// +// here, ((ClientWin*) windows)->src.x, ((ClientWin*) windows)->src.y +// hold the original coordinates +// ((ClientWin*) windows)->src.width, ((ClientWin*) windows)->src.height +// hold the window size +// ((ClientWin*) windows)->x, ((ClientWin*) windows)->y +// hold the final window position +// better NOT to change the final window size... +// which is implicitly handled by MainWin transformation +// +// in summary, use this function to implement the exposed layout +// by controlling the windows position +// and calculating the final screen width and height +// = total windows width and height + minimal distance between windows void layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { layout_boxy(mw, windows, total_width, total_height); @@ -245,14 +263,14 @@ do ClientWin *cw = (ClientWin *) iter->data; if (!cw->mode) continue; - int slotx = round((float) cw->x / (float) slot_width); - int sloty = round((float) cw->y / (float) slot_height); - int slotxx = round((float) (cw->x + cw->src.width) / (float) slot_width); - int slotyy = round((float) (cw->y + cw->src.height) / (float) slot_height); - if (slotxx == slotx) + int slotx = floor((float) cw->x / (float) slot_width); + int sloty = floor((float) cw->y / (float) slot_height); + int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); + /*if (slotxx == slotx) slotxx++; if (slotyy == sloty) - slotyy++; + slotyy++;*/ printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->x, cw->y, cw->src.width, cw->src.height); printfdf("(): window %p slot: (%d,%d) (%d,%d)", cw, slotx, sloty, slotxx, slotyy); @@ -292,10 +310,10 @@ do cw->slots = 0; // reset - int slotx = round((float) cw->x / (float) slot_width); - int sloty = round((float) cw->y / (float) slot_height); - int slotxx = round((float) (cw->x + (float) cw->src.width) / (float) slot_width); - int slotyy = round((float) (cw->y + (float) cw->src.height) / (float) slot_height); + int slotx = floor((float) cw->x / (float) slot_width); + int sloty = floor((float) cw->y / (float) slot_height); + int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); if (slotxx == slotx) slotxx++; if (slotyy == sloty) @@ -344,7 +362,7 @@ do printfdf("(): prune row %d",j); foreach_dlist (windows) { ClientWin *cw = iter->data; - int sloty = round((float) cw->y / (float) slot_height); + int sloty = floor((float) cw->y / (float) slot_height); if (sloty >= j) cw->y -= slot_height; } @@ -360,7 +378,7 @@ do printfdf("(): prune column %d",i); foreach_dlist (windows) { ClientWin *cw = iter->data; - int slotx = round((float) cw->x / (float) slot_width); + int slotx = floor((float) cw->x / (float) slot_width); if (slotx >= i) cw->x -= slot_width; } @@ -420,8 +438,8 @@ do // move all windows right/down of move_window foreach_dlist (windows) { ClientWin *cw = (ClientWin*) iter->data; - int cw_slotx = round((float) cw->x / (float) slot_width); - int cw_sloty = round((float) cw->y / (float) slot_height); + int cw_slotx = floor((float) cw->x / (float) slot_width); + int cw_sloty = floor((float) cw->y / (float) slot_height); if (cw != moving_window) { if (ii > i && cw_slotx > i) { @@ -495,10 +513,10 @@ do if (ii[l]==0 && jj[l]==0) continue; - int slotx = round((float) cw[l]->x / (float) slot_width); - int sloty = round((float) cw[l]->y / (float) slot_height); - int slotxx = round((float) (cw[l]->x + (float) cw[l]->src.width) / (float) slot_width); - int slotyy = round((float) (cw[l]->y + (float) cw[l]->src.height) / (float) slot_height); + int slotx = floor((float) cw[l]->x / (float) slot_width); + int sloty = floor((float) cw[l]->y / (float) slot_height); + int slotxx = slotx + ceil((float) cw[l]->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) cw[l]->src.height / (float) slot_height); bool window_at_ij = slotx==i+ii[l] && sloty==j+jj[l]; bool colliding = false; @@ -580,6 +598,38 @@ do } } + // arrange windows ordering by left->right, top->bottom + // so we can put in windows offset, + // rather than having overlapping windows + // which is not desirable for user experience, + // nor allowable for focus_left() focus_right() etc + /*dlist_sort(windows, sort_cw_by_pos, 0); + + int row_y = INT_MIN; + foreach_dlist (windows) { + while (iter->prev == NULL) { + iter = iter->next; + } + ClientWin *cw = (ClientWin *) iter->data; + + ClientWin *prev = (ClientWin *) iter->prev->data; + if (!cw->mode) continue; + if (cw->x <= prev->x) { // new row + if (cw->y <= prev->y + prev->src.height + mw->distance) { +printfdf("() AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + cw->y = MAX(cw->y, + prev->y + prev->src.height + mw->distance); + row_y = cw->y + cw->src.height; + } + } + else { // new column + if (cw->x <= prev->x + prev->src.width + mw->distance) { +printfdf("() BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB (%d,%d)",cw->x,cw->y); + cw->x = prev->x + prev->src.width + mw->distance; + } + } + }*/ + // and finally, calculate new total used screen dimension // int minx=INT_MAX, miny=INT_MAX, maxx=INT_MIN, maxy=INT_MIN; @@ -628,10 +678,10 @@ int boxy_affinity( ) { // cw->src.x cw->src.y should be taken into account also - int slotx = round((float) cw->x / (float) slot_width); - int sloty = round((float) cw->y / (float) slot_height); - int slotxx = round((float) (cw->x + cw->src.width) / (float) slot_width); - int slotyy = round((float) (cw->y + cw->src.height) / (float) slot_height); + int slotx = floor((float) cw->x / (float) slot_width); + int sloty = floor((float) cw->y / (float) slot_height); + int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); /*if (ii!=0 && ii * slotx < x) return INT_MIN; From 9d6ac569bc0054e02d5ecde35151863fa4f2c4ba Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 17:09:26 -0800 Subject: [PATCH 054/205] Remove bogus mouse movement --- src/skippy.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 12a4018..9a159ed 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -478,11 +478,6 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { } - // Unfortunately it does not work... - // focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); - focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); - // clientwin_render(mw->client_to_focus); - return clients; } From 5d556bd2429c96df130bb516e390cf4915f3455b Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 17:29:40 -0800 Subject: [PATCH 055/205] Next/prev ordering by column rather than row --- src/skippy.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/skippy.h b/src/skippy.h index a197bc3..5e8ef39 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1345,13 +1345,13 @@ sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) { ClientWin *cw1 = (ClientWin *) dlist1->data; ClientWin *cw2 = (ClientWin *) dlist2->data; - if (cw1->y < cw2->y) + if (cw1->x < cw2->x) return -1; - else if (cw1->y > cw2->y) + else if (cw1->x > cw2->x) return 1; - else if (cw1->x < cw2->x) + else if (cw1->y < cw2->y) return -1; - else if (cw1->x > cw2->x) + else if (cw1->y > cw2->y) return 1; else return 0; From 85d873f88bc36f7a25f563a1a076d15d7886e24e Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 17:51:45 -0800 Subject: [PATCH 056/205] Alt-Tab requires window order based on stack --- src/skippy.c | 68 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 12a4018..817765d 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -394,40 +394,6 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { dlist_sort(mw->cod, clientwin_sort_func, 0); - /* Move the mini windows around */ - { - unsigned int newwidth = 0, newheight = 0; - layout_run(mw, mw->cod, &newwidth, &newheight); - - // ordering of client windows list - // is important for prev/next window selection - dlist_sort(mw->cod, sort_cw_by_pos, 0); - - float multiplier = (float) (mw->width - 100) / newwidth; - if (multiplier * newheight > mw->height - 100) - multiplier = (float) (mw->height - 100) / newheight; - if (!ps->o.allowUpscale) - multiplier = MIN(multiplier, 1.0f); - - int xoff = (mw->width - (float) newwidth * multiplier) / 2; - int yoff = (mw->height - (float) newheight * multiplier) / 2; - - mw->multiplier = multiplier; - mw->xoff = xoff; - mw->yoff = yoff; - mw->newwidth = newwidth; - mw->newheight = newheight; - - mainwin_transform(mw, multiplier); - foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, multiplier, xoff, yoff, 0); - } - } - - foreach_dlist(mw->cod) { - clientwin_update2((ClientWin *) iter->data); - } - // Get the currently focused window and select which mini-window to focus { dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) focus); @@ -478,6 +444,40 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { } + /* Move the mini windows around */ + { + unsigned int newwidth = 0, newheight = 0; + layout_run(mw, mw->cod, &newwidth, &newheight); + + // ordering of client windows list + // is important for prev/next window selection + dlist_sort(mw->cod, sort_cw_by_pos, 0); + + float multiplier = (float) (mw->width - 100) / newwidth; + if (multiplier * newheight > mw->height - 100) + multiplier = (float) (mw->height - 100) / newheight; + if (!ps->o.allowUpscale) + multiplier = MIN(multiplier, 1.0f); + + int xoff = (mw->width - (float) newwidth * multiplier) / 2; + int yoff = (mw->height - (float) newheight * multiplier) / 2; + + mw->multiplier = multiplier; + mw->xoff = xoff; + mw->yoff = yoff; + mw->newwidth = newwidth; + mw->newheight = newheight; + + mainwin_transform(mw, multiplier); + foreach_dlist (mw->cod) { + clientwin_move((ClientWin *) iter->data, multiplier, xoff, yoff, 0); + } + } + + foreach_dlist(mw->cod) { + clientwin_update2((ClientWin *) iter->data); + } + // Unfortunately it does not work... // focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); From dc175e661de7741cc5607b24c555e69dfa1b2f9d Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 18:22:34 -0800 Subject: [PATCH 057/205] Comment out printfs and tidy white space --- src/layout.c | 698 ++++++++++++++++++++++++--------------------------- 1 file changed, 331 insertions(+), 367 deletions(-) diff --git a/src/layout.c b/src/layout.c index 7566b8b..1f5d663 100644 --- a/src/layout.c +++ b/src/layout.c @@ -39,7 +39,7 @@ // = total windows width and height + minimal distance between windows void layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { - layout_boxy(mw, windows, total_width, total_height); + layout_boxy(mw, windows, total_width, total_height); } // original legacy layout @@ -201,45 +201,45 @@ void layout_boxy(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { - // find screen aspect ratio - // - float screen_aspect = (float) mw->width / (float) mw->height; - - // find slot size - // offset window positions by virtual desktop - // initialize destination position as source position - // + // find screen aspect ratio + // + float screen_aspect = (float) mw->width / (float) mw->height; + + // find slot size + // offset window positions by virtual desktop + // initialize destination position as source position + // int slot_width=INT_MAX, slot_height=INT_MAX; foreach_dlist (windows) { ClientWin *cw = (ClientWin *) iter->data; if (!cw->mode) continue; - slot_width = MIN(slot_width, cw->src.width); + slot_width = MIN(slot_width, cw->src.width); slot_height = MIN(slot_height, cw->src.height); - CARD32 desktop = wm_get_window_desktop(mw->ps, cw->wid_client) - - wm_get_current_desktop(mw->ps); - cw->src.x += desktop * mw->width; + CARD32 desktop = wm_get_window_desktop(mw->ps, cw->wid_client) + - wm_get_current_desktop(mw->ps); + cw->src.x += desktop * mw->width; - cw->x = cw->src.x; - cw->y = cw->src.y; + cw->x = cw->src.x; + cw->y = cw->src.y; } - // minimal slot size required, - // otherwise windows too small create round-off issus - if (slot_width < mw->width/5) - slot_width = mw->width/5; - if (slot_height < mw->height/5) - slot_height = mw->height/5; - - printfdf("(): slot size: (%d,%d)", slot_width, slot_height); - - // array declaration - // properly allocated in the beginning of each iteration of the loop - // and freed at the end of the loop - // we declare it here because the final coordinate calculations - // use this 2D array - dlist** slot2cw; - int* slot2n; + // minimal slot size required, + // otherwise windows too small create round-off issus + if (slot_width < mw->width/5) + slot_width = mw->width/5; + if (slot_height < mw->height/5) + slot_height = mw->height/5; + + //printfdf("(): slot size: (%d,%d)", slot_width, slot_height); + + // array declaration + // properly allocated in the beginning of each iteration of the loop + // and freed at the end of the loop + // we declare it here because the final coordinate calculations + // use this 2D array + dlist** slot2cw; + int* slot2n; int slot_minx=INT_MAX, slot_miny=INT_MAX, slot_maxx=INT_MIN, slot_maxy=INT_MIN; @@ -247,7 +247,7 @@ layout_boxy(MainWin *mw, dlist *windows, bool recalculate = true; do { - recalculate = false; + recalculate = false; // create 2D arrays of slots: // @@ -267,13 +267,9 @@ do int sloty = floor((float) cw->y / (float) slot_height); int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); - /*if (slotxx == slotx) - slotxx++; - if (slotyy == sloty) - slotyy++;*/ - printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->x, cw->y, cw->src.width, cw->src.height); - printfdf("(): window %p slot: (%d,%d) (%d,%d)", cw, slotx, sloty, slotxx, slotyy); + //printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->x, cw->y, cw->src.width, cw->src.height); + //printfdf("(): window %p slot: (%d,%d) (%d,%d)", cw, slotx, sloty, slotxx, slotyy); slot_minx = MIN(slot_minx, slotx); slot_miny = MIN(slot_miny, sloty); slot_maxx = MAX(slot_maxx, slotxx); @@ -283,19 +279,19 @@ do //printfdf("(): slot maxes: (%d,%d) (%d,%d)", slot_minx, slot_miny, slot_maxx, slot_maxy); int number_of_slots = (slot_maxx -slot_minx) * (slot_maxy -slot_miny); - printfdf("(): slot layout: %dx%d, %d slots", - slot_maxx-slot_minx, slot_maxy-slot_miny, number_of_slots); + //printfdf("(): slot layout: %dx%d, %d slots", + //slot_maxx-slot_minx, slot_maxy-slot_miny, number_of_slots); // allocate and initailize 2D arrays - // - slot2cw = malloc(number_of_slots * sizeof(dlist*)); + // + slot2cw = malloc(number_of_slots * sizeof(dlist*)); for (int j=slot_miny; jdata; if (!cw->mode) continue; - cw->slots = 0; // reset + cw->slots = 0; // reset int slotx = floor((float) cw->x / (float) slot_width); int sloty = floor((float) cw->y / (float) slot_height); int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); - if (slotxx == slotx) - slotxx++; - if (slotyy == sloty) - slotyy++; + if (slotxx == slotx) + slotxx++; + if (slotyy == sloty) + slotyy++; for (int j=sloty; jslots++; + cw->slots++; } } } - printf("Slot occupancy:\n"); + /*printf("Slot occupancy:\n"); for (int j=slot_miny; j 0) - row_empty = false; + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 0) + row_empty = false; + } + if (row_empty) { + //printfdf("(): prune row %d",j); + foreach_dlist (windows) { + ClientWin *cw = iter->data; + int sloty = floor((float) cw->y / (float) slot_height); + if (sloty >= j) + cw->y -= slot_height; + } + recalculate = true; } - if (row_empty) { - printfdf("(): prune row %d",j); - foreach_dlist (windows) { - ClientWin *cw = iter->data; - int sloty = floor((float) cw->y / (float) slot_height); - if (sloty >= j) - cw->y -= slot_height; - } - recalculate = true; - } } for (int i=slot_minx; i 0) - column_empty = false; + bool column_empty = true; + for (int j=slot_miny; column_empty && j 0) + column_empty = false; + } + if (column_empty) { + //printfdf("(): prune column %d",i); + foreach_dlist (windows) { + ClientWin *cw = iter->data; + int slotx = floor((float) cw->x / (float) slot_width); + if (slotx >= i) + cw->x -= slot_width; + } + recalculate = true; } - if (column_empty) { - printfdf("(): prune column %d",i); - foreach_dlist (windows) { - ClientWin *cw = iter->data; - int slotx = floor((float) cw->x / (float) slot_width); - if (slotx >= i) - cw->x -= slot_width; - } - recalculate = true; - } } - // expansion: - // - // loop slots right->left, bottom->top, for each slot with collision, - // insert right/below new row/columns based on screen aspect ratio - // move windows to right/down, sorted by affinity - // + // expansion: + // + // loop slots right->left, bottom->top, for each slot with collision, + // insert right/below new row/columns based on screen aspect ratio + // move windows to right/down, sorted by affinity + // for (int j=slot_maxy-1; !recalculate && j>=slot_miny; j--) { for (int i=slot_maxx-1; !recalculate && i>=slot_minx; i--) { - if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 1) { - recalculate = true; - printfdf("(): Collision on slot (%d,%d) with %d windows", - i, j, slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); - - // insert new row or column - // based on estimated used screen aspect ratio - // we favour adding new row below current slot - int ii = i, jj = j + 1; - float estimated_aspect = (float) (slot_width * slot_maxx) - / (float) (slot_height * slot_maxy); - if (estimated_aspect < screen_aspect * 1.4) { - ii = i + 1; - jj = j; - } - - // find window with highest affinity to neighbouring slot - ClientWin *moving_window = NULL;//dlist_first(slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); - int max_affinity = INT_MIN; - foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { - ClientWin *slotw = (ClientWin*) iter->data; - int affinity = boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j); - max_affinity = MAX(max_affinity, affinity); - printfdf("(): window %p has affinity %d", slotw, affinity); - } - printfdf("(): affinity: %d", max_affinity); - - // move window to right/down - foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { - ClientWin *slotw = (ClientWin*) iter->data; - if (boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j) - == max_affinity) { - moving_window = slotw; - - printfdf("(): moving window %p: (%d,%d) -> (%d,%d)", slotw, i, j, ii, jj); - moving_window->x += (ii - i) * slot_width; - moving_window->y += (jj - j) * slot_height; - goto move_window; - } - } + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 1) { + recalculate = true; + //printfdf("(): Collision on slot (%d,%d) with %d windows", + //i, j, slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); + + // insert new row or column + // based on estimated used screen aspect ratio + // we favour adding new row below current slot + int ii = i, jj = j + 1; + float estimated_aspect = (float) (slot_width * slot_maxx) + / (float) (slot_height * slot_maxy); + if (estimated_aspect < screen_aspect * 1.4) { + ii = i + 1; + jj = j; + } + + // find window with highest affinity to neighbouring slot + ClientWin *moving_window = NULL;//dlist_first(slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); + int max_affinity = INT_MIN; + foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { + ClientWin *slotw = (ClientWin*) iter->data; + int affinity = boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j); + max_affinity = MAX(max_affinity, affinity); + //printfdf("(): window %p has affinity %d", slotw, affinity); + } + //printfdf("(): affinity: %d", max_affinity); + + // move window to right/down + foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { + ClientWin *slotw = (ClientWin*) iter->data; + if (boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j) + == max_affinity) { + moving_window = slotw; + + //printfdf("(): moving window %p: (%d,%d) -> (%d,%d)", slotw, i, j, ii, jj); + moving_window->x += (ii - i) * slot_width; + moving_window->y += (jj - j) * slot_height; + goto move_window; + } + } move_window: - // move all windows right/down of move_window - foreach_dlist (windows) { - ClientWin *cw = (ClientWin*) iter->data; - int cw_slotx = floor((float) cw->x / (float) slot_width); - int cw_sloty = floor((float) cw->y / (float) slot_height); - if (cw != moving_window) { - - if (ii > i && cw_slotx > i) { - printfdf("(): expand window %p to right: (%d,%d) -> (%d,%d)", cw, i, j, ii, jj); - cw->x += slot_width; - } - else if (jj > j && cw_sloty > j) { - printfdf("(): moving window %p to down: (%d,%d) -> (%d,%d)", cw, i, j, ii, jj); - cw->y += slot_height; - } - } - } - } - } + // move all windows right/down of move_window + foreach_dlist (windows) { + ClientWin *cw = (ClientWin*) iter->data; + int cw_slotx = floor((float) cw->x / (float) slot_width); + int cw_sloty = floor((float) cw->y / (float) slot_height); + if (cw != moving_window) { + + if (ii > i && cw_slotx > i) { + //printfdf("(): expand window %p to right: (%d,%d) -> (%d,%d)", cw, i, j, ii, jj); + cw->x += slot_width; + } + else if (jj > j && cw_sloty > j) { + //printfdf("(): moving window %p to down: (%d,%d) -> (%d,%d)", cw, i, j, ii, jj); + cw->y += slot_height; + } + } + } + } + } } - // contract: - // - // loop slots left->right, top->bottom, for each free slot, - // compare window below, window rightside, window below and right side - // to current slot, sorted by affinity, - // and whether current slots can fit the window - // + // contract: + // + // loop slots left->right, top->bottom, for each free slot, + // compare window below, window rightside, window below and right side + // to current slot, sorted by affinity, + // and whether current slots can fit the window + // for (int j=slot_miny; !recalculate && j 0; - if (slot_occupied[k]) - cw[k] = dlist_first(slot2cw[index])->data; - } - - printfdf("(): windows E(%d) %p S(%d) %p SE(%d) %p", slot_occupied[0], cw[0], slot_occupied[1], cw[1], slot_occupied[2], cw[2]); - - int affinity_e = INT_MIN, - affinity_s = INT_MIN, - affinity_se = INT_MIN; - - if (slot_occupied[0]) - affinity_e = boxy_affinity( cw[0], - slot_width, slot_height, i, j, -ii[0], -jj[0]); - if (slot_occupied[1]) - affinity_s = boxy_affinity( cw[1], - slot_width, slot_height, i, j, -ii[1], -jj[1]); - if (slot_occupied[2]) - affinity_se = boxy_affinity( cw[2], - slot_width, slot_height, i, j, -ii[2], -jj[2]); - - int affinity[3] = {0,0,0}; - affinity[0] = MAX(MAX(affinity_e, affinity_s), affinity_se); - affinity[1] = middleOfThree(affinity_e, affinity_s, affinity_se); - affinity[2] = MIN(MIN(affinity_e, affinity_s), affinity_se); - - printfdf("(): affinities %d %d %d", affinity[0], affinity[1], affinity[2]); - for (int k=0; !recalculate && k<3; k++) { // affinity score - for (int l=0; !recalculate && l<3; l++) { // direction: e, s, se - if (cw[l] && affinity[k] == boxy_affinity( cw[l], - slot_width, slot_height, i, j, -ii[l], -jj[l])) { - - if (ii[l]==0 && jj[l]==0) - continue; - - int slotx = floor((float) cw[l]->x / (float) slot_width); - int sloty = floor((float) cw[l]->y / (float) slot_height); - int slotxx = slotx + ceil((float) cw[l]->src.width / (float) slot_width); - int slotyy = sloty + ceil((float) cw[l]->src.height / (float) slot_height); - bool window_at_ij = slotx==i+ii[l] && sloty==j+jj[l]; - - bool colliding = false; - if (l==0) { // e - for (int yy=j+1; window_at_ij && !colliding - && yyx -= ii[l] * slot_width; - cw[l]->y -= jj[l] * slot_height; - recalculate = true; - } - } - } - } - } - } - } - - if (recalculate) { - free(slot2cw); - free(slot2n); - } + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] == 0) { + //printfdf("(): free slot for compacting at (%d %d)",i, j); + + // indices correspond to east, south, southeast + int ii[3] = { i + 1 < slot_maxx, 0, i + 1 < slot_maxx }; + int jj[3] = { 0, j + 1 < slot_maxy, j + 1 < slot_maxy }; + //for (int k=0; k<3; k++) + //printfdf("(): (%d,%d) (%d,%d) (%d,%d)",i,j,ii[k],jj[k],slot_maxx,slot_maxy); + + bool slot_occupied[3] = {false,false,false}; + ClientWin *cw[3] = {NULL,NULL,NULL}; + for (int k=0; k<3; k++) { + int index = (j-slot_miny+jj[k]) * (slot_maxx - slot_minx) + i-slot_minx+ii[k]; + slot_occupied[k] = slot2n[index] > 0; + if (slot_occupied[k]) + cw[k] = dlist_first(slot2cw[index])->data; + } + + //printfdf("(): windows E(%d) %p S(%d) %p SE(%d) %p", slot_occupied[0], cw[0], slot_occupied[1], cw[1], slot_occupied[2], cw[2]); + + int affinity_e = INT_MIN, + affinity_s = INT_MIN, + affinity_se = INT_MIN; + + if (slot_occupied[0]) + affinity_e = boxy_affinity( cw[0], + slot_width, slot_height, i, j, -ii[0], -jj[0]); + if (slot_occupied[1]) + affinity_s = boxy_affinity( cw[1], + slot_width, slot_height, i, j, -ii[1], -jj[1]); + if (slot_occupied[2]) + affinity_se = boxy_affinity( cw[2], + slot_width, slot_height, i, j, -ii[2], -jj[2]); + + int affinity[3] = {0,0,0}; + affinity[0] = MAX(MAX(affinity_e, affinity_s), affinity_se); + affinity[1] = middleOfThree(affinity_e, affinity_s, affinity_se); + affinity[2] = MIN(MIN(affinity_e, affinity_s), affinity_se); + + //printfdf("(): affinities %d %d %d", affinity[0], affinity[1], affinity[2]); + for (int k=0; !recalculate && k<3; k++) { // affinity score + for (int l=0; !recalculate && l<3; l++) { // direction: e, s, se + if (cw[l] && affinity[k] == boxy_affinity( cw[l], + slot_width, slot_height, i, j, -ii[l], -jj[l])) { + + if (ii[l]==0 && jj[l]==0) + continue; + + int slotx = floor((float) cw[l]->x / (float) slot_width); + int sloty = floor((float) cw[l]->y / (float) slot_height); + int slotxx = slotx + ceil((float) cw[l]->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) cw[l]->src.height / (float) slot_height); + bool window_at_ij = slotx==i+ii[l] && sloty==j+jj[l]; + + bool colliding = false; + if (l==0) { // e + for (int yy=j+1; window_at_ij && !colliding + && yyx -= ii[l] * slot_width; + cw[l]->y -= jj[l] * slot_height; + recalculate = true; + } + } + } + } + } + } + } + + if (recalculate) { + free(slot2cw); + free(slot2n); + } } while (recalculate); // move windows to slots, // from the 2D array calculate the centre of window and move - // + // foreach_dlist (windows) { ClientWin *cw = (ClientWin *) iter->data; if (!cw->mode) continue; @@ -598,119 +594,87 @@ do } } - // arrange windows ordering by left->right, top->bottom - // so we can put in windows offset, - // rather than having overlapping windows - // which is not desirable for user experience, - // nor allowable for focus_left() focus_right() etc - /*dlist_sort(windows, sort_cw_by_pos, 0); - - int row_y = INT_MIN; - foreach_dlist (windows) { - while (iter->prev == NULL) { - iter = iter->next; - } - ClientWin *cw = (ClientWin *) iter->data; - - ClientWin *prev = (ClientWin *) iter->prev->data; - if (!cw->mode) continue; - if (cw->x <= prev->x) { // new row - if (cw->y <= prev->y + prev->src.height + mw->distance) { -printfdf("() AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - cw->y = MAX(cw->y, - prev->y + prev->src.height + mw->distance); - row_y = cw->y + cw->src.height; - } - } - else { // new column - if (cw->x <= prev->x + prev->src.width + mw->distance) { -printfdf("() BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB (%d,%d)",cw->x,cw->y); - cw->x = prev->x + prev->src.width + mw->distance; - } - } - }*/ - // and finally, calculate new total used screen dimension // int minx=INT_MAX, miny=INT_MAX, maxx=INT_MIN, maxy=INT_MIN; - foreach_dlist (windows) { - ClientWin *cw = (ClientWin *) iter->data; - if (!cw->mode) continue; + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; //printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->x, cw->y, cw->x+cw->src.width, cw->y+cw->src.height); - minx = MIN(minx, cw->x); - miny = MIN(miny, cw->y); - maxx = MAX(maxx, cw->x + cw->src.width); - maxy = MAX(maxy, cw->y + cw->src.height); - } - - if (minx < 0) { - foreach_dlist (windows) { - ClientWin *cw = (ClientWin *) iter->data; - if (!cw->mode) continue; - cw->x -= minx; - } - maxx -= minx; - minx = 0; - } - - if (miny < 0) { - foreach_dlist (windows) { - ClientWin *cw = (ClientWin *) iter->data; - if (!cw->mode) continue; - cw->y -= miny; - } - maxy -= miny; - miny = 0; - } + minx = MIN(minx, cw->x); + miny = MIN(miny, cw->y); + maxx = MAX(maxx, cw->x + cw->src.width); + maxy = MAX(maxy, cw->y + cw->src.height); + } + + if (minx < 0) { + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + cw->x -= minx; + } + maxx -= minx; + minx = 0; + } + + if (miny < 0) { + foreach_dlist (windows) { + ClientWin *cw = (ClientWin *) iter->data; + if (!cw->mode) continue; + cw->y -= miny; + } + maxy -= miny; + miny = 0; + } *total_width = maxx - minx; *total_height = maxy - miny; - free(slot2cw); - free(slot2n); + free(slot2cw); + free(slot2n); } int boxy_affinity( - ClientWin *cw, int slot_width, int slot_height, int x, int y, int ii, int jj - // x, y is coordinate the window asks for - // ii, jj is direction of potential move - ) + ClientWin *cw, int slot_width, int slot_height, int x, int y, int ii, int jj + // x, y is coordinate the window asks for + // ii, jj is direction of potential move + ) { - // cw->src.x cw->src.y should be taken into account also - int slotx = floor((float) cw->x / (float) slot_width); - int sloty = floor((float) cw->y / (float) slot_height); - int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); - int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); - - /*if (ii!=0 && ii * slotx < x) - return INT_MIN; - if (jj!=0 && jj * sloty < y) - return INT_MIN;*/ - printfdf("(): affinity for window %p (%d,%d)->(%d,%d) (%d,%d,%d,%d)", - cw, x,y,x+ii,y+jj,slotx,sloty,slotxx,slotyy); - return cw->slots * (ii * (slotxx - x - x + slotx) - + jj * (slotyy - y - y + sloty)); + // cw->src.x cw->src.y should be taken into account also + int slotx = floor((float) cw->x / (float) slot_width); + int sloty = floor((float) cw->y / (float) slot_height); + int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); + + /*if (ii!=0 && ii * slotx < x) + return INT_MIN; + if (jj!=0 && jj * sloty < y) + return INT_MIN;*/ + //printfdf("(): affinity for window %p (%d,%d)->(%d,%d) (%d,%d,%d,%d)", + //cw, x,y,x+ii,y+jj,slotx,sloty,slotxx,slotyy); + return cw->slots * (ii * (slotxx - x - x + slotx) + + jj * (slotyy - y - y + sloty)); } int middleOfThree(int a, int b, int c) { - // x is positive if a is greater than b. - // x is negative if b is greater than a. - int x = a - b; - - int y = b - c; // Similar to x - int z = a - c; // Similar to x and y. - - // Checking if b is middle (x and y both - // are positive) - if (x * y > 0) - return b; - - // Checking if c is middle (x and z both - // are positive) - else if (x * z > 0) - return c; - else - return a; + // x is positive if a is greater than b. + // x is negative if b is greater than a. + int x = a - b; + + int y = b - c; // Similar to x + int z = a - c; // Similar to x and y. + + // Checking if b is middle (x and y both + // are positive) + if (x * y > 0) + return b; + + // Checking if c is middle (x and z both + // are positive) + else if (x * z > 0) + return c; + else + return a; } From a7cd5bef097b35c772b9e7ddf164f440ae6d35aa Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 20:24:56 -0800 Subject: [PATCH 058/205] Fix "crooked" window layout root cause being round-off errors --- src/clientwin.c | 13 +++++++------ src/skippy.c | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 24b71c3..309cc7d 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -408,8 +408,8 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) XSetWindowBorderWidth(cw->mainwin->ps->dpy, cw->mini.window, border); cw->factor = f; - cw->mini.x = x + (int)cw->x * f; - cw->mini.y = y + (int)cw->y * f; + cw->mini.x = x + (float) cw->x * f; + cw->mini.y = y + (float) cw->y * f; if(cw->mainwin->ps->o.lazyTrans) { cw->mini.x += cw->mainwin->x; @@ -420,11 +420,12 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) // animate window by changing these in time linearly: // here, cw->mini has destination coordinates, cw->src has original coordinates - cw->mini.x = cw->src.x + (cw->mini.x - cw->src.x) * timeslice; - cw->mini.y = cw->src.y + (cw->mini.y - cw->src.y) * timeslice; - cw->mini.width = cw->src.width * f; - cw->mini.height = cw->src.height * f; + cw->mini.x = cw->src.x + (float) (cw->mini.x - cw->src.x) * timeslice; + cw->mini.y = cw->src.y + (float) (cw->mini.y - cw->src.y) * timeslice; + cw->mini.width = (float) cw->src.width * f; + cw->mini.height = (float) cw->src.height * f; } + printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->mini.x, cw->mini.y, cw->mini.width, cw->mini.height); XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); diff --git a/src/skippy.c b/src/skippy.c index 12a4018..1c7b2ea 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -744,6 +744,7 @@ mainloop(session_t *ps, bool activate_on_start) { anime(ps->mainwin, ps->mainwin->clients, ((float)timeslice)/(float)ps->o.animationDuration); if ( timeslice >= ps->o.animationDuration) { + anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; last_rendered = time_in_millis(); focus_miniw_adv(ps, mw->client_to_focus, From 65958ae53e83077c8ea3fbcb35e796bb3ba454a3 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 20:26:44 -0800 Subject: [PATCH 059/205] Remove printf --- src/clientwin.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/clientwin.c b/src/clientwin.c index 309cc7d..14e784c 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -425,7 +425,6 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) cw->mini.width = (float) cw->src.width * f; cw->mini.height = (float) cw->src.height * f; } - printfdf("(): window %p coord: (%d,%d) (%d,%d)", cw, cw->mini.x, cw->mini.y, cw->mini.width, cw->mini.height); XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); From 523b2e2c256dcb37297397b52aef17f844b4046a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 19 Feb 2023 20:32:49 -0800 Subject: [PATCH 060/205] White space --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 1c7b2ea..1d907b8 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -744,7 +744,7 @@ mainloop(session_t *ps, bool activate_on_start) { anime(ps->mainwin, ps->mainwin->clients, ((float)timeslice)/(float)ps->o.animationDuration); if ( timeslice >= ps->o.animationDuration) { - anime(ps->mainwin, ps->mainwin->clients, 1); + anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; last_rendered = time_in_millis(); focus_miniw_adv(ps, mw->client_to_focus, From de2c1938bdbf844cdad1f98617c3c9e711f68f3d Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 20 Feb 2023 03:37:44 -0800 Subject: [PATCH 061/205] Arithmetics between signed and unsigned ints causes segfault --- src/mainwin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainwin.h b/src/mainwin.h index 5104972..2643de7 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -39,7 +39,7 @@ struct _mainwin_t { Picture background; Pixmap bg_pixmap; int x, y, xoff, yoff; - unsigned int width, height, newwidth, newheight, distance; + int width, height, newwidth, newheight, distance; float multiplier; XRenderPictFormat *format; From 2f8db59505f6d544b05274a6f2420a06d1dc6a84 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 20 Feb 2023 12:52:33 -0800 Subject: [PATCH 062/205] Resolving git race condition --- src/skippy.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index b5422aa..228a449 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -453,9 +453,9 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { // is important for prev/next window selection dlist_sort(mw->cod, sort_cw_by_pos, 0); - float multiplier = (float) (mw->width - 100) / newwidth; - if (multiplier * newheight > mw->height - 100) - multiplier = (float) (mw->height - 100) / newheight; + float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; + if (multiplier * newheight > mw->height - 2 * mw->distance) + multiplier = (float) (mw->height - 2 * mw->distance) / newheight; if (!ps->o.allowUpscale) multiplier = MIN(multiplier, 1.0f); @@ -478,11 +478,6 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { clientwin_update2((ClientWin *) iter->data); } - // Unfortunately it does not work... - // focus_miniw_adv(ps, mw->focus, ps->o.movePointerOnStart); - focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); - // clientwin_render(mw->client_to_focus); - return clients; } From 1e221eaa18c42f76eb79722eb77951e9149c75c0 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 20 Feb 2023 13:06:37 -0800 Subject: [PATCH 063/205] Window ordering on window centre. Add documentation. --- skippy-xd.sample.rc | 8 ++++++++ src/skippy.h | 12 ++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index ccfdd05..e2ec0a5 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -27,6 +27,14 @@ # [WIDTHxHEIGHT] [orig|scale|scalek|tile] [left|mid|right] [left|mid|right] # [COLOR|#FFFFFFFF] [PATH] # +# - keysUp, keywDown, eysLeft, keysRight: +# selects the window in the direction compared to the current selected window, +# without wrapping +# +# - keysPrev, keysNext: +# selects window previous or next to current one, in up->down, left->right +# ordering, wrapping per column and per row +# # Examples: # background = 500x400 tile right mid #FF0000 /home/richard/screenshots/256.png # background = orig mid mid #FF000080 diff --git a/src/skippy.h b/src/skippy.h index 5e8ef39..37fe213 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1345,13 +1345,17 @@ sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) { ClientWin *cw1 = (ClientWin *) dlist1->data; ClientWin *cw2 = (ClientWin *) dlist2->data; - if (cw1->x < cw2->x) + if (cw1->x + cw1->src.width / 2 + < cw2->x + cw2->src.width / 2) return -1; - else if (cw1->x > cw2->x) + else if (cw1->x + cw1->src.width / 2 + > cw2->x + cw2->src.width / 2) return 1; - else if (cw1->y < cw2->y) + else if (cw1->y + cw1->src.height / 2 + < cw2->y + cw2->src.height / 2) return -1; - else if (cw1->y > cw2->y) + else if (cw1->y + cw1->src.height / 2 + > cw2->y + cw2->src.height / 2) return 1; else return 0; From 57e3ca82bb2705f31d2562971e3f6fc5a03a5aa3 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 20 Feb 2023 23:21:43 +0000 Subject: [PATCH 064/205] add: can now keep local custom user rc file ./skippy-xd.rc in-repo (.gitignored), which make install optionally installs into /etc/xdg/ (if detected) example usage: $ make $ cp ./skippy-xd.sample.rc ./skippy-xd.rc $ sudo make install your custom skippy config file will be installed to: /etc/xdg/skippy-xd.rc install -m 644 skippy-xd.rc "/etc/xdg/skippy-xd.rc" skippy's sample config file will be installed to: /etc/xdg/skippy-xd.sample.rc install -m 644 skippy-xd.sample.rc "/etc/xdg/skippy-xd.sample.rc" --- .gitignore | 3 +++ Makefile | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6035773..0bb9f6b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ man/*.1 doxygen/ .clang_complete /src/backtrace-symbols.[ch] + +# User config override +skippy-xd.rc* diff --git a/Makefile b/Makefile index 301a25f..bfd2910 100644 --- a/Makefile +++ b/Makefile @@ -83,12 +83,23 @@ install-check: @echo "'make install' target folders:" @echo "PREFIX=${PREFIX} DESTDIR=${DESTDIR} BINDIR=${BINDIR}" @echo "skippy executables will be installed into: ${DESTDIR}${BINDIR}" - @echo "skippy's config file will be installed to: ${DESTDIR}/etc/xdg/skippy-xd.rc" install: ${BINS} skippy-xd.sample.rc install -d "${DESTDIR}${BINDIR}/" "${DESTDIR}/etc/xdg/" install -m 755 ${BINS} "${DESTDIR}${BINDIR}/" + +ifneq ("$(wildcard skippy-xd.rc)","") + @echo "your custom skippy config file will be installed to: ${DESTDIR}/etc/xdg/skippy-xd.rc" + install -m 644 skippy-xd.rc "${DESTDIR}/etc/xdg/skippy-xd.rc" + + @echo "skippy's sample config file will be installed to: ${DESTDIR}/etc/xdg/skippy-xd.sample.rc" + install -m 644 skippy-xd.sample.rc "${DESTDIR}/etc/xdg/skippy-xd.sample.rc" +else + @echo "skippy's default config file will be installed to: ${DESTDIR}/etc/xdg/skippy-xd.rc" install -m 644 skippy-xd.sample.rc "${DESTDIR}/etc/xdg/skippy-xd.rc" + install -m 644 skippy-xd.sample.rc "${DESTDIR}/etc/xdg/skippy-xd.sample.rc" +endif + install -m 755 skippy-xd-runner "${DESTDIR}${BINDIR}/" uninstall: From 61f979b16ec6b67d94f7956670c3c35c36e7bdc4 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 21 Feb 2023 23:54:38 -0800 Subject: [PATCH 065/205] Fix daemon segfault --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 228a449..d10d21b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -647,7 +647,7 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; - bool animating = true; + bool animating = activate; long first_animated = 0L; long last_animated = 0L; @@ -968,7 +968,7 @@ mainloop(session_t *ps, bool activate_on_start) { else { printfef("(): activate = true;"); - activate = true; + animating = activate = true; } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: @@ -979,7 +979,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; else - activate = true; + animating = activate = true; break; case PIPECMD_EXIT_RUNNING_DAEMON: printfdf("(): Exit command received, killing daemon..."); From afba3e01540d7d13660d30fd1ec3f87f9434e5fe Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 21 Feb 2023 23:54:38 -0800 Subject: [PATCH 066/205] Fix daemon segfault --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 9b84e9b..09ceb69 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -647,7 +647,7 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; - bool animating = true; + bool animating = activate; long first_animated = 0L; long last_animated = 0L; @@ -968,7 +968,7 @@ mainloop(session_t *ps, bool activate_on_start) { else { printfef("(): activate = true;"); - activate = true; + animating = activate = true; } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: @@ -979,7 +979,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; else - activate = true; + animating = activate = true; break; case PIPECMD_EXIT_RUNNING_DAEMON: printfdf("(): Exit command received, killing daemon..."); From 5d0ac13ac943673bded6b0f32bd97a5b5867f18e Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 21 Feb 2023 17:43:34 -0800 Subject: [PATCH 067/205] Thumbnail for iconized window, Active daemon tracking --- Makefile | 2 +- skippy-xd.sample.rc | 9 +- src/anime.c | 40 ----- src/anime.h | 31 ---- src/clientwin.c | 130 ++++++++++------ src/clientwin.h | 7 +- src/focus.h | 2 +- src/mainwin.c | 21 ++- src/mainwin.h | 6 +- src/skippy.c | 368 ++++++++++++++++++++++++-------------------- src/skippy.h | 5 + src/wm.c | 6 +- 12 files changed, 328 insertions(+), 299 deletions(-) delete mode 100644 src/anime.c delete mode 100644 src/anime.h diff --git a/Makefile b/Makefile index bfd2910..866887b 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ endif CPPFLAGS += -std=c99 -Wall -I/usr/include/freetype2 -SRCS_RAW = skippy wm dlist mainwin clientwin layout focus config tooltip img img-xlib anime +SRCS_RAW = skippy wm dlist mainwin clientwin layout focus config tooltip img img-xlib PACKAGES = x11 xft xrender xcomposite xdamage xfixes # === Options === diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index e2ec0a5..1fc6328 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -55,7 +55,7 @@ distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true -updateFreq = 60.0 +updateFreq = 200.0 animationDuration = 200 # set = 0 to switch off animations lazyTrans = false pipePath = /tmp/skippy-xd-fifo @@ -70,7 +70,7 @@ allowUpscale = true showAllDesktops = false showUnmapped = true preferredIconSize = 48 -clientDisplayModes = thumbnail-icon thumbnail icon filled none +clientDisplayModes = thumbnail-icon thumbnail zombie icon filled none iconFillSpec = orig mid mid #00FFFF fillSpec = orig mid mid #FFFFFF background = @@ -88,6 +88,11 @@ tint = #101020 tintOpacity = 64 opacity = 255 +[shadow] +tint = #040404 +tintOpacity = 64 +opacity = 255 + [tooltip] show = true followsMouse = true diff --git a/src/anime.c b/src/anime.c deleted file mode 100644 index c6bc6df..0000000 --- a/src/anime.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Skippy - Seduces Kids Into Perversion - * - * Copyright (C) 2004 Hyriand - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "anime.h" -#include "skippy.h" - -void anime( - MainWin *mw, - dlist *clients, - float timeslice -) { - clients = dlist_first(clients); - wm_get_current_desktop(mw->ps); - float multiplier = 1.0 + timeslice * (mw->multiplier - 1.0); - mainwin_transform(mw, multiplier); - foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, multiplier, mw->xoff, mw->yoff, timeslice); - clientwin_map((ClientWin*)iter->data); - } - if (!mw->cod) { - printfef("(): Failed to build layout."); - return; - } -} diff --git a/src/anime.h b/src/anime.h deleted file mode 100644 index ca536bf..0000000 --- a/src/anime.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Skippy - Seduces Kids Into Perversion - * - * Copyright (C) 2004 Hyriand - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ANIME_H -#define ANIME_H - -#include "skippy.h" - -/** - * @brief Perform animation from existing window position to layout positions - */ - -void anime(MainWin *mw, dlist *clients, float timeslice); - -#endif /* ANIME_H */ diff --git a/src/clientwin.c b/src/clientwin.c index 14e784c..67a2a7c 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -93,11 +93,13 @@ clientwin_create(MainWin *mw, Window client) { cw->mainwin = mw; cw->wid_client = client; + cw->origin = None; if (ps->o.includeFrame) cw->src.window = wm_find_frame(ps, client); if (!cw->src.window) cw->src.window = client; cw->mini.format = mw->format; + { XSetWindowAttributes sattr = { .border_pixel = 0, @@ -125,6 +127,8 @@ clientwin_create(MainWin *mw, Window client) { free(str); } + cw->cpixmap = None; + // Listen to events on the window. We don't want to miss any changes so // this is to be done as early as possible XSelectInput(cw->mainwin->ps->dpy, cw->src.window, SubstructureNotifyMask | StructureNotifyMask); @@ -143,9 +147,7 @@ clientwin_create(MainWin *mw, Window client) { */ bool clientwin_update(ClientWin *cw) { - MainWin *mw = cw->mainwin; - session_t *ps = mw->ps; - + session_t *ps = cw->mainwin->ps; clientwin_free_res2(ps, cw); // Get window attributes @@ -164,28 +166,36 @@ clientwin_update(ClientWin *cw) { cw->src.format = XRenderFindVisualFormat(ps->dpy, wattr.visual); } + cw->zombie = wattr.map_state != IsViewable; + if (IsViewable == wattr.map_state && !(ps->o.includeAllScreens && ps->o.avoidThumbnailsFromOtherScreens && ps->root != wattr.root)) { - // Get window pixmap - if (ps->o.useNameWindowPixmap) { - XCompositeRedirectWindow(ps->dpy, cw->src.window, - CompositeRedirectAutomatic); - cw->redirected = true; - cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); - } + //if (cw->mode == CLIDISP_THUMBNAIL || cw->mode == CLIDISP_THUMBNAIL_ICON) { // Create window picture - if (!(ps->o.useNameWindowPixmap && ps->o.forceNameWindowPixmap - && !cw->cpixmap)) { +// if (!(ps->o.useNameWindowPixmap && ps->o.forceNameWindowPixmap +// && !cw->cpixmap)) { Drawable draw = cw->cpixmap; if (!draw) draw = cw->src.window; + static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; cw->origin = XRenderCreatePicture(ps->dpy, - draw, cw->src.format, CPSubwindowMode, &pa); - } + cw->src.window, cw->src.format, CPSubwindowMode, &pa); +// } if (cw->origin) { XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); } + + // Get window pixmap + //if (ps->o.useNameWindowPixmap) { + XCompositeRedirectWindow(ps->dpy, cw->src.window, + CompositeRedirectAutomatic); + cw->redirected = true; + cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); + + cw->shadow = XRenderCreatePicture(ps->dpy, + cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); + //} } // Get window icon @@ -197,8 +207,17 @@ clientwin_update(ClientWin *cw) { cw->mini.x = cw->mini.y = 0; cw->mini.width = cw->mini.height = 1; + // modes are CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, + // CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + // if we ever got a thumbnail for the window, + // the mode for that window always will be thumbnail + // + // FUTURE: when config is reloaded with less modes, + // then clientwin_get_disp_mode() may get different result, + // so that clientwin_update() needs to be called + // after reloading config file cw->mode = clientwin_get_disp_mode(ps, cw); - // printfdf("(%#010lx): %d", cw->wid_client, cw->mode); + //printfdf("(%#010lx): %d", cw->wid_client, cw->mode); return true; } @@ -241,6 +260,7 @@ clientwin_update2(ClientWin *cw) { case CLIDISP_ICON: clientwin_update2_icon(ps, mw, cw); break; + case CLIDISP_ZOMBIE: case CLIDISP_THUMBNAIL: case CLIDISP_THUMBNAIL_ICON: break; @@ -283,7 +303,8 @@ clientwin_destroy(ClientWin *cw, bool destroyed) { } static void -clientwin_repaint(ClientWin *cw, const XRectangle *pbound) { +clientwin_repaint(ClientWin *cw, const XRectangle *pbound) +{ session_t *ps = cw->mainwin->ps; Picture source = None; int s_x = 0, s_y = 0, s_w = cw->mini.width, s_h = cw->mini.height; @@ -294,8 +315,7 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) { s_h = pbound->height; } - // printfdf("(%#010lx): %d, %d, %d, %d", cw->wid_client, s_x, s_y, s_w, s_h); - + clientwin_update2(cw); switch (cw->mode) { case CLIDISP_NONE: break; @@ -305,6 +325,9 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) { case CLIDISP_ICON: source = cw->icon_pict_filled->pict; break; + case CLIDISP_ZOMBIE: + source = cw->shadow; + break; case CLIDISP_THUMBNAIL: // We will draw the icon later case CLIDISP_THUMBNAIL_ICON: @@ -312,13 +335,14 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) { break; } - if (!source) return; // Drawing main picture + //if (!cw->zombie) //if(IsViewable == wattr.map_state) { const Picture mask = (cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture); + if (ps->o.lazyTrans) { XRenderComposite(ps->dpy, PictOpSrc, source, mask, cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); @@ -343,19 +367,20 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) { } // Tinting + if (cw->mode >= CLIDISP_ZOMBIE) // tint only thumbnail { // here the client window is being tinted - // if (cw->focused) - // printfef("(): *tint = &cw->mainwin->highlightTint"); - // else - // printfef("(): *tint = &cw->mainwin->normalTint"); + XRenderColor *tint = &cw->mainwin->normalTint; + if (cw->focused) + tint = &cw->mainwin->highlightTint; + else if (cw->zombie) + tint = &cw->mainwin->shadowTint; - XRenderColor *tint = (cw->focused ? &cw->mainwin->highlightTint - : &cw->mainwin->normalTint); if (tint->alpha) XRenderFillRectangle(cw->mainwin->ps->dpy, PictOpOver, cw->destination, tint, s_x, s_y, s_w, s_h); } + //if (!cw->zombie) //if(IsViewable == wattr.map_state) XClearArea(cw->mainwin->ps->dpy, cw->mini.window, s_x, s_y, s_w, s_h, False); } @@ -374,7 +399,7 @@ clientwin_repair(ClientWin *cw) { { XserverRegion rgn = XFixesCreateRegion(ps->dpy, 0, 0); XDamageSubtract(ps->dpy, cw->damage, None, rgn); - if (CLIDISP_THUMBNAIL == cw->mode || CLIDISP_THUMBNAIL_ICON == cw->mode) + if (cw->mode >= CLIDISP_ZOMBIE) rects = XFixesFetchRegion(ps->dpy, rgn, &nrects); XFixesDestroyRegion(ps->dpy, rgn); } @@ -427,16 +452,16 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) } XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); - + if(cw->pixmap) XFreePixmap(cw->mainwin->ps->dpy, cw->pixmap); - + if(cw->destination) XRenderFreePicture(cw->mainwin->ps->dpy, cw->destination); - + cw->pixmap = XCreatePixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.width, cw->mini.height, cw->mainwin->depth); XSetWindowBackgroundPixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->pixmap); - + cw->destination = XRenderCreatePicture(cw->mainwin->ps->dpy, cw->pixmap, cw->mini.format, 0, 0); } @@ -453,6 +478,11 @@ clientwin_map(ClientWin *cw) { XRenderSetPictureTransform(ps->dpy, cw->origin, &cw->mainwin->transform); } + if (cw->shadow) { + cw->damage = XDamageCreate(ps->dpy, cw->src.window, XDamageReportDeltaRectangles); + XRenderSetPictureTransform(ps->dpy, cw->shadow, &cw->mainwin->transform); + } + clientwin_render(cw); XMapWindow(ps->dpy, cw->mini.window); @@ -499,8 +529,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (ev->type == KeyPress) { - report_key(ev); - report_key_modifiers(evk); + //report_key(ev); + //report_key_modifiers(evk); fputs("\n", stdout); fflush(stdout); bool reverse_direction = false; @@ -559,7 +589,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) { - printfef("(): Quitting."); + //printfef("(): Quitting."); mw->client_to_focus = mw->client_to_focus_on_cancel; return 1; } @@ -574,8 +604,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { { // report_key(ev); - report_key(ev); - report_key_modifiers(evk); + //report_key(ev); + //report_key_modifiers(evk); // fputs("\n", stdout); fflush(stdout); if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode)) @@ -589,7 +619,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnRelease, evk->keycode)) { - printfef("(): Quitting."); + //printfef("(): Quitting."); return 1; } } @@ -607,25 +637,25 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { int ret = clientwin_action(cw, ps->o.bindings_miwMouse[button]); if (ret) { - printfef("(): Quitting."); + //printfef("(): Quitting."); return ret; } } } - else - printfef("(): ButtonRelease %u ignored.", button); + //else + //printfef("(): ButtonRelease %u ignored.", button); } else if (ev->type == FocusIn) { - printfef("(): else if (ev->type == FocusIn) {"); + //printfef("(): else if (ev->type == FocusIn) {"); XFocusChangeEvent *evf = &ev->xfocus; // for debugging XEvents // see: https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html - printfef("(): main window id = %#010lx", cw->mainwin->window); - printfefWindowName(ps, "(): client window = ", cw->mainwin->window); - printfef("(): client window id = %#010lx", cw->wid_client); - printfefXFocusChangeEvent(ps, evf); + //printfef("(): main window id = %#010lx", cw->mainwin->window); + //printfefWindowName(ps, "(): client window = ", cw->mainwin->window); + //printfef("(): client window id = %#010lx", cw->wid_client); + //printfefXFocusChangeEvent(ps, evf); // printfef("(): usleep(10000);"); // usleep(10000); @@ -639,15 +669,15 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { XFlush(ps->dpy); } else if (ev->type == FocusOut) { - printfef("(): else if (ev->type == FocusOut) {"); + //printfef("(): else if (ev->type == FocusOut) {"); XFocusChangeEvent *evf = &ev->xfocus; // for debugging XEvents // see: https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html - printfef("(): main window id = %#010lx", cw->mainwin->window); - printfefWindowName(ps, "(): client window = ", cw->mainwin->window); - printfef("(): client window id = %#010lx", cw->wid_client); - printfefXFocusChangeEvent(ps, evf); + //printfef("(): main window id = %#010lx", cw->mainwin->window); + //printfefWindowName(ps, "(): client window = ", cw->mainwin->window); + //printfef("(): client window id = %#010lx", cw->wid_client); + //printfefXFocusChangeEvent(ps, evf); // printfef("(): usleep(10000);"); // usleep(10000); @@ -692,7 +722,7 @@ clientwin_action(ClientWin *cw, enum cliop action) { case CLIENTOP_NO: break; case CLIENTOP_FOCUS: - printfef("(): case CLIENTOP_FOCUS:"); + //printfef("(): case CLIENTOP_FOCUS:"); mw->client_to_focus = cw; return 1; case CLIENTOP_ICONIFY: diff --git a/src/clientwin.h b/src/clientwin.h index 72c4a41..4595e29 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -44,13 +44,15 @@ struct _clientwin_t { SkippyWindow mini; Pixmap pixmap; - Picture origin, destination; + Picture origin, destination, shadow; Damage damage; float factor; bool focused; bool damaged; + + bool zombie; /* XserverRegion repair; */ /* These are virtual positions set by the layout routine */ @@ -80,6 +82,9 @@ clientwin_get_disp_mode(session_t *ps, ClientWin *cw) { case CLIDISP_THUMBNAIL: if (IsViewable == wattr.map_state && cw->origin) return *p; break; + case CLIDISP_ZOMBIE: + if (cw->shadow) return *p; + break; case CLIDISP_ICON: if (cw->icon_pict) return *p; break; diff --git a/src/focus.h b/src/focus.h index f6a3f6d..3b5e46a 100644 --- a/src/focus.h +++ b/src/focus.h @@ -82,7 +82,7 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { clear_focus_all(cw->mainwin->cod); - printfefWindowName(ps, "(): window = ", cw->wid_client); + //printfefWindowName(ps, "(): window = ", cw->wid_client); if (unlikely(!cw)) { diff --git a/src/mainwin.c b/src/mainwin.c index fcfb61e..abb5fc7 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -197,7 +197,7 @@ mainwin_create(session_t *ps) { if(tmp_d != 0.0) mw->poll_time = (1.0 / tmp_d) * 1000.0; else - mw->poll_time = 0; + mw->poll_time = (1.0 / 60.0) * 1000.0; if(!XParseColor(ps->dpy, mw->colormap, ps->o.normal_tint, &exact_color)) { printfef("(): Couldn't look up color '%s', reverting to black.", ps->o.normal_tint); @@ -226,6 +226,20 @@ mainwin_create(session_t *ps) { } mw->highlightTint.alpha = alphaconv(ps->o.highlight_tintOpacity); + tmp = ps->o.shadow_tint; + if(! XParseColor(ps->dpy, mw->colormap, tmp, &exact_color)) + { + fprintf(stderr, "Couldn't look up color '%s', reverting to #010101", tmp); + mw->shadowTint.red = mw->shadowTint.green = mw->shadowTint.blue = 0x01; + } + else + { + mw->shadowTint.red = exact_color.red; + mw->shadowTint.green = exact_color.green; + mw->shadowTint.blue = exact_color.blue; + } + mw->shadowTint.alpha = alphaconv(ps->o.shadow_tintOpacity); + pa.repeat = True; clear.alpha = alphaconv(ps->o.normal_opacity); mw->normalPixmap = XCreatePixmap(ps->dpy, mw->window, 1, 1, 8); @@ -237,6 +251,11 @@ mainwin_create(session_t *ps) { mw->highlightPicture = XRenderCreatePicture(ps->dpy, mw->highlightPixmap, XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); XRenderFillRectangle(ps->dpy, PictOpSrc, mw->highlightPicture, &clear, 0, 0, 1, 1); + clear.alpha = alphaconv(ps->o.shadow_opacity); + mw->shadowPixmap = XCreatePixmap(ps->dpy, mw->window, 1, 1, 8); + mw->shadowPicture = XRenderCreatePicture(ps->dpy, mw->shadowPixmap, XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); + XRenderFillRectangle(ps->dpy, PictOpSrc, mw->shadowPicture, &clear, 0, 0, 1, 1); + mw->distance = ps->o.distance; if (ps->o.tooltip_show) diff --git a/src/mainwin.h b/src/mainwin.h index 2643de7..17a2549 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -45,9 +45,9 @@ struct _mainwin_t { XRenderPictFormat *format; XTransform transform; - XRenderColor normalTint, highlightTint; - Pixmap normalPixmap, highlightPixmap; - Picture normalPicture, highlightPicture; + XRenderColor normalTint, highlightTint, shadowTint; + Pixmap normalPixmap, highlightPixmap, shadowPixmap; + Picture normalPicture, highlightPicture, shadowPicture; ClientWin *pressed, *focus; dlist *cod; diff --git a/src/skippy.c b/src/skippy.c index fa3ed33..4664d00 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -18,7 +18,6 @@ */ #include "skippy.h" -#include "anime.h" #include #include #include @@ -268,6 +267,7 @@ parse_client_disp_mode(session_t *ps, const char *s) { { CLIDISP_NONE, "none" }, { CLIDISP_FILLED, "filled" }, { CLIDISP_ICON, "icon" }, + { CLIDISP_ZOMBIE, "zombie" }, { CLIDISP_THUMBNAIL, "thumbnail" }, { CLIDISP_THUMBNAIL_ICON, "thumbnail-icon" }, }; @@ -310,25 +310,44 @@ parse_client_disp_mode(session_t *ps, const char *s) { return ret; } -static dlist * -update_clients(MainWin *mw, dlist *clients, Bool *touched) { - dlist *stack = dlist_first(wm_get_stack(mw->ps)); +static void +anime( + MainWin *mw, + dlist *clients, + float timeslice +) +{ clients = dlist_first(clients); + wm_get_current_desktop(mw->ps); + float multiplier = 1.0 + timeslice * (mw->multiplier - 1.0); + mainwin_transform(mw, multiplier); + foreach_dlist (mw->cod) { + clientwin_move((ClientWin *) iter->data, multiplier, mw->xoff, mw->yoff, timeslice); + clientwin_map((ClientWin*)iter->data); + } +} + +static void +update_clients(MainWin *mw, Bool *touched) +{ + // Update the client table, pick the ones we want and sort them + dlist *stack = dlist_first(wm_get_stack(mw->ps)); + mw->clients = dlist_first(mw->clients); if (touched) *touched = False; - // Terminate clients that are no longer managed - for (dlist *iter = clients; iter; ) { + // Terminate mw->clients that are no longer managed + for (dlist *iter = mw->clients; iter; ) { ClientWin *cw = (ClientWin *) iter->data; - if (dlist_find_data(stack, (void *) cw->src.window) - && clientwin_update(cw)) { + if (dlist_find_data(stack, (void *) cw->wid_client) + /*&& clientwin_update(cw)*/) { iter = iter->next; } else { dlist *tmp = iter->next; clientwin_destroy((ClientWin *) iter->data, True); - clients = dlist_remove(iter); + mw->clients = dlist_remove(iter); iter = tmp; if (touched) *touched = True; @@ -336,48 +355,51 @@ update_clients(MainWin *mw, dlist *clients, Bool *touched) { } XFlush(mw->ps->dpy); - // Add new clients + // Add new mw->clients foreach_dlist (stack) { ClientWin *cw = (ClientWin *) - dlist_find(clients, clientwin_cmp_func, iter->data); + dlist_find(mw->clients, clientwin_cmp_func, iter->data); if (!cw && ((Window) iter->data) != mw->window) { cw = clientwin_create(mw, (Window)iter->data); if (!cw) continue; - clients = dlist_add(clients, cw); - clientwin_update(cw); + mw->clients = dlist_add(mw->clients, cw); + /*clientwin_update(cw)*/; if (touched) *touched = True; } } dlist_free(stack); - - return clients; } -static dlist * -do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { - session_t * const ps = mw->ps; +static void +daemon_count_clients(MainWin *mw, Bool *touched, Window leader) +{ + // given the client table, update the cod + // the difference between mw->clients and mw->cod + // is that mw->clients is all the client windows + // while mw->cod is only those in current virtual desktop + // if that option is user supplied - long desktop = wm_get_current_desktop(ps); - - /* Update the client table, pick the ones we want and sort them */ // printfef("(): updating dl list of clients"); - clients = update_clients(mw, clients, 0); - if (!clients) { + update_clients(mw, 0); + if (!mw->clients) { printfef("(): No client windows found."); - return clients; + return; } dlist_free(mw->cod); mw->cod = NULL; { - dlist *tmp = dlist_first(dlist_find_all(clients, + session_t * const ps = mw->ps; + long desktop = wm_get_current_desktop(ps); + + dlist *tmp = dlist_first(dlist_find_all(mw->clients, (dlist_match_func) clientwin_validate_func, &desktop)); if (!tmp) { printfef("(): No client window on current desktop found."); - return clients; + return; } if (leader) { @@ -388,25 +410,31 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { mw->cod = tmp; } } - + + return; +} + +static dlist * +init_layout(MainWin *mw, Window focus, Window leader) +{ if (!mw->cod) - return clients; + return; dlist_sort(mw->cod, clientwin_sort_func, 0); - /* Move the mini windows around */ + /* set up the windows layout */ { - unsigned int newwidth = 0, newheight = 0; + int newwidth = 0, newheight = 0; layout_run(mw, mw->cod, &newwidth, &newheight); // ordering of client windows list // is important for prev/next window selection dlist_sort(mw->cod, sort_cw_by_pos, 0); - float multiplier = (float) (mw->width - 100) / newwidth; - if (multiplier * newheight > mw->height - 100) - multiplier = (float) (mw->height - 100) / newheight; - if (!ps->o.allowUpscale) + float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; + if (multiplier * newheight > mw->height - 2 * mw->distance) + multiplier = (float) (mw->height - 2 * mw->distance) / newheight; + if (!mw->ps->o.allowUpscale) multiplier = MIN(multiplier, 1.0f); int xoff = (mw->width - (float) newwidth * multiplier) / 2; @@ -417,68 +445,9 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader) { mw->yoff = yoff; mw->newwidth = newwidth; mw->newheight = newheight; - - mainwin_transform(mw, multiplier); - foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, multiplier, xoff, yoff, 0); - } - } - - foreach_dlist(mw->cod) { - clientwin_update2((ClientWin *) iter->data); - } - - // Get the currently focused window and select which mini-window to focus - { - dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) focus); - - // check if the user specified --prev or --next on the cmdline - if(ps->o.focus_initial) - { - - // ps->mainwin->ignore_next_refocus = 1; - // ps->mainwin->ignore_next_refocus = 2; - // ps->mainwin->ignore_next_refocus = 4; - - - if(ps->o.focus_initial == FI_PREV) - { - // here, mw->cod is the first (dlist*) item in the list - if (iter == mw->cod) - iter = dlist_last(mw->cod); - else - { - dlist *i = mw->cod; - for (; i != NULL; i = i->next) - if (i->next && i->next == iter) - break; - iter = i; - } - } - else if(ps->o.focus_initial == FI_NEXT) - iter = iter->next; - - } - - - // then clear this flag, so daemon not remember on its next activation - ps->o.focus_initial = 0; - - if (!iter) - iter = mw->cod; - - // mw->focus = (ClientWin *) iter->data; - mw->client_to_focus = (ClientWin *) iter->data; - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; - // mw->focus->focused = 1; - - - mw->client_to_focus->focused = 1; - // focus_miniw(ps, mw->client_to_focus); - } - return clients; + return; } static inline const char * @@ -582,7 +551,8 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { } static bool -skippy_run_init(MainWin *mw, Window leader) { +skippy_activate(MainWin *mw, Window leader) +{ session_t *ps = mw->ps; // Do this window before main window gets mapped @@ -596,23 +566,72 @@ skippy_run_init(MainWin *mw, Window leader) { #endif /* CFG_XINERAMA */ // Map the main window and run our event loop - if (ps->o.lazyTrans) { + /*if (ps->o.lazyTrans) { mainwin_map(mw); XFlush(ps->dpy); - } + }*/ mw->client_to_focus = NULL; - mw->clients = do_layout(mw, mw->clients, mw->revert_focus_win, leader); + daemon_count_clients(mw, 0, leader); + foreach_dlist(mw->clients) { + clientwin_update((ClientWin *) iter->data); + clientwin_update2((ClientWin *) iter->data); + } + + init_layout(mw, mw->revert_focus_win, leader); if (!mw->cod) { printfef("(): Failed to build layout."); return false; } - /* Map the main window and run our event loop */ - if (!ps->o.lazyTrans) - mainwin_map(mw); - XFlush(ps->dpy); + // Get the currently focused window and select which mini-window to focus + { + dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) mw->revert_focus_win); + + // check if the user specified --prev or --next on the cmdline + if(ps->o.focus_initial) + { + + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; + + + if(ps->o.focus_initial == FI_PREV) + { + // here, mw->cod is the first (dlist*) item in the list + if (iter == mw->cod) + iter = dlist_last(mw->cod); + else + { + dlist *i = mw->cod; + for (; i != NULL; i = i->next) + if (i->next && i->next == iter) + break; + iter = i; + } + } + else if(ps->o.focus_initial == FI_NEXT) + iter = iter->next; + + } + + // then clear this flag, so daemon not remember on its next activation + ps->o.focus_initial = 0; + + if (!iter) + iter = mw->cod; + + // mw->focus = (ClientWin *) iter->data; + mw->client_to_focus = (ClientWin *) iter->data; + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + // mw->focus->focused = 1; + + + mw->client_to_focus->focused = 1; + // focus_miniw(ps, mw->client_to_focus); + } return true; } @@ -647,9 +666,8 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; - bool animating = true; + bool animating = activate; long first_animated = 0L; - long last_animated = 0L; struct pollfd r_fd[2] = { { @@ -674,18 +692,14 @@ mainloop(session_t *ps, bool activate_on_start) { assert(ps->mainwin); activate = false; - if (skippy_run_init(ps->mainwin, None)) { - // printfef("(): if (skippy_run_init(ps->mainwin, None)) {"); - // printfef("(): was in skippy_run_init"); + if (skippy_activate(ps->mainwin, None)) { + // printfef("(): if (skippy_activate(ps->mainwin, None)) {"); + // printfef("(): was in skippy_activate"); last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; pending_damage = false; - } - - first_animated = time_in_millis(); - if (ps->o.animationDuration <= 0) { - ps->o.animationDuration = 1; + first_animated = time_in_millis(); } } if (mw) @@ -731,13 +745,23 @@ mainloop(session_t *ps, bool activate_on_start) { if (activate_on_start && !mw) return; - // animation! - if (animating) { - if(time_in_millis() - last_animated > mw->poll_time) { - last_animated = time_in_millis(); + // Poll for events + int timeout = ps->mainwin->poll_time; + int time_offset = last_rendered - time_in_millis(); + timeout -= time_offset; + if (timeout < 0) + timeout = 0; + if (pending_damage) + timeout = 0; + poll(r_fd, (r_fd[1].fd >= 0 ? 2: 1), timeout); + + { + // animation! + if (animating) { + last_rendered = time_in_millis(); long timeslice = time_in_millis() - first_animated; anime(ps->mainwin, ps->mainwin->clients, - ((float)timeslice)/(float)ps->o.animationDuration); + ((float)timeslice)/(float)ps->o.animationDuration); if ( timeslice >= ps->o.animationDuration) { anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; @@ -746,16 +770,14 @@ mainloop(session_t *ps, bool activate_on_start) { ps->o.movePointerOnStart); } - } - continue; // while animating, do not allow user actions - } + /* Map the main window and run our event loop */ + if (!ps->o.lazyTrans && !mw->mapped) + mainwin_map(mw); + XFlush(ps->dpy); - // Poll for events - int timeout = (pending_damage && mw && mw->poll_time > 0 ? - MAX(0, mw->poll_time + last_rendered - time_in_millis()): -1); - poll(r_fd, (r_fd[1].fd >= 0 ? 2: 1), timeout); + continue; // while animating, do not allow user actions + } - if (mw) { // Process X events int num_events = 0; XEvent ev = { }; @@ -767,8 +789,9 @@ mainloop(session_t *ps, bool activate_on_start) { ev_dump(ps, mw, &ev); #endif Window wid = ev_window(ps, &ev); +//printfdf("(): Event!); - if (MotionNotify == ev.type) + if (mw && MotionNotify == ev.type) { // Speed up responsiveness when the user is moving the mouse around // The queue gets filled up with consquetive MotionNotify events @@ -804,15 +827,14 @@ mainloop(session_t *ps, bool activate_on_start) { tooltip_move(mw->tooltip, ev.xmotion.x_root, ev.xmotion.y_root); } - else if (ev.type == DestroyNotify || ev.type == UnmapNotify) { - // printfef("(): else if (ev.type == DestroyNotify || ev.type == UnmapNotify) {"); + else if (mw && ev.type == DestroyNotify) { + // printfef("(): else if (ev.type == DestroyNotify) {"); + daemon_count_clients(ps->mainwin, 0, None); dlist *iter = (wid ? dlist_find(mw->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { // printfef("(): if (iter) {"); ClientWin *cw = (ClientWin *) iter->data; - if (DestroyNotify != ev.type) - cw->mode = clientwin_get_disp_mode(ps, cw); - if (DestroyNotify == ev.type || !cw->mode) { + if (!cw->mode) { mw->clients = dlist_first(dlist_remove(iter)); iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) wid); if (iter) @@ -835,25 +857,31 @@ mainloop(session_t *ps, bool activate_on_start) { } } } - else if (ps->xinfo.damage_ev_base + XDamageNotify == ev.type) { + else if (ev.type == MapNotify || ev.type == UnmapNotify) { + //printfef("(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); + daemon_count_clients(ps->mainwin, 0, None); + dlist *iter = (wid ? dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid): NULL); + if (iter) { + ClientWin *cw = (ClientWin *) iter->data; + clientwin_update(cw); + clientwin_update2(cw); + clientwin_render(cw); + } + } + else if (mw && (ps->xinfo.damage_ev_base + XDamageNotify == ev.type)) { + //printfef("(): else if (ev.type == XDamageNotify) {"); // XDamageNotifyEvent *d_ev = (XDamageNotifyEvent *) &ev; - dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, + dlist *iter = dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid); pending_damage = true; if (iter) { - if (!mw->poll_time) - { - // printfef("(): if (!mw->poll_time)"); - clientwin_repair((ClientWin *)iter->data); - } - else - ((ClientWin *)iter->data)->damaged = true; + ((ClientWin *)iter->data)->damaged = true; } - } - else if (wid == mw->window) + else if (mw && wid == mw->window) die = mainwin_handle(mw, &ev); - else if (PropertyNotify == ev.type) { + else if (mw && PropertyNotify == ev.type) { + printfef("(): else if (ev.type == PropertyNotify) {"); // printfef("(): else if (PropertyNotify == ev.type) {"); @@ -869,9 +897,9 @@ mainloop(session_t *ps, bool activate_on_start) { REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod); } } - else if (mw->tooltip && wid == mw->tooltip->window) + else if (mw && mw->tooltip && wid == mw->tooltip->window) tooltip_handle(mw->tooltip, &ev); - else if (wid) { + else if (mw && wid) { for (dlist *iter = mw->cod; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { @@ -888,28 +916,26 @@ mainloop(session_t *ps, bool activate_on_start) { } // Do delayed painting if it's active - if (mw->poll_time && pending_damage && !die) { - long now = time_in_millis(); - if (now >= last_rendered + mw->poll_time) { - pending_damage = false; - foreach_dlist(mw->cod) { - if (((ClientWin *) iter->data)->damaged) - { - // printfef("(): if (((ClientWin *) iter->data)->damaged)"); - clientwin_repair(iter->data); - // fputs("\n", stdout); - } + if (mw && pending_damage && !die) { + //printfdf("(): delayed painting"); + pending_damage = false; + foreach_dlist(mw->cod) { + if (((ClientWin *) iter->data)->damaged) + { + // printfef("(): if (((ClientWin *) iter->data)->damaged)"); + clientwin_repair(iter->data); + // fputs("\n", stdout); } - last_rendered = now; } + last_rendered = time_in_millis(); } - XFlush(ps->dpy); - } - else { // Discards all events so that poll() won't constantly hit data to read - XSync(ps->dpy, True); - assert(!XEventsQueued(ps->dpy, QueuedAfterReading)); + //XSync(ps->dpy, True); + //assert(!XEventsQueued(ps->dpy, QueuedAfterReading)); + + last_rendered = time_in_millis(); + XFlush(ps->dpy); } // Handle daemon commands @@ -968,7 +994,7 @@ mainloop(session_t *ps, bool activate_on_start) { else { printfef("(): activate = true;"); - activate = true; + animating = activate = true; } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: @@ -979,7 +1005,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; else - activate = true; + animating = activate = true; break; case PIPECMD_EXIT_RUNNING_DAEMON: printfdf("(): Exit command received, killing daemon..."); @@ -1113,7 +1139,7 @@ xerror(Display *dpy, XErrorEvent *ev) { { char buf[BUF_LEN] = ""; XGetErrorText(ps->dpy, ev->error_code, buf, BUF_LEN); - printf("error %d (%s) request %d minor %d serial %lu (\"%s\")\n", + printfef("error %d (%s) request %d minor %d serial %lu (\"%s\")\n", ev->error_code, name, ev->request_code, ev->minor_code, ev->serial, buf); } @@ -1440,6 +1466,7 @@ int main(int argc, char *argv[]) { ps->o.pipePath = mstrdup(config_get(config, "general", "pipePath", "/tmp/skippy-xd-fifo")); ps->o.normal_tint = mstrdup(config_get(config, "normal", "tint", "black")); ps->o.highlight_tint = mstrdup(config_get(config, "highlight", "tint", "#101020")); + ps->o.shadow_tint = mstrdup(config_get(config, "shadow", "tint", "#010101")); ps->o.tooltip_border = mstrdup(config_get(config, "tooltip", "border", "#e0e0e0")); ps->o.tooltip_background = mstrdup(config_get(config, "tooltip", "background", "#404040")); ps->o.tooltip_text = mstrdup(config_get(config, "tooltip", "text", "#e0e0e0")); @@ -1504,6 +1531,8 @@ int main(int argc, char *argv[]) { config_get_int_wrap(config, "normal", "opacity", &ps->o.normal_opacity, 0, 256); config_get_int_wrap(config, "highlight", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); config_get_int_wrap(config, "highlight", "opacity", &ps->o.highlight_opacity, 0, 256); + config_get_int_wrap(config, "shadow", "tintOpacity", &ps->o.shadow_tintOpacity, 0, 256); + config_get_int_wrap(config, "shadow", "opacity", &ps->o.shadow_opacity, 0, 256); config_get_bool_wrap(config, "tooltip", "show", &ps->o.tooltip_show); config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse); config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX); @@ -1518,7 +1547,7 @@ int main(int argc, char *argv[]) { return RET_BADARG; if (!ps->o.clientDisplayModes) { static const client_disp_mode_t DEF_CLIDISPM[] = { - CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE }; ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); @@ -1658,6 +1687,13 @@ int main(int argc, char *argv[]) { printfdf("(): Finished flushing pipe \"%s\".", pipePath); } + daemon_count_clients(mw, 0, None); + + foreach_dlist(mw->clients) { + clientwin_update((ClientWin *) iter->data); + clientwin_update2((ClientWin *) iter->data); + } + mainloop(ps, false); } else { diff --git a/src/skippy.h b/src/skippy.h index 37fe213..13ece7b 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -191,6 +191,7 @@ typedef enum { CLIDISP_NONE, CLIDISP_FILLED, CLIDISP_ICON, + CLIDISP_ZOMBIE, CLIDISP_THUMBNAIL, CLIDISP_THUMBNAIL_ICON, } client_disp_mode_t; @@ -248,6 +249,10 @@ typedef struct { int highlight_tintOpacity; int highlight_opacity; + char *shadow_tint; + int shadow_tintOpacity; + int shadow_opacity; + bool tooltip_show; bool tooltip_followsMouse; int tooltip_offsetX; diff --git a/src/wm.c b/src/wm.c index 8107c41..008bbf9 100644 --- a/src/wm.c +++ b/src/wm.c @@ -347,14 +347,14 @@ wm_get_stack_sub(session_t *ps, Window root) { // EWMH l = wm_get_stack_fromprop(ps, root, _NET_CLIENT_LIST); if (l) { - printfdf("(): Retrieved window stack from _NET_CLIENT_LIST."); + //printfef("(): Retrieved window stack from _NET_CLIENT_LIST."); return l; } // GNOME WM l = wm_get_stack_fromprop(ps, root, _WIN_CLIENT_LIST); if (l) { - printfdf("(): Retrieved window stack from _WIN_CLIENT_LIST."); + //printfef("(): Retrieved window stack from _WIN_CLIENT_LIST."); return l; } } @@ -384,7 +384,7 @@ wm_get_stack_sub(session_t *ps, Window root) { } } sxfree(children); - printfdf("(): Retrieved window stack by querying all children."); + //printfef("(): Retrieved window stack by querying all children."); } return l; From 92d4b155a4e2101362bd8b6d8fe0b2b223307967 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 5 Mar 2023 21:00:30 -0800 Subject: [PATCH 068/205] Small changes --- skippy-xd.sample.rc | 5 +---- src/clientwin.c | 45 ++++++++++++++------------------------------- src/clientwin.h | 3 --- src/skippy.c | 13 ++++++------- src/skippy.h | 6 ------ src/wm.c | 8 ++++---- 6 files changed, 25 insertions(+), 55 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 1fc6328..d0f9ace 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -63,12 +63,9 @@ movePointerOnStart = true movePointerOnSelect = true movePointerOnRaise = true switchDesktopOnActivate = false -useNameWindowPixmap = false -forceNameWindowPixmap = false includeFrame = true allowUpscale = true showAllDesktops = false -showUnmapped = true preferredIconSize = 48 clientDisplayModes = thumbnail-icon thumbnail zombie icon filled none iconFillSpec = orig mid mid #00FFFF @@ -90,7 +87,7 @@ opacity = 255 [shadow] tint = #040404 -tintOpacity = 64 +tintOpacity = 164 opacity = 255 [tooltip] diff --git a/src/clientwin.c b/src/clientwin.c index 67a2a7c..90c6855 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -80,11 +80,6 @@ clientwin_create(MainWin *mw, Window client) { XWindowAttributes attr = { }; XGetWindowAttributes(ps->dpy, client, &attr); - // Check if window is mapped - // TODO: Move to validate function? - if (!ps->o.showUnmapped && IsViewable != attr.map_state) - goto clientwin_create_err; - cw = smalloc(1, ClientWin); { static const ClientWin CLIENTWT_DEF = CLIENTWT_INIT; @@ -170,32 +165,23 @@ clientwin_update(ClientWin *cw) { if (IsViewable == wattr.map_state && !(ps->o.includeAllScreens && ps->o.avoidThumbnailsFromOtherScreens && ps->root != wattr.root)) { - //if (cw->mode == CLIDISP_THUMBNAIL || cw->mode == CLIDISP_THUMBNAIL_ICON) { - // Create window picture -// if (!(ps->o.useNameWindowPixmap && ps->o.forceNameWindowPixmap -// && !cw->cpixmap)) { - Drawable draw = cw->cpixmap; - if (!draw) draw = cw->src.window; - - static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; - cw->origin = XRenderCreatePicture(ps->dpy, - cw->src.window, cw->src.format, CPSubwindowMode, &pa); -// } - if (cw->origin) { - XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); - } + Drawable draw = cw->cpixmap; + if (!draw) draw = cw->src.window; + + static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; + cw->origin = XRenderCreatePicture(ps->dpy, + cw->src.window, cw->src.format, CPSubwindowMode, &pa); + XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); // Get window pixmap - //if (ps->o.useNameWindowPixmap) { - XCompositeRedirectWindow(ps->dpy, cw->src.window, - CompositeRedirectAutomatic); - cw->redirected = true; - cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); - - cw->shadow = XRenderCreatePicture(ps->dpy, - cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); - //} + XCompositeRedirectWindow(ps->dpy, cw->src.window, + CompositeRedirectAutomatic); + cw->redirected = true; + cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); + + cw->shadow = XRenderCreatePicture(ps->dpy, + cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); } // Get window icon @@ -315,7 +301,6 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) s_h = pbound->height; } - clientwin_update2(cw); switch (cw->mode) { case CLIDISP_NONE: break; @@ -338,7 +323,6 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) if (!source) return; // Drawing main picture - //if (!cw->zombie) //if(IsViewable == wattr.map_state) { const Picture mask = (cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture); @@ -380,7 +364,6 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) XRenderFillRectangle(cw->mainwin->ps->dpy, PictOpOver, cw->destination, tint, s_x, s_y, s_w, s_h); } - //if (!cw->zombie) //if(IsViewable == wattr.map_state) XClearArea(cw->mainwin->ps->dpy, cw->mini.window, s_x, s_y, s_w, s_h, False); } diff --git a/src/clientwin.h b/src/clientwin.h index 4595e29..424e6d5 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -70,9 +70,6 @@ clientwin_get_disp_mode(session_t *ps, ClientWin *cw) { XWindowAttributes wattr = { }; XGetWindowAttributes(ps->dpy, cw->src.window, &wattr); - if (!ps->o.showUnmapped && IsViewable != wattr.map_state) - return CLIDISP_NONE; - for (client_disp_mode_t *p = ps->o.clientDisplayModes; *p; p++) { switch (*p) { case CLIDISP_THUMBNAIL_ICON: diff --git a/src/skippy.c b/src/skippy.c index 4664d00..1134bd3 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -322,8 +322,10 @@ anime( float multiplier = 1.0 + timeslice * (mw->multiplier - 1.0); mainwin_transform(mw, multiplier); foreach_dlist (mw->cod) { - clientwin_move((ClientWin *) iter->data, multiplier, mw->xoff, mw->yoff, timeslice); - clientwin_map((ClientWin*)iter->data); + ClientWin *cw = (ClientWin *) iter->data; + clientwin_update2(cw); + clientwin_move(cw, multiplier, mw->xoff, mw->yoff, timeslice); + clientwin_map(cw); } } @@ -414,7 +416,7 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) return; } -static dlist * +static void init_layout(MainWin *mw, Window focus, Window leader) { if (!mw->cod) @@ -424,7 +426,7 @@ init_layout(MainWin *mw, Window focus, Window leader) /* set up the windows layout */ { - int newwidth = 0, newheight = 0; + unsigned int newwidth = 0, newheight = 0; layout_run(mw, mw->cod, &newwidth, &newheight); // ordering of client windows list @@ -1513,15 +1515,12 @@ int main(int argc, char *argv[]) { config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); - config_get_bool_wrap(config, "general", "useNameWindowPixmap", &ps->o.useNameWindowPixmap); - config_get_bool_wrap(config, "general", "forceNameWindowPixmap", &ps->o.forceNameWindowPixmap); config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); config_get_bool_wrap(config, "general", "includeAllScreens", &ps->o.includeAllScreens); config_get_bool_wrap(config, "general", "avoidThumbnailsFromOtherScreens", &ps->o.avoidThumbnailsFromOtherScreens); config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); - config_get_bool_wrap(config, "general", "showUnmapped", &ps->o.showUnmapped); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); diff --git a/src/skippy.h b/src/skippy.h index 13ece7b..ac0700b 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -218,8 +218,6 @@ typedef struct { double updateFreq; int animationDuration;; bool lazyTrans; - bool useNameWindowPixmap; - bool forceNameWindowPixmap; bool includeFrame; char *pipePath; bool movePointerOnStart; @@ -230,7 +228,6 @@ typedef struct { bool includeAllScreens; bool avoidThumbnailsFromOtherScreens; bool showAllDesktops; - bool showUnmapped; int preferredIconSize; client_disp_mode_t *clientDisplayModes; pictspec_t iconFillSpec; @@ -294,8 +291,6 @@ typedef struct { .updateFreq = 60.0, \ .animationDuration = 200, \ .lazyTrans = false, \ - .useNameWindowPixmap = false, \ - .forceNameWindowPixmap = false, \ .includeFrame = false, \ .pipePath = NULL, \ .movePointerOnStart = true, \ @@ -310,7 +305,6 @@ typedef struct { .iconFillSpec = PICTSPECT_INIT, \ .fillSpec = PICTSPECT_INIT, \ .showAllDesktops = false, \ - .showUnmapped = true, \ .buttonImgs = { NULL }, \ .background = NULL, \ .xinerama_showAll = true, \ diff --git a/src/wm.c b/src/wm.c index 008bbf9..2c52d2c 100644 --- a/src/wm.c +++ b/src/wm.c @@ -572,9 +572,9 @@ wm_validate_window(session_t *ps, Window wid) { prop = wid_get_prop(ps, wid, _NET_WM_STATE, 8192, XA_ATOM, 32); for (int i = 0; result && i < prop.nitems; i++) { long v = prop.data32[i]; - if (!ps->o.showUnmapped && _NET_WM_STATE_HIDDEN == v) + /*if (!ps->o.showUnmapped && _NET_WM_STATE_HIDDEN == v) result = false; - else if (ps->o.ignoreSkipTaskbar + else*/ if (ps->o.ignoreSkipTaskbar && _NET_WM_STATE_SKIP_TASKBAR == v) result = false; else if (_NET_WM_STATE_SHADED == v) @@ -585,11 +585,11 @@ wm_validate_window(session_t *ps, Window wid) { } else if (WMPSN_GNOME == ps->wmpsn) { // Check _WIN_STATE - prop = wid_get_prop(ps, wid, _WIN_STATE, 1, XA_CARDINAL, 0); + /*prop = wid_get_prop(ps, wid, _WIN_STATE, 1, XA_CARDINAL, 0); if (!ps->o.showUnmapped && winprop_get_int(&prop) & (WIN_STATE_MINIMIZED | WIN_STATE_SHADED | WIN_STATE_HIDDEN)) result = false; - free_winprop(&prop); + free_winprop(&prop);*/ if (result && ps->o.ignoreSkipTaskbar) { prop = wid_get_prop(ps, wid, _WIN_HINTS, 1, XA_CARDINAL, 0); From b77d00f84bf8e8129add66be368d6a5285b2dab9 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 5 Mar 2023 22:20:26 -0800 Subject: [PATCH 069/205] Fix segfault when there is no active window --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 1134bd3..6c24093 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -759,7 +759,7 @@ mainloop(session_t *ps, bool activate_on_start) { { // animation! - if (animating) { + if (mw && animating) { last_rendered = time_in_millis(); long timeslice = time_in_millis() - first_animated; anime(ps->mainwin, ps->mainwin->clients, From a2056369702dd7dbd061fdd5199197b12301cdf1 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 6 Mar 2023 00:11:11 -0800 Subject: [PATCH 070/205] Free shadow thumbnail --- src/clientwin.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 90c6855..282ebd2 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -180,8 +180,10 @@ clientwin_update(ClientWin *cw) { cw->redirected = true; cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); - cw->shadow = XRenderCreatePicture(ps->dpy, - cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); + if (cw->shadow) + free_picture(ps, &cw->shadow); + cw->shadow = XRenderCreatePicture(ps->dpy, + cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); } // Get window icon @@ -262,6 +264,7 @@ clientwin_destroy(ClientWin *cw, bool destroyed) { free_picture(ps, &cw->origin); free_picture(ps, &cw->destination); + free_picture(ps, &cw->shadow); free_pixmap(ps, &cw->pixmap); free_pixmap(ps, &cw->cpixmap); free_pictw(ps, &cw->icon_pict); From 88370cb8f319b640289cd3b35bfd9eb84efca1c8 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 6 Mar 2023 22:03:42 -0800 Subject: [PATCH 071/205] Remove two config options includeAllScreens and avoidThumbnailsFromOtherScreens --- src/clientwin.c | 3 +-- src/skippy.c | 2 -- src/skippy.h | 4 ---- src/wm.c | 2 +- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 282ebd2..12619fb 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -163,8 +163,7 @@ clientwin_update(ClientWin *cw) { cw->zombie = wattr.map_state != IsViewable; - if (IsViewable == wattr.map_state - && !(ps->o.includeAllScreens && ps->o.avoidThumbnailsFromOtherScreens && ps->root != wattr.root)) { + if (IsViewable == wattr.map_state) { // Create window picture Drawable draw = cw->cpixmap; if (!draw) draw = cw->src.window; diff --git a/src/skippy.c b/src/skippy.c index 6c24093..e720652 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1518,8 +1518,6 @@ int main(int argc, char *argv[]) { config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); - config_get_bool_wrap(config, "general", "includeAllScreens", &ps->o.includeAllScreens); - config_get_bool_wrap(config, "general", "avoidThumbnailsFromOtherScreens", &ps->o.avoidThumbnailsFromOtherScreens); config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); diff --git a/src/skippy.h b/src/skippy.h index ac0700b..c0b23e1 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -225,8 +225,6 @@ typedef struct { bool movePointerOnRaise; bool switchDesktopOnActivate; bool allowUpscale; - bool includeAllScreens; - bool avoidThumbnailsFromOtherScreens; bool showAllDesktops; int preferredIconSize; client_disp_mode_t *clientDisplayModes; @@ -298,8 +296,6 @@ typedef struct { .movePointerOnRaise = true, \ .switchDesktopOnActivate = false, \ .allowUpscale = true, \ - .includeAllScreens = false, \ - .avoidThumbnailsFromOtherScreens = true, \ .preferredIconSize = 48, \ .clientDisplayModes = NULL, \ .iconFillSpec = PICTSPECT_INIT, \ diff --git a/src/wm.c b/src/wm.c index 2c52d2c..a9ee2e8 100644 --- a/src/wm.c +++ b/src/wm.c @@ -392,7 +392,7 @@ wm_get_stack_sub(session_t *ps, Window root) { dlist * wm_get_stack(session_t *ps) { - if (ps->o.includeAllScreens) { + if (ps->o.showAllDesktops) { dlist *l = NULL; for (int i = 0; i < ScreenCount(ps->dpy); ++i) l = dlist_join(l, wm_get_stack_sub(ps, RootWindow(ps->dpy, i))); From 38b964405bd2174b6bddc09c0fa1613ecee06b61 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 6 Mar 2023 22:52:52 -0800 Subject: [PATCH 072/205] Config option for layout algo "xd" and "boxy" --- skippy-xd.sample.rc | 1 + src/layout.c | 5 ++++- src/skippy.c | 14 ++++++++++++++ src/skippy.h | 8 ++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index ccfdd05..10be895 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -44,6 +44,7 @@ # [general] +layout = boxy distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true diff --git a/src/layout.c b/src/layout.c index 1f5d663..e8451bd 100644 --- a/src/layout.c +++ b/src/layout.c @@ -39,7 +39,10 @@ // = total windows width and height + minimal distance between windows void layout_run(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) { - layout_boxy(mw, windows, total_width, total_height); + if (mw->ps->o.layout == LAYOUT_BOXY) + layout_boxy(mw, windows, total_width, total_height); + else if (mw->ps->o.layout == LAYOUT_XD) + layout_xd(mw, windows, total_width, total_height); } // original legacy layout diff --git a/src/skippy.c b/src/skippy.c index 33746ac..507c88f 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1482,6 +1482,20 @@ int main(int argc, char *argv[]) { || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) return RET_BADARG; + { + const char *s = config_get(config, "general", "layout", NULL); + if (s) { + if (strcmp(s,"boxy") == 0) { + ps->o.layout = LAYOUT_BOXY; + } + else if (strcmp(s,"xd") == 0) { + ps->o.layout = LAYOUT_XD; + } + else { + ps->o.layout = LAYOUT_BOXY; + } + } + } config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); config_get_bool_wrap(config, "general", "ignoreSkipTaskbar", &ps->o.ignoreSkipTaskbar); diff --git a/src/skippy.h b/src/skippy.h index a197bc3..bd09fff 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -101,6 +101,12 @@ hexdump(const char *data, int len) { } /// @brief Possible return values. + +enum { + LAYOUT_BOXY, + LAYOUT_XD +}; + enum { RET_SUCCESS = 0, RET_UNKNOWN, @@ -209,6 +215,7 @@ typedef struct { bool synchronize; int focus_initial; + int layout; int distance; bool useNetWMFullscreen; bool ignoreSkipTaskbar; @@ -281,6 +288,7 @@ typedef struct { .runAsDaemon = false, \ .synchronize = false, \ \ + .layout = LAYOUT_BOXY, \ .distance = 50, \ .useNetWMFullscreen = true, \ .ignoreSkipTaskbar = false, \ From bbda250c7a532f3901926cf761d7a6cc6ed37297 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 7 Mar 2023 21:20:59 -0800 Subject: [PATCH 073/205] Remove clientDisplayModes from config --- src/skippy.c | 67 ++++------------------------------------------------ 1 file changed, 5 insertions(+), 62 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index cac6735..759adb2 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -258,58 +258,6 @@ parse_pictspec(session_t *ps, const char *s, pictspec_t *dest) { return true; } -static client_disp_mode_t * -parse_client_disp_mode(session_t *ps, const char *s) { - static const struct { - client_disp_mode_t mode; - const char *name; - } ENTRIES[] = { - { CLIDISP_NONE, "none" }, - { CLIDISP_FILLED, "filled" }, - { CLIDISP_ICON, "icon" }, - { CLIDISP_ZOMBIE, "zombie" }, - { CLIDISP_THUMBNAIL, "thumbnail" }, - { CLIDISP_THUMBNAIL_ICON, "thumbnail-icon" }, - }; - static const int ALLOC_STEP = 3; - int capacity = 0; - client_disp_mode_t *ret = NULL; - - int i = 0; - for (; s; ++i) { - char *word = NULL; - s = str_get_word(s, &word); - if (!word) - break; - if (capacity <= i + 1) { - capacity += ALLOC_STEP; - ret = srealloc(ret, capacity, client_disp_mode_t); - } - { - bool found = false; - for (int j = 0; j < CARR_LEN(ENTRIES); ++j) - if (!strcmp(word, ENTRIES[j].name)) { - found = true; - ret[i] = ENTRIES[j].mode; - } - if (!found) { - printfef("(\"%s\"): Invalid mode \"%s\" ignored.", s, word); - --i; - } - } - free(word); - } - - if (!i) { - free(ret); - } - else { - ret[i] = CLIDISP_NONE; - } - - return ret; -} - static void anime( MainWin *mw, @@ -1553,16 +1501,11 @@ int main(int argc, char *argv[]) { config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256); { - const char *s = config_get(config, "general", "clientDisplayModes", NULL); - if (s && !(ps->o.clientDisplayModes = parse_client_disp_mode(ps, s))) - return RET_BADARG; - if (!ps->o.clientDisplayModes) { - static const client_disp_mode_t DEF_CLIDISPM[] = { - CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE - }; - ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); - memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); - } + static const client_disp_mode_t DEF_CLIDISPM[] = { + CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + }; + ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); + memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); } { const char *sspec = config_get(config, "general", "background", NULL); From 8cb6d961fa987d32a162ddf89d48d9bd3251a0ac Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 7 Mar 2023 21:53:29 -0800 Subject: [PATCH 074/205] Add CLIDISP_ZOMBIE_ICON --- src/clientwin.c | 14 ++++++-------- src/clientwin.h | 3 +++ src/skippy.c | 2 +- src/skippy.h | 1 + 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 7de8b85..2f2d689 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -196,16 +196,11 @@ clientwin_update(ClientWin *cw) { cw->mini.width = cw->mini.height = 1; // modes are CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, - // CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + // CLIDISP_ZOMBIE_ICON, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE // if we ever got a thumbnail for the window, // the mode for that window always will be thumbnail - // - // FUTURE: when config is reloaded with less modes, - // then clientwin_get_disp_mode() may get different result, - // so that clientwin_update() needs to be called - // after reloading config file cw->mode = clientwin_get_disp_mode(ps, cw); - //printfdf("(%#010lx): %d", cw->wid_client, cw->mode); + // printfdf("(%#010lx): %d", cw->wid_client, cw->mode); return true; } @@ -249,6 +244,7 @@ clientwin_update2(ClientWin *cw) { clientwin_update2_icon(ps, mw, cw); break; case CLIDISP_ZOMBIE: + case CLIDISP_ZOMBIE_ICON: case CLIDISP_THUMBNAIL: case CLIDISP_THUMBNAIL_ICON: break; @@ -314,6 +310,8 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) source = cw->icon_pict_filled->pict; break; case CLIDISP_ZOMBIE: + // We will draw the icon later + case CLIDISP_ZOMBIE_ICON: source = cw->shadow; break; case CLIDISP_THUMBNAIL: @@ -341,7 +339,7 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) XRenderComposite(ps->dpy, PictOpOver, source, mask, cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); } - if (CLIDISP_THUMBNAIL_ICON == cw->mode) { + if (CLIDISP_ZOMBIE_ICON == cw->mode || CLIDISP_THUMBNAIL_ICON == cw->mode) { assert(cw->icon_pict && cw->icon_pict->pict); img_composite_params_t params = IMG_COMPOSITE_PARAMS_INIT; simg_get_composite_params(cw->icon_pict, diff --git a/src/clientwin.h b/src/clientwin.h index 901aa86..3861a86 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -80,6 +80,9 @@ clientwin_get_disp_mode(session_t *ps, ClientWin *cw) { case CLIDISP_THUMBNAIL: if (IsViewable == wattr.map_state && cw->origin) return *p; break; + case CLIDISP_ZOMBIE_ICON: + if (cw->shadow && cw->icon_pict != NULL) return *p; + break; case CLIDISP_ZOMBIE: if (cw->shadow) return *p; break; diff --git a/src/skippy.c b/src/skippy.c index 759adb2..8000b3d 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1502,7 +1502,7 @@ int main(int argc, char *argv[]) { config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256); { static const client_disp_mode_t DEF_CLIDISPM[] = { - CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE_ICON, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE }; ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); diff --git a/src/skippy.h b/src/skippy.h index fca8563..ae04ee5 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -198,6 +198,7 @@ typedef enum { CLIDISP_FILLED, CLIDISP_ICON, CLIDISP_ZOMBIE, + CLIDISP_ZOMBIE_ICON, CLIDISP_THUMBNAIL, CLIDISP_THUMBNAIL_ICON, } client_disp_mode_t; From fa896633c1a430e60625398036793d52c9c56bd8 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 7 Mar 2023 22:07:58 -0800 Subject: [PATCH 075/205] Add config option for thumbnail icons --- skippy-xd.sample.rc | 2 +- src/skippy.c | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 41edb1e..49d91f2 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -68,7 +68,7 @@ includeFrame = true allowUpscale = true showAllDesktops = false preferredIconSize = 48 -clientDisplayModes = thumbnail-icon thumbnail zombie icon filled none +showIconsOnThumbnails = true iconFillSpec = orig mid mid #00FFFF fillSpec = orig mid mid #FFFFFF background = diff --git a/src/skippy.c b/src/skippy.c index 8000b3d..dd7512f 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1501,11 +1501,25 @@ int main(int argc, char *argv[]) { config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256); { - static const client_disp_mode_t DEF_CLIDISPM[] = { - CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE_ICON, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + static client_disp_mode_t DEF_CLIDISPM[] = { + CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE }; - ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); - memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); + + static client_disp_mode_t DEF_CLIDISPM_ICON[] = { + CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE_ICON, + CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + }; + + bool thumbnail_icons = false; + config_get_bool_wrap(config, "general", "showIconsOnThumbnails", &thumbnail_icons); + if (thumbnail_icons) { + ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM_ICON))); + memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM_ICON, sizeof(DEF_CLIDISPM_ICON)); + } + else { + ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); + memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); + } } { const char *sspec = config_get(config, "general", "background", NULL); From 5f26c62f32aeb3cd9cbe9abf5e9158ec1b8b79a5 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 7 Mar 2023 22:49:31 -0800 Subject: [PATCH 076/205] Put config reading code into own function --- src/skippy.c | 343 ++++++++++++++++++++++++++------------------------- 1 file changed, 175 insertions(+), 168 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index dd7512f..db56aa7 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1353,7 +1353,178 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { } } } - + +static int +load_config_file(session_t *ps) +{ + dlist *config = NULL; + { + bool user_specified_config = ps->o.config_path; + if (!ps->o.config_path) + ps->o.config_path = get_cfg_path(); + if (ps->o.config_path) + config = config_load(ps->o.config_path); + else + printfef("(): WARNING: No configuration file found."); + if (!config && user_specified_config) + return 1; + } + + char *lc_numeric_old = mstrdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + + // Read configuration into ps->o, because searching all the time is much + // less efficient, may introduce inconsistent default value, and + // occupies a lot more memory for non-string types. + ps->o.pipePath = mstrdup(config_get(config, "general", "pipePath", "/tmp/skippy-xd-fifo")); + ps->o.normal_tint = mstrdup(config_get(config, "normal", "tint", "black")); + ps->o.highlight_tint = mstrdup(config_get(config, "highlight", "tint", "#101020")); + ps->o.shadow_tint = mstrdup(config_get(config, "shadow", "tint", "#010101")); + ps->o.tooltip_border = mstrdup(config_get(config, "tooltip", "border", "#e0e0e0")); + ps->o.tooltip_background = mstrdup(config_get(config, "tooltip", "background", "#404040")); + ps->o.tooltip_text = mstrdup(config_get(config, "tooltip", "text", "#e0e0e0")); + ps->o.tooltip_textShadow = mstrdup(config_get(config, "tooltip", "textShadow", "black")); + ps->o.tooltip_font = mstrdup(config_get(config, "tooltip", "font", "fixed-11:weight=bold")); + + // load keybindings settings + ps->o.bindings_keysUp = mstrdup(config_get(config, "bindings", "keysUp", "Up w")); + ps->o.bindings_keysDown = mstrdup(config_get(config, "bindings", "keysDown", "Down s")); + ps->o.bindings_keysLeft = mstrdup(config_get(config, "bindings", "keysLeft", "Left a")); + ps->o.bindings_keysRight = mstrdup(config_get(config, "bindings", "keysRight", "Right Tab d")); + ps->o.bindings_keysPrev = mstrdup(config_get(config, "bindings", "keysPrev", "p b")); + ps->o.bindings_keysNext = mstrdup(config_get(config, "bindings", "keysNext", "n f")); + ps->o.bindings_keysExitCancelOnPress = mstrdup(config_get(config, "bindings", "keysExitCancelOnPress", "Escape BackSpace x q")); + ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitCancelOnRelease", "")); + ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitSelectOnPress", "Return space")); + ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitSelectOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); + ps->o.bindings_keysReverseDirection = mstrdup(config_get(config, "bindings", "keysReverseDirection", "Tab")); + ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); + + // print an error message for any key bindings that aren't recognized + check_keysyms(ps->o.config_path, ": [bindings] keysUp =", ps->o.bindings_keysUp); + check_keysyms(ps->o.config_path, ": [bindings] keysDown =", ps->o.bindings_keysDown); + check_keysyms(ps->o.config_path, ": [bindings] keysLeft =", ps->o.bindings_keysLeft); + check_keysyms(ps->o.config_path, ": [bindings] keysRight =", ps->o.bindings_keysRight); + check_keysyms(ps->o.config_path, ": [bindings] keysPrev =", ps->o.bindings_keysPrev); + check_keysyms(ps->o.config_path, ": [bindings] keysNext =", ps->o.bindings_keysNext); + check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnPress =", ps->o.bindings_keysExitCancelOnPress); + check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); + check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); + check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnRelease =", ps->o.bindings_keysExitSelectOnRelease); + check_keysyms(ps->o.config_path, ": [bindings] keysReverseDirection =", ps->o.bindings_keysReverseDirection); + check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); + + if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) + return RET_BADARG; + { + const char *s = config_get(config, "general", "layout", NULL); + if (s) { + if (strcmp(s,"boxy") == 0) { + ps->o.layout = LAYOUT_BOXY; + } + else if (strcmp(s,"xd") == 0) { + ps->o.layout = LAYOUT_XD; + } + else { + ps->o.layout = LAYOUT_BOXY; + } + } + } + config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); + config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); + config_get_bool_wrap(config, "general", "ignoreSkipTaskbar", &ps->o.ignoreSkipTaskbar); + config_get_bool_wrap(config, "general", "acceptOvRedir", &ps->o.acceptOvRedir); + config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); + config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); + config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); + config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); + config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); + config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); + config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); + config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); + config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); + config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); + config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); + config_get_bool_wrap(config, "general", "switchDesktopOnActivate", &ps->o.switchDesktopOnActivate); + config_get_bool_wrap(config, "xinerama", "showAll", &ps->o.xinerama_showAll); + config_get_int_wrap(config, "normal", "tintOpacity", &ps->o.normal_tintOpacity, 0, 256); + config_get_int_wrap(config, "normal", "opacity", &ps->o.normal_opacity, 0, 256); + config_get_int_wrap(config, "highlight", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); + config_get_int_wrap(config, "highlight", "opacity", &ps->o.highlight_opacity, 0, 256); + config_get_int_wrap(config, "shadow", "tintOpacity", &ps->o.shadow_tintOpacity, 0, 256); + config_get_int_wrap(config, "shadow", "opacity", &ps->o.shadow_opacity, 0, 256); + config_get_bool_wrap(config, "tooltip", "show", &ps->o.tooltip_show); + config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse); + config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX); + config_get_int_wrap(config, "tooltip", "offsetY", &ps->o.tooltip_offsetY, INT_MIN, INT_MAX); + if (!parse_align_full(ps, config_get(config, "tooltip", "align", "left"), &ps->o.tooltip_align)) + return RET_BADARG; + config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); + config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256); + { + static client_disp_mode_t DEF_CLIDISPM[] = { + CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + }; + + static client_disp_mode_t DEF_CLIDISPM_ICON[] = { + CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE_ICON, + CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE + }; + + bool thumbnail_icons = false; + config_get_bool_wrap(config, "general", "showIconsOnThumbnails", &thumbnail_icons); + if (thumbnail_icons) { + ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM_ICON))); + memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM_ICON, sizeof(DEF_CLIDISPM_ICON)); + } + else { + ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); + memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); + } + } + { + const char *sspec = config_get(config, "general", "background", NULL); + if (sspec && strlen(sspec)) { + pictspec_t spec = PICTSPECT_INIT; + if (!parse_pictspec(ps, sspec, &spec)) + return RET_BADARG; + int root_width = DisplayWidth(ps->dpy, ps->screen), + root_height = DisplayHeight(ps->dpy, ps->screen); + if (!(spec.twidth || spec.theight)) { + spec.twidth = root_width; + spec.theight = root_height; + } + pictw_t *p = simg_load_s(ps, &spec); + if (!p) + exit(1); + if (p->width != root_width || p->height != root_height) + ps->o.background = simg_postprocess(ps, p, PICTPOSP_ORIG, + root_width, root_height, spec.alg, spec.valg, &spec.c); + else + ps->o.background = p; + free_pictspec(ps, &spec); + } + } + if (!parse_pictspec(ps, config_get(config, "general", "iconFillSpec", "orig mid mid #FFFFFF"), &ps->o.iconFillSpec) + || !parse_pictspec(ps, config_get(config, "general", "fillSpec", "orig mid mid #FFFFFF"), &ps->o.fillSpec)) + return RET_BADARG; + if (!simg_cachespec(ps, &ps->o.fillSpec)) + return RET_BADARG; + if (ps->o.iconFillSpec.path + && !(ps->o.iconDefault = simg_load(ps, ps->o.iconFillSpec.path, + PICTPOSP_SCALEK, ps->o.preferredIconSize, ps->o.preferredIconSize, + ALIGN_MID, ALIGN_MID, NULL))) + return RET_BADARG; + + setlocale(LC_NUMERIC, lc_numeric_old); + free(lc_numeric_old); + config_free(config); + + return RET_SUCCESS; +} + int main(int argc, char *argv[]) { session_t *ps = NULL; int ret = RET_SUCCESS; @@ -1392,173 +1563,9 @@ int main(int argc, char *argv[]) { wm_get_atoms(ps); - // Load configuration file - { - dlist *config = NULL; - { - bool user_specified_config = ps->o.config_path; - if (!ps->o.config_path) - ps->o.config_path = get_cfg_path(); - if (ps->o.config_path) - config = config_load(ps->o.config_path); - else - printfef("(): WARNING: No configuration file found."); - if (!config && user_specified_config) - return 1; - } - - char *lc_numeric_old = mstrdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - - // Read configuration into ps->o, because searching all the time is much - // less efficient, may introduce inconsistent default value, and - // occupies a lot more memory for non-string types. - ps->o.pipePath = mstrdup(config_get(config, "general", "pipePath", "/tmp/skippy-xd-fifo")); - ps->o.normal_tint = mstrdup(config_get(config, "normal", "tint", "black")); - ps->o.highlight_tint = mstrdup(config_get(config, "highlight", "tint", "#101020")); - ps->o.shadow_tint = mstrdup(config_get(config, "shadow", "tint", "#010101")); - ps->o.tooltip_border = mstrdup(config_get(config, "tooltip", "border", "#e0e0e0")); - ps->o.tooltip_background = mstrdup(config_get(config, "tooltip", "background", "#404040")); - ps->o.tooltip_text = mstrdup(config_get(config, "tooltip", "text", "#e0e0e0")); - ps->o.tooltip_textShadow = mstrdup(config_get(config, "tooltip", "textShadow", "black")); - ps->o.tooltip_font = mstrdup(config_get(config, "tooltip", "font", "fixed-11:weight=bold")); - - // load keybindings settings - ps->o.bindings_keysUp = mstrdup(config_get(config, "bindings", "keysUp", "Up w")); - ps->o.bindings_keysDown = mstrdup(config_get(config, "bindings", "keysDown", "Down s")); - ps->o.bindings_keysLeft = mstrdup(config_get(config, "bindings", "keysLeft", "Left a")); - ps->o.bindings_keysRight = mstrdup(config_get(config, "bindings", "keysRight", "Right Tab d")); - ps->o.bindings_keysPrev = mstrdup(config_get(config, "bindings", "keysPrev", "p b")); - ps->o.bindings_keysNext = mstrdup(config_get(config, "bindings", "keysNext", "n f")); - ps->o.bindings_keysExitCancelOnPress = mstrdup(config_get(config, "bindings", "keysExitCancelOnPress", "Escape BackSpace x q")); - ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitCancelOnRelease", "")); - ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitSelectOnPress", "Return space")); - ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitSelectOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); - ps->o.bindings_keysReverseDirection = mstrdup(config_get(config, "bindings", "keysReverseDirection", "Tab")); - ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); - - // print an error message for any key bindings that aren't recognized - check_keysyms(ps->o.config_path, ": [bindings] keysUp =", ps->o.bindings_keysUp); - check_keysyms(ps->o.config_path, ": [bindings] keysDown =", ps->o.bindings_keysDown); - check_keysyms(ps->o.config_path, ": [bindings] keysLeft =", ps->o.bindings_keysLeft); - check_keysyms(ps->o.config_path, ": [bindings] keysRight =", ps->o.bindings_keysRight); - check_keysyms(ps->o.config_path, ": [bindings] keysPrev =", ps->o.bindings_keysPrev); - check_keysyms(ps->o.config_path, ": [bindings] keysNext =", ps->o.bindings_keysNext); - check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnPress =", ps->o.bindings_keysExitCancelOnPress); - check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); - check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); - check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnRelease =", ps->o.bindings_keysExitSelectOnRelease); - check_keysyms(ps->o.config_path, ": [bindings] keysReverseDirection =", ps->o.bindings_keysReverseDirection); - check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); - - if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) - || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) - || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) - return RET_BADARG; - { - const char *s = config_get(config, "general", "layout", NULL); - if (s) { - if (strcmp(s,"boxy") == 0) { - ps->o.layout = LAYOUT_BOXY; - } - else if (strcmp(s,"xd") == 0) { - ps->o.layout = LAYOUT_XD; - } - else { - ps->o.layout = LAYOUT_BOXY; - } - } - } - config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); - config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); - config_get_bool_wrap(config, "general", "ignoreSkipTaskbar", &ps->o.ignoreSkipTaskbar); - config_get_bool_wrap(config, "general", "acceptOvRedir", &ps->o.acceptOvRedir); - config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); - config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); - config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); - config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); - config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); - config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); - config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); - config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); - config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); - config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); - config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); - config_get_bool_wrap(config, "general", "switchDesktopOnActivate", &ps->o.switchDesktopOnActivate); - config_get_bool_wrap(config, "xinerama", "showAll", &ps->o.xinerama_showAll); - config_get_int_wrap(config, "normal", "tintOpacity", &ps->o.normal_tintOpacity, 0, 256); - config_get_int_wrap(config, "normal", "opacity", &ps->o.normal_opacity, 0, 256); - config_get_int_wrap(config, "highlight", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); - config_get_int_wrap(config, "highlight", "opacity", &ps->o.highlight_opacity, 0, 256); - config_get_int_wrap(config, "shadow", "tintOpacity", &ps->o.shadow_tintOpacity, 0, 256); - config_get_int_wrap(config, "shadow", "opacity", &ps->o.shadow_opacity, 0, 256); - config_get_bool_wrap(config, "tooltip", "show", &ps->o.tooltip_show); - config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse); - config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX); - config_get_int_wrap(config, "tooltip", "offsetY", &ps->o.tooltip_offsetY, INT_MIN, INT_MAX); - if (!parse_align_full(ps, config_get(config, "tooltip", "align", "left"), &ps->o.tooltip_align)) - return RET_BADARG; - config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); - config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256); - { - static client_disp_mode_t DEF_CLIDISPM[] = { - CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE - }; - - static client_disp_mode_t DEF_CLIDISPM_ICON[] = { - CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE_ICON, - CLIDISP_ZOMBIE, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE - }; - - bool thumbnail_icons = false; - config_get_bool_wrap(config, "general", "showIconsOnThumbnails", &thumbnail_icons); - if (thumbnail_icons) { - ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM_ICON))); - memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM_ICON, sizeof(DEF_CLIDISPM_ICON)); - } - else { - ps->o.clientDisplayModes = allocchk(malloc(sizeof(DEF_CLIDISPM))); - memcpy(ps->o.clientDisplayModes, &DEF_CLIDISPM, sizeof(DEF_CLIDISPM)); - } - } - { - const char *sspec = config_get(config, "general", "background", NULL); - if (sspec && strlen(sspec)) { - pictspec_t spec = PICTSPECT_INIT; - if (!parse_pictspec(ps, sspec, &spec)) - return RET_BADARG; - int root_width = DisplayWidth(ps->dpy, ps->screen), - root_height = DisplayHeight(ps->dpy, ps->screen); - if (!(spec.twidth || spec.theight)) { - spec.twidth = root_width; - spec.theight = root_height; - } - pictw_t *p = simg_load_s(ps, &spec); - if (!p) - exit(1); - if (p->width != root_width || p->height != root_height) - ps->o.background = simg_postprocess(ps, p, PICTPOSP_ORIG, - root_width, root_height, spec.alg, spec.valg, &spec.c); - else - ps->o.background = p; - free_pictspec(ps, &spec); - } - } - if (!parse_pictspec(ps, config_get(config, "general", "iconFillSpec", "orig mid mid #FFFFFF"), &ps->o.iconFillSpec) - || !parse_pictspec(ps, config_get(config, "general", "fillSpec", "orig mid mid #FFFFFF"), &ps->o.fillSpec)) - return RET_BADARG; - if (!simg_cachespec(ps, &ps->o.fillSpec)) - return RET_BADARG; - if (ps->o.iconFillSpec.path - && !(ps->o.iconDefault = simg_load(ps, ps->o.iconFillSpec.path, - PICTPOSP_SCALEK, ps->o.preferredIconSize, ps->o.preferredIconSize, - ALIGN_MID, ALIGN_MID, NULL))) - return RET_BADARG; - - setlocale(LC_NUMERIC, lc_numeric_old); - free(lc_numeric_old); - config_free(config); - } + int config_load_ret = load_config_file(ps); + if (config_load_ret != 0) + return config_load_ret; // Second pass parse_args(ps, argc, argv, false); From 61745b5becbab514a661ea0011ca286cd7404801 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 7 Mar 2023 23:34:19 -0800 Subject: [PATCH 077/205] Pipe command to reload config file --- src/skippy.c | 20 +++++++++++++++++++- src/skippy.h | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index db56aa7..9f8e6f6 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -28,6 +28,7 @@ enum pipe_cmd_t { // Not ordered properly for backward compatibility + PIPECMD_RELOAD_CONFIG = 0, PIPECMD_ACTIVATE_WINDOW_PICKER = 1, PIPECMD_EXIT_RUNNING_DAEMON, PIPECMD_DEACTIVATE_WINDOW_PICKER, @@ -905,6 +906,9 @@ mainloop(session_t *ps, bool activate_on_start) { printfdf("(): Received pipe command: %d", piped_input); switch (piped_input) { + case PIPECMD_RELOAD_CONFIG: + load_config_file(ps); + break; case PIPECMD_QUEUE_FI_PREV: ps->o.focus_initial = FI_PREV; break; @@ -996,6 +1000,12 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { return true; } +static inline bool +queue_reload_config(const char *pipePath) { + printfdf("(): Reload config file..."); + return send_command_to_daemon_via_fifo(PIPECMD_RELOAD_CONFIG, pipePath); +} + static inline bool queue_initial_focus_prev(const char *pipePath) { printfdf("(): Set initial focus to previous selection..."); @@ -1269,6 +1279,7 @@ static void parse_args(session_t *ps, int argc, char **argv, bool first_pass) { enum options { OPT_CONFIG = 256, + OPT_CONFIG_RELOAD, OPT_ACTV_PICKER, OPT_DEACTV_PICKER, OPT_TOGGLE_PICKER, @@ -1281,6 +1292,7 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { static const struct option opts_long[] = { { "help", no_argument, NULL, 'h' }, { "config", required_argument, NULL, OPT_CONFIG }, + { "config-reload", no_argument, NULL, OPT_CONFIG_RELOAD }, { "activate-window-picker", no_argument, NULL, OPT_ACTV_PICKER }, { "deactivate-window-picker", no_argument, NULL, OPT_DEACTV_PICKER }, { "toggle-window-picker", no_argument, NULL, OPT_TOGGLE_PICKER }, @@ -1331,6 +1343,9 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { switch (o) { case 'S': break; case OPT_CONFIG: break; + case OPT_CONFIG_RELOAD: + ps->o.mode = PROGMODE_RELOAD_CONFIG; + break; case OPT_PREV: break; case OPT_NEXT: break; case OPT_ACTV_PICKER: @@ -1354,7 +1369,7 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { } } -static int +int load_config_file(session_t *ps) { dlist *config = NULL; @@ -1608,6 +1623,9 @@ int main(int argc, char *argv[]) { } toggle_window_picker(pipePath); goto main_end; + case PROGMODE_RELOAD_CONFIG: + queue_reload_config(pipePath); + goto main_end; case PROGMODE_DM_STOP: exit_daemon(pipePath); goto main_end; diff --git a/src/skippy.h b/src/skippy.h index ae04ee5..0a9a3fb 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -120,6 +120,7 @@ enum progmode { PROGMODE_ACTV_PICKER, PROGMODE_DEACTV_PICKER, PROGMODE_TOGGLE_PICKER, + PROGMODE_RELOAD_CONFIG, PROGMODE_DM_STOP, }; @@ -1367,4 +1368,6 @@ sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) extern session_t *ps_g; +int load_config_file(session_t *ps); + #endif /* SKIPPY_H */ From 55a721489132d56f93cc8bf84c48cd4750fa65fd Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 8 Mar 2023 01:25:08 -0800 Subject: [PATCH 078/205] Complete config reload, with mainwin_reload() also --- src/clientwin.c | 12 ++-- src/mainwin.c | 152 +++++++++++++++++++++++++++--------------------- src/mainwin.h | 1 + src/skippy.c | 2 + 4 files changed, 92 insertions(+), 75 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 2f2d689..866c7a6 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -165,10 +165,6 @@ clientwin_update(ClientWin *cw) { cw->zombie = wattr.map_state != IsViewable; if (IsViewable == wattr.map_state) { - // Create window picture - Drawable draw = cw->cpixmap; - if (!draw) draw = cw->src.window; - static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; cw->origin = XRenderCreatePicture(ps->dpy, cw->src.window, cw->src.format, CPSubwindowMode, &pa); @@ -180,10 +176,10 @@ clientwin_update(ClientWin *cw) { cw->redirected = true; cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); - if (cw->shadow) - free_picture(ps, &cw->shadow); - cw->shadow = XRenderCreatePicture(ps->dpy, - cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); + if (cw->shadow) + free_picture(ps, &cw->shadow); + cw->shadow = XRenderCreatePicture(ps->dpy, + cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); } // Get window icon diff --git a/src/mainwin.c b/src/mainwin.c index abb5fc7..37669ad 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -50,14 +50,6 @@ MainWin * mainwin_create(session_t *ps) { Display * const dpy = ps->dpy; - const char *tmp; - double tmp_d; - XColor exact_color; - XSetWindowAttributes wattr; - XWindowAttributes rootattr; - XRenderPictureAttributes pa; - XRenderColor clear; - // Get ARGB visual. // FIXME: Move this to skippy.c? if (!ps->argb_visual) @@ -67,22 +59,9 @@ mainwin_create(session_t *ps) { MainWin *mw = allocchk(calloc(1, sizeof(MainWin))); mw->ps = ps; - if (ps->o.lazyTrans) { - mw->depth = 32; - mw->visual = ps->argb_visual; - if (!mw->visual) { - printfef("(): Couldn't find ARGB visual, lazy transparency can't work."); - goto mainwin_create_err; - } - } - if (!ps->o.lazyTrans) { - mw->depth = DefaultDepth(dpy, ps->screen); - mw->visual = DefaultVisual(dpy, ps->screen); - } - mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone); mw->bg_pixmap = None; mw->background = None; - mw->format = XRenderFindVisualFormat(dpy, mw->visual); + #ifdef CFG_XINERAMA mw->xin_info = mw->xin_active = 0; mw->xin_screens = 0; @@ -93,6 +72,54 @@ mainwin_create(session_t *ps) { mw->tooltip = 0; mw->cod = 0; + XWindowAttributes rootattr; + XGetWindowAttributes(dpy, ps->root, &rootattr); + mw->x = mw->y = 0; + mw->width = rootattr.width; + mw->height = rootattr.height; + + XSetWindowAttributes wattr; + wattr.colormap = mw->colormap; + wattr.background_pixel = wattr.border_pixel = 0; + wattr.override_redirect = True; + // I have no idea why, but seemingly without ButtonPressMask, we can't + // receive ButtonRelease events in some cases + wattr.event_mask = VisibilityChangeMask | ButtonPressMask + | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; + + mw->window = XCreateWindow(dpy, ps->root, 0, 0, mw->width, mw->height, 0, + mw->depth, InputOutput, mw->visual, + CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &wattr); + if (!mw->window) { + free(mw); + return 0; + } + wm_wid_set_info(ps, mw->window, "main window", None); + +#ifdef CFG_XINERAMA + if (ps->xinfo.xinerama_exist && XineramaIsActive(dpy)) { + mw->xin_info = XineramaQueryScreens(ps->dpy, &mw->xin_screens); +# ifdef DEBUG_XINERAMA + printfef("(): Xinerama is enabled (%d screens).", mw->xin_screens); +# endif /* DEBUG_XINERAMA */ + } +#endif /* CFG_XINERAMA */ + + XCompositeRedirectSubwindows (ps->dpy, ps->root, CompositeRedirectAutomatic); + + return mainwin_reload(ps, mw); +} + +MainWin * +mainwin_reload(session_t *ps, MainWin *mw) { + Display * const dpy = ps->dpy; + + const char *tmp; + double tmp_d; + XColor exact_color; + XRenderPictureAttributes pa; + XRenderColor clear; + // convert the keybindings settings strings into arrays of KeySyms keys_str_syms(ps->o.bindings_keysUp, &mw->keysyms_Up); keys_str_syms(ps->o.bindings_keysDown, &mw->keysyms_Down); @@ -159,46 +186,29 @@ mainwin_create(session_t *ps) { check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress); check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); check_keybindings_conflict(ps->o.config_path, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); - - XGetWindowAttributes(dpy, ps->root, &rootattr); - mw->x = mw->y = 0; - mw->width = rootattr.width; - mw->height = rootattr.height; - - wattr.colormap = mw->colormap; - wattr.background_pixel = wattr.border_pixel = 0; - wattr.override_redirect = True; - // I have no idea why, but seemingly without ButtonPressMask, we can't - // receive ButtonRelease events in some cases - wattr.event_mask = VisibilityChangeMask | ButtonPressMask - | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; - - mw->window = XCreateWindow(dpy, ps->root, 0, 0, mw->width, mw->height, 0, - mw->depth, InputOutput, mw->visual, - CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &wattr); - if (!mw->window) { - free(mw); - return 0; - } - wm_wid_set_info(ps, mw->window, "main window", None); - -#ifdef CFG_XINERAMA - if (ps->xinfo.xinerama_exist && XineramaIsActive(dpy)) { - mw->xin_info = XineramaQueryScreens(ps->dpy, &mw->xin_screens); -# ifdef DEBUG_XINERAMA - printfef("(): Xinerama is enabled (%d screens).", mw->xin_screens); -# endif /* DEBUG_XINERAMA */ - } -#endif /* CFG_XINERAMA */ - - XCompositeRedirectSubwindows (ps->dpy, ps->root, CompositeRedirectAutomatic); tmp_d = ps->o.updateFreq; if(tmp_d != 0.0) mw->poll_time = (1.0 / tmp_d) * 1000.0; else - mw->poll_time = (1.0 / 60.0) * 1000.0; - + mw->poll_time = (1.0 / 200.0) * 1000.0; + + if (ps->o.lazyTrans) { + mw->depth = 32; + mw->visual = ps->argb_visual; + if (!mw->visual) { + printfef("(): Couldn't find ARGB visual, lazy transparency can't work."); + goto mainwin_create_err; + } + } + if (!ps->o.lazyTrans) { + mw->depth = DefaultDepth(dpy, ps->screen); + mw->visual = DefaultVisual(dpy, ps->screen); + } + + mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone); + mw->format = XRenderFindVisualFormat(dpy, mw->visual); + if(!XParseColor(ps->dpy, mw->colormap, ps->o.normal_tint, &exact_color)) { printfef("(): Couldn't look up color '%s', reverting to black.", ps->o.normal_tint); mw->normalTint.red = mw->normalTint.green = mw->normalTint.blue = 0; @@ -229,8 +239,8 @@ mainwin_create(session_t *ps) { tmp = ps->o.shadow_tint; if(! XParseColor(ps->dpy, mw->colormap, tmp, &exact_color)) { - fprintf(stderr, "Couldn't look up color '%s', reverting to #010101", tmp); - mw->shadowTint.red = mw->shadowTint.green = mw->shadowTint.blue = 0x01; + fprintf(stderr, "Couldn't look up color '%s', reverting to #040404", tmp); + mw->shadowTint.red = mw->shadowTint.green = mw->shadowTint.blue = 0x04; } else { @@ -242,24 +252,32 @@ mainwin_create(session_t *ps) { pa.repeat = True; clear.alpha = alphaconv(ps->o.normal_opacity); + if(mw->normalPixmap != None) + XFreePixmap(ps->dpy, mw->normalPixmap); mw->normalPixmap = XCreatePixmap(ps->dpy, mw->window, 1, 1, 8); - mw->normalPicture = XRenderCreatePicture(ps->dpy, mw->normalPixmap, XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); + if(mw->normalPicture != None) + XRenderFreePicture(ps->dpy, mw->normalPicture); + mw->normalPicture = XRenderCreatePicture(ps->dpy, mw->normalPixmap, + XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); XRenderFillRectangle(ps->dpy, PictOpSrc, mw->normalPicture, &clear, 0, 0, 1, 1); clear.alpha = alphaconv(ps->o.highlight_opacity); + if(mw->highlightPixmap != None) + XFreePixmap(ps->dpy, mw->highlightPixmap); mw->highlightPixmap = XCreatePixmap(ps->dpy, mw->window, 1, 1, 8); - mw->highlightPicture = XRenderCreatePicture(ps->dpy, mw->highlightPixmap, XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); + if(mw->highlightPicture != None) + XRenderFreePicture(ps->dpy, mw->highlightPicture); + mw->highlightPicture = XRenderCreatePicture(ps->dpy, mw->highlightPixmap, + XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); XRenderFillRectangle(ps->dpy, PictOpSrc, mw->highlightPicture, &clear, 0, 0, 1, 1); - - clear.alpha = alphaconv(ps->o.shadow_opacity); - mw->shadowPixmap = XCreatePixmap(ps->dpy, mw->window, 1, 1, 8); - mw->shadowPicture = XRenderCreatePicture(ps->dpy, mw->shadowPixmap, XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); - XRenderFillRectangle(ps->dpy, PictOpSrc, mw->shadowPicture, &clear, 0, 0, 1, 1); mw->distance = ps->o.distance; - if (ps->o.tooltip_show) + if (ps->o.tooltip_show) { + if(mw->tooltip) + tooltip_destroy(mw->tooltip); mw->tooltip = tooltip_create(mw); + } return mw; diff --git a/src/mainwin.h b/src/mainwin.h index 17a2549..9fe3352 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -97,6 +97,7 @@ struct _mainwin_t { }; MainWin *mainwin_create(session_t *ps); +MainWin *mainwin_reload(session_t *ps, MainWin *mw); void mainwin_destroy(MainWin *); void mainwin_map(MainWin *); void mainwin_unmap(MainWin *); diff --git a/src/skippy.c b/src/skippy.c index 9f8e6f6..eb4878b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -908,6 +908,7 @@ mainloop(session_t *ps, bool activate_on_start) { switch (piped_input) { case PIPECMD_RELOAD_CONFIG: load_config_file(ps); + mainwin_reload(ps, ps->mainwin); break; case PIPECMD_QUEUE_FI_PREV: ps->o.focus_initial = FI_PREV; @@ -1704,6 +1705,7 @@ int main(int argc, char *argv[]) { free(ps->o.clientDisplayModes); free(ps->o.normal_tint); free(ps->o.highlight_tint); + free(ps->o.shadow_tint); free(ps->o.tooltip_border); free(ps->o.tooltip_background); free(ps->o.tooltip_text); From bd6767f5c914491b5e46073cd4fa5a966b56a8a4 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 8 Mar 2023 02:59:54 -0800 Subject: [PATCH 079/205] Fix inconsistent size of filled windows --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index eb4878b..67afffa 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -272,8 +272,8 @@ anime( mainwin_transform(mw, multiplier); foreach_dlist (mw->cod) { ClientWin *cw = (ClientWin *) iter->data; - clientwin_update2(cw); clientwin_move(cw, multiplier, mw->xoff, mw->yoff, timeslice); + clientwin_update2(cw); clientwin_map(cw); } } From 53f3cd3145be817cd69a25232fc14c1d22170495 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Thu, 9 Mar 2023 23:00:23 +0000 Subject: [PATCH 080/205] config: explain more clearly what certain settings are for --- skippy-xd.sample.rc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 49d91f2..19ff86e 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -60,9 +60,17 @@ updateFreq = 200.0 animationDuration = 200 # set = 0 to switch off animations lazyTrans = false pipePath = /tmp/skippy-xd-fifo + +# Move the mouse cursor to the next highlighted window, straight after launching skippy movePointerOnStart = true + +# Move the mouse cursor over the currently highlighted window, when using the keyboard to navigate between windows movePointerOnSelect = true + +# After activating the selected window, the skippy window picker is dissmissed. Then move mouse cursor to the center of the selected window. +# Otherwise (if false), the mouse cursor will remain in the location where it was at the time when skippy was dismissed. movePointerOnRaise = true + switchDesktopOnActivate = false includeFrame = true allowUpscale = true From 923c8fd2a4b6d528c6ede0df5c815e2c6e66b3bf Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Thu, 9 Mar 2023 23:16:01 +0000 Subject: [PATCH 081/205] config: fix config syntax error - lines cannot have # comments appended to them, all # comments must be on seperate lines --- skippy-xd.sample.rc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 19ff86e..2845090 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -2,6 +2,10 @@ # # Notes: # +# - File Syntax: +# Comments must be on their own seperate lines that start with a # +# You cannot append # comment after a settings line or a section header +# # - colors can be anything XAllocNamedColor can handle # (like "black" or "#000000") # @@ -52,12 +56,18 @@ # [general] -layout = boxy + +# layout = xd (traditional layout), or boxy (=grouped #1) +layout = xd + distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true updateFreq = 200.0 -animationDuration = 200 # set = 0 to switch off animations + +# set = 0 to switch off animations +animationDuration = 200 + lazyTrans = false pipePath = /tmp/skippy-xd-fifo @@ -75,6 +85,7 @@ switchDesktopOnActivate = false includeFrame = true allowUpscale = true showAllDesktops = false +cornerRadius = 0 preferredIconSize = 48 showIconsOnThumbnails = true iconFillSpec = orig mid mid #00FFFF From 146b240b9666b49b711afa98fbbdb6faf1c52ee4 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Thu, 9 Mar 2023 23:25:44 +0000 Subject: [PATCH 082/205] layout: prefer the original XD skippy layout as default setting * Boxy layout (as of this time) isn't yet a preferred layout (by populatity, by general user consensus) * Boxy layout is still relatively new at this point in time (for example, it doesn not seem to render correctly on my system) * Boxy layout may itself be superseeded by a 3rd possible layout style in future All of this means, that while it maybe is preffered for the lead dev (fung) - it should not be default setting as things currently are ATM Please use the following method to keep yourself a custom config with alternate settings: # 1. create custom conf in-repo $ cp skippy-xd.sample.rc skippy-xd.rc # 2. edit custom conf $EDITOR skippy-xd.rc # 3. install custom conf sudo make install # 4. It's then necessary to update your custom.conf periodically. To stay in sync with any changes in the upstream sample.rc --- src/skippy.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.h b/src/skippy.h index 0a9a3fb..3df0e27 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -103,8 +103,8 @@ hexdump(const char *data, int len) { /// @brief Possible return values. enum { - LAYOUT_BOXY, - LAYOUT_XD + LAYOUT_XD, + LAYOUT_BOXY }; enum { @@ -290,7 +290,7 @@ typedef struct { .runAsDaemon = false, \ .synchronize = false, \ \ - .layout = LAYOUT_BOXY, \ + .layout = LAYOUT_XD, \ .distance = 50, \ .useNetWMFullscreen = true, \ .ignoreSkipTaskbar = false, \ From eafc9a905b8416ab564fd4a41e2e7150f3392950 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Thu, 9 Mar 2023 23:52:05 +0000 Subject: [PATCH 083/205] Revert "Next/prev ordering by column rather than row" This reverts commit 5d556bd2429c96df130bb516e390cf4915f3455b. # Conflicts: # src/skippy.h --- src/skippy.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/skippy.h b/src/skippy.h index 3df0e27..5c25a5e 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1350,18 +1350,19 @@ sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) { ClientWin *cw1 = (ClientWin *) dlist1->data; ClientWin *cw2 = (ClientWin *) dlist2->data; - if (cw1->x + cw1->src.width / 2 - < cw2->x + cw2->src.width / 2) - return -1; - else if (cw1->x + cw1->src.width / 2 - > cw2->x + cw2->src.width / 2) - return 1; - else if (cw1->y + cw1->src.height / 2 + + if (cw1->y + cw1->src.height / 2 < cw2->y + cw2->src.height / 2) return -1; else if (cw1->y + cw1->src.height / 2 > cw2->y + cw2->src.height / 2) return 1; + else if (cw1->x + cw1->src.width / 2 + < cw2->x + cw2->src.width / 2) + return -1; + else if (cw1->x + cw1->src.width / 2 + > cw2->x + cw2->src.width / 2) + return 1; else return 0; } From 900c88bc5543520a2f35773be5d27d89be87b059 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Thu, 9 Mar 2023 23:54:46 +0000 Subject: [PATCH 084/205] Revert "Window ordering on window centre." This reverts commit 1e221eaa18c42f76eb79722eb77951e9149c75c0. # Conflicts: # src/skippy.h --- src/skippy.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/skippy.h b/src/skippy.h index 5c25a5e..0239803 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1350,18 +1350,13 @@ sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) { ClientWin *cw1 = (ClientWin *) dlist1->data; ClientWin *cw2 = (ClientWin *) dlist2->data; - - if (cw1->y + cw1->src.height / 2 - < cw2->y + cw2->src.height / 2) + if (cw1->y < cw2->y) return -1; - else if (cw1->y + cw1->src.height / 2 - > cw2->y + cw2->src.height / 2) + else if (cw1->y > cw2->y) return 1; - else if (cw1->x + cw1->src.width / 2 - < cw2->x + cw2->src.width / 2) + else if (cw1->x < cw2->x) return -1; - else if (cw1->x + cw1->src.width / 2 - > cw2->x + cw2->src.width / 2) + else if (cw1->x > cw2->x) return 1; else return 0; From 3849eee7d072c340f92b77f2ccae643e41272462 Mon Sep 17 00:00:00 2001 From: cezaris13 Date: Mon, 27 Feb 2023 23:49:47 +0200 Subject: [PATCH 085/205] Revert "fixed segmentation fault in --start-daemon" This reverts commit a07013f38e092c82200c77b9b7b1e21338339d41. --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 67afffa..558dd0a 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -617,7 +617,7 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; - bool animating = activate; + bool animating = true; long first_animated = 0L; struct pollfd r_fd[2] = { @@ -949,7 +949,7 @@ mainloop(session_t *ps, bool activate_on_start) { else { printfef("(): activate = true;"); - animating = activate = true; + activate = true; } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: @@ -960,7 +960,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; else - animating = activate = true; + activate = true; break; case PIPECMD_EXIT_RUNNING_DAEMON: printfdf("(): Exit command received, killing daemon..."); From 0017e2f54862d869576e24db3190ae672a7c2cdf Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 21 Feb 2023 23:54:38 -0800 Subject: [PATCH 086/205] Fix daemon segfault --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 558dd0a..67afffa 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -617,7 +617,7 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; - bool animating = true; + bool animating = activate; long first_animated = 0L; struct pollfd r_fd[2] = { @@ -949,7 +949,7 @@ mainloop(session_t *ps, bool activate_on_start) { else { printfef("(): activate = true;"); - activate = true; + animating = activate = true; } break; case PIPECMD_DEACTIVATE_WINDOW_PICKER: @@ -960,7 +960,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; else - activate = true; + animating = activate = true; break; case PIPECMD_EXIT_RUNNING_DAEMON: printfdf("(): Exit command received, killing daemon..."); From 562e4f9393966444317b4f84bcb3b1925aba069b Mon Sep 17 00:00:00 2001 From: cezaris13 Date: Wed, 8 Mar 2023 23:51:49 +0200 Subject: [PATCH 087/205] Added corner radius option for mini windows --- skippy-xd.sample.rc | 1 + src/clientwin.c | 30 ++++++++++++++++++++++++++++++ src/skippy.c | 1 + src/skippy.h | 2 ++ 4 files changed, 34 insertions(+) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 2845090..2efccd1 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -69,6 +69,7 @@ updateFreq = 200.0 animationDuration = 200 lazyTrans = false +cornerRadius = 0 # set > 0 to round corners pipePath = /tmp/skippy-xd-fifo # Move the mouse cursor to the next highlighted window, straight after launching skippy diff --git a/src/clientwin.c b/src/clientwin.c index 866c7a6..8c6f6ef 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -33,6 +33,8 @@ clientwin_cmp_func(dlist *l, void *data) { || cw->wid_client == (Window) data; } +void clientwin_round_corners(ClientWin *cw); + int clientwin_validate_func(dlist *l, void *data) { ClientWin *cw = l->data; @@ -361,6 +363,8 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) XRenderFillRectangle(cw->mainwin->ps->dpy, PictOpOver, cw->destination, tint, s_x, s_y, s_w, s_h); } + if(ps->o.cornerRadius) + clientwin_round_corners(cw); XClearArea(cw->mainwin->ps->dpy, cw->mini.window, s_x, s_y, s_w, s_h, False); } @@ -443,6 +447,9 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) XSetWindowBackgroundPixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->pixmap); cw->destination = XRenderCreatePicture(cw->mainwin->ps->dpy, cw->pixmap, cw->mini.format, 0, 0); + + if(cw->mainwin->ps->o.cornerRadius) + clientwin_round_corners(cw); } void @@ -724,3 +731,26 @@ clientwin_action(ClientWin *cw, enum cliop action) { return 0; } + +void clientwin_round_corners(ClientWin *cw) { + session_t* ps = cw->mainwin->ps; + int dia = 2 * ps->o.cornerRadius; + int w = cw->mini.width; + int h = cw->mini.height; + XGCValues xgcv; + Pixmap mask = XCreatePixmap(ps->dpy, cw->mini.window, w, h, 1); + GC shape_gc = XCreateGC(ps->dpy, mask, 0, &xgcv); + + XSetForeground(ps->dpy, shape_gc, 0); + XFillRectangle(ps->dpy, mask, shape_gc, 0, 0, w, h); + XSetForeground(ps->dpy, shape_gc, 1); + XFillArc(ps->dpy, mask, shape_gc, 0, 0, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 360 * 64); + XFillRectangle(ps->dpy, mask, shape_gc, ps->o.cornerRadius, 0, w-dia, h); + XFillRectangle(ps->dpy, mask, shape_gc, 0, ps->o.cornerRadius, w, h-dia); + XShapeCombineMask(ps->dpy, cw->mini.window, ShapeBounding, 0, 0, mask, ShapeSet); + XFreePixmap(ps->dpy, mask); + XFreeGC(ps->dpy, shape_gc); +} \ No newline at end of file diff --git a/src/skippy.c b/src/skippy.c index 67afffa..b01f5da 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1458,6 +1458,7 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); + config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); diff --git a/src/skippy.h b/src/skippy.h index 0239803..a458535 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -235,6 +235,7 @@ typedef struct { bool switchDesktopOnActivate; bool allowUpscale; bool showAllDesktops; + int cornerRadius; int preferredIconSize; client_disp_mode_t *clientDisplayModes; pictspec_t iconFillSpec; @@ -306,6 +307,7 @@ typedef struct { .movePointerOnRaise = true, \ .switchDesktopOnActivate = false, \ .allowUpscale = true, \ + .cornerRadius = 0, \ .preferredIconSize = 48, \ .clientDisplayModes = NULL, \ .iconFillSpec = PICTSPECT_INIT, \ From 20f10365b0f76e5111fcfd5d610386a9bf7e2197 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Fri, 10 Mar 2023 00:16:34 +0000 Subject: [PATCH 088/205] config: fix invalid # comments syntax (my mistake for asking for this, sorry to mislead anybody...) --- skippy-xd.sample.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 2efccd1..a317fab 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -69,7 +69,7 @@ updateFreq = 200.0 animationDuration = 200 lazyTrans = false -cornerRadius = 0 # set > 0 to round corners +cornerRadius = 0 pipePath = /tmp/skippy-xd-fifo # Move the mouse cursor to the next highlighted window, straight after launching skippy From 109c59f22967180841cde5f8c1ab4efe1968a019 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Fri, 10 Mar 2023 00:35:12 +0000 Subject: [PATCH 089/205] corner radius - thanks! just a little bit of extra finessing / massaging, closes pr #55 this feature might have some yet-to-be resolved visual drawing bug(s), but is nice / usable --- skippy-xd.sample.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index a317fab..2845090 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -69,7 +69,6 @@ updateFreq = 200.0 animationDuration = 200 lazyTrans = false -cornerRadius = 0 pipePath = /tmp/skippy-xd-fifo # Move the mouse cursor to the next highlighted window, straight after launching skippy From d0557c3144fc67568a49d7207efef89c1d5777a0 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Fri, 10 Mar 2023 02:05:38 +0000 Subject: [PATCH 090/205] v0.6.0 - update README and changelog, with new version --- CHANGELOG | 10 ++++++---- README.md | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c715c37..77bf35d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,12 @@ Skippy-XD changelog +0.6.0~fung -- "" (10 Mar 2023) ~/felixfung + - Iconized thumbnails + - Config reloading while daemon is kept running + - Rounded Corners + - Boxy layout / multiple layouts + 0.5.2~pre -- "Puzzlebox" (09 Sept 2018) ~/dreamcat4 - ===== - - This is a pre-release version. Certain features are not fully complete. - When the release is ready, this msg + the '~pre' tag will be removed. - ===== - Fully customizable keybindings, and documentation for configuring them - Default keybindings settings made consistent with 'Alt-Tab' behaviour - (Alt-Tab) New --prev and --next args for --activate and --toggle modes diff --git a/README.md b/README.md index a59e7e1..d62d2da 100644 --- a/README.md +++ b/README.md @@ -175,12 +175,22 @@ Be sure to separate with ` ` spaces each keybinding in a given setting. Like `ke ## Maintainership / Contributions -The last 'stable maintiner' of this software was [richardgv](https://github.com/richardgv). And that is where the vast majority of Skippy issues are raised / the bug tracker is still on his [fork over there](https://github.com/richardgv/skippy-xd/issues). However at this time, it looks like Richard really does not have time anymore to continue to maintain this software anymore (since 2015). And neither do I as a matter of fact. +* Creator: Hyriand (2004) - This makes skippy-xd 19 years old now... +* Current lead developer: `felixfung`. Who has made some fantastic improvements to skippy-xd during the year 2023+ +* Contributions from: `richardgv`, `dreamcat4`, `felixfung`, `cezaris13`, and many others (please edit this line to add any here missing contributor credits) +* Maintenance / Secondary supportive role: `dreamcat4` +* Previous stable maintiner: `richardgv`. -This project is definately in need of a new maintainer. In the meantime, best thing we can do is to just fork based off the latest / most reaonable commits. And add whatever feature(s) or bugfixes ontop of that version. A top priority (very important) is not to be super-picky about this but: make safe changes to the code. Do not do anything that is *too risky* or over-extend yourself. Definately play on the safe side. For some pointers see next section +Richard's upstreamm repo was previously where the majority of Skippy issues were raised. A bug tracker is still over [on his fork](https://github.com/richardgv/skippy-xd/issues). With all older legacy issues. However at this time, it looks like, (as Richard had previously indicated) that he really does not have time anymore to continue to maintain this software (since 2015). But he is welcome to come back and see what developements have been going on in his absense! + +In the meanntime we maintain new bugs tracker, here on this fork. And welcome any contributions / PRs. + +This project is in need of more contributors, and perhaps a new maintainer. Best thing we can do is just continue along over here. Adding whatever feature(s) & bugfixes ontop of the latest version. ## Developer notes +A top priority (very important) is not to be super-picky about this but: make safe changes to the code. Do not do anything that is *too risky* or over-extend yourself. Definately play on the safe side. + Here are 3 basic safeguard mechanisms you can use in this project: 1) Uncomment the `--test` developer test mode. And use it as a temporary sandbox to test any new library functions that you need to add. Throw bad input at all your new funtions. Specifically try to catch errors regarding the memory management. Bad pointers, not checking for null, etc. And when such a bug is found, try to use that as a reason for justifying a further scrutinyg / enhancement of your error handling, in your new code. Spend the vast majority of your developer time just writing the parts of the code that does the error handling. I estimate that I spend something like around 75% of my time doing that, and catching errors. With the remaining 25% of my time (or even less than that) on the actual 'doing stuff' new code that not library functinos. I.e. working in the existing skippy code paths / where I was actually trying to implement the new feature. That 'felt right' (for me) in C. Particularly because C has is no garbage collection / pointer safety, etc. And a large percentage of my bugs (perhaps about half of them!) were almost completely hidden to me, unless the code was actually exercised with bad input. In order to exercise those non-critical code paths. From 3160f7e2a39d379f1aad1d73a4d7cee337305e93 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 9 Mar 2023 18:24:34 -0800 Subject: [PATCH 091/205] Fix animation frames --- skippy-xd.sample.rc | 4 ++-- src/clientwin.c | 14 +++++++++----- src/skippy.c | 30 +++++++++++++++++++----------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 2845090..a86152f 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -63,7 +63,7 @@ layout = xd distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true -updateFreq = 200.0 +updateFreq = 60.0 # set = 0 to switch off animations animationDuration = 200 @@ -108,7 +108,7 @@ opacity = 255 [shadow] tint = #040404 tintOpacity = 164 -opacity = 255 +opacity = 200 [tooltip] show = true diff --git a/src/clientwin.c b/src/clientwin.c index 8c6f6ef..529d38c 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -92,6 +92,11 @@ clientwin_create(MainWin *mw, Window client) { cw->mainwin = mw; cw->wid_client = client; cw->origin = None; + cw->destination = None; + cw->shadow = None; + cw->pixmap = None; + cw->cpixmap = None; + if (ps->o.includeFrame) cw->src.window = wm_find_frame(ps, client); if (!cw->src.window) @@ -125,8 +130,6 @@ clientwin_create(MainWin *mw, Window client) { free(str); } - cw->cpixmap = None; - // Listen to events on the window. We don't want to miss any changes so // this is to be done as early as possible XSelectInput(cw->mainwin->ps->dpy, cw->src.window, SubstructureNotifyMask | StructureNotifyMask); @@ -164,15 +167,14 @@ clientwin_update(ClientWin *cw) { cw->src.format = XRenderFindVisualFormat(ps->dpy, wattr.visual); } - cw->zombie = wattr.map_state != IsViewable; - if (IsViewable == wattr.map_state) { + // create cw->origin static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; cw->origin = XRenderCreatePicture(ps->dpy, cw->src.window, cw->src.format, CPSubwindowMode, &pa); XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); - // Get window pixmap + // create cw->shadow XCompositeRedirectWindow(ps->dpy, cw->src.window, CompositeRedirectAutomatic); cw->redirected = true; @@ -193,6 +195,8 @@ clientwin_update(ClientWin *cw) { cw->mini.x = cw->mini.y = 0; cw->mini.width = cw->mini.height = 1; + cw->zombie = wattr.map_state != IsViewable; + // modes are CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, // CLIDISP_ZOMBIE_ICON, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE // if we ever got a thumbnail for the window, diff --git a/src/skippy.c b/src/skippy.c index b01f5da..1027818 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -267,7 +267,6 @@ anime( ) { clients = dlist_first(clients); - wm_get_current_desktop(mw->ps); float multiplier = 1.0 + timeslice * (mw->multiplier - 1.0); mainwin_transform(mw, multiplier); foreach_dlist (mw->cod) { @@ -709,22 +708,31 @@ mainloop(session_t *ps, bool activate_on_start) { { // animation! if (mw && animating) { - last_rendered = time_in_millis(); - long timeslice = time_in_millis() - first_animated; - anime(ps->mainwin, ps->mainwin->clients, - ((float)timeslice)/(float)ps->o.animationDuration); - if ( timeslice >= ps->o.animationDuration) { + int timeslice = time_in_millis() - first_animated; + if (timeslice < ps->o.animationDuration + && timeslice + first_animated >= + last_rendered + ps->mainwin->poll_time) { + anime(ps->mainwin, ps->mainwin->clients, + ((float)timeslice)/(float)ps->o.animationDuration); + last_rendered = time_in_millis(); + + /* Map the main window and run our event loop */ + if (!ps->o.lazyTrans && !mw->mapped) + mainwin_map(mw); + XFlush(ps->dpy); + } + else if (timeslice >= ps->o.animationDuration) { anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; last_rendered = time_in_millis(); focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); - } - /* Map the main window and run our event loop */ - if (!ps->o.lazyTrans && !mw->mapped) - mainwin_map(mw); - XFlush(ps->dpy); + /* Map the main window and run our event loop */ + if (!ps->o.lazyTrans && !mw->mapped) + mainwin_map(mw); + XFlush(ps->dpy); + } continue; // while animating, do not allow user actions } From a1eb955e98c82b4feda0c0ed883a5cc738bd28c9 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 9 Mar 2023 18:55:34 -0800 Subject: [PATCH 092/205] Implement opacity for shadow windows --- src/clientwin.c | 7 +++++-- src/mainwin.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 529d38c..3a13d79 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -327,8 +327,11 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) // Drawing main picture { - const Picture mask = (cw->focused ? cw->mainwin->highlightPicture : - cw->mainwin->normalPicture); + Picture mask = cw->mainwin->normalPicture; + if (cw->focused) + mask = cw->mainwin->highlightPicture; + else if (cw->zombie) + mask = cw->mainwin->shadowPicture; if (ps->o.lazyTrans) { XRenderComposite(ps->dpy, PictOpSrc, source, mask, diff --git a/src/mainwin.c b/src/mainwin.c index 37669ad..08e7b6b 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -235,7 +235,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { mw->highlightTint.blue = exact_color.blue; } mw->highlightTint.alpha = alphaconv(ps->o.highlight_tintOpacity); - + tmp = ps->o.shadow_tint; if(! XParseColor(ps->dpy, mw->colormap, tmp, &exact_color)) { @@ -260,7 +260,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { mw->normalPicture = XRenderCreatePicture(ps->dpy, mw->normalPixmap, XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); XRenderFillRectangle(ps->dpy, PictOpSrc, mw->normalPicture, &clear, 0, 0, 1, 1); - + clear.alpha = alphaconv(ps->o.highlight_opacity); if(mw->highlightPixmap != None) XFreePixmap(ps->dpy, mw->highlightPixmap); @@ -271,6 +271,16 @@ mainwin_reload(session_t *ps, MainWin *mw) { XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); XRenderFillRectangle(ps->dpy, PictOpSrc, mw->highlightPicture, &clear, 0, 0, 1, 1); + clear.alpha = alphaconv(ps->o.shadow_opacity); + if(mw->shadowPixmap != None) + XFreePixmap(ps->dpy, mw->shadowPixmap); + mw->shadowPixmap = XCreatePixmap(ps->dpy, mw->window, 1, 1, 8); + if(mw->shadowPicture != None) + XRenderFreePicture(ps->dpy, mw->shadowPicture); + mw->shadowPicture = XRenderCreatePicture(ps->dpy, mw->shadowPixmap, + XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); + XRenderFillRectangle(ps->dpy, PictOpSrc, mw->shadowPicture, &clear, 0, 0, 1, 1); + mw->distance = ps->o.distance; if (ps->o.tooltip_show) { From 2a7fa1a3668adb8666693a699bef7d3e5f15dae9 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 15 Mar 2023 00:04:28 -0700 Subject: [PATCH 093/205] Free some resources, no performance difference noted --- src/clientwin.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 8c6f6ef..e02adc8 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -168,15 +168,19 @@ clientwin_update(ClientWin *cw) { if (IsViewable == wattr.map_state) { static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; - cw->origin = XRenderCreatePicture(ps->dpy, - cw->src.window, cw->src.format, CPSubwindowMode, &pa); - XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); + if (cw->origin) + free_picture(ps, &cw->origin); + cw->origin = XRenderCreatePicture(ps->dpy, + cw->src.window, cw->src.format, CPSubwindowMode, &pa); + XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); // Get window pixmap - XCompositeRedirectWindow(ps->dpy, cw->src.window, - CompositeRedirectAutomatic); - cw->redirected = true; - cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); + XCompositeRedirectWindow(ps->dpy, cw->src.window, + CompositeRedirectAutomatic); + cw->redirected = true; + if (cw->cpixmap) + free_pixmap(ps, &cw->cpixmap); + cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); if (cw->shadow) free_picture(ps, &cw->shadow); @@ -753,4 +757,4 @@ void clientwin_round_corners(ClientWin *cw) { XShapeCombineMask(ps->dpy, cw->mini.window, ShapeBounding, 0, 0, mask, ShapeSet); XFreePixmap(ps->dpy, mask); XFreeGC(ps->dpy, shape_gc); -} \ No newline at end of file +} From 0d43ed501430cd45ca5edf18e400f87d8c4f38ff Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 15 Mar 2023 00:12:40 -0700 Subject: [PATCH 094/205] Whitespace --- src/clientwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clientwin.c b/src/clientwin.c index 4de1ce7..033ba99 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -169,7 +169,7 @@ clientwin_update(ClientWin *cw) { if (IsViewable == wattr.map_state) { // create cw->origin - static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; + static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; if (cw->origin) free_picture(ps, &cw->origin); cw->origin = XRenderCreatePicture(ps->dpy, From e5ba295f64c9acd648ee3db914adfb1cf5a53288 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 15 Mar 2023 01:09:32 -0700 Subject: [PATCH 095/205] mainwin_create() mw->visual proper ordering --- src/mainwin.c | 72 ++++++++++++++++++++++++++++----------------------- src/mainwin.h | 1 + 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/mainwin.c b/src/mainwin.c index 08e7b6b..ce47a0a 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -86,7 +86,9 @@ mainwin_create(session_t *ps) { // receive ButtonRelease events in some cases wattr.event_mask = VisibilityChangeMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; - + + mw = mainwin_reload(ps, mw); + mw->window = XCreateWindow(dpy, ps->root, 0, 0, mw->width, mw->height, 0, mw->depth, InputOutput, mw->visual, CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &wattr); @@ -96,6 +98,8 @@ mainwin_create(session_t *ps) { } wm_wid_set_info(ps, mw->window, "main window", None); + mainwin_create_pixmap(mw); + #ifdef CFG_XINERAMA if (ps->xinfo.xinerama_exist && XineramaIsActive(dpy)) { mw->xin_info = XineramaQueryScreens(ps->dpy, &mw->xin_screens); @@ -107,19 +111,13 @@ mainwin_create(session_t *ps) { XCompositeRedirectSubwindows (ps->dpy, ps->root, CompositeRedirectAutomatic); - return mainwin_reload(ps, mw); + return mw; } MainWin * mainwin_reload(session_t *ps, MainWin *mw) { Display * const dpy = ps->dpy; - const char *tmp; - double tmp_d; - XColor exact_color; - XRenderPictureAttributes pa; - XRenderColor clear; - // convert the keybindings settings strings into arrays of KeySyms keys_str_syms(ps->o.bindings_keysUp, &mw->keysyms_Up); keys_str_syms(ps->o.bindings_keysDown, &mw->keysyms_Down); @@ -187,11 +185,10 @@ mainwin_reload(session_t *ps, MainWin *mw) { check_keybindings_conflict(ps->o.config_path, "keysExitCancelOnRelease", mw->keysyms_ExitCancelOnRelease, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); check_keybindings_conflict(ps->o.config_path, "keysExitSelectOnPress", mw->keysyms_ExitSelectOnPress, "keysExitSelectOnRelease", mw->keysyms_ExitSelectOnRelease); - tmp_d = ps->o.updateFreq; - if(tmp_d != 0.0) - mw->poll_time = (1.0 / tmp_d) * 1000.0; + if (ps->o.updateFreq != 0.0) + mw->poll_time = (1.0 / ps->o.updateFreq) * 1000.0; else - mw->poll_time = (1.0 / 200.0) * 1000.0; + mw->poll_time = (1.0 / 60.0) * 1000.0; if (ps->o.lazyTrans) { mw->depth = 32; @@ -209,6 +206,8 @@ mainwin_reload(session_t *ps, MainWin *mw) { mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone); mw->format = XRenderFindVisualFormat(dpy, mw->visual); + XColor exact_color; + if(!XParseColor(ps->dpy, mw->colormap, ps->o.normal_tint, &exact_color)) { printfef("(): Couldn't look up color '%s', reverting to black.", ps->o.normal_tint); mw->normalTint.red = mw->normalTint.green = mw->normalTint.blue = 0; @@ -220,11 +219,10 @@ mainwin_reload(session_t *ps, MainWin *mw) { mw->normalTint.blue = exact_color.blue; } mw->normalTint.alpha = alphaconv(ps->o.normal_tintOpacity); - - tmp = ps->o.highlight_tint; - if(! XParseColor(ps->dpy, mw->colormap, tmp, &exact_color)) + + if(! XParseColor(ps->dpy, mw->colormap, ps->o.highlight_tint, &exact_color)) { - fprintf(stderr, "Couldn't look up color '%s', reverting to #101020", tmp); + fprintf(stderr, "Couldn't look up color '%s', reverting to #101020", ps->o.highlight_tint); mw->highlightTint.red = mw->highlightTint.green = 0x10; mw->highlightTint.blue = 0x20; } @@ -236,10 +234,10 @@ mainwin_reload(session_t *ps, MainWin *mw) { } mw->highlightTint.alpha = alphaconv(ps->o.highlight_tintOpacity); - tmp = ps->o.shadow_tint; - if(! XParseColor(ps->dpy, mw->colormap, tmp, &exact_color)) + ; + if(! XParseColor(ps->dpy, mw->colormap, ps->o.shadow_tint, &exact_color)) { - fprintf(stderr, "Couldn't look up color '%s', reverting to #040404", tmp); + fprintf(stderr, "Couldn't look up color '%s', reverting to #040404", ps->o.shadow_tint); mw->shadowTint.red = mw->shadowTint.green = mw->shadowTint.blue = 0x04; } else @@ -250,6 +248,29 @@ mainwin_reload(session_t *ps, MainWin *mw) { } mw->shadowTint.alpha = alphaconv(ps->o.shadow_tintOpacity); + mw->distance = ps->o.distance; + + if (ps->o.tooltip_show) { + if(mw->tooltip) + tooltip_destroy(mw->tooltip); + mw->tooltip = tooltip_create(mw); + } + + return mw; + +mainwin_create_err: + if (mw) + free(mw); + return NULL; +} + +MainWin * +mainwin_create_pixmap(MainWin *mw) { + session_t *ps = mw->ps; + + XRenderPictureAttributes pa; + XRenderColor clear; + pa.repeat = True; clear.alpha = alphaconv(ps->o.normal_opacity); if(mw->normalPixmap != None) @@ -281,20 +302,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { XRenderFindStandardFormat(ps->dpy, PictStandardA8), CPRepeat, &pa); XRenderFillRectangle(ps->dpy, PictOpSrc, mw->shadowPicture, &clear, 0, 0, 1, 1); - mw->distance = ps->o.distance; - - if (ps->o.tooltip_show) { - if(mw->tooltip) - tooltip_destroy(mw->tooltip); - mw->tooltip = tooltip_create(mw); - } - return mw; - -mainwin_create_err: - if (mw) - free(mw); - return NULL; } void diff --git a/src/mainwin.h b/src/mainwin.h index 9fe3352..f1f51de 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -104,6 +104,7 @@ void mainwin_unmap(MainWin *); int mainwin_handle(MainWin *, XEvent *); void mainwin_update_background(MainWin *mw); void mainwin_update(MainWin *mw); +MainWin *mainwin_create_pixmap(MainWin *mw); void mainwin_transform(MainWin *mw, float f); #endif /* SKIPPY_MAINWIN_H */ From 6c03ffb0d7cc03e019cff83d604c56d09653f77c Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 15 Mar 2023 01:18:10 -0700 Subject: [PATCH 096/205] Update changelog --- CHANGELOG | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 77bf35d..5a6caff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,11 @@ Skippy-XD changelog 0.6.0~fung -- "" (10 Mar 2023) ~/felixfung - - Iconized thumbnails + - Thumbnail displays for iconized or otherwise unmapped windows + - Animation when activating skippy + - Boxy layout / multiple layouts - Config reloading while daemon is kept running - Rounded Corners - - Boxy layout / multiple layouts 0.5.2~pre -- "Puzzlebox" (09 Sept 2018) ~/dreamcat4 - Fully customizable keybindings, and documentation for configuring them From 81fbe71e2d6b6d0a59a0268008f76cb36501c6c7 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 15 Mar 2023 21:17:23 -0700 Subject: [PATCH 097/205] Improve animation movement --- src/clientwin.c | 17 +++++------------ src/skippy.c | 11 +++++++++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 033ba99..0932b62 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -428,22 +428,15 @@ clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) XSetWindowBorderWidth(cw->mainwin->ps->dpy, cw->mini.window, border); cw->factor = f; - cw->mini.x = x + (float) cw->x * f; - cw->mini.y = y + (float) cw->y * f; - if(cw->mainwin->ps->o.lazyTrans) - { - cw->mini.x += cw->mainwin->x; - cw->mini.y += cw->mainwin->y; - } - { // animate window by changing these in time linearly: // here, cw->mini has destination coordinates, cw->src has original coordinates - cw->mini.x = cw->src.x + (float) (cw->mini.x - cw->src.x) * timeslice; - cw->mini.y = cw->src.y + (float) (cw->mini.y - cw->src.y) * timeslice; - cw->mini.width = (float) cw->src.width * f; - cw->mini.height = (float) cw->src.height * f; + cw->mini.x = cw->src.x + (cw->x - cw->src.x + x) * timeslice; + cw->mini.y = cw->src.y + (cw->y - cw->src.y + y) * timeslice; + + cw->mini.width = cw->src.width * f; + cw->mini.height = cw->src.height * f; } XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height); diff --git a/src/skippy.c b/src/skippy.c index 1027818..7d2e198 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -535,6 +535,17 @@ skippy_activate(MainWin *mw, Window leader) return false; } + foreach_dlist(mw->clients) { + ClientWin *cw = iter->data; + if(mw->ps->o.lazyTrans) + { + cw->x += cw->mainwin->x; + cw->y += cw->mainwin->y; + } + cw->x *= mw->multiplier; + cw->y *= mw->multiplier; + } + // Get the currently focused window and select which mini-window to focus { dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) mw->revert_focus_win); From 2247d0607c551ee83c8fe1970111b62a23c68c85 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 29 Mar 2023 01:54:01 -0700 Subject: [PATCH 098/205] Correct mainwin_reload() ordering --- src/mainwin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mainwin.c b/src/mainwin.c index ce47a0a..e708dc9 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -78,6 +78,8 @@ mainwin_create(session_t *ps) { mw->width = rootattr.width; mw->height = rootattr.height; + mw = mainwin_reload(ps, mw); + XSetWindowAttributes wattr; wattr.colormap = mw->colormap; wattr.background_pixel = wattr.border_pixel = 0; @@ -87,8 +89,6 @@ mainwin_create(session_t *ps) { wattr.event_mask = VisibilityChangeMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; - mw = mainwin_reload(ps, mw); - mw->window = XCreateWindow(dpy, ps->root, 0, 0, mw->width, mw->height, 0, mw->depth, InputOutput, mw->visual, CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &wattr); From 3520aefe0a225df724e324ffa2fadc89db2f84ea Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 29 Mar 2023 02:53:00 -0700 Subject: [PATCH 099/205] Add sortByColumn user config --- skippy-xd.sample.rc | 10 +++++-- src/focus.c | 4 +-- src/focus.h | 10 +++---- src/mainwin.c | 3 ++- src/mainwin.h | 2 +- src/skippy.c | 63 ++++++++++++++++++++++++--------------------- src/skippy.h | 26 ++++++++++++++++++- 7 files changed, 77 insertions(+), 41 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index a86152f..97ed757 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -57,8 +57,14 @@ [general] -# layout = xd (traditional layout), or boxy (=grouped #1) -layout = xd +# layout=boxy is favoured by expo usage +# layout=xd is favoured by alt+tab usage +layout = boxy + +# sort by row or sort by column +# sorting by column is favoured by boxy layout +# sorting by row is favoured by xd layout +sortByColumn = true distance = 50 useNetWMFullscreen = true diff --git a/src/focus.c b/src/focus.c index 0e4dbca..114f157 100644 --- a/src/focus.c +++ b/src/focus.c @@ -31,7 +31,7 @@ focus_miniw_dir(ClientWin *cw, match_func match, dist_func func) { ClientWin *candidate = NULL; session_t * const ps = cw->mainwin->ps; - dlist *candidates = dlist_first(dlist_find_all(cw->mainwin->cod, (dlist_match_func) match, &cw->mini)); + dlist *candidates = dlist_first(dlist_find_all(cw->mainwin->focuslist, (dlist_match_func) match, &cw->mini)); if (!candidates) return; foreach_dlist (candidates) { @@ -43,7 +43,7 @@ focus_miniw_dir(ClientWin *cw, match_func match, dist_func func) { } } - clear_focus_all(cw->mainwin->cod); + clear_focus_all(cw->mainwin->focuslist); clientwin_render(cw); XFlush(ps->dpy); diff --git a/src/focus.h b/src/focus.h index 3b5e46a..87bcd05 100644 --- a/src/focus.h +++ b/src/focus.h @@ -58,9 +58,9 @@ printfefXFocusChangeEvent(session_t *ps, XFocusChangeEvent *evf) } static inline void -clear_focus_all(dlist *cod) +clear_focus_all(dlist *focuslist) { - dlist *elem = dlist_first(cod); + dlist *elem = dlist_first(focuslist); while (elem) { ClientWin *cw = (ClientWin *)elem->data; @@ -80,7 +80,7 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { if (!cw || !ps) return; - clear_focus_all(cw->mainwin->cod); + clear_focus_all(cw->mainwin->focuslist); //printfefWindowName(ps, "(): window = ", cw->wid_client); @@ -118,7 +118,7 @@ focus_miniw(session_t *ps, ClientWin *cw) { */ static inline void focus_miniw_next(session_t *ps, ClientWin *cw) { - dlist *e = dlist_find_data(cw->mainwin->cod, cw); + dlist *e = dlist_find_data(cw->mainwin->focuslist, cw); if (!e) { printfef("(%#010lx): Client window not found in list.", cw->src.window); return; @@ -134,7 +134,7 @@ focus_miniw_next(session_t *ps, ClientWin *cw) { */ static inline void focus_miniw_prev(session_t *ps, ClientWin *cw) { - dlist *cwlist = dlist_first(cw->mainwin->cod); + dlist *cwlist = dlist_first(cw->mainwin->focuslist); dlist *tgt = NULL; if (cw == cwlist->data) diff --git a/src/mainwin.c b/src/mainwin.c index e708dc9..80e9fdd 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -70,7 +70,8 @@ mainwin_create(session_t *ps) { // mw->pressed = mw->focus = 0; mw->pressed = mw->client_to_focus = 0; mw->tooltip = 0; - mw->cod = 0; + mw->clientondesktop = 0; + mw->focuslist = 0; XWindowAttributes rootattr; XGetWindowAttributes(dpy, ps->root, &rootattr); diff --git a/src/mainwin.h b/src/mainwin.h index f1f51de..3313b92 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -50,7 +50,7 @@ struct _mainwin_t { Picture normalPicture, highlightPicture, shadowPicture; ClientWin *pressed, *focus; - dlist *cod; + dlist *clientondesktop, *focuslist; struct _Tooltip *tooltip; KeySym *keysyms_Up; diff --git a/src/skippy.c b/src/skippy.c index 7d2e198..c8f5fbf 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -269,7 +269,7 @@ anime( clients = dlist_first(clients); float multiplier = 1.0 + timeslice * (mw->multiplier - 1.0); mainwin_transform(mw, multiplier); - foreach_dlist (mw->cod) { + foreach_dlist (mw->clientondesktop) { ClientWin *cw = (ClientWin *) iter->data; clientwin_move(cw, multiplier, mw->xoff, mw->yoff, timeslice); clientwin_update2(cw); @@ -325,10 +325,10 @@ update_clients(MainWin *mw, Bool *touched) static void daemon_count_clients(MainWin *mw, Bool *touched, Window leader) { - // given the client table, update the cod - // the difference between mw->clients and mw->cod + // given the client table, update the clientondesktop + // the difference between mw->clients and mw->clientondesktop // is that mw->clients is all the client windows - // while mw->cod is only those in current virtual desktop + // while mw->clientondesktop is only those in current virtual desktop // if that option is user supplied // printfef("(): updating dl list of clients"); @@ -338,8 +338,8 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) return; } - dlist_free(mw->cod); - mw->cod = NULL; + dlist_free(mw->clientondesktop); + mw->clientondesktop = NULL; { session_t * const ps = mw->ps; @@ -353,11 +353,11 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) } if (leader) { - mw->cod = dlist_first(dlist_find_all(tmp, clientwin_check_group_leader_func, (void*)&leader)); + mw->clientondesktop = dlist_first(dlist_find_all(tmp, clientwin_check_group_leader_func, (void*)&leader)); dlist_free(tmp); } else { - mw->cod = tmp; + mw->clientondesktop = tmp; } } @@ -367,19 +367,23 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) static void init_layout(MainWin *mw, Window focus, Window leader) { - if (!mw->cod) + if (!mw->clientondesktop) return; - dlist_sort(mw->cod, clientwin_sort_func, 0); + dlist_sort(mw->clientondesktop, clientwin_sort_func, 0); /* set up the windows layout */ { unsigned int newwidth = 0, newheight = 0; - layout_run(mw, mw->cod, &newwidth, &newheight); + layout_run(mw, mw->clientondesktop, &newwidth, &newheight); // ordering of client windows list // is important for prev/next window selection - dlist_sort(mw->cod, sort_cw_by_pos, 0); + if (mw->ps->o.sortByColumn) + dlist_sort(mw->clientondesktop, sort_cw_by_column, 0); + else + dlist_sort(mw->clientondesktop, sort_cw_by_row, 0); + mw->focuslist = mw->clientondesktop; float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; if (multiplier * newheight > mw->height - 2 * mw->distance) @@ -530,7 +534,7 @@ skippy_activate(MainWin *mw, Window leader) } init_layout(mw, mw->revert_focus_win, leader); - if (!mw->cod) { + if (!mw->clientondesktop) { printfef("(): Failed to build layout."); return false; } @@ -548,7 +552,7 @@ skippy_activate(MainWin *mw, Window leader) // Get the currently focused window and select which mini-window to focus { - dlist *iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) mw->revert_focus_win); + dlist *iter = dlist_find(mw->clientondesktop, clientwin_cmp_func, (void *) mw->revert_focus_win); // check if the user specified --prev or --next on the cmdline if(ps->o.focus_initial) @@ -561,12 +565,12 @@ skippy_activate(MainWin *mw, Window leader) if(ps->o.focus_initial == FI_PREV) { - // here, mw->cod is the first (dlist*) item in the list - if (iter == mw->cod) - iter = dlist_last(mw->cod); + // here, mw->clientondesktop is the first (dlist*) item in the list + if (iter == mw->clientondesktop) + iter = dlist_last(mw->clientondesktop); else { - dlist *i = mw->cod; + dlist *i = mw->clientondesktop; for (; i != NULL; i = i->next) if (i->next && i->next == iter) break; @@ -582,7 +586,7 @@ skippy_activate(MainWin *mw, Window leader) ps->o.focus_initial = 0; if (!iter) - iter = mw->cod; + iter = mw->clientondesktop; // mw->focus = (ClientWin *) iter->data; mw->client_to_focus = (ClientWin *) iter->data; @@ -671,7 +675,7 @@ mainloop(session_t *ps, bool activate_on_start) { // Unmap the main window and all clients, to make sure focus doesn't fall out // when we start setting focus on client window mainwin_unmap(mw); - foreach_dlist(mw->cod) { clientwin_unmap((ClientWin *) iter->data); } + foreach_dlist(mw->clientondesktop) { clientwin_unmap((ClientWin *) iter->data); } XSync(ps->dpy, False); // Focus the client window only after the main window get unmapped and @@ -684,8 +688,8 @@ mainloop(session_t *ps, bool activate_on_start) { } // Cleanup - dlist_free(mw->cod); - mw->cod = 0; + dlist_free(mw->clientondesktop); + mw->clientondesktop = 0; if (refocus && mw->revert_focus_win) { // printfef("(): if (refocus && mw->revert_focus_win) {"); @@ -806,11 +810,11 @@ mainloop(session_t *ps, bool activate_on_start) { ClientWin *cw = (ClientWin *) iter->data; if (!cw->mode) { mw->clients = dlist_first(dlist_remove(iter)); - iter = dlist_find(mw->cod, clientwin_cmp_func, (void *) wid); + iter = dlist_find(mw->clientondesktop, clientwin_cmp_func, (void *) wid); if (iter) - mw->cod = dlist_first(dlist_remove(iter)); + mw->clientondesktop = dlist_first(dlist_remove(iter)); clientwin_destroy(cw, true); - if (!mw->cod) { + if (!mw->clientondesktop) { printfef("(): Last client window destroyed/unmapped, " "exiting."); die = true; @@ -861,16 +865,16 @@ mainloop(session_t *ps, bool activate_on_start) { // printfef("(): if (!ps->o.background && ..."); // printfef("(): mainwin_update_background(mw);"); - // printfef("(): REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod);"); + // printfef("(): REDUCE(clientwin_render((ClientWin *)iter->data), mw->clientondesktop);"); mainwin_update_background(mw); - REDUCE(clientwin_render((ClientWin *)iter->data), mw->cod); + REDUCE(clientwin_render((ClientWin *)iter->data), mw->clientondesktop); } } else if (mw && mw->tooltip && wid == mw->tooltip->window) tooltip_handle(mw->tooltip, &ev); else if (mw && wid) { - for (dlist *iter = mw->cod; iter; iter = iter->next) { + for (dlist *iter = mw->clientondesktop; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { if (!(POLLIN & r_fd[1].revents)) @@ -889,7 +893,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw && pending_damage && !die) { //printfdf("(): delayed painting"); pending_damage = false; - foreach_dlist(mw->cod) { + foreach_dlist(mw->clientondesktop) { if (((ClientWin *) iter->data)->damaged) { // printfef("(): if (((ClientWin *) iter->data)->damaged)"); @@ -1467,6 +1471,7 @@ load_config_file(session_t *ps) } } } + config_get_bool_wrap(config, "general", "sortByColumn", &ps->o.sortByColumn); config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); config_get_bool_wrap(config, "general", "ignoreSkipTaskbar", &ps->o.ignoreSkipTaskbar); diff --git a/src/skippy.h b/src/skippy.h index a458535..60d519a 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -219,6 +219,7 @@ typedef struct { int focus_initial; int layout; + bool sortByColumn; int distance; bool useNetWMFullscreen; bool ignoreSkipTaskbar; @@ -292,6 +293,7 @@ typedef struct { .synchronize = false, \ \ .layout = LAYOUT_XD, \ + .sortByColumn = true, \ .distance = 50, \ .useNetWMFullscreen = true, \ .ignoreSkipTaskbar = false, \ @@ -1348,7 +1350,7 @@ report_key_modifiers(XKeyEvent *evk) #endif static inline int -sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) +sort_cw_by_row(dlist* dlist1, dlist* dlist2, void* data) { ClientWin *cw1 = (ClientWin *) dlist1->data; ClientWin *cw2 = (ClientWin *) dlist2->data; @@ -1364,6 +1366,28 @@ sort_cw_by_pos(dlist* dlist1, dlist* dlist2, void* data) return 0; } +static inline int +sort_cw_by_column(dlist* dlist1, dlist* dlist2, void* data) +{ + ClientWin *cw1 = (ClientWin *) dlist1->data; + ClientWin *cw2 = (ClientWin *) dlist2->data; + + if (cw1->x + cw1->src.width / 2 + < cw2->x + cw2->src.width / 2) + return -1; + else if (cw1->x + cw1->src.width / 2 + > cw2->x + cw2->src.width / 2) + return 1; + else if (cw1->y + cw1->src.height / 2 + < cw2->y + cw2->src.height / 2) + return -1; + else if (cw1->y + cw1->src.height / 2 + > cw2->y + cw2->src.height / 2) + return 1; + else + return 0; +} + extern session_t *ps_g; int load_config_file(session_t *ps); From 4211ef54c1d5fa25d66690bb6cb5aaa886b6b710 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 29 Mar 2023 03:05:12 -0700 Subject: [PATCH 100/205] Add missing help option --- src/skippy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 7d2e198..0be2a7c 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1136,7 +1136,8 @@ show_help() { fputs("skippy-xd " SKIPPYXD_VERSION "\n" "Usage: skippy-xd [command]\n\n" "The available commands are:\n" - " --config - Read the specified configuration file.\n" + " --config-reload - reload configuration file; currently the file path must ermain unchanged.\n" + " --config - read the specified configuration file.\n" " --start-daemon - starts the daemon running.\n" " --stop-daemon - stops the daemon running.\n" " --activate-window-picker - tells the daemon to show the window picker.\n" From 1acaab05ae4ddafe39501884f930b9c58d3299e5 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 29 Mar 2023 18:48:12 -0700 Subject: [PATCH 101/205] Primitvie paging feature --- src/mainwin.h | 2 +- src/skippy.c | 166 ++++++++++++++++++++++++++++++++++---------------- src/wm.c | 30 +++++++++ src/wm.h | 1 + 4 files changed, 146 insertions(+), 53 deletions(-) diff --git a/src/mainwin.h b/src/mainwin.h index 3313b92..11ad087 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -39,7 +39,7 @@ struct _mainwin_t { Picture background; Pixmap bg_pixmap; int x, y, xoff, yoff; - int width, height, newwidth, newheight, distance; + int width, height, distance; float multiplier; XRenderPictFormat *format; diff --git a/src/skippy.c b/src/skippy.c index 07f2098..4616b57 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -397,8 +397,54 @@ init_layout(MainWin *mw, Window focus, Window leader) mw->multiplier = multiplier; mw->xoff = xoff; mw->yoff = yoff; - mw->newwidth = newwidth; - mw->newheight = newheight; + } + + return; +} + +static void +init_desktop_layout(MainWin *mw, Window focus, Window leader) +{ + if (!mw->clients) + return; + + int screencount = wm_get_desktops(mw->ps); + if (screencount == -1) + screencount = 1; + int desktop_dim = ceil(sqrt(screencount)); + + { + int totalwidth = desktop_dim * (mw->width + mw->distance) - mw->distance; + int totalheight = desktop_dim * (mw->height + mw->distance) - mw->distance; + + float multiplier = (float) (mw->width - 1 * mw->distance) / (float) totalwidth; + if (multiplier * totalheight > mw->height - 1 * mw->distance) + multiplier = (float) (mw->height - 1 * mw->distance) / (float) totalheight; + + int xoff = (mw->width - (float) totalwidth * multiplier) / 2; + int yoff = (mw->height - (float) totalheight * multiplier) / 2; + + mw->multiplier = multiplier; + mw->xoff = xoff; + mw->yoff = yoff; + } + + foreach_dlist (mw->clients) { + ClientWin *cw = (ClientWin *) iter->data; + int win_desktop = wm_get_window_desktop(mw->ps, cw->wid_client); + int current_desktop = wm_get_current_desktop(mw->ps); + + int win_desktop_x = win_desktop % desktop_dim; + int win_desktop_y = win_desktop / desktop_dim; + + int current_desktop_x = current_desktop % desktop_dim; + int current_desktop_y = current_desktop / desktop_dim; + + cw->x = cw->src.x + win_desktop_x * (mw->width + mw->distance); + cw->y = cw->src.y + win_desktop_y * (mw->height + mw->distance); + + cw->src.x += (win_desktop_x - current_desktop_x) * (mw->width + mw->distance); + cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); } return; @@ -504,55 +550,13 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { printfd("Event %-13.13s wid %#010lx %s", name, wid, wextra); } -static bool -skippy_activate(MainWin *mw, Window leader) -{ +static void +init_focus(MainWin *mw, Window leader) { session_t *ps = mw->ps; - // Do this window before main window gets mapped - mw->revert_focus_win = wm_get_focused(ps); - - // Update the main window's geometry (and Xinerama info if applicable) - mainwin_update(mw); -#ifdef CFG_XINERAMA - if (ps->o.xinerama_showAll) - mw->xin_active = 0; -#endif /* CFG_XINERAMA */ - - // Map the main window and run our event loop - /*if (ps->o.lazyTrans) { - mainwin_map(mw); - XFlush(ps->dpy); - }*/ - - mw->client_to_focus = NULL; - - daemon_count_clients(mw, 0, leader); - foreach_dlist(mw->clients) { - clientwin_update((ClientWin *) iter->data); - clientwin_update2((ClientWin *) iter->data); - } - - init_layout(mw, mw->revert_focus_win, leader); - if (!mw->clientondesktop) { - printfef("(): Failed to build layout."); - return false; - } - - foreach_dlist(mw->clients) { - ClientWin *cw = iter->data; - if(mw->ps->o.lazyTrans) - { - cw->x += cw->mainwin->x; - cw->y += cw->mainwin->y; - } - cw->x *= mw->multiplier; - cw->y *= mw->multiplier; - } - // Get the currently focused window and select which mini-window to focus { - dlist *iter = dlist_find(mw->clientondesktop, clientwin_cmp_func, (void *) mw->revert_focus_win); + dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) mw->revert_focus_win); // check if the user specified --prev or --next on the cmdline if(ps->o.focus_initial) @@ -565,12 +569,12 @@ skippy_activate(MainWin *mw, Window leader) if(ps->o.focus_initial == FI_PREV) { - // here, mw->clientondesktop is the first (dlist*) item in the list - if (iter == mw->clientondesktop) - iter = dlist_last(mw->clientondesktop); + // here, mw->focuslist is the first (dlist*) item in the list + if (iter == mw->focuslist) + iter = dlist_last(mw->focuslist); else { - dlist *i = mw->clientondesktop; + dlist *i = mw->focuslist; for (; i != NULL; i = i->next) if (i->next && i->next == iter) break; @@ -586,7 +590,7 @@ skippy_activate(MainWin *mw, Window leader) ps->o.focus_initial = 0; if (!iter) - iter = mw->clientondesktop; + iter = mw->focuslist; // mw->focus = (ClientWin *) iter->data; mw->client_to_focus = (ClientWin *) iter->data; @@ -597,6 +601,64 @@ skippy_activate(MainWin *mw, Window leader) mw->client_to_focus->focused = 1; // focus_miniw(ps, mw->client_to_focus); } +} + +static bool +skippy_activate(MainWin *mw, Window leader) +{ + session_t *ps = mw->ps; + + // Do this window before main window gets mapped + mw->revert_focus_win = wm_get_focused(ps); + + // Update the main window's geometry (and Xinerama info if applicable) + mainwin_update(mw); +#ifdef CFG_XINERAMA + if (ps->o.xinerama_showAll) + mw->xin_active = 0; +#endif /* CFG_XINERAMA */ + + // Map the main window and run our event loop + /*if (ps->o.lazyTrans) { + mainwin_map(mw); + XFlush(ps->dpy); + }*/ + + mw->client_to_focus = NULL; + + daemon_count_clients(mw, 0, leader); + foreach_dlist(mw->clients) { + clientwin_update((ClientWin *) iter->data); + clientwin_update2((ClientWin *) iter->data); + } + + if (mw->ps->o.showAllDesktops) { + init_desktop_layout(mw, mw->revert_focus_win, leader); + if (!mw->clientondesktop) { + printfef("(): Failed to build layout."); + return false; + } + mw->focuslist = mw->clientondesktop; + } + else { + init_layout(mw, mw->revert_focus_win, leader); + if (!mw->clientondesktop) { + printfef("(): Failed to build layout."); + return false; + } + } + init_focus(mw, leader); + + foreach_dlist(mw->clients) { + ClientWin *cw = iter->data; + if (mw->ps->o.lazyTrans) + { + cw->x += cw->mainwin->x; + cw->y += cw->mainwin->y; + } + cw->x *= mw->multiplier; + cw->y *= mw->multiplier; + } return true; } diff --git a/src/wm.c b/src/wm.c index a9ee2e8..bea0aa4 100644 --- a/src/wm.c +++ b/src/wm.c @@ -429,6 +429,36 @@ wm_get_root_pmap(Display *dpy) return rootpmap; } +unsigned long +wm_get_desktops(session_t *ps) { + Atom real_type; + int real_format; + unsigned long items_read, items_left; + unsigned char *data; + + char num_desktops = -1; + + int status = XGetWindowProperty(ps->dpy, ps->root, + _NET_NUMBER_OF_DESKTOPS, 0L, 1L, False, XA_CARDINAL, + &real_type, &real_format, &items_read, &items_left, &data); + + if (status == Success && items_read && data && real_format == 32) + goto return_status; + + status = XGetWindowProperty(ps->dpy, ps->root, + _WIN_WORKSPACE_COUNT, 0L, 1L, False, XA_CARDINAL, + &real_type, &real_format, &items_read, &items_left, &data); + + if (status == Success && items_read && data && real_format == 32) + goto return_status; + +return_status: + if (status == Success && items_read && data && real_format == 32) + num_desktops = data[0]; + + return num_desktops; +} + long wm_get_current_desktop(session_t *ps) { winprop_t prop = { }; diff --git a/src/wm.h b/src/wm.h index 8b1234c..11d2e40 100644 --- a/src/wm.h +++ b/src/wm.h @@ -82,6 +82,7 @@ wm_check(session_t *ps) { dlist *wm_get_stack(session_t *ps); Pixmap wm_get_root_pmap(Display *dpy); +unsigned long wm_get_desktops(session_t *ps); long wm_get_current_desktop(session_t *ps); FcChar8 *wm_get_window_title(session_t *ps, Window wid, int *length_return); void printfefWindowName(session_t *ps, char *prefix_str, Window wid); From f325623d0cb7977eb4e9c20904557188d06f68bd Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 29 Mar 2023 22:27:38 -0700 Subject: [PATCH 102/205] Put in entry path to paging --- src/clientwin.c | 2 +- src/skippy.c | 145 ++++++++++++++++++++++++++++-------------------- src/skippy.h | 7 ++- 3 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 0932b62..aacee5e 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -48,7 +48,7 @@ clientwin_validate_func(dlist *l, void *data) { return false; #endif - if (!ps->o.showAllDesktops) { + if (!ps->o.showAllDesktops && ps->o.mode != PROGMODE_ACTV_PAGING) { CARD32 desktop = (*(CARD32 *)data), w_desktop = wm_get_window_desktop(ps, cw->wid_client); diff --git a/src/skippy.c b/src/skippy.c index 4616b57..ec5d511 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -29,10 +29,11 @@ enum pipe_cmd_t { // Not ordered properly for backward compatibility PIPECMD_RELOAD_CONFIG = 0, - PIPECMD_ACTIVATE_WINDOW_PICKER = 1, - PIPECMD_EXIT_RUNNING_DAEMON, - PIPECMD_DEACTIVATE_WINDOW_PICKER, - PIPECMD_TOGGLE_WINDOW_PICKER, + PIPECMD_ACTIVATE_EXPOSE = 1, + PIPECMD_ACTIVATE_PAGING, + PIPECMD_DEACTIVATE, + PIPECMD_TOGGLE, + PIPECMD_EXIT_DAEMON, PIPECMD_QUEUE_FI_PREV, PIPECMD_QUEUE_FI_NEXT, }; @@ -447,6 +448,9 @@ init_desktop_layout(MainWin *mw, Window focus, Window leader) cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); } + dlist_sort(mw->clientondesktop, sort_cw_by_row, 0); + mw->focuslist = mw->clientondesktop; + return; } @@ -604,7 +608,7 @@ init_focus(MainWin *mw, Window leader) { } static bool -skippy_activate(MainWin *mw, Window leader) +skippy_activate(MainWin *mw, Window leader, bool paging) { session_t *ps = mw->ps; @@ -632,7 +636,7 @@ skippy_activate(MainWin *mw, Window leader) clientwin_update2((ClientWin *) iter->data); } - if (mw->ps->o.showAllDesktops) { + if (paging) { init_desktop_layout(mw, mw->revert_focus_win, leader); if (!mw->clientondesktop) { printfef("(): Failed to build layout."); @@ -693,6 +697,7 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; + bool paging = ps->o.mode == PROGMODE_ACTV_PAGING; bool animating = activate; long first_animated = 0L; @@ -719,7 +724,7 @@ mainloop(session_t *ps, bool activate_on_start) { assert(ps->mainwin); activate = false; - if (skippy_activate(ps->mainwin, None)) { + if (skippy_activate(ps->mainwin, None, paging)) { // printfef("(): if (skippy_activate(ps->mainwin, None)) {"); // printfef("(): was in skippy_activate"); last_rendered = time_in_millis(); @@ -995,14 +1000,11 @@ mainloop(session_t *ps, bool activate_on_start) { load_config_file(ps); mainwin_reload(ps, ps->mainwin); break; - case PIPECMD_QUEUE_FI_PREV: - ps->o.focus_initial = FI_PREV; - break; - case PIPECMD_QUEUE_FI_NEXT: - ps->o.focus_initial = FI_NEXT; - break; - case PIPECMD_ACTIVATE_WINDOW_PICKER: - printfef("(): case PIPECMD_ACTIVATE_WINDOW_PICKER:"); + case PIPECMD_ACTIVATE_EXPOSE: + case PIPECMD_ACTIVATE_PAGING: + paging = piped_input == PIPECMD_ACTIVATE_PAGING; + ps->o.mode = paging? PROGMODE_ACTV_PAGING: PROGMODE_ACTV_EXPOSE; + printfef("(): case PIPECMD_ACTIVATE, paging=%d:", paging); if (ps->mainwin->mapped) { printfef("(): if (ps->mainwin->mapped)"); @@ -1028,8 +1030,6 @@ mainloop(session_t *ps, bool activate_on_start) { focus_miniw_next(ps, mw->client_to_focus); } clientwin_render(mw->client_to_focus); - - } else { @@ -1037,20 +1037,26 @@ mainloop(session_t *ps, bool activate_on_start) { animating = activate = true; } break; - case PIPECMD_DEACTIVATE_WINDOW_PICKER: + case PIPECMD_DEACTIVATE: if (mw) die = true; break; - case PIPECMD_TOGGLE_WINDOW_PICKER: + case PIPECMD_TOGGLE: if (mw) die = true; else animating = activate = true; break; - case PIPECMD_EXIT_RUNNING_DAEMON: + case PIPECMD_EXIT_DAEMON: printfdf("(): Exit command received, killing daemon..."); unlink(ps->o.pipePath); return; + case PIPECMD_QUEUE_FI_PREV: + ps->o.focus_initial = FI_PREV; + break; + case PIPECMD_QUEUE_FI_NEXT: + ps->o.focus_initial = FI_NEXT; + break; default: printfdf("(): Unknown daemon command \"%d\" received.", piped_input); break; @@ -1105,27 +1111,33 @@ queue_initial_focus_next(const char *pipePath) { } static inline bool -activate_window_picker(const char *pipePath) { - printfdf("(): Activating window picker..."); - return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_WINDOW_PICKER, pipePath); +activate_expose(const char *pipePath) { + printfdf("(): Activating expose..."); + return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_EXPOSE, pipePath); +} + +static inline bool +activate_paging(const char *pipePath) { + printfdf("(): Activating paging..."); + return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_PAGING, pipePath); } static inline bool exit_daemon(const char *pipePath) { printfdf("(): Killing daemon..."); - return send_command_to_daemon_via_fifo(PIPECMD_EXIT_RUNNING_DAEMON, pipePath); + return send_command_to_daemon_via_fifo(PIPECMD_EXIT_DAEMON, pipePath); } static inline bool -deactivate_window_picker(const char *pipePath) { - printfdf("(): Deactivating window picker..."); - return send_command_to_daemon_via_fifo(PIPECMD_DEACTIVATE_WINDOW_PICKER, pipePath); +deactivate(const char *pipePath) { + printfdf("(): Deactivating..."); + return send_command_to_daemon_via_fifo(PIPECMD_DEACTIVATE, pipePath); } static inline bool -toggle_window_picker(const char *pipePath) { +toggle_activate(const char *pipePath) { printfdf("(): Toggling window picker..."); - return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_WINDOW_PICKER, pipePath); + return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE, pipePath); } /** @@ -1202,19 +1214,21 @@ show_help() { fputs("skippy-xd " SKIPPYXD_VERSION "\n" "Usage: skippy-xd [command]\n\n" "The available commands are:\n" - " --config-reload - reload configuration file; currently the file path must ermain unchanged.\n" - " --config - read the specified configuration file.\n" - " --start-daemon - starts the daemon running.\n" - " --stop-daemon - stops the daemon running.\n" - " --activate-window-picker - tells the daemon to show the window picker.\n" - " --deactivate-window-picker - tells the daemon to hide the window picker.\n" - " --toggle-window-picker - tells the daemon to toggle the window picker.\n" - " --prev - launch initially focussed to previous selection.\n" - " --next - launch initially focussed to next selection.\n" + " [no command] - activate expose once without daemon.\n" + " --config-reload - reload configuration file; currently the file path must remain unchanged.\n" + " --config - read the specified configuration file.\n" + " --start-daemon - starts the daemon running.\n" + " --stop-daemon - stops the daemon running.\n" + " --activate-expose - connects to daemon and activate expose.\n" + " --activate-paging - connects to daemon and activate paging.\n" + " --deactivate - connects to daemon and deactivate expose or paging.\n" + " --toggle - connects to daemon and toggle activation.\n" + " --prev - focus window to previous.\n" + " --next - focus window to next.\n" // " --test - Temporary development testing. To be removed.\n" "\n" - " --help - show this message.\n" - " -S - Synchronize X operation (debugging).\n" + " --help - show this message.\n" + " -S - Synchronize X operation (debugging).\n" , stdout); #ifdef CFG_LIBPNG spng_about(stdout); @@ -1367,9 +1381,10 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { enum options { OPT_CONFIG = 256, OPT_CONFIG_RELOAD, - OPT_ACTV_PICKER, - OPT_DEACTV_PICKER, - OPT_TOGGLE_PICKER, + OPT_ACTV_EXPOSE, + OPT_ACTV_PAGING, + OPT_DEACTV, + OPT_TOGGLE, OPT_DM_START, OPT_DM_STOP, OPT_PREV, @@ -1380,9 +1395,10 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "help", no_argument, NULL, 'h' }, { "config", required_argument, NULL, OPT_CONFIG }, { "config-reload", no_argument, NULL, OPT_CONFIG_RELOAD }, - { "activate-window-picker", no_argument, NULL, OPT_ACTV_PICKER }, - { "deactivate-window-picker", no_argument, NULL, OPT_DEACTV_PICKER }, - { "toggle-window-picker", no_argument, NULL, OPT_TOGGLE_PICKER }, + { "activate-expose", no_argument, NULL, OPT_ACTV_EXPOSE }, + { "activate-paging", no_argument, NULL, OPT_ACTV_PAGING }, + { "deactivate", no_argument, NULL, OPT_DEACTV }, + { "toggle", no_argument, NULL, OPT_TOGGLE }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, { "prev", no_argument, NULL, OPT_PREV }, @@ -1433,21 +1449,24 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG_RELOAD: ps->o.mode = PROGMODE_RELOAD_CONFIG; break; - case OPT_PREV: break; - case OPT_NEXT: break; - case OPT_ACTV_PICKER: - ps->o.mode = PROGMODE_ACTV_PICKER; + case OPT_ACTV_EXPOSE: + ps->o.mode = PROGMODE_ACTV_EXPOSE; break; - case OPT_DEACTV_PICKER: - ps->o.mode = PROGMODE_DEACTV_PICKER; + case OPT_ACTV_PAGING: + ps->o.mode = PROGMODE_ACTV_PAGING; break; - case OPT_TOGGLE_PICKER: - ps->o.mode = PROGMODE_TOGGLE_PICKER; + case OPT_DEACTV: + ps->o.mode = PROGMODE_DEACTV; + break; + case OPT_TOGGLE: + ps->o.mode = PROGMODE_TOGGLE; break; - T_CASEBOOL(OPT_DM_START, runAsDaemon); case OPT_DM_STOP: ps->o.mode = PROGMODE_DM_STOP; break; + T_CASEBOOL(OPT_DM_START, runAsDaemon); + case OPT_PREV: break; + case OPT_NEXT: break; #undef T_CASEBOOL default: printfef("(0): Unimplemented option %d.", o); @@ -1682,7 +1701,8 @@ int main(int argc, char *argv[]) { switch (ps->o.mode) { case PROGMODE_NORMAL: break; - case PROGMODE_ACTV_PICKER: + case PROGMODE_ACTV_EXPOSE: + case PROGMODE_ACTV_PAGING: if(ps->o.focus_initial) { if(ps->o.focus_initial == FI_PREV) @@ -1694,12 +1714,15 @@ int main(int argc, char *argv[]) { // we must pause slightly, otherwise will miss next read() call in this loop() usleep(10000); } - activate_window_picker(pipePath); + if (ps->o.mode == PROGMODE_ACTV_EXPOSE) + activate_expose(pipePath); + else + activate_paging(pipePath); goto main_end; - case PROGMODE_DEACTV_PICKER: - deactivate_window_picker(pipePath); + case PROGMODE_DEACTV: + deactivate(pipePath); goto main_end; - case PROGMODE_TOGGLE_PICKER: + case PROGMODE_TOGGLE: if(ps->o.focus_initial) { if(ps->o.focus_initial == FI_PREV) @@ -1710,7 +1733,7 @@ int main(int argc, char *argv[]) { // we must pause slightly, otherwise will miss next read() call in this loop() usleep(10000); } - toggle_window_picker(pipePath); + toggle_activate(pipePath); goto main_end; case PROGMODE_RELOAD_CONFIG: queue_reload_config(pipePath); diff --git a/src/skippy.h b/src/skippy.h index 60d519a..7dd461d 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -117,9 +117,10 @@ enum { enum progmode { PROGMODE_NORMAL, - PROGMODE_ACTV_PICKER, - PROGMODE_DEACTV_PICKER, - PROGMODE_TOGGLE_PICKER, + PROGMODE_ACTV_EXPOSE, + PROGMODE_ACTV_PAGING, + PROGMODE_DEACTV, + PROGMODE_TOGGLE, PROGMODE_RELOAD_CONFIG, PROGMODE_DM_STOP, }; From bbe2d42af8a2f15767dc614e2e306d29076f286f Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 29 Mar 2023 22:50:55 -0700 Subject: [PATCH 103/205] Add toggle-expose and toggle-paging commands --- src/clientwin.c | 4 +++- src/skippy.c | 55 ++++++++++++++++++++++++++++++++++--------------- src/skippy.h | 3 ++- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index aacee5e..021df15 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -48,7 +48,9 @@ clientwin_validate_func(dlist *l, void *data) { return false; #endif - if (!ps->o.showAllDesktops && ps->o.mode != PROGMODE_ACTV_PAGING) { + if (!ps->o.showAllDesktops + && ps->o.mode != PROGMODE_ACTV_PAGING + && ps->o.mode != PROGMODE_TGG_PAGING) { CARD32 desktop = (*(CARD32 *)data), w_desktop = wm_get_window_desktop(ps, cw->wid_client); diff --git a/src/skippy.c b/src/skippy.c index ec5d511..c3aaeed 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -30,9 +30,10 @@ enum pipe_cmd_t { // Not ordered properly for backward compatibility PIPECMD_RELOAD_CONFIG = 0, PIPECMD_ACTIVATE_EXPOSE = 1, + PIPECMD_TOGGLE_EXPOSE, PIPECMD_ACTIVATE_PAGING, + PIPECMD_TOGGLE_PAGING, PIPECMD_DEACTIVATE, - PIPECMD_TOGGLE, PIPECMD_EXIT_DAEMON, PIPECMD_QUEUE_FI_PREV, PIPECMD_QUEUE_FI_NEXT, @@ -1041,11 +1042,15 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; break; - case PIPECMD_TOGGLE: + case PIPECMD_TOGGLE_EXPOSE: + case PIPECMD_TOGGLE_PAGING: if (mw) die = true; - else + else { animating = activate = true; + paging = piped_input == PIPECMD_TOGGLE_PAGING; + ps->o.mode = paging? PROGMODE_TGG_PAGING: PROGMODE_TGG_EXPOSE; + } break; case PIPECMD_EXIT_DAEMON: printfdf("(): Exit command received, killing daemon..."); @@ -1135,9 +1140,15 @@ deactivate(const char *pipePath) { } static inline bool -toggle_activate(const char *pipePath) { - printfdf("(): Toggling window picker..."); - return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE, pipePath); +toggle_expose(const char *pipePath) { + printfdf("(): Toggling expose..."); + return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_EXPOSE, pipePath); +} + +static inline bool +toggle_paging(const char *pipePath) { + printfdf("(): Toggling paging..."); + return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_PAGING, pipePath); } /** @@ -1220,9 +1231,10 @@ show_help() { " --start-daemon - starts the daemon running.\n" " --stop-daemon - stops the daemon running.\n" " --activate-expose - connects to daemon and activate expose.\n" + " --toggle-expose - connects to daemon and toggle expose.\n" " --activate-paging - connects to daemon and activate paging.\n" + " --toggle-paging - connects to daemon and toggle paging.\n" " --deactivate - connects to daemon and deactivate expose or paging.\n" - " --toggle - connects to daemon and toggle activation.\n" " --prev - focus window to previous.\n" " --next - focus window to next.\n" // " --test - Temporary development testing. To be removed.\n" @@ -1382,9 +1394,10 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { OPT_CONFIG = 256, OPT_CONFIG_RELOAD, OPT_ACTV_EXPOSE, + OPT_TGG_EXPOSE, OPT_ACTV_PAGING, + OPT_TGG_PAGING, OPT_DEACTV, - OPT_TOGGLE, OPT_DM_START, OPT_DM_STOP, OPT_PREV, @@ -1396,9 +1409,10 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "config", required_argument, NULL, OPT_CONFIG }, { "config-reload", no_argument, NULL, OPT_CONFIG_RELOAD }, { "activate-expose", no_argument, NULL, OPT_ACTV_EXPOSE }, + { "toggle-expose", no_argument, NULL, OPT_TGG_EXPOSE }, { "activate-paging", no_argument, NULL, OPT_ACTV_PAGING }, + { "toggle-paging", no_argument, NULL, OPT_TGG_PAGING }, { "deactivate", no_argument, NULL, OPT_DEACTV }, - { "toggle", no_argument, NULL, OPT_TOGGLE }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, { "prev", no_argument, NULL, OPT_PREV }, @@ -1452,15 +1466,18 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_ACTV_EXPOSE: ps->o.mode = PROGMODE_ACTV_EXPOSE; break; + case OPT_TGG_EXPOSE: + ps->o.mode = PROGMODE_TGG_EXPOSE; + break; case OPT_ACTV_PAGING: ps->o.mode = PROGMODE_ACTV_PAGING; break; + case OPT_TGG_PAGING: + ps->o.mode = PROGMODE_TGG_PAGING; + break; case OPT_DEACTV: ps->o.mode = PROGMODE_DEACTV; break; - case OPT_TOGGLE: - ps->o.mode = PROGMODE_TOGGLE; - break; case OPT_DM_STOP: ps->o.mode = PROGMODE_DM_STOP; break; @@ -1719,10 +1736,8 @@ int main(int argc, char *argv[]) { else activate_paging(pipePath); goto main_end; - case PROGMODE_DEACTV: - deactivate(pipePath); - goto main_end; - case PROGMODE_TOGGLE: + case PROGMODE_TGG_EXPOSE: + case PROGMODE_TGG_PAGING: if(ps->o.focus_initial) { if(ps->o.focus_initial == FI_PREV) @@ -1733,7 +1748,13 @@ int main(int argc, char *argv[]) { // we must pause slightly, otherwise will miss next read() call in this loop() usleep(10000); } - toggle_activate(pipePath); + if (PROGMODE_TGG_EXPOSE == ps->o.mode) + toggle_expose(pipePath); + else + toggle_paging(pipePath); + goto main_end; + case PROGMODE_DEACTV: + deactivate(pipePath); goto main_end; case PROGMODE_RELOAD_CONFIG: queue_reload_config(pipePath); diff --git a/src/skippy.h b/src/skippy.h index 7dd461d..a0b0f7b 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -118,9 +118,10 @@ enum { enum progmode { PROGMODE_NORMAL, PROGMODE_ACTV_EXPOSE, + PROGMODE_TGG_EXPOSE, PROGMODE_ACTV_PAGING, + PROGMODE_TGG_PAGING, PROGMODE_DEACTV, - PROGMODE_TOGGLE, PROGMODE_RELOAD_CONFIG, PROGMODE_DM_STOP, }; From 41bf71432f5f9e1b0a9cd502dc590e1af76bca23 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 31 Mar 2023 00:14:54 -0700 Subject: [PATCH 104/205] Fix memory leaks --- src/mainwin.c | 2 ++ src/skippy.h | 1 + src/wm.c | 1 + 3 files changed, 4 insertions(+) diff --git a/src/mainwin.c b/src/mainwin.c index 80e9fdd..ceff2a9 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -472,6 +472,8 @@ mainwin_destroy(MainWin *mw) { free(mw->keysyms_Down); free(mw->keysyms_Left); free(mw->keysyms_Right); + free(mw->keysyms_Prev); + free(mw->keysyms_Next); free(mw->keysyms_ExitCancelOnPress); free(mw->keysyms_ExitCancelOnRelease); free(mw->keysyms_ExitSelectOnPress); diff --git a/src/skippy.h b/src/skippy.h index a0b0f7b..b1bb887 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -1100,6 +1100,7 @@ check_keybindings_conflict(const char *config_path, const char *arr1_str, KeySym free(conflicts); return true; } + free(conflicts); return false; } diff --git a/src/wm.c b/src/wm.c index bea0aa4..612a4e6 100644 --- a/src/wm.c +++ b/src/wm.c @@ -456,6 +456,7 @@ wm_get_desktops(session_t *ps) { if (status == Success && items_read && data && real_format == 32) num_desktops = data[0]; + XFree(data); return num_desktops; } From cc7f7ffb0b7da04e4ce8113254d346dffab20410 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 31 Mar 2023 00:34:56 -0700 Subject: [PATCH 105/205] Free icon and filled box resources --- src/clientwin.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/clientwin.c b/src/clientwin.c index 021df15..a760a06 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -193,6 +193,8 @@ clientwin_update(ClientWin *cw) { } // Get window icon + if (cw->icon_pict) + free_pictw(ps, &cw->icon_pict); cw->icon_pict = simg_load_icon(ps, cw->wid_client, ps->o.preferredIconSize); if (!cw->icon_pict && ps->o.iconDefault) cw->icon_pict = clone_pictw(ps, ps->o.iconDefault); @@ -215,6 +217,8 @@ clientwin_update(ClientWin *cw) { static inline bool clientwin_update2_filled(session_t *ps, MainWin *mw, ClientWin *cw) { + if (cw->pict_filled) + free_pictw(ps, &cw->pict_filled); cw->pict_filled = simg_postprocess(ps, clone_pictw(ps, ps->o.fillSpec.img), ps->o.fillSpec.mode, @@ -226,6 +230,8 @@ clientwin_update2_filled(session_t *ps, MainWin *mw, ClientWin *cw) { static inline bool clientwin_update2_icon(session_t *ps, MainWin *mw, ClientWin *cw) { + if (cw->icon_pict_filled) + free_pictw(ps, &cw->icon_pict_filled); cw->icon_pict_filled = simg_postprocess(ps, clone_pictw(ps, cw->icon_pict), ps->o.iconFillSpec.mode, From f69c7707ce2364a86a73cfe1d481a915c3ec27bc Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 31 Mar 2023 01:22:51 -0700 Subject: [PATCH 106/205] Free layout dlist --- src/layout.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/layout.c b/src/layout.c index e8451bd..ec01a3c 100644 --- a/src/layout.c +++ b/src/layout.c @@ -571,6 +571,8 @@ do } if (recalculate) { + for (int i=0; i Date: Fri, 31 Mar 2023 19:12:57 +0100 Subject: [PATCH 107/205] fix: skippy-xd-runner script for new paging / cmdline options --- skippy-xd-runner | 62 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/skippy-xd-runner b/skippy-xd-runner index f1af1ad..37a1fde 100755 --- a/skippy-xd-runner +++ b/skippy-xd-runner @@ -15,15 +15,20 @@ # skippy-xd-runner # # The available commands are: -# --config - Read the specified configuration file. -# --start-daemon - starts the daemon running. -# --stop-daemon - stops the daemon running. -# --activate-window-picker - tells the daemon to show the window picker. -# --deactivate-window-picker - tells the daemon to hide the window picker. -# --toggle-window-picker - tells the daemon to toggle the window picker. -# --prev - launch initially focussed to previous selection. -# --next - launch initially focussed to next selection. -# --help - show this message. +# [no command] - activate expose once without daemon. +# --config-reload - reload configuration file; currently the file path must remain unchanged. +# --config - read the specified configuration file. +# --start-daemon - starts the daemon running. +# --stop-daemon - stops the daemon running. +# --activate-expose - connects to daemon and activate expose. +# --toggle-expose - connects to daemon and toggle expose. +# --activate-paging - connects to daemon and activate paging. +# --toggle-paging - connects to daemon and toggle paging. +# --deactivate - connects to daemon and deactivate expose or paging. +# --prev - focus window to previous. +# --next - focus window to next. +# +# --help - show this message. # -S - Synchronize X operation (debugging). # # @@ -48,12 +53,15 @@ _parse_args() case $arg in + --config-reload) _config_reload=true ;; --config) shift && _config="$1" ;; --start-daemon|--start) _start_daemon=true ;; --stop-daemon|--stop) _stop_daemon=true ;; - --activate-window-picker|--activate) _activate=true ;; - --deactivate-window-picker|--deactivate) _deactivate=true ;; - --toggle-window-picker|--toggle) _toggle=true ;; + --activate-expose|--activate) _activate_expose=true ;; + --toggle-expose|--toggle) _toggle_expose=true ;; + --activate-paging|--activate) _activate_paging=true ;; + --toggle-paging|--toggle) _toggle_paging=true ;; + --deactivate|--deactivate) _deactivate=true ;; --prev) _prev=true ;; --next) _next=true ;; --help|-h) _help=true ;; @@ -65,16 +73,24 @@ _parse_args() done unset _first_arg - if [ "$_activate" ]; then - _first_arg="--activate" + if [ "$_activate_expose" ]; then + _first_arg="--activate-expose" fi - if [ "$_deactivate" ]; then - _first_arg="--deactivate" + if [ "$_toggle_expose" ]; then + _first_arg="--toggle-expose" + fi + + if [ "$_activate_paging" ]; then + _first_arg="--activate-paging" + fi + + if [ "$_toggle_paging" ]; then + _first_arg="--toggle-paging" fi - if [ "$_toggle" ]; then - _first_arg="--toggle" + if [ "$_deactivate" ]; then + _first_arg="--deactivate" fi if [ "$_first_arg" ]; then @@ -86,12 +102,14 @@ _main() { lastActivationTimeoutSeconds=1 - psSkippyActivateOut="`pgrep -f 'skippy-xd --activate'`" + psSkippyActivateExposeOut="`pgrep -f 'skippy-xd --activate-expose'`" + psSkippyToggleExposeOut="`pgrep -f 'skippy-xd --toggle-expose'`" + psSkippyActivatePagingOut="`pgrep -f 'skippy-xd --activate-paging'`" + psSkippyTogglePagingOut="`pgrep -f 'skippy-xd --toggle-paging'`" psSkippyDeactivateOut="`pgrep -f 'skippy-xd --deactivate'`" - psSkippyToggleOut="`pgrep -f 'skippy-xd --toggle'`" _other_clients=0 - for pid in $psSkippyActivateOut $psSkippyDeactivateOut $psSkippyToggleOut; do + for pid in $psSkippyActivateExposeOut $psSkippyToggleExposeOut $psSkippyActivatePagingOut $psSkippyTogglePagingOut $psSkippyDeactivateOut; do ptime="$(ps -o etimes= -p "$pid")" if [ "$ptime" -ge "$lastActivationTimeoutSeconds" ]; then _killall=true @@ -120,8 +138,10 @@ _main() # if the action requires the skippy-xd daemon, but it is not already running, we should start it if [ "$_first_arg" ] && [ ! "$_deactivate" ] && [ ! "$(pgrep -f 'skippy-xd ')" ]; then + if [ "$_config" ]; then skippy-xd --start-daemon --config "$_config" & + else skippy-xd --start-daemon & fi From 8d1f84ca4722ed27b4e97bc1cb79571da51cdb4b Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Fri, 31 Mar 2023 19:22:42 +0100 Subject: [PATCH 108/205] closes #65 fixes #65 - a new option requires setting default C initialization values in skippy.h This protects when the user either launches skippy with no config file, (or missing config file) or when: tThe user is using an old versions of config (that they did not realize to update) or when: The user has simplified their config by removing lines they don't wish to customize A sensible defaults is really normally supposed to be same exact what is in the skippy-xs.sample.rc file --- src/skippy.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/skippy.h b/src/skippy.h index a0b0f7b..880fff5 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -326,6 +326,9 @@ typedef struct { .highlight_tint = NULL, \ .highlight_tintOpacity = 64, \ .highlight_opacity = 255, \ + .shadow_tint = NULL, \ + .shadow_tintOpacity = 164, \ + .shadow_opacity = 200, \ .tooltip_show = true, \ .tooltip_followsMouse = true, \ .tooltip_offsetX = 20, \ From 39330ab5ae75fff1aa1933ced544c1c18f84e90e Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Fri, 31 Mar 2023 19:35:05 +0100 Subject: [PATCH 109/205] tweak the user defaults a little bit more, in following ways: * Default small corner radius of 5px: small enough not to bother anybody, but enough to notice this new feature exists * Show all desktops by default true - this seems like a more sensible default (for most typical users) * Improve default keyboard shortcuts for navigation, include TAB key --- skippy-xd.sample.rc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 97ed757..e14af1a 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -90,8 +90,8 @@ movePointerOnRaise = true switchDesktopOnActivate = false includeFrame = true allowUpscale = true -showAllDesktops = false -cornerRadius = 0 +showAllDesktops = true +cornerRadius = 5 preferredIconSize = 48 showIconsOnThumbnails = true iconFillSpec = orig mid mid #00FFFF @@ -138,7 +138,7 @@ keysDown = Down s keysLeft = Left a keysRight = Right d keysPrev = p b -keysNext = n f +keysNext = Tab n f keysExitCancelOnPress = Escape BackSpace x q keysExitCancelOnRelease = keysExitSelectOnPress = Return space From 63dbeac51c2799e5a968941bbe55bd55d1953994 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 31 Mar 2023 23:09:06 -0700 Subject: [PATCH 110/205] cherry-pick from nick87720z to append uid to pipe --- src/skippy.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index c3aaeed..2fbb0e7 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1514,7 +1514,23 @@ load_config_file(session_t *ps) // Read configuration into ps->o, because searching all the time is much // less efficient, may introduce inconsistent default value, and // occupies a lot more memory for non-string types. - ps->o.pipePath = mstrdup(config_get(config, "general", "pipePath", "/tmp/skippy-xd-fifo")); + { + // Appending UID to the file name + // Dash-separated initial single-digit string + int uid = (int)getuid(), pipeStrLen = 3; + { + int num; + for (num = uid; num >= 10; num /= 10) pipeStrLen++; + } + + const char * path = config_get(config, "general", "pipePath", "/tmp/skippy-xd-fifo"); + pipeStrLen += strlen(path); + + char * pipePath = malloc (pipeStrLen * sizeof(unsigned char)); + sprintf(pipePath, "%s-%i", path, uid); + + ps->o.pipePath = pipePath; + } ps->o.normal_tint = mstrdup(config_get(config, "normal", "tint", "black")); ps->o.highlight_tint = mstrdup(config_get(config, "highlight", "tint", "#101020")); ps->o.shadow_tint = mstrdup(config_get(config, "shadow", "tint", "#010101")); From 8ef592d82b96866c5ecdf2a7e962d799fc8e8125 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 31 Mar 2023 23:59:07 -0700 Subject: [PATCH 111/205] namedpipe name uses display file descriptor rather than UID --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 2fbb0e7..dcf2abb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1517,17 +1517,17 @@ load_config_file(session_t *ps) { // Appending UID to the file name // Dash-separated initial single-digit string - int uid = (int)getuid(), pipeStrLen = 3; + int xid = XConnectionNumber(ps->dpy), pipeStrLen = 3; { int num; - for (num = uid; num >= 10; num /= 10) pipeStrLen++; + for (num = xid; num >= 10; num /= 10) pipeStrLen++; } const char * path = config_get(config, "general", "pipePath", "/tmp/skippy-xd-fifo"); pipeStrLen += strlen(path); char * pipePath = malloc (pipeStrLen * sizeof(unsigned char)); - sprintf(pipePath, "%s-%i", path, uid); + sprintf(pipePath, "%s-%i", path, xid); ps->o.pipePath = pipePath; } From 0a5356acce6173c1c695916100bec37f05f9e84d Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 2 Apr 2023 14:47:37 -0700 Subject: [PATCH 112/205] Removed 1-2 xerrors --- src/clientwin.c | 54 +++++++++++++++++++++++++++++++++++++++---------- src/clientwin.h | 33 ++---------------------------- src/skippy.c | 11 ++++------ 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index a760a06..def76e2 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -145,6 +145,37 @@ clientwin_create(MainWin *mw, Window client) { return NULL; } +client_disp_mode_t +clientwin_get_disp_mode(session_t *ps, ClientWin *cw, bool isViewable) { + for (client_disp_mode_t *p = ps->o.clientDisplayModes; *p; p++) { + switch (*p) { + case CLIDISP_THUMBNAIL_ICON: + if (isViewable && cw->origin && cw->icon_pict) + return *p; + break; + case CLIDISP_THUMBNAIL: + if (isViewable && cw->origin) + return *p; + break; + case CLIDISP_ZOMBIE_ICON: + if (cw->shadow && cw->icon_pict != NULL) + return *p; + break; + case CLIDISP_ZOMBIE: + if (cw->shadow) return *p; + break; + case CLIDISP_ICON: + if (cw->icon_pict) return *p; + break; + case CLIDISP_FILLED: + case CLIDISP_NONE: + return *p; + } + } + + return CLIDISP_NONE; +} + /** * @brief Update window data to prepare for rendering. */ @@ -153,6 +184,10 @@ clientwin_update(ClientWin *cw) { session_t *ps = cw->mainwin->ps; clientwin_free_res2(ps, cw); + // Reset mini window parameters + cw->mini.x = cw->mini.y = 0; + cw->mini.width = cw->mini.height = 1; + // Get window attributes XWindowAttributes wattr = { }; XGetWindowAttributes(ps->dpy, cw->src.window, &wattr); @@ -169,19 +204,22 @@ clientwin_update(ClientWin *cw) { cw->src.format = XRenderFindVisualFormat(ps->dpy, wattr.visual); } - if (IsViewable == wattr.map_state) { - // create cw->origin + bool isViewable = wattr.map_state == IsViewable; + cw->zombie = !isViewable; + + if (isViewable) { static XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; + if (cw->origin) free_picture(ps, &cw->origin); cw->origin = XRenderCreatePicture(ps->dpy, cw->src.window, cw->src.format, CPSubwindowMode, &pa); XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); - // Get window pixmap XCompositeRedirectWindow(ps->dpy, cw->src.window, CompositeRedirectAutomatic); cw->redirected = true; + if (cw->cpixmap) free_pixmap(ps, &cw->cpixmap); cw->cpixmap = XCompositeNameWindowPixmap(ps->dpy, cw->src.window); @@ -190,6 +228,7 @@ clientwin_update(ClientWin *cw) { free_picture(ps, &cw->shadow); cw->shadow = XRenderCreatePicture(ps->dpy, cw->cpixmap, cw->src.format, CPSubwindowMode, &pa); + XRenderSetPictureFilter(ps->dpy, cw->shadow, FilterBest, 0, 0); } // Get window icon @@ -199,17 +238,11 @@ clientwin_update(ClientWin *cw) { if (!cw->icon_pict && ps->o.iconDefault) cw->icon_pict = clone_pictw(ps, ps->o.iconDefault); - // Reset mini window parameters - cw->mini.x = cw->mini.y = 0; - cw->mini.width = cw->mini.height = 1; - - cw->zombie = wattr.map_state != IsViewable; - // modes are CLIDISP_THUMBNAIL_ICON, CLIDISP_THUMBNAIL, CLIDISP_ZOMBIE, // CLIDISP_ZOMBIE_ICON, CLIDISP_ICON, CLIDISP_FILLED, CLIDISP_NONE // if we ever got a thumbnail for the window, // the mode for that window always will be thumbnail - cw->mode = clientwin_get_disp_mode(ps, cw); + cw->mode = clientwin_get_disp_mode(ps, cw, isViewable); // printfdf("(%#010lx): %d", cw->wid_client, cw->mode); return true; @@ -283,7 +316,6 @@ clientwin_destroy(ClientWin *cw, bool destroyed) { if (cw->src.window && !destroyed) { free_damage(ps, &cw->damage); - // Stop listening to events, this should be safe because we don't // monitor window re-map anyway XSelectInput(ps->dpy, cw->src.window, 0); diff --git a/src/clientwin.h b/src/clientwin.h index 3861a86..3272100 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -66,37 +66,8 @@ struct _clientwin_t { .mainwin = NULL \ } -static inline client_disp_mode_t -clientwin_get_disp_mode(session_t *ps, ClientWin *cw) { - XWindowAttributes wattr = { }; - XGetWindowAttributes(ps->dpy, cw->src.window, &wattr); - - for (client_disp_mode_t *p = ps->o.clientDisplayModes; *p; p++) { - switch (*p) { - case CLIDISP_THUMBNAIL_ICON: - if (IsViewable == wattr.map_state && cw->origin && cw->icon_pict) - return *p; - break; - case CLIDISP_THUMBNAIL: - if (IsViewable == wattr.map_state && cw->origin) return *p; - break; - case CLIDISP_ZOMBIE_ICON: - if (cw->shadow && cw->icon_pict != NULL) return *p; - break; - case CLIDISP_ZOMBIE: - if (cw->shadow) return *p; - break; - case CLIDISP_ICON: - if (cw->icon_pict) return *p; - break; - case CLIDISP_FILLED: - case CLIDISP_NONE: - return *p; - } - } - - return CLIDISP_NONE; -} +client_disp_mode_t +clientwin_get_disp_mode(session_t *ps, ClientWin *cw, bool isViewable); static inline void clientwin_free_res2(session_t *ps, ClientWin *cw) { diff --git a/src/skippy.c b/src/skippy.c index c3aaeed..0596d1b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -292,8 +292,7 @@ update_clients(MainWin *mw, Bool *touched) // Terminate mw->clients that are no longer managed for (dlist *iter = mw->clients; iter; ) { ClientWin *cw = (ClientWin *) iter->data; - if (dlist_find_data(stack, (void *) cw->wid_client) - /*&& clientwin_update(cw)*/) { + if (dlist_find_data(stack, (void *) cw->wid_client)) { iter = iter->next; } else { @@ -315,7 +314,6 @@ update_clients(MainWin *mw, Bool *touched) cw = clientwin_create(mw, (Window)iter->data); if (!cw) continue; mw->clients = dlist_add(mw->clients, cw); - /*clientwin_update(cw)*/; if (touched) *touched = True; } @@ -344,8 +342,8 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) mw->clientondesktop = NULL; { - session_t * const ps = mw->ps; - long desktop = wm_get_current_desktop(ps); + session_t * const ps = mw->ps; + long desktop = wm_get_current_desktop(ps); dlist *tmp = dlist_first(dlist_find_all(mw->clients, (dlist_match_func) clientwin_validate_func, &desktop)); @@ -900,14 +898,13 @@ mainloop(session_t *ps, bool activate_on_start) { } } else if (ev.type == MapNotify || ev.type == UnmapNotify) { - //printfef("(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); + // printfef("(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); daemon_count_clients(ps->mainwin, 0, None); dlist *iter = (wid ? dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { ClientWin *cw = (ClientWin *) iter->data; clientwin_update(cw); clientwin_update2(cw); - clientwin_render(cw); } } else if (mw && (ps->xinfo.damage_ev_base + XDamageNotify == ev.type)) { From ea62d5a51e2bc5c18a4e07f984d4b34fa59f76ef Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 2 Apr 2023 15:05:17 -0700 Subject: [PATCH 113/205] Fix segfault when last window is killed --- src/skippy.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 05a1b3f..b1f340b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -870,31 +870,11 @@ mainloop(session_t *ps, bool activate_on_start) { else if (mw && ev.type == DestroyNotify) { // printfef("(): else if (ev.type == DestroyNotify) {"); daemon_count_clients(ps->mainwin, 0, None); - dlist *iter = (wid ? dlist_find(mw->clients, clientwin_cmp_func, (void *) wid): NULL); - if (iter) { - // printfef("(): if (iter) {"); - ClientWin *cw = (ClientWin *) iter->data; - if (!cw->mode) { - mw->clients = dlist_first(dlist_remove(iter)); - iter = dlist_find(mw->clientondesktop, clientwin_cmp_func, (void *) wid); - if (iter) - mw->clientondesktop = dlist_first(dlist_remove(iter)); - clientwin_destroy(cw, true); - if (!mw->clientondesktop) { - printfef("(): Last client window destroyed/unmapped, " - "exiting."); - die = true; - } - } - else { - // printfef("(): else {"); - // printfef("(): do: clientwin_render(cw);"); - free_pixmap(ps, &cw->cpixmap); - free_picture(ps, &cw->origin); - free_damage(ps, &cw->damage); - clientwin_update2(cw); - clientwin_render(cw); - } + if (!mw->clientondesktop) { + printfef("(): Last client window destroyed/unmapped, " + "exiting."); + die = true; + mw->client_to_focus = NULL; } } else if (ev.type == MapNotify || ev.type == UnmapNotify) { From 76de634df014455899fed82488db81be6f5f2b60 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 5 Apr 2023 21:32:13 -0700 Subject: [PATCH 114/205] Tidy up printing --- src/clientwin.c | 56 ++++++++---------- src/config.c | 10 ++-- src/config.h | 14 ++--- src/dlist.c | 2 +- src/focus.h | 96 ++++++++++++++++-------------- src/img-gif.c | 22 +++---- src/img-jpeg.c | 8 +-- src/img-png.c | 22 +++---- src/img-xlib.c | 12 ++-- src/img.c | 7 ++- src/img.h | 26 ++++----- src/mainwin.c | 34 +++++------ src/skippy.c | 151 ++++++++++++++++++++++-------------------------- src/skippy.h | 86 +++++++-------------------- src/tooltip.c | 16 +++-- src/wm.c | 26 +++++---- src/wm.h | 8 +-- 17 files changed, 271 insertions(+), 325 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index def76e2..8ec24f0 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -243,7 +243,7 @@ clientwin_update(ClientWin *cw) { // if we ever got a thumbnail for the window, // the mode for that window always will be thumbnail cw->mode = clientwin_get_disp_mode(ps, cw, isViewable); - // printfdf("(%#010lx): %d", cw->wid_client, cw->mode); + printfdf(false, "(%#010lx): %d", cw->wid_client, cw->mode); return true; } @@ -548,8 +548,6 @@ childwin_focus(ClientWin *cw) { int clientwin_handle(ClientWin *cw, XEvent *ev) { - // printfef("(): "); - if (! cw) return 1; @@ -560,9 +558,9 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (ev->type == KeyPress) { - //report_key(ev); - //report_key_modifiers(evk); - fputs("\n", stdout); fflush(stdout); + report_key(ev); + report_key_modifiers(evk); + if (debuglog) fputs("\n", stdout); bool reverse_direction = false; @@ -620,7 +618,6 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) { - //printfef("(): Quitting."); mw->client_to_focus = mw->client_to_focus_on_cancel; return 1; } @@ -633,24 +630,20 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } else if (ev->type == KeyRelease) { - // report_key(ev); - - //report_key(ev); - //report_key_modifiers(evk); - // fputs("\n", stdout); fflush(stdout); + report_key(ev); + report_key_modifiers(evk); + if (debuglog) fputs("\n", stdout); if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode)) { - // printfef("(): if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode))"); - // printfef("(): client_to_focus = %p", (uintptr_t)ps->mainwin->client_to_focus); + printfdf(false, "(): if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnRelease, evk->keycode))"); + printfdf(false, "(): client_to_focus = %p", ps->mainwin->client_to_focus); // mw->client_to_focus = cw; - // printfef("(): client_to_focus = %p", (uintptr_t)ps->mainwin->client_to_focus); return 1; } else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnRelease, evk->keycode)) { - //printfef("(): Quitting."); return 1; } } @@ -661,32 +654,30 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { cw->mainwin->pressed = cw; */ } else if (ev->type == ButtonRelease) { - // printfef("(): else if (ev->type == ButtonRelease) {"); const unsigned button = ev->xbutton.button; if (cw->mainwin->pressed_mouse) { if (button < MAX_MOUSE_BUTTONS) { int ret = clientwin_action(cw, ps->o.bindings_miwMouse[button]); if (ret) { - //printfef("(): Quitting."); return ret; } } } - //else - //printfef("(): ButtonRelease %u ignored.", button); + else + printfdf(false, "(): ButtonRelease %u ignored.", button); } else if (ev->type == FocusIn) { - //printfef("(): else if (ev->type == FocusIn) {"); + printfdf(false, "(): else if (ev->type == FocusIn) {"); XFocusChangeEvent *evf = &ev->xfocus; // for debugging XEvents // see: https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html - //printfef("(): main window id = %#010lx", cw->mainwin->window); - //printfefWindowName(ps, "(): client window = ", cw->mainwin->window); - //printfef("(): client window id = %#010lx", cw->wid_client); - //printfefXFocusChangeEvent(ps, evf); + printfdf(false, "(): main window id = %#010lx", cw->mainwin->window); + printfdfWindowName(ps, "(): client window = ", cw->mainwin->window); + printfdf(false, "(): client window id = %#010lx", cw->wid_client); + printfdfXFocusChangeEvent(ps, evf); // printfef("(): usleep(10000);"); // usleep(10000); @@ -696,19 +687,19 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { cw->focused = true; clientwin_render(cw); - fputs("\n", stdout); + if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); } else if (ev->type == FocusOut) { - //printfef("(): else if (ev->type == FocusOut) {"); + printfdf(false, "(): else if (ev->type == FocusOut) {"); XFocusChangeEvent *evf = &ev->xfocus; // for debugging XEvents // see: https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html - //printfef("(): main window id = %#010lx", cw->mainwin->window); - //printfefWindowName(ps, "(): client window = ", cw->mainwin->window); - //printfef("(): client window id = %#010lx", cw->wid_client); - //printfefXFocusChangeEvent(ps, evf); + printfdf(false, "(): main window id = %#010lx", cw->mainwin->window); + printfdfWindowName(ps, "(): client window = ", cw->mainwin->window); + printfdf(false, "(): client window id = %#010lx", cw->wid_client); + printfdfXFocusChangeEvent(ps, evf); // printfef("(): usleep(10000);"); // usleep(10000); @@ -718,7 +709,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { cw->focused = false; clientwin_render(cw); - fputs("\n", stdout); + if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); } else if(ev->type == EnterNotify) { @@ -753,7 +744,6 @@ clientwin_action(ClientWin *cw, enum cliop action) { case CLIENTOP_NO: break; case CLIENTOP_FOCUS: - //printfef("(): case CLIENTOP_FOCUS:"); mw->client_to_focus = cw; return 1; case CLIENTOP_ICONIFY: diff --git a/src/config.c b/src/config.c index af8515c..e0574e0 100644 --- a/src/config.c +++ b/src/config.c @@ -93,7 +93,7 @@ config_parse(const char *config) { *value = copy_match(line, &matches[2]); new_config = entry_set(new_config, section, key, value); } else { - fprintf(stderr, "WARNING: Ignoring invalid line: %s\n", line); + printfef(true, "WARNING: Ignoring invalid line: %s\n", line); } l_ix = 0; } else { @@ -125,12 +125,12 @@ config_load(const char *path) if(! fin) { - fprintf(stderr, "WARNING: Couldn't load config file '%s'.\n", path); + printfef(true, "WARNING: Couldn't load config file '%s'.\n", path); return 0; } else { - printfef("(): config file found. using \"%s\"", path); + printfef(true, "(): config file found. using \"%s\"", path); } fseek(fin, 0, SEEK_END); @@ -138,7 +138,7 @@ config_load(const char *path) if(! flen) { - fprintf(stderr, "WARNING: '%s' is empty.\n", path); + printfef(true, "WARNING: '%s' is empty.\n", path); fclose(fin); return 0; } @@ -149,7 +149,7 @@ config_load(const char *path) data[flen] = '\0'; if(fread(data, 1, flen, fin) != flen) { - fprintf(stderr, "WARNING: Couldn't read from config file '%s'.\n", path); + printfef(true, "WARNING: Couldn't read from config file '%s'.\n", path); free(data); fclose(fin); return 0; diff --git a/src/config.h b/src/config.h index 1663787..ee5bc77 100644 --- a/src/config.h +++ b/src/config.h @@ -41,7 +41,7 @@ config_get_bool(dlist *config, const char *section, const char *key, return true; if (!strcasecmp("false", result)) return false; - printfe("(%s, %s, %d): Unrecogized boolean value \"%s\".", + printfef(true, "(%s, %s, %d): Unrecogized boolean value \"%s\".", section, key, def, result); return def; } @@ -67,17 +67,17 @@ config_get_int(dlist *config, const char *section, const char *key, char *endptr = NULL; int iresult = strtol(result, &endptr, 0); if (!endptr || (*endptr && !isspace(*endptr))) { - printfef("(%s, %s, %d): Value \"%s\" is not a valid integer.", + printfef(true, "(%s, %s, %d): Value \"%s\" is not a valid integer.", section, key, def, result); return def; } if (iresult > max) { - printfef("(%s, %s, %d): Value \"%s\" larger than maximum value %d.", + printfef(true, "(%s, %s, %d): Value \"%s\" larger than maximum value %d.", section, key, def, result, max); return max; } if (iresult < min) { - printfef("(%s, %s, %d): Value \"%s\" smaller than minimal value %d.", + printfef(true, "(%s, %s, %d): Value \"%s\" smaller than minimal value %d.", section, key, def, result, min); return min; } @@ -105,17 +105,17 @@ config_get_double(dlist *config, const char *section, const char *key, char *endptr = NULL; double dresult = strtod(result, &endptr); if (!endptr || (*endptr && !isspace(*endptr))) { - printfef("(%s, %s, %f): Value \"%s\" is not a valid floating-point number.", + printfef(true, "(%s, %s, %f): Value \"%s\" is not a valid floating-point number.", section, key, def, result); return def; } if (dresult > max) { - printfef("(%s, %s, %f): Value \"%s\" larger than maximum value %f.", + printfef(true, "(%s, %s, %f): Value \"%s\" larger than maximum value %f.", section, key, def, result, max); return max; } if (dresult < min) { - printfef("(%s, %s, %f): Value \"%s\" smaller than minimal value %f.", + printfef(true, "(%s, %s, %f): Value \"%s\" smaller than minimal value %f.", section, key, def, result, min); return min; } diff --git a/src/dlist.c b/src/dlist.c index 36a0b55..2698c06 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -141,7 +141,7 @@ dlist_insert_nth(dlist *l, dlist *new_elem, unsigned int n) else { // there is no nth element - printfef("(%p,%p,%i): list has fewer than %i elements. appending as the last element.", l, new_elem, n, n); + printfef(false, "(%p,%p,%i): list has fewer than %i elements. appending as the last element.", l, new_elem, n, n); first_elem = dlist_insert_after( dlist_last(l), new_elem); } diff --git a/src/focus.h b/src/focus.h index 87bcd05..72175d9 100644 --- a/src/focus.h +++ b/src/focus.h @@ -21,40 +21,54 @@ #define SKIPPY_FOCUS_H static inline void -printfefXFocusChangeEvent(session_t *ps, XFocusChangeEvent *evf) +printfdfXFocusChangeEvent(session_t *ps, XFocusChangeEvent *evf) { - printfefWindowName(ps, "(): event window = ", evf->window); - printfef("(): event window id = %#010lx", evf->window); - - if(evf->mode == NotifyNormal) - printfef("(): evf->mode = NotifyNormal"); - else if(evf->mode == NotifyGrab) - printfef("(): evf->mode = NotifyGrab"); - else if(evf->mode == NotifyUngrab) - printfef("(): evf->mode = NotifyUngrab"); - else if(evf->mode == NotifyWhileGrabbed) - printfef("(): evf->mode = NotifyWhileGrabbed"); - else - printfef("(): evf->mode = %i (not recognized)", evf->mode); - - if(evf->detail == NotifyAncestor) - printfef("(): evf->detail = NotifyAncestor"); - else if(evf->detail == NotifyVirtual) - printfef("(): evf->detail = NotifyVirtual"); - else if(evf->detail == NotifyInferior) - printfef("(): evf->detail = NotifyInferior"); - else if(evf->detail == NotifyNonlinear) - printfef("(): evf->detail = NotifyNonlinear"); - else if(evf->detail == NotifyNonlinearVirtual) - printfef("(): evf->detail = NotifyNonlinearVirtual"); - else if(evf->detail == NotifyPointer) - printfef("(): evf->detail = NotifyPointer"); - else if(evf->detail == NotifyPointerRoot) - printfef("(): evf->detail = NotifyPointerRoot"); - else if(evf->detail == NotifyDetailNone) - printfef("(): evf->detail = NotifyDetailNone"); - else - printfef("(): evf->detail = %i (not recognized)", evf->detail); + printfdfWindowName(ps, "(): event window = ", evf->window); + printfdf(false, "(): event window id = %#010lx", evf->window); + + if(evf->mode == NotifyNormal) { + printfdf(false, "(): evf->mode = NotifyNormal"); + } + else if(evf->mode == NotifyGrab) { + printfdf(false, "(): evf->mode = NotifyGrab"); + } + else if(evf->mode == NotifyUngrab) { + printfdf(false, "(): evf->mode = NotifyUngrab"); + } + else if(evf->mode == NotifyWhileGrabbed) { + printfdf(false, "(): evf->mode = NotifyWhileGrabbed"); + } + else { + printfdf(false, "(): evf->mode = %i (not recognized)", evf->mode); + } + + if(evf->detail == NotifyAncestor) { + printfdf(false, "(): evf->detail = NotifyAncestor"); + } + else if(evf->detail == NotifyVirtual) { + printfdf(false, "(): evf->detail = NotifyVirtual"); + } + else if(evf->detail == NotifyInferior) { + printfdf(false, "(): evf->detail = NotifyInferior"); + } + else if(evf->detail == NotifyNonlinear) { + printfdf(false, "(): evf->detail = NotifyNonlinear"); + } + else if(evf->detail == NotifyNonlinearVirtual) { + printfdf(false, "(): evf->detail = NotifyNonlinearVirtual"); + } + else if(evf->detail == NotifyPointer) { + printfdf(false, "(): evf->detail = NotifyPointer"); + } + else if(evf->detail == NotifyPointerRoot) { + printfdf(false, "(): evf->detail = NotifyPointerRoot"); + } + else if(evf->detail == NotifyDetailNone) { + printfdf(false, "(): evf->detail = NotifyDetailNone"); + } + else { + printfdf(false, "(): evf->detail = %i (not recognized)", evf->detail); + } } static inline void @@ -75,18 +89,16 @@ clear_focus_all(dlist *focuslist) */ static inline void focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { - // printfef("(): "); - if (!cw || !ps) return; clear_focus_all(cw->mainwin->focuslist); - //printfefWindowName(ps, "(): window = ", cw->wid_client); + printfdfWindowName(ps, "(): window = ", cw->wid_client); if (unlikely(!cw)) { - // printfef("(): if (unlikely(!cw))"); + printfdf(false, "(): if (unlikely(!cw))"); return; } assert(cw->mini.window); @@ -95,7 +107,7 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { if (move_ptr) { - // printfef("(): if (move_ptr)"); + printfdf(false, "(): if (move_ptr)"); XWarpPointer(ps->dpy, None, cw->mini.window, 0, 0, 0, 0, cw->mini.width / 2, cw->mini.height / 2); } XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); @@ -104,8 +116,8 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { ps->mainwin->client_to_focus = cw; ps->mainwin->client_to_focus->focused = 1; - // printfef("(): "); - // printfef("(): client_to_focus = %p", (uintptr_t)ps->mainwin->client_to_focus); + printfdf(false, "(): "); + printfdf(false, "(): client_to_focus = %p", ps->mainwin->client_to_focus); } static inline void @@ -120,7 +132,7 @@ static inline void focus_miniw_next(session_t *ps, ClientWin *cw) { dlist *e = dlist_find_data(cw->mainwin->focuslist, cw); if (!e) { - printfef("(%#010lx): Client window not found in list.", cw->src.window); + printfef(false, "(%#010lx): Client window not found in list.", cw->src.window); return; } if (e->next) @@ -148,7 +160,7 @@ focus_miniw_prev(session_t *ps, ClientWin *cw) { } if (!tgt) { - printfef("(%#010lx): Client window not found in list.", cw->src.window); + printfef(false, "(%#010lx): Client window not found in list.", cw->src.window); return; } diff --git a/src/img-gif.c b/src/img-gif.c index 95709ce..6b852bb 100644 --- a/src/img-gif.c +++ b/src/img-gif.c @@ -39,7 +39,7 @@ sgif_read(session_t *ps, const char *path) { #ifdef SGIF_THREADSAFE errstr = GifErrorString(err); #endif - printfef("(\"%s\"): Failed to open file: %d (%s)", path, err, errstr); + printfef(false, "(\"%s\"): Failed to open file: %d (%s)", path, err, errstr); goto sgif_read_end; } @@ -51,29 +51,29 @@ sgif_read(session_t *ps, const char *path) { ++i; switch (rectype) { case UNDEFINED_RECORD_TYPE: - printfef("(\"%s\"): %d: Encountered a record of unknown type.", + printfef(false, "(\"%s\"): %d: Encountered a record of unknown type.", path, i); break; case SCREEN_DESC_RECORD_TYPE: - printfef("(\"%s\"): %d: Encountered a record of " + printfef(false, "(\"%s\"): %d: Encountered a record of " "ScreenDescRecordType. This shouldn't happen!", path, i); break; case IMAGE_DESC_RECORD_TYPE: if (data) { - printfef("(\"%s\"): %d: Extra image section ignored.", + printfef(false, "(\"%s\"): %d: Extra image section ignored.", path, i); break; } if (GIF_ERROR == DGifGetImageDesc(f)) { - printfef("(\"%s\"): %d: Failed to read GIF image info.", + printfef(false, "(\"%s\"): %d: Failed to read GIF image info.", path, i); break; } width = f->Image.Width; height = f->Image.Height; if (width <= 0 || height <= 0) { - printfef("(\"%s\"): %d: Width/height invalid.", path, i); + printfef(false, "(\"%s\"): %d: Width/height invalid.", path, i); break; } assert(!data); @@ -81,7 +81,7 @@ sgif_read(session_t *ps, const char *path) { // FIXME: Interlace images may need special treatments for (int j = 0; j < height; ++j) if (GIF_OK != DGifGetLine(f, &data[j * width], width)) { - printfef("(\"%s\"): %d: Failed to read line %d.", path, i, j); + printfef(false, "(\"%s\"): %d: Failed to read line %d.", path, i, j); goto sgif_read_end; } break; @@ -90,7 +90,7 @@ sgif_read(session_t *ps, const char *path) { int code = 0; GifByteType *pbytes = NULL; if (GIF_OK != DGifGetExtension(f, &code, &pbytes) || !pbytes) { - printfef("(\"%s\"): %d: Failed to read extension block.", + printfef(false, "(\"%s\"): %d: Failed to read extension block.", path, i); break; } @@ -107,7 +107,7 @@ sgif_read(session_t *ps, const char *path) { } } if (unlikely(!data)) { - printfef("(\"%s\"): No valid data found.", path); + printfef(false, "(\"%s\"): No valid data found.", path); goto sgif_read_end; } } @@ -118,7 +118,7 @@ sgif_read(session_t *ps, const char *path) { ColorMapObject *cmap = f->Image.ColorMap; if (!cmap) cmap = f->SColorMap; if (unlikely(!cmap)) { - printfef("(\"%s\"): No colormap found.", path); + printfef(false, "(\"%s\"): No colormap found.", path); goto sgif_read_end; } tdata = allocchk(malloc(width * height * depth / 8)); @@ -143,7 +143,7 @@ sgif_read(session_t *ps, const char *path) { pictw = simg_data_to_pictw(ps, width, height, depth, tdata, 0); free(tdata); if (unlikely(!pictw)) { - printfef("(\"%s\"): Failed to create Picture.", path); + printfef(false, "(\"%s\"): Failed to create Picture.", path); goto sgif_read_end; } diff --git a/src/img-jpeg.c b/src/img-jpeg.c index 2b7b0c9..323cca9 100644 --- a/src/img-jpeg.c +++ b/src/img-jpeg.c @@ -14,7 +14,7 @@ sjpg_read(session_t *ps, const char *path) { FILE *fp = fopen(path, "rb"); if (unlikely(!fp)) { - printfef("(\"%s\"): Failed to open file.", path); + printfef(false, "(\"%s\"): Failed to open file.", path); goto sjpg_read_end; } jpeg_stdio_src(&cinfo, fp); @@ -35,7 +35,7 @@ sjpg_read(session_t *ps, const char *path) { while (cinfo.output_scanline < cinfo.output_height) { if (unlikely(!jpeg_read_scanlines(&cinfo, &rowptrs[cinfo.output_scanline], cinfo.output_height - cinfo.output_scanline))) { - printfef("(\"%s\"): Failed to read scanline %d.", path, + printfef(false, "(\"%s\"): Failed to read scanline %d.", path, cinfo.output_scanline); goto sjpg_read_end; } @@ -60,14 +60,14 @@ sjpg_read(session_t *ps, const char *path) { } } if (unlikely(!jpeg_finish_decompress(&cinfo))) { - printfef("(\"%s\"): Failed to finish decompression.", path); + printfef(false, "(\"%s\"): Failed to finish decompression.", path); goto sjpg_read_end; } need_abort = false; pictw = simg_data_to_pictw(ps, width, height, depth, data, 0); free(data); if (unlikely(!pictw)) { - printfef("(\"%s\"): Failed to create Picture.", path); + printfef(false, "(\"%s\"): Failed to create Picture.", path); goto sjpg_read_end; } diff --git a/src/img-png.c b/src/img-png.c index 4ba9404..859f86c 100644 --- a/src/img-png.c +++ b/src/img-png.c @@ -10,7 +10,7 @@ void spng_about(FILE *os) { - fprintf(os, "PNG support: Yes\n" + printfdf(true, "PNG support: Yes\n" " Compiled with libpng %s, using %s.\n" " Compiled with zlib %s, using %s.\n", PNG_LIBPNG_VER_STRING, png_libpng_ver, @@ -28,16 +28,16 @@ spng_read(session_t *ps, const char *path) { FILE *fp = fopen(path, "rb"); bool need_premultiply = false; if (unlikely(!fp)) { - printfef("(\"%s\"): Failed to open file.", path); + printfef(false, "(\"%s\"): Failed to open file.", path); goto spng_read_end; } if (unlikely(SPNG_SIGBYTES != fread(&sig, 1, SPNG_SIGBYTES, fp))) { - printfef("(\"%s\"): Failed to read %d-byte signature.", + printfef(false, "(\"%s\"): Failed to read %d-byte signature.", path, SPNG_SIGBYTES); goto spng_read_end; } if (unlikely(png_sig_cmp((png_bytep) sig, 0, SPNG_SIGBYTES))) { - printfef("(\"%s\"): PNG signature invalid.", path); + printfef(false, "(\"%s\"): PNG signature invalid.", path); goto spng_read_end; } png_ptr = allocchk(png_create_read_struct(PNG_LIBPNG_VER_STRING, @@ -59,7 +59,7 @@ spng_read(session_t *ps, const char *path) { // Scale or strip 16-bit colors if (bit_depth == 16) { - printfdf("(\"%s\"): Scaling 16-bit colors.", path); + printfdf(false, "(\"%s\"): Scaling 16-bit colors.", path); #if PNG_LIBPNG_VER >= 10504 png_set_scale_16(png_ptr); #else @@ -76,19 +76,19 @@ spng_read(session_t *ps, const char *path) { // Convert palette to RGB if (color_type == PNG_COLOR_TYPE_PALETTE) { - printfdf("(\"%s\"): Converting palette PNG to RGB.", path); + printfdf(false, "(\"%s\"): Converting palette PNG to RGB.", path); png_set_palette_to_rgb(png_ptr); color_type = PNG_COLOR_TYPE_RGB; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - printfdf("(\"%s\"): Converting rDNS to full alpha.", path); + printfdf(false, "(\"%s\"): Converting rDNS to full alpha.", path); png_set_tRNS_to_alpha(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { - printfdf("(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path); + printfdf(false, "(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path); png_set_gray_to_rgb(png_ptr); if (PNG_COLOR_TYPE_GRAY == color_type) color_type = PNG_COLOR_TYPE_RGB; @@ -98,7 +98,7 @@ spng_read(session_t *ps, const char *path) { /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - printfdf("(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path); + printfdf(false, "(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path); #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8(png_ptr); #else @@ -110,7 +110,7 @@ spng_read(session_t *ps, const char *path) { // Somehow XImage requires 24-bit visual to use 32 bits per pixel if (color_type == PNG_COLOR_TYPE_RGB) { - printfdf("(\"%s\"): Appending filler alpha values.", path); + printfdf(false, "(\"%s\"): Appending filler alpha values.", path); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } @@ -161,7 +161,7 @@ spng_read(session_t *ps, const char *path) { row_pointers[0], rowbytes); png_free(png_ptr, row_pointers[0]); if (unlikely(!pictw)) { - printfef("(\"%s\"): Failed to create Picture.", path); + printfef(false, "(\"%s\"): Failed to create Picture.", path); goto spng_read_end; } } diff --git a/src/img-xlib.c b/src/img-xlib.c index 0d2e2d9..bb153b9 100644 --- a/src/img-xlib.c +++ b/src/img-xlib.c @@ -20,19 +20,19 @@ simg_load_icon(session_t *ps, Window wid, int desired_size) { int wanted_bytes = 0; for (const long *p = prop.data32; p < end; p += wanted_bytes) { if (p + 2 >= end) { - printfef("(%#010lx): %d trailing byte(s).", wid, (int) (end - p)); + printfef(false, "(%#010lx): %d trailing byte(s).", wid, (int) (end - p)); break; } width = p[0]; height = p[1]; if (width <= 0 || height <= 0) { - printfef("(%#010lx): (offset %d, width %d, height %d) Invalid width/height.", + printfef(false, "(%#010lx): (offset %d, width %d, height %d) Invalid width/height.", wid, (int) (p - prop.data32), width, height); break; } wanted_bytes = 2 + width * height; if ((end - p) < wanted_bytes) { - printfef("(%#010lx): (offset %d, width %d, height %d) Not enough bytes (%d/%d).", + printfef(false, "(%#010lx): (offset %d, width %d, height %d) Not enough bytes (%d/%d).", wid, (int) (p - prop.data32), width, height, (int) (end - p), wanted_bytes); break; } @@ -62,9 +62,9 @@ simg_load_icon(session_t *ps, Window wid, int desired_size) { free(converted_data); } if (!pictw) - printfef("(%#010lx): Failed to create picture.", wid); + printfef(false, "(%#010lx): Failed to create picture.", wid); /* if (pictw) - printfdf("(%#010lx): (offset %d, width %d, height %d) Loaded.", + printfdf(false, "(%#010lx): (offset %d, width %d, height %d) Loaded.", wid, (int) (best_data - prop.data8), pictw->width, pictw->height); */ } free_winprop(&prop); @@ -104,7 +104,7 @@ simg_load_icon(session_t *ps, Window wid, int desired_size) { if (pictw && !processed) { pictw = simg_postprocess(ps, pictw, PICTPOSP_SCALEK, desired_size, desired_size, ALIGN_MID, ALIGN_MID, NULL); - /* printfdf("(%#010lx): (width %d, height %d) Processed.", + /* printfdf(false, "(%#010lx): (width %d, height %d) Processed.", wid, pictw->width, pictw->height); */ } diff --git a/src/img.c b/src/img.c index 0599ec4..29d21ed 100644 --- a/src/img.c +++ b/src/img.c @@ -43,8 +43,9 @@ simg_postprocess(session_t *ps, pictw_t *src, enum pict_posp_mode mode, if (!src) { if (twidth && theight) { - if (!(dest = create_pictw(ps, twidth, theight, depth))) - printfef("(): Failed to create Picture."); + if (!(dest = create_pictw(ps, twidth, theight, depth))) { + printfef(false, "(): Failed to create Picture."); + } else XRenderFillRectangle(ps->dpy, PictOpSrc, dest->pict, pc, 0, 0, twidth, theight); @@ -60,7 +61,7 @@ simg_postprocess(session_t *ps, pictw_t *src, enum pict_posp_mode mode, else if (!theight) theight = (double) twidth / src->width * src->height; if (!(dest = create_pictw(ps, twidth, theight, depth))) { - printfef("(): Failed to create Picture."); + printfef(false, "(): Failed to create Picture."); goto simg_postprocess_end; } diff --git a/src/img.h b/src/img.h index ec6ce7d..7040074 100644 --- a/src/img.h +++ b/src/img.h @@ -115,7 +115,7 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, pictw_t *pictw = NULL; if (!pxmap) { - printfef("(%d, %d, %d, %#010lx): Missing pixmap.", width, height, depth, pxmap); + printfef(false, "(%d, %d, %d, %#010lx): Missing pixmap.", width, height, depth, pxmap); return NULL; } @@ -126,7 +126,7 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, unsigned rwidth = 0, rheight = 0, rborder_width = 0, rdepth = 0; if (!XGetGeometry(ps->dpy, pxmap, &rroot, &rx, &ry, &rwidth, &rheight, &rborder_width, &rdepth)) { - printfef("(%d, %d, %d, %#010lx): Failed to determine pixmap size.", width, height, depth, pxmap); + printfef(false, "(%d, %d, %d, %#010lx): Failed to determine pixmap size.", width, height, depth, pxmap); return NULL; } width = rwidth; @@ -136,14 +136,14 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, // Sanity check if (!(width && height && depth)) { - printfef("(%d, %d, %d, %#010lx): Failed to get pixmap info.", width, height, depth, pxmap); + printfef(false, "(%d, %d, %d, %#010lx): Failed to get pixmap info.", width, height, depth, pxmap); return NULL; } // Find X Render format const XRenderPictFormat *rfmt = depth_to_rfmt(ps, depth); if (!rfmt) { - printfef("(%d, %d, %d, %#010lx): Failed to find X Render format for depth %d.", + printfef(false, "(%d, %d, %d, %#010lx): Failed to find X Render format for depth %d.", width, height, depth, pxmap, depth); return NULL; } @@ -157,7 +157,7 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, if (!(pictw->pict = XRenderCreatePicture(ps->dpy, pictw->pxmap, rfmt, 0, NULL))) { - printfef("(%d, %d, %d, %#010lx): Failed to create Picture.", + printfef(false, "(%d, %d, %d, %#010lx): Failed to create Picture.", width, height, depth, pxmap); free_pictw(ps, &pictw); } @@ -172,7 +172,7 @@ static inline pictw_t * create_pictw(session_t *ps, int width, int height, int depth) { Pixmap pxmap = XCreatePixmap(ps->dpy, ps->root, width, height, depth); if (!pxmap) { - printfef("(%d, %d, %d): Failed to create Pixmap.", width, height, depth); + printfef(false, "(%d, %d, %d): Failed to create Pixmap.", width, height, depth); return NULL; } @@ -265,14 +265,14 @@ simg_pixmap_to_pictw(session_t *ps, int width, int height, int depth, pictw_t *pictw = NULL; if (!porig) { - printfef("(%d, %d, %d, %#010lx, %#010lx): Failed to create picture for pixmap.", + printfef(false, "(%d, %d, %d, %#010lx, %#010lx): Failed to create picture for pixmap.", width, height, depth, pxmap, mask); goto simg_pixmap_to_pict_end; } if (mask) { if (!(pmask = create_pictw_frompixmap(ps, width, height, depth, mask))) { - printfef("(%d, %d, %d, %#010lx, %#010lx): Failed to create picture for mask.", + printfef(false, "(%d, %d, %d, %#010lx, %#010lx): Failed to create picture for mask.", width, height, depth, pxmap, mask); goto simg_pixmap_to_pict_end; } @@ -281,7 +281,7 @@ simg_pixmap_to_pictw(session_t *ps, int width, int height, int depth, } if (!(pictw = create_pictw(ps, porig->width, porig->height, (mask ? 32: porig->depth)))) { - printfef("(%d, %d, %d, %#010lx, %#010lx): Failed to create target picture.", + printfef(false, "(%d, %d, %d, %#010lx, %#010lx): Failed to create target picture.", width, height, depth, pxmap, mask); goto simg_pixmap_to_pict_end; } @@ -299,7 +299,7 @@ simg_pixmap_to_pictw(session_t *ps, int width, int height, int depth, /* gc = XCreateGC(ps->dpy, pictw->pxmap, 0, 0); if (!gc) { - printfef("(%#010lx, %#010lx, %d, %d, %d): Failed to create GC.", + printfef(false, "(%#010lx, %#010lx, %d, %d, %d): Failed to create GC.", pxmap, mask, width, height, depth); free_pictw(ps, &pictw); goto simg_data_to_pict_end; @@ -334,18 +334,18 @@ simg_data_to_pictw(session_t *ps, int width, int height, int depth, depth, ZPixmap, 0, (char *) data, width, height, 8, bytes_per_line); if (!img) { - printfef("(%d, %d, %d): Failed to create XImage.", + printfef(false, "(%d, %d, %d): Failed to create XImage.", width, height, depth); goto simg_data_to_pict_end; } if (!(pictw = create_pictw(ps, width, height, depth))) { - printfef("(%d, %d, %d): Failed to create Picture.", + printfef(false, "(%d, %d, %d): Failed to create Picture.", width, height, depth); goto simg_data_to_pict_end; } gc = XCreateGC(ps->dpy, pictw->pxmap, 0, 0); if (!gc) { - printfef("(%d, %d, %d): Failed to create GC.", + printfef(false, "(%d, %d, %d): Failed to create GC.", width, height, depth); free_pictw(ps, &pictw); goto simg_data_to_pict_end; diff --git a/src/mainwin.c b/src/mainwin.c index ceff2a9..5bea484 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -105,7 +105,7 @@ mainwin_create(session_t *ps) { if (ps->xinfo.xinerama_exist && XineramaIsActive(dpy)) { mw->xin_info = XineramaQueryScreens(ps->dpy, &mw->xin_screens); # ifdef DEBUG_XINERAMA - printfef("(): Xinerama is enabled (%d screens).", mw->xin_screens); + printfdf(false, "(): Xinerama is enabled (%d screens).", mw->xin_screens); # endif /* DEBUG_XINERAMA */ } #endif /* CFG_XINERAMA */ @@ -195,7 +195,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { mw->depth = 32; mw->visual = ps->argb_visual; if (!mw->visual) { - printfef("(): Couldn't find ARGB visual, lazy transparency can't work."); + printfef(true, "(): Couldn't find ARGB visual, lazy transparency can't work."); goto mainwin_create_err; } } @@ -210,7 +210,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { XColor exact_color; if(!XParseColor(ps->dpy, mw->colormap, ps->o.normal_tint, &exact_color)) { - printfef("(): Couldn't look up color '%s', reverting to black.", ps->o.normal_tint); + printfef(true, "(): Couldn't look up color '%s', reverting to black.", ps->o.normal_tint); mw->normalTint.red = mw->normalTint.green = mw->normalTint.blue = 0; } else @@ -223,7 +223,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { if(! XParseColor(ps->dpy, mw->colormap, ps->o.highlight_tint, &exact_color)) { - fprintf(stderr, "Couldn't look up color '%s', reverting to #101020", ps->o.highlight_tint); + printfef(true, "Couldn't look up color '%s', reverting to #101020", ps->o.highlight_tint); mw->highlightTint.red = mw->highlightTint.green = 0x10; mw->highlightTint.blue = 0x20; } @@ -238,7 +238,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { ; if(! XParseColor(ps->dpy, mw->colormap, ps->o.shadow_tint, &exact_color)) { - fprintf(stderr, "Couldn't look up color '%s', reverting to #040404", ps->o.shadow_tint); + printfef(true, "Couldn't look up color '%s', reverting to #040404", ps->o.shadow_tint); mw->shadowTint.red = mw->shadowTint.green = mw->shadowTint.blue = 0x04; } else @@ -358,13 +358,13 @@ mainwin_update(MainWin *mw) } # ifdef DEBUG - fprintf(stderr, "--> querying pointer... "); + printfdf(false, "--> querying pointer... "); # endif /* DEBUG */ XQueryPointer(ps->dpy, ps->root, &dummy_w, &dummy_w, &root_x, &root_y, &dummy_i, &dummy_i, &dummy_u); # ifdef DEBUG - fprintf(stderr, "+%i+%i\n", root_x, root_y); + printfdf(false, "+%i+%i\n", root_x, root_y); - fprintf(stderr, "--> figuring out which screen we're on... "); + printfdf(false, "--> figuring out which screen we're on... "); # endif /* DEBUG */ iter = mw->xin_info; for(i = 0; i < mw->xin_screens; ++i) @@ -373,7 +373,7 @@ mainwin_update(MainWin *mw) root_y >= iter->y_org && root_y < iter->y_org + iter->height) { # ifdef DEBUG - fprintf(stderr, "screen %i %ix%i+%i+%i\n", iter->screen_number, iter->width, iter->height, iter->x_org, iter->y_org); + printfdf(false, "screen %i %ix%i+%i+%i\n", iter->screen_number, iter->width, iter->height, iter->x_org, iter->y_org); # endif /* DEBUG */ break; } @@ -382,7 +382,7 @@ mainwin_update(MainWin *mw) if(i == mw->xin_screens) { # ifdef DEBUG - fprintf(stderr, "unknown\n"); + printfdf(false, "unknown\n"); # endif /* DEBUG */ return; } @@ -413,7 +413,7 @@ mainwin_map(MainWin *mw) { int ret = XGrabKeyboard(ps->dpy, mw->window, True, GrabModeAsync, GrabModeAsync, CurrentTime); if (Success != ret) - printfef("(): Failed to grab keyboard (%d), troubles ahead.", ret); + printfef(true, "(): Failed to grab keyboard (%d), troubles ahead.", ret); } */ mw->mapped = true; } @@ -513,7 +513,7 @@ mainwin_transform(MainWin *mw, float f) int mainwin_handle(MainWin *mw, XEvent *ev) { - // printfef("(): "); + printfdf(false, "(): "); session_t *ps = mw->ps; switch(ev->type) { @@ -522,17 +522,17 @@ mainwin_handle(MainWin *mw, XEvent *ev) { break; case KeyPress: case KeyRelease: - // printfef("(): KeyPress or KeyRelease"); + printfdf(false, "(): KeyPress or KeyRelease"); // if(mw->client_to_focus) // { - // printfef("(): clientwin_handle(mw->client_to_focus, ev);"); + // printfdf(false, "(): clientwin_handle(mw->client_to_focus, ev);"); if(clientwin_handle(mw->client_to_focus, ev)) return 1; // } // else // { - // printfef("(): mw->client_to_focus == NULL"); + // printfdf(false, "(): mw->client_to_focus == NULL"); // } break; case ButtonPress: @@ -540,12 +540,12 @@ mainwin_handle(MainWin *mw, XEvent *ev) { break; case ButtonRelease: if (mw->pressed_mouse) { - printfef("(): Detected mouse button release on main window, " + printfdf(false, "(): Detected mouse button release on main window, " "exiting."); return 1; } else - printfef("(): ButtonRelease %u ignored.", ev->xbutton.button); + printfdf(false, "(): ButtonRelease %u ignored.", ev->xbutton.button); break; } diff --git a/src/skippy.c b/src/skippy.c index b1f340b..366f931 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -26,6 +26,8 @@ #include #include +bool debuglog = true; + enum pipe_cmd_t { // Not ordered properly for backward compatibility PIPECMD_RELOAD_CONFIG = 0, @@ -61,7 +63,7 @@ parse_cliop(session_t *ps, const char *str, enum cliop *dest) { return true; } - printfef("(\"%s\"): Unrecognized operation.", str); + printfef(true, "(\"%s\"): Unrecognized operation.", str); return false; } @@ -81,7 +83,7 @@ parse_align(session_t *ps, const char *str, enum align *dest) { return strlen(STRS_ALIGN[i]); } - printfef("(\"%s\"): Unrecognized operation.", str); + printfef(true, "(\"%s\"): Unrecognized operation.", str); return 0; } @@ -111,7 +113,7 @@ parse_pict_posp_mode(session_t *ps, const char *str, enum pict_posp_mode *dest) return strlen(STRS_PICTPOSP[i]); } - printfef("(\"%s\"): Unrecognized operation.", str); + printfef(true, "(\"%s\"): Unrecognized operation.", str); return 0; } static inline int @@ -159,7 +161,7 @@ parse_color(session_t *ps, const char *s, XRenderColor *pc) { if (!((next = parse_color_sub(s, &pc->red)) && (next = parse_color_sub((s += next), &pc->green)) && (next = parse_color_sub((s += next), &pc->blue)))) { - printfef("(\"%s\"): Failed to read color segment.", s); + printfef(true, "(\"%s\"): Failed to read color segment.", s); return 0; } if (!(next = parse_color_sub((s += next), &pc->alpha))) @@ -168,7 +170,7 @@ parse_color(session_t *ps, const char *s, XRenderColor *pc) { return s - sorig; } - printfef("(\"%s\"): Unrecognized color format.", s); + printfef(true, "(\"%s\"): Unrecognized color format.", s); return 0; } @@ -204,7 +206,7 @@ parse_size(const char *s, int *px, int *py) { if (endptr && s != endptr) { *py = val; if (*py < 0) { - printfef("(\"%s\"): Invalid height.", s); + printfef(true, "(\"%s\"): Invalid height.", s); return 0; } s = endptr; @@ -218,7 +220,7 @@ parse_size(const char *s, int *px, int *py) { return 0; if (!isspace0(*s)) { - printfef("(\"%s\"): Trailing characters.", s); + printfef(true, "(\"%s\"): Trailing characters.", s); return 0; } @@ -331,10 +333,9 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) // while mw->clientondesktop is only those in current virtual desktop // if that option is user supplied - // printfef("(): updating dl list of clients"); update_clients(mw, 0); if (!mw->clients) { - printfef("(): No client windows found."); + printfdf(false, "(): No client windows found."); return; } @@ -348,7 +349,7 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) dlist *tmp = dlist_first(dlist_find_all(mw->clients, (dlist_match_func) clientwin_validate_func, &desktop)); if (!tmp) { - printfef("(): No client window on current desktop found."); + printfdf(false, "(): No client window on current desktop found."); return; } @@ -531,7 +532,7 @@ ev_window(session_t *ps, const XEvent *ev) { if (ps->xinfo.damage_ev_base + XDamageNotify == ev->type) return ((XDamageNotifyEvent *) ev)->drawable; - printf("(): Failed to find window for event type %d. Troubles ahead.", + printfef(false, "(): Failed to find window for event type %d. Troubles ahead.", ev->type); return ev->xany.window; @@ -550,7 +551,7 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { if (mw && mw->window == wid) wextra = "(Main)"; print_timestamp(ps); - printfd("Event %-13.13s wid %#010lx %s", name, wid, wextra); + printfdf(false, "Event %-13.13s wid %#010lx %s", name, wid, wextra); } static void @@ -638,7 +639,7 @@ skippy_activate(MainWin *mw, Window leader, bool paging) if (paging) { init_desktop_layout(mw, mw->revert_focus_win, leader); if (!mw->clientondesktop) { - printfef("(): Failed to build layout."); + printfef(false, "(): Failed to build layout."); return false; } mw->focuslist = mw->clientondesktop; @@ -646,7 +647,7 @@ skippy_activate(MainWin *mw, Window leader, bool paging) else { init_layout(mw, mw->revert_focus_win, leader); if (!mw->clientondesktop) { - printfef("(): Failed to build layout."); + printfef(false, "(): Failed to build layout."); return false; } } @@ -681,7 +682,7 @@ open_pipe(session_t *ps, struct pollfd *r_fd) { return true; } else { - printfef("(): Failed to open pipe \"%s\": %d", ps->o.pipePath, errno); + printfef(true, "(): Failed to open pipe \"%s\": %d", ps->o.pipePath, errno); perror("open"); } @@ -718,14 +719,10 @@ mainloop(session_t *ps, bool activate_on_start) { // Activation goes first, so that it won't be delayed by poll() if (!mw && activate) { - // printfef("(): if (!mw && activate) {"); - assert(ps->mainwin); activate = false; if (skippy_activate(ps->mainwin, None, paging)) { - // printfef("(): if (skippy_activate(ps->mainwin, None)) {"); - // printfef("(): was in skippy_activate"); last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; @@ -758,8 +755,6 @@ mainloop(session_t *ps, bool activate_on_start) { mw->clientondesktop = 0; if (refocus && mw->revert_focus_win) { - // printfef("(): if (refocus && mw->revert_focus_win) {"); - // printfef("(): wm_activate_window(ps, mw->revert_focus_win);"); // No idea why. Plain XSetInputFocus() no longer works after ungrabbing. wm_activate_window(ps, mw->revert_focus_win); refocus = false; @@ -829,7 +824,6 @@ mainloop(session_t *ps, bool activate_on_start) { ev_dump(ps, mw, &ev); #endif Window wid = ev_window(ps, &ev); -//printfdf("(): Event!); if (mw && MotionNotify == ev.type) { @@ -868,17 +862,17 @@ mainloop(session_t *ps, bool activate_on_start) { ev.xmotion.x_root, ev.xmotion.y_root); } else if (mw && ev.type == DestroyNotify) { - // printfef("(): else if (ev.type == DestroyNotify) {"); + printfdf(false, "(): else if (ev.type == DestroyNotify) {"); daemon_count_clients(ps->mainwin, 0, None); if (!mw->clientondesktop) { - printfef("(): Last client window destroyed/unmapped, " + printfdf(false, "(): Last client window destroyed/unmapped, " "exiting."); die = true; mw->client_to_focus = NULL; } } else if (ev.type == MapNotify || ev.type == UnmapNotify) { - // printfef("(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); + printfdf(false, "(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); daemon_count_clients(ps->mainwin, 0, None); dlist *iter = (wid ? dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { @@ -888,8 +882,7 @@ mainloop(session_t *ps, bool activate_on_start) { } } else if (mw && (ps->xinfo.damage_ev_base + XDamageNotify == ev.type)) { - //printfef("(): else if (ev.type == XDamageNotify) {"); - // XDamageNotifyEvent *d_ev = (XDamageNotifyEvent *) &ev; + //printfdf(false, "(): else if (ev.type == XDamageNotify) {"); dlist *iter = dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid); pending_damage = true; @@ -900,18 +893,12 @@ mainloop(session_t *ps, bool activate_on_start) { else if (mw && wid == mw->window) die = mainwin_handle(mw, &ev); else if (mw && PropertyNotify == ev.type) { - printfef("(): else if (ev.type == PropertyNotify) {"); - - // printfef("(): else if (PropertyNotify == ev.type) {"); + printfdf(false, "(): else if (ev.type == PropertyNotify) {"); if (!ps->o.background && (ESETROOT_PMAP_ID == ev.xproperty.atom || _XROOTPMAP_ID == ev.xproperty.atom)) { - // printfef("(): if (!ps->o.background && ..."); - // printfef("(): mainwin_update_background(mw);"); - // printfef("(): REDUCE(clientwin_render((ClientWin *)iter->data), mw->clientondesktop);"); - mainwin_update_background(mw); REDUCE(clientwin_render((ClientWin *)iter->data), mw->clientondesktop); } @@ -924,8 +911,6 @@ mainloop(session_t *ps, bool activate_on_start) { if (cw->mini.window == wid) { if (!(POLLIN & r_fd[1].revents)) { - // we handle key events in here - // printfef("(): die = clientwin_handle(cw, &ev);"); die = clientwin_handle(cw, &ev); } break; @@ -936,14 +921,12 @@ mainloop(session_t *ps, bool activate_on_start) { // Do delayed painting if it's active if (mw && pending_damage && !die) { - //printfdf("(): delayed painting"); + //printfdf(false, "(): delayed painting"); pending_damage = false; foreach_dlist(mw->clientondesktop) { if (((ClientWin *) iter->data)->damaged) { - // printfef("(): if (((ClientWin *) iter->data)->damaged)"); clientwin_repair(iter->data); - // fputs("\n", stdout); } } last_rendered = time_in_millis(); @@ -962,16 +945,16 @@ mainloop(session_t *ps, bool activate_on_start) { unsigned char piped_input = 0; int read_ret = read(ps->fd_pipe, &piped_input, 1); if (0 == read_ret) { - printfdf("(): EOF reached on pipe \"%s\".", ps->o.pipePath); + printfdf(false, "(): EOF reached on pipe \"%s\".", ps->o.pipePath); open_pipe(ps, r_fd); } else if (-1 == read_ret) { if (EAGAIN != errno) - printfef("(): Reading pipe \"%s\" failed: %d", ps->o.pipePath, errno); + printfdf(false, "(): Reading pipe \"%s\" failed: %d", ps->o.pipePath, errno); } else { assert(1 == read_ret); - printfdf("(): Received pipe command: %d", piped_input); + printfdf(false, "(): Received pipe command: %d", piped_input); switch (piped_input) { case PIPECMD_RELOAD_CONFIG: @@ -982,10 +965,10 @@ mainloop(session_t *ps, bool activate_on_start) { case PIPECMD_ACTIVATE_PAGING: paging = piped_input == PIPECMD_ACTIVATE_PAGING; ps->o.mode = paging? PROGMODE_ACTV_PAGING: PROGMODE_ACTV_EXPOSE; - printfef("(): case PIPECMD_ACTIVATE, paging=%d:", paging); + printfdf(false, "(): case PIPECMD_ACTIVATE, paging=%d:", paging); if (ps->mainwin->mapped) { - printfef("(): if (ps->mainwin->mapped)"); + printfdf(false, "(): if (ps->mainwin->mapped)"); fflush(stdout);fflush(stderr); // There is a glitch whereby calling focus_miniw_prev() or focus_miniw_next() @@ -998,20 +981,20 @@ mainloop(session_t *ps, bool activate_on_start) { if (ps->o.focus_initial == FI_PREV) { - printfef("(): focus_miniw_prev(ps, mw->client_to_focus);"); + printfdf(false, "(): focus_miniw_prev(ps, mw->client_to_focus);"); focus_miniw_prev(ps, mw->client_to_focus); } else if (ps->o.focus_initial == FI_NEXT) { - printfef("(): focus_miniw_next(ps, mw->client_to_focus);"); + printfdf(false, "(): focus_miniw_next(ps, mw->client_to_focus);"); focus_miniw_next(ps, mw->client_to_focus); } clientwin_render(mw->client_to_focus); } else { - printfef("(): activate = true;"); + printfdf(false, "(): activate = true;"); animating = activate = true; } break; @@ -1030,7 +1013,7 @@ mainloop(session_t *ps, bool activate_on_start) { } break; case PIPECMD_EXIT_DAEMON: - printfdf("(): Exit command received, killing daemon..."); + printfdf(false, "(): Exit command received, killing daemon..."); unlink(ps->o.pipePath); return; case PIPECMD_QUEUE_FI_PREV: @@ -1040,14 +1023,14 @@ mainloop(session_t *ps, bool activate_on_start) { ps->o.focus_initial = FI_NEXT; break; default: - printfdf("(): Unknown daemon command \"%d\" received.", piped_input); + printfdf(false, "(): Unknown daemon command \"%d\" received.", piped_input); break; } } } if (POLLHUP & r_fd[1].revents) { - printfdf("(): PIPEHUP on pipe \"%s\".", ps->o.pipePath); + printfdf(false, "(): PIPEHUP on pipe \"%s\".", ps->o.pipePath); open_pipe(ps, r_fd); } } @@ -1058,7 +1041,7 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { { int access_ret = 0; if ((access_ret = access(pipePath, W_OK))) { - printfef("(): Failed to access() pipe \"%s\": %d", pipePath, access_ret); + printfef(true, "(): Failed to access() pipe \"%s\": %d", pipePath, access_ret); perror("access"); exit(1); } @@ -1066,7 +1049,7 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { FILE *fp = fopen(pipePath, "w"); - printfdf("(): Sending command..."); + printfdf(false, "(): Sending command..."); fputc(command, fp); fclose(fp); @@ -1076,55 +1059,55 @@ send_command_to_daemon_via_fifo(int command, const char *pipePath) { static inline bool queue_reload_config(const char *pipePath) { - printfdf("(): Reload config file..."); + printfdf(false, "(): Reload config file..."); return send_command_to_daemon_via_fifo(PIPECMD_RELOAD_CONFIG, pipePath); } static inline bool queue_initial_focus_prev(const char *pipePath) { - printfdf("(): Set initial focus to previous selection..."); + printfdf(false, "(): Set initial focus to previous selection..."); return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_PREV, pipePath); } static inline bool queue_initial_focus_next(const char *pipePath) { - printfdf("(): Set initial focus to next selection..."); + printfdf(false, "(): Set initial focus to next selection..."); return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_NEXT, pipePath); } static inline bool activate_expose(const char *pipePath) { - printfdf("(): Activating expose..."); + printfdf(false, "(): Activating expose..."); return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_EXPOSE, pipePath); } static inline bool activate_paging(const char *pipePath) { - printfdf("(): Activating paging..."); + printfdf(false, "(): Activating paging..."); return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_PAGING, pipePath); } static inline bool exit_daemon(const char *pipePath) { - printfdf("(): Killing daemon..."); + printfdf(false, "(): Killing daemon..."); return send_command_to_daemon_via_fifo(PIPECMD_EXIT_DAEMON, pipePath); } static inline bool deactivate(const char *pipePath) { - printfdf("(): Deactivating..."); + printfdf(false, "(): Deactivating..."); return send_command_to_daemon_via_fifo(PIPECMD_DEACTIVATE, pipePath); } static inline bool toggle_expose(const char *pipePath) { - printfdf("(): Toggling expose..."); + printfdf(false, "(): Toggling expose..."); return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_EXPOSE, pipePath); } static inline bool toggle_paging(const char *pipePath) { - printfdf("(): Toggling paging..."); + printfdf(false, "(): Toggling paging..."); return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_PAGING, pipePath); } @@ -1185,7 +1168,7 @@ xerror(Display *dpy, XErrorEvent *ev) { { char buf[BUF_LEN] = ""; XGetErrorText(ps->dpy, ev->error_code, buf, BUF_LEN); - printfef("error %d (%s) request %d minor %d serial %lu (\"%s\")\n", + printfef(false, "error %d (%s) request %d minor %d serial %lu (\"%s\")", ev->error_code, name, ev->request_code, ev->minor_code, ev->serial, buf); } @@ -1217,7 +1200,7 @@ show_help() { // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" - " -S - Synchronize X operation (debugging).\n" + " --debug - enable debugging logs.\n" , stdout); #ifdef CFG_LIBPNG spng_about(stdout); @@ -1256,32 +1239,32 @@ init_xexts(session_t *ps) { ps->xinfo.xinerama_exist = XineramaQueryExtension(dpy, &ps->xinfo.xinerama_ev_base, &ps->xinfo.xinerama_err_base); # ifdef DEBUG_XINERAMA - printfef("(): Xinerama extension: %s", + printfef(true, "(): Xinerama extension: %s", (ps->xinfo.xinerama_exist ? "yes": "no")); # endif /* DEBUG_XINERAMA */ #endif /* CFG_XINERAMA */ if(!XDamageQueryExtension(dpy, &ps->xinfo.damage_ev_base, &ps->xinfo.damage_err_base)) { - printfef("(): FATAL: XDamage extension not found."); + printfef(true, "(): FATAL: XDamage extension not found."); return false; } if(!XCompositeQueryExtension(dpy, &ps->xinfo.composite_ev_base, &ps->xinfo.composite_err_base)) { - printfef("(): FATAL: XComposite extension not found."); + printfef(true, "(): FATAL: XComposite extension not found."); return false; } if(!XRenderQueryExtension(dpy, &ps->xinfo.render_ev_base, &ps->xinfo.render_err_base)) { - printfef("(): FATAL: XRender extension not found."); + printfef(true, "(): FATAL: XRender extension not found."); return false; } if(!XFixesQueryExtension(dpy, &ps->xinfo.fixes_ev_base, &ps->xinfo.fixes_err_base)) { - printfef("(): FATAL: XFixes extension not found."); + printfef(true, "(): FATAL: XFixes extension not found."); return false; } @@ -1411,13 +1394,14 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { break; case OPT_PREV: ps->o.focus_initial = FI_PREV; - // fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + printfdf(false, "ps->o.focus_initial=%i\n", ps->o.focus_initial); break; case OPT_NEXT: ps->o.focus_initial = FI_NEXT; - // fprintf(stdout, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + printfdf(false, "ps->o.focus_initial=%i\n", ps->o.focus_initial); break; - T_CASEBOOL('S', synchronize); + case 'S': + debuglog = true; // case 't': // developer_tests(); // exit('t' == o ? RET_SUCCESS: RET_BADARG); @@ -1463,7 +1447,7 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_NEXT: break; #undef T_CASEBOOL default: - printfef("(0): Unimplemented option %d.", o); + printfef(false, "(0): Unimplemented option %d.", o); exit(RET_UNKNOWN); } } @@ -1480,7 +1464,7 @@ load_config_file(session_t *ps) if (ps->o.config_path) config = config_load(ps->o.config_path); else - printfef("(): WARNING: No configuration file found."); + printfef(true, "(): WARNING: No configuration file found."); if (!config && user_specified_config) return 1; } @@ -1562,6 +1546,8 @@ load_config_file(session_t *ps) ps->o.layout = LAYOUT_BOXY; } } + else + ps->o.layout = LAYOUT_BOXY; } config_get_bool_wrap(config, "general", "sortByColumn", &ps->o.sortByColumn); config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); @@ -1639,6 +1625,9 @@ load_config_file(session_t *ps) ps->o.background = p; free_pictspec(ps, &spec); } + else { + ps->o.background = None; + } } if (!parse_pictspec(ps, config_get(config, "general", "iconFillSpec", "orig mid mid #FFFFFF"), &ps->o.iconFillSpec) || !parse_pictspec(ps, config_get(config, "general", "fillSpec", "orig mid mid #FFFFFF"), &ps->o.fillSpec)) @@ -1679,7 +1668,7 @@ int main(int argc, char *argv[]) { // Open connection to X if (!(ps->dpy = dpy = XOpenDisplay(NULL))) { - printfef("(): FATAL: Couldn't connect to display."); + printfef(true, "(): FATAL: Couldn't connect to display."); ret = RET_XFAIL; goto main_end; } @@ -1687,7 +1676,7 @@ int main(int argc, char *argv[]) { ret = RET_XFAIL; goto main_end; } - if (ps->o.synchronize) + if (debuglog) XSynchronize(ps->dpy, True); XSetErrorHandler(xerror); @@ -1703,7 +1692,7 @@ int main(int argc, char *argv[]) { // Second pass parse_args(ps, argc, argv, false); - // fprintf(stdout, "after 2nd pass: ps->o.focus_initial = %i\n", ps->o.focus_initial); + printfdf(false, "(): after 2nd pass: ps->o.focus_initial = %i", ps->o.focus_initial); const char* pipePath = ps->o.pipePath; @@ -1765,7 +1754,7 @@ int main(int argc, char *argv[]) { // Main branch MainWin *mw = mainwin_create(ps); if (!mw) { - printfef("(): FATAL: Couldn't create main window."); + printfef(true, "(): FATAL: Couldn't create main window."); ret = 1; goto main_end; } @@ -1777,7 +1766,7 @@ int main(int argc, char *argv[]) { if (ps->o.runAsDaemon) { bool flush_file = false; - printfdf("(): Running as daemon..."); + printfdf(false, "(): Running as daemon..."); // Flush file if we could access() it (or, usually, if it exists) if (!access(pipePath, R_OK)) @@ -1786,7 +1775,7 @@ int main(int argc, char *argv[]) { { int result = mkfifo(pipePath, S_IRUSR | S_IWUSR); if (result < 0 && EEXIST != errno) { - printfef("(): Failed to create named pipe \"%s\": %d", pipePath, result); + printfef(true, "(): Failed to create named pipe \"%s\": %d", pipePath, result); perror("mkfifo"); ret = 2; goto main_end; @@ -1803,7 +1792,7 @@ int main(int argc, char *argv[]) { char *buf[BUF_LEN]; while (read(ps->fd_pipe, buf, sizeof(buf)) > 0) continue; - printfdf("(): Finished flushing pipe \"%s\".", pipePath); + printfdf(false, "(): Finished flushing pipe \"%s\".", pipePath); } daemon_count_clients(mw, 0, None); @@ -1816,7 +1805,7 @@ int main(int argc, char *argv[]) { mainloop(ps, false); } else { - printfdf("(): running once then quitting..."); + printfdf(false, "(): running once then quitting..."); mainloop(ps, true); } diff --git a/src/skippy.h b/src/skippy.h index d4c6e26..e2e69ad 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -65,40 +65,7 @@ #define MAX_MOUSE_BUTTONS 4 -/** - * @brief Dump raw bytes in HEX format. - * - * @param data pointer to raw data - * @param len length of data - */ -static inline void -hexdump(const char *data, int len) { - static const int BYTE_PER_LN = 16; - - if (len <= 0) - return; - - // Print header - printf("%10s:", "Offset"); - for (int i = 0; i < BYTE_PER_LN; ++i) - printf(" %2d", i); - putchar('\n'); - - // Dump content - for (int offset = 0; offset < len; ++offset) { - if (!(offset % BYTE_PER_LN)) - printf("0x%08x:", offset); - - printf(" %02hhx", data[offset]); - - if ((BYTE_PER_LN - 1) == offset % BYTE_PER_LN) - putchar('\n'); - } - if (len % BYTE_PER_LN) - putchar('\n'); - - fflush(stdout); -} +extern bool debuglog; /// @brief Possible return values. @@ -217,7 +184,6 @@ typedef struct { char *config_path; enum progmode mode; bool runAsDaemon; - bool synchronize; int focus_initial; int layout; @@ -292,7 +258,6 @@ typedef struct { .config_path = NULL, \ .mode = PROGMODE_NORMAL, \ .runAsDaemon = false, \ - .synchronize = false, \ \ .layout = LAYOUT_XD, \ .sortByColumn = true, \ @@ -398,21 +363,13 @@ typedef struct { .fd_pipe = -1, \ } -/// @brief Print out a debug message. -#define printfd(format, ...) \ - (fprintf(stdout, format "\n", ## __VA_ARGS__), fflush(stdout)) - /// @brief Print out a debug message with function name. -#define printfdf(format, ...) \ - (fprintf(stdout, "%s" format "\n", __func__, ## __VA_ARGS__), fflush(stdout)) - -/// @brief Print out an error message. -#define printfe(format, ...) \ - (fprintf(stderr, format "\n", ## __VA_ARGS__), fflush(stderr)) +#define printfdf(alwaysprint, format, ...) \ + ((alwaysprint) || (debuglog))? fprintf(stdout, "%s" format "\n", __func__, ## __VA_ARGS__):true; /// @brief Print out an error message with function name. -#define printfef(format, ...) \ - printfe("%s" format, __func__, ## __VA_ARGS__) +#define printfef(alwaysprint, format, ...) \ + ((alwaysprint) || (debuglog))? fprintf(stderr, "%s" format "\n", __func__, ## __VA_ARGS__):true; /// @brief Return a value if it's true. #define retif(x) do { if (x) return (x); } while (0) @@ -428,7 +385,7 @@ typedef struct { static inline void * allocchk_(void *ptr, const char *func_name) { if (unlikely(!ptr)) { - printfe("%s(): Failed to allocate memory.", func_name); + printfef(true, "%s(): Failed to allocate memory.", func_name); exit(RET_BADALLOC); } @@ -523,7 +480,7 @@ print_timestamp(session_t *ps) { timeval_subtract(&diff, &tm, &ps->time_start); - printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000); + printfef(false, "[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000); } /** @@ -885,7 +842,7 @@ check_keysyms(const char *str_err_prefix1, const char *str_err_prefix2, const ch KeySym keysym = key_str_sym(word); if (!keysym) - printfef("(): %s%s \"%s\" was not recognized as a valid KeySym. Run the program 'xev' to find the correct value.", str_err_prefix1, str_err_prefix2, word); + printfef(true, "(): %s%s \"%s\" was not recognized as a valid KeySym. Run the program 'xev' to find the correct value.", str_err_prefix1, str_err_prefix2, word); free(word); } @@ -985,7 +942,7 @@ keysyms_arr_keycodes(Display *display, KeySym *keysyms, KeyCode **dest) for (int i = 0; i < num_keysyms; i++) { arr_keycodes[i] = XKeysymToKeycode(display, keysyms[i]); - // fprintf(stdout, "i=%i, keysym=%i, keycode=(0x%02lx)\n", i, keysyms[i], arr_keycodes[i]); + printfdf(false, "(): i=%i, keysym=%lu, keycode=(0x%02i)", i, keysyms[i], arr_keycodes[i]); count++; } // fputs("\n", stdout); fflush(stdout); @@ -1096,9 +1053,8 @@ check_keybindings_conflict(const char *config_path, const char *arr1_str, KeySym for (int i = 0; i < num_conflicts; i++) { KeySym keysym = conflicts[i]; - printfef("(): %s: [bindings] Conflict detected. Remove the duplicate setting. Keybinding: '%s' found in both '%s' and '%s'.", config_path, XKeysymToString(keysym), arr1_str, arr2_str); - // fprintf(stdout, "%s (0x%02lx)\n", XKeysymToString(keysym), keysym); - // fputs("\n", stdout); + printfdf(true, "(): %s: [bindings] Conflict detected. Remove the duplicate setting. Keybinding: '%s' found in both '%s' and '%s'.", config_path, XKeysymToString(keysym), arr1_str, arr2_str); + printfdf(true, "%s (0x%02lx)\n", XKeysymToString(keysym), keysym); } free(conflicts); return true; @@ -1108,15 +1064,15 @@ check_keybindings_conflict(const char *config_path, const char *arr1_str, KeySym } #define report_key(ev) \ - printfef("(): Key %u (%s) occured.", (ev)->xkey.keycode, \ + printfdf(false, "(): Key %u (%s) occured.", (ev)->xkey.keycode, \ ev_key_str(&(ev)->xkey)) #define report_key_ignored(ev) \ - printfef("(): KeyRelease %u (%s) ignored.", (ev)->xkey.keycode, \ + printfdf(false, "(): KeyRelease %u (%s) ignored.", (ev)->xkey.keycode, \ ev_key_str(&(ev)->xkey)) #define report_key_unbinded(ev) \ - printfef("(): KeyRelease %u (%s) not binded to anything.", \ + printfdf(false, "(): KeyRelease %u (%s) not binded to anything.", \ (ev)->xkey.keycode, ev_key_str(&(ev)->xkey)) @@ -1230,10 +1186,10 @@ check_modmasks(const char *str_err_prefix1, const char *str_err_prefix2, const c break; int modkeymask = str_key_modifier_int(word); - // fprintf(stdout, "%s %i (0x%02lx)\n", word, modkeymask, modkeymask); + printfdf(false, "(): %s %i (0x%02i)", word, modkeymask, modkeymask); if (!modkeymask) - printfef("(): %s%s \"%s\" not recognized as a Modifier Key Mask. See: /usr/include/X11/X.h", str_err_prefix1, str_err_prefix2, word); + printfef(true, "(): %s%s \"%s\" not recognized as a Modifier Key Mask. See: /usr/include/X11/X.h", str_err_prefix1, str_err_prefix2, word); free(word); } @@ -1275,7 +1231,7 @@ modkeymasks_str_enums(const char *s, int** dest) break; int modkeymask = str_key_modifier_int(word); - // fprintf(stdout, "%s %i (0x%02lx)\n", word, modkeymask, modkeymask); + printfdf(false, "(): %s %i (0x%02i)", word, modkeymask, modkeymask); // only increment the array counter if the modifier key mask is valid if(modkeymask) @@ -1316,22 +1272,20 @@ arr_modkeymasks_includes(int *arr_modkeymasks, int modkeymask) /** * @brief Print a log message if the keyboard event has a modifier key held down */ -static inline int +static inline void report_key_modifiers(XKeyEvent *evk) { // fputs("report_key_modifiers(XKeyEvent *evk)\n", stdout); - if (!evk) return 0; + if (!evk) return; - int result = 0; int i = 0; while (ev_modifier_mask[i]) { if (evk->state & ev_modifier_mask[i]) - result = printfef("(): Key modifier (%s) is held for key (%s).", ev_modifier_mask_str[i], ev_key_str(evk)); + printfdf(false,"(): Key modifier (%s) is held for key (%s).", ev_modifier_mask_str[i], ev_key_str(evk)); i++; } // fputs("\n", stdout); - return result; } #include "img.h" diff --git a/src/tooltip.c b/src/tooltip.c index b63b9d6..7ba3c12 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -88,7 +88,7 @@ tooltip_create(MainWin *mw) { } if (!tt->window) { - printfef("(): WARNING: Couldn't create tooltip window."); + printfef(false, "(): WARNING: Couldn't create tooltip window."); tooltip_destroy(tt); return 0; } @@ -97,7 +97,7 @@ tooltip_create(MainWin *mw) { tmp = ps->o.tooltip_border; if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->border)) { - fprintf(stderr, "WARNING: Invalid color '%s'.\n", tmp); + printfef(false, "WARNING: Invalid color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -105,7 +105,7 @@ tooltip_create(MainWin *mw) { tmp = ps->o.tooltip_background; if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->background)) { - fprintf(stderr, "WARNING: Invalid color '%s'.\n", tmp); + printfef(false, "WARNING: Invalid color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -117,7 +117,7 @@ tooltip_create(MainWin *mw) { tmp = ps->o.tooltip_text; if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->color)) { - fprintf(stderr, "WARNING: Couldn't allocate color '%s'.\n", tmp); + printfef(false, "WARNING: Couldn't allocate color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -127,7 +127,7 @@ tooltip_create(MainWin *mw) { { if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->shadow)) { - fprintf(stderr, "WARNING: Couldn't allocate color '%s'.\n", tmp); + printfef(false, "WARNING: Couldn't allocate color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -136,7 +136,7 @@ tooltip_create(MainWin *mw) { tt->draw = XftDrawCreate(ps->dpy, tt->window, mw->visual, mw->colormap); if(! tt->draw) { - fprintf(stderr, "WARNING: Couldn't create Xft draw surface.\n"); + printfef(false, "WARNING: Couldn't create Xft draw surface.\n"); tooltip_destroy(tt); return 0; } @@ -144,7 +144,7 @@ tooltip_create(MainWin *mw) { tt->font = XftFontOpenName(ps->dpy, ps->screen, ps->o.tooltip_font); if(! tt->font) { - fprintf(stderr, "WARNING: Couldn't open Xft font.\n"); + printfef(false, "WARNING: Couldn't open Xft font.\n"); tooltip_destroy(tt); return 0; } @@ -204,8 +204,6 @@ tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y) { - // printfdf("(): x=%i y=%i",mouse_x,mouse_y); - session_t *ps = tt->mainwin->ps; int x = ps->o.tooltip_offsetX, y = ps->o.tooltip_offsetY; if (ps->o.tooltip_followsMouse) { diff --git a/src/wm.c b/src/wm.c index 612a4e6..191b18c 100644 --- a/src/wm.c +++ b/src/wm.c @@ -347,14 +347,14 @@ wm_get_stack_sub(session_t *ps, Window root) { // EWMH l = wm_get_stack_fromprop(ps, root, _NET_CLIENT_LIST); if (l) { - //printfef("(): Retrieved window stack from _NET_CLIENT_LIST."); + printfdf(false, "(): Retrieved window stack from _NET_CLIENT_LIST."); return l; } // GNOME WM l = wm_get_stack_fromprop(ps, root, _WIN_CLIENT_LIST); if (l) { - //printfef("(): Retrieved window stack from _WIN_CLIENT_LIST."); + printfdf(false, "(): Retrieved window stack from _WIN_CLIENT_LIST."); return l; } } @@ -384,7 +384,7 @@ wm_get_stack_sub(session_t *ps, Window root) { } } sxfree(children); - //printfef("(): Retrieved window stack by querying all children."); + printfdf(false, "(): Retrieved window stack by querying all children."); } return l; @@ -502,7 +502,7 @@ wm_get_window_title(session_t *ps, Window wid, int *length_return) { } void -printfefWindowName(session_t *ps, char *prefix_str, Window wid) +printfdfWindowName(session_t *ps, char *prefix_str, Window wid) { int win_title_len = 0; FcChar8 *win_title = wm_get_window_title(ps, wid, &win_title_len); @@ -510,11 +510,13 @@ printfefWindowName(session_t *ps, char *prefix_str, Window wid) if (! win_title) return; - if (prefix_str) - printfef("%s%s", prefix_str, win_title); + if (prefix_str) { + printfdf(false, "%s%s", prefix_str, win_title); + } - else - printfef("%s", win_title); + else { + printfdf(false, "%s", win_title); + } free(win_title); } @@ -673,10 +675,10 @@ wm_get_focused(session_t *ps) { { int revert_to = 0; if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { - printfef("(): Failed to get current focused window."); + printfdf(false, "(): Failed to get current focused window."); return None; } - // printfdf("(): Focused window is %#010lx.", focused); + printfdf(false, "(): Focused window is %#010lx.", focused); } while (focused) { @@ -698,10 +700,10 @@ wm_get_focused(session_t *ps) { XQueryTree(ps->dpy, focused, &rroot, &parent, &children, &nchildren); sxfree(children); if (!status) { - printfef("(): Failed to get parent window of %#010lx.", focused); + printfef(false, "(): Failed to get parent window of %#010lx.", focused); return None; } - // printfdf("(): Parent window of %#010lx is %#010lx.", focused, parent); + printfdf(false, "(): Parent window of %#010lx is %#010lx.", focused, parent); focused = parent; assert(ps->root == rroot); } diff --git a/src/wm.h b/src/wm.h index 11d2e40..e3752ef 100644 --- a/src/wm.h +++ b/src/wm.h @@ -67,15 +67,15 @@ static inline bool wm_check(session_t *ps) { if (wm_check_netwm(ps)) { ps->wmpsn = WMPSN_EWMH; - printfdf("(): Your WM looks EWMH compliant."); + printfdf(true, "(): Your WM looks EWMH compliant."); return true; } if (wm_check_gnome(ps)) { ps->wmpsn = WMPSN_GNOME; - printfdf("(): Your WM looks GNOME compliant."); + printfdf(true, "(): Your WM looks GNOME compliant."); return true; } - printfef("(): Your WM is neither EWMH nor GNOME WM compliant. " + printfdf(true, "(): Your WM is neither EWMH nor GNOME WM compliant. " "Troubles ahead."); return false; } @@ -85,7 +85,7 @@ Pixmap wm_get_root_pmap(Display *dpy); unsigned long wm_get_desktops(session_t *ps); long wm_get_current_desktop(session_t *ps); FcChar8 *wm_get_window_title(session_t *ps, Window wid, int *length_return); -void printfefWindowName(session_t *ps, char *prefix_str, Window wid); +void printfdfWindowName(session_t *ps, char *prefix_str, Window wid); Window wm_get_group_leader(Display *dpy, Window window); void wm_set_fullscreen(session_t *ps, Window window, int x, int y, unsigned width, unsigned height); From 36da64ac3a04f62c05a563f3ac810f2ca3a520d3 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 5 Apr 2023 21:37:45 -0700 Subject: [PATCH 115/205] Correct debug flag --- src/skippy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 366f931..c4ab602 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -26,7 +26,7 @@ #include #include -bool debuglog = true; +bool debuglog = false; enum pipe_cmd_t { // Not ordered properly for backward compatibility @@ -1402,6 +1402,7 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { break; case 'S': debuglog = true; + break; // case 't': // developer_tests(); // exit('t' == o ? RET_SUCCESS: RET_BADARG); From 7d73b5cc92ae9b15aa9b12f649f1867209c1d58c Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 5 Apr 2023 22:03:33 -0700 Subject: [PATCH 116/205] Corrections --- src/clientwin.c | 2 +- src/config.c | 8 +++---- src/dlist.c | 2 +- src/focus.h | 4 ++-- src/img-gif.c | 22 +++++++++--------- src/img-jpeg.c | 8 +++---- src/img-png.c | 22 +++++++++--------- src/img-xlib.c | 12 +++++----- src/img.h | 26 +++++++++++----------- src/mainwin.c | 14 ++++++------ src/skippy.c | 59 ++++++++++++++++++++++++++----------------------- src/skippy.h | 2 +- src/tooltip.c | 12 +++++----- src/wm.c | 4 ++-- 14 files changed, 100 insertions(+), 97 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 8ec24f0..8b9d609 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -243,7 +243,7 @@ clientwin_update(ClientWin *cw) { // if we ever got a thumbnail for the window, // the mode for that window always will be thumbnail cw->mode = clientwin_get_disp_mode(ps, cw, isViewable); - printfdf(false, "(%#010lx): %d", cw->wid_client, cw->mode); + printfdf(false, "(): (%#010lx): %d", cw->wid_client, cw->mode); return true; } diff --git a/src/config.c b/src/config.c index e0574e0..2b6a650 100644 --- a/src/config.c +++ b/src/config.c @@ -93,7 +93,7 @@ config_parse(const char *config) { *value = copy_match(line, &matches[2]); new_config = entry_set(new_config, section, key, value); } else { - printfef(true, "WARNING: Ignoring invalid line: %s\n", line); + printfef(true, "(): WARNING: Ignoring invalid line: %s\n", line); } l_ix = 0; } else { @@ -125,7 +125,7 @@ config_load(const char *path) if(! fin) { - printfef(true, "WARNING: Couldn't load config file '%s'.\n", path); + printfef(true, "(): WARNING: Couldn't load config file '%s'.\n", path); return 0; } else @@ -138,7 +138,7 @@ config_load(const char *path) if(! flen) { - printfef(true, "WARNING: '%s' is empty.\n", path); + printfef(true, "(): WARNING: '%s' is empty.\n", path); fclose(fin); return 0; } @@ -149,7 +149,7 @@ config_load(const char *path) data[flen] = '\0'; if(fread(data, 1, flen, fin) != flen) { - printfef(true, "WARNING: Couldn't read from config file '%s'.\n", path); + printfef(true, "(): WARNING: Couldn't read from config file '%s'.\n", path); free(data); fclose(fin); return 0; diff --git a/src/dlist.c b/src/dlist.c index 2698c06..3a2662e 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -141,7 +141,7 @@ dlist_insert_nth(dlist *l, dlist *new_elem, unsigned int n) else { // there is no nth element - printfef(false, "(%p,%p,%i): list has fewer than %i elements. appending as the last element.", l, new_elem, n, n); + printfef(false, "(): (%p,%p,%i): list has fewer than %i elements. appending as the last element.", l, new_elem, n, n); first_elem = dlist_insert_after( dlist_last(l), new_elem); } diff --git a/src/focus.h b/src/focus.h index 72175d9..502af5c 100644 --- a/src/focus.h +++ b/src/focus.h @@ -132,7 +132,7 @@ static inline void focus_miniw_next(session_t *ps, ClientWin *cw) { dlist *e = dlist_find_data(cw->mainwin->focuslist, cw); if (!e) { - printfef(false, "(%#010lx): Client window not found in list.", cw->src.window); + printfef(false, "() (%#010lx): Client window not found in list.", cw->src.window); return; } if (e->next) @@ -160,7 +160,7 @@ focus_miniw_prev(session_t *ps, ClientWin *cw) { } if (!tgt) { - printfef(false, "(%#010lx): Client window not found in list.", cw->src.window); + printfef(false, "() (%#010lx): Client window not found in list.", cw->src.window); return; } diff --git a/src/img-gif.c b/src/img-gif.c index 6b852bb..0e2ac45 100644 --- a/src/img-gif.c +++ b/src/img-gif.c @@ -39,7 +39,7 @@ sgif_read(session_t *ps, const char *path) { #ifdef SGIF_THREADSAFE errstr = GifErrorString(err); #endif - printfef(false, "(\"%s\"): Failed to open file: %d (%s)", path, err, errstr); + printfef(false, "(): (\"%s\"): Failed to open file: %d (%s)", path, err, errstr); goto sgif_read_end; } @@ -51,29 +51,29 @@ sgif_read(session_t *ps, const char *path) { ++i; switch (rectype) { case UNDEFINED_RECORD_TYPE: - printfef(false, "(\"%s\"): %d: Encountered a record of unknown type.", + printfef(false, "(): (\"%s\"): %d: Encountered a record of unknown type.", path, i); break; case SCREEN_DESC_RECORD_TYPE: - printfef(false, "(\"%s\"): %d: Encountered a record of " + printfef(false, "(): (\"%s\"): %d: Encountered a record of " "ScreenDescRecordType. This shouldn't happen!", path, i); break; case IMAGE_DESC_RECORD_TYPE: if (data) { - printfef(false, "(\"%s\"): %d: Extra image section ignored.", + printfef(false, "(): (\"%s\"): %d: Extra image section ignored.", path, i); break; } if (GIF_ERROR == DGifGetImageDesc(f)) { - printfef(false, "(\"%s\"): %d: Failed to read GIF image info.", + printfef(false, "(): (\"%s\"): %d: Failed to read GIF image info.", path, i); break; } width = f->Image.Width; height = f->Image.Height; if (width <= 0 || height <= 0) { - printfef(false, "(\"%s\"): %d: Width/height invalid.", path, i); + printfef(false, "(): (\"%s\"): %d: Width/height invalid.", path, i); break; } assert(!data); @@ -81,7 +81,7 @@ sgif_read(session_t *ps, const char *path) { // FIXME: Interlace images may need special treatments for (int j = 0; j < height; ++j) if (GIF_OK != DGifGetLine(f, &data[j * width], width)) { - printfef(false, "(\"%s\"): %d: Failed to read line %d.", path, i, j); + printfef(false, "(): (\"%s\"): %d: Failed to read line %d.", path, i, j); goto sgif_read_end; } break; @@ -90,7 +90,7 @@ sgif_read(session_t *ps, const char *path) { int code = 0; GifByteType *pbytes = NULL; if (GIF_OK != DGifGetExtension(f, &code, &pbytes) || !pbytes) { - printfef(false, "(\"%s\"): %d: Failed to read extension block.", + printfef(false, "(): (\"%s\"): %d: Failed to read extension block.", path, i); break; } @@ -107,7 +107,7 @@ sgif_read(session_t *ps, const char *path) { } } if (unlikely(!data)) { - printfef(false, "(\"%s\"): No valid data found.", path); + printfef(false, "(): (\"%s\"): No valid data found.", path); goto sgif_read_end; } } @@ -118,7 +118,7 @@ sgif_read(session_t *ps, const char *path) { ColorMapObject *cmap = f->Image.ColorMap; if (!cmap) cmap = f->SColorMap; if (unlikely(!cmap)) { - printfef(false, "(\"%s\"): No colormap found.", path); + printfef(false, "(): (\"%s\"): No colormap found.", path); goto sgif_read_end; } tdata = allocchk(malloc(width * height * depth / 8)); @@ -143,7 +143,7 @@ sgif_read(session_t *ps, const char *path) { pictw = simg_data_to_pictw(ps, width, height, depth, tdata, 0); free(tdata); if (unlikely(!pictw)) { - printfef(false, "(\"%s\"): Failed to create Picture.", path); + printfef(false, "(): (\"%s\"): Failed to create Picture.", path); goto sgif_read_end; } diff --git a/src/img-jpeg.c b/src/img-jpeg.c index 323cca9..19f8b98 100644 --- a/src/img-jpeg.c +++ b/src/img-jpeg.c @@ -14,7 +14,7 @@ sjpg_read(session_t *ps, const char *path) { FILE *fp = fopen(path, "rb"); if (unlikely(!fp)) { - printfef(false, "(\"%s\"): Failed to open file.", path); + printfef(false, "(): (\"%s\"): Failed to open file.", path); goto sjpg_read_end; } jpeg_stdio_src(&cinfo, fp); @@ -35,7 +35,7 @@ sjpg_read(session_t *ps, const char *path) { while (cinfo.output_scanline < cinfo.output_height) { if (unlikely(!jpeg_read_scanlines(&cinfo, &rowptrs[cinfo.output_scanline], cinfo.output_height - cinfo.output_scanline))) { - printfef(false, "(\"%s\"): Failed to read scanline %d.", path, + printfef(false, "(): (\"%s\"): Failed to read scanline %d.", path, cinfo.output_scanline); goto sjpg_read_end; } @@ -60,14 +60,14 @@ sjpg_read(session_t *ps, const char *path) { } } if (unlikely(!jpeg_finish_decompress(&cinfo))) { - printfef(false, "(\"%s\"): Failed to finish decompression.", path); + printfef(false, "(): (\"%s\"): Failed to finish decompression.", path); goto sjpg_read_end; } need_abort = false; pictw = simg_data_to_pictw(ps, width, height, depth, data, 0); free(data); if (unlikely(!pictw)) { - printfef(false, "(\"%s\"): Failed to create Picture.", path); + printfef(false, "(): (\"%s\"): Failed to create Picture.", path); goto sjpg_read_end; } diff --git a/src/img-png.c b/src/img-png.c index 859f86c..9f8b308 100644 --- a/src/img-png.c +++ b/src/img-png.c @@ -10,7 +10,7 @@ void spng_about(FILE *os) { - printfdf(true, "PNG support: Yes\n" + printfdf(true, "(): PNG support: Yes\n" " Compiled with libpng %s, using %s.\n" " Compiled with zlib %s, using %s.\n", PNG_LIBPNG_VER_STRING, png_libpng_ver, @@ -28,16 +28,16 @@ spng_read(session_t *ps, const char *path) { FILE *fp = fopen(path, "rb"); bool need_premultiply = false; if (unlikely(!fp)) { - printfef(false, "(\"%s\"): Failed to open file.", path); + printfef(false, "(): (\"%s\"): Failed to open file.", path); goto spng_read_end; } if (unlikely(SPNG_SIGBYTES != fread(&sig, 1, SPNG_SIGBYTES, fp))) { - printfef(false, "(\"%s\"): Failed to read %d-byte signature.", + printfef(false, "(): (\"%s\"): Failed to read %d-byte signature.", path, SPNG_SIGBYTES); goto spng_read_end; } if (unlikely(png_sig_cmp((png_bytep) sig, 0, SPNG_SIGBYTES))) { - printfef(false, "(\"%s\"): PNG signature invalid.", path); + printfef(false, "(): (\"%s\"): PNG signature invalid.", path); goto spng_read_end; } png_ptr = allocchk(png_create_read_struct(PNG_LIBPNG_VER_STRING, @@ -59,7 +59,7 @@ spng_read(session_t *ps, const char *path) { // Scale or strip 16-bit colors if (bit_depth == 16) { - printfdf(false, "(\"%s\"): Scaling 16-bit colors.", path); + printfdf(false, "(): (\"%s\"): Scaling 16-bit colors.", path); #if PNG_LIBPNG_VER >= 10504 png_set_scale_16(png_ptr); #else @@ -76,19 +76,19 @@ spng_read(session_t *ps, const char *path) { // Convert palette to RGB if (color_type == PNG_COLOR_TYPE_PALETTE) { - printfdf(false, "(\"%s\"): Converting palette PNG to RGB.", path); + printfdf(false, "(): (\"%s\"): Converting palette PNG to RGB.", path); png_set_palette_to_rgb(png_ptr); color_type = PNG_COLOR_TYPE_RGB; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - printfdf(false, "(\"%s\"): Converting rDNS to full alpha.", path); + printfdf(false, "(): (\"%s\"): Converting rDNS to full alpha.", path); png_set_tRNS_to_alpha(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { - printfdf(false, "(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path); + printfdf(false, "(): (\"%s\"): Converting gray (+ alpha) PNG to RGB.", path); png_set_gray_to_rgb(png_ptr); if (PNG_COLOR_TYPE_GRAY == color_type) color_type = PNG_COLOR_TYPE_RGB; @@ -98,7 +98,7 @@ spng_read(session_t *ps, const char *path) { /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - printfdf(false, "(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path); + printfdf(false, "(): (\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path); #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8(png_ptr); #else @@ -110,7 +110,7 @@ spng_read(session_t *ps, const char *path) { // Somehow XImage requires 24-bit visual to use 32 bits per pixel if (color_type == PNG_COLOR_TYPE_RGB) { - printfdf(false, "(\"%s\"): Appending filler alpha values.", path); + printfdf(false, "(): (\"%s\"): Appending filler alpha values.", path); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } @@ -161,7 +161,7 @@ spng_read(session_t *ps, const char *path) { row_pointers[0], rowbytes); png_free(png_ptr, row_pointers[0]); if (unlikely(!pictw)) { - printfef(false, "(\"%s\"): Failed to create Picture.", path); + printfef(false, "(): (\"%s\"): Failed to create Picture.", path); goto spng_read_end; } } diff --git a/src/img-xlib.c b/src/img-xlib.c index bb153b9..63a2234 100644 --- a/src/img-xlib.c +++ b/src/img-xlib.c @@ -20,19 +20,19 @@ simg_load_icon(session_t *ps, Window wid, int desired_size) { int wanted_bytes = 0; for (const long *p = prop.data32; p < end; p += wanted_bytes) { if (p + 2 >= end) { - printfef(false, "(%#010lx): %d trailing byte(s).", wid, (int) (end - p)); + printfef(false, "() (%#010lx): %d trailing byte(s).", wid, (int) (end - p)); break; } width = p[0]; height = p[1]; if (width <= 0 || height <= 0) { - printfef(false, "(%#010lx): (offset %d, width %d, height %d) Invalid width/height.", + printfef(false, "() (%#010lx): (offset %d, width %d, height %d) Invalid width/height.", wid, (int) (p - prop.data32), width, height); break; } wanted_bytes = 2 + width * height; if ((end - p) < wanted_bytes) { - printfef(false, "(%#010lx): (offset %d, width %d, height %d) Not enough bytes (%d/%d).", + printfef(false, "() (%#010lx): (offset %d, width %d, height %d) Not enough bytes (%d/%d).", wid, (int) (p - prop.data32), width, height, (int) (end - p), wanted_bytes); break; } @@ -62,9 +62,9 @@ simg_load_icon(session_t *ps, Window wid, int desired_size) { free(converted_data); } if (!pictw) - printfef(false, "(%#010lx): Failed to create picture.", wid); + printfef(false, "() (%#010lx): Failed to create picture.", wid); /* if (pictw) - printfdf(false, "(%#010lx): (offset %d, width %d, height %d) Loaded.", + printfdf(false, "() (%#010lx): (offset %d, width %d, height %d) Loaded.", wid, (int) (best_data - prop.data8), pictw->width, pictw->height); */ } free_winprop(&prop); @@ -104,7 +104,7 @@ simg_load_icon(session_t *ps, Window wid, int desired_size) { if (pictw && !processed) { pictw = simg_postprocess(ps, pictw, PICTPOSP_SCALEK, desired_size, desired_size, ALIGN_MID, ALIGN_MID, NULL); - /* printfdf(false, "(%#010lx): (width %d, height %d) Processed.", + /* printfdf(false, "() (%#010lx): (width %d, height %d) Processed.", wid, pictw->width, pictw->height); */ } diff --git a/src/img.h b/src/img.h index 7040074..d52030f 100644 --- a/src/img.h +++ b/src/img.h @@ -115,7 +115,7 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, pictw_t *pictw = NULL; if (!pxmap) { - printfef(false, "(%d, %d, %d, %#010lx): Missing pixmap.", width, height, depth, pxmap); + printfef(false, "(): (%d, %d, %d, %#010lx): Missing pixmap.", width, height, depth, pxmap); return NULL; } @@ -126,7 +126,7 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, unsigned rwidth = 0, rheight = 0, rborder_width = 0, rdepth = 0; if (!XGetGeometry(ps->dpy, pxmap, &rroot, &rx, &ry, &rwidth, &rheight, &rborder_width, &rdepth)) { - printfef(false, "(%d, %d, %d, %#010lx): Failed to determine pixmap size.", width, height, depth, pxmap); + printfef(false, "(): (%d, %d, %d, %#010lx): Failed to determine pixmap size.", width, height, depth, pxmap); return NULL; } width = rwidth; @@ -136,14 +136,14 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, // Sanity check if (!(width && height && depth)) { - printfef(false, "(%d, %d, %d, %#010lx): Failed to get pixmap info.", width, height, depth, pxmap); + printfef(false, "(): (%d, %d, %d, %#010lx): Failed to get pixmap info.", width, height, depth, pxmap); return NULL; } // Find X Render format const XRenderPictFormat *rfmt = depth_to_rfmt(ps, depth); if (!rfmt) { - printfef(false, "(%d, %d, %d, %#010lx): Failed to find X Render format for depth %d.", + printfef(false, "(): (%d, %d, %d, %#010lx): Failed to find X Render format for depth %d.", width, height, depth, pxmap, depth); return NULL; } @@ -157,7 +157,7 @@ create_pictw_frompixmap(session_t *ps, int width, int height, int depth, if (!(pictw->pict = XRenderCreatePicture(ps->dpy, pictw->pxmap, rfmt, 0, NULL))) { - printfef(false, "(%d, %d, %d, %#010lx): Failed to create Picture.", + printfef(false, "(): (%d, %d, %d, %#010lx): Failed to create Picture.", width, height, depth, pxmap); free_pictw(ps, &pictw); } @@ -172,7 +172,7 @@ static inline pictw_t * create_pictw(session_t *ps, int width, int height, int depth) { Pixmap pxmap = XCreatePixmap(ps->dpy, ps->root, width, height, depth); if (!pxmap) { - printfef(false, "(%d, %d, %d): Failed to create Pixmap.", width, height, depth); + printfef(false, "(): (%d, %d, %d): Failed to create Pixmap.", width, height, depth); return NULL; } @@ -265,14 +265,14 @@ simg_pixmap_to_pictw(session_t *ps, int width, int height, int depth, pictw_t *pictw = NULL; if (!porig) { - printfef(false, "(%d, %d, %d, %#010lx, %#010lx): Failed to create picture for pixmap.", + printfef(false, "(): (%d, %d, %d, %#010lx, %#010lx): Failed to create picture for pixmap.", width, height, depth, pxmap, mask); goto simg_pixmap_to_pict_end; } if (mask) { if (!(pmask = create_pictw_frompixmap(ps, width, height, depth, mask))) { - printfef(false, "(%d, %d, %d, %#010lx, %#010lx): Failed to create picture for mask.", + printfef(false, "(): (%d, %d, %d, %#010lx, %#010lx): Failed to create picture for mask.", width, height, depth, pxmap, mask); goto simg_pixmap_to_pict_end; } @@ -281,7 +281,7 @@ simg_pixmap_to_pictw(session_t *ps, int width, int height, int depth, } if (!(pictw = create_pictw(ps, porig->width, porig->height, (mask ? 32: porig->depth)))) { - printfef(false, "(%d, %d, %d, %#010lx, %#010lx): Failed to create target picture.", + printfef(false, "(): (%d, %d, %d, %#010lx, %#010lx): Failed to create target picture.", width, height, depth, pxmap, mask); goto simg_pixmap_to_pict_end; } @@ -299,7 +299,7 @@ simg_pixmap_to_pictw(session_t *ps, int width, int height, int depth, /* gc = XCreateGC(ps->dpy, pictw->pxmap, 0, 0); if (!gc) { - printfef(false, "(%#010lx, %#010lx, %d, %d, %d): Failed to create GC.", + printfef(false, "(): (%#010lx, %#010lx, %d, %d, %d): Failed to create GC.", pxmap, mask, width, height, depth); free_pictw(ps, &pictw); goto simg_data_to_pict_end; @@ -334,18 +334,18 @@ simg_data_to_pictw(session_t *ps, int width, int height, int depth, depth, ZPixmap, 0, (char *) data, width, height, 8, bytes_per_line); if (!img) { - printfef(false, "(%d, %d, %d): Failed to create XImage.", + printfef(false, "(): (%d, %d, %d): Failed to create XImage.", width, height, depth); goto simg_data_to_pict_end; } if (!(pictw = create_pictw(ps, width, height, depth))) { - printfef(false, "(%d, %d, %d): Failed to create Picture.", + printfef(false, "(): (%d, %d, %d): Failed to create Picture.", width, height, depth); goto simg_data_to_pict_end; } gc = XCreateGC(ps->dpy, pictw->pxmap, 0, 0); if (!gc) { - printfef(false, "(%d, %d, %d): Failed to create GC.", + printfef(false, "(): (%d, %d, %d): Failed to create GC.", width, height, depth); free_pictw(ps, &pictw); goto simg_data_to_pict_end; diff --git a/src/mainwin.c b/src/mainwin.c index 5bea484..1425d5e 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -223,7 +223,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { if(! XParseColor(ps->dpy, mw->colormap, ps->o.highlight_tint, &exact_color)) { - printfef(true, "Couldn't look up color '%s', reverting to #101020", ps->o.highlight_tint); + printfef(true, "(): Couldn't look up color '%s', reverting to #101020", ps->o.highlight_tint); mw->highlightTint.red = mw->highlightTint.green = 0x10; mw->highlightTint.blue = 0x20; } @@ -238,7 +238,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { ; if(! XParseColor(ps->dpy, mw->colormap, ps->o.shadow_tint, &exact_color)) { - printfef(true, "Couldn't look up color '%s', reverting to #040404", ps->o.shadow_tint); + printfef(true, "(): Couldn't look up color '%s', reverting to #040404", ps->o.shadow_tint); mw->shadowTint.red = mw->shadowTint.green = mw->shadowTint.blue = 0x04; } else @@ -358,13 +358,13 @@ mainwin_update(MainWin *mw) } # ifdef DEBUG - printfdf(false, "--> querying pointer... "); + printfdf(false, "(): --> querying pointer... "); # endif /* DEBUG */ XQueryPointer(ps->dpy, ps->root, &dummy_w, &dummy_w, &root_x, &root_y, &dummy_i, &dummy_i, &dummy_u); # ifdef DEBUG - printfdf(false, "+%i+%i\n", root_x, root_y); + printfdf(false, "(): +%i+%i\n", root_x, root_y); - printfdf(false, "--> figuring out which screen we're on... "); + printfdf(false, "(): --> figuring out which screen we're on... "); # endif /* DEBUG */ iter = mw->xin_info; for(i = 0; i < mw->xin_screens; ++i) @@ -373,7 +373,7 @@ mainwin_update(MainWin *mw) root_y >= iter->y_org && root_y < iter->y_org + iter->height) { # ifdef DEBUG - printfdf(false, "screen %i %ix%i+%i+%i\n", iter->screen_number, iter->width, iter->height, iter->x_org, iter->y_org); + printfdf(false, "(): screen %i %ix%i+%i+%i\n", iter->screen_number, iter->width, iter->height, iter->x_org, iter->y_org); # endif /* DEBUG */ break; } @@ -382,7 +382,7 @@ mainwin_update(MainWin *mw) if(i == mw->xin_screens) { # ifdef DEBUG - printfdf(false, "unknown\n"); + printfdf(false, "(): unknown\n"); # endif /* DEBUG */ return; } diff --git a/src/skippy.c b/src/skippy.c index c4ab602..cebdcdb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -63,7 +63,7 @@ parse_cliop(session_t *ps, const char *str, enum cliop *dest) { return true; } - printfef(true, "(\"%s\"): Unrecognized operation.", str); + printfef(true, "() (\"%s\"): Unrecognized operation.", str); return false; } @@ -83,7 +83,7 @@ parse_align(session_t *ps, const char *str, enum align *dest) { return strlen(STRS_ALIGN[i]); } - printfef(true, "(\"%s\"): Unrecognized operation.", str); + printfef(true, "() (\"%s\"): Unrecognized operation.", str); return 0; } @@ -113,7 +113,7 @@ parse_pict_posp_mode(session_t *ps, const char *str, enum pict_posp_mode *dest) return strlen(STRS_PICTPOSP[i]); } - printfef(true, "(\"%s\"): Unrecognized operation.", str); + printfef(true, "() (\"%s\"): Unrecognized operation.", str); return 0; } static inline int @@ -161,7 +161,7 @@ parse_color(session_t *ps, const char *s, XRenderColor *pc) { if (!((next = parse_color_sub(s, &pc->red)) && (next = parse_color_sub((s += next), &pc->green)) && (next = parse_color_sub((s += next), &pc->blue)))) { - printfef(true, "(\"%s\"): Failed to read color segment.", s); + printfef(true, "() (\"%s\"): Failed to read color segment.", s); return 0; } if (!(next = parse_color_sub((s += next), &pc->alpha))) @@ -206,7 +206,7 @@ parse_size(const char *s, int *px, int *py) { if (endptr && s != endptr) { *py = val; if (*py < 0) { - printfef(true, "(\"%s\"): Invalid height.", s); + printfef(true, "() (\"%s\"): Invalid height.", s); return 0; } s = endptr; @@ -220,7 +220,7 @@ parse_size(const char *s, int *px, int *py) { return 0; if (!isspace0(*s)) { - printfef(true, "(\"%s\"): Trailing characters.", s); + printfef(true, "() (\"%s\"): Trailing characters.", s); return 0; } @@ -551,7 +551,7 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { if (mw && mw->window == wid) wextra = "(Main)"; print_timestamp(ps); - printfdf(false, "Event %-13.13s wid %#010lx %s", name, wid, wextra); + printfdf(false, "(): Event %-13.13s wid %#010lx %s", name, wid, wextra); } static void @@ -1168,7 +1168,7 @@ xerror(Display *dpy, XErrorEvent *ev) { { char buf[BUF_LEN] = ""; XGetErrorText(ps->dpy, ev->error_code, buf, BUF_LEN); - printfef(false, "error %d (%s) request %d minor %d serial %lu (\"%s\")", + printfef(false, "(): error %d (%s) request %d minor %d serial %lu (\"%s\")", ev->error_code, name, ev->request_code, ev->minor_code, ev->serial, buf); } @@ -1200,7 +1200,7 @@ show_help() { // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" - " --debug - enable debugging logs.\n" + " -S - enable debugging logs.\n" , stdout); #ifdef CFG_LIBPNG spng_about(stdout); @@ -1394,11 +1394,11 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { break; case OPT_PREV: ps->o.focus_initial = FI_PREV; - printfdf(false, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + printfdf(false, "(): ps->o.focus_initial=%i\n", ps->o.focus_initial); break; case OPT_NEXT: ps->o.focus_initial = FI_NEXT; - printfdf(false, "ps->o.focus_initial=%i\n", ps->o.focus_initial); + printfdf(false, "(): ps->o.focus_initial=%i\n", ps->o.focus_initial); break; case 'S': debuglog = true; @@ -1530,26 +1530,29 @@ load_config_file(session_t *ps) check_keysyms(ps->o.config_path, ": [bindings] keysReverseDirection =", ps->o.bindings_keysReverseDirection); check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); - if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) - || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) - || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) - return RET_BADARG; - { - const char *s = config_get(config, "general", "layout", NULL); - if (s) { - if (strcmp(s,"boxy") == 0) { - ps->o.layout = LAYOUT_BOXY; - } - else if (strcmp(s,"xd") == 0) { - ps->o.layout = LAYOUT_XD; - } - else { - ps->o.layout = LAYOUT_BOXY; - } - } + if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) { + return RET_BADARG; + } + + { + const char *s = config_get(config, "general", "layout", NULL); + if (s) { + if (strcmp(s,"boxy") == 0) { + ps->o.layout = LAYOUT_BOXY; + } + else if (strcmp(s,"xd") == 0) { + ps->o.layout = LAYOUT_XD; + } + else { + ps->o.layout = LAYOUT_BOXY; + } + } else ps->o.layout = LAYOUT_BOXY; } + config_get_bool_wrap(config, "general", "sortByColumn", &ps->o.sortByColumn); config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); diff --git a/src/skippy.h b/src/skippy.h index e2e69ad..a3c7bcf 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -480,7 +480,7 @@ print_timestamp(session_t *ps) { timeval_subtract(&diff, &tm, &ps->time_start); - printfef(false, "[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000); + printfef(false, "() [ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000); } /** diff --git a/src/tooltip.c b/src/tooltip.c index 7ba3c12..d49cb1f 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -97,7 +97,7 @@ tooltip_create(MainWin *mw) { tmp = ps->o.tooltip_border; if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->border)) { - printfef(false, "WARNING: Invalid color '%s'.\n", tmp); + printfef(false, "(): WARNING: Invalid color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -105,7 +105,7 @@ tooltip_create(MainWin *mw) { tmp = ps->o.tooltip_background; if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->background)) { - printfef(false, "WARNING: Invalid color '%s'.\n", tmp); + printfef(false, "(): WARNING: Invalid color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -117,7 +117,7 @@ tooltip_create(MainWin *mw) { tmp = ps->o.tooltip_text; if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->color)) { - printfef(false, "WARNING: Couldn't allocate color '%s'.\n", tmp); + printfef(false, "(): WARNING: Couldn't allocate color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -127,7 +127,7 @@ tooltip_create(MainWin *mw) { { if(! XftColorAllocName(ps->dpy, mw->visual, mw->colormap, tmp, &tt->shadow)) { - printfef(false, "WARNING: Couldn't allocate color '%s'.\n", tmp); + printfef(false, "(): WARNING: Couldn't allocate color '%s'.\n", tmp); tooltip_destroy(tt); return 0; } @@ -136,7 +136,7 @@ tooltip_create(MainWin *mw) { tt->draw = XftDrawCreate(ps->dpy, tt->window, mw->visual, mw->colormap); if(! tt->draw) { - printfef(false, "WARNING: Couldn't create Xft draw surface.\n"); + printfef(false, "(): WARNING: Couldn't create Xft draw surface.\n"); tooltip_destroy(tt); return 0; } @@ -144,7 +144,7 @@ tooltip_create(MainWin *mw) { tt->font = XftFontOpenName(ps->dpy, ps->screen, ps->o.tooltip_font); if(! tt->font) { - printfef(false, "WARNING: Couldn't open Xft font.\n"); + printfef(false, "(): WARNING: Couldn't open Xft font.\n"); tooltip_destroy(tt); return 0; } diff --git a/src/wm.c b/src/wm.c index 191b18c..4c371d5 100644 --- a/src/wm.c +++ b/src/wm.c @@ -511,11 +511,11 @@ printfdfWindowName(session_t *ps, char *prefix_str, Window wid) return; if (prefix_str) { - printfdf(false, "%s%s", prefix_str, win_title); + printfdf(false, "(): %s%s", prefix_str, win_title); } else { - printfdf(false, "%s", win_title); + printfdf(false, "(): %s", win_title); } free(win_title); From 8d665ddc8a3998c0b341868c7487b92455401b76 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 5 Apr 2023 22:34:40 -0700 Subject: [PATCH 117/205] improve boxy layout under showAllDesktop=true --- src/layout.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/layout.c b/src/layout.c index ec01a3c..5e363e9 100644 --- a/src/layout.c +++ b/src/layout.c @@ -220,9 +220,24 @@ layout_boxy(MainWin *mw, dlist *windows, slot_width = MIN(slot_width, cw->src.width); slot_height = MIN(slot_height, cw->src.height); - CARD32 desktop = wm_get_window_desktop(mw->ps, cw->wid_client) - - wm_get_current_desktop(mw->ps); - cw->src.x += desktop * mw->width; + { + int screencount = wm_get_desktops(mw->ps); + if (screencount == -1) + screencount = 1; + int desktop_dim = ceil(sqrt(screencount)); + + int win_desktop = wm_get_window_desktop(mw->ps, cw->wid_client); + int current_desktop = wm_get_current_desktop(mw->ps); + + int win_desktop_x = win_desktop % desktop_dim; + int win_desktop_y = win_desktop / desktop_dim; + + int current_desktop_x = current_desktop % desktop_dim; + int current_desktop_y = current_desktop / desktop_dim; + + cw->src.x += (win_desktop_x - current_desktop_x) * (mw->width + mw->distance); + cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); + } cw->x = cw->src.x; cw->y = cw->src.y; From ebcab23be8a791ca576ad3f9f339f6e08c1c9da6 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 5 Apr 2023 22:39:52 -0700 Subject: [PATCH 118/205] Whitespace --- src/layout.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/layout.c b/src/layout.c index 5e363e9..acb95ed 100644 --- a/src/layout.c +++ b/src/layout.c @@ -220,24 +220,24 @@ layout_boxy(MainWin *mw, dlist *windows, slot_width = MIN(slot_width, cw->src.width); slot_height = MIN(slot_height, cw->src.height); - { - int screencount = wm_get_desktops(mw->ps); - if (screencount == -1) - screencount = 1; - int desktop_dim = ceil(sqrt(screencount)); + { + int screencount = wm_get_desktops(mw->ps); + if (screencount == -1) + screencount = 1; + int desktop_dim = ceil(sqrt(screencount)); - int win_desktop = wm_get_window_desktop(mw->ps, cw->wid_client); - int current_desktop = wm_get_current_desktop(mw->ps); + int win_desktop = wm_get_window_desktop(mw->ps, cw->wid_client); + int current_desktop = wm_get_current_desktop(mw->ps); - int win_desktop_x = win_desktop % desktop_dim; - int win_desktop_y = win_desktop / desktop_dim; + int win_desktop_x = win_desktop % desktop_dim; + int win_desktop_y = win_desktop / desktop_dim; - int current_desktop_x = current_desktop % desktop_dim; - int current_desktop_y = current_desktop / desktop_dim; + int current_desktop_x = current_desktop % desktop_dim; + int current_desktop_y = current_desktop / desktop_dim; - cw->src.x += (win_desktop_x - current_desktop_x) * (mw->width + mw->distance); - cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); - } + cw->src.x += (win_desktop_x - current_desktop_x) * (mw->width + mw->distance); + cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); + } cw->x = cw->src.x; cw->y = cw->src.y; From 5f7971c316f11831a00b5411f951d6e85f0ffc8d Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 6 Apr 2023 17:00:43 -0700 Subject: [PATCH 119/205] Remove lazy transparency options --- skippy-xd.sample.rc | 1 - src/clientwin.c | 20 +++++++------------- src/mainwin.c | 14 ++------------ src/skippy.c | 16 ++-------------- src/skippy.h | 2 -- 5 files changed, 11 insertions(+), 42 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index e14af1a..ade393f 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -74,7 +74,6 @@ updateFreq = 60.0 # set = 0 to switch off animations animationDuration = 200 -lazyTrans = false pipePath = /tmp/skippy-xd-fifo # Move the mouse cursor to the next highlighted window, straight after launching skippy diff --git a/src/clientwin.c b/src/clientwin.c index 8b9d609..cec9461 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -113,10 +113,10 @@ clientwin_create(MainWin *mw, Window client) { .event_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ExposureMask | FocusChangeMask, - .override_redirect = ps->o.lazyTrans, + .override_redirect = false, }; cw->mini.window = XCreateWindow(ps->dpy, - (ps->o.lazyTrans ? ps->root : mw->window), 0, 0, 1, 1, 0, + mw->window, 0, 0, 1, 1, 0, mw->depth, InputOutput, mw->visual, CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr); } @@ -377,17 +377,11 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) else if (cw->zombie) mask = cw->mainwin->shadowPicture; - if (ps->o.lazyTrans) { - XRenderComposite(ps->dpy, PictOpSrc, source, mask, - cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); - } - else { - XRenderComposite(ps->dpy, PictOpSrc, cw->mainwin->background, None, - cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, - s_x, s_y, s_w, s_h); - XRenderComposite(ps->dpy, PictOpOver, source, mask, - cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); - } + XRenderComposite(ps->dpy, PictOpSrc, cw->mainwin->background, None, + cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, + s_x, s_y, s_w, s_h); + XRenderComposite(ps->dpy, PictOpOver, source, mask, + cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); if (CLIDISP_ZOMBIE_ICON == cw->mode || CLIDISP_THUMBNAIL_ICON == cw->mode) { assert(cw->icon_pict && cw->icon_pict->pict); img_composite_params_t params = IMG_COMPOSITE_PARAMS_INIT; diff --git a/src/mainwin.c b/src/mainwin.c index 1425d5e..e75d591 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -191,18 +191,8 @@ mainwin_reload(session_t *ps, MainWin *mw) { else mw->poll_time = (1.0 / 60.0) * 1000.0; - if (ps->o.lazyTrans) { - mw->depth = 32; - mw->visual = ps->argb_visual; - if (!mw->visual) { - printfef(true, "(): Couldn't find ARGB visual, lazy transparency can't work."); - goto mainwin_create_err; - } - } - if (!ps->o.lazyTrans) { - mw->depth = DefaultDepth(dpy, ps->screen); - mw->visual = DefaultVisual(dpy, ps->screen); - } + mw->depth = DefaultDepth(dpy, ps->screen); + mw->visual = DefaultVisual(dpy, ps->screen); mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone); mw->format = XRenderFindVisualFormat(dpy, mw->visual); diff --git a/src/skippy.c b/src/skippy.c index cebdcdb..05081fb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -622,12 +622,6 @@ skippy_activate(MainWin *mw, Window leader, bool paging) mw->xin_active = 0; #endif /* CFG_XINERAMA */ - // Map the main window and run our event loop - /*if (ps->o.lazyTrans) { - mainwin_map(mw); - XFlush(ps->dpy); - }*/ - mw->client_to_focus = NULL; daemon_count_clients(mw, 0, leader); @@ -655,11 +649,6 @@ skippy_activate(MainWin *mw, Window leader, bool paging) foreach_dlist(mw->clients) { ClientWin *cw = iter->data; - if (mw->ps->o.lazyTrans) - { - cw->x += cw->mainwin->x; - cw->y += cw->mainwin->y; - } cw->x *= mw->multiplier; cw->y *= mw->multiplier; } @@ -793,7 +782,7 @@ mainloop(session_t *ps, bool activate_on_start) { last_rendered = time_in_millis(); /* Map the main window and run our event loop */ - if (!ps->o.lazyTrans && !mw->mapped) + if (!mw->mapped) mainwin_map(mw); XFlush(ps->dpy); } @@ -805,7 +794,7 @@ mainloop(session_t *ps, bool activate_on_start) { ps->o.movePointerOnStart); /* Map the main window and run our event loop */ - if (!ps->o.lazyTrans && !mw->mapped) + if (!mw->mapped) mainwin_map(mw); XFlush(ps->dpy); } @@ -1561,7 +1550,6 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); - config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); diff --git a/src/skippy.h b/src/skippy.h index a3c7bcf..9ce7c1d 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -195,7 +195,6 @@ typedef struct { bool acceptWMWin; double updateFreq; int animationDuration;; - bool lazyTrans; bool includeFrame; char *pipePath; bool movePointerOnStart; @@ -268,7 +267,6 @@ typedef struct { .acceptWMWin = false, \ .updateFreq = 60.0, \ .animationDuration = 200, \ - .lazyTrans = false, \ .includeFrame = false, \ .pipePath = NULL, \ .movePointerOnStart = true, \ From 5dab1699ca07550d364201702b1a2eb216a6b987 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 6 Apr 2023 17:07:23 -0700 Subject: [PATCH 120/205] Update Makefile version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 866887b..73e2a46 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ INCS = $(shell pkg-config --cflags $(PACKAGES)) LIBS += -lm $(shell pkg-config --libs $(PACKAGES)) # === Version string === -SKIPPYXD_VERSION = "v0.5.2~pre (2018.09.09) - \\\"Puzzlebox\\\" Edition" +SKIPPYXD_VERSION = "v0.6.0~fung (2023.03.10) - \\\"\\\" Edition" CPPFLAGS += -DSKIPPYXD_VERSION=\"${SKIPPYXD_VERSION}\" # === Recipes === From 5166e32104ac24d1fcb19dc44a53e9d7532cb187 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 6 Apr 2023 17:17:50 -0700 Subject: [PATCH 121/205] Correct MainWin create error flow --- src/mainwin.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/mainwin.c b/src/mainwin.c index 1425d5e..5ce2aad 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -80,6 +80,8 @@ mainwin_create(session_t *ps) { mw->height = rootattr.height; mw = mainwin_reload(ps, mw); + if (!mw) + goto mainwin_create_err; XSetWindowAttributes wattr; wattr.colormap = mw->colormap; @@ -93,10 +95,9 @@ mainwin_create(session_t *ps) { mw->window = XCreateWindow(dpy, ps->root, 0, 0, mw->width, mw->height, 0, mw->depth, InputOutput, mw->visual, CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &wattr); - if (!mw->window) { - free(mw); - return 0; - } + if (!mw->window) + goto mainwin_create_err; + wm_wid_set_info(ps, mw->window, "main window", None); mainwin_create_pixmap(mw); @@ -113,6 +114,11 @@ mainwin_create(session_t *ps) { XCompositeRedirectSubwindows (ps->dpy, ps->root, CompositeRedirectAutomatic); return mw; + +mainwin_create_err: + if (mw) + free(mw); + return NULL; } MainWin * @@ -195,8 +201,8 @@ mainwin_reload(session_t *ps, MainWin *mw) { mw->depth = 32; mw->visual = ps->argb_visual; if (!mw->visual) { - printfef(true, "(): Couldn't find ARGB visual, lazy transparency can't work."); - goto mainwin_create_err; + printfef(true, "(): Couldn't find ARGB visual."); + return mw; } } if (!ps->o.lazyTrans) { @@ -258,11 +264,6 @@ mainwin_reload(session_t *ps, MainWin *mw) { } return mw; - -mainwin_create_err: - if (mw) - free(mw); - return NULL; } MainWin * From a6f14cb6764bae4d6a26bc8c43669628df41eb3b Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 7 Apr 2023 03:53:07 -0700 Subject: [PATCH 122/205] Paging proxy client desktop windows without proper painting --- src/clientwin.c | 1 - src/mainwin.h | 2 +- src/skippy.c | 198 ++++++++++++++++++++++++++++++++++-------------- 3 files changed, 142 insertions(+), 59 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index cec9461..da6d2cc 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -395,7 +395,6 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) } // Tinting - if (cw->mode >= CLIDISP_ZOMBIE) // tint only thumbnail { // here the client window is being tinted XRenderColor *tint = &cw->mainwin->normalTint; diff --git a/src/mainwin.h b/src/mainwin.h index 11ad087..359ab7f 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -50,7 +50,7 @@ struct _mainwin_t { Picture normalPicture, highlightPicture, shadowPicture; ClientWin *pressed, *focus; - dlist *clientondesktop, *focuslist; + dlist *clientondesktop, *focuslist, *desktopwins, *dminis; struct _Tooltip *tooltip; KeySym *keysyms_Up; diff --git a/src/skippy.c b/src/skippy.c index 05081fb..17dc488 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -365,11 +365,11 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) return; } -static void +static bool init_layout(MainWin *mw, Window focus, Window leader) { if (!mw->clientondesktop) - return; + return true; dlist_sort(mw->clientondesktop, clientwin_sort_func, 0); @@ -400,14 +400,14 @@ init_layout(MainWin *mw, Window focus, Window leader) mw->yoff = yoff; } - return; + return true; } -static void -init_desktop_layout(MainWin *mw, Window focus, Window leader) +static bool +init_paging_layout(MainWin *mw, Window focus, Window leader) { if (!mw->clients) - return; + return true; int screencount = wm_get_desktops(mw->ps); if (screencount == -1) @@ -448,10 +448,73 @@ init_desktop_layout(MainWin *mw, Window focus, Window leader) cw->src.y += (win_desktop_y - current_desktop_y) * (mw->height + mw->distance); } - dlist_sort(mw->clientondesktop, sort_cw_by_row, 0); - mw->focuslist = mw->clientondesktop; + // create windows which represent each virtual desktop + int current_desktop = wm_get_current_desktop(mw->ps); + for (int j=0; jcolormap, + /*.event_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask + | KeyReleaseMask | EnterWindowMask | LeaveWindowMask + | PointerMotionMask | ExposureMask | FocusChangeMask,*/ + .override_redirect = false, + // exclude window frame + }; + Window desktopwin = XCreateWindow(mw->ps->dpy, + mw->window, + 0, 0, 0, 0, + //i * (mw->width + mw->distance), j * (mw->height + mw->distance), + //mw->width, mw->height, + 0, mw->depth, InputOnly, mw->visual, + CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr); + if (!desktopwin) return false; + //XMapWindow(mw->ps->dpy, desktopwin); + //XRaiseWindow(mw->ps->dpy, desktopwin); + + if (!mw->desktopwins) + mw->desktopwins = dlist_add(NULL, &desktopwin); + else + mw->desktopwins = dlist_add(mw->desktopwins, &desktopwin); - return; + ClientWin *cw = clientwin_create(mw, desktopwin); + if (!cw) return false; + + clientwin_update(cw); + clientwin_update2(cw); + cw->slots = desktop_dim * j + i; + + cw->x = cw->src.x = (i * (mw->width + mw->distance)) * mw->multiplier; + cw->y = cw->src.y = (j * (mw->height + mw->distance)) * mw->multiplier; + cw->src.width = mw->width; + cw->src.height = mw->height; +printfdf(true,"(): desktop window %d %p %d", cw->slots, cw, cw->mode); + + //clientwin_update_desktopwin(cw); + clientwin_move(cw, mw->multiplier, mw->xoff, mw->yoff, 1); + + if (!mw->dminis) + mw->dminis = dlist_add(NULL, cw); + else + dlist_add(mw->dminis, cw); + + XRaiseWindow(mw->ps->dpy, cw->mini.window); + //XSelectInput(cw->mainwin->ps->dpy, + //desktopwin, SubstructureNotifyMask | StructureNotifyMask); + + if (cw->slots == current_desktop) { + mw->client_to_focus = cw; + mw->revert_focus_win = cw->wid_client; + mw->client_to_focus_on_cancel = cw; + mw->client_to_focus->focused = 1; + } + } + } + + mw->focuslist = mw->dminis; + + return true; } static inline const char * @@ -559,52 +622,45 @@ init_focus(MainWin *mw, Window leader) { session_t *ps = mw->ps; // Get the currently focused window and select which mini-window to focus - { - dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) mw->revert_focus_win); + dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) mw->revert_focus_win); - // check if the user specified --prev or --next on the cmdline - if(ps->o.focus_initial) - { + // check if the user specified --prev or --next on the cmdline + if(ps->o.focus_initial) + { - // ps->mainwin->ignore_next_refocus = 1; - // ps->mainwin->ignore_next_refocus = 2; - // ps->mainwin->ignore_next_refocus = 4; + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; - if(ps->o.focus_initial == FI_PREV) + if(ps->o.focus_initial == FI_PREV) + { + // here, mw->focuslist is the first (dlist*) item in the list + if (iter == mw->focuslist) + iter = dlist_last(mw->focuslist); + else { - // here, mw->focuslist is the first (dlist*) item in the list - if (iter == mw->focuslist) - iter = dlist_last(mw->focuslist); - else - { - dlist *i = mw->focuslist; - for (; i != NULL; i = i->next) - if (i->next && i->next == iter) - break; - iter = i; - } + dlist *i = mw->focuslist; + for (; i != NULL; i = i->next) + if (i->next && i->next == iter) + break; + iter = i; } - else if(ps->o.focus_initial == FI_NEXT) - iter = iter->next; - } + else if(ps->o.focus_initial == FI_NEXT) + iter = iter->next; - // then clear this flag, so daemon not remember on its next activation - ps->o.focus_initial = 0; - - if (!iter) - iter = mw->focuslist; + } - // mw->focus = (ClientWin *) iter->data; - mw->client_to_focus = (ClientWin *) iter->data; - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; - // mw->focus->focused = 1; + // then clear this flag, so daemon not remember on its next activation + ps->o.focus_initial = 0; + if (!iter) + iter = mw->focuslist; - mw->client_to_focus->focused = 1; - // focus_miniw(ps, mw->client_to_focus); - } + mw->client_to_focus = (ClientWin *) iter->data; + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + mw->client_to_focus->focused = 1; } static bool @@ -631,20 +687,18 @@ skippy_activate(MainWin *mw, Window leader, bool paging) } if (paging) { - init_desktop_layout(mw, mw->revert_focus_win, leader); - if (!mw->clientondesktop) { - printfef(false, "(): Failed to build layout."); + if (!init_paging_layout(mw, mw->revert_focus_win, leader)) { + printfef(false, "(): init_paging_layout() failed."); return false; } - mw->focuslist = mw->clientondesktop; } else { - init_layout(mw, mw->revert_focus_win, leader); - if (!mw->clientondesktop) { - printfef(false, "(): Failed to build layout."); + if (!init_layout(mw, mw->revert_focus_win, leader)) { + printfef(false, "(): init_layout() failed."); return false; } } + init_focus(mw, leader); foreach_dlist(mw->clients) { @@ -733,7 +787,10 @@ mainloop(session_t *ps, bool activate_on_start) { // Focus the client window only after the main window get unmapped and // keyboard gets ungrabbed. if (mw->client_to_focus) { - childwin_focus(mw->client_to_focus); + if (paging) + wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); + else + childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; refocus = false; pending_damage = false; @@ -749,6 +806,17 @@ mainloop(session_t *ps, bool activate_on_start) { refocus = false; } + // free all mini desktop representations + dlist_free_with_func(mw->dminis, (dlist_free_func) clientwin_destroy); + mw->dminis = NULL; + + foreach_dlist (mw->desktopwins) { + XDestroyWindow(ps->dpy, (Window) (iter->data)); + //XSelectInput(ps->dpy, (Window) (iter->data), 0); + } + dlist_free(mw->desktopwins); + mw->desktopwins = NULL; + // Catch all errors, but remove all events XSync(ps->dpy, False); XSync(ps->dpy, True); @@ -793,6 +861,12 @@ mainloop(session_t *ps, bool activate_on_start) { focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); + if (paging) { + foreach_dlist (mw->dminis) { + clientwin_map(((ClientWin *) iter->data)); + } + } + /* Map the main window and run our event loop */ if (!mw->mapped) mainwin_map(mw); @@ -872,9 +946,14 @@ mainloop(session_t *ps, bool activate_on_start) { } else if (mw && (ps->xinfo.damage_ev_base + XDamageNotify == ev.type)) { //printfdf(false, "(): else if (ev.type == XDamageNotify) {"); - dlist *iter = dlist_find(ps->mainwin->clients, clientwin_cmp_func, - (void *) wid); pending_damage = true; + dlist *iter = dlist_find(ps->mainwin->clients, + clientwin_cmp_func, (void *) wid); + if (iter) { + ((ClientWin *)iter->data)->damaged = true; + } + iter = dlist_find(ps->mainwin->dminis, + clientwin_cmp_func, (void *) wid); if (iter) { ((ClientWin *)iter->data)->damaged = true; } @@ -895,7 +974,10 @@ mainloop(session_t *ps, bool activate_on_start) { else if (mw && mw->tooltip && wid == mw->tooltip->window) tooltip_handle(mw->tooltip, &ev); else if (mw && wid) { - for (dlist *iter = mw->clientondesktop; iter; iter = iter->next) { + dlist *iter = mw->clientondesktop; + if (paging) + iter = mw->dminis; + for (; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { if (!(POLLIN & r_fd[1].revents)) @@ -914,9 +996,11 @@ mainloop(session_t *ps, bool activate_on_start) { pending_damage = false; foreach_dlist(mw->clientondesktop) { if (((ClientWin *) iter->data)->damaged) - { clientwin_repair(iter->data); - } + } + foreach_dlist(mw->dminis) { + if (((ClientWin *) iter->data)->damaged) + clientwin_repair(iter->data); } last_rendered = time_in_millis(); } From f97a0caf307f0874acec1733298d7c09bef4c127 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 7 Apr 2023 16:34:40 -0700 Subject: [PATCH 123/205] Paging proxy window works but no tinting --- src/clientwin.c | 55 +++++++++++++++++++++++++-------------------- src/skippy.c | 59 ++++++++++++++++++++++++++++++++++++++++++------- src/skippy.h | 1 + 3 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index da6d2cc..e6bad6d 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -170,6 +170,8 @@ clientwin_get_disp_mode(session_t *ps, ClientWin *cw, bool isViewable) { case CLIDISP_FILLED: case CLIDISP_NONE: return *p; + case CLIDISP_DESKTOP: + return *p; } } @@ -282,6 +284,8 @@ clientwin_update2(ClientWin *cw) { clientwin_free_res2(ps, cw); switch (cw->mode) { + case CLIDISP_DESKTOP: + break; case CLIDISP_NONE: break; case CLIDISP_FILLED: @@ -347,6 +351,9 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) } switch (cw->mode) { + case CLIDISP_DESKTOP: + source = cw->origin; + break; case CLIDISP_NONE: break; case CLIDISP_FILLED: @@ -382,6 +389,7 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) s_x, s_y, s_w, s_h); XRenderComposite(ps->dpy, PictOpOver, source, mask, cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); + if (CLIDISP_ZOMBIE_ICON == cw->mode || CLIDISP_THUMBNAIL_ICON == cw->mode) { assert(cw->icon_pict && cw->icon_pict->pict); img_composite_params_t params = IMG_COMPOSITE_PARAMS_INIT; @@ -396,7 +404,6 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) // Tinting { - // here the client window is being tinted XRenderColor *tint = &cw->mainwin->normalTint; if (cw->focused) tint = &cw->mainwin->highlightTint; @@ -453,6 +460,29 @@ clientwin_schedule_repair(ClientWin *cw, XRectangle *area) cw->damaged = true; } +void clientwin_round_corners(ClientWin *cw) { + session_t* ps = cw->mainwin->ps; + int dia = 2 * ps->o.cornerRadius; + int w = cw->mini.width; + int h = cw->mini.height; + XGCValues xgcv; + Pixmap mask = XCreatePixmap(ps->dpy, cw->mini.window, w, h, 1); + GC shape_gc = XCreateGC(ps->dpy, mask, 0, &xgcv); + + XSetForeground(ps->dpy, shape_gc, 0); + XFillRectangle(ps->dpy, mask, shape_gc, 0, 0, w, h); + XSetForeground(ps->dpy, shape_gc, 1); + XFillArc(ps->dpy, mask, shape_gc, 0, 0, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 360 * 64); + XFillArc(ps->dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 360 * 64); + XFillRectangle(ps->dpy, mask, shape_gc, ps->o.cornerRadius, 0, w-dia, h); + XFillRectangle(ps->dpy, mask, shape_gc, 0, ps->o.cornerRadius, w, h-dia); + XShapeCombineMask(ps->dpy, cw->mini.window, ShapeBounding, 0, 0, mask, ShapeSet); + XFreePixmap(ps->dpy, mask); + XFreeGC(ps->dpy, shape_gc); +} + void clientwin_move(ClientWin *cw, float f, int x, int y, float timeslice) { @@ -758,26 +788,3 @@ clientwin_action(ClientWin *cw, enum cliop action) { return 0; } - -void clientwin_round_corners(ClientWin *cw) { - session_t* ps = cw->mainwin->ps; - int dia = 2 * ps->o.cornerRadius; - int w = cw->mini.width; - int h = cw->mini.height; - XGCValues xgcv; - Pixmap mask = XCreatePixmap(ps->dpy, cw->mini.window, w, h, 1); - GC shape_gc = XCreateGC(ps->dpy, mask, 0, &xgcv); - - XSetForeground(ps->dpy, shape_gc, 0); - XFillRectangle(ps->dpy, mask, shape_gc, 0, 0, w, h); - XSetForeground(ps->dpy, shape_gc, 1); - XFillArc(ps->dpy, mask, shape_gc, 0, 0, dia, dia, 0, 360 * 64); - XFillArc(ps->dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 360 * 64); - XFillArc(ps->dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 360 * 64); - XFillArc(ps->dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 360 * 64); - XFillRectangle(ps->dpy, mask, shape_gc, ps->o.cornerRadius, 0, w-dia, h); - XFillRectangle(ps->dpy, mask, shape_gc, 0, ps->o.cornerRadius, w, h-dia); - XShapeCombineMask(ps->dpy, cw->mini.window, ShapeBounding, 0, 0, mask, ShapeSet); - XFreePixmap(ps->dpy, mask); - XFreeGC(ps->dpy, shape_gc); -} diff --git a/src/skippy.c b/src/skippy.c index 17dc488..1010102 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -481,15 +481,24 @@ init_paging_layout(MainWin *mw, Window focus, Window leader) ClientWin *cw = clientwin_create(mw, desktopwin); if (!cw) return false; - clientwin_update(cw); - clientwin_update2(cw); cw->slots = desktop_dim * j + i; + { + static const char *PREFIX = "virtual desktop "; + const int len = strlen(PREFIX) + 20; + char *str = allocchk(malloc(len)); + snprintf(str, len, "%s%d", PREFIX, cw->slots); + wm_wid_set_info(cw->mainwin->ps, cw->mini.window, str, None); + free(str); + } + + cw->zombie = false; + cw->mode = CLIDISP_DESKTOP; + cw->x = cw->src.x = (i * (mw->width + mw->distance)) * mw->multiplier; cw->y = cw->src.y = (j * (mw->height + mw->distance)) * mw->multiplier; cw->src.width = mw->width; cw->src.height = mw->height; -printfdf(true,"(): desktop window %d %p %d", cw->slots, cw, cw->mode); //clientwin_update_desktopwin(cw); clientwin_move(cw, mw->multiplier, mw->xoff, mw->yoff, 1); @@ -517,6 +526,35 @@ printfdf(true,"(): desktop window %d %p %d", cw->slots, cw, cw->mode); return true; } +static void +desktopwin_map(ClientWin *cw) +{ + session_t *ps = cw->mainwin->ps; + + free_damage(ps, &cw->damage); + free_pixmap(ps, &cw->pixmap); + + XUnmapWindow(ps->dpy, cw->mini.window); + XSetWindowBackgroundPixmap(ps->dpy, cw->mini.window, None); + + XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; + + if (cw->origin) + free_picture(ps, &cw->origin); + cw->origin = XRenderCreatePicture(ps->dpy, + None, cw->mainwin->format, CPSubwindowMode, &pa); + XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); + + XCompositeRedirectWindow(ps->dpy, cw->src.window, + CompositeRedirectAutomatic); + cw->redirected = true; + + clientwin_render(cw); + + XMapWindow(ps->dpy, cw->mini.window); + XRaiseWindow(ps->dpy, cw->mini.window); +} + static inline const char * ev_dumpstr_type(const XEvent *ev) { switch (ev->type) { @@ -787,8 +825,11 @@ mainloop(session_t *ps, bool activate_on_start) { // Focus the client window only after the main window get unmapped and // keyboard gets ungrabbed. if (mw->client_to_focus) { - if (paging) + if (paging) { wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); + //daemon_count_clients(mw, 0, 0); + //mw->client_to_focus = dlist_first(mw->clientondesktop)->data; + } else childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; @@ -863,7 +904,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (paging) { foreach_dlist (mw->dminis) { - clientwin_map(((ClientWin *) iter->data)); + desktopwin_map(((ClientWin *) iter->data)); } } @@ -998,9 +1039,11 @@ mainloop(session_t *ps, bool activate_on_start) { if (((ClientWin *) iter->data)->damaged) clientwin_repair(iter->data); } - foreach_dlist(mw->dminis) { - if (((ClientWin *) iter->data)->damaged) - clientwin_repair(iter->data); + + if (paging) { + foreach_dlist (mw->dminis) { + desktopwin_map(((ClientWin *) iter->data)); + } } last_rendered = time_in_millis(); } diff --git a/src/skippy.h b/src/skippy.h index 9ce7c1d..3651cc2 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -164,6 +164,7 @@ typedef struct { } keydef_t; typedef enum { + CLIDISP_DESKTOP = -1, CLIDISP_NONE, CLIDISP_FILLED, CLIDISP_ICON, From 1a500f7d5c63ab25350cc7ee6c50d0545dcc2dd0 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 7 Apr 2023 23:47:02 -0700 Subject: [PATCH 124/205] Fix segfault --- src/skippy.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 1010102..239c6d4 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -452,6 +452,7 @@ init_paging_layout(MainWin *mw, Window focus, Window leader) int current_desktop = wm_get_current_desktop(mw->ps); for (int j=0; jps->dpy, mw->window, 0, 0, 0, 0, - //i * (mw->width + mw->distance), j * (mw->height + mw->distance), - //mw->width, mw->height, 0, mw->depth, InputOnly, mw->visual, CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr); if (!desktopwin) return false; - //XMapWindow(mw->ps->dpy, desktopwin); - //XRaiseWindow(mw->ps->dpy, desktopwin); if (!mw->desktopwins) mw->desktopwins = dlist_add(NULL, &desktopwin); @@ -481,7 +478,7 @@ init_paging_layout(MainWin *mw, Window focus, Window leader) ClientWin *cw = clientwin_create(mw, desktopwin); if (!cw) return false; - cw->slots = desktop_dim * j + i; + cw->slots = desktop_idx; { static const char *PREFIX = "virtual desktop "; @@ -500,7 +497,6 @@ init_paging_layout(MainWin *mw, Window focus, Window leader) cw->src.width = mw->width; cw->src.height = mw->height; - //clientwin_update_desktopwin(cw); clientwin_move(cw, mw->multiplier, mw->xoff, mw->yoff, 1); if (!mw->dminis) @@ -509,8 +505,6 @@ init_paging_layout(MainWin *mw, Window focus, Window leader) dlist_add(mw->dminis, cw); XRaiseWindow(mw->ps->dpy, cw->mini.window); - //XSelectInput(cw->mainwin->ps->dpy, - //desktopwin, SubstructureNotifyMask | StructureNotifyMask); if (cw->slots == current_desktop) { mw->client_to_focus = cw; @@ -537,7 +531,7 @@ desktopwin_map(ClientWin *cw) XUnmapWindow(ps->dpy, cw->mini.window); XSetWindowBackgroundPixmap(ps->dpy, cw->mini.window, None); - XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors }; + XRenderPictureAttributes pa = { }; if (cw->origin) free_picture(ps, &cw->origin); @@ -694,7 +688,7 @@ init_focus(MainWin *mw, Window leader) { ps->o.focus_initial = 0; if (!iter) - iter = mw->focuslist; + return; mw->client_to_focus = (ClientWin *) iter->data; mw->client_to_focus_on_cancel = (ClientWin *) iter->data; @@ -826,6 +820,7 @@ mainloop(session_t *ps, bool activate_on_start) { // keyboard gets ungrabbed. if (mw->client_to_focus) { if (paging) { + childwin_focus(mw->client_to_focus); wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); //daemon_count_clients(mw, 0, 0); //mw->client_to_focus = dlist_first(mw->clientondesktop)->data; From ed61e56c7883b9c5f464e9ec81c29a547a132437 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 11 Apr 2023 22:52:37 -0700 Subject: [PATCH 125/205] Revert "Remove lazy transparency options" This reverts commit 5f7971c316f11831a00b5411f951d6e85f0ffc8d. --- skippy-xd.sample.rc | 1 + src/clientwin.c | 20 +++++++++++++------- src/mainwin.c | 14 ++++++++++++-- src/skippy.c | 16 ++++++++++++++-- src/skippy.h | 2 ++ 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index ade393f..e14af1a 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -74,6 +74,7 @@ updateFreq = 60.0 # set = 0 to switch off animations animationDuration = 200 +lazyTrans = false pipePath = /tmp/skippy-xd-fifo # Move the mouse cursor to the next highlighted window, straight after launching skippy diff --git a/src/clientwin.c b/src/clientwin.c index cec9461..8b9d609 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -113,10 +113,10 @@ clientwin_create(MainWin *mw, Window client) { .event_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ExposureMask | FocusChangeMask, - .override_redirect = false, + .override_redirect = ps->o.lazyTrans, }; cw->mini.window = XCreateWindow(ps->dpy, - mw->window, 0, 0, 1, 1, 0, + (ps->o.lazyTrans ? ps->root : mw->window), 0, 0, 1, 1, 0, mw->depth, InputOutput, mw->visual, CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr); } @@ -377,11 +377,17 @@ clientwin_repaint(ClientWin *cw, const XRectangle *pbound) else if (cw->zombie) mask = cw->mainwin->shadowPicture; - XRenderComposite(ps->dpy, PictOpSrc, cw->mainwin->background, None, - cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, - s_x, s_y, s_w, s_h); - XRenderComposite(ps->dpy, PictOpOver, source, mask, - cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); + if (ps->o.lazyTrans) { + XRenderComposite(ps->dpy, PictOpSrc, source, mask, + cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); + } + else { + XRenderComposite(ps->dpy, PictOpSrc, cw->mainwin->background, None, + cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, + s_x, s_y, s_w, s_h); + XRenderComposite(ps->dpy, PictOpOver, source, mask, + cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h); + } if (CLIDISP_ZOMBIE_ICON == cw->mode || CLIDISP_THUMBNAIL_ICON == cw->mode) { assert(cw->icon_pict && cw->icon_pict->pict); img_composite_params_t params = IMG_COMPOSITE_PARAMS_INIT; diff --git a/src/mainwin.c b/src/mainwin.c index 0f8dd5b..506d40e 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -197,8 +197,18 @@ mainwin_reload(session_t *ps, MainWin *mw) { else mw->poll_time = (1.0 / 60.0) * 1000.0; - mw->depth = DefaultDepth(dpy, ps->screen); - mw->visual = DefaultVisual(dpy, ps->screen); + if (ps->o.lazyTrans) { + mw->depth = 32; + mw->visual = ps->argb_visual; + if (!mw->visual) { + printfef(true, "(): Couldn't find ARGB visual, lazy transparency can't work."); + goto mainwin_create_err; + } + } + if (!ps->o.lazyTrans) { + mw->depth = DefaultDepth(dpy, ps->screen); + mw->visual = DefaultVisual(dpy, ps->screen); + } mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone); mw->format = XRenderFindVisualFormat(dpy, mw->visual); diff --git a/src/skippy.c b/src/skippy.c index 05081fb..cebdcdb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -622,6 +622,12 @@ skippy_activate(MainWin *mw, Window leader, bool paging) mw->xin_active = 0; #endif /* CFG_XINERAMA */ + // Map the main window and run our event loop + /*if (ps->o.lazyTrans) { + mainwin_map(mw); + XFlush(ps->dpy); + }*/ + mw->client_to_focus = NULL; daemon_count_clients(mw, 0, leader); @@ -649,6 +655,11 @@ skippy_activate(MainWin *mw, Window leader, bool paging) foreach_dlist(mw->clients) { ClientWin *cw = iter->data; + if (mw->ps->o.lazyTrans) + { + cw->x += cw->mainwin->x; + cw->y += cw->mainwin->y; + } cw->x *= mw->multiplier; cw->y *= mw->multiplier; } @@ -782,7 +793,7 @@ mainloop(session_t *ps, bool activate_on_start) { last_rendered = time_in_millis(); /* Map the main window and run our event loop */ - if (!mw->mapped) + if (!ps->o.lazyTrans && !mw->mapped) mainwin_map(mw); XFlush(ps->dpy); } @@ -794,7 +805,7 @@ mainloop(session_t *ps, bool activate_on_start) { ps->o.movePointerOnStart); /* Map the main window and run our event loop */ - if (!mw->mapped) + if (!ps->o.lazyTrans && !mw->mapped) mainwin_map(mw); XFlush(ps->dpy); } @@ -1550,6 +1561,7 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); + config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); config_get_bool_wrap(config, "general", "includeFrame", &ps->o.includeFrame); config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); diff --git a/src/skippy.h b/src/skippy.h index 9ce7c1d..a3c7bcf 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -195,6 +195,7 @@ typedef struct { bool acceptWMWin; double updateFreq; int animationDuration;; + bool lazyTrans; bool includeFrame; char *pipePath; bool movePointerOnStart; @@ -267,6 +268,7 @@ typedef struct { .acceptWMWin = false, \ .updateFreq = 60.0, \ .animationDuration = 200, \ + .lazyTrans = false, \ .includeFrame = false, \ .pipePath = NULL, \ .movePointerOnStart = true, \ From b48d5e6879d400f4bb5eedb293cd63b84327c2cd Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 11 Apr 2023 23:00:26 -0700 Subject: [PATCH 126/205] Correct mainwin_create() ordering --- src/mainwin.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mainwin.c b/src/mainwin.c index 506d40e..cf348c1 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -79,6 +79,19 @@ mainwin_create(session_t *ps) { mw->width = rootattr.width; mw->height = rootattr.height; + if (ps->o.lazyTrans) { + mw->depth = 32; + mw->visual = ps->argb_visual; + if (!mw->visual) { + printfef(true, "(): Couldn't find ARGB visual, lazy transparency can't work."); + goto mainwin_create_err; + } + } + else { + mw->depth = DefaultDepth(dpy, ps->screen); + mw->visual = DefaultVisual(dpy, ps->screen); + } + mw = mainwin_reload(ps, mw); if (!mw) goto mainwin_create_err; @@ -197,19 +210,6 @@ mainwin_reload(session_t *ps, MainWin *mw) { else mw->poll_time = (1.0 / 60.0) * 1000.0; - if (ps->o.lazyTrans) { - mw->depth = 32; - mw->visual = ps->argb_visual; - if (!mw->visual) { - printfef(true, "(): Couldn't find ARGB visual, lazy transparency can't work."); - goto mainwin_create_err; - } - } - if (!ps->o.lazyTrans) { - mw->depth = DefaultDepth(dpy, ps->screen); - mw->visual = DefaultVisual(dpy, ps->screen); - } - mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone); mw->format = XRenderFindVisualFormat(dpy, mw->visual); From 4eeca6ededf6e59c07cdfff4e0f752f6b40ea231 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 11 Apr 2023 23:07:31 -0700 Subject: [PATCH 127/205] Re-add mainwin_map for lazy transparency --- src/skippy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index cebdcdb..4365ad5 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -623,10 +623,10 @@ skippy_activate(MainWin *mw, Window leader, bool paging) #endif /* CFG_XINERAMA */ // Map the main window and run our event loop - /*if (ps->o.lazyTrans) { + if (ps->o.lazyTrans) { mainwin_map(mw); XFlush(ps->dpy); - }*/ + } mw->client_to_focus = NULL; From c8e445cf5a2e7de6665068980908a5c1a7403341 Mon Sep 17 00:00:00 2001 From: Nimrod Maclomhair Date: Wed, 19 Apr 2023 11:03:35 +0200 Subject: [PATCH 128/205] Reintroduce filtering of minimized windows --- skippy-xd.sample.rc | 4 ++++ src/skippy.c | 1 + src/skippy.h | 2 ++ src/wm.c | 4 ++-- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index ade393f..cd887af 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -90,6 +90,10 @@ switchDesktopOnActivate = false includeFrame = true allowUpscale = true showAllDesktops = true + +# Choose wether to show minimized windows +showUnmapped = true + cornerRadius = 5 preferredIconSize = 48 showIconsOnThumbnails = true diff --git a/src/skippy.c b/src/skippy.c index 05081fb..2ec0e16 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1555,6 +1555,7 @@ load_config_file(session_t *ps) config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); + config_get_bool_wrap(config, "general", "showUnmapped", &ps->o.showUnmapped); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); diff --git a/src/skippy.h b/src/skippy.h index 9ce7c1d..0aa6445 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -203,6 +203,7 @@ typedef struct { bool switchDesktopOnActivate; bool allowUpscale; bool showAllDesktops; + bool showUnmapped; int cornerRadius; int preferredIconSize; client_disp_mode_t *clientDisplayModes; @@ -280,6 +281,7 @@ typedef struct { .iconFillSpec = PICTSPECT_INIT, \ .fillSpec = PICTSPECT_INIT, \ .showAllDesktops = false, \ + .showUnmapped = true, \ .buttonImgs = { NULL }, \ .background = NULL, \ .xinerama_showAll = true, \ diff --git a/src/wm.c b/src/wm.c index 4c371d5..cd0dc3e 100644 --- a/src/wm.c +++ b/src/wm.c @@ -605,9 +605,9 @@ wm_validate_window(session_t *ps, Window wid) { prop = wid_get_prop(ps, wid, _NET_WM_STATE, 8192, XA_ATOM, 32); for (int i = 0; result && i < prop.nitems; i++) { long v = prop.data32[i]; - /*if (!ps->o.showUnmapped && _NET_WM_STATE_HIDDEN == v) + if (!ps->o.showUnmapped && _NET_WM_STATE_HIDDEN == v) result = false; - else*/ if (ps->o.ignoreSkipTaskbar + else if (ps->o.ignoreSkipTaskbar && _NET_WM_STATE_SKIP_TASKBAR == v) result = false; else if (_NET_WM_STATE_SHADED == v) From e27f1f20d18ab1b2bbbe07f3cbe7b1603f3bd30f Mon Sep 17 00:00:00 2001 From: Nimrod Maclomhair Date: Wed, 10 May 2023 10:54:41 +0200 Subject: [PATCH 129/205] Change name of showUnmapped to showMinimized --- skippy-xd.sample.rc | 2 +- src/skippy.c | 2 +- src/skippy.h | 4 ++-- src/wm.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index cd887af..53a0741 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -92,7 +92,7 @@ allowUpscale = true showAllDesktops = true # Choose wether to show minimized windows -showUnmapped = true +showMinimized = true cornerRadius = 5 preferredIconSize = 48 diff --git a/src/skippy.c b/src/skippy.c index 2ec0e16..70b87e2 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1555,7 +1555,7 @@ load_config_file(session_t *ps) config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); - config_get_bool_wrap(config, "general", "showUnmapped", &ps->o.showUnmapped); + config_get_bool_wrap(config, "general", "showMinimized", &ps->o.showMinimized); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); diff --git a/src/skippy.h b/src/skippy.h index 0aa6445..f279d72 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -203,7 +203,7 @@ typedef struct { bool switchDesktopOnActivate; bool allowUpscale; bool showAllDesktops; - bool showUnmapped; + bool showMinimized; int cornerRadius; int preferredIconSize; client_disp_mode_t *clientDisplayModes; @@ -281,7 +281,7 @@ typedef struct { .iconFillSpec = PICTSPECT_INIT, \ .fillSpec = PICTSPECT_INIT, \ .showAllDesktops = false, \ - .showUnmapped = true, \ + .showMinimized = true, \ .buttonImgs = { NULL }, \ .background = NULL, \ .xinerama_showAll = true, \ diff --git a/src/wm.c b/src/wm.c index cd0dc3e..40012b2 100644 --- a/src/wm.c +++ b/src/wm.c @@ -605,7 +605,7 @@ wm_validate_window(session_t *ps, Window wid) { prop = wid_get_prop(ps, wid, _NET_WM_STATE, 8192, XA_ATOM, 32); for (int i = 0; result && i < prop.nitems; i++) { long v = prop.data32[i]; - if (!ps->o.showUnmapped && _NET_WM_STATE_HIDDEN == v) + if (!ps->o.showMinimized && _NET_WM_STATE_HIDDEN == v) result = false; else if (ps->o.ignoreSkipTaskbar && _NET_WM_STATE_SKIP_TASKBAR == v) @@ -619,7 +619,7 @@ wm_validate_window(session_t *ps, Window wid) { else if (WMPSN_GNOME == ps->wmpsn) { // Check _WIN_STATE /*prop = wid_get_prop(ps, wid, _WIN_STATE, 1, XA_CARDINAL, 0); - if (!ps->o.showUnmapped && winprop_get_int(&prop) + if (!ps->o.showMinimized && winprop_get_int(&prop) & (WIN_STATE_MINIMIZED | WIN_STATE_SHADED | WIN_STATE_HIDDEN)) result = false; free_winprop(&prop);*/ From 604c29c97d8bf2a82c668c0f86f8b0a9bef8466f Mon Sep 17 00:00:00 2001 From: Nimrod Maclomhair Date: Wed, 10 May 2023 14:17:51 +0200 Subject: [PATCH 130/205] Change name of showMinimized to showShadow, enable filtering in GNOME compliant WMs --- skippy-xd.sample.rc | 2 +- src/skippy.c | 2 +- src/skippy.h | 4 ++-- src/wm.c | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 53a0741..ca76105 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -92,7 +92,7 @@ allowUpscale = true showAllDesktops = true # Choose wether to show minimized windows -showMinimized = true +showShadow = true cornerRadius = 5 preferredIconSize = 48 diff --git a/src/skippy.c b/src/skippy.c index 70b87e2..4db30fb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1555,7 +1555,7 @@ load_config_file(session_t *ps) config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); - config_get_bool_wrap(config, "general", "showMinimized", &ps->o.showMinimized); + config_get_bool_wrap(config, "general", "showShadow", &ps->o.showShadow); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); diff --git a/src/skippy.h b/src/skippy.h index f279d72..f7600dd 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -203,7 +203,7 @@ typedef struct { bool switchDesktopOnActivate; bool allowUpscale; bool showAllDesktops; - bool showMinimized; + bool showShadow; int cornerRadius; int preferredIconSize; client_disp_mode_t *clientDisplayModes; @@ -281,7 +281,7 @@ typedef struct { .iconFillSpec = PICTSPECT_INIT, \ .fillSpec = PICTSPECT_INIT, \ .showAllDesktops = false, \ - .showMinimized = true, \ + .showShadow = true, \ .buttonImgs = { NULL }, \ .background = NULL, \ .xinerama_showAll = true, \ diff --git a/src/wm.c b/src/wm.c index 40012b2..e220a70 100644 --- a/src/wm.c +++ b/src/wm.c @@ -605,7 +605,7 @@ wm_validate_window(session_t *ps, Window wid) { prop = wid_get_prop(ps, wid, _NET_WM_STATE, 8192, XA_ATOM, 32); for (int i = 0; result && i < prop.nitems; i++) { long v = prop.data32[i]; - if (!ps->o.showMinimized && _NET_WM_STATE_HIDDEN == v) + if (!ps->o.showShadow && _NET_WM_STATE_HIDDEN == v) result = false; else if (ps->o.ignoreSkipTaskbar && _NET_WM_STATE_SKIP_TASKBAR == v) @@ -618,11 +618,11 @@ wm_validate_window(session_t *ps, Window wid) { } else if (WMPSN_GNOME == ps->wmpsn) { // Check _WIN_STATE - /*prop = wid_get_prop(ps, wid, _WIN_STATE, 1, XA_CARDINAL, 0); - if (!ps->o.showMinimized && winprop_get_int(&prop) + prop = wid_get_prop(ps, wid, _WIN_STATE, 1, XA_CARDINAL, 0); + if (!ps->o.showShadow && winprop_get_int(&prop) & (WIN_STATE_MINIMIZED | WIN_STATE_SHADED | WIN_STATE_HIDDEN)) result = false; - free_winprop(&prop);*/ + free_winprop(&prop); if (result && ps->o.ignoreSkipTaskbar) { prop = wid_get_prop(ps, wid, _WIN_HINTS, 1, XA_CARDINAL, 0); From f8bc46b3e8874fe739e8e71fe27ba027de816299 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 18:06:12 -0700 Subject: [PATCH 131/205] Update read me, the old stuff is all moved to wiki --- README.md | 201 ++---------------------------------------------------- 1 file changed, 4 insertions(+), 197 deletions(-) diff --git a/README.md b/README.md index d62d2da..1c07786 100644 --- a/README.md +++ b/README.md @@ -1,200 +1,7 @@ -# Skippy-XD +Welcome to the skippy-xd wiki! -...is a full-screen, expose-style, task-switcher for X11. You know that thing Mac OS X, Gnome 3, Compiz and KWin do where you press a hotkey and suddenly you see miniature versions of all your windows at once? Skippy-XD does just that. +Skippy-xd is a lightweight, customizable, feature rich, window-manager-agnostic composite window selector for windows in the X server. With skippy, you get live-preview on your alt-tab motions; you get the much coveted expose feature from Mac; you get a handy overview of all your virtual desktops in one glance with paging mode. -Originally mirrored from [the Google Code project](https://code.google.com/p/skippy-xd/) this GitHub repo hosts the code of a fork from the original 0.5.0 release (2004), initially maintained by Nick Watts (2011) and Richard Grenville (2013). +If you want to fly around your daily window flow, if you want cool window motions that adds to your productivity, if you want to manage your windows like a boss, skippy-xd might be the thing for you. -Skippy-XD is a standalone application for providing a window picker with live previews (including live video) on Linux desktops that run an X server with compositing support. That means it's not baked into the window manager, and compositing is used only when the window picker is active. - -The performance of your window manager isn't degraded, and you get a window picker that's every bit as elegant as OSX's Exposé or KWin's "Present Windows", with all the desktop-navigational efficiency. - -**You can see a demo on [YouTube](http://www.youtube.com/watch?v=gVRPCd7OS38).** - -## Installation - -If you're using Ubuntu, you may simply install via the [Skippy-XD PPA.](https://launchpad.net/~landronimirc/+archive/skippy-xd) (or the [daily PPA](https://launchpad.net/~landronimirc/+archive/skippy-xd-daily/)). - -```sh -sudo add-apt-repository ppa:landronimirc/skippy-xd -sudo apt-get update -sudo apt-get install skippy-xd -``` - -### From Source - -To compile Skippy-XD from source you need to install the following development packages: - -```sh -apt-get install libimlib2-dev libfontconfig1-dev libfreetype6-dev libx11-dev libxext-dev libxft-dev -libxrender-dev zlib1g-dev libxinerama-dev libxcomposite-dev libxdamage-dev libxfixes-dev libxmu-dev -``` - -Now get the source, build and install: - -```sh -git clone https://github.com/dreamcat4/skippy-xd.git -cd skippy-xd -make -make install -``` - -## Usage - -### Config file - -Download the original `skippy-xd.rc-default` config file and copy it to `~/.config/skippy-xd/skippy-xd.rc` and edit it to your liking. - -### Command Line - -Once Skippy-XD is installed, you can run it by entering `skippy-xd` at the command line. This will start the program, activate the window picker once, then exit. However it is far better to keep the application running in the background as a daemon and just activate it when you want to use the window picker. - -```sh -skippy-xd --help -skippy-xd v0.5.2~pre (2018.09.09) - "Puzzlebox" Edition -Usage: skippy-xd [command] - -The available commands are: - --config - Read the specified configuration file. - --start-daemon - starts the daemon running. - --stop-daemon - stops the daemon running. - --activate-window-picker - tells the daemon to show the window picker. - --deactivate-window-picker - tells the daemon to hide the window picker. - --toggle-window-picker - tells the daemon to toggle the window picker. - --prev - launch initially focussed to previous selection. - --next - launch initially focussed to next selection. - - --help - show this message. - -S - Synchronize X operation (debugging). -PNG support: Yes - Compiled with libpng 1.6.34, using 1.6.34. - Compiled with zlib 1.2.11, using 1.2.11. -``` - -### skippy-xd-runner - -However, sometimes skippy won't activate properly. This can either be because it launches too quickly, and receives the last Return key press event, that was used to launch it by. Or because when bound to a global key binding, and when the key is being held down. Then the key repeats and skippy will be activated far too much, causing the daemon to lock up. Because it is getting many more requests than it can actually handle. Over it's simple FIFO buffer loop. - -To try to address those kinds of problems, we now include the wrapper script `skippy-xd-runner`. However it is not an ideal solution and introduces new problems of it's own. Ideally we should prefer to upgrade or replace the FIFO queue (file socket) / polling of `read()`. With someting a bit less dumb. - -Anyhow, for the time being `skippy-xd-runner` is a useful safeguard. To prevent lockups of your window manager (or whatever your parent process) that is activating skippy. Those types of background usage / invokation of skippy are discussed in more detail in the next sections. - -### Keyboard Shortcuts - -There are 2 types of keyboard shortcuts. Global keyboard shortcuts, and skippy's own keyboard shortcuts, for when the skippy window picker becomes activated. - - -#### Global keyboard shortcuts - -Firstly, there are global keyboard shortcuts, to be configured for invoking / launching Skippy. How to setup a global keyboard shortcut depends entirely on your chosen window manager. So we cannot provide you with specific instructions in that regard. But here are some links for a few of them: - -* Budgie: https://gist.github.com/dreamcat4/bc4d6e6b6959901bf641f03b3c18462e -* Xfce: http://wiki.xfce.org/faq#keyboard -* Openbox: https://urukrama.wordpress.com/openbox-guide/#Key_mouse -* Fluxbox: http://fluxbox-wiki.org/index.php/Keyboard_shortcuts#How_to_use_the_keys_file - -It is recommended (best way) to set `skippy-xd --start-daemon` to be run after login. By adding it to the Startup Applications of your window manager. Then you should bind `skippy-xd-runner --toggle`, or `skippy-xd-runner --activate` to your preferred global keyboard shortcut. For most people, that will be `Alt+Tab` or `Super+Tab`. - -Quite a few window managers already assign `Alt+Tab` (or `Super+Tab`) to something else. Like their own built-in Alt-Tab feature. So you might also need to figure out how to un-bind those pre-existing shortcuts, before you can re-assign them to Skippy-XD instead. - -#### Program Keyboard Shortcuts - -Once skippy is launched, it then has it's own set of keyboard shortcuts. These are fully configurable. You can specify your own values in your `skippy-xd.rc` configuration file. Should you need to override any of the defaults. To find the right key symbol names (keysyms) for regular keypress and/or key release events. For all the keybindings settings. Please use the program `xev` to probe for them. By typing / pressing the keys on your keyboard. Which is explained in the next section. - -The sample config file `skippy-xd.sample.rc` shows all the default keyboard shortcuts. They in the `[bindings]` section, at the bottom of the file. - -Normally, you will want them to be consistent with your chosen Global Keyboard Shortcut(s). As was described earlier (for invoking skippy). The default values have already been chosen to match program invocation via `Alt+Tab` and/or `Super+Tab`. This includes releasing the `Alt` key, or the `Super` key. Which will to select the currently highlighed item. As is consistent with `Alt-Tab` behaviour on other platforms. - -Along with the above Key Bindings, there finally also a setting for specifying certain modifier keys. Which will reverse the direction od Alt-Tabbing. These can only be one of the special modifiers listed below. Rather than just any arbitrary key. Normally this function is mapped to either `Shift` and/or the `Control` modifier key. So those are the default. For example `Shift+Alt+Tab` will make skippy cycle backwards through the open windows. Again, the default value is chosen to be consistent with the expected Alt-Tabbing behaviour, as it is on other platforms. - -However if you need to change it, then the masks which Skippy knows about / recognizes are listed near the bottom of `src/skippy.h` in a pair of lookup tables named `ev_modifier_mask` and `ev_modifier_mask_str`. Which were taken out from the original X windows header file `/usr/include/X11/X.h`. The current version of skippy knows about these X modifiers: - -```c -static const int ev_modifier_mask[] = // { ... holds the lookup values } - -static const char *ev_modifier_mask_str[] = \ -{ - "ShiftMask", - "LockMask", - "ControlMask", - "Mod1Mask", - "Mod2Mask", - "Mod3Mask", - "Mod4Mask", - "Mod5Mask", - "Button1Mask", - "Button2Mask", - "Button3Mask", - "Button4Mask", - "Button5Mask", - "AnyModifier", - 0x00 -}; -``` - -As it turns out, it's possible hold down a mouse button istead. As another type of modifier key. This is just to reverse the tabbing direction in skippy. If you wish to configure custom direction modifier(s), then you can just append them to the relevant setting `modifierKeyMasksReverseDirection`. Which is in the `[bindings]` section of your Skippy RC file. - -#### How to identify keysyms with xev - -Run the program `xev` in a terminal window. Then press the keys you are interested in. Observe the output. - -***Example:*** - -Here is the name of the keysym on my keyboard for the Right Alt key. It is `ISO_Level3_Shift`. But it may be different for your keyboard. - -```sh -KeyPress event, serial 38, synthetic NO, window 0x6000001, - root 0x1e7, subw 0x0, time 29447789, (159,-18), root:(311,152), - state 0x0, keycode 108 (keysym 0xfe03, ISO_Level3_Shift), same_screen YES, - XKeysymToKeycode returns keycode: 92 - XLookupString gives 0 bytes: - XmbLookupString gives 0 bytes: - XFilterEvent returns: False - -KeyRelease event, serial 38, synthetic NO, window 0x6000001, - root 0x1e7, subw 0x0, time 29447853, (159,-18), root:(311,152), - state 0x80, keycode 108 (keysym 0xfe03, ISO_Level3_Shift), same_screen YES, - XKeysymToKeycode returns keycode: 92 - XLookupString gives 0 bytes: - XFilterEvent returns: False -``` - -***Note 1:*** - -Key strings are case sensitive. So `alt_l` will not work - it will no match anything at all. You need to use the exact capitalization as it appears in the output from the `xev` program. For example `Alt_L` is a valid key name. - -***Note 2:*** - -Be sure to separate with ` ` spaces each keybinding in a given setting. Like `keysLeft = Left b a h B A H` for example. You cannot use commas `, ; :` or other special characters in the keybindings settings in the `[bindings]` section of the skippy rc file. Otherwise it won't work. - -## See Also - -* [Skippy-XD on Ubuntu Wiki](https://wiki.ubuntu.com/Skippy) -* [Skippy-XD on Google Code](https://code.google.com/p/skippy-xd/) -* [Original home of Skippy-XD](http://thegraveyard.org/skippy.html) -* [Skippy-XD on freecode](http://freecode.com/projects/skippy) - -## Maintainership / Contributions - -* Creator: Hyriand (2004) - This makes skippy-xd 19 years old now... -* Current lead developer: `felixfung`. Who has made some fantastic improvements to skippy-xd during the year 2023+ -* Contributions from: `richardgv`, `dreamcat4`, `felixfung`, `cezaris13`, and many others (please edit this line to add any here missing contributor credits) -* Maintenance / Secondary supportive role: `dreamcat4` -* Previous stable maintiner: `richardgv`. - -Richard's upstreamm repo was previously where the majority of Skippy issues were raised. A bug tracker is still over [on his fork](https://github.com/richardgv/skippy-xd/issues). With all older legacy issues. However at this time, it looks like, (as Richard had previously indicated) that he really does not have time anymore to continue to maintain this software (since 2015). But he is welcome to come back and see what developements have been going on in his absense! - -In the meanntime we maintain new bugs tracker, here on this fork. And welcome any contributions / PRs. - -This project is in need of more contributors, and perhaps a new maintainer. Best thing we can do is just continue along over here. Adding whatever feature(s) & bugfixes ontop of the latest version. - -## Developer notes - -A top priority (very important) is not to be super-picky about this but: make safe changes to the code. Do not do anything that is *too risky* or over-extend yourself. Definately play on the safe side. - -Here are 3 basic safeguard mechanisms you can use in this project: - -1) Uncomment the `--test` developer test mode. And use it as a temporary sandbox to test any new library functions that you need to add. Throw bad input at all your new funtions. Specifically try to catch errors regarding the memory management. Bad pointers, not checking for null, etc. And when such a bug is found, try to use that as a reason for justifying a further scrutinyg / enhancement of your error handling, in your new code. Spend the vast majority of your developer time just writing the parts of the code that does the error handling. I estimate that I spend something like around 75% of my time doing that, and catching errors. With the remaining 25% of my time (or even less than that) on the actual 'doing stuff' new code that not library functinos. I.e. working in the existing skippy code paths / where I was actually trying to implement the new feature. That 'felt right' (for me) in C. Particularly because C has is no garbage collection / pointer safety, etc. And a large percentage of my bugs (perhaps about half of them!) were almost completely hidden to me, unless the code was actually exercised with bad input. In order to exercise those non-critical code paths. - -2) Run the program `valgrind` on the executable. To check for memory leaks. Try to exercise all of the code pathways that your change touches. To make sure nothing is missed. The results of `valgrind` should also help you to guage whether your error checking and code quality practices in step 1) were thorough enough (or not, in which case, go back to step 1). For those people who don't like valgrind, for the leak testing, then (on `clang` compiler) you can add some flags like `-fsanitize=address` to enable the clang address sanitizer. This will create a debug version of the binary. Note that: I have not tried that myself. It requires some further changes to skippy's `Makefile`... More information about how to setup the clang address sanitizer (aka `asan`), can be found [on this wiki page here](https://github.com/google/sanitizers/wiki/AddressSanitizer). - -3) Compile in developer mode. Which switches on all of the compiler warnings. There is a lot of noise / output. But you can save the output before and after. Then use the `diff` program to filter out and see which new warnings were due to your new code changes. Compile in dev mode like this: `make clean && CFG_DEV=true make`. Dev mode is also the way to produce a debug binary, with gdb symbols, etc. +Checkout the wiki for gallery, how to use, config options, and other info. From d346f1834c47b0868d18913f1c1b7d1f56b7bdb9 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 18:14:56 -0700 Subject: [PATCH 132/205] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c07786..38dab2e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Welcome to the skippy-xd wiki! +Welcome to skippy-xd! Skippy-xd is a lightweight, customizable, feature rich, window-manager-agnostic composite window selector for windows in the X server. With skippy, you get live-preview on your alt-tab motions; you get the much coveted expose feature from Mac; you get a handy overview of all your virtual desktops in one glance with paging mode. From 1d62b6c5f3e21d2903c6d40196c586dfa57797e3 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 18:48:20 -0700 Subject: [PATCH 133/205] XSync to increase chance of proper focus on paging --- src/skippy.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 6c9b2d7..0842e1b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -831,13 +831,11 @@ mainloop(session_t *ps, bool activate_on_start) { // keyboard gets ungrabbed. if (mw->client_to_focus) { if (paging) { - childwin_focus(mw->client_to_focus); wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); - //daemon_count_clients(mw, 0, 0); - //mw->client_to_focus = dlist_first(mw->clientondesktop)->data; + XSync(ps->dpy, True); + XSync(ps->dpy, False); } - else - childwin_focus(mw->client_to_focus); + childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; refocus = false; pending_damage = false; From 49ec6973d0606b64d820cf1d34616b6c196c15dd Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 18:49:54 -0700 Subject: [PATCH 134/205] Whitespace --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 0842e1b..582d96b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -835,7 +835,7 @@ mainloop(session_t *ps, bool activate_on_start) { XSync(ps->dpy, True); XSync(ps->dpy, False); } - childwin_focus(mw->client_to_focus); + childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; refocus = false; pending_damage = false; From 33a84d1f11281be580eeca5931a8408f8c85a19a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 22:36:22 -0700 Subject: [PATCH 135/205] Entry points for switcher, expose, paging --- skippy-xd.sample.rc | 11 +--- src/layout.c | 8 ++- src/layout.h | 2 +- src/skippy.c | 136 +++++++++++++++++++++++++++++++++----------- src/skippy.h | 14 +++-- 5 files changed, 122 insertions(+), 49 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 1d04f59..ab22a87 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -57,14 +57,9 @@ [general] -# layout=boxy is favoured by expo usage -# layout=xd is favoured by alt+tab usage -layout = boxy - -# sort by row or sort by column -# sorting by column is favoured by boxy layout -# sorting by row is favoured by xd layout -sortByColumn = true +# exposeLayout=xd uses the same layout as switcher, maximizing screen estate +# exposeLayout=boxy tends to preserve window positions, thus guiding the eye more +exposeLayout = boxy distance = 50 useNetWMFullscreen = true diff --git a/src/layout.c b/src/layout.c index acb95ed..dc04bdb 100644 --- a/src/layout.c +++ b/src/layout.c @@ -38,10 +38,12 @@ // and calculating the final screen width and height // = total windows width and height + minimal distance between windows void layout_run(MainWin *mw, dlist *windows, - unsigned int *total_width, unsigned int *total_height) { - if (mw->ps->o.layout == LAYOUT_BOXY) + unsigned int *total_width, unsigned int *total_height, + enum layoutmode layout) { + if (layout == LAYOUTMODE_EXPOSE + && mw->ps->o.exposeLayout == LAYOUT_BOXY) layout_boxy(mw, windows, total_width, total_height); - else if (mw->ps->o.layout == LAYOUT_XD) + else layout_xd(mw, windows, total_width, total_height); } diff --git a/src/layout.h b/src/layout.h index 1e90909..ec6cc22 100644 --- a/src/layout.h +++ b/src/layout.h @@ -22,7 +22,7 @@ // calculate and populate windows destination positions // switches to different layout algorithms based on user/default config -void layout_run(MainWin *, dlist *, unsigned int *, unsigned int *); +void layout_run(MainWin *, dlist *, unsigned int *, unsigned int *, enum layoutmode); void layout_xd(MainWin *, dlist *, unsigned int *, unsigned int *); void layout_boxy(MainWin *, dlist *, unsigned int *, unsigned int *); int boxy_affinity(ClientWin *, int, int, int, int, int, int); diff --git a/src/skippy.c b/src/skippy.c index 582d96b..345dfb4 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -31,7 +31,9 @@ bool debuglog = false; enum pipe_cmd_t { // Not ordered properly for backward compatibility PIPECMD_RELOAD_CONFIG = 0, - PIPECMD_ACTIVATE_EXPOSE = 1, + PIPECMD_ACTIVATE_SWITCHER = 1, + PIPECMD_TOGGLE_SWITCHER, + PIPECMD_ACTIVATE_EXPOSE, PIPECMD_TOGGLE_EXPOSE, PIPECMD_ACTIVATE_PAGING, PIPECMD_TOGGLE_PAGING, @@ -366,7 +368,7 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) } static bool -init_layout(MainWin *mw, Window focus, Window leader) +init_layout(MainWin *mw, Window focus, Window leader, enum layoutmode layout) { if (!mw->clientondesktop) return true; @@ -376,14 +378,14 @@ init_layout(MainWin *mw, Window focus, Window leader) /* set up the windows layout */ { unsigned int newwidth = 0, newheight = 0; - layout_run(mw, mw->clientondesktop, &newwidth, &newheight); + layout_run(mw, mw->clientondesktop, &newwidth, &newheight, layout); // ordering of client windows list // is important for prev/next window selection - if (mw->ps->o.sortByColumn) - dlist_sort(mw->clientondesktop, sort_cw_by_column, 0); - else + if (layout == LAYOUTMODE_SWITCHER) dlist_sort(mw->clientondesktop, sort_cw_by_row, 0); + else /*if (layout == LAYOUTMODE_EXPOSE)*/ + dlist_sort(mw->clientondesktop, sort_cw_by_column, 0); mw->focuslist = mw->clientondesktop; float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; @@ -696,7 +698,7 @@ init_focus(MainWin *mw, Window leader) { } static bool -skippy_activate(MainWin *mw, Window leader, bool paging) +skippy_activate(MainWin *mw, Window leader, enum layoutmode layout) { session_t *ps = mw->ps; @@ -724,15 +726,15 @@ skippy_activate(MainWin *mw, Window leader, bool paging) clientwin_update2((ClientWin *) iter->data); } - if (paging) { + if (layout == LAYOUTMODE_PAGING) { if (!init_paging_layout(mw, mw->revert_focus_win, leader)) { printfef(false, "(): init_paging_layout() failed."); return false; } } else { - if (!init_layout(mw, mw->revert_focus_win, leader)) { - printfef(false, "(): init_layout() failed."); + if (!init_layout(mw, mw->revert_focus_win, leader, layout)) { + printfef(false, "(): init_expose_layout() failed."); return false; } } @@ -783,10 +785,24 @@ mainloop(session_t *ps, bool activate_on_start) { bool refocus = false; bool pending_damage = false; long last_rendered = 0L; - bool paging = ps->o.mode == PROGMODE_ACTV_PAGING; + enum layoutmode layout = LAYOUTMODE_SWITCHER; bool animating = activate; long first_animated = 0L; + switch (ps->o.mode) { + case PROGMODE_ACTV_EXPOSE: + case PROGMODE_TGG_EXPOSE: + layout = LAYOUTMODE_EXPOSE; + break; + case PROGMODE_ACTV_PAGING: + case PROGMODE_TGG_PAGING: + layout = LAYOUTMODE_PAGING; + break; + default: + layout = LAYOUTMODE_SWITCHER; + break; + } + struct pollfd r_fd[2] = { { .fd = ConnectionNumber(ps->dpy), @@ -808,7 +824,7 @@ mainloop(session_t *ps, bool activate_on_start) { assert(ps->mainwin); activate = false; - if (skippy_activate(ps->mainwin, None, paging)) { + if (skippy_activate(ps->mainwin, None, layout)) { last_rendered = time_in_millis(); mw = ps->mainwin; refocus = false; @@ -830,7 +846,7 @@ mainloop(session_t *ps, bool activate_on_start) { // Focus the client window only after the main window get unmapped and // keyboard gets ungrabbed. if (mw->client_to_focus) { - if (paging) { + if (layout == LAYOUTMODE_PAGING) { wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); XSync(ps->dpy, True); XSync(ps->dpy, False); @@ -887,7 +903,8 @@ mainloop(session_t *ps, bool activate_on_start) { // animation! if (mw && animating) { int timeslice = time_in_millis() - first_animated; - if (timeslice < ps->o.animationDuration + if (layout != LAYOUTMODE_SWITCHER + && timeslice < ps->o.animationDuration && timeslice + first_animated >= last_rendered + ps->mainwin->poll_time) { anime(ps->mainwin, ps->mainwin->clients, @@ -906,7 +923,7 @@ mainloop(session_t *ps, bool activate_on_start) { focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointerOnStart); - if (paging) { + if (layout == LAYOUTMODE_PAGING) { foreach_dlist (mw->dminis) { desktopwin_map(((ClientWin *) iter->data)); } @@ -1020,7 +1037,7 @@ mainloop(session_t *ps, bool activate_on_start) { tooltip_handle(mw->tooltip, &ev); else if (mw && wid) { dlist *iter = mw->clientondesktop; - if (paging) + if (layout == LAYOUTMODE_PAGING) iter = mw->dminis; for (; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; @@ -1044,7 +1061,7 @@ mainloop(session_t *ps, bool activate_on_start) { clientwin_repair(iter->data); } - if (paging) { + if (layout == LAYOUTMODE_PAGING) { foreach_dlist (mw->dminis) { desktopwin_map(((ClientWin *) iter->data)); } @@ -1081,11 +1098,23 @@ mainloop(session_t *ps, bool activate_on_start) { load_config_file(ps); mainwin_reload(ps, ps->mainwin); break; + case PIPECMD_ACTIVATE_SWITCHER: case PIPECMD_ACTIVATE_EXPOSE: case PIPECMD_ACTIVATE_PAGING: - paging = piped_input == PIPECMD_ACTIVATE_PAGING; - ps->o.mode = paging? PROGMODE_ACTV_PAGING: PROGMODE_ACTV_EXPOSE; - printfdf(false, "(): case PIPECMD_ACTIVATE, paging=%d:", paging); + if (piped_input == PIPECMD_ACTIVATE_SWITCHER) { + ps->o.mode = PROGMODE_ACTV_SWITCHER; + layout = LAYOUTMODE_SWITCHER; + } + else if (piped_input == PIPECMD_ACTIVATE_EXPOSE) { + ps->o.mode = PROGMODE_ACTV_EXPOSE; + layout = LAYOUTMODE_EXPOSE; + } + else /* if (piped_input == PIPECMD_ACTIVATE_PAGING) */ { + ps->o.mode = PROGMODE_ACTV_PAGING; + layout = LAYOUTMODE_PAGING; + } + + printfdf(false, "(): case PIPECMD_ACTIVATE, mode=%d", layout); if (ps->mainwin->mapped) { printfdf(false, "(): if (ps->mainwin->mapped)"); @@ -1122,15 +1151,27 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw) die = true; break; + case PIPECMD_TOGGLE_SWITCHER: case PIPECMD_TOGGLE_EXPOSE: case PIPECMD_TOGGLE_PAGING: if (mw) die = true; else { animating = activate = true; - paging = piped_input == PIPECMD_TOGGLE_PAGING; - ps->o.mode = paging? PROGMODE_TGG_PAGING: PROGMODE_TGG_EXPOSE; + if (piped_input == PIPECMD_TOGGLE_SWITCHER) { + ps->o.mode = PROGMODE_TGG_SWITCHER; + layout = LAYOUTMODE_SWITCHER; + } + else if (piped_input == PIPECMD_TOGGLE_EXPOSE) { + ps->o.mode = PROGMODE_TGG_EXPOSE; + layout = LAYOUTMODE_EXPOSE; + } + else /* if (piped_input == PIPECMD_TOGGLE_PAGING) */ { + ps->o.mode = PROGMODE_TGG_PAGING; + layout = LAYOUTMODE_PAGING; + } } + printfdf(false, "(): case PIPECMD_TOGGLE, mode=%d", layout); break; case PIPECMD_EXIT_DAEMON: printfdf(false, "(): Exit command received, killing daemon..."); @@ -1195,6 +1236,12 @@ queue_initial_focus_next(const char *pipePath) { return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_NEXT, pipePath); } +static inline bool +activate_switcher(const char *pipePath) { + printfdf(false, "(): Activating switcher..."); + return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_SWITCHER, pipePath); +} + static inline bool activate_expose(const char *pipePath) { printfdf(false, "(): Activating expose..."); @@ -1219,6 +1266,12 @@ deactivate(const char *pipePath) { return send_command_to_daemon_via_fifo(PIPECMD_DEACTIVATE, pipePath); } +static inline bool +toggle_switcher(const char *pipePath) { + printfdf(false, "(): Toggling switcher..."); + return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_SWITCHER, pipePath); +} + static inline bool toggle_expose(const char *pipePath) { printfdf(false, "(): Toggling expose..."); @@ -1310,11 +1363,13 @@ show_help() { " --config - read the specified configuration file.\n" " --start-daemon - starts the daemon running.\n" " --stop-daemon - stops the daemon running.\n" + " --activate-switcher - connects to daemon and activate switcher.\n" + " --toggle-switcher - connects to daemon and toggle switcher.\n" " --activate-expose - connects to daemon and activate expose.\n" " --toggle-expose - connects to daemon and toggle expose.\n" " --activate-paging - connects to daemon and activate paging.\n" " --toggle-paging - connects to daemon and toggle paging.\n" - " --deactivate - connects to daemon and deactivate expose or paging.\n" + " --deactivate - connects to daemon and deactivate switcher, expose or paging.\n" " --prev - focus window to previous.\n" " --next - focus window to next.\n" // " --test - Temporary development testing. To be removed.\n" @@ -1473,6 +1528,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { enum options { OPT_CONFIG = 256, OPT_CONFIG_RELOAD, + OPT_ACTV_SWITCHER, + OPT_TGG_SWITCHER, OPT_ACTV_EXPOSE, OPT_TGG_EXPOSE, OPT_ACTV_PAGING, @@ -1488,6 +1545,8 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { { "help", no_argument, NULL, 'h' }, { "config", required_argument, NULL, OPT_CONFIG }, { "config-reload", no_argument, NULL, OPT_CONFIG_RELOAD }, + { "activate-switcher", no_argument, NULL, OPT_ACTV_SWITCHER }, + { "toggle-switcher", no_argument, NULL, OPT_TGG_SWITCHER }, { "activate-expose", no_argument, NULL, OPT_ACTV_EXPOSE }, { "toggle-expose", no_argument, NULL, OPT_TGG_EXPOSE }, { "activate-paging", no_argument, NULL, OPT_ACTV_PAGING }, @@ -1545,6 +1604,12 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG_RELOAD: ps->o.mode = PROGMODE_RELOAD_CONFIG; break; + case OPT_ACTV_SWITCHER: + ps->o.mode = PROGMODE_ACTV_SWITCHER; + break; + case OPT_TGG_SWITCHER: + ps->o.mode = PROGMODE_TGG_SWITCHER; + break; case OPT_ACTV_EXPOSE: ps->o.mode = PROGMODE_ACTV_EXPOSE; break; @@ -1657,23 +1722,22 @@ load_config_file(session_t *ps) } { - const char *s = config_get(config, "general", "layout", NULL); + const char *s = config_get(config, "general", "exposeLayout", NULL); if (s) { if (strcmp(s,"boxy") == 0) { - ps->o.layout = LAYOUT_BOXY; + ps->o.exposeLayout = LAYOUT_BOXY; } else if (strcmp(s,"xd") == 0) { - ps->o.layout = LAYOUT_XD; + ps->o.exposeLayout = LAYOUT_XD; } else { - ps->o.layout = LAYOUT_BOXY; + ps->o.exposeLayout = LAYOUT_BOXY; } } else - ps->o.layout = LAYOUT_BOXY; + ps->o.exposeLayout = LAYOUT_BOXY; } - config_get_bool_wrap(config, "general", "sortByColumn", &ps->o.sortByColumn); config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); config_get_bool_wrap(config, "general", "ignoreSkipTaskbar", &ps->o.ignoreSkipTaskbar); @@ -1825,6 +1889,7 @@ int main(int argc, char *argv[]) { switch (ps->o.mode) { case PROGMODE_NORMAL: break; + case PROGMODE_ACTV_SWITCHER: case PROGMODE_ACTV_EXPOSE: case PROGMODE_ACTV_PAGING: if(ps->o.focus_initial) @@ -1838,11 +1903,14 @@ int main(int argc, char *argv[]) { // we must pause slightly, otherwise will miss next read() call in this loop() usleep(10000); } - if (ps->o.mode == PROGMODE_ACTV_EXPOSE) + if (ps->o.mode == PROGMODE_ACTV_SWITCHER) + activate_switcher(pipePath); + else if (ps->o.mode == PROGMODE_ACTV_EXPOSE) activate_expose(pipePath); - else + else if (ps->o.mode == PROGMODE_ACTV_PAGING) activate_paging(pipePath); goto main_end; + case PROGMODE_TGG_SWITCHER: case PROGMODE_TGG_EXPOSE: case PROGMODE_TGG_PAGING: if(ps->o.focus_initial) @@ -1855,9 +1923,11 @@ int main(int argc, char *argv[]) { // we must pause slightly, otherwise will miss next read() call in this loop() usleep(10000); } - if (PROGMODE_TGG_EXPOSE == ps->o.mode) + if (ps->o.mode == PROGMODE_TGG_SWITCHER) + toggle_switcher(pipePath); + else if (ps->o.mode == PROGMODE_TGG_EXPOSE) toggle_expose(pipePath); - else + else if (ps->o.mode == PROGMODE_TGG_PAGING) toggle_paging(pipePath); goto main_end; case PROGMODE_DEACTV: diff --git a/src/skippy.h b/src/skippy.h index 5f3bf29..385452f 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -84,6 +84,8 @@ enum { enum progmode { PROGMODE_NORMAL, + PROGMODE_ACTV_SWITCHER, + PROGMODE_TGG_SWITCHER, PROGMODE_ACTV_EXPOSE, PROGMODE_TGG_EXPOSE, PROGMODE_ACTV_PAGING, @@ -93,6 +95,12 @@ enum progmode { PROGMODE_DM_STOP, }; +enum layoutmode { + LAYOUTMODE_SWITCHER, + LAYOUTMODE_EXPOSE, + LAYOUTMODE_PAGING, +}; + enum cliop { CLIENTOP_NO, CLIENTOP_FOCUS, @@ -187,8 +195,7 @@ typedef struct { bool runAsDaemon; int focus_initial; - int layout; - bool sortByColumn; + int exposeLayout; int distance; bool useNetWMFullscreen; bool ignoreSkipTaskbar; @@ -261,8 +268,7 @@ typedef struct { .mode = PROGMODE_NORMAL, \ .runAsDaemon = false, \ \ - .layout = LAYOUT_XD, \ - .sortByColumn = true, \ + .exposeLayout = LAYOUT_BOXY, \ .distance = 50, \ .useNetWMFullscreen = true, \ .ignoreSkipTaskbar = false, \ From 6df5f684e05237f031ff6985a1bd84691bd790c6 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 22:46:12 -0700 Subject: [PATCH 136/205] Make switcher activation a bit faster --- src/skippy.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 345dfb4..b9fcb1f 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -889,16 +889,6 @@ mainloop(session_t *ps, bool activate_on_start) { if (activate_on_start && !mw) return; - // Poll for events - int timeout = ps->mainwin->poll_time; - int time_offset = last_rendered - time_in_millis(); - timeout -= time_offset; - if (timeout < 0) - timeout = 0; - if (pending_damage) - timeout = 0; - poll(r_fd, (r_fd[1].fd >= 0 ? 2: 1), timeout); - { // animation! if (mw && animating) { @@ -1077,6 +1067,16 @@ mainloop(session_t *ps, bool activate_on_start) { XFlush(ps->dpy); } + // Poll for events + int timeout = ps->mainwin->poll_time; + int time_offset = last_rendered - time_in_millis(); + timeout -= time_offset; + if (timeout < 0) + timeout = 0; + if (pending_damage) + timeout = 0; + poll(r_fd, (r_fd[1].fd >= 0 ? 2: 1), timeout); + // Handle daemon commands if (POLLIN & r_fd[1].revents) { unsigned char piped_input = 0; From a0ef6f48aa12e9f0d32a41c32a99331bd19bd90a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 17 May 2023 23:03:30 -0700 Subject: [PATCH 137/205] Default shadow appearance is reduced alpha, rather than dark tint --- skippy-xd.sample.rc | 4 ++-- src/skippy.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index ab22a87..9d8f41b 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -112,8 +112,8 @@ opacity = 255 [shadow] tint = #040404 -tintOpacity = 164 -opacity = 200 +tintOpacity = 0 +opacity = 128 [tooltip] show = true diff --git a/src/skippy.h b/src/skippy.h index 385452f..d959459 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -301,8 +301,8 @@ typedef struct { .highlight_tintOpacity = 64, \ .highlight_opacity = 255, \ .shadow_tint = NULL, \ - .shadow_tintOpacity = 164, \ - .shadow_opacity = 200, \ + .shadow_tintOpacity = 0, \ + .shadow_opacity = 128, \ .tooltip_show = true, \ .tooltip_followsMouse = true, \ .tooltip_offsetX = 20, \ From fa895911fd7bf65bda956e04840e06a77c3a67d6 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 22 May 2023 18:05:48 -0700 Subject: [PATCH 138/205] Animation always at 60 fps --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index b9fcb1f..84b5fdf 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -896,7 +896,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (layout != LAYOUTMODE_SWITCHER && timeslice < ps->o.animationDuration && timeslice + first_animated >= - last_rendered + ps->mainwin->poll_time) { + last_rendered + (1000.0 / 60.0)) { anime(ps->mainwin, ps->mainwin->clients, ((float)timeslice)/(float)ps->o.animationDuration); last_rendered = time_in_millis(); From 184561b2d153d74dd9f638dc9784fe5029cbca79 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 25 May 2023 18:37:17 -0700 Subject: [PATCH 139/205] Fix segfault when no windows on all desktops --- src/skippy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/skippy.c b/src/skippy.c index 84b5fdf..abbce3c 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -721,6 +721,10 @@ skippy_activate(MainWin *mw, Window leader, enum layoutmode layout) mw->client_to_focus = NULL; daemon_count_clients(mw, 0, leader); + if (!mw->clients || !mw->clientondesktop) { + return false; + } + foreach_dlist(mw->clients) { clientwin_update((ClientWin *) iter->data); clientwin_update2((ClientWin *) iter->data); From f860a05eff71a479c6496a6b23646915183adadf Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 25 May 2023 19:29:23 -0700 Subject: [PATCH 140/205] Flush pipes --- src/skippy.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 84b5fdf..36f5a46 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1959,14 +1959,9 @@ int main(int argc, char *argv[]) { // Daemon mode if (ps->o.runAsDaemon) { - bool flush_file = false; printfdf(false, "(): Running as daemon..."); - // Flush file if we could access() it (or, usually, if it exists) - if (!access(pipePath, R_OK)) - flush_file = true; - { int result = mkfifo(pipePath, S_IRUSR | S_IWUSR); if (result < 0 && EEXIST != errno) { @@ -1983,9 +1978,10 @@ int main(int argc, char *argv[]) { goto main_end; } assert(ps->fd_pipe >= 0); - if (flush_file) { + + { char *buf[BUF_LEN]; - while (read(ps->fd_pipe, buf, sizeof(buf)) > 0) + while (read(ps->fd_pipe, buf, sizeof(buf))) continue; printfdf(false, "(): Finished flushing pipe \"%s\".", pipePath); } From 07a0cbc0b99cdd4f5602e6639ee38bd8c07e808e Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 2 Jun 2023 02:39:29 -0700 Subject: [PATCH 141/205] Always focus on some window via XSetInputFocus() --- src/skippy.c | 1 + src/wm.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 6aafa6e..c807001 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -854,6 +854,7 @@ mainloop(session_t *ps, bool activate_on_start) { wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); XSync(ps->dpy, True); XSync(ps->dpy, False); + XSetInputFocus(ps->dpy, PointerRoot, RevertToPointerRoot, CurrentTime); } childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; diff --git a/src/wm.c b/src/wm.c index e220a70..f2b8ecd 100644 --- a/src/wm.c +++ b/src/wm.c @@ -675,8 +675,12 @@ wm_get_focused(session_t *ps) { { int revert_to = 0; if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { - printfdf(false, "(): Failed to get current focused window."); - return None; + printfdf(false, "(): Currently not focused on any window; trying to find focus..."); + XSetInputFocus(ps->dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { + printfdf(false, "(): Failed to get current focused window."); + return None; + } } printfdf(false, "(): Focused window is %#010lx.", focused); } From 9b140a4936c96793a70ccdbb982bdfec36ad818a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 7 Jun 2023 23:44:57 -0700 Subject: [PATCH 142/205] Fixed bad experience when on window is focused --- src/skippy.c | 21 ++++++++++----------- src/wm.c | 4 ++-- src/wm.h | 6 ++++++ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index c807001..3136984 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -689,12 +689,15 @@ init_focus(MainWin *mw, Window leader) { // then clear this flag, so daemon not remember on its next activation ps->o.focus_initial = 0; - if (!iter) - return; - - mw->client_to_focus = (ClientWin *) iter->data; - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; - mw->client_to_focus->focused = 1; + if (!iter) { + mw->client_to_focus = NULL; + mw->client_to_focus_on_cancel = NULL; + } + else { + mw->client_to_focus = (ClientWin *) iter->data; + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + mw->client_to_focus->focused = 1; + } } static bool @@ -850,12 +853,8 @@ mainloop(session_t *ps, bool activate_on_start) { // Focus the client window only after the main window get unmapped and // keyboard gets ungrabbed. if (mw->client_to_focus) { - if (layout == LAYOUTMODE_PAGING) { + if (layout == LAYOUTMODE_PAGING) wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); - XSync(ps->dpy, True); - XSync(ps->dpy, False); - XSetInputFocus(ps->dpy, PointerRoot, RevertToPointerRoot, CurrentTime); - } childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; refocus = false; diff --git a/src/wm.c b/src/wm.c index f2b8ecd..a7121f5 100644 --- a/src/wm.c +++ b/src/wm.c @@ -676,7 +676,7 @@ wm_get_focused(session_t *ps) { int revert_to = 0; if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { printfdf(false, "(): Currently not focused on any window; trying to find focus..."); - XSetInputFocus(ps->dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + wm_set_desktop_ewmh(ps, wm_get_current_desktop(ps)); if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { printfdf(false, "(): Failed to get current focused window."); return None; @@ -688,7 +688,7 @@ wm_get_focused(session_t *ps) { while (focused) { // Discard insane values if (ps->root == focused || PointerRoot == focused) - return None; + return focused; // Check for WM_STATE if (wid_has_prop(ps, focused, XA_WM_STATE)) diff --git a/src/wm.h b/src/wm.h index e3752ef..67d390e 100644 --- a/src/wm.h +++ b/src/wm.h @@ -149,6 +149,12 @@ wm_set_desktop_ewmh(session_t *ps, long desktop) { long data[] = { desktop, CurrentTime }; wm_send_clientmsg_ewmh_root(ps, ps->root, _NET_CURRENT_DESKTOP, CARR_LEN(data), data); + + XChangeProperty(ps->dpy, ps->root, + XInternAtom(ps->dpy, "_NET_CURRENT_DESKTOP", False), + XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &desktop, 1); + XSync(ps->dpy, True); + XSync(ps->dpy, False); } /** From cc8c82a645a8d95c894b892f65d3f1169dd1fd5e Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 9 Jun 2023 22:01:12 -0700 Subject: [PATCH 143/205] Paging updates thumbnail --- src/skippy.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 3136984..e6d079c 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -852,9 +852,10 @@ mainloop(session_t *ps, bool activate_on_start) { // Focus the client window only after the main window get unmapped and // keyboard gets ungrabbed. + long new_desktop = -1; if (mw->client_to_focus) { if (layout == LAYOUTMODE_PAGING) - wm_set_desktop_ewmh(ps, mw->client_to_focus->slots); + new_desktop = mw->client_to_focus->slots; childwin_focus(mw->client_to_focus); mw->client_to_focus = NULL; refocus = false; @@ -887,6 +888,9 @@ mainloop(session_t *ps, bool activate_on_start) { XSync(ps->dpy, True); mw = NULL; + + if (new_desktop != -1) + wm_set_desktop_ewmh(ps, new_desktop); } if (!mw) die = false; From 0261095379e241f27fff5621eb049227f9c5d56b Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 9 Jun 2023 22:12:00 -0700 Subject: [PATCH 144/205] Remove bogus xlib call --- src/wm.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/wm.h b/src/wm.h index 67d390e..e3752ef 100644 --- a/src/wm.h +++ b/src/wm.h @@ -149,12 +149,6 @@ wm_set_desktop_ewmh(session_t *ps, long desktop) { long data[] = { desktop, CurrentTime }; wm_send_clientmsg_ewmh_root(ps, ps->root, _NET_CURRENT_DESKTOP, CARR_LEN(data), data); - - XChangeProperty(ps->dpy, ps->root, - XInternAtom(ps->dpy, "_NET_CURRENT_DESKTOP", False), - XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &desktop, 1); - XSync(ps->dpy, True); - XSync(ps->dpy, False); } /** From 780abda880adcbb3c0db167e93b0d1cc2c2e819b Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 11 Jun 2023 04:23:53 -0700 Subject: [PATCH 145/205] Refactor code around focus --- src/skippy.c | 160 +++++++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 83 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index e6d079c..d2ce947 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -327,7 +327,7 @@ update_clients(MainWin *mw, Bool *touched) } static void -daemon_count_clients(MainWin *mw, Bool *touched, Window leader) +daemon_count_clients(MainWin *mw, Bool *touched) { // given the client table, update the clientondesktop // the difference between mw->clients and mw->clientondesktop @@ -355,20 +355,63 @@ daemon_count_clients(MainWin *mw, Bool *touched, Window leader) return; } - if (leader) { - mw->clientondesktop = dlist_first(dlist_find_all(tmp, clientwin_check_group_leader_func, (void*)&leader)); - dlist_free(tmp); - } - else { - mw->clientondesktop = tmp; - } + mw->clientondesktop = tmp; } return; } +static void +init_focus(MainWin *mw, Window leader) { + session_t *ps = mw->ps; + + // Get the currently focused window and select which mini-window to focus + dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) leader); + + // check if the user specified --prev or --next on the cmdline + if(ps->o.focus_initial) + { + + // ps->mainwin->ignore_next_refocus = 1; + // ps->mainwin->ignore_next_refocus = 2; + // ps->mainwin->ignore_next_refocus = 4; + + + if(ps->o.focus_initial == FI_PREV) + { + // here, mw->focuslist is the first (dlist*) item in the list + if (iter == mw->focuslist) + iter = dlist_last(mw->focuslist); + else + { + dlist *i = mw->focuslist; + for (; i != NULL; i = i->next) + if (i->next && i->next == iter) + break; + iter = i; + } + } + else if(ps->o.focus_initial == FI_NEXT) + iter = iter->next; + + } + + // then clear this flag, so daemon not remember on its next activation + ps->o.focus_initial = 0; + + if (!iter) { + mw->client_to_focus = NULL; + mw->client_to_focus_on_cancel = NULL; + } + else { + mw->client_to_focus = (ClientWin *) iter->data; + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + mw->client_to_focus->focused = 1; + } +} + static bool -init_layout(MainWin *mw, Window focus, Window leader, enum layoutmode layout) +init_layout(MainWin *mw, enum layoutmode layout, Window leader) { if (!mw->clientondesktop) return true; @@ -402,11 +445,13 @@ init_layout(MainWin *mw, Window focus, Window leader, enum layoutmode layout) mw->yoff = yoff; } + init_focus(mw, leader); + return true; } static bool -init_paging_layout(MainWin *mw, Window focus, Window leader) +init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) { if (!mw->clients) return true; @@ -510,7 +555,6 @@ init_paging_layout(MainWin *mw, Window focus, Window leader) if (cw->slots == current_desktop) { mw->client_to_focus = cw; - mw->revert_focus_win = cw->wid_client; mw->client_to_focus_on_cancel = cw; mw->client_to_focus->focused = 1; } @@ -651,57 +695,8 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { printfdf(false, "(): Event %-13.13s wid %#010lx %s", name, wid, wextra); } -static void -init_focus(MainWin *mw, Window leader) { - session_t *ps = mw->ps; - - // Get the currently focused window and select which mini-window to focus - dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) mw->revert_focus_win); - - // check if the user specified --prev or --next on the cmdline - if(ps->o.focus_initial) - { - - // ps->mainwin->ignore_next_refocus = 1; - // ps->mainwin->ignore_next_refocus = 2; - // ps->mainwin->ignore_next_refocus = 4; - - - if(ps->o.focus_initial == FI_PREV) - { - // here, mw->focuslist is the first (dlist*) item in the list - if (iter == mw->focuslist) - iter = dlist_last(mw->focuslist); - else - { - dlist *i = mw->focuslist; - for (; i != NULL; i = i->next) - if (i->next && i->next == iter) - break; - iter = i; - } - } - else if(ps->o.focus_initial == FI_NEXT) - iter = iter->next; - - } - - // then clear this flag, so daemon not remember on its next activation - ps->o.focus_initial = 0; - - if (!iter) { - mw->client_to_focus = NULL; - mw->client_to_focus_on_cancel = NULL; - } - else { - mw->client_to_focus = (ClientWin *) iter->data; - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; - mw->client_to_focus->focused = 1; - } -} - static bool -skippy_activate(MainWin *mw, Window leader, enum layoutmode layout) +skippy_activate(MainWin *mw, enum layoutmode layout) { session_t *ps = mw->ps; @@ -723,7 +718,7 @@ skippy_activate(MainWin *mw, Window leader, enum layoutmode layout) mw->client_to_focus = NULL; - daemon_count_clients(mw, 0, leader); + daemon_count_clients(mw, 0); if (!mw->clients || !mw->clientondesktop) { return false; } @@ -734,20 +729,18 @@ skippy_activate(MainWin *mw, Window leader, enum layoutmode layout) } if (layout == LAYOUTMODE_PAGING) { - if (!init_paging_layout(mw, mw->revert_focus_win, leader)) { - printfef(false, "(): init_paging_layout() failed."); + if (!init_paging_layout(mw, layout, mw->revert_focus_win)) { + printfef(false, "(): failed."); return false; } } else { - if (!init_layout(mw, mw->revert_focus_win, leader, layout)) { - printfef(false, "(): init_expose_layout() failed."); + if (!init_layout(mw, layout, mw->revert_focus_win)) { + printfef(false, "(): failed."); return false; } } - init_focus(mw, leader); - foreach_dlist(mw->clients) { ClientWin *cw = iter->data; if (mw->ps->o.lazyTrans) @@ -789,7 +782,6 @@ mainloop(session_t *ps, bool activate_on_start) { MainWin *mw = NULL; bool die = false; bool activate = activate_on_start; - bool refocus = false; bool pending_damage = false; long last_rendered = 0L; enum layoutmode layout = LAYOUTMODE_SWITCHER; @@ -831,10 +823,9 @@ mainloop(session_t *ps, bool activate_on_start) { assert(ps->mainwin); activate = false; - if (skippy_activate(ps->mainwin, None, layout)) { + if (skippy_activate(ps->mainwin, layout)) { last_rendered = time_in_millis(); mw = ps->mainwin; - refocus = false; pending_damage = false; first_animated = time_in_millis(); } @@ -854,11 +845,20 @@ mainloop(session_t *ps, bool activate_on_start) { // keyboard gets ungrabbed. long new_desktop = -1; if (mw->client_to_focus) { - if (layout == LAYOUTMODE_PAGING) + if (layout == LAYOUTMODE_PAGING) { new_desktop = mw->client_to_focus->slots; - childwin_focus(mw->client_to_focus); + dlist *iter = dlist_find(mw->focuslist, + clientwin_cmp_func, (void *) mw->revert_focus_win); + if (iter) { + ClientWin *cw = iter->data; + if (cw) + childwin_focus(cw); + } + } + else { + childwin_focus(mw->client_to_focus); + } mw->client_to_focus = NULL; - refocus = false; pending_damage = false; } @@ -866,12 +866,6 @@ mainloop(session_t *ps, bool activate_on_start) { dlist_free(mw->clientondesktop); mw->clientondesktop = 0; - if (refocus && mw->revert_focus_win) { - // No idea why. Plain XSetInputFocus() no longer works after ungrabbing. - wm_activate_window(ps, mw->revert_focus_win); - refocus = false; - } - // free all mini desktop representations dlist_free_with_func(mw->dminis, (dlist_free_func) clientwin_destroy); mw->dminis = NULL; @@ -986,7 +980,7 @@ mainloop(session_t *ps, bool activate_on_start) { } else if (mw && ev.type == DestroyNotify) { printfdf(false, "(): else if (ev.type == DestroyNotify) {"); - daemon_count_clients(ps->mainwin, 0, None); + daemon_count_clients(ps->mainwin, 0); if (!mw->clientondesktop) { printfdf(false, "(): Last client window destroyed/unmapped, " "exiting."); @@ -996,7 +990,7 @@ mainloop(session_t *ps, bool activate_on_start) { } else if (ev.type == MapNotify || ev.type == UnmapNotify) { printfdf(false, "(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); - daemon_count_clients(ps->mainwin, 0, None); + daemon_count_clients(ps->mainwin, 0); dlist *iter = (wid ? dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { ClientWin *cw = (ClientWin *) iter->data; @@ -1994,7 +1988,7 @@ int main(int argc, char *argv[]) { printfdf(false, "(): Finished flushing pipe \"%s\".", pipePath); } - daemon_count_clients(mw, 0, None); + daemon_count_clients(mw, 0); foreach_dlist(mw->clients) { clientwin_update((ClientWin *) iter->data); From 5fc16a315118994a56f956badb95cff87aab3c22 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 12 Jun 2023 02:06:55 -0700 Subject: [PATCH 146/205] Default event handling to MainWin, default MainWin->client_to_focus to MainWin->focuslist->first --- src/skippy.c | 3 ++- src/wm.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index d2ce947..c2e5b41 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -400,7 +400,8 @@ init_focus(MainWin *mw, Window leader) { ps->o.focus_initial = 0; if (!iter) { - mw->client_to_focus = NULL; + dlist * first = dlist_first(mw->focuslist); + mw->client_to_focus = first->data; mw->client_to_focus_on_cancel = NULL; } else { diff --git a/src/wm.c b/src/wm.c index a7121f5..cc6b086 100644 --- a/src/wm.c +++ b/src/wm.c @@ -688,7 +688,7 @@ wm_get_focused(session_t *ps) { while (focused) { // Discard insane values if (ps->root == focused || PointerRoot == focused) - return focused; + return ps->mainwin->window; // Check for WM_STATE if (wid_has_prop(ps, focused, XA_WM_STATE)) From 31efa15f805526afadad7231bae8469e0f3c9ea8 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 12 Jun 2023 17:14:27 -0700 Subject: [PATCH 147/205] Refactor around focus window and remove bogus code --- src/mainwin.h | 6 ++---- src/skippy.c | 19 +++++-------------- src/wm.c | 9 ++------- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/mainwin.h b/src/mainwin.h index 359ab7f..feff307 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -86,12 +86,10 @@ struct _mainwin_t { XineramaScreenInfo *xin_info, *xin_active; #endif /* CFG_XINERAMA */ - /// @brief Window ID to revert focus to when the main window is unmapped. - Window revert_focus_win; - /// @brief the originally focused window - ClientWin *client_to_focus_on_cancel; /// @brief The client window to eventually focus. ClientWin *client_to_focus; + /// @brief the originally focused window + ClientWin *client_to_focus_on_cancel; // int ignore_next_refocus; ClientWin *cw_tooltip; }; diff --git a/src/skippy.c b/src/skippy.c index c2e5b41..cbc4005 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -702,7 +702,7 @@ skippy_activate(MainWin *mw, enum layoutmode layout) session_t *ps = mw->ps; // Do this window before main window gets mapped - mw->revert_focus_win = wm_get_focused(ps); + Window focus_win = wm_get_focused(ps); // Update the main window's geometry (and Xinerama info if applicable) mainwin_update(mw); @@ -730,13 +730,13 @@ skippy_activate(MainWin *mw, enum layoutmode layout) } if (layout == LAYOUTMODE_PAGING) { - if (!init_paging_layout(mw, layout, mw->revert_focus_win)) { + if (!init_paging_layout(mw, layout, focus_win)) { printfef(false, "(): failed."); return false; } } else { - if (!init_layout(mw, layout, mw->revert_focus_win)) { + if (!init_layout(mw, layout, focus_win)) { printfef(false, "(): failed."); return false; } @@ -846,19 +846,10 @@ mainloop(session_t *ps, bool activate_on_start) { // keyboard gets ungrabbed. long new_desktop = -1; if (mw->client_to_focus) { - if (layout == LAYOUTMODE_PAGING) { + if (layout == LAYOUTMODE_PAGING) new_desktop = mw->client_to_focus->slots; - dlist *iter = dlist_find(mw->focuslist, - clientwin_cmp_func, (void *) mw->revert_focus_win); - if (iter) { - ClientWin *cw = iter->data; - if (cw) - childwin_focus(cw); - } - } - else { + else childwin_focus(mw->client_to_focus); - } mw->client_to_focus = NULL; pending_damage = false; } diff --git a/src/wm.c b/src/wm.c index cc6b086..9bb6eed 100644 --- a/src/wm.c +++ b/src/wm.c @@ -675,14 +675,9 @@ wm_get_focused(session_t *ps) { { int revert_to = 0; if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { - printfdf(false, "(): Currently not focused on any window; trying to find focus..."); - wm_set_desktop_ewmh(ps, wm_get_current_desktop(ps)); - if (!XGetInputFocus(ps->dpy, &focused, &revert_to)) { - printfdf(false, "(): Failed to get current focused window."); - return None; - } + printfdf(false, "(): Currently not focused on any window; returning main window..."); + return ps->mainwin->window; } - printfdf(false, "(): Focused window is %#010lx.", focused); } while (focused) { From 9975e335126489622134741c767341e9d3b2fc95 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 12 Jun 2023 17:51:26 -0700 Subject: [PATCH 148/205] Refactor focus logic on cancel --- src/clientwin.c | 3 ++- src/mainwin.c | 1 + src/mainwin.h | 1 + src/skippy.c | 22 ++++++++++++++++------ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index e3530ba..96c0b34 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -647,7 +647,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) { - mw->client_to_focus = mw->client_to_focus_on_cancel; + cw->mainwin->refocus = true; return 1; } @@ -673,6 +673,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnRelease, evk->keycode)) { + cw->mainwin->refocus = true; return 1; } } diff --git a/src/mainwin.c b/src/mainwin.c index cf348c1..4725c15 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -72,6 +72,7 @@ mainwin_create(session_t *ps) { mw->tooltip = 0; mw->clientondesktop = 0; mw->focuslist = 0; + mw->refocus = false; XWindowAttributes rootattr; XGetWindowAttributes(dpy, ps->root, &rootattr); diff --git a/src/mainwin.h b/src/mainwin.h index feff307..4686ebb 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -90,6 +90,7 @@ struct _mainwin_t { ClientWin *client_to_focus; /// @brief the originally focused window ClientWin *client_to_focus_on_cancel; + bool refocus; // int ignore_next_refocus; ClientWin *cw_tooltip; }; diff --git a/src/skippy.c b/src/skippy.c index cbc4005..0839e7f 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -846,10 +846,19 @@ mainloop(session_t *ps, bool activate_on_start) { // keyboard gets ungrabbed. long new_desktop = -1; if (mw->client_to_focus) { - if (layout == LAYOUTMODE_PAGING) - new_desktop = mw->client_to_focus->slots; - else - childwin_focus(mw->client_to_focus); + if (layout == LAYOUTMODE_PAGING) { + if (!mw->refocus) + new_desktop = mw->client_to_focus->slots; + else + new_desktop = mw->client_to_focus_on_cancel->slots; + } + else { + if (!mw->refocus) + childwin_focus(mw->client_to_focus); + else if(mw->client_to_focus_on_cancel) + childwin_focus(mw->client_to_focus_on_cancel); + } + mw->refocus = false; mw->client_to_focus = NULL; pending_damage = false; } @@ -1148,8 +1157,9 @@ mainloop(session_t *ps, bool activate_on_start) { case PIPECMD_TOGGLE_SWITCHER: case PIPECMD_TOGGLE_EXPOSE: case PIPECMD_TOGGLE_PAGING: - if (mw) - die = true; + if (mw) { + mw->refocus = die = true; + } else { animating = activate = true; if (piped_input == PIPECMD_TOGGLE_SWITCHER) { From 2dc1a19c1aa9bf1382c07f77727631afb5754cb7 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 12 Jun 2023 18:24:06 -0700 Subject: [PATCH 149/205] Duplicate MainWin->focuslist from MainWin->clientsondesktop rather than point to the same linked list (of pointers to ClientWin*) This decoupling allows preserving proper windows z-order while changing focus order --- src/skippy.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 0839e7f..2344f8d 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -362,9 +362,18 @@ daemon_count_clients(MainWin *mw, Bool *touched) } static void -init_focus(MainWin *mw, Window leader) { +init_focus(MainWin *mw, enum layoutmode layout, Window leader) { session_t *ps = mw->ps; + // ordering of client windows list + // is important for prev/next window selection + mw->focuslist = dlist_dup(mw->clientondesktop); + + /*if (layout == LAYOUTMODE_SWITCHER) + dlist_sort(mw->focuslist, sort_cw_by_row, 0); + else*/ if (layout == LAYOUTMODE_EXPOSE) + dlist_sort(mw->focuslist, sort_cw_by_column, 0); + // Get the currently focused window and select which mini-window to focus dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) leader); @@ -417,21 +426,11 @@ init_layout(MainWin *mw, enum layoutmode layout, Window leader) if (!mw->clientondesktop) return true; - dlist_sort(mw->clientondesktop, clientwin_sort_func, 0); - /* set up the windows layout */ { unsigned int newwidth = 0, newheight = 0; layout_run(mw, mw->clientondesktop, &newwidth, &newheight, layout); - // ordering of client windows list - // is important for prev/next window selection - if (layout == LAYOUTMODE_SWITCHER) - dlist_sort(mw->clientondesktop, sort_cw_by_row, 0); - else /*if (layout == LAYOUTMODE_EXPOSE)*/ - dlist_sort(mw->clientondesktop, sort_cw_by_column, 0); - mw->focuslist = mw->clientondesktop; - float multiplier = (float) (mw->width - 2 * mw->distance) / newwidth; if (multiplier * newheight > mw->height - 2 * mw->distance) multiplier = (float) (mw->height - 2 * mw->distance) / newheight; @@ -446,7 +445,7 @@ init_layout(MainWin *mw, enum layoutmode layout, Window leader) mw->yoff = yoff; } - init_focus(mw, leader); + init_focus(mw, layout, leader); return true; } @@ -562,7 +561,7 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) } } - mw->focuslist = mw->dminis; + mw->focuslist = dlist_dup(mw->dminis); return true; } @@ -866,6 +865,7 @@ mainloop(session_t *ps, bool activate_on_start) { // Cleanup dlist_free(mw->clientondesktop); mw->clientondesktop = 0; + dlist_free(mw->focuslist); // free all mini desktop representations dlist_free_with_func(mw->dminis, (dlist_free_func) clientwin_destroy); From 365d550af6b72ac10883ae3f7e3605250d5b8cc0 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 12 Jun 2023 19:25:49 -0700 Subject: [PATCH 150/205] z-ordering, especially for switcher and rendering But introduced a bug... --- src/layout.c | 8 ++++++- src/skippy.c | 63 ++++++++++++++-------------------------------------- src/wm.c | 7 +++--- 3 files changed, 28 insertions(+), 50 deletions(-) diff --git a/src/layout.c b/src/layout.c index dc04bdb..7e917a3 100644 --- a/src/layout.c +++ b/src/layout.c @@ -43,8 +43,14 @@ void layout_run(MainWin *mw, dlist *windows, if (layout == LAYOUTMODE_EXPOSE && mw->ps->o.exposeLayout == LAYOUT_BOXY) layout_boxy(mw, windows, total_width, total_height); - else + else { + // to get the proper z-order based window ordering, + // reversing the list of windows is needed + dlist_reverse(windows); layout_xd(mw, windows, total_width, total_height); + // reversing the linked list again for proper focus ordering + dlist_reverse(windows); + } } // original legacy layout diff --git a/src/skippy.c b/src/skippy.c index 2344f8d..e61de4f 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -284,58 +284,29 @@ anime( } static void -update_clients(MainWin *mw, Bool *touched) +daemon_count_clients(MainWin *mw, Bool *touched) { - // Update the client table, pick the ones we want and sort them - dlist *stack = dlist_first(wm_get_stack(mw->ps)); - mw->clients = dlist_first(mw->clients); + // given the client table, update the clientondesktop + // the difference between mw->clients and mw->clientondesktop + // is that mw->clients is all the client windows + // while mw->clientondesktop is only those in current virtual desktop + // if that option is user supplied - if (touched) - *touched = False; - - // Terminate mw->clients that are no longer managed - for (dlist *iter = mw->clients; iter; ) { - ClientWin *cw = (ClientWin *) iter->data; - if (dlist_find_data(stack, (void *) cw->wid_client)) { - iter = iter->next; - } - else { - dlist *tmp = iter->next; - clientwin_destroy((ClientWin *) iter->data, True); - mw->clients = dlist_remove(iter); - iter = tmp; - if (touched) - *touched = True; - } - } - XFlush(mw->ps->dpy); + // remove old client windows + dlist_free(mw->clients); + // is clientwin_destroy(cw, True) needed? + mw->clients = NULL; - // Add new mw->clients + // create new client windows from EWMH or XQueryTree(), in the right z-order + dlist *stack = dlist_first(wm_get_stack(mw->ps)); foreach_dlist (stack) { - ClientWin *cw = (ClientWin *) - dlist_find(mw->clients, clientwin_cmp_func, iter->data); - if (!cw && ((Window) iter->data) != mw->window) { - cw = clientwin_create(mw, (Window)iter->data); + if (((Window) iter->data) != mw->window) { + ClientWin *cw = clientwin_create(mw, (Window)iter->data); if (!cw) continue; mw->clients = dlist_add(mw->clients, cw); - if (touched) - *touched = True; } } - dlist_free(stack); -} - -static void -daemon_count_clients(MainWin *mw, Bool *touched) -{ - // given the client table, update the clientondesktop - // the difference between mw->clients and mw->clientondesktop - // is that mw->clients is all the client windows - // while mw->clientondesktop is only those in current virtual desktop - // if that option is user supplied - - update_clients(mw, 0); if (!mw->clients) { printfdf(false, "(): No client windows found."); return; @@ -369,9 +340,9 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { // is important for prev/next window selection mw->focuslist = dlist_dup(mw->clientondesktop); - /*if (layout == LAYOUTMODE_SWITCHER) - dlist_sort(mw->focuslist, sort_cw_by_row, 0); - else*/ if (layout == LAYOUTMODE_EXPOSE) + if (layout == LAYOUTMODE_SWITCHER) + dlist_reverse(mw->focuslist); + else if (layout == LAYOUTMODE_EXPOSE) dlist_sort(mw->focuslist, sort_cw_by_column, 0); // Get the currently focused window and select which mini-window to focus diff --git a/src/wm.c b/src/wm.c index 9bb6eed..ed7295b 100644 --- a/src/wm.c +++ b/src/wm.c @@ -343,7 +343,8 @@ static inline dlist * wm_get_stack_sub(session_t *ps, Window root) { dlist *l = NULL; - if (!(ps->o.acceptOvRedir || ps->o.acceptWMWin)) { + // does not give info on windows z-order + /*if (!(ps->o.acceptOvRedir || ps->o.acceptWMWin)) { // EWMH l = wm_get_stack_fromprop(ps, root, _NET_CLIENT_LIST); if (l) { @@ -357,9 +358,9 @@ wm_get_stack_sub(session_t *ps, Window root) { printfdf(false, "(): Retrieved window stack from _WIN_CLIENT_LIST."); return l; } - } + }*/ - // Stupid method + // Stupid method, but this gives windows ordered by z-order { Window *children = NULL; unsigned nchildren = 0; From b121e6f4af6e7f48b84488ae9152a3eb16dd2ee4 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 12 Jun 2023 19:50:08 -0700 Subject: [PATCH 151/205] Fix bug where all thumbnails are thrown away --- src/skippy.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index e61de4f..ab6da1b 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -284,29 +284,53 @@ anime( } static void -daemon_count_clients(MainWin *mw, Bool *touched) +update_clients(MainWin *mw) { - // given the client table, update the clientondesktop - // the difference between mw->clients and mw->clientondesktop - // is that mw->clients is all the client windows - // while mw->clientondesktop is only those in current virtual desktop - // if that option is user supplied + // Update the list of windows with correct z-ordering + dlist *stack = dlist_first(wm_get_stack(mw->ps)); + mw->clients = dlist_first(mw->clients); - // remove old client windows - dlist_free(mw->clients); - // is clientwin_destroy(cw, True) needed? - mw->clients = NULL; + // Terminate mw->clients that are no longer managed + for (dlist *iter = mw->clients; iter; ) { + ClientWin *cw = (ClientWin *) iter->data; + if (dlist_find_data(stack, (void *) cw->wid_client)) { + iter = iter->next; + } + else { + dlist *tmp = iter->next; + clientwin_destroy((ClientWin *) iter->data, True); + mw->clients = dlist_remove(iter); + iter = tmp; + } + } + XFlush(mw->ps->dpy); - // create new client windows from EWMH or XQueryTree(), in the right z-order - dlist *stack = dlist_first(wm_get_stack(mw->ps)); + // Add new mw->clients + // This algorithm preserves correct z-order foreach_dlist (stack) { - if (((Window) iter->data) != mw->window) { - ClientWin *cw = clientwin_create(mw, (Window)iter->data); + ClientWin *cw = (ClientWin *) + dlist_find(mw->clients, clientwin_cmp_func, iter->data); + if (!cw && ((Window) iter->data) != mw->window) { + cw = clientwin_create(mw, (Window)iter->data); if (!cw) continue; mw->clients = dlist_add(mw->clients, cw); } } + dlist_free(stack); +} + +static void +daemon_count_clients(MainWin *mw, Bool *touched) +{ + // given the client table, update the clientondesktop + // the difference between mw->clients and mw->clientondesktop + // is that mw->clients is all the client windows + // while mw->clientondesktop is only those in current virtual desktop + // if that option is user supplied + + update_clients(mw); + if (!mw->clients) { printfdf(false, "(): No client windows found."); return; From 3ed38ebcee70bc2c0c2edd6dd253a557a22f59fa Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 13 Jun 2023 18:45:41 -0700 Subject: [PATCH 152/205] Correct z-ordering --- src/skippy.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index ab6da1b..50559d3 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -306,22 +306,32 @@ update_clients(MainWin *mw) XFlush(mw->ps->dpy); // Add new mw->clients - // This algorithm preserves correct z-order + // This algorithm preserves correct z-order: + // stack is ordered by correct z-order + // and we re-order existing or new ClientWin to match that in stack + // yes, it is O(n^2) complexity + dlist *new_clients = NULL; + foreach_dlist (stack) { - ClientWin *cw = (ClientWin *) - dlist_find(mw->clients, clientwin_cmp_func, iter->data); - if (!cw && ((Window) iter->data) != mw->window) { - cw = clientwin_create(mw, (Window)iter->data); + dlist *insert_point = dlist_find(mw->clients, clientwin_cmp_func, iter->data); + if (!insert_point && ((Window) iter->data) != mw->window) { + ClientWin *cw = clientwin_create(mw, (Window)iter->data); if (!cw) continue; - mw->clients = dlist_add(mw->clients, cw); + new_clients = dlist_add(new_clients, cw); + } + else { + ClientWin *cw = (ClientWin *) insert_point->data; + new_clients = dlist_add(new_clients, cw); } } dlist_free(stack); + dlist_free(mw->clients); + mw->clients = dlist_first(new_clients); } static void -daemon_count_clients(MainWin *mw, Bool *touched) +daemon_count_clients(MainWin *mw) { // given the client table, update the clientondesktop // the difference between mw->clients and mw->clientondesktop @@ -713,7 +723,7 @@ skippy_activate(MainWin *mw, enum layoutmode layout) mw->client_to_focus = NULL; - daemon_count_clients(mw, 0); + daemon_count_clients(mw); if (!mw->clients || !mw->clientondesktop) { return false; } @@ -976,7 +986,7 @@ mainloop(session_t *ps, bool activate_on_start) { } else if (mw && ev.type == DestroyNotify) { printfdf(false, "(): else if (ev.type == DestroyNotify) {"); - daemon_count_clients(ps->mainwin, 0); + daemon_count_clients(ps->mainwin); if (!mw->clientondesktop) { printfdf(false, "(): Last client window destroyed/unmapped, " "exiting."); @@ -986,7 +996,7 @@ mainloop(session_t *ps, bool activate_on_start) { } else if (ev.type == MapNotify || ev.type == UnmapNotify) { printfdf(false, "(): else if (ev.type == MapNotify || ev.type == UnmapNotify) {"); - daemon_count_clients(ps->mainwin, 0); + daemon_count_clients(ps->mainwin); dlist *iter = (wid ? dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid): NULL); if (iter) { ClientWin *cw = (ClientWin *) iter->data; @@ -1985,7 +1995,7 @@ int main(int argc, char *argv[]) { printfdf(false, "(): Finished flushing pipe \"%s\".", pipePath); } - daemon_count_clients(mw, 0); + daemon_count_clients(mw); foreach_dlist(mw->clients) { clientwin_update((ClientWin *) iter->data); From d681cbefe9887d26ad7c02a42e9cb4537d27edf0 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 13 Jun 2023 21:55:43 -0700 Subject: [PATCH 153/205] Speed up switcher --- src/skippy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 50559d3..6f63639 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -914,7 +914,8 @@ mainloop(session_t *ps, bool activate_on_start) { mainwin_map(mw); XFlush(ps->dpy); } - else if (timeslice >= ps->o.animationDuration) { + else if (layout == LAYOUTMODE_SWITCHER + || timeslice >= ps->o.animationDuration) { anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; last_rendered = time_in_millis(); From 601ccec4c1b759943a1e6c444525e516a960150f Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 16:21:52 -0700 Subject: [PATCH 154/205] Alt-Tab style cycling through windows through skippy-xd --activate-switcher --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 6f63639..8efd542 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1124,7 +1124,7 @@ mainloop(session_t *ps, bool activate_on_start) { } printfdf(false, "(): case PIPECMD_ACTIVATE, mode=%d", layout); - if (ps->mainwin->mapped) + if (mw) { printfdf(false, "(): if (ps->mainwin->mapped)"); fflush(stdout);fflush(stderr); @@ -1137,13 +1137,13 @@ mainloop(session_t *ps, bool activate_on_start) { mw->client_to_focus->focused = 0; clientwin_render(mw->client_to_focus); - if (ps->o.focus_initial == FI_PREV) + /*if (ps->o.focus_initial == FI_PREV) { printfdf(false, "(): focus_miniw_prev(ps, mw->client_to_focus);"); focus_miniw_prev(ps, mw->client_to_focus); } - else if (ps->o.focus_initial == FI_NEXT) + else if (ps->o.focus_initial == FI_NEXT)*/ { printfdf(false, "(): focus_miniw_next(ps, mw->client_to_focus);"); focus_miniw_next(ps, mw->client_to_focus); From 7bc3045cd695780c2b8c52d8e6153615114bd498 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 16:27:21 -0700 Subject: [PATCH 155/205] skippy-xd --activate-switcher starts at next window --- src/skippy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/skippy.c b/src/skippy.c index 8efd542..9326a02 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1154,6 +1154,8 @@ mainloop(session_t *ps, bool activate_on_start) { { printfdf(false, "(): activate = true;"); animating = activate = true; + if (layout == LAYOUTMODE_SWITCHER) + ps->o.focus_initial = FI_NEXT; } break; case PIPECMD_DEACTIVATE: From 71a5c81e20a2453ff5bc05652332521fb314ddf2 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 17:11:15 -0700 Subject: [PATCH 156/205] Redesign and refactor cmdline entry points --- src/clientwin.c | 3 +- src/skippy.c | 259 +++++++++++++----------------------------------- src/skippy.h | 13 +-- 3 files changed, 73 insertions(+), 202 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 96c0b34..1d0b2a1 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -49,8 +49,7 @@ clientwin_validate_func(dlist *l, void *data) { #endif if (!ps->o.showAllDesktops - && ps->o.mode != PROGMODE_ACTV_PAGING - && ps->o.mode != PROGMODE_TGG_PAGING) { + && ps->o.mode != PROGMODE_PAGING) { CARD32 desktop = (*(CARD32 *)data), w_desktop = wm_get_window_desktop(ps, cw->wid_client); diff --git a/src/skippy.c b/src/skippy.c index 9326a02..68e4c7f 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -31,16 +31,12 @@ bool debuglog = false; enum pipe_cmd_t { // Not ordered properly for backward compatibility PIPECMD_RELOAD_CONFIG = 0, - PIPECMD_ACTIVATE_SWITCHER = 1, - PIPECMD_TOGGLE_SWITCHER, - PIPECMD_ACTIVATE_EXPOSE, - PIPECMD_TOGGLE_EXPOSE, - PIPECMD_ACTIVATE_PAGING, - PIPECMD_TOGGLE_PAGING, + PIPECMD_SWITCH = 1, + PIPECMD_SWITCH_PREV, + PIPECMD_EXPOSE, + PIPECMD_PAGING, PIPECMD_DEACTIVATE, PIPECMD_EXIT_DAEMON, - PIPECMD_QUEUE_FI_PREV, - PIPECMD_QUEUE_FI_NEXT, }; session_t *ps_g = NULL; @@ -374,7 +370,7 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { // is important for prev/next window selection mw->focuslist = dlist_dup(mw->clientondesktop); - if (layout == LAYOUTMODE_SWITCHER) + if (layout == LAYOUTMODE_SWITCH) dlist_reverse(mw->focuslist); else if (layout == LAYOUTMODE_EXPOSE) dlist_sort(mw->focuslist, sort_cw_by_column, 0); @@ -789,21 +785,19 @@ mainloop(session_t *ps, bool activate_on_start) { bool activate = activate_on_start; bool pending_damage = false; long last_rendered = 0L; - enum layoutmode layout = LAYOUTMODE_SWITCHER; + enum layoutmode layout = LAYOUTMODE_SWITCH; bool animating = activate; long first_animated = 0L; switch (ps->o.mode) { - case PROGMODE_ACTV_EXPOSE: - case PROGMODE_TGG_EXPOSE: + case PROGMODE_EXPOSE: layout = LAYOUTMODE_EXPOSE; break; - case PROGMODE_ACTV_PAGING: - case PROGMODE_TGG_PAGING: + case PROGMODE_PAGING: layout = LAYOUTMODE_PAGING; break; default: - layout = LAYOUTMODE_SWITCHER; + layout = LAYOUTMODE_SWITCH; break; } @@ -901,7 +895,7 @@ mainloop(session_t *ps, bool activate_on_start) { // animation! if (mw && animating) { int timeslice = time_in_millis() - first_animated; - if (layout != LAYOUTMODE_SWITCHER + if (layout != LAYOUTMODE_SWITCH && timeslice < ps->o.animationDuration && timeslice + first_animated >= last_rendered + (1000.0 / 60.0)) { @@ -914,7 +908,7 @@ mainloop(session_t *ps, bool activate_on_start) { mainwin_map(mw); XFlush(ps->dpy); } - else if (layout == LAYOUTMODE_SWITCHER + else if (layout == LAYOUTMODE_SWITCH || timeslice >= ps->o.animationDuration) { anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; @@ -1107,23 +1101,32 @@ mainloop(session_t *ps, bool activate_on_start) { load_config_file(ps); mainwin_reload(ps, ps->mainwin); break; - case PIPECMD_ACTIVATE_SWITCHER: - case PIPECMD_ACTIVATE_EXPOSE: - case PIPECMD_ACTIVATE_PAGING: - if (piped_input == PIPECMD_ACTIVATE_SWITCHER) { - ps->o.mode = PROGMODE_ACTV_SWITCHER; - layout = LAYOUTMODE_SWITCHER; + case PIPECMD_SWITCH: + case PIPECMD_SWITCH_PREV: + case PIPECMD_EXPOSE: + case PIPECMD_PAGING: + if (mw) { + if (piped_input != PIPECMD_SWITCH) { + mw->refocus = die = true; + break; + } + } + + animating = activate = true; + if (piped_input == PIPECMD_SWITCH) { + ps->o.mode = PROGMODE_SWITCH; + layout = LAYOUTMODE_SWITCH; } - else if (piped_input == PIPECMD_ACTIVATE_EXPOSE) { - ps->o.mode = PROGMODE_ACTV_EXPOSE; + else if (piped_input == PIPECMD_EXPOSE) { + ps->o.mode = PROGMODE_EXPOSE; layout = LAYOUTMODE_EXPOSE; } - else /* if (piped_input == PIPECMD_ACTIVATE_PAGING) */ { - ps->o.mode = PROGMODE_ACTV_PAGING; + else /* if (piped_input == PIPECMD_PAGING) */ { + ps->o.mode = PROGMODE_PAGING; layout = LAYOUTMODE_PAGING; } - printfdf(false, "(): case PIPECMD_ACTIVATE, mode=%d", layout); + printfdf(false, "(): skippy activating, mode=%d", layout); if (mw) { printfdf(false, "(): if (ps->mainwin->mapped)"); @@ -1137,13 +1140,13 @@ mainloop(session_t *ps, bool activate_on_start) { mw->client_to_focus->focused = 0; clientwin_render(mw->client_to_focus); - /*if (ps->o.focus_initial == FI_PREV) + if (piped_input == PIPECMD_SWITCH_PREV) { printfdf(false, "(): focus_miniw_prev(ps, mw->client_to_focus);"); focus_miniw_prev(ps, mw->client_to_focus); } - else if (ps->o.focus_initial == FI_NEXT)*/ + else if (piped_input == PIPECMD_SWITCH) { printfdf(false, "(): focus_miniw_next(ps, mw->client_to_focus);"); focus_miniw_next(ps, mw->client_to_focus); @@ -1154,47 +1157,16 @@ mainloop(session_t *ps, bool activate_on_start) { { printfdf(false, "(): activate = true;"); animating = activate = true; - if (layout == LAYOUTMODE_SWITCHER) + if (piped_input == PIPECMD_SWITCH) ps->o.focus_initial = FI_NEXT; + else if (piped_input == PIPECMD_SWITCH_PREV) + ps->o.focus_initial = FI_PREV; } break; - case PIPECMD_DEACTIVATE: - if (mw) - die = true; - break; - case PIPECMD_TOGGLE_SWITCHER: - case PIPECMD_TOGGLE_EXPOSE: - case PIPECMD_TOGGLE_PAGING: - if (mw) { - mw->refocus = die = true; - } - else { - animating = activate = true; - if (piped_input == PIPECMD_TOGGLE_SWITCHER) { - ps->o.mode = PROGMODE_TGG_SWITCHER; - layout = LAYOUTMODE_SWITCHER; - } - else if (piped_input == PIPECMD_TOGGLE_EXPOSE) { - ps->o.mode = PROGMODE_TGG_EXPOSE; - layout = LAYOUTMODE_EXPOSE; - } - else /* if (piped_input == PIPECMD_TOGGLE_PAGING) */ { - ps->o.mode = PROGMODE_TGG_PAGING; - layout = LAYOUTMODE_PAGING; - } - } - printfdf(false, "(): case PIPECMD_TOGGLE, mode=%d", layout); - break; case PIPECMD_EXIT_DAEMON: printfdf(false, "(): Exit command received, killing daemon..."); unlink(ps->o.pipePath); return; - case PIPECMD_QUEUE_FI_PREV: - ps->o.focus_initial = FI_PREV; - break; - case PIPECMD_QUEUE_FI_NEXT: - ps->o.focus_initial = FI_NEXT; - break; default: printfdf(false, "(): Unknown daemon command \"%d\" received.", piped_input); break; @@ -1237,33 +1209,27 @@ queue_reload_config(const char *pipePath) { } static inline bool -queue_initial_focus_prev(const char *pipePath) { - printfdf(false, "(): Set initial focus to previous selection..."); - return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_PREV, pipePath); -} - -static inline bool -queue_initial_focus_next(const char *pipePath) { - printfdf(false, "(): Set initial focus to next selection..."); - return send_command_to_daemon_via_fifo(PIPECMD_QUEUE_FI_NEXT, pipePath); +activate_switch(const char *pipePath) { + printfdf(false, "(): Activating switcher..."); + return send_command_to_daemon_via_fifo(PIPECMD_SWITCH, pipePath); } static inline bool -activate_switcher(const char *pipePath) { +activate_switch_prev(const char *pipePath) { printfdf(false, "(): Activating switcher..."); - return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_SWITCHER, pipePath); + return send_command_to_daemon_via_fifo(PIPECMD_SWITCH_PREV, pipePath); } static inline bool activate_expose(const char *pipePath) { printfdf(false, "(): Activating expose..."); - return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_EXPOSE, pipePath); + return send_command_to_daemon_via_fifo(PIPECMD_EXPOSE, pipePath); } static inline bool activate_paging(const char *pipePath) { printfdf(false, "(): Activating paging..."); - return send_command_to_daemon_via_fifo(PIPECMD_ACTIVATE_PAGING, pipePath); + return send_command_to_daemon_via_fifo(PIPECMD_PAGING, pipePath); } static inline bool @@ -1272,30 +1238,6 @@ exit_daemon(const char *pipePath) { return send_command_to_daemon_via_fifo(PIPECMD_EXIT_DAEMON, pipePath); } -static inline bool -deactivate(const char *pipePath) { - printfdf(false, "(): Deactivating..."); - return send_command_to_daemon_via_fifo(PIPECMD_DEACTIVATE, pipePath); -} - -static inline bool -toggle_switcher(const char *pipePath) { - printfdf(false, "(): Toggling switcher..."); - return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_SWITCHER, pipePath); -} - -static inline bool -toggle_expose(const char *pipePath) { - printfdf(false, "(): Toggling expose..."); - return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_EXPOSE, pipePath); -} - -static inline bool -toggle_paging(const char *pipePath) { - printfdf(false, "(): Toggling paging..."); - return send_command_to_daemon_via_fifo(PIPECMD_TOGGLE_PAGING, pipePath); -} - /** * @brief Xlib error handler function. */ @@ -1375,15 +1317,10 @@ show_help() { " --config - read the specified configuration file.\n" " --start-daemon - starts the daemon running.\n" " --stop-daemon - stops the daemon running.\n" - " --activate-switcher - connects to daemon and activate switcher.\n" - " --toggle-switcher - connects to daemon and toggle switcher.\n" - " --activate-expose - connects to daemon and activate expose.\n" - " --toggle-expose - connects to daemon and toggle expose.\n" - " --activate-paging - connects to daemon and activate paging.\n" - " --toggle-paging - connects to daemon and toggle paging.\n" - " --deactivate - connects to daemon and deactivate switcher, expose or paging.\n" - " --prev - focus window to previous.\n" - " --next - focus window to next.\n" + " --switch - connects to daemon and activate switch.\n" + " --switch-prev - connects to daemon and activate switch.\n" + " --expose - connects to daemon and activate expose.\n" + " --paging - connects to daemon and activate paging.\n" // " --test - Temporary development testing. To be removed.\n" "\n" " --help - show this message.\n" @@ -1540,34 +1477,24 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { enum options { OPT_CONFIG = 256, OPT_CONFIG_RELOAD, - OPT_ACTV_SWITCHER, - OPT_TGG_SWITCHER, + OPT_ACTV_SWITCH, + OPT_ACTV_SWITCH_PREV, OPT_ACTV_EXPOSE, - OPT_TGG_EXPOSE, OPT_ACTV_PAGING, - OPT_TGG_PAGING, - OPT_DEACTV, OPT_DM_START, OPT_DM_STOP, - OPT_PREV, - OPT_NEXT, }; static const char * opts_short = "hS"; static const struct option opts_long[] = { { "help", no_argument, NULL, 'h' }, { "config", required_argument, NULL, OPT_CONFIG }, { "config-reload", no_argument, NULL, OPT_CONFIG_RELOAD }, - { "activate-switcher", no_argument, NULL, OPT_ACTV_SWITCHER }, - { "toggle-switcher", no_argument, NULL, OPT_TGG_SWITCHER }, - { "activate-expose", no_argument, NULL, OPT_ACTV_EXPOSE }, - { "toggle-expose", no_argument, NULL, OPT_TGG_EXPOSE }, - { "activate-paging", no_argument, NULL, OPT_ACTV_PAGING }, - { "toggle-paging", no_argument, NULL, OPT_TGG_PAGING }, - { "deactivate", no_argument, NULL, OPT_DEACTV }, + { "switch", no_argument, NULL, OPT_ACTV_SWITCH }, + { "switch-prev", no_argument, NULL, OPT_ACTV_SWITCH_PREV }, + { "expose", no_argument, NULL, OPT_ACTV_EXPOSE }, + { "paging", no_argument, NULL, OPT_ACTV_PAGING }, { "start-daemon", no_argument, NULL, OPT_DM_START }, { "stop-daemon", no_argument, NULL, OPT_DM_STOP }, - { "prev", no_argument, NULL, OPT_PREV }, - { "next", no_argument, NULL, OPT_NEXT }, // { "test", no_argument, NULL, 't' }, { NULL, no_argument, NULL, 0 } }; @@ -1583,14 +1510,6 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG: ps->o.config_path = mstrdup(optarg); break; - case OPT_PREV: - ps->o.focus_initial = FI_PREV; - printfdf(false, "(): ps->o.focus_initial=%i\n", ps->o.focus_initial); - break; - case OPT_NEXT: - ps->o.focus_initial = FI_NEXT; - printfdf(false, "(): ps->o.focus_initial=%i\n", ps->o.focus_initial); - break; case 'S': debuglog = true; break; @@ -1616,33 +1535,22 @@ parse_args(session_t *ps, int argc, char **argv, bool first_pass) { case OPT_CONFIG_RELOAD: ps->o.mode = PROGMODE_RELOAD_CONFIG; break; - case OPT_ACTV_SWITCHER: - ps->o.mode = PROGMODE_ACTV_SWITCHER; + case OPT_ACTV_SWITCH: + ps->o.mode = PROGMODE_SWITCH; break; - case OPT_TGG_SWITCHER: - ps->o.mode = PROGMODE_TGG_SWITCHER; + case OPT_ACTV_SWITCH_PREV: + ps->o.mode = PROGMODE_SWITCH_PREV; break; case OPT_ACTV_EXPOSE: - ps->o.mode = PROGMODE_ACTV_EXPOSE; - break; - case OPT_TGG_EXPOSE: - ps->o.mode = PROGMODE_TGG_EXPOSE; + ps->o.mode = PROGMODE_EXPOSE; break; case OPT_ACTV_PAGING: - ps->o.mode = PROGMODE_ACTV_PAGING; - break; - case OPT_TGG_PAGING: - ps->o.mode = PROGMODE_TGG_PAGING; - break; - case OPT_DEACTV: - ps->o.mode = PROGMODE_DEACTV; + ps->o.mode = PROGMODE_PAGING; break; case OPT_DM_STOP: ps->o.mode = PROGMODE_DM_STOP; break; T_CASEBOOL(OPT_DM_START, runAsDaemon); - case OPT_PREV: break; - case OPT_NEXT: break; #undef T_CASEBOOL default: printfef(false, "(0): Unimplemented option %d.", o); @@ -1901,50 +1809,17 @@ int main(int argc, char *argv[]) { switch (ps->o.mode) { case PROGMODE_NORMAL: break; - case PROGMODE_ACTV_SWITCHER: - case PROGMODE_ACTV_EXPOSE: - case PROGMODE_ACTV_PAGING: - if(ps->o.focus_initial) - { - if(ps->o.focus_initial == FI_PREV) - queue_initial_focus_prev(pipePath); - - else if(ps->o.focus_initial == FI_NEXT) - queue_initial_focus_next(pipePath); - - // we must pause slightly, otherwise will miss next read() call in this loop() - usleep(10000); - } - if (ps->o.mode == PROGMODE_ACTV_SWITCHER) - activate_switcher(pipePath); - else if (ps->o.mode == PROGMODE_ACTV_EXPOSE) + case PROGMODE_SWITCH: + case PROGMODE_SWITCH_PREV: + case PROGMODE_EXPOSE: + case PROGMODE_PAGING: + if (ps->o.mode == PROGMODE_SWITCH) + activate_switch(pipePath); + else if (ps->o.mode == PROGMODE_EXPOSE) activate_expose(pipePath); - else if (ps->o.mode == PROGMODE_ACTV_PAGING) + else if (ps->o.mode == PROGMODE_PAGING) activate_paging(pipePath); goto main_end; - case PROGMODE_TGG_SWITCHER: - case PROGMODE_TGG_EXPOSE: - case PROGMODE_TGG_PAGING: - if(ps->o.focus_initial) - { - if(ps->o.focus_initial == FI_PREV) - queue_initial_focus_prev(pipePath); - else if(ps->o.focus_initial == FI_NEXT) - queue_initial_focus_next(pipePath); - - // we must pause slightly, otherwise will miss next read() call in this loop() - usleep(10000); - } - if (ps->o.mode == PROGMODE_TGG_SWITCHER) - toggle_switcher(pipePath); - else if (ps->o.mode == PROGMODE_TGG_EXPOSE) - toggle_expose(pipePath); - else if (ps->o.mode == PROGMODE_TGG_PAGING) - toggle_paging(pipePath); - goto main_end; - case PROGMODE_DEACTV: - deactivate(pipePath); - goto main_end; case PROGMODE_RELOAD_CONFIG: queue_reload_config(pipePath); goto main_end; diff --git a/src/skippy.h b/src/skippy.h index d959459..0978a5e 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -84,19 +84,16 @@ enum { enum progmode { PROGMODE_NORMAL, - PROGMODE_ACTV_SWITCHER, - PROGMODE_TGG_SWITCHER, - PROGMODE_ACTV_EXPOSE, - PROGMODE_TGG_EXPOSE, - PROGMODE_ACTV_PAGING, - PROGMODE_TGG_PAGING, - PROGMODE_DEACTV, + PROGMODE_SWITCH, + PROGMODE_SWITCH_PREV, + PROGMODE_EXPOSE, + PROGMODE_PAGING, PROGMODE_RELOAD_CONFIG, PROGMODE_DM_STOP, }; enum layoutmode { - LAYOUTMODE_SWITCHER, + LAYOUTMODE_SWITCH, LAYOUTMODE_EXPOSE, LAYOUTMODE_PAGING, }; From cb27de931be3f2a0d08d01d42280f751d15f25ae Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 17:36:22 -0700 Subject: [PATCH 157/205] Fix segfault: switch when not focusing on any window --- src/skippy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skippy.c b/src/skippy.c index 68e4c7f..5038dce 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -379,7 +379,7 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) leader); // check if the user specified --prev or --next on the cmdline - if(ps->o.focus_initial) + if(ps->o.focus_initial && iter) { // ps->mainwin->ignore_next_refocus = 1; From 10ee35cbb5657a74d44d2449681c0ed5a77749b0 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 17:48:54 -0700 Subject: [PATCH 158/205] Fix skippy-xd --switch-prev --- src/skippy.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 5038dce..3cc9a9a 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1106,14 +1106,16 @@ mainloop(session_t *ps, bool activate_on_start) { case PIPECMD_EXPOSE: case PIPECMD_PAGING: if (mw) { - if (piped_input != PIPECMD_SWITCH) { + if (piped_input != PIPECMD_SWITCH + && piped_input != PIPECMD_SWITCH_PREV) { mw->refocus = die = true; break; } } animating = activate = true; - if (piped_input == PIPECMD_SWITCH) { + if (piped_input == PIPECMD_SWITCH + || piped_input == PIPECMD_SWITCH_PREV) { ps->o.mode = PROGMODE_SWITCH; layout = LAYOUTMODE_SWITCH; } @@ -1810,15 +1812,16 @@ int main(int argc, char *argv[]) { case PROGMODE_NORMAL: break; case PROGMODE_SWITCH: + activate_switch(pipePath); + goto main_end; case PROGMODE_SWITCH_PREV: + activate_switch_prev(pipePath); + goto main_end; case PROGMODE_EXPOSE: + activate_expose(pipePath); + goto main_end; case PROGMODE_PAGING: - if (ps->o.mode == PROGMODE_SWITCH) - activate_switch(pipePath); - else if (ps->o.mode == PROGMODE_EXPOSE) - activate_expose(pipePath); - else if (ps->o.mode == PROGMODE_PAGING) - activate_paging(pipePath); + activate_paging(pipePath); goto main_end; case PROGMODE_RELOAD_CONFIG: queue_reload_config(pipePath); From 76d6186b742fbdb909e37ad5ab6301996335fe84 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 18:26:48 -0700 Subject: [PATCH 159/205] Default action to expose --- src/skippy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 3cc9a9a..533a522 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -785,11 +785,13 @@ mainloop(session_t *ps, bool activate_on_start) { bool activate = activate_on_start; bool pending_damage = false; long last_rendered = 0L; - enum layoutmode layout = LAYOUTMODE_SWITCH; + enum layoutmode layout = LAYOUTMODE_EXPOSE; bool animating = activate; long first_animated = 0L; switch (ps->o.mode) { + case PROGMODE_SWITCH: + layout = LAYOUTMODE_SWITCH; case PROGMODE_EXPOSE: layout = LAYOUTMODE_EXPOSE; break; @@ -797,7 +799,7 @@ mainloop(session_t *ps, bool activate_on_start) { layout = LAYOUTMODE_PAGING; break; default: - layout = LAYOUTMODE_SWITCH; + layout = LAYOUTMODE_EXPOSE; break; } From f0210dbd90d134407676c5f9365b1840d47d5c9a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 18:52:42 -0700 Subject: [PATCH 160/205] Separate showAllDesktop options for switch and expose --- skippy-xd.sample.rc | 14 ++++++++------ src/clientwin.c | 4 ++-- src/skippy.c | 3 ++- src/skippy.h | 6 ++++-- src/wm.c | 3 ++- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 9d8f41b..3ee8223 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -57,10 +57,6 @@ [general] -# exposeLayout=xd uses the same layout as switcher, maximizing screen estate -# exposeLayout=boxy tends to preserve window positions, thus guiding the eye more -exposeLayout = boxy - distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true @@ -72,6 +68,13 @@ animationDuration = 200 lazyTrans = false pipePath = /tmp/skippy-xd-fifo +# exposeLayout=xd uses the same layout as switcher, maximizing screen estate +# exposeLayout=boxy tends to preserve window positions, thus guiding the eye more +exposeLayout = boxy + +switchShowAllDesktops = true +exposeShowAllDesktops = false + # Move the mouse cursor to the next highlighted window, straight after launching skippy movePointerOnStart = true @@ -85,9 +88,8 @@ movePointerOnRaise = true switchDesktopOnActivate = false includeFrame = true allowUpscale = true -showAllDesktops = true -# Choose wether to show minimized windows +# Choose whether to show minimized windows showShadow = true cornerRadius = 5 diff --git a/src/clientwin.c b/src/clientwin.c index 1d0b2a1..00e324b 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -48,8 +48,8 @@ clientwin_validate_func(dlist *l, void *data) { return false; #endif - if (!ps->o.showAllDesktops - && ps->o.mode != PROGMODE_PAGING) { + if ((!ps->o.switchShowAllDesktops && ps->o.mode == PROGMODE_SWITCH) + || (!ps->o.exposeShowAllDesktops && ps->o.mode == PROGMODE_EXPOSE)) { CARD32 desktop = (*(CARD32 *)data), w_desktop = wm_get_window_desktop(ps, cw->wid_client); diff --git a/src/skippy.c b/src/skippy.c index 533a522..35fdf85 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1674,7 +1674,8 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "general", "allowUpscale", &ps->o.allowUpscale); config_get_int_wrap(config, "general", "cornerRadius", &ps->o.cornerRadius, 0, INT_MAX); config_get_int_wrap(config, "general", "preferredIconSize", &ps->o.preferredIconSize, 1, INT_MAX); - config_get_bool_wrap(config, "general", "showAllDesktops", &ps->o.showAllDesktops); + config_get_bool_wrap(config, "general", "switchShowAllDesktops", &ps->o.switchShowAllDesktops); + config_get_bool_wrap(config, "general", "exposeShowAllDesktops", &ps->o.exposeShowAllDesktops); config_get_bool_wrap(config, "general", "showShadow", &ps->o.showShadow); config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); diff --git a/src/skippy.h b/src/skippy.h index 0978a5e..966fea8 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -208,7 +208,8 @@ typedef struct { bool movePointerOnRaise; bool switchDesktopOnActivate; bool allowUpscale; - bool showAllDesktops; + bool switchShowAllDesktops; + bool exposeShowAllDesktops; bool showShadow; int cornerRadius; int preferredIconSize; @@ -286,7 +287,8 @@ typedef struct { .clientDisplayModes = NULL, \ .iconFillSpec = PICTSPECT_INIT, \ .fillSpec = PICTSPECT_INIT, \ - .showAllDesktops = false, \ + .switchShowAllDesktops = true, \ + .exposeShowAllDesktops = false, \ .showShadow = true, \ .buttonImgs = { NULL }, \ .background = NULL, \ diff --git a/src/wm.c b/src/wm.c index ed7295b..916bd76 100644 --- a/src/wm.c +++ b/src/wm.c @@ -393,7 +393,8 @@ wm_get_stack_sub(session_t *ps, Window root) { dlist * wm_get_stack(session_t *ps) { - if (ps->o.showAllDesktops) { + if ((!ps->o.switchShowAllDesktops && ps->o.mode == PROGMODE_SWITCH) + || (!ps->o.exposeShowAllDesktops && ps->o.mode == PROGMODE_EXPOSE)) { dlist *l = NULL; for (int i = 0; i < ScreenCount(ps->dpy); ++i) l = dlist_join(l, wm_get_stack_sub(ps, RootWindow(ps->dpy, i))); From a3d23a54edb3401249a4bf679c64ae16bdb31826 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 20:20:12 -0700 Subject: [PATCH 161/205] Highlight 1st focused window on switch --- src/focus.h | 1 + src/skippy.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/focus.h b/src/focus.h index 502af5c..ad5c3ca 100644 --- a/src/focus.h +++ b/src/focus.h @@ -115,6 +115,7 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { ps->mainwin->client_to_focus = cw; ps->mainwin->client_to_focus->focused = 1; + clientwin_render(cw); printfdf(false, "(): "); printfdf(false, "(): client_to_focus = %p", ps->mainwin->client_to_focus); diff --git a/src/skippy.c b/src/skippy.c index 35fdf85..dae0b68 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1141,8 +1141,8 @@ mainloop(session_t *ps, bool activate_on_start) { // 1st highlighted win, so we manually unfocus it here first, before moving on // to focus and highlight the next window... it's probably because we miss the Xev // since we are not in the right place in the main loop, cant unwind the call stack - mw->client_to_focus->focused = 0; - clientwin_render(mw->client_to_focus); + //mw->client_to_focus->focused = 0; + //clientwin_render(mw->client_to_focus); if (piped_input == PIPECMD_SWITCH_PREV) { From 44f3198bb18f6a3203bb7104be7ec5427ceb4235 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 14 Jun 2023 20:24:42 -0700 Subject: [PATCH 162/205] Remove bogus rendering --- src/focus.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/focus.h b/src/focus.h index ad5c3ca..3f0c6f7 100644 --- a/src/focus.h +++ b/src/focus.h @@ -103,8 +103,6 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { } assert(cw->mini.window); - clientwin_render(cw); - if (move_ptr) { printfdf(false, "(): if (move_ptr)"); From 76f34539054b78ba1f976c62bd95f4a18db08c7a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 15 Jun 2023 16:52:56 -0700 Subject: [PATCH 163/205] Window focus on paging cancel --- src/skippy.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index dae0b68..f07aed8 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -556,8 +556,17 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) if (cw->slots == current_desktop) { mw->client_to_focus = cw; - mw->client_to_focus_on_cancel = cw; mw->client_to_focus->focused = 1; + + { + dlist *iter = dlist_find(mw->clientondesktop, clientwin_cmp_func, (void *) leader); + if (!iter) { + mw->client_to_focus_on_cancel = NULL; + } + else { + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + } + } } } } @@ -849,8 +858,15 @@ mainloop(session_t *ps, bool activate_on_start) { if (layout == LAYOUTMODE_PAGING) { if (!mw->refocus) new_desktop = mw->client_to_focus->slots; - else - new_desktop = mw->client_to_focus_on_cancel->slots; + else { + if(mw->client_to_focus_on_cancel) + childwin_focus(mw->client_to_focus_on_cancel); + } + if (new_desktop == wm_get_current_desktop(ps)) { + new_desktop = -1; + if(mw->client_to_focus_on_cancel) + childwin_focus(mw->client_to_focus_on_cancel); + } } else { if (!mw->refocus) From 3f92d8dba0608fe5553a9ae18dab2d5c6b0bfe66 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 15 Jun 2023 16:52:56 -0700 Subject: [PATCH 164/205] Window focus on paging cancel --- src/skippy.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 6f63639..d036a49 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -560,8 +560,17 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) if (cw->slots == current_desktop) { mw->client_to_focus = cw; - mw->client_to_focus_on_cancel = cw; mw->client_to_focus->focused = 1; + + { + dlist *iter = dlist_find(mw->clientondesktop, clientwin_cmp_func, (void *) leader); + if (!iter) { + mw->client_to_focus_on_cancel = NULL; + } + else { + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + } + } } } } @@ -853,8 +862,15 @@ mainloop(session_t *ps, bool activate_on_start) { if (layout == LAYOUTMODE_PAGING) { if (!mw->refocus) new_desktop = mw->client_to_focus->slots; - else - new_desktop = mw->client_to_focus_on_cancel->slots; + else { + if(mw->client_to_focus_on_cancel) + childwin_focus(mw->client_to_focus_on_cancel); + } + if (new_desktop == wm_get_current_desktop(ps)) { + new_desktop = -1; + if(mw->client_to_focus_on_cancel) + childwin_focus(mw->client_to_focus_on_cancel); + } } else { if (!mw->refocus) From 2896342b5f70e1cf7d8c3019ecbb761583b9ff5a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 15 Jun 2023 19:17:40 -0700 Subject: [PATCH 165/205] Tooltip on paging desktop representatives --- src/clientwin.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/clientwin.c b/src/clientwin.c index 00e324b..a8459de 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -747,6 +747,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { cw->mainwin->cw_tooltip = cw; int win_title_len = 0; FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); + if (!win_title) + win_title = wm_get_window_title(ps, cw->mini.window, &win_title_len); if (win_title) { tooltip_map(cw->mainwin->tooltip, ev->xcrossing.x_root, ev->xcrossing.y_root, From 3a493c56008ce87b097feebf89af4de103ffe40d Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 17 Jun 2023 20:42:14 -0700 Subject: [PATCH 166/205] Rewrite help message --- src/skippy.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index f07aed8..687932e 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1332,19 +1332,23 @@ show_help() { fputs("skippy-xd " SKIPPYXD_VERSION "\n" "Usage: skippy-xd [command]\n\n" "The available commands are:\n" + "\n" " [no command] - activate expose once without daemon.\n" - " --config-reload - reload configuration file; currently the file path must remain unchanged.\n" - " --config - read the specified configuration file.\n" - " --start-daemon - starts the daemon running.\n" - " --stop-daemon - stops the daemon running.\n" - " --switch - connects to daemon and activate switch.\n" - " --switch-prev - connects to daemon and activate switch.\n" + " --help - show this message.\n" + " -S - enable debugging logs.\n" + "\n" + " --config - read configuration file from path.\n" + " --config-reload - reload configuration file from the previous path.\n" + "\n" + " --start-daemon - runs as daemon mode.\n" + " --stop-daemon - terminates skippy-xd daemon.\n" + "\n" + " --switch - connects to daemon and switch to next window.\n" + " --switch-prev - connects to daemon and switch to previous window.\n" " --expose - connects to daemon and activate expose.\n" " --paging - connects to daemon and activate paging.\n" // " --test - Temporary development testing. To be removed.\n" "\n" - " --help - show this message.\n" - " -S - enable debugging logs.\n" , stdout); #ifdef CFG_LIBPNG spng_about(stdout); From 104f3d15830b6c735ffe6c8b2928d9da2eaaec89 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 20:59:52 -0700 Subject: [PATCH 167/205] Reorder functions in file --- src/skippy.c | 200 +++++++++++++++++++++++++-------------------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 687932e..e32eb3a 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -261,6 +261,106 @@ parse_pictspec(session_t *ps, const char *s, pictspec_t *dest) { return true; } +static inline const char * +ev_dumpstr_type(const XEvent *ev) { + switch (ev->type) { + CASESTRRET(KeyPress); + CASESTRRET(KeyRelease); + CASESTRRET(ButtonPress); + CASESTRRET(ButtonRelease); + CASESTRRET(MotionNotify); + CASESTRRET(EnterNotify); + CASESTRRET(LeaveNotify); + CASESTRRET(FocusIn); + CASESTRRET(FocusOut); + CASESTRRET(KeymapNotify); + CASESTRRET(Expose); + CASESTRRET(GraphicsExpose); + CASESTRRET(NoExpose); + CASESTRRET(CirculateRequest); + CASESTRRET(ConfigureRequest); + CASESTRRET(MapRequest); + CASESTRRET(ResizeRequest); + CASESTRRET(CirculateNotify); + CASESTRRET(ConfigureNotify); + CASESTRRET(CreateNotify); + CASESTRRET(DestroyNotify); + CASESTRRET(GravityNotify); + CASESTRRET(MapNotify); + CASESTRRET(MappingNotify); + CASESTRRET(ReparentNotify); + CASESTRRET(UnmapNotify); + CASESTRRET(VisibilityNotify); + CASESTRRET(ColormapNotify); + CASESTRRET(ClientMessage); + CASESTRRET(PropertyNotify); + CASESTRRET(SelectionClear); + CASESTRRET(SelectionNotify); + CASESTRRET(SelectionRequest); + } + + return "Unknown"; +} + +static inline Window +ev_window(session_t *ps, const XEvent *ev) { +#define T_SETWID(type, ele) case type: return ev->ele.window + switch (ev->type) { + case KeyPress: + T_SETWID(KeyRelease, xkey); + case ButtonPress: + T_SETWID(ButtonRelease, xbutton); + T_SETWID(MotionNotify, xmotion); + case EnterNotify: + T_SETWID(LeaveNotify, xcrossing); + case FocusIn: + T_SETWID(FocusOut, xfocus); + T_SETWID(KeymapNotify, xkeymap); + T_SETWID(Expose, xexpose); + case GraphicsExpose: return ev->xgraphicsexpose.drawable; + case NoExpose: return ev->xnoexpose.drawable; + T_SETWID(CirculateNotify, xcirculate); + T_SETWID(ConfigureNotify, xconfigure); + T_SETWID(CreateNotify, xcreatewindow); + T_SETWID(DestroyNotify, xdestroywindow); + T_SETWID(GravityNotify, xgravity); + T_SETWID(MapNotify, xmap); + T_SETWID(MappingNotify, xmapping); + T_SETWID(ReparentNotify, xreparent); + T_SETWID(UnmapNotify, xunmap); + T_SETWID(VisibilityNotify, xvisibility); + T_SETWID(ColormapNotify, xcolormap); + T_SETWID(ClientMessage, xclient); + T_SETWID(PropertyNotify, xproperty); + T_SETWID(SelectionClear, xselectionclear); + case SelectionNotify: return ev->xselection.requestor; + } +#undef T_SETWID + if (ps->xinfo.damage_ev_base + XDamageNotify == ev->type) + return ((XDamageNotifyEvent *) ev)->drawable; + + printfef(false, "(): Failed to find window for event type %d. Troubles ahead.", + ev->type); + + return ev->xany.window; +} + +static inline void +ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { + if (!ev || (ps->xinfo.damage_ev_base + XDamageNotify) == ev->type) return; + // if (MotionNotify == ev->type) return; + + const char *name = ev_dumpstr_type(ev); + + Window wid = ev_window(ps, ev); + const char *wextra = ""; + if (ps->root == wid) wextra = "(Root)"; + if (mw && mw->window == wid) wextra = "(Main)"; + + print_timestamp(ps); + printfdf(false, "(): Event %-13.13s wid %#010lx %s", name, wid, wextra); +} + static void anime( MainWin *mw, @@ -605,106 +705,6 @@ desktopwin_map(ClientWin *cw) XRaiseWindow(ps->dpy, cw->mini.window); } -static inline const char * -ev_dumpstr_type(const XEvent *ev) { - switch (ev->type) { - CASESTRRET(KeyPress); - CASESTRRET(KeyRelease); - CASESTRRET(ButtonPress); - CASESTRRET(ButtonRelease); - CASESTRRET(MotionNotify); - CASESTRRET(EnterNotify); - CASESTRRET(LeaveNotify); - CASESTRRET(FocusIn); - CASESTRRET(FocusOut); - CASESTRRET(KeymapNotify); - CASESTRRET(Expose); - CASESTRRET(GraphicsExpose); - CASESTRRET(NoExpose); - CASESTRRET(CirculateRequest); - CASESTRRET(ConfigureRequest); - CASESTRRET(MapRequest); - CASESTRRET(ResizeRequest); - CASESTRRET(CirculateNotify); - CASESTRRET(ConfigureNotify); - CASESTRRET(CreateNotify); - CASESTRRET(DestroyNotify); - CASESTRRET(GravityNotify); - CASESTRRET(MapNotify); - CASESTRRET(MappingNotify); - CASESTRRET(ReparentNotify); - CASESTRRET(UnmapNotify); - CASESTRRET(VisibilityNotify); - CASESTRRET(ColormapNotify); - CASESTRRET(ClientMessage); - CASESTRRET(PropertyNotify); - CASESTRRET(SelectionClear); - CASESTRRET(SelectionNotify); - CASESTRRET(SelectionRequest); - } - - return "Unknown"; -} - -static inline Window -ev_window(session_t *ps, const XEvent *ev) { -#define T_SETWID(type, ele) case type: return ev->ele.window - switch (ev->type) { - case KeyPress: - T_SETWID(KeyRelease, xkey); - case ButtonPress: - T_SETWID(ButtonRelease, xbutton); - T_SETWID(MotionNotify, xmotion); - case EnterNotify: - T_SETWID(LeaveNotify, xcrossing); - case FocusIn: - T_SETWID(FocusOut, xfocus); - T_SETWID(KeymapNotify, xkeymap); - T_SETWID(Expose, xexpose); - case GraphicsExpose: return ev->xgraphicsexpose.drawable; - case NoExpose: return ev->xnoexpose.drawable; - T_SETWID(CirculateNotify, xcirculate); - T_SETWID(ConfigureNotify, xconfigure); - T_SETWID(CreateNotify, xcreatewindow); - T_SETWID(DestroyNotify, xdestroywindow); - T_SETWID(GravityNotify, xgravity); - T_SETWID(MapNotify, xmap); - T_SETWID(MappingNotify, xmapping); - T_SETWID(ReparentNotify, xreparent); - T_SETWID(UnmapNotify, xunmap); - T_SETWID(VisibilityNotify, xvisibility); - T_SETWID(ColormapNotify, xcolormap); - T_SETWID(ClientMessage, xclient); - T_SETWID(PropertyNotify, xproperty); - T_SETWID(SelectionClear, xselectionclear); - case SelectionNotify: return ev->xselection.requestor; - } -#undef T_SETWID - if (ps->xinfo.damage_ev_base + XDamageNotify == ev->type) - return ((XDamageNotifyEvent *) ev)->drawable; - - printfef(false, "(): Failed to find window for event type %d. Troubles ahead.", - ev->type); - - return ev->xany.window; -} - -static inline void -ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) { - if (!ev || (ps->xinfo.damage_ev_base + XDamageNotify) == ev->type) return; - // if (MotionNotify == ev->type) return; - - const char *name = ev_dumpstr_type(ev); - - Window wid = ev_window(ps, ev); - const char *wextra = ""; - if (ps->root == wid) wextra = "(Root)"; - if (mw && mw->window == wid) wextra = "(Main)"; - - print_timestamp(ps); - printfdf(false, "(): Event %-13.13s wid %#010lx %s", name, wid, wextra); -} - static bool skippy_activate(MainWin *mw, enum layoutmode layout) { From cb4d194f9cd42416b4d9527e9372cae454dcc32c Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 21:10:20 -0700 Subject: [PATCH 168/205] Refactor config option movePointer* into one --- skippy-xd.sample.rc | 11 ++--------- src/clientwin.c | 2 +- src/focus.h | 2 +- src/skippy.c | 6 ++---- src/skippy.h | 8 ++------ 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 3ee8223..2ab8277 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -75,15 +75,8 @@ exposeLayout = boxy switchShowAllDesktops = true exposeShowAllDesktops = false -# Move the mouse cursor to the next highlighted window, straight after launching skippy -movePointerOnStart = true - -# Move the mouse cursor over the currently highlighted window, when using the keyboard to navigate between windows -movePointerOnSelect = true - -# After activating the selected window, the skippy window picker is dissmissed. Then move mouse cursor to the center of the selected window. -# Otherwise (if false), the mouse cursor will remain in the location where it was at the time when skippy was dismissed. -movePointerOnRaise = true +# Move the mouse cursor when skippy is activated +movePointer = false switchDesktopOnActivate = false includeFrame = true diff --git a/src/clientwin.c b/src/clientwin.c index a8459de..536a836 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -566,7 +566,7 @@ void childwin_focus(ClientWin *cw) { session_t * const ps = cw->mainwin->ps; - if (ps->o.movePointerOnRaise) + if (ps->o.movePointer) XWarpPointer(ps->dpy, None, cw->wid_client, 0, 0, 0, 0, cw->src.width / 2, cw->src.height / 2); XRaiseWindow(ps->dpy, cw->wid_client); diff --git a/src/focus.h b/src/focus.h index 3f0c6f7..89bcad2 100644 --- a/src/focus.h +++ b/src/focus.h @@ -121,7 +121,7 @@ focus_miniw_adv(session_t *ps, ClientWin *cw, bool move_ptr) { static inline void focus_miniw(session_t *ps, ClientWin *cw) { - focus_miniw_adv(ps, cw, ps->o.movePointerOnSelect); + focus_miniw_adv(ps, cw, ps->o.movePointer); } /** diff --git a/src/skippy.c b/src/skippy.c index e32eb3a..e13a112 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -932,7 +932,7 @@ mainloop(session_t *ps, bool activate_on_start) { animating = false; last_rendered = time_in_millis(); focus_miniw_adv(ps, mw->client_to_focus, - ps->o.movePointerOnStart); + ps->o.movePointer); if (layout == LAYOUTMODE_PAGING) { foreach_dlist (mw->dminis) { @@ -1697,9 +1697,7 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "general", "switchShowAllDesktops", &ps->o.switchShowAllDesktops); config_get_bool_wrap(config, "general", "exposeShowAllDesktops", &ps->o.exposeShowAllDesktops); config_get_bool_wrap(config, "general", "showShadow", &ps->o.showShadow); - config_get_bool_wrap(config, "general", "movePointerOnStart", &ps->o.movePointerOnStart); - config_get_bool_wrap(config, "general", "movePointerOnSelect", &ps->o.movePointerOnSelect); - config_get_bool_wrap(config, "general", "movePointerOnRaise", &ps->o.movePointerOnRaise); + config_get_bool_wrap(config, "general", "movePointer", &ps->o.movePointer); config_get_bool_wrap(config, "general", "switchDesktopOnActivate", &ps->o.switchDesktopOnActivate); config_get_bool_wrap(config, "xinerama", "showAll", &ps->o.xinerama_showAll); config_get_int_wrap(config, "normal", "tintOpacity", &ps->o.normal_tintOpacity, 0, 256); diff --git a/src/skippy.h b/src/skippy.h index 966fea8..6068107 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -203,9 +203,7 @@ typedef struct { bool lazyTrans; bool includeFrame; char *pipePath; - bool movePointerOnStart; - bool movePointerOnSelect; - bool movePointerOnRaise; + bool movePointer; bool switchDesktopOnActivate; bool allowUpscale; bool switchShowAllDesktops; @@ -277,9 +275,7 @@ typedef struct { .lazyTrans = false, \ .includeFrame = false, \ .pipePath = NULL, \ - .movePointerOnStart = true, \ - .movePointerOnSelect = true, \ - .movePointerOnRaise = true, \ + .movePointer = false, \ .switchDesktopOnActivate = false, \ .allowUpscale = true, \ .cornerRadius = 0, \ From 13ddb77b7264254780a4fb546a9234dab2ad3d86 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 21:25:42 -0700 Subject: [PATCH 169/205] Remove config option switchDesktopOnActivate, which apparently does nothing --- skippy-xd.sample.rc | 12 ++++++------ src/skippy.c | 1 - src/skippy.h | 2 -- src/wm.h | 5 ----- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 2ab8277..4254fda 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -57,6 +57,10 @@ [general] +background = +lazyTrans = false +pipePath = /tmp/skippy-xd-fifo + distance = 50 useNetWMFullscreen = true ignoreSkipTaskbar = true @@ -65,9 +69,6 @@ updateFreq = 60.0 # set = 0 to switch off animations animationDuration = 200 -lazyTrans = false -pipePath = /tmp/skippy-xd-fifo - # exposeLayout=xd uses the same layout as switcher, maximizing screen estate # exposeLayout=boxy tends to preserve window positions, thus guiding the eye more exposeLayout = boxy @@ -78,11 +79,11 @@ exposeShowAllDesktops = false # Move the mouse cursor when skippy is activated movePointer = false -switchDesktopOnActivate = false includeFrame = true allowUpscale = true -# Choose whether to show minimized windows +# Choose whether to show shadow windows: windows that are minimized, +# shaded, or on other virtual desktops showShadow = true cornerRadius = 5 @@ -90,7 +91,6 @@ preferredIconSize = 48 showIconsOnThumbnails = true iconFillSpec = orig mid mid #00FFFF fillSpec = orig mid mid #FFFFFF -background = [xinerama] showAll = true diff --git a/src/skippy.c b/src/skippy.c index e13a112..ec7b3dd 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1698,7 +1698,6 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "general", "exposeShowAllDesktops", &ps->o.exposeShowAllDesktops); config_get_bool_wrap(config, "general", "showShadow", &ps->o.showShadow); config_get_bool_wrap(config, "general", "movePointer", &ps->o.movePointer); - config_get_bool_wrap(config, "general", "switchDesktopOnActivate", &ps->o.switchDesktopOnActivate); config_get_bool_wrap(config, "xinerama", "showAll", &ps->o.xinerama_showAll); config_get_int_wrap(config, "normal", "tintOpacity", &ps->o.normal_tintOpacity, 0, 256); config_get_int_wrap(config, "normal", "opacity", &ps->o.normal_opacity, 0, 256); diff --git a/src/skippy.h b/src/skippy.h index 6068107..6e4ffc9 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -204,7 +204,6 @@ typedef struct { bool includeFrame; char *pipePath; bool movePointer; - bool switchDesktopOnActivate; bool allowUpscale; bool switchShowAllDesktops; bool exposeShowAllDesktops; @@ -276,7 +275,6 @@ typedef struct { .includeFrame = false, \ .pipePath = NULL, \ .movePointer = false, \ - .switchDesktopOnActivate = false, \ .allowUpscale = true, \ .cornerRadius = 0, \ .preferredIconSize = 48, \ diff --git a/src/wm.h b/src/wm.h index e3752ef..bf8b6b1 100644 --- a/src/wm.h +++ b/src/wm.h @@ -158,11 +158,6 @@ static inline void wm_activate_window(session_t *ps, Window wid) { if (!wid) return; - if (ps->o.switchDesktopOnActivate) { - long tgt = wm_get_window_desktop(ps, wid); - if (tgt >= 0) - wm_set_desktop_ewmh(ps, tgt); - } // Order is important, to avoid "intelligent" WMs fixing our focus stealing wm_activate_window_ewmh(ps, wid); XSetInputFocus(ps->dpy, wid, RevertToParent, CurrentTime); From e1a32e16a5efccda808213d7fd03fd14159de7f1 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 21:33:52 -0700 Subject: [PATCH 170/205] Remove config option useNetWMFullscreen, since wm_check_netwm() checks it, and it defaults to true anyway --- skippy-xd.sample.rc | 1 - src/wm.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 4254fda..6255a3e 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -62,7 +62,6 @@ lazyTrans = false pipePath = /tmp/skippy-xd-fifo distance = 50 -useNetWMFullscreen = true ignoreSkipTaskbar = true updateFreq = 60.0 diff --git a/src/wm.c b/src/wm.c index 916bd76..dda4038 100644 --- a/src/wm.c +++ b/src/wm.c @@ -560,7 +560,7 @@ void wm_set_fullscreen(session_t *ps, Window window, int x, int y, unsigned width, unsigned height) { Display *dpy = ps->dpy; - if (ps->o.useNetWMFullscreen && ps->has_ewmh_fullscreen) { + if (ps->has_ewmh_fullscreen) { Atom props[] = { _NET_WM_STATE_FULLSCREEN, _NET_WM_STATE_SKIP_TASKBAR, From f853182a24e5c2c62a482673a09b1bfd826b1fe8 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 21:48:14 -0700 Subject: [PATCH 171/205] Remove config option ignoreSkipTaskbar Perhaps similar filtering of window states to be implemented in the future --- skippy-xd.sample.rc | 1 - src/skippy.c | 1 - src/skippy.h | 2 -- src/wm.c | 5 ++--- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 6255a3e..f30cfe6 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -62,7 +62,6 @@ lazyTrans = false pipePath = /tmp/skippy-xd-fifo distance = 50 -ignoreSkipTaskbar = true updateFreq = 60.0 # set = 0 to switch off animations diff --git a/src/skippy.c b/src/skippy.c index ec7b3dd..9ac1661 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1684,7 +1684,6 @@ load_config_file(session_t *ps) config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); - config_get_bool_wrap(config, "general", "ignoreSkipTaskbar", &ps->o.ignoreSkipTaskbar); config_get_bool_wrap(config, "general", "acceptOvRedir", &ps->o.acceptOvRedir); config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); diff --git a/src/skippy.h b/src/skippy.h index 6e4ffc9..e7c2ea1 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -195,7 +195,6 @@ typedef struct { int exposeLayout; int distance; bool useNetWMFullscreen; - bool ignoreSkipTaskbar; bool acceptOvRedir; bool acceptWMWin; double updateFreq; @@ -266,7 +265,6 @@ typedef struct { .exposeLayout = LAYOUT_BOXY, \ .distance = 50, \ .useNetWMFullscreen = true, \ - .ignoreSkipTaskbar = false, \ .acceptOvRedir = false, \ .acceptWMWin = false, \ .updateFreq = 60.0, \ diff --git a/src/wm.c b/src/wm.c index dda4038..8fe49bf 100644 --- a/src/wm.c +++ b/src/wm.c @@ -609,8 +609,7 @@ wm_validate_window(session_t *ps, Window wid) { long v = prop.data32[i]; if (!ps->o.showShadow && _NET_WM_STATE_HIDDEN == v) result = false; - else if (ps->o.ignoreSkipTaskbar - && _NET_WM_STATE_SKIP_TASKBAR == v) + else if (_NET_WM_STATE_SKIP_TASKBAR == v) result = false; else if (_NET_WM_STATE_SHADED == v) result = false; @@ -626,7 +625,7 @@ wm_validate_window(session_t *ps, Window wid) { result = false; free_winprop(&prop); - if (result && ps->o.ignoreSkipTaskbar) { + if (result) { prop = wid_get_prop(ps, wid, _WIN_HINTS, 1, XA_CARDINAL, 0); if (winprop_get_int(&prop) & WIN_HINTS_SKIP_TASKBAR) result = false; From 94e440b92e4406458f4448a85e002274872c4eb2 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 22:02:28 -0700 Subject: [PATCH 172/205] Fill comments for config options --- skippy-xd.sample.rc | 52 +++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index f30cfe6..f573961 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -18,7 +18,7 @@ # # - opacity is an integer in the range of 0-255 # -# - brighness is a floating point number (with 0.0 as neutral) +# - brightness is a floating point number (with 0.0 as neutral) # # - if the update frequency is a negative value, the mini-windows will only # be updated when they're explicitly rendered (like, when they gain or @@ -31,7 +31,7 @@ # [WIDTHxHEIGHT] [orig|scale|scalek|tile] [left|mid|right] [left|mid|right] # [COLOR|#FFFFFFFF] [PATH] # -# - keysUp, keywDown, eysLeft, keysRight: +# - keysUp, keysDown, keysLeft, keysRight: # selects the window in the direction compared to the current selected window, # without wrapping # @@ -57,34 +57,54 @@ [general] -background = -lazyTrans = false +# File path of skippy-xd pipe daemon communication pipePath = /tmp/skippy-xd-fifo -distance = 50 -updateFreq = 60.0 - -# set = 0 to switch off animations -animationDuration = 200 +# Background picture when skippy-xd is activated +background = -# exposeLayout=xd uses the same layout as switcher, maximizing screen estate -# exposeLayout=boxy tends to preserve window positions, thus guiding the eye more -exposeLayout = boxy +# Frequency to update pixmaps +updateFreq = 60.0 -switchShowAllDesktops = true -exposeShowAllDesktops = false +# Allow other compositors such as picom handle transparency +lazyTrans = false # Move the mouse cursor when skippy is activated movePointer = false +# Set = 0 to switch off animations +# for switch, there is never animation +animationDuration = 200 + +# Relative minimal distance between windows +distance = 50 + +# Whether to display window frames includeFrame = true + +# Whether to show the window bigger than its original size allowUpscale = true -# Choose whether to show shadow windows: windows that are minimized, -# shaded, or on other virtual desktops +# Choose whether to show shadow windows: +# windows that are minimized, shaded, or on other virtual desktops showShadow = true +# exposeLayout=xd uses the same layout as switcher, maximizing screen estate +# exposeLayout=boxy tends to preserve window positions, thus guiding the eye more +exposeLayout = boxy + +# For switch and expose, +# Whether to limit window select on current virtual desktop +# Or allow window selection on all virtual desktops +# Paging always show all desktops +switchShowAllDesktops = true +exposeShowAllDesktops = false + +# Show window previews with rounded corners, +# with corner radius in pixels cornerRadius = 5 + +# Icon visual parameters preferredIconSize = 48 showIconsOnThumbnails = true iconFillSpec = orig mid mid #00FFFF From 0e43b8360a8bbdebaf2ad4f102210457f250256f Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 22:07:24 -0700 Subject: [PATCH 173/205] Remove keysReverseDirection and modifierKeyMasksReverseDirection, which are apparently never used --- skippy-xd.sample.rc | 2 -- src/clientwin.c | 36 ++++++------------------------------ src/mainwin.c | 9 --------- src/mainwin.h | 4 ---- src/skippy.c | 6 ------ src/skippy.h | 2 -- 6 files changed, 6 insertions(+), 53 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index f573961..b93839a 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -155,5 +155,3 @@ keysExitCancelOnPress = Escape BackSpace x q keysExitCancelOnRelease = keysExitSelectOnPress = Return space keysExitSelectOnRelease = Super_L Super_R Alt_L Alt_R ISO_Level3_Shift -keysReverseDirection = Tab -modifierKeyMasksReverseDirection = ShiftMask ControlMask diff --git a/src/clientwin.c b/src/clientwin.c index 536a836..0e6d16c 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -590,58 +590,34 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { report_key_modifiers(evk); if (debuglog) fputs("\n", stdout); - bool reverse_direction = false; - - if (arr_modkeymasks_includes(cw->mainwin->modifierKeyMasks_ReverseDirection, evk->state)) - if(arr_keycodes_includes(cw->mainwin->keycodes_ReverseDirection, evk->keycode)) - reverse_direction = true; - if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) { - if(reverse_direction) - focus_down(cw); - else - focus_up(cw); + focus_up(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) { - if(reverse_direction) - focus_up(cw); - else - focus_down(cw); + focus_down(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Left, evk->keycode)) { - if(reverse_direction) - focus_right(cw); - else - focus_left(cw); + focus_left(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) { - if(reverse_direction) - focus_left(cw); - else - focus_right(cw); + focus_right(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Prev, evk->keycode)) { - if(reverse_direction) - focus_miniw_next(ps, cw); - else - focus_miniw_prev(ps, cw); + focus_miniw_prev(ps, cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Next, evk->keycode)) { - if(reverse_direction) - focus_miniw_prev(ps, cw); - else - focus_miniw_next(ps, cw); + focus_miniw_next(ps, cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) diff --git a/src/mainwin.c b/src/mainwin.c index 4725c15..5ce1980 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -150,10 +150,6 @@ mainwin_reload(session_t *ps, MainWin *mw) { keys_str_syms(ps->o.bindings_keysExitCancelOnRelease, &mw->keysyms_ExitCancelOnRelease); keys_str_syms(ps->o.bindings_keysExitSelectOnPress, &mw->keysyms_ExitSelectOnPress); keys_str_syms(ps->o.bindings_keysExitSelectOnRelease, &mw->keysyms_ExitSelectOnRelease); - keys_str_syms(ps->o.bindings_keysReverseDirection, &mw->keysyms_ReverseDirection); - - // convert the modifier key masks settings strings into arrays of enums - modkeymasks_str_enums(ps->o.bindings_modifierKeyMasksReverseDirection, &mw->modifierKeyMasks_ReverseDirection); // convert the arrays of KeySyms into arrays of KeyCodes, for this specific Display keysyms_arr_keycodes(dpy, mw->keysyms_Up, &mw->keycodes_Up); @@ -166,7 +162,6 @@ mainwin_reload(session_t *ps, MainWin *mw) { keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnRelease, &mw->keycodes_ExitCancelOnRelease); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnPress, &mw->keycodes_ExitSelectOnPress); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnRelease, &mw->keycodes_ExitSelectOnRelease); - keysyms_arr_keycodes(dpy, mw->keysyms_ReverseDirection, &mw->keycodes_ReverseDirection); // we check all possible pairs, one pair at a time. This is in a specific order, to give a more helpful error msg check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysDown", mw->keysyms_Down); @@ -480,9 +475,6 @@ mainwin_destroy(MainWin *mw) { free(mw->keysyms_ExitCancelOnRelease); free(mw->keysyms_ExitSelectOnPress); free(mw->keysyms_ExitSelectOnRelease); - free(mw->keysyms_ReverseDirection); - - free(mw->modifierKeyMasks_ReverseDirection); free(mw->keycodes_Up); free(mw->keycodes_Down); @@ -494,7 +486,6 @@ mainwin_destroy(MainWin *mw) { free(mw->keycodes_ExitCancelOnRelease); free(mw->keycodes_ExitSelectOnPress); free(mw->keycodes_ExitSelectOnRelease); - free(mw->keycodes_ReverseDirection); free(mw); } diff --git a/src/mainwin.h b/src/mainwin.h index 4686ebb..83d95dc 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -63,9 +63,6 @@ struct _mainwin_t { KeySym *keysyms_ExitCancelOnRelease; KeySym *keysyms_ExitSelectOnPress; KeySym *keysyms_ExitSelectOnRelease; - KeySym *keysyms_ReverseDirection; - - int *modifierKeyMasks_ReverseDirection; KeyCode *keycodes_Up; KeyCode *keycodes_Down; @@ -77,7 +74,6 @@ struct _mainwin_t { KeyCode *keycodes_ExitCancelOnRelease; KeyCode *keycodes_ExitSelectOnPress; KeyCode *keycodes_ExitSelectOnRelease; - KeyCode *keycodes_ReverseDirection; bool mapped; diff --git a/src/skippy.c b/src/skippy.c index 9ac1661..39481eb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1642,8 +1642,6 @@ load_config_file(session_t *ps) ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitCancelOnRelease", "")); ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitSelectOnPress", "Return space")); ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitSelectOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); - ps->o.bindings_keysReverseDirection = mstrdup(config_get(config, "bindings", "keysReverseDirection", "Tab")); - ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); // print an error message for any key bindings that aren't recognized check_keysyms(ps->o.config_path, ": [bindings] keysUp =", ps->o.bindings_keysUp); @@ -1656,8 +1654,6 @@ load_config_file(session_t *ps) check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnRelease =", ps->o.bindings_keysExitSelectOnRelease); - check_keysyms(ps->o.config_path, ": [bindings] keysReverseDirection =", ps->o.bindings_keysReverseDirection); - check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) @@ -1939,8 +1935,6 @@ int main(int argc, char *argv[]) { free(ps->o.bindings_keysExitCancelOnRelease); free(ps->o.bindings_keysExitSelectOnPress); free(ps->o.bindings_keysExitSelectOnRelease); - free(ps->o.bindings_keysReverseDirection); - free(ps->o.bindings_modifierKeyMasksReverseDirection); } if (ps->fd_pipe >= 0) diff --git a/src/skippy.h b/src/skippy.h index e7c2ea1..b36ac7a 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -253,8 +253,6 @@ typedef struct { char *bindings_keysExitCancelOnRelease; char *bindings_keysExitSelectOnPress; char *bindings_keysExitSelectOnRelease; - char *bindings_keysReverseDirection; - char *bindings_modifierKeyMasksReverseDirection; } options_t; #define OPTIONST_INIT { \ From bd9b79d56da0c9a8dc29b422947bb7506aabe18e Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 22:17:00 -0700 Subject: [PATCH 174/205] Remove comments in config file --- skippy-xd.sample.rc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index b93839a..bdb6d0f 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -9,9 +9,6 @@ # - colors can be anything XAllocNamedColor can handle # (like "black" or "#000000") # -# - distance is a relative number, and is scaled according to the scale -# factor applied to windows -# # - fonts are Xft font descriptions # # - booleans are "true" or anything but "true" (-> false) @@ -20,13 +17,6 @@ # # - brightness is a floating point number (with 0.0 as neutral) # -# - if the update frequency is a negative value, the mini-windows will only -# be updated when they're explicitly rendered (like, when they gain or -# lose focus). otherwise updateFreq is how many updates per second (fps) -# -# - the 'shadowText' option can be a color or 'none', in which case the -# drop-shadow effect is disabled -# # - Picture specification: # [WIDTHxHEIGHT] [orig|scale|scalek|tile] [left|mid|right] [left|mid|right] # [COLOR|#FFFFFFFF] [PATH] From e356c318e8ec048375dc3260c10f70f64d72d9dd Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sun, 18 Jun 2023 22:53:10 -0700 Subject: [PATCH 175/205] Remove comment in config file --- skippy-xd.sample.rc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index bdb6d0f..e056c57 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -38,12 +38,6 @@ # "close-icccm" (close window with ICCCM method), "close-ewmh" (close # window with EWMH method), or "destroy" (forcefully destroy the window). # -# - [bindings] key* = is a list of valid XWindows KeySym identifiers, case -# sensitive and seperated list. Run the program 'xev' to find them. -# -# - [bindings] modifierKeyMasks* = is a list of valid XWindows modifier key -# bitmask identifiers, as defined in the /usr/include/X11/X.h header file. -# [general] From a5a0d491005d36db5ac98c070933128cd44234e6 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 19 Jun 2023 07:28:06 +0100 Subject: [PATCH 176/205] Revert "Remove comment in config file" (#131) --- skippy-xd.sample.rc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index e056c57..bdb6d0f 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -38,6 +38,12 @@ # "close-icccm" (close window with ICCCM method), "close-ewmh" (close # window with EWMH method), or "destroy" (forcefully destroy the window). # +# - [bindings] key* = is a list of valid XWindows KeySym identifiers, case +# sensitive and seperated list. Run the program 'xev' to find them. +# +# - [bindings] modifierKeyMasks* = is a list of valid XWindows modifier key +# bitmask identifiers, as defined in the /usr/include/X11/X.h header file. +# [general] From 3fb3b95a672dee9e6d9c4d030d1a5d55471f8098 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Mon, 19 Jun 2023 13:03:46 +0100 Subject: [PATCH 177/205] Revert "Remove keysReverseDirection and modifierKeyMasksReverseDirection, which" This reverts commit 0e43b8360a8bbdebaf2ad4f102210457f250256f. --- skippy-xd.sample.rc | 2 ++ src/clientwin.c | 36 ++++++++++++++++++++++++++++++------ src/mainwin.c | 9 +++++++++ src/mainwin.h | 4 ++++ src/skippy.c | 6 ++++++ src/skippy.h | 2 ++ 6 files changed, 53 insertions(+), 6 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index bdb6d0f..b187754 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -145,3 +145,5 @@ keysExitCancelOnPress = Escape BackSpace x q keysExitCancelOnRelease = keysExitSelectOnPress = Return space keysExitSelectOnRelease = Super_L Super_R Alt_L Alt_R ISO_Level3_Shift +keysReverseDirection = Tab +modifierKeyMasksReverseDirection = ShiftMask ControlMask diff --git a/src/clientwin.c b/src/clientwin.c index 0e6d16c..536a836 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -590,34 +590,58 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { report_key_modifiers(evk); if (debuglog) fputs("\n", stdout); + bool reverse_direction = false; + + if (arr_modkeymasks_includes(cw->mainwin->modifierKeyMasks_ReverseDirection, evk->state)) + if(arr_keycodes_includes(cw->mainwin->keycodes_ReverseDirection, evk->keycode)) + reverse_direction = true; + if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) { - focus_up(cw); + if(reverse_direction) + focus_down(cw); + else + focus_up(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) { - focus_down(cw); + if(reverse_direction) + focus_up(cw); + else + focus_down(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Left, evk->keycode)) { - focus_left(cw); + if(reverse_direction) + focus_right(cw); + else + focus_left(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) { - focus_right(cw); + if(reverse_direction) + focus_left(cw); + else + focus_right(cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Prev, evk->keycode)) { - focus_miniw_prev(ps, cw); + if(reverse_direction) + focus_miniw_next(ps, cw); + else + focus_miniw_prev(ps, cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Next, evk->keycode)) { - focus_miniw_next(ps, cw); + if(reverse_direction) + focus_miniw_prev(ps, cw); + else + focus_miniw_next(ps, cw); } else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) diff --git a/src/mainwin.c b/src/mainwin.c index 5ce1980..4725c15 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -150,6 +150,10 @@ mainwin_reload(session_t *ps, MainWin *mw) { keys_str_syms(ps->o.bindings_keysExitCancelOnRelease, &mw->keysyms_ExitCancelOnRelease); keys_str_syms(ps->o.bindings_keysExitSelectOnPress, &mw->keysyms_ExitSelectOnPress); keys_str_syms(ps->o.bindings_keysExitSelectOnRelease, &mw->keysyms_ExitSelectOnRelease); + keys_str_syms(ps->o.bindings_keysReverseDirection, &mw->keysyms_ReverseDirection); + + // convert the modifier key masks settings strings into arrays of enums + modkeymasks_str_enums(ps->o.bindings_modifierKeyMasksReverseDirection, &mw->modifierKeyMasks_ReverseDirection); // convert the arrays of KeySyms into arrays of KeyCodes, for this specific Display keysyms_arr_keycodes(dpy, mw->keysyms_Up, &mw->keycodes_Up); @@ -162,6 +166,7 @@ mainwin_reload(session_t *ps, MainWin *mw) { keysyms_arr_keycodes(dpy, mw->keysyms_ExitCancelOnRelease, &mw->keycodes_ExitCancelOnRelease); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnPress, &mw->keycodes_ExitSelectOnPress); keysyms_arr_keycodes(dpy, mw->keysyms_ExitSelectOnRelease, &mw->keycodes_ExitSelectOnRelease); + keysyms_arr_keycodes(dpy, mw->keysyms_ReverseDirection, &mw->keycodes_ReverseDirection); // we check all possible pairs, one pair at a time. This is in a specific order, to give a more helpful error msg check_keybindings_conflict(ps->o.config_path, "keysUp", mw->keysyms_Up, "keysDown", mw->keysyms_Down); @@ -475,6 +480,9 @@ mainwin_destroy(MainWin *mw) { free(mw->keysyms_ExitCancelOnRelease); free(mw->keysyms_ExitSelectOnPress); free(mw->keysyms_ExitSelectOnRelease); + free(mw->keysyms_ReverseDirection); + + free(mw->modifierKeyMasks_ReverseDirection); free(mw->keycodes_Up); free(mw->keycodes_Down); @@ -486,6 +494,7 @@ mainwin_destroy(MainWin *mw) { free(mw->keycodes_ExitCancelOnRelease); free(mw->keycodes_ExitSelectOnPress); free(mw->keycodes_ExitSelectOnRelease); + free(mw->keycodes_ReverseDirection); free(mw); } diff --git a/src/mainwin.h b/src/mainwin.h index 83d95dc..4686ebb 100644 --- a/src/mainwin.h +++ b/src/mainwin.h @@ -63,6 +63,9 @@ struct _mainwin_t { KeySym *keysyms_ExitCancelOnRelease; KeySym *keysyms_ExitSelectOnPress; KeySym *keysyms_ExitSelectOnRelease; + KeySym *keysyms_ReverseDirection; + + int *modifierKeyMasks_ReverseDirection; KeyCode *keycodes_Up; KeyCode *keycodes_Down; @@ -74,6 +77,7 @@ struct _mainwin_t { KeyCode *keycodes_ExitCancelOnRelease; KeyCode *keycodes_ExitSelectOnPress; KeyCode *keycodes_ExitSelectOnRelease; + KeyCode *keycodes_ReverseDirection; bool mapped; diff --git a/src/skippy.c b/src/skippy.c index 39481eb..9ac1661 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1642,6 +1642,8 @@ load_config_file(session_t *ps) ps->o.bindings_keysExitCancelOnRelease = mstrdup(config_get(config, "bindings", "keysExitCancelOnRelease", "")); ps->o.bindings_keysExitSelectOnPress = mstrdup(config_get(config, "bindings", "keysExitSelectOnPress", "Return space")); ps->o.bindings_keysExitSelectOnRelease = mstrdup(config_get(config, "bindings", "keysExitSelectOnRelease", "Super_L Super_R Alt_L Alt_R ISO_Level3_Shift")); + ps->o.bindings_keysReverseDirection = mstrdup(config_get(config, "bindings", "keysReverseDirection", "Tab")); + ps->o.bindings_modifierKeyMasksReverseDirection = mstrdup(config_get(config, "bindings", "modifierKeyMasksReverseDirection", "ShiftMask ControlMask")); // print an error message for any key bindings that aren't recognized check_keysyms(ps->o.config_path, ": [bindings] keysUp =", ps->o.bindings_keysUp); @@ -1654,6 +1656,8 @@ load_config_file(session_t *ps) check_keysyms(ps->o.config_path, ": [bindings] keysExitCancelOnRelease =", ps->o.bindings_keysExitCancelOnRelease); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnPress =", ps->o.bindings_keysExitSelectOnPress); check_keysyms(ps->o.config_path, ": [bindings] keysExitSelectOnRelease =", ps->o.bindings_keysExitSelectOnRelease); + check_keysyms(ps->o.config_path, ": [bindings] keysReverseDirection =", ps->o.bindings_keysReverseDirection); + check_modmasks(ps->o.config_path, ": [bindings] modifierKeyMasksReverseDirection =", ps->o.bindings_modifierKeyMasksReverseDirection); if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) @@ -1935,6 +1939,8 @@ int main(int argc, char *argv[]) { free(ps->o.bindings_keysExitCancelOnRelease); free(ps->o.bindings_keysExitSelectOnPress); free(ps->o.bindings_keysExitSelectOnRelease); + free(ps->o.bindings_keysReverseDirection); + free(ps->o.bindings_modifierKeyMasksReverseDirection); } if (ps->fd_pipe >= 0) diff --git a/src/skippy.h b/src/skippy.h index b36ac7a..e7c2ea1 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -253,6 +253,8 @@ typedef struct { char *bindings_keysExitCancelOnRelease; char *bindings_keysExitSelectOnPress; char *bindings_keysExitSelectOnRelease; + char *bindings_keysReverseDirection; + char *bindings_modifierKeyMasksReverseDirection; } options_t; #define OPTIONST_INIT { \ From bc2146e8dd0ced461faa5cee5a29c44960839daa Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Mon, 19 Jun 2023 19:17:12 -0700 Subject: [PATCH 178/205] Support mouse scroll (#134) * Add mouse scroll wheel support * Allows mouse button to do nothing on MainWin * Update sample config file on mouse scroll * Mouse scroll starts on MainWin->client_to_focus --- skippy-xd.sample.rc | 5 ++++- src/clientwin.c | 6 ++++++ src/mainwin.c | 15 +++++++++++++++ src/skippy.c | 14 +++++++++----- src/skippy.h | 4 +++- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index b187754..dae4484 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -36,7 +36,8 @@ # - [bindings] for miwMouse[1,2,3] can bind to "no" (do nothing), "focus" # (focus to window), "iconify", "shade-ewmh" (toggle window shade state), # "close-icccm" (close window with ICCCM method), "close-ewmh" (close -# window with EWMH method), or "destroy" (forcefully destroy the window). +# window with EWMH method), or "destroy" (forcefully destroy the window), +# "keysPrev" to focus on previous window, "keysNext" to focus on next window. # # - [bindings] key* = is a list of valid XWindows KeySym identifiers, case # sensitive and seperated list. Run the program 'xev' to find them. @@ -135,6 +136,8 @@ font = fixed-11:weight=bold miwMouse1 = focus miwMouse2 = close-ewmh miwMouse3 = iconify +miwMouse4 = keysNext +miwMouse5 = keysPrev keysUp = Up w keysDown = Down s keysLeft = Left a diff --git a/src/clientwin.c b/src/clientwin.c index 536a836..eac7e53 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -792,6 +792,12 @@ clientwin_action(ClientWin *cw, enum cliop action) { case CLIENTOP_DESTROY: XDestroyWindow(cw->mainwin->ps->dpy, wid); break; + case CLIENTOP_PREV: + focus_miniw_prev(ps, cw->mainwin->client_to_focus); + break; + case CLIENTOP_NEXT: + focus_miniw_next(ps, cw->mainwin->client_to_focus); + break; } return 0; diff --git a/src/mainwin.c b/src/mainwin.c index 4725c15..dc5d03b 100644 --- a/src/mainwin.c +++ b/src/mainwin.c @@ -542,6 +542,21 @@ mainwin_handle(MainWin *mw, XEvent *ev) { break; case ButtonRelease: if (mw->pressed_mouse) { + const unsigned button = ev->xbutton.button; + if (button < MAX_MOUSE_BUTTONS) { + enum cliop action = ps->o.bindings_miwMouse[button]; + if (action == CLIENTOP_PREV) { + focus_miniw_prev(ps, mw->client_to_focus); + return 0; + } + else if (action == CLIENTOP_NEXT) { + focus_miniw_next(ps, mw->client_to_focus); + return 0; + } + else if (action == CLIENTOP_NO) { + return 0; + } + } printfdf(false, "(): Detected mouse button release on main window, " "exiting."); return 1; diff --git a/src/skippy.c b/src/skippy.c index 9ac1661..5f69a86 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -47,13 +47,15 @@ session_t *ps_g = NULL; static bool parse_cliop(session_t *ps, const char *str, enum cliop *dest) { static const char * const STRS_CLIENTOP[] = { - [ CLIENTOP_NO ] = "no", + [ CLIENTOP_NO ] = "no", [ CLIENTOP_FOCUS ] = "focus", [ CLIENTOP_ICONIFY ] = "iconify", - [ CLIENTOP_SHADE_EWMH ] = "shade-ewmh", - [ CLIENTOP_CLOSE_ICCCM ] = "close-icccm", - [ CLIENTOP_CLOSE_EWMH ] = "close-ewmh", + [ CLIENTOP_SHADE_EWMH ] = "shade-ewmh", + [ CLIENTOP_CLOSE_ICCCM ] = "close-icccm", + [ CLIENTOP_CLOSE_EWMH ] = "close-ewmh", [ CLIENTOP_DESTROY ] = "destroy", + [ CLIENTOP_PREV ] = "keysPrev", + [ CLIENTOP_NEXT ] = "keysNext", }; for (int i = 0; i < sizeof(STRS_CLIENTOP) / sizeof(STRS_CLIENTOP[0]); ++i) if (!strcmp(STRS_CLIENTOP[i], str)) { @@ -1661,7 +1663,9 @@ load_config_file(session_t *ps) if (!parse_cliop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1]) || !parse_cliop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2]) - || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3])) { + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3]) + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse4", "keysNext"), &ps->o.bindings_miwMouse[4]) + || !parse_cliop(ps, config_get(config, "bindings", "miwMouse5", "keysPrev"), &ps->o.bindings_miwMouse[5])) { return RET_BADARG; } diff --git a/src/skippy.h b/src/skippy.h index e7c2ea1..d56cbbf 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -63,7 +63,7 @@ #include "dlist.h" -#define MAX_MOUSE_BUTTONS 4 +#define MAX_MOUSE_BUTTONS 6 extern bool debuglog; @@ -106,6 +106,8 @@ enum cliop { CLIENTOP_CLOSE_ICCCM, CLIENTOP_CLOSE_EWMH, CLIENTOP_DESTROY, + CLIENTOP_PREV, + CLIENTOP_NEXT, }; enum align { From 57e0e3055fd8c8d463d89cca8d24b4f62268263c Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 20 Jun 2023 04:43:25 -0700 Subject: [PATCH 179/205] Mouse focus to trigger only after pointer movement (#135) * Move EnterNotify logic to MotionNotify * Fix bug in Alt-Tab --- src/clientwin.c | 35 +++++++++++++++++++---------------- src/skippy.c | 15 +++++++++++++++ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index eac7e53..65808f3 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -583,7 +583,6 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { session_t *ps = mw->ps; XKeyEvent * const evk = &ev->xkey; - if (ev->type == KeyPress) { report_key(ev); @@ -599,49 +598,49 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) { if(reverse_direction) - focus_down(cw); + focus_down(cw->mainwin->client_to_focus); else - focus_up(cw); + focus_up(cw->mainwin->client_to_focus); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Down, evk->keycode)) { if(reverse_direction) - focus_up(cw); + focus_up(cw->mainwin->client_to_focus); else - focus_down(cw); + focus_down(cw->mainwin->client_to_focus); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Left, evk->keycode)) { if(reverse_direction) - focus_right(cw); + focus_right(cw->mainwin->client_to_focus); else - focus_left(cw); + focus_left(cw->mainwin->client_to_focus); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Right, evk->keycode)) { if(reverse_direction) - focus_left(cw); + focus_left(cw->mainwin->client_to_focus); else - focus_right(cw); + focus_right(cw->mainwin->client_to_focus); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Prev, evk->keycode)) { if(reverse_direction) - focus_miniw_next(ps, cw); + focus_miniw_next(ps, cw->mainwin->client_to_focus); else - focus_miniw_prev(ps, cw); + focus_miniw_prev(ps, cw->mainwin->client_to_focus); } else if (arr_keycodes_includes(cw->mainwin->keycodes_Next, evk->keycode)) { if(reverse_direction) - focus_miniw_prev(ps, cw); + focus_miniw_prev(ps, cw->mainwin->client_to_focus); else - focus_miniw_next(ps, cw); + focus_miniw_next(ps, cw->mainwin->client_to_focus); } else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) @@ -652,7 +651,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitSelectOnPress, evk->keycode)) { - mw->client_to_focus = cw; + mw->client_to_focus = cw->mainwin->client_to_focus; return 1; } } @@ -741,8 +740,12 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); - } else if(ev->type == EnterNotify) { + } else if(ev->type == MotionNotify) { + printfdf(false, "(): else if (ev->type == MotionNotify) {"); + XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); + cw->mainwin->client_to_focus = cw; + if (cw->mainwin->tooltip) { cw->mainwin->cw_tooltip = cw; int win_title_len = 0; @@ -757,7 +760,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } } } else if(ev->type == LeaveNotify) { - // XSetInputFocus(ps->dpy, mw->window, RevertToParent, CurrentTime); + printfdf(false, "(): else if (ev->type == LeaveNotify) {"); cw->mainwin->cw_tooltip = NULL; if(cw->mainwin->tooltip) tooltip_unmap(cw->mainwin->tooltip); diff --git a/src/skippy.c b/src/skippy.c index 5f69a86..29492f3 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -965,6 +965,21 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw && MotionNotify == ev.type) { + // when mouse move within a client window, focus on it + if (wid) { + dlist *iter = mw->clientondesktop; + if (layout == LAYOUTMODE_PAGING) + iter = mw->dminis; + for (; iter; iter = iter->next) { + ClientWin *cw = (ClientWin *) iter->data; + if (cw->mini.window == wid) { + if (!(POLLIN & r_fd[1].revents)) { + die = clientwin_handle(cw, &ev); + } + } + } + } + // Speed up responsiveness when the user is moving the mouse around // The queue gets filled up with consquetive MotionNotify events // discard all except the last MotionNotify event in a contiguous block of MotionNotify events From f43980be283b4909c4bb27e67b2a90bcaf3ece37 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 21 Jun 2023 00:22:27 -0700 Subject: [PATCH 180/205] If tooltip followsMouse=false, show on at window center --- src/clientwin.c | 2 +- src/skippy.c | 2 +- src/tooltip.c | 10 +++++++--- src/tooltip.h | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 65808f3..83daa69 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -754,7 +754,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { win_title = wm_get_window_title(ps, cw->mini.window, &win_title_len); if (win_title) { tooltip_map(cw->mainwin->tooltip, - ev->xcrossing.x_root, ev->xcrossing.y_root, + ev->xcrossing.x_root, ev->xcrossing.y_root, cw, win_title, win_title_len); free(win_title); } diff --git a/src/skippy.c b/src/skippy.c index 29492f3..eb81a34 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1012,7 +1012,7 @@ mainloop(session_t *ps, bool activate_on_start) { if (mw->tooltip && ps->o.tooltip_followsMouse) tooltip_move(mw->tooltip, - ev.xmotion.x_root, ev.xmotion.y_root); + ev.xmotion.x_root, ev.xmotion.y_root, mw->client_to_focus); } else if (mw && ev.type == DestroyNotify) { printfdf(false, "(): else if (ev.type == DestroyNotify) {"); diff --git a/src/tooltip.c b/src/tooltip.c index d49cb1f..3d5d8d2 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -163,7 +163,7 @@ tooltip_create(MainWin *mw) { } void -tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, +tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, ClientWin *cw, FcChar8 *text, int len) { session_t * const ps = tt->mainwin->ps; @@ -187,7 +187,7 @@ tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, tt->width = tt->extents.width + 8; tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0); XResizeWindow(ps->dpy, tt->window, tt->width, tt->height); - tooltip_move(tt, mouse_x, mouse_y); + tooltip_move(tt, mouse_x, mouse_y, cw); if(tt->text) free(tt->text); @@ -202,7 +202,7 @@ tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, } void -tooltip_move(Tooltip *tt, int mouse_x, int mouse_y) { +tooltip_move(Tooltip *tt, int mouse_x, int mouse_y, ClientWin *cw) { session_t *ps = tt->mainwin->ps; int x = ps->o.tooltip_offsetX, y = ps->o.tooltip_offsetY; @@ -210,6 +210,10 @@ tooltip_move(Tooltip *tt, int mouse_x, int mouse_y) { x += mouse_x; y += mouse_y; } + else { + x += cw->mini.x + cw->mini.width/2; + y += cw->mini.y + cw->mini.height/2; + } switch (ps->o.tooltip_align) { case ALIGN_LEFT: break; case ALIGN_MID: diff --git a/src/tooltip.h b/src/tooltip.h index 33fa53e..269b9e3 100644 --- a/src/tooltip.h +++ b/src/tooltip.h @@ -39,10 +39,10 @@ typedef struct _Tooltip Tooltip; Tooltip *tooltip_create(MainWin *mw); void tooltip_destroy(Tooltip *); -void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, +void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y, ClientWin *cw, FcChar8 *text, int len); void tooltip_unmap(Tooltip *); void tooltip_handle(Tooltip *, XEvent *); -void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y); +void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y, ClientWin *cw); #endif /* SKIPPY_TOOLTIP_H */ From 05aa96c358505ae216220d389bc5ab7b9922a68e Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 21 Jun 2023 00:37:28 -0700 Subject: [PATCH 181/205] Remove tooltip align config option --- skippy-xd.sample.rc | 1 - src/skippy.c | 2 -- src/skippy.h | 4 +--- src/tooltip.c | 17 +++++------------ 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index dae4484..71b3cbd 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -124,7 +124,6 @@ show = true followsMouse = true offsetX = 20 offsetY = 20 -align = left border = #ffffff background = #404040 opacity = 128 diff --git a/src/skippy.c b/src/skippy.c index eb81a34..8bc8581 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1727,8 +1727,6 @@ load_config_file(session_t *ps) config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse); config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX); config_get_int_wrap(config, "tooltip", "offsetY", &ps->o.tooltip_offsetY, INT_MIN, INT_MAX); - if (!parse_align_full(ps, config_get(config, "tooltip", "align", "left"), &ps->o.tooltip_align)) - return RET_BADARG; config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256); { diff --git a/src/skippy.h b/src/skippy.h index d56cbbf..42213a5 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -236,7 +236,6 @@ typedef struct { bool tooltip_followsMouse; int tooltip_offsetX; int tooltip_offsetY; - enum align tooltip_align; char *tooltip_border; char *tooltip_background; int tooltip_opacity; @@ -298,9 +297,8 @@ typedef struct { .shadow_opacity = 128, \ .tooltip_show = true, \ .tooltip_followsMouse = true, \ - .tooltip_offsetX = 20, \ + .tooltip_offsetX = 0, \ .tooltip_offsetY = 20, \ - .tooltip_align = ALIGN_LEFT, \ .tooltip_border = NULL, \ .tooltip_background = NULL, \ .tooltip_opacity = 128, \ diff --git a/src/tooltip.c b/src/tooltip.c index 3d5d8d2..bd88f82 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -205,24 +205,17 @@ void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y, ClientWin *cw) { session_t *ps = tt->mainwin->ps; - int x = ps->o.tooltip_offsetX, y = ps->o.tooltip_offsetY; + int x = ps->o.tooltip_offsetX, + y = ps->o.tooltip_offsetY; if (ps->o.tooltip_followsMouse) { x += mouse_x; y += mouse_y; } else { - x += cw->mini.x + cw->mini.width/2; - y += cw->mini.y + cw->mini.height/2; - } - switch (ps->o.tooltip_align) { - case ALIGN_LEFT: break; - case ALIGN_MID: - x -= tt->width / 2; - break; - case ALIGN_RIGHT: - x -= tt->width; - break; + x += cw->mini.x + cw->mini.width/2 - tt->width / 2; + y += cw->mini.y + cw->mini.height; } + x = MIN(MAX(0, x), tt->mainwin->x + tt->mainwin->width - tt->width); y = MIN(MAX(0, y), tt->mainwin->y + tt->mainwin->height - tt->height); From 3e41ce50e41005e587563a5fd0d09d14c78a6865 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 21 Jun 2023 00:51:09 -0700 Subject: [PATCH 182/205] Correct tooltip mouse focus --- src/clientwin.c | 29 +++++++++++++++-------------- src/skippy.c | 11 +++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 83daa69..f30e10b 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -718,6 +718,21 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); + cw->mainwin->cw_tooltip = cw; + if (cw->mainwin->tooltip) { + cw->mainwin->cw_tooltip = cw; + int win_title_len = 0; + FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); + if (!win_title) + win_title = wm_get_window_title(ps, cw->mini.window, &win_title_len); + if (win_title) { + tooltip_map(cw->mainwin->tooltip, + ev->xcrossing.x_root, ev->xcrossing.y_root, cw, + win_title, win_title_len); + free(win_title); + } + } + } else if (ev->type == FocusOut) { printfdf(false, "(): else if (ev->type == FocusOut) {"); XFocusChangeEvent *evf = &ev->xfocus; @@ -745,20 +760,6 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); cw->mainwin->client_to_focus = cw; - - if (cw->mainwin->tooltip) { - cw->mainwin->cw_tooltip = cw; - int win_title_len = 0; - FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); - if (!win_title) - win_title = wm_get_window_title(ps, cw->mini.window, &win_title_len); - if (win_title) { - tooltip_map(cw->mainwin->tooltip, - ev->xcrossing.x_root, ev->xcrossing.y_root, cw, - win_title, win_title_len); - free(win_title); - } - } } else if(ev->type == LeaveNotify) { printfdf(false, "(): else if (ev->type == LeaveNotify) {"); cw->mainwin->cw_tooltip = NULL; diff --git a/src/skippy.c b/src/skippy.c index 8bc8581..38c782a 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -1003,12 +1003,11 @@ mainloop(session_t *ps, bool activate_on_start) { // mw->ignore_next_refocus = 0; // we also need to refocus here - if(mw->cw_tooltip && (mw->cw_tooltip != mw->client_to_focus)) - { - focus_miniw(ps, mw->cw_tooltip); - clientwin_render(mw->client_to_focus); - } - + //if(mw->cw_tooltip && (mw->cw_tooltip != mw->client_to_focus)) + //{ + //focus_miniw(ps, mw->cw_tooltip); + //clientwin_render(mw->client_to_focus); + //} if (mw->tooltip && ps->o.tooltip_followsMouse) tooltip_move(mw->tooltip, From b158114ad68d62493dc3e6a458f8a5d4e713a8fa Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 21 Jun 2023 00:53:15 -0700 Subject: [PATCH 183/205] Correct tooltip disappearance: Only when tooltip follows mouse option=true, and mouse leaves window --- src/clientwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clientwin.c b/src/clientwin.c index f30e10b..fc2ca11 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -763,7 +763,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } else if(ev->type == LeaveNotify) { printfdf(false, "(): else if (ev->type == LeaveNotify) {"); cw->mainwin->cw_tooltip = NULL; - if(cw->mainwin->tooltip) + if(ps->o.tooltip_followsMouse && cw->mainwin->tooltip) tooltip_unmap(cw->mainwin->tooltip); } return 0; From dc341689a0c9f7769e796a3d587d0e18f8fc1d77 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 22 Jun 2023 18:22:04 -0700 Subject: [PATCH 184/205] Tooltip position (#138) * If tooltip followsMouse=false, show on at window center * Remove tooltip align config option * Correct tooltip mouse focus * Correct tooltip disappearance: Only when tooltip follows mouse option=true, and mouse leaves window * Eliminate tooltip flicker * Remove tooltip followsMouse config option * Fix bug where tooltip text is not updated * Update default tooltip offset (to bottom) * Correct first tooltip focus on paging --- skippy-xd.sample.rc | 5 ++--- src/clientwin.c | 38 +++++++++++++++++++++----------------- src/clientwin.h | 1 + src/skippy.c | 23 +++++------------------ src/skippy.h | 2 -- src/tooltip.c | 11 +++-------- 6 files changed, 32 insertions(+), 48 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 71b3cbd..263902b 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -121,9 +121,8 @@ opacity = 128 [tooltip] show = true -followsMouse = true -offsetX = 20 -offsetY = 20 +offsetX = 0 +offsetY = 5 border = #ffffff background = #404040 opacity = 128 diff --git a/src/clientwin.c b/src/clientwin.c index fc2ca11..5438c96 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -574,6 +574,26 @@ childwin_focus(ClientWin *cw) { XFlush(ps->dpy); } +void +clientwin_tooltip(ClientWin *cw, XEvent *ev) { + MainWin *mw = cw->mainwin; + session_t *ps = mw->ps; + cw->mainwin->cw_tooltip = cw; + if (cw->mainwin->tooltip) { + cw->mainwin->cw_tooltip = cw; + int win_title_len = 0; + FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); + if (!win_title) + win_title = wm_get_window_title(ps, cw->mini.window, &win_title_len); + if (win_title) { + tooltip_map(cw->mainwin->tooltip, + ev->xcrossing.x_root, ev->xcrossing.y_root, cw, + win_title, win_title_len); + free(win_title); + } + } +} + int clientwin_handle(ClientWin *cw, XEvent *ev) { if (! cw) @@ -718,21 +738,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); - cw->mainwin->cw_tooltip = cw; - if (cw->mainwin->tooltip) { - cw->mainwin->cw_tooltip = cw; - int win_title_len = 0; - FcChar8 *win_title = wm_get_window_title(ps, cw->wid_client, &win_title_len); - if (!win_title) - win_title = wm_get_window_title(ps, cw->mini.window, &win_title_len); - if (win_title) { - tooltip_map(cw->mainwin->tooltip, - ev->xcrossing.x_root, ev->xcrossing.y_root, cw, - win_title, win_title_len); - free(win_title); - } - } - + clientwin_tooltip(cw, ev); } else if (ev->type == FocusOut) { printfdf(false, "(): else if (ev->type == FocusOut) {"); XFocusChangeEvent *evf = &ev->xfocus; @@ -763,8 +769,6 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { } else if(ev->type == LeaveNotify) { printfdf(false, "(): else if (ev->type == LeaveNotify) {"); cw->mainwin->cw_tooltip = NULL; - if(ps->o.tooltip_followsMouse && cw->mainwin->tooltip) - tooltip_unmap(cw->mainwin->tooltip); } return 0; } diff --git a/src/clientwin.h b/src/clientwin.h index 3272100..1611b3c 100644 --- a/src/clientwin.h +++ b/src/clientwin.h @@ -98,6 +98,7 @@ int clientwin_check_group_leader_func(dlist *l, void *data); void clientwin_render(ClientWin *); void clientwin_schedule_repair(ClientWin *cw, XRectangle *area); void clientwin_repair(ClientWin *cw); +void clientwin_tooltip(ClientWin *cw, XEvent *ev); void childwin_focus(ClientWin *cw); #endif /* SKIPPY_CLIENT_H */ diff --git a/src/skippy.c b/src/skippy.c index 38c782a..c9e04eb 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -933,8 +933,6 @@ mainloop(session_t *ps, bool activate_on_start) { anime(ps->mainwin, ps->mainwin->clients, 1); animating = false; last_rendered = time_in_millis(); - focus_miniw_adv(ps, mw->client_to_focus, - ps->o.movePointer); if (layout == LAYOUTMODE_PAGING) { foreach_dlist (mw->dminis) { @@ -946,6 +944,11 @@ mainloop(session_t *ps, bool activate_on_start) { if (!ps->o.lazyTrans && !mw->mapped) mainwin_map(mw); XFlush(ps->dpy); + + XSync(ps->dpy, False); + XSync(ps->dpy, True); + focus_miniw_adv(ps, mw->client_to_focus, + ps->o.movePointer); } continue; // while animating, do not allow user actions @@ -997,21 +1000,6 @@ mainloop(session_t *ps, bool activate_on_start) { num_events--; } - - // the mouse has moved - // refocus enable - // mw->ignore_next_refocus = 0; - - // we also need to refocus here - //if(mw->cw_tooltip && (mw->cw_tooltip != mw->client_to_focus)) - //{ - //focus_miniw(ps, mw->cw_tooltip); - //clientwin_render(mw->client_to_focus); - //} - - if (mw->tooltip && ps->o.tooltip_followsMouse) - tooltip_move(mw->tooltip, - ev.xmotion.x_root, ev.xmotion.y_root, mw->client_to_focus); } else if (mw && ev.type == DestroyNotify) { printfdf(false, "(): else if (ev.type == DestroyNotify) {"); @@ -1723,7 +1711,6 @@ load_config_file(session_t *ps) config_get_int_wrap(config, "shadow", "tintOpacity", &ps->o.shadow_tintOpacity, 0, 256); config_get_int_wrap(config, "shadow", "opacity", &ps->o.shadow_opacity, 0, 256); config_get_bool_wrap(config, "tooltip", "show", &ps->o.tooltip_show); - config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse); config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX); config_get_int_wrap(config, "tooltip", "offsetY", &ps->o.tooltip_offsetY, INT_MIN, INT_MAX); config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256); diff --git a/src/skippy.h b/src/skippy.h index 42213a5..3a0771b 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -233,7 +233,6 @@ typedef struct { int shadow_opacity; bool tooltip_show; - bool tooltip_followsMouse; int tooltip_offsetX; int tooltip_offsetY; char *tooltip_border; @@ -296,7 +295,6 @@ typedef struct { .shadow_tintOpacity = 0, \ .shadow_opacity = 128, \ .tooltip_show = true, \ - .tooltip_followsMouse = true, \ .tooltip_offsetX = 0, \ .tooltip_offsetY = 20, \ .tooltip_border = NULL, \ diff --git a/src/tooltip.c b/src/tooltip.c index bd88f82..e208fec 100644 --- a/src/tooltip.c +++ b/src/tooltip.c @@ -207,14 +207,9 @@ tooltip_move(Tooltip *tt, int mouse_x, int mouse_y, ClientWin *cw) { session_t *ps = tt->mainwin->ps; int x = ps->o.tooltip_offsetX, y = ps->o.tooltip_offsetY; - if (ps->o.tooltip_followsMouse) { - x += mouse_x; - y += mouse_y; - } - else { - x += cw->mini.x + cw->mini.width/2 - tt->width / 2; - y += cw->mini.y + cw->mini.height; - } + + x += cw->mini.x + cw->mini.width/2 - tt->width / 2; + y += cw->mini.y + cw->mini.height; x = MIN(MAX(0, x), tt->mainwin->x + tt->mainwin->width - tt->width); y = MIN(MAX(0, y), tt->mainwin->y + tt->mainwin->height - tt->height); From 98b936fc5ea7f543e60b2897f98b753a81466e08 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 22 Jun 2023 18:31:20 -0700 Subject: [PATCH 185/205] Call wm_set_desktop_ewmh() in wm_activate_window() --- src/wm.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wm.h b/src/wm.h index bf8b6b1..ef31472 100644 --- a/src/wm.h +++ b/src/wm.h @@ -157,6 +157,12 @@ wm_set_desktop_ewmh(session_t *ps, long desktop) { static inline void wm_activate_window(session_t *ps, Window wid) { if (!wid) return; + + { + long tgt = wm_get_window_desktop(ps, wid); + if (tgt >= 0) + wm_set_desktop_ewmh(ps, tgt); + } // Order is important, to avoid "intelligent" WMs fixing our focus stealing wm_activate_window_ewmh(ps, wid); From 85d69c03bf45183450d5fbb43e0294565f025c61 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 22 Jun 2023 19:28:44 -0700 Subject: [PATCH 186/205] Add config option for XQueryTree, _NET_CLIENT_LIST, _WIN_CLIENT_LIST --- skippy-xd.sample.rc | 4 +++ src/skippy.c | 11 ++++++-- src/skippy.h | 6 ++--- src/wm.c | 66 ++++++++++++++++++++++----------------------- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 263902b..a38e3cc 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -51,6 +51,10 @@ # File path of skippy-xd pipe daemon communication pipePath = /tmp/skippy-xd-fifo +# Depending on your window manager, you may want to choose between +# XQueryTree, _NET_CLIENT_LIST, _WIN_CLIENT_LIST +clientList = XQueryTree + # Background picture when skippy-xd is activated background = diff --git a/src/skippy.c b/src/skippy.c index c9e04eb..788f395 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -116,6 +116,7 @@ parse_pict_posp_mode(session_t *ps, const char *str, enum pict_posp_mode *dest) printfef(true, "() (\"%s\"): Unrecognized operation.", str); return 0; } + static inline int parse_color_sub(const char *s, unsigned short *dest) { static const int SEG = 2; @@ -1690,8 +1691,14 @@ load_config_file(session_t *ps) config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX); config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen); - config_get_bool_wrap(config, "general", "acceptOvRedir", &ps->o.acceptOvRedir); - config_get_bool_wrap(config, "general", "acceptWMWin", &ps->o.acceptWMWin); + { + ps->o.clientList = 0; + const char *tmp = config_get(config, "general", "clientList", NULL); + if (tmp && strcmp(tmp, "_NET_CLIENT_LIST") == 0) + ps->o.clientList = 1; + if (tmp && strcmp(tmp, "_WIN_CLIENT_LIST") == 0) + ps->o.clientList = 2; + } config_get_double_wrap(config, "general", "updateFreq", &ps->o.updateFreq, -1000.0, 1000.0); config_get_int_wrap(config, "general", "animationDuration", &ps->o.animationDuration, 0, 2000); config_get_bool_wrap(config, "general", "lazyTrans", &ps->o.lazyTrans); diff --git a/src/skippy.h b/src/skippy.h index 3a0771b..ac5e8bb 100644 --- a/src/skippy.h +++ b/src/skippy.h @@ -197,8 +197,7 @@ typedef struct { int exposeLayout; int distance; bool useNetWMFullscreen; - bool acceptOvRedir; - bool acceptWMWin; + int clientList; double updateFreq; int animationDuration;; bool lazyTrans; @@ -265,8 +264,7 @@ typedef struct { .exposeLayout = LAYOUT_BOXY, \ .distance = 50, \ .useNetWMFullscreen = true, \ - .acceptOvRedir = false, \ - .acceptWMWin = false, \ + .clientList = 0, \ .updateFreq = 60.0, \ .animationDuration = 200, \ .lazyTrans = false, \ diff --git a/src/wm.c b/src/wm.c index 8fe49bf..0514ce1 100644 --- a/src/wm.c +++ b/src/wm.c @@ -344,48 +344,48 @@ wm_get_stack_sub(session_t *ps, Window root) { dlist *l = NULL; // does not give info on windows z-order - /*if (!(ps->o.acceptOvRedir || ps->o.acceptWMWin)) { + switch (ps->o.clientList) { // EWMH - l = wm_get_stack_fromprop(ps, root, _NET_CLIENT_LIST); - if (l) { + case 1: printfdf(false, "(): Retrieved window stack from _NET_CLIENT_LIST."); - return l; - } + return wm_get_stack_fromprop(ps, root, _NET_CLIENT_LIST); // GNOME WM - l = wm_get_stack_fromprop(ps, root, _WIN_CLIENT_LIST); - if (l) { + case 2: printfdf(false, "(): Retrieved window stack from _WIN_CLIENT_LIST."); - return l; - } - }*/ + return wm_get_stack_fromprop(ps, root, _WIN_CLIENT_LIST); - // Stupid method, but this gives windows ordered by z-order - { - Window *children = NULL; - unsigned nchildren = 0; - Window rroot = None, rparent = None; - if (XQueryTree(ps->dpy, root, &rroot, &rparent, - &children, &nchildren) && nchildren && children) { - // Fluxbox sets override-redirect on its frame windows, - // so we can't skip override-redirect windows. - for (int i = 0; i < nchildren; ++i) { - Window wid = children[i]; - Window client = wm_find_client(ps, wid); - if (!client && (ps->o.acceptOvRedir || ps->o.acceptWMWin)) { - XWindowAttributes attr = { }; - if (XGetWindowAttributes(ps->dpy, wid, &attr) - && ((attr.override_redirect && ps->o.acceptOvRedir) - || (!attr.override_redirect && ps->o.acceptWMWin))) { - client = wid; - } + // Stupid method, but this gives windows ordered by z-order + default: + { + Window *children = NULL; + unsigned nchildren = 0; + Window rroot = None, rparent = None; + if (XQueryTree(ps->dpy, root, &rroot, &rparent, + &children, &nchildren) && nchildren && children) { + // Fluxbox sets override-redirect on its frame windows, + // so we can't skip override-redirect windows. + for (int i = 0; i < nchildren; ++i) { + Window wid = children[i]; + Window client = wm_find_client(ps, wid); + // both obsolete config options + // ps->o.acceptOvRedir and ps->o.acceptWMWin were always false + // hence this loop never runs + /*if (!client && (ps->o.acceptOvRedir || ps->o.acceptWMWin)) { + XWindowAttributes attr = { }; + if (XGetWindowAttributes(ps->dpy, wid, &attr) + && ((attr.override_redirect && ps->o.acceptOvRedir) + || (!attr.override_redirect && ps->o.acceptWMWin))) { + client = wid; + } + }*/ + if (client) + l = dlist_add(l, (void *) client); } - if (client) - l = dlist_add(l, (void *) client); } + sxfree(children); + printfdf(false, "(): Retrieved window stack by querying all children."); } - sxfree(children); - printfdf(false, "(): Retrieved window stack by querying all children."); } return l; From f1e864aa95627dfa5676174c15988eca45a3d95f Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 24 Jun 2023 03:30:23 -0700 Subject: [PATCH 187/205] New version 0.7.0 (#141) * New version 0.7.0 * Remove debug flags in Makefile --- CHANGELOG | 9 +++++++++ Makefile | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5a6caff..115b07a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,14 @@ Skippy-XD changelog +0.7.0 -- "Popsicle" (23 Jun 2023) ~/felixfung + - New paging mode + - New command line parameters + - Named pipe name postfixed with X session ID + - Bug fixes particularly polishing around focus logic + - Proper z-order management + - Support mouse scroll wheel + - Tooltip shows on bottom of windows + 0.6.0~fung -- "" (10 Mar 2023) ~/felixfung - Thumbnail displays for iconized or otherwise unmapped windows - Animation when activating skippy diff --git a/Makefile b/Makefile index 73e2a46..24149ec 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ INCS = $(shell pkg-config --cflags $(PACKAGES)) LIBS += -lm $(shell pkg-config --libs $(PACKAGES)) # === Version string === -SKIPPYXD_VERSION = "v0.6.0~fung (2023.03.10) - \\\"\\\" Edition" +SKIPPYXD_VERSION = "v0.7.0 (2023.06.23) - \\\"Popsicle\\\" Edition" CPPFLAGS += -DSKIPPYXD_VERSION=\"${SKIPPYXD_VERSION}\" # === Recipes === From 82fe69e53b8a0e36f22e7c8320eb4ef5706dcabc Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 24 Jun 2023 13:04:48 -0700 Subject: [PATCH 188/205] Recover live thumbnail preview --- src/skippy.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 788f395..2833f6d 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -946,8 +946,6 @@ mainloop(session_t *ps, bool activate_on_start) { mainwin_map(mw); XFlush(ps->dpy); - XSync(ps->dpy, False); - XSync(ps->dpy, True); focus_miniw_adv(ps, mw->client_to_focus, ps->o.movePointer); } From ab121af5ef53351021100cbf658b8edc79b59e69 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 24 Jun 2023 13:07:23 -0700 Subject: [PATCH 189/205] Paging tooltip starts on correct desktop --- src/clientwin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clientwin.c b/src/clientwin.c index 5438c96..06536ce 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -738,7 +738,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); - clientwin_tooltip(cw, ev); + clientwin_tooltip(cw->mainwin->client_to_focus, ev); } else if (ev->type == FocusOut) { printfdf(false, "(): else if (ev->type == FocusOut) {"); XFocusChangeEvent *evf = &ev->xfocus; From 53604e2098cd04e586629da53156528651aa6886 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 24 Jun 2023 15:53:15 -0700 Subject: [PATCH 190/205] Tinting for paging but tinting refresh mechanism sucks... --- src/skippy.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 2833f6d..7c51ab0 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -682,22 +682,42 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) static void desktopwin_map(ClientWin *cw) { - session_t *ps = cw->mainwin->ps; + MainWin *mw = cw->mainwin; + session_t *ps = mw->ps; free_damage(ps, &cw->damage); free_pixmap(ps, &cw->pixmap); XUnmapWindow(ps->dpy, cw->mini.window); - XSetWindowBackgroundPixmap(ps->dpy, cw->mini.window, None); XRenderPictureAttributes pa = { }; if (cw->origin) free_picture(ps, &cw->origin); cw->origin = XRenderCreatePicture(ps->dpy, - None, cw->mainwin->format, CPSubwindowMode, &pa); + mw->window, mw->format, CPSubwindowMode, &pa); XRenderSetPictureFilter(ps->dpy, cw->origin, FilterBest, 0, 0); + { + float matrix[9]; + matrix[0] = 1.0; + matrix[1] = 0.0; + matrix[2] = cw->x + mw->xoff; + matrix[3] = 0.0; + matrix[4] = 1.0; + matrix[5] = cw->y + mw->yoff; + matrix[6] = 0.0; + matrix[7] = 0.0; + matrix[8] = 1.0; + + XTransform transform; + for (int j=0; j<3; j++) + for (int i=0; i<3; i++) + transform.matrix[j][i] = matrix[j*3+i]; + + XRenderSetPictureTransform(ps->dpy, cw->origin, &transform); + } + XCompositeRedirectWindow(ps->dpy, cw->src.window, CompositeRedirectAutomatic); cw->redirected = true; @@ -1101,6 +1121,18 @@ mainloop(session_t *ps, bool activate_on_start) { timeout = 0; poll(r_fd, (r_fd[1].fd >= 0 ? 2: 1), timeout); + // force refresh focused desktop tint + // not great solution at all... + { + static int counter = 0; + if (mw && layout == LAYOUTMODE_PAGING && counter == 0) { + foreach_dlist (mw->dminis) { + desktopwin_map(((ClientWin *) iter->data)); + } + } + counter = (counter + 1) % 10; + } + // Handle daemon commands if (POLLIN & r_fd[1].revents) { unsigned char piped_input = 0; From 43b46f0b65c14c63db1886493bc9a8b827d103ff Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Tue, 27 Jun 2023 03:47:42 -0700 Subject: [PATCH 191/205] Paging activation on no windows at all --- src/skippy.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 7c51ab0..1006161 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -440,11 +440,6 @@ daemon_count_clients(MainWin *mw) update_clients(mw); - if (!mw->clients) { - printfdf(false, "(): No client windows found."); - return; - } - dlist_free(mw->clientondesktop); mw->clientondesktop = NULL; @@ -454,10 +449,6 @@ daemon_count_clients(MainWin *mw) dlist *tmp = dlist_first(dlist_find_all(mw->clients, (dlist_match_func) clientwin_validate_func, &desktop)); - if (!tmp) { - printfdf(false, "(): No client window on current desktop found."); - return; - } mw->clientondesktop = tmp; } @@ -557,9 +548,6 @@ init_layout(MainWin *mw, enum layoutmode layout, Window leader) static bool init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) { - if (!mw->clients) - return true; - int screencount = wm_get_desktops(mw->ps); if (screencount == -1) screencount = 1; @@ -752,7 +740,7 @@ skippy_activate(MainWin *mw, enum layoutmode layout) mw->client_to_focus = NULL; daemon_count_clients(mw); - if (!mw->clients || !mw->clientondesktop) { + if ((!mw->clients || !mw->clientondesktop) && layout != LAYOUTMODE_PAGING) { return false; } From e7c2482be7b853a109619fef41f06940c671df6a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 29 Jun 2023 18:58:24 -0700 Subject: [PATCH 192/205] Proper paging tint for keyboard+mouse Still hacky code though... --- src/clientwin.c | 13 +++++++++---- src/skippy.c | 25 ++++++++++++++++--------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 06536ce..27f02f0 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -702,6 +702,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { cw->mainwin->pressed = cw; */ } else if (ev->type == ButtonRelease) { + printfdf(false, "(): else if (ev->type == ButtonRelease) {"); const unsigned button = ev->xbutton.button; if (cw->mainwin->pressed_mouse) { if (button < MAX_MOUSE_BUTTONS) { @@ -731,10 +732,11 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { // usleep(10000); // if (evf->detail == NotifyWhileGrabbed) - if (evf->detail == NotifyNonlinear) + if (evf->detail == NotifyNonlinear || evf->detail == NotifyAncestor) cw->focused = true; clientwin_render(cw); + if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); @@ -754,18 +756,21 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { // usleep(10000); // if (evf->detail == NotifyWhileGrabbed) - if (evf->detail == NotifyNonlinear) + if (evf->detail == NotifyNonlinear || evf->detail == NotifyPointer) cw->focused = false; clientwin_render(cw); + if (debuglog) fputs("\n", stdout); XFlush(ps->dpy); } else if(ev->type == MotionNotify) { printfdf(false, "(): else if (ev->type == MotionNotify) {"); - XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); - cw->mainwin->client_to_focus = cw; + if (cw->mainwin->client_to_focus != cw) { + XSetInputFocus(ps->dpy, cw->mini.window, RevertToParent, CurrentTime); + cw->mainwin->client_to_focus = cw; + } } else if(ev->type == LeaveNotify) { printfdf(false, "(): else if (ev->type == LeaveNotify) {"); cw->mainwin->cw_tooltip = NULL; diff --git a/src/skippy.c b/src/skippy.c index 1006161..5932b4e 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -709,6 +709,8 @@ desktopwin_map(ClientWin *cw) XCompositeRedirectWindow(ps->dpy, cw->src.window, CompositeRedirectAutomatic); cw->redirected = true; + + cw->focused = cw == mw->client_to_focus; clientwin_render(cw); @@ -1064,10 +1066,17 @@ mainloop(session_t *ps, bool activate_on_start) { for (; iter; iter = iter->next) { ClientWin *cw = (ClientWin *) iter->data; if (cw->mini.window == wid) { - if (!(POLLIN & r_fd[1].revents)) - { - die = clientwin_handle(cw, &ev); - } + if (!(POLLIN & r_fd[1].revents) + && ((layout != LAYOUTMODE_PAGING) + || (ev.type != Expose + && ev.type != GraphicsExpose + && ev.type != EnterNotify + && ev.type != LeaveNotify))) { + die = clientwin_handle(cw, &ev); + if (layout == LAYOUTMODE_PAGING + && ev.type != MotionNotify){ + desktopwin_map(cw);} + } break; } } @@ -1111,13 +1120,11 @@ mainloop(session_t *ps, bool activate_on_start) { // force refresh focused desktop tint // not great solution at all... + if (mw && layout == LAYOUTMODE_PAGING) { static int counter = 0; - if (mw && layout == LAYOUTMODE_PAGING && counter == 0) { - foreach_dlist (mw->dminis) { - desktopwin_map(((ClientWin *) iter->data)); - } - } + if(counter == 0) + pending_damage = true; counter = (counter + 1) % 10; } From e30ca3a04506e7dba3750e7a9e2cb7bf99998b63 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 1 Jul 2023 05:38:27 -0700 Subject: [PATCH 193/205] Correct boxy layout affinity calculation --- src/layout.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/layout.c b/src/layout.c index 7e917a3..45d8d55 100644 --- a/src/layout.c +++ b/src/layout.c @@ -673,10 +673,10 @@ int boxy_affinity( ) { // cw->src.x cw->src.y should be taken into account also - int slotx = floor((float) cw->x / (float) slot_width); - int sloty = floor((float) cw->y / (float) slot_height); - int slotxx = slotx + ceil((float) cw->src.width / (float) slot_width); - int slotyy = sloty + ceil((float) cw->src.height / (float) slot_height); + float slotx = (float) cw->x / (float) slot_width; + float sloty = (float) cw->y / (float) slot_height; + float slotxx = slotx + (float) cw->src.width / (float) slot_width; + float slotyy = sloty + (float) cw->src.height / (float) slot_height; /*if (ii!=0 && ii * slotx < x) return INT_MIN; @@ -684,8 +684,8 @@ int boxy_affinity( return INT_MIN;*/ //printfdf("(): affinity for window %p (%d,%d)->(%d,%d) (%d,%d,%d,%d)", //cw, x,y,x+ii,y+jj,slotx,sloty,slotxx,slotyy); - return cw->slots * (ii * (slotxx - x - x + slotx) - + jj * (slotyy - y - y + sloty)); + return (int)((float)ii * (slotxx - (float)x - (float)x + slotx) + + (float)jj * (slotyy - (float)y - (float)y + sloty)); } int middleOfThree(int a, int b, int c) From 1a4cf05107f3b75094d470abacf2b8486ff30f9a Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Sat, 1 Jul 2023 06:19:03 -0700 Subject: [PATCH 194/205] boxy layout: introduce rotate contraction --- src/layout.c | 227 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 200 insertions(+), 27 deletions(-) diff --git a/src/layout.c b/src/layout.c index 45d8d55..4e8021a 100644 --- a/src/layout.c +++ b/src/layout.c @@ -194,12 +194,20 @@ layout_xd(MainWin *mw, dlist *windows, // move windows to right/down, sorted by "affinity": // which is the number of slots in that direction minus those // in opposite direction, times the windows' number of slots -// so the the higher the affinity, the further from the original slot +// so the higher the affinity, the further from the original slot // b. contract: -// loop slots left->right, top->bottom, for each free slot, -// compare window below, window rightside, window below and right side -// to current slot, sorted by affinity, -// and whether current slots can fit the window +// because expansion goes only to right and down, +// we often get layouts in top-left half e.g. +// +// o o o o +// o o +// o +// +// rotate contract row/column +// routine is grab rightmost/tpomost bottom/rightmost slot, +// move right/down while slot above/left is empty +// then move up/left +// // 4. END LOOP when no windows have been moved // 5. move windows to slots // @@ -208,6 +216,14 @@ layout_xd(MainWin *mw, dlist *windows, // dramatic aspect ratio defined as aspect ratio bigger than 10 // so aspect ratio of (25,1) or (1,4) +#ifndef ASPECT_TOLERANCE +#define ASPECT_TOLERANCE 1.4 +#endif + +#ifndef TRIANGULAR_TOLERANCE +#define TRIANGULAR_TOLERANCE 0.7 +#endif + void layout_boxy(MainWin *mw, dlist *windows, unsigned int *total_width, unsigned int *total_height) @@ -271,7 +287,7 @@ layout_boxy(MainWin *mw, dlist *windows, // main calculation loop bool recalculate = true; -do +for (int max_iterations=0; recalculate && max_iterations<100; max_iterations++) { recalculate = false; @@ -418,8 +434,8 @@ do for (int i=slot_maxx-1; !recalculate && i>=slot_minx; i--) { if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 1) { recalculate = true; - //printfdf("(): Collision on slot (%d,%d) with %d windows", - //i, j, slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); + printfdf(false,"(): Collision on slot (%d,%d) with %d windows", + i, j, slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]); // insert new row or column // based on estimated used screen aspect ratio @@ -427,7 +443,7 @@ do int ii = i, jj = j + 1; float estimated_aspect = (float) (slot_width * slot_maxx) / (float) (slot_height * slot_maxy); - if (estimated_aspect < screen_aspect * 1.4) { + if (estimated_aspect < screen_aspect * ASPECT_TOLERANCE) { ii = i + 1; jj = j; } @@ -438,27 +454,43 @@ do foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { ClientWin *slotw = (ClientWin*) iter->data; int affinity = boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j); + if (affinity > max_affinity) { + max_affinity = affinity; + moving_window = slotw; + } max_affinity = MAX(max_affinity, affinity); - //printfdf("(): window %p has affinity %d", slotw, affinity); + printfdf(false,"(): window %p has affinity %d", slotw, affinity); + } + + { + int slotx = floor((float) moving_window->x / (float) slot_width); + int sloty = floor((float) moving_window->y / (float) slot_height); + int slotxx = slotx + ceil((float) moving_window->src.width / (float) slot_width); + int slotyy = sloty + ceil((float) moving_window->src.height / (float) slot_height); + if (slotxx == slotx) + slotxx++; + if (slotyy == sloty) + slotyy++; + + printfdf(false,"(): moving window %p (%d,%d) -> (%d,%d) which has size (%d,%d)", + moving_window, slotx, sloty, slotx+ii-i, sloty+jj-j, slotxx-slotx, slotyy-sloty); } - //printfdf("(): affinity: %d", max_affinity); // move window to right/down - foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { - ClientWin *slotw = (ClientWin*) iter->data; - if (boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j) - == max_affinity) { - moving_window = slotw; + //foreach_dlist (slot2cw[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx]) { + //ClientWin *slotw = (ClientWin*) iter->data; + //if (boxy_affinity(slotw, slot_width, slot_height, i, j, ii-i, jj-j) + //== max_affinity) { //printfdf("(): moving window %p: (%d,%d) -> (%d,%d)", slotw, i, j, ii, jj); moving_window->x += (ii - i) * slot_width; moving_window->y += (jj - j) * slot_height; - goto move_window; - } - } -move_window: + //goto move_window; + //} + //} +//move_window: // move all windows right/down of move_window - foreach_dlist (windows) { + /*foreach_dlist (windows) { ClientWin *cw = (ClientWin*) iter->data; int cw_slotx = floor((float) cw->x / (float) slot_width); int cw_sloty = floor((float) cw->y / (float) slot_height); @@ -473,7 +505,7 @@ do cw->y += slot_height; } } - } + }*/ } } } @@ -485,7 +517,7 @@ do // to current slot, sorted by affinity, // and whether current slots can fit the window // - for (int j=slot_miny; !recalculate && j 0; + total_occupancy += slot_occupancy; + if ((slot_maxx - slot_minx) * (j - slot_miny) + + (slot_maxy - slot_miny) * (i - slot_minx) + < (slot_maxx - slot_minx) * (slot_maxy - slot_miny) + 1){ + printfdf(false,"(): (%d,%d) in top left", i,j); + top_left_occupancy += slot_occupancy; + } + } + } + float occupancy_ratio = (float)top_left_occupancy / (float)total_occupancy; + printfdf(false,"(): top left occupancy: %d total occupancy: %d triangular ratio: %f", + top_left_occupancy, total_occupancy, occupancy_ratio); + + // if too triangular, perform rotate contraction + if (occupancy_ratio > TRIANGULAR_TOLERANCE) { + + // determine whether to perform row or column rotate contraction + int pivotx = 0, pivoty = 0, ii = 0, jj = 0; + bool pivoted = false; + float estimated_aspect = (float) (slot_width * slot_maxx) + / (float) (slot_height * slot_maxy); + printfdf(false,"(): aspect %f %f",estimated_aspect, screen_aspect*ASPECT_TOLERANCE); + if (estimated_aspect < screen_aspect * ASPECT_TOLERANCE) { + ii = 1; + for (int j=slot_maxy-1; j>slot_miny && !pivoted; j--) { + for (int i=slot_maxx-1; i>=slot_minx && !pivoted; i--) { + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 0) { + printfdf(false,"(): perform row rotate contraction at (%d,%d)", + i, j); + pivotx = i; + pivoty = j; + pivoted = true; + } + } + } + } + else { + jj = 1; + for (int i=slot_maxx-1; i>slot_minx && !pivoted; i--) { + for (int j=slot_maxy-1; j>=slot_miny && !pivoted; j--) { + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] > 0) { + printfdf(false,"(): perform column rotate contraction at (%d,%d)", + i, j); + pivotx = i; + pivoty = j; + pivoted = true; + } + } + } + } + + // rotate contraction: + // identify next empty slot as target + int targetx = pivotx, targety = pivoty; + + while (targetx-jj < slot_maxx-1 && targety-ii < slot_maxy-1 + && slot2n[(targety-ii -slot_miny) * (slot_maxx - slot_minx) + + targetx-jj -slot_minx] > 0) { // notice swapping and -ve of ii,jj + targetx += ii; + targety += jj; + } + + if (!(targetx == pivotx && targety == pivoty) + && targetx-jj >= 0 + && targety-ii >= 0 + && slot2n[(targety-ii -slot_miny) * (slot_maxx - slot_minx) + + targetx-jj -slot_minx] == 0) { // notice swapping and -ve of ii,jj + targetx -= jj; + targety -= ii; + + // find window from pivot slot to move, associated with max affinity + ClientWin *moving_window = NULL; + int max_affinity = INT_MIN; + foreach_dlist (slot2cw[(pivoty-slot_miny) * (slot_maxx - slot_minx) + + pivotx-slot_minx]) { + ClientWin *slotw = (ClientWin*) iter->data; + int affinity = boxy_affinity(slotw, slot_width, slot_height, + pivotx, pivoty, + targetx - pivotx, targety - pivoty); + if (affinity > max_affinity) { + bool collision = false; + { + int slotx_old = floor((float) slotw->x / (float) slot_width); + int sloty_old = floor((float) slotw->y / (float) slot_height); + int slotxx_old = slotx_old + ceil((float) slotw->src.width / (float) slot_width); + int slotyy_old = sloty_old + ceil((float) slotw->src.height / (float) slot_height); + if (slotxx_old == slotx_old) + slotxx_old++; + if (slotyy_old == sloty_old) + slotyy_old++; + + int slotx_new = slotx_old + targetx - pivotx; + int sloty_new = slotx_old + targety - pivoty; + int slotxx_new = slotx_old + targetx - pivotx; + int slotyy_new = slotx_old + targety - pivoty; + + for (int j=sloty_new; !collision && j 0) { + if (slot2n[(j-slot_miny) * (slot_maxx - slot_minx) + i-slot_minx] == 1 + && slotx_old <= i && i <= slotxx_old + && sloty_old <= j && j <= slotyy_old) { + // do not count own window slots + continue; + } + printfdf(false,"(): collision at (%d,%d), window dimensions (%d,%d,%d,%d)", + i,j, slotx_old, sloty_old, slotxx_old-slotx_old, slotyy_old-sloty_old); + collision = true; + } + } + } + } + if (!collision) { + max_affinity = affinity; + moving_window = slotw; + } + } + max_affinity = MAX(max_affinity, affinity); + printfdf(false,"(): window %p has affinity %d", slotw, affinity); + } + + // move window + if (moving_window != NULL) { + printfdf(false,"(): rotate contraction from (%d,%d) -> (%d,%d)", + pivotx, pivoty, targetx, targety); + recalculate = true; + moving_window->x += (targetx - pivotx) *slot_width; + moving_window->y += (targety - pivoty) *slot_height; + } + } + } } - if (recalculate) { + if (recalculate && max_iterations<100-1) { for (int i=0; i Date: Tue, 4 Jul 2023 09:52:17 -0700 Subject: [PATCH 195/205] Expose XD sorts by row/z-order (#151) seems fine, (merged) --- src/skippy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 5932b4e..684b6a5 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -464,10 +464,10 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { // is important for prev/next window selection mw->focuslist = dlist_dup(mw->clientondesktop); - if (layout == LAYOUTMODE_SWITCH) - dlist_reverse(mw->focuslist); - else if (layout == LAYOUTMODE_EXPOSE) + if (layout == LAYOUTMODE_EXPOSE && ps->o.exposeLayout == LAYOUT_BOXY) dlist_sort(mw->focuslist, sort_cw_by_column, 0); + else + dlist_reverse(mw->focuslist); // Get the currently focused window and select which mini-window to focus dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) leader); From 65b8e854c32d168e410c12fa5a1ae9c2b871b862 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Wed, 5 Jul 2023 00:02:23 +0100 Subject: [PATCH 196/205] fix: client_focus_on_cancel - it makes this work. remember prior active window, before skippy was ever activated, when cancelling with Esc key Previously there was an oversight or bug in the code, whereby this variable wasn't getting set or used correctly. By moving assignment of variable to place slightly before in the code, skippy can now remember what it was! :Yum: (easy fix) Maybe for some reason(s) this was already working after moving about with the mouse. In different areas of code. This fix is for situation(s) where mouse isn't moved / triggering those alternate code paths. So maybe other places in the code is already OK. (And no need to bother elsewhere) --- src/clientwin.c | 2 +- src/skippy.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 27f02f0..453f14e 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -665,7 +665,7 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { else if (arr_keycodes_includes(cw->mainwin->keycodes_ExitCancelOnPress, evk->keycode)) { - cw->mainwin->refocus = true; + mw->client_to_focus = cw->mainwin->client_to_focus_on_cancel; return 1; } diff --git a/src/skippy.c b/src/skippy.c index 684b6a5..ea7819c 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -480,6 +480,8 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { // ps->mainwin->ignore_next_refocus = 2; // ps->mainwin->ignore_next_refocus = 4; + // remember what was the currently focused window (before this activation of skippy) + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; if(ps->o.focus_initial == FI_PREV) { @@ -510,7 +512,6 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { } else { mw->client_to_focus = (ClientWin *) iter->data; - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; mw->client_to_focus->focused = 1; } } From ae6de07a670e97ad5c13b5b8a21477e1c49c8ca0 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Wed, 5 Jul 2023 00:03:36 +0100 Subject: [PATCH 197/205] runner: update this script to work with new cmdline flags It's probably gotten a bit broken now, but at minimum at least some basic/medium level(s) functionality works. --- skippy-xd-runner | 94 +++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/skippy-xd-runner b/skippy-xd-runner index 37a1fde..441d2b7 100755 --- a/skippy-xd-runner +++ b/skippy-xd-runner @@ -15,21 +15,20 @@ # skippy-xd-runner # # The available commands are: -# [no command] - activate expose once without daemon. -# --config-reload - reload configuration file; currently the file path must remain unchanged. -# --config - read the specified configuration file. -# --start-daemon - starts the daemon running. -# --stop-daemon - stops the daemon running. -# --activate-expose - connects to daemon and activate expose. -# --toggle-expose - connects to daemon and toggle expose. -# --activate-paging - connects to daemon and activate paging. -# --toggle-paging - connects to daemon and toggle paging. -# --deactivate - connects to daemon and deactivate expose or paging. -# --prev - focus window to previous. -# --next - focus window to next. -# -# --help - show this message. -# -S - Synchronize X operation (debugging). +# [no command] - activate expose once without daemon. +# --help - show this message. +# -S - enable debugging logs. + +# --config - read configuration file from path. +# --config-reload - reload configuration file from the previous path. + +# --start-daemon - runs as daemon mode. +# --stop-daemon - terminates skippy-xd daemon. + +# --switch - connects to daemon and switch to next window. +# --switch-prev - connects to daemon and switch to previous window. +# --expose - connects to daemon and activate expose. +# --paging - connects to daemon and activate paging. # # # @@ -45,7 +44,7 @@ _kill_skippy() { } - + _parse_args() { while [ "$1" ]; do @@ -53,19 +52,23 @@ _parse_args() case $arg in - --config-reload) _config_reload=true ;; + --help|-h) _help=true ;; + -S) _sync=true ;; + --config) shift && _config="$1" ;; + --config-reload) _config_reload=true ;; + --start-daemon|--start) _start_daemon=true ;; --stop-daemon|--stop) _stop_daemon=true ;; - --activate-expose|--activate) _activate_expose=true ;; - --toggle-expose|--toggle) _toggle_expose=true ;; - --activate-paging|--activate) _activate_paging=true ;; - --toggle-paging|--toggle) _toggle_paging=true ;; - --deactivate|--deactivate) _deactivate=true ;; - --prev) _prev=true ;; - --next) _next=true ;; - --help|-h) _help=true ;; - -S) _sync=true ;; + + --switch) _activate=true; _next=true ;; + --switch-prev) _activate=true; _prev=true ;; + + --expose) _activate=true; _expose=true ;; + --paging) _activate=true; _paging=true ;; + + --toggle) _toggle=true ;; + --deactivate) _deactivate=true ;; esac @@ -73,24 +76,20 @@ _parse_args() done unset _first_arg - if [ "$_activate_expose" ]; then - _first_arg="--activate-expose" + if [ "$_next" ]; then + _first_arg="--switch" fi - if [ "$_toggle_expose" ]; then - _first_arg="--toggle-expose" + if [ "$_prev" ]; then + _first_arg="--switch-prev" fi - if [ "$_activate_paging" ]; then - _first_arg="--activate-paging" + if [ "$_expose" ]; then + _first_arg="--expose" fi - if [ "$_toggle_paging" ]; then - _first_arg="--toggle-paging" - fi - - if [ "$_deactivate" ]; then - _first_arg="--deactivate" + if [ "$_paging" ]; then + _first_arg="--paging" fi if [ "$_first_arg" ]; then @@ -100,16 +99,21 @@ _parse_args() _main() { - lastActivationTimeoutSeconds=1 + # if [ "$(command -v xdotool)" ]; then + # if xdotool search -class --onlyvisible skippy-xd > /dev/null; then + # echo "ignored. skippy is already open / active" + # exit 1 + # fi + # fi - psSkippyActivateExposeOut="`pgrep -f 'skippy-xd --activate-expose'`" - psSkippyToggleExposeOut="`pgrep -f 'skippy-xd --toggle-expose'`" - psSkippyActivatePagingOut="`pgrep -f 'skippy-xd --activate-paging'`" - psSkippyTogglePagingOut="`pgrep -f 'skippy-xd --toggle-paging'`" - psSkippyDeactivateOut="`pgrep -f 'skippy-xd --deactivate'`" + lastActivationTimeoutSeconds=1 + psSkippyAltTabOut="`pgrep -f 'skippy-xd --switch'`" + psSkippyAltTabOut="$psSkippyAltTabOut `pgrep -f 'skippy-xd --switch-prev'`" + psSkippyExposeOut="`pgrep -f 'skippy-xd --expose'`" + psSkippyPagingOut="`pgrep -f 'skippy-xd --paging'`" _other_clients=0 - for pid in $psSkippyActivateExposeOut $psSkippyToggleExposeOut $psSkippyActivatePagingOut $psSkippyTogglePagingOut $psSkippyDeactivateOut; do + for pid in $psSkippyAltTabOut $psSkippyExposeOut $psSkippyPagingOut; do ptime="$(ps -o etimes= -p "$pid")" if [ "$ptime" -ge "$lastActivationTimeoutSeconds" ]; then _killall=true From 3b84bdb62867a76e69638cde1c2d69656169ea17 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Wed, 5 Jul 2023 01:01:06 +0100 Subject: [PATCH 198/205] fix: logic error for modifier keys - to reverse direction when pressing / releasing SHIFT of CTRL during TAB-bing --- src/clientwin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clientwin.c b/src/clientwin.c index 453f14e..6b9c41d 100644 --- a/src/clientwin.c +++ b/src/clientwin.c @@ -611,8 +611,8 @@ clientwin_handle(ClientWin *cw, XEvent *ev) { bool reverse_direction = false; - if (arr_modkeymasks_includes(cw->mainwin->modifierKeyMasks_ReverseDirection, evk->state)) - if(arr_keycodes_includes(cw->mainwin->keycodes_ReverseDirection, evk->keycode)) + if (arr_modkeymasks_includes(cw->mainwin->modifierKeyMasks_ReverseDirection, evk->state) || + arr_keycodes_includes(cw->mainwin->keycodes_ReverseDirection, evk->keycode)) reverse_direction = true; if (arr_keycodes_includes(cw->mainwin->keycodes_Up, evk->keycode)) From 132399f1e11d603f5706ac510c75ce4c8d0daac6 Mon Sep 17 00:00:00 2001 From: Dreamcat4 Date: Wed, 5 Jul 2023 01:17:34 +0100 Subject: [PATCH 199/205] config: improve parsing of comments within the file * These regexes are type POSIX regex extended * They have been updated and tested online at https://regex101.com/ In the situation where a configuration value contains any hex color codes (#aaafff) Then the regexp can correctly identify those, but still distinguish the #comment at the end of a line Example test string: iconFillSpec = orig mid mid #00FFFF //fffffoo #Something ;comment Should split out to: matches[1] = "iconFillSpec" matches[2] = "orig mid mid #00FFFF" matches[3] = "//fffffoo #Something ;comment" Where a partial or inexact match of matches[3] it never matters (because it is always discarded). --- skippy-xd.sample.rc | 5 +++-- src/config.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index a38e3cc..5e90f82 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -3,8 +3,9 @@ # Notes: # # - File Syntax: -# Comments must be on their own seperate lines that start with a # -# You cannot append # comment after a settings line or a section header +# Comments can start with a #comment ;comment or //comment +# Comments can also be appended to the end of a valid configuration line for example: +# key = value #comment # # - colors can be anything XAllocNamedColor can handle # (like "black" or "#000000") diff --git a/src/config.c b/src/config.c index 2b6a650..cd6046f 100644 --- a/src/config.c +++ b/src/config.c @@ -74,8 +74,8 @@ config_parse(const char *config) { dlist *new_config = 0; regcomp(&re_section, "^[[:space:]]*\\[[[:space:]]*([[:alnum:]]*?)[[:space:]]*\\][[:space:]]*$", REG_EXTENDED); - regcomp(&re_empty, "^[[:space:]]*#|^[[:space:]]*$", REG_EXTENDED); - regcomp(&re_entry, "^[[:space:]]*([[:alnum:]]+)[[:space:]]*=[[:space:]]*(.*?)[[:space:]]*$", REG_EXTENDED); + regcomp(&re_empty, "^[[:space:]]*\/\/|^[[:space:]]*;|^[[:space:]]*#|^[[:space:]]*$", REG_EXTENDED); + regcomp(&re_entry, "^[[:space:]]*([[:alnum:]]+)[[:space:]]*=[[:space:]]*(.*?)([[:space:]]*$|[[:space:]]*\/\/|[[:space:]]*;.*$|[[:space:]]*(#[^0-9a-fA-F]|#.{1,5}[^0-9a-fA-F]).*$)", REG_EXTENDED); while(1) { From 847d3c35a659e0f0b3445ed44e9d18e0edcbc715 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 7 Jul 2023 01:15:18 -0700 Subject: [PATCH 200/205] set window to focus on cancel outside of guard (#154) Thank you felix --- src/skippy.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index ea7819c..f266bcf 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -472,6 +472,12 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { // Get the currently focused window and select which mini-window to focus dlist *iter = dlist_find(mw->focuslist, clientwin_cmp_func, (void *) leader); + // remember what was the currently focused window (before this activation of skippy) + if (iter) + mw->client_to_focus_on_cancel = (ClientWin *) iter->data; + else + mw->client_to_focus_on_cancel = NULL; + // check if the user specified --prev or --next on the cmdline if(ps->o.focus_initial && iter) { @@ -480,9 +486,6 @@ init_focus(MainWin *mw, enum layoutmode layout, Window leader) { // ps->mainwin->ignore_next_refocus = 2; // ps->mainwin->ignore_next_refocus = 4; - // remember what was the currently focused window (before this activation of skippy) - mw->client_to_focus_on_cancel = (ClientWin *) iter->data; - if(ps->o.focus_initial == FI_PREV) { // here, mw->focuslist is the first (dlist*) item in the list From 5455985c674a1d1345b33ed0a95e3634f8d1c4d4 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Fri, 7 Jul 2023 17:56:40 -0700 Subject: [PATCH 201/205] Paging tinting finally works properly! --- src/skippy.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index f266bcf..17f145e 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -814,6 +814,7 @@ mainloop(session_t *ps, bool activate_on_start) { enum layoutmode layout = LAYOUTMODE_EXPOSE; bool animating = activate; long first_animated = 0L; + long paging_last_forced_update = 0; switch (ps->o.mode) { case PROGMODE_SWITCH: @@ -1035,18 +1036,18 @@ mainloop(session_t *ps, bool activate_on_start) { } } else if (mw && (ps->xinfo.damage_ev_base + XDamageNotify == ev.type)) { - //printfdf(false, "(): else if (ev.type == XDamageNotify) {"); + printfdf(false, "(): else if (ev.type == XDamageNotify) {"); pending_damage = true; dlist *iter = dlist_find(ps->mainwin->clients, clientwin_cmp_func, (void *) wid); if (iter) { ((ClientWin *)iter->data)->damaged = true; } - iter = dlist_find(ps->mainwin->dminis, - clientwin_cmp_func, (void *) wid); - if (iter) { - ((ClientWin *)iter->data)->damaged = true; - } + //iter = dlist_find(ps->mainwin->dminis, + //clientwin_cmp_func, (void *) wid); + //if (iter) { + //((ClientWin *)iter->data)->damaged = true; + //} } else if (mw && wid == mw->window) die = mainwin_handle(mw, &ev); @@ -1089,7 +1090,7 @@ mainloop(session_t *ps, bool activate_on_start) { // Do delayed painting if it's active if (mw && pending_damage && !die) { - //printfdf(false, "(): delayed painting"); + printfdf(false, "(): delayed painting"); pending_damage = false; foreach_dlist(mw->clientondesktop) { if (((ClientWin *) iter->data)->damaged) @@ -1126,10 +1127,10 @@ mainloop(session_t *ps, bool activate_on_start) { // not great solution at all... if (mw && layout == LAYOUTMODE_PAGING) { - static int counter = 0; - if(counter == 0) + if (time_in_millis() - paging_last_forced_update > 10) { pending_damage = true; - counter = (counter + 1) % 10; + paging_last_forced_update = time_in_millis(); + } } // Handle daemon commands From 0aa7638152580e50af512cd1013cfabcc5171086 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Wed, 12 Jul 2023 01:52:44 -0700 Subject: [PATCH 202/205] The number of paging desktops is now correct (#157) --- src/skippy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 17f145e..193b2e8 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -593,8 +593,8 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) // create windows which represent each virtual desktop int current_desktop = wm_get_current_desktop(mw->ps); - for (int j=0; j Date: Wed, 12 Jul 2023 14:29:55 +0100 Subject: [PATCH 203/205] Revert "config: improve parsing of comments within the file" This reverts commit 132399f1e11d603f5706ac510c75ce4c8d0daac6. --- skippy-xd.sample.rc | 5 ++--- src/config.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index 5e90f82..a38e3cc 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -3,9 +3,8 @@ # Notes: # # - File Syntax: -# Comments can start with a #comment ;comment or //comment -# Comments can also be appended to the end of a valid configuration line for example: -# key = value #comment +# Comments must be on their own seperate lines that start with a # +# You cannot append # comment after a settings line or a section header # # - colors can be anything XAllocNamedColor can handle # (like "black" or "#000000") diff --git a/src/config.c b/src/config.c index cd6046f..2b6a650 100644 --- a/src/config.c +++ b/src/config.c @@ -74,8 +74,8 @@ config_parse(const char *config) { dlist *new_config = 0; regcomp(&re_section, "^[[:space:]]*\\[[[:space:]]*([[:alnum:]]*?)[[:space:]]*\\][[:space:]]*$", REG_EXTENDED); - regcomp(&re_empty, "^[[:space:]]*\/\/|^[[:space:]]*;|^[[:space:]]*#|^[[:space:]]*$", REG_EXTENDED); - regcomp(&re_entry, "^[[:space:]]*([[:alnum:]]+)[[:space:]]*=[[:space:]]*(.*?)([[:space:]]*$|[[:space:]]*\/\/|[[:space:]]*;.*$|[[:space:]]*(#[^0-9a-fA-F]|#.{1,5}[^0-9a-fA-F]).*$)", REG_EXTENDED); + regcomp(&re_empty, "^[[:space:]]*#|^[[:space:]]*$", REG_EXTENDED); + regcomp(&re_entry, "^[[:space:]]*([[:alnum:]]+)[[:space:]]*=[[:space:]]*(.*?)[[:space:]]*$", REG_EXTENDED); while(1) { From 0c454d7d6c6beb6dad27ac091b0970d3f22a7491 Mon Sep 17 00:00:00 2001 From: Felix Fung Date: Thu, 13 Jul 2023 00:01:30 -0700 Subject: [PATCH 204/205] Paging desktop offset to centre of screen --- src/skippy.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/skippy.c b/src/skippy.c index 193b2e8..7b32fb4 100644 --- a/src/skippy.c +++ b/src/skippy.c @@ -557,9 +557,15 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) screencount = 1; int desktop_dim = ceil(sqrt(screencount)); + // the paging layout is rectangular + // such that screenwidth == ceil(sqrt(screencount)) + // and the screenheight == ceil(screencount / screenwidth) + int screenwidth = desktop_dim; + int screenheight = ceil((float)screencount / (float)screenwidth); + { - int totalwidth = desktop_dim * (mw->width + mw->distance) - mw->distance; - int totalheight = desktop_dim * (mw->height + mw->distance) - mw->distance; + int totalwidth = screenwidth * (mw->width + mw->distance) - mw->distance; + int totalheight = screenheight * (mw->height + mw->distance) - mw->distance; float multiplier = (float) (mw->width - 1 * mw->distance) / (float) totalwidth; if (multiplier * totalheight > mw->height - 1 * mw->distance) @@ -578,11 +584,11 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) int win_desktop = wm_get_window_desktop(mw->ps, cw->wid_client); int current_desktop = wm_get_current_desktop(mw->ps); - int win_desktop_x = win_desktop % desktop_dim; - int win_desktop_y = win_desktop / desktop_dim; + int win_desktop_x = win_desktop % screenwidth; + int win_desktop_y = win_desktop / screenwidth; - int current_desktop_x = current_desktop % desktop_dim; - int current_desktop_y = current_desktop / desktop_dim; + int current_desktop_x = current_desktop % screenwidth; + int current_desktop_y = current_desktop / screenwidth; cw->x = cw->src.x + win_desktop_x * (mw->width + mw->distance); cw->y = cw->src.y + win_desktop_y * (mw->height + mw->distance); @@ -593,9 +599,9 @@ init_paging_layout(MainWin *mw, enum layoutmode layout, Window leader) // create windows which represent each virtual desktop int current_desktop = wm_get_current_desktop(mw->ps); - for (int j=0, k=0; j Date: Fri, 14 Jul 2023 13:30:30 +0100 Subject: [PATCH 205/205] config: sample.rc: Improve inline comments, exaplains what these keybinds settings actually does. (previously was not documented) --- skippy-xd.sample.rc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/skippy-xd.sample.rc b/skippy-xd.sample.rc index a38e3cc..247f501 100644 --- a/skippy-xd.sample.rc +++ b/skippy-xd.sample.rc @@ -150,5 +150,11 @@ keysExitCancelOnPress = Escape BackSpace x q keysExitCancelOnRelease = keysExitSelectOnPress = Return space keysExitSelectOnRelease = Super_L Super_R Alt_L Alt_R ISO_Level3_Shift -keysReverseDirection = Tab + +# Put here the modifier keys that (when held) reverses the direction of skippy's navigation keys (prev, next, up, down) +# Normally this is (typically) just "Shift" key only, however you might instead have special accessibility needs ;) modifierKeyMasksReverseDirection = ShiftMask ControlMask + +# The *subset* of navigation keys, for which "modifierKeyMasksReverseDirection" is applied to actually reverse the direction +# All other nav keys are then ignored, (eg: 'left','right','up','down'). It seems 'wrong' but gives more intuitive keyboard navigation. +keysReverseDirection = Tab