Toggle window decorations on Linux GTK3 with Python3

The Internet is full of outdated Python code for doing things with windows, so here is what I got working today in a Python 3, GTK 3 environment.

This script toggles the window decorations on the active window on and off. I have it bound to Ctrl+NumPadMinus for easy access.

#!/usr/bin/env python3

import gi
gi.require_version('Gdk', '3.0')
gi.require_version('GdkX11', '3.0')
gi.require_version('Wnck', '3.0')
from gi.repository import Gdk
from gi.repository import GdkX11
from gi.repository import Wnck


def active_window(screen):
    for window in screen.get_windows():
       if window.is_active() == True:
            return window


def toggle_decorations(w):
    if w.get_decorations().decorations == 0:
        w.set_decorations(Gdk.WMDecoration.ALL)
    else:
        w.set_decorations(0)


screen = Wnck.Screen.get_default()
screen.force_update()
display = GdkX11.X11Display.get_default()
window = active_window(screen)
window_id = window.get_xid()

w = GdkX11.X11Window.foreign_new_for_display(display, window_id)
toggle_decorations(w)


window = None
screen = None
Wnck.shutdown()

Desktop sharing not working in Lubuntu 14.04

On my recently-upgraded to 14.04 Lubuntu machine, desktop sharing didn’t work.

Here’s how I made it work:

Once (to allow some Windows clients to connect without encryption):

gsettings set org.gnome.Vino require-encryption false

Then every time I want to share my desktop:

/usr/lib/vino/vino-server

and leave that running while I’m sharing.

rdesktop swallows keyboard events

The Linux remote desktop client rdesktop grabs all keyboard events by default, which is good, because it allows e.g. you to Alt-Tab between applications and Ctrl-Alt-Del as if you were in front of the remote machine.

However, it is also bad because you can’t use the standard keyboard shortcuts to switch between virtual desktops. Varius Googling had convinced me that this problem was not soluble, since X only provides a global keyboard-grabbing function XGrabKeyboard, and once the event has been grabbed and fed to rdesktop, there doesn’t appear to be a way to re-emit it back up to the window manager so that it can be used to switch desktops.

Kudos to Sunner, therefore, for coming up with a workaround. It’s really simple: you have to press the key twice, and the first time, rdesktop simply ungrabs the keyboard. The second time, the window manager receives the event as normal.

Here’s my version of Sunner’s patch, against rdesktop 1.6.0. It removes Alt-Tab support since I don’t need that, and adds Ctrl-Alt-Up and -Down, because I do need those:

--- rdesktop-1.6.0/xkeymap.c	2011-07-06 12:49:01.000000000 +0100
+++ rdesktop-1.6.0-mod/xkeymap.c	2011-07-06 11:40:24.000000000 +0100
@@ -598,6 +598,25 @@
 				ui_seamless_toggle();
 			break;
 
+		case XK_Left:
+		case XK_Right:
+		case XK_Up:
+		case XK_Down:
+			if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
+					&& (get_key_state(state, XK_Control_L)
+						|| get_key_state(state, XK_Control_R)))
+			{
+				/* Ctrl-Alt-Left/Right/Up/Down:
+				 * Ungrab the keyboard so that user can use Windows manager's hot keys */
+				extern RD_BOOL g_fullscreen;
+				if (g_fullscreen) { /* Turn to normal window. Otherwise, rdesktop will be always on top */
+					xwin_toggle_fullscreen();
+				}
+
+				XUngrabKeyboard(g_display, CurrentTime);
+				return True;
+			}
+			break;
 	}
 	return False;
 }

(Download it here: rdesktop-1.6.0-ungrab-on-ctrl-alt-direction.patch)

And as usual here is how to patch your Ubuntu system to include this patch:

sudo apt-get install build-essential fakeroot dpkg-dev
sudo apt-get build-dep rdesktop
mkdir tmp
cd tmp
apt-get source rdesktop
cd rdesktop-*
wget http://www.artificialworlds.net/blog/wp-content/uploads/rdesktop-1.6.0-ungrab-on-ctrl-alt-direction.patch
patch -p1 < rdesktop-1.6.0-ungrab-on-ctrl-alt-direction.patch
dpkg-buildpackage -rfakeroot -b
cd ..
sudo dpkg -i rdesktop*.deb

Now someone just needs to add support for reading your window manager settings to determine automatically what shortcuts you use to switch desktops, and/or support for a config file listing keys that make rdesktop ungrab the keyboard.

Reclaiming desktop space with Ubuntu’s window-picker-applet

For a long time I’ve customised GNOME to have a vertical task bar on the left and launcher buttons across the top. I’ve struggled with a long-standing bug with using a vertical panel, and I’ve sacrificed quite a lot of screen space to make enough room to see the window titles.

Recently I’ve found myself using smaller screens, and finding certain aspects of the Ubuntu Netbook Remix quite good. In particular, I like the combination of Maximus and window-picker-applet, which I combine with GNOME Do. This setup allows me to have almost all of my screen set aside for programs I am using, without feeling lost or inconvenienced.

I need one setting to prevent Maximus from automatically maximising windows – I just want it to remove the title bar when a window is maximised, because window-picker-applet shows the title in my panel instead:

gconftool –type bool –set /apps/maximus/no_maximize true

and then I add Maximus to my Startup Applications (Click Add, give it a name, and set command to “maximus”), and set GNOME Do’s “Start GNOME Do at login” preference (the Preferences screen can be found on the drop-down at the top right of the GNOME Do window).

Now I am happy, except for a little bug fix and visual tweak I want for window-picker-applet. The relevant bugs are Bug #425813 (see my patch at the bottom) and Bug #798197. On an Ubuntu system it’s amazingly easy to use a patched version:

sudo apt-get install build-essential fakeroot dpkg-dev
sudo apt-get build-dep window-picker-applet
mkdir tmp
cd tmp
apt-get source window-picker-applet
cd window-picker-applet-*
wget http://bugs.launchpad.net/ubuntu/+source/window-picker-applet/+bug/798197/+attachment/2171550/+files/show-windows-requring-attention-on-all-workspaces.patch
patch -p1 < show-windows-requring-attention-on-all-workspaces.patch wget http://bugs.launchpad.net/ubuntu/+source/window-picker-applet/+bug/425813/+attachment/2171630/+files/faster-deeper-attention-flash.patch patch -p1 < faster-deeper-attention-flash.patch dpkg-buildpackage -rfakeroot -b cd .. sudo dpkg -i window-picker-applet_*.deb killall gnome-panel

Switching workspace in GNOME via the command line

I use rdesktop to connect to some Windows machines, and it works beautifully. I like to allow it to grab keyboard input so I can switch and close windows on my Windows desktop without fear of accidentally doing something to the rest of my Linux desktop.

However, I have never found a way of letting some keystrokes escape – specifically Ctrl-Alt-Left, Right, Up, Down so that I can switch workspaces (virtual desktops) away from the workspace containing rdesktop.

I have finally found what I hope is a good workaround – I have installed easystroke and defined some mouse gestures I can use to switch desktop. These mouse gestures are not swallowed by rdesktop, so they still work, even when it has focus.

When I asked easystroke to send the Ctrl-Alt-Left etc. keystrokes, they got swallowed by rdesktop, so all I needed to be able to do complete the story was a command-line tool to switch workspace.

That turned out to be trickier than you might imagine, but here is my solution, using the amazing wmctrl.

This should work on GNOME with the metacity window manager, and the standard GNOME workspace switcher. It should be easy to adapt to other window managers and workspace tools.

First, install some tools. On Ubuntu you need:

sudo apt-get install bc wmctrl coreutils grep bash

Now create a file with gedit ~/bin/workspace-switcher & and edit it to look like this:

#!/bin/bash

CMD="$1"

NUM_WORKSPACES=`gconftool-2 --get /apps/metacity/general/num_workspaces`
NUM_COLS=`gconftool-2 --get /apps/panel/applets/workspace_switcher_screen0/prefs/num_rows`

NUM_ROWS=`echo "$NUM_WORKSPACES / $NUM_COLS" | bc`

CURRENT_WS=`wmctrl -d | grep \* | cut -d " " -f 1`

MOVE_LEFT="- $NUM_ROWS"
MOVE_RIGHT="+ $NUM_ROWS"
MOVE_UP="-1"
MOVE_DOWN="+1"

case $CMD in

"Left" )
	NEW_WS=`echo $CURRENT_WS "-" $NUM_ROWS | bc`
	if [[ $NEW_WS -lt 0 ]]; then NEW_WS=$CURRENT_WS; fi
	;;

"Right" )
	NEW_WS=`echo $CURRENT_WS "+" $NUM_ROWS | bc`
	if [[ $NEW_WS -ge $NUM_WORKSPACES ]]; then NEW_WS=$CURRENT_WS; fi
	;;

"Up" )
	WS_COL=`echo $CURRENT_WS "%" $NUM_ROWS | bc`
	if [[ $WS_COL -eq 0 ]]; then
	{
		NEW_WS=$CURRENT_WS
	}
	else
	{
		NEW_WS=`echo $CURRENT_WS "- 1" | bc`
	}; fi
	;;

"Down" )
	NEW_WS=`echo $CURRENT_WS "+ 1" | bc`
	NEW_WS_COL=`echo $NEW_WS "%" $NUM_ROWS | bc`
	if [[ $NEW_WS_COL -eq 0 ]]; then NEW_WS=$CURRENT_WS; fi
	;;

* )
	NEW_WS=$CMD

esac

wmctrl -s $NEW_WS

Make it executable with chmod +x ~/bin/workspace-switcher and make sure ~/bin is in your PATH.

You can run it like this:

switch-workspace Left

to move left – the other possiblities are, obviously, Right, Up and Down.

Or like this:

switch-workspace 3

to move to a workspace by number.

If you want to use it with easystroke, create an action, and for the command simply enter switch-workspace Left and similar as the command.

Easystroke can be installed on Ubuntu like this:

sudo apt-get install easystroke