Wednesday, June 29, 2011

Forcing fullscreen in Linux for apps that don't support it properly

Following situation: You have an application or game in Linux that you want to run in fullscreen, but the app doesn't support it or not with the flexibility you want.

Simple Case

In the simple case you will have the problem with an application that allows window resize, if that's the case, the solution is a simple:

wmctrl -r ":ACTIVE:" -b toggle,fullscreen

Which will put the currently focused window into fullscreen, i.e. maximize it and get rid of the window borders and title.

Complicated Case

There are of course also applications that don't do window resize properly or not at all, for those the solution is a bit more complicated. First thing we have to do is get rid of the window borders on move the window to 0,0. As the Gnome panel doesn't allow that, just removing the decorations, which can be done with wmctrl, isn't enough, we have to set override redirect, which will take the window out of the window managers hand and thus allow us to position it above the Gnome panel at the top/left of the screen. So how do we do that? A bit of Python and Gtk (raw X11 would of course do as will, but Gtk makes things a little easier):

#! /usr/bin/python
from gtk.gdk import *
import gtk.gdk
import time
import sys

if len(sys.argv) == 2:
w = window_foreign_new(int(sys.argv[1], 16))
w = window_foreign_new((get_default_root_window().property_get("_NET_ACTIVE_WINDOW")[2][0]))

w.set_keep_above(True) # to raise it over the panel
w.move(0, 0)

This script will either take the currently focused window or a window given on the command line and put it in override redirect mode, as well as position it at 0,0. There is also a keep_above() in there so that the panel won't end up behind the Gnome panel.

The script isn't pretty, bug free or finished, it's actually kind of a mess. The flush() stuff is trying to work around the image move() command getting ignored, but doesn't really fix it. And I am not sure why the set_decorations(0) is needed in addition when doing a set_override_redirect(True). But whatever, it kind of works and if it doesn't just run it twice. Once run the currently focused window should be hanging at the top/left of your screen.

Switching the resolution

A window at the top/left screen is of course by itself not very attractive, so the next step is to switch the resolution, that can either be done manually via the XRandr GUI tools or via shell with something like:

xrandr --output DFP2 --mode "640x480"

Exact commands will of course vary from system to system. The fun part is that this also allows multi-monitor setups:

xrandr \
--output DFP2 \
--mode "640x480" \
--panning "640x480+1280+0/0x0+0+0" \
--output CRT1 \
--mode "1280x1024" \
--panning "1280x1024+0+0/0x0+0+0"

This would put the right monitor into 640x480, while keeping the left monitor at its native resolution, thus you can browse the web while playing an old game in Dosbox or whatever.

Other solutions and remaining issues

Another solution to the fullscreen problem is to run a separate Xserver for the game with the right resolution and without a window manager, this allows clean switching between game and desktop, but doesn't allow multi monitor use.

Mouse/keyboard grab is another problem that might be worth some further exploration, some games depend on it, so it might be worthwhile to force it, while other don't let you ungrab the mouse without exiting the game. I haven't really looked into either, but at least for the more popular things like Dosbox, there is generally a keyboard combination to break it (Ctrl-F10). Another problem with grab is that it is often to tight, i.e. commands like Volume Up/Down will get eaten by the app and not make it to the window manager which is quite annoying.

It might also be worth to cleanup the above script into a proper wrapper that can be used around the game executable to make the whole process of override redirect and resolution switch fully automatic. Integration into the window manager would also be nice, to make it a more standard part of the Linux desktop experience, not an dirty hack.

1 comment:

LukeStanley said...

I wanted to do this for Firefox :)
this is my variation: