Adds window-tiling keybindings to any X11-based desktop. (An analogue to WinSplit Revolution for people who don't want to use the Compiz Grid plugin)
Clone or download
Stephan Sokolow Stephan Sokolow
Stephan Sokolow and Stephan Sokolow README.rst: Add removal instructions
Fixes #94
Latest commit 147b995 Sep 11, 2018
Permalink
Failed to load latest commit information.
quicktile Fix ePyDoc complaint that's causing Travis-CI to go red Aug 24, 2017
.codeclimate.yml Add a CodeClimate config file Apr 9, 2017
.coveragerc Fix oversight in code coverage calculation Aug 20, 2017
.gitignore Start adding MyPy type signatures to functions and certain variable d… Aug 21, 2017
.scrutinizer.yml Add Scrutinizer static analysis Jan 29, 2017
.travis.yml Fix unrequested ePyDoc magic import that's breaking Travis-CI build Aug 20, 2017
ChangeLog Switch to a proper solution for trackng cycle position in cycle_dimen… Aug 23, 2017
LICENSE Add a copy of the GPL 2.0 to the source tree. Aug 15, 2013
MANIFEST.in Split up QuickTile into multiple files and fix bugs thus revealed Aug 20, 2017
README.rst README.rst: Add removal instructions Sep 12, 2018
install.sh install.sh: Automatically attempt to remove old quicktile files Aug 20, 2017
quicktile.desktop Split up QuickTile into multiple files and fix bugs thus revealed Aug 20, 2017
quicktile.sh Split up QuickTile into multiple files and fix bugs thus revealed Aug 20, 2017
run_tests.sh Start adding MyPy type signatures to functions and certain variable d… Aug 21, 2017
setup.cfg Also run a basic epydoc sanity check on Travis-CI Apr 9, 2017
setup.py Fix Codacy and CodeClimate complaints Aug 22, 2017
test_functional.py Implement quick and dirty context manager for background procs in tests Sep 10, 2018
test_quicktile.py Switch to a proper solution for trackng cycle position in cycle_dimen… Aug 23, 2017
tox.ini Set up basic tox support Aug 20, 2017

README.rst

QuickTile

Code Health Scrutinizer Code Quality Codacy Code Climate Travis-CI Coveralls

Keyboard-driven Window Tiling for your existing X11 window manager

Important Message For Existing Users

As of QuickTile 0.3.0, the installation process has changed.

This was necessary to allow QuickTile to be split across multiple files so I could get past some mental blocks and start to clean up the code and implement new features.

Requirements:

  • An X11-based desktop (The code expects NETWM hints and X11-style window decorations)
  • Python 2.7
  • PyGTK
  • python-wnck
  • python-setuptools
  • python-xlib (optional, required for key-binding)
  • dbus-python (optional, required for D-Bus service)

As PyGTK was never ported to Python 3.x and porting to GTK+ 3.x wouldn't bring any significant benefits for a utility that is fundamentally incompatible with Wayland's security model, these requirements are unlikely to change.

Depending on the distro you are using, you may be able to use one of the following commands to easily install them:

Debian and derivatives (Ubuntu, Mint, etc.):

sudo apt-get install python python-gtk2 python-xlib python-dbus python-wnck python-setuptools

Fedora 22 and above:

sudo dnf install python pygtk2 pygobject2 dbus-python gnome-python2-libwnck

Fedora 21 and below:

sudo yum install python pygtk2 pygobject2 dbus-python gnome-python2-libwnck

Installation (Typical Use)

After you have installed the above requirements (including python-xlib) via your system package manager, you can install QuickTile using either of the following methods:

  1. If you have pip2 installed, just run this:
sudo pip2 install https://github.com/ssokolow/quicktile/archive/master.zip

NOTE: If you attempt to use the --upgrade option and it fails to properly ignore system-provided dependencies, just use these commands instead:

sudo pip2 uninstall quicktile
sudo rm /usr/local/bin/quicktile /usr/local/bin/quicktile.py
sudo pip2 install https://github.com/ssokolow/quicktile/archive/master.zip
  1. Without pip2, download and unpack the zip file and run the following:
cd /path/to/local/copy
./install.sh

Technically speaking, an ordinary sudo python2 setup.py install will also work, but install.sh has three advantages:

  1. It runs the setup.py build step without root privileges to avoid leaving root-owned cruft around.
  2. It will attempt to remove old QuickTile files which might cause a newer install to break.
  3. It saves you the trouble of setting QuickTile to run on startup. (setup.py can't do this because it has no mechanism for adding files to /etc.)
  1. Without pip2, if you don't want a system-wide install:
  1. Download and unpack the zip file.
  2. Copy the quicktile folder and the quicktile.sh script into a folder of your choice.
  3. Make sure quicktile.sh is marked executable.

NOTE: If you'd rather roll your own, the quicktile.sh shell script is just three simple lines.

AFTER INSTALLING:

  1. Run quicktile once to generate your configuration file

    NOTE: If the quicktile command dies with a No module named __main__ error, you probably have an old quicktile.py file in /usr/local/bin that needs to be deleted. If that doesn't fix the problem, you should still be able to run QuickTile as python2 -m quicktile instead.

  2. Edit ~/.config/quicktile.cfg to customize your keybinds

    Note: Customizing the available window shapes currently requires editing the source code (though it's quite simple). This will be remedied when I have time to decide between extending the standard Python rcfile parser and replacing quicktile.cfg with quicktile.json.

  3. Set your desktop to run quicktile --daemonize if you didn't use install.sh.

Important Notes:

  • If you are running a desktop which uses Compiz (such as Unity), make sure you've used CCSM to disable the grid plugin or the fight between it and QuickTile for the same type of functionality may cause unpredictable problems.
  • Some systems may not provide a Python 2.x binary under the name python2. If this is the case on yours, install.sh must be edited if you choose to use it.
  • You can list your current keybindings by running quicktile --show-bindings
  • You can get a list of valid actions for the configuration file by running quicktile --show-actions

Usage (Typical Use)

  1. Focus the window you want to tile
  2. Hold the modifiers defined in ModMask (Ctrl+Alt by default).
  3. Repeatedly press one of the defined keybindings to cycle through window sizes available at the desired location on the screen.

The default keybindings are:

  • 1 through 9 on the numeric keypad represent regions of your screen
  • 0 on the numeric keypad will fully maximize the active window.
  • H and V will maximize a window horizontally or vertically.
  • Enter on the numeric keypad will cycle the active window to the next monitor.

This works best when combined with functionality your existing window manager provides (eg. Alt+Tab) to minimize the need to switch your hand between your keyboard and your mouse.

Keybinding Syntax

Both the ModMask field and the [keys] section use GTK+ accelerator syntax and you can use modifier keys in both places. (ModMask is prepended to each [keys] value before parsing it.)

GTK+ modifier syntax looks like this:

<Ctrl><Alt>Delete

The important things to keep in mind for using it are:

  1. Do not put any spaces inside your keybind string.
  2. Modifier names and non-modifier key names are not the same thing.
  3. Modifier names are case-insensitive.
  4. Key names like Down are case-sensitive. (Don't let the letter keys fool you. Those work the way they do because A and a are two separate names for the same key.)

Valid Key Names

GTK+ key names are just X11 key symbols so the simplest way to identify the name for a key is to use the xev command. Just run it in a terminal and press the key you want. It will print out something like this:

KeyPress event, serial 41, synthetic NO, window 0x8400001,
   root 0x291, subw 0x0, time 2976251798, (149,-352), root:(192,460),
   state 0x10, keycode 116 (keysym 0xff54, Down), same_screen YES,
   XLookupString gives 0 bytes:
   XmbLookupString gives 0 bytes:
   XFilterEvent returns: False

The part I've bolded is the name QuickTile expects.

Troubleshooting xev:

  • If nothing happens, make sure the xev window (and not the terminal) has focus.
  • If pressing the key triggers some messages but you do not see one which says KeyPress event, it's likely that some other program has already grabbed that key combination.

Also, in my testing, QuickTile currently fails to bind keys like Super_L (left Windows key) when they've been configured as modifiers. I'll look into this as time permits.

Valid Modifier Names

I haven't found a comprehensive document listing the modifier names gtk.accelerator_parse() accepts, but here are the names I'm aware of with consistent mappings:

  • Mappings that should be consistent across pretty much any system:
    • Control: <Control>, <Ctrl>, <Ctl>, <Primary>
    • Shift: <Shift>, <Shft>
    • Alt: <Alt>, <Mod1>
  • Mappings which worked for me but I can't make any guarantees for:
    • Windows Key: <Mod4>
    • AltGr: <Mod5>
  • Mappings which are possible but need to be manually set up using setxkbmap and xmodmap:
    • <Mod3> (I redefined Caps Lock as Hyper_L and bound it to this)
  • Modifiers which cause QuickTile to error out deep in python-xlib because GTK+ maps them to integers beyond the limits of the X11 wire protocol:
    • <Meta>
    • <Super>
    • <Hyper>

Advanced Uses

  • If you want to trigger QuickTile from another application in an efficient manner, make sure you have dbus-python installed and read up on how to send D-Bus messages using either your language's D-Bus bindings or the dbus-send or qdbus commands.
  • If, for some reason, you want scripted tiling without D-Bus, you can also run commands like quicktile top-left but it may be slower as quicktile has to start, perform an action, and then quit every time you call it.

As with the built-in keybinding, requesting the same action more than once in a row will cycle through the available window sizes. For further details, see --help.

Known Bugs

  • libwnck tries to flood the logging output with Unhandled action type _OB_WM_ACTION_UNDECORATE\n\n messages, which is a bug, and PyGTK doesn't expose the function needed to filter them away. As a result, the best QuickTile can do is pipe its output through grep, leaving a flood of blank lines since grep is finicky about matching them.
  • pip2 uninstall doesn't remove the quicktile and/or quicktile.py files from /usr/local/bin, which can cause subsequent installs to break.

Thanks to Thomas Vander Stichele for some of the documentation cleanups.

Removal

As QuickTile does not yet have a one-command uninstall script, you will need to do the following.

  1. If you installed via pip2...
sudo pip2 uninstall quicktile
sudo rm /usr/local/bin/quicktile
  1. If you installed via install.sh...

install.sh doesn't yet log what it installed the way pip2 does, so this will be a bit more involved.

First, remove the system integration files:

# Remove the command that can be typed at the command-line
sudo rm /usr/local/bin/quicktile

# Remove the autostart file
sudo rm /etc/xdg/autostart/quicktile.desktop

# Remove the launcher menu entry
sudo rm /usr/local/share/applications/quicktile.desktop

Second, remove QuickTile itself from your Python packages folder.

As development and release installations produce different file layouts, the way I recommend doing this is to run the following command, verify that nothing looks obviously wrong about the list of files and folders it produces, and then delete them:

find /usr/local/lib/python2.7 -iname 'quicktile*'