How to create Alt+Tab friendly fullscreen programs (like games) in Linux?
Asked Answered
P

1

7

I want to create an application where I draw on an window, either windowed or fullscreen, where I have the mouse grabbed but without intercepting any WM keyboard shortcuts, like Alt+Tab, and I also need to be notified whenever the user enter/leaves focus.

Common applications like Google Chrome, Firefox or gnome-terminal can handle this just fine (going fullscreen with F11, but still having Alt+Tab), but they do not grab the mouse.

SDL has a notorious poor handling of this use case: SDL_WM_GrabInput grabs the mouse but also intercepts WM shortcuts; and SDL_FULLSCREEN seems to have some sort of automatic grab by itself (don't ask me why).

A solution could be to write code for Alt+Tab myself, but this sucks (and doesn't help for other WM shortcuts, like changing to another workspace).

Another solution is to not call SDL_WM_GrabInput, but instead fake a grab: just hide the mouse pointer (with SDL_ShowCursor) and move it back to the center whenever the user moves. Which is ugly, but in practice works - except of course for SDL_FULLSCREEN, because it grabs automatically (unlike sane implementations). A fullscreen-capable SDL solution is this, but that's still not what I want. I don't want to have hacks to enable and disable grab, I want to grab the mouse but not grab the keyboard.

So I am mad with SDL and want to see alternatives. I would like to use SDL but this is not necessary.

This question seems to point out that what SDL actually does is to use XGrabKeyboard. By reading the man page it's not immediately clear to me whether you can grab the mouse without grabbing the keyboard (I never used Xlib myself).

I know how to make "fake fullscreen" with GTK (that is, of the Alt+Tab friendly, gnome-terminal variety). I imagine that doing this, coupled with mouse hiding and moving it back to the center ("fake grabbing") could do the trick, but this feels like too much duct tape. There must be a simpler way. (Also I don't want to add GTK as a dependency; but I'm also not sure if making raw Xlib calls is a good idea).

What's a good solution for this?

I need a Linux/X11 solution but it would be nice for it to be cross-platform - I know this can be solved smoothly on Windows, so perhaps there is a library that does exactly this. (also, I render with OpenGL but this is irrelevant)

PS: Perhaps I am having a bad understanding of this issue and I'm not asking the right question, so feel free to point out approaches I haven't considered.

Pentup answered 13/2, 2013 at 4:25 Comment(2)
The question I cited, in my opinion, isn't really a duplicate, since I'm not looking specifically for a SDL solution. SDL is merely the library I'm using right now.Pentup
I just saw at Xlib API the XGrabPointer function. So, apparently, Xlib has enough functionality for grabbing only the mouse, without having to grab the keyboard.Pentup
A
5

I have been using Gtk and GtkGLExt for gaming on Linux these days (e.g., my Ludum Dare entries). Here (gtk.c Gist) is my code, I have released it under the FreeBSD license. You can see the code I've commented out for debugging window state changes. I should mention that this is part of a much larger framework which I use for things like Ludum Dare, and I prefer it to SDL precisely for the same reasons that you mention: the resulting applications conform more closely to users' expectations for native applications on their platforms (Linux, OS X, Windows). Needless to say, going this route is a lot of work.

Raw X11 programming, however, is a real mess. I estimate that it would take me a couple weeks of solid programming and reading docs to convert my Gtk code to X11 code; it's just not worth it for me but you may decide differently. (Many hours just to eliminate a dependency that everyone has installed anyway!) The Gtk dependency is not actually that outrageous, it's probably already loaded into memory anyway, and the ABI for 2.x is very stable so it won't hurt binary compatibility.

A big problem with X11 programming for games is that event handling is a total mess. You can't easily poll for events. The Xlib interface is blocking, so you have to use an arcane sequence of function calls to read data, check that there are events pending, and then only read events from the queue if they exist (otherwise your application will block until events appear). The xcb library is alternative to Xlib which is much better all around and supports a non-blocking interface, but it doesn't play well with OpenGL. So you could try to mix the two, or you could just use Gtk.

Let me give you a snippet of the Gtk code for fullscreen:

static void toggle_fullscreen()
{
    if (sg_gtk_status & SG_STATUS_VISIBLE) {
        if (sg_gtk_status & SG_STATUS_FULLSCREEN)
            gtk_window_unfullscreen(sg_window);
        else
            gtk_window_fullscreen(sg_window);
    }
}

Just imagine how much work this would be with the X11 interface: figure out the size of the screen (there might be more than one!), resize the window, change the ordering so that it's on top of everything else, change the decoration, and then respond intelligently when the user switches virtual desktops. Blah! (Actually, this describes how my code works on OS X, but the APIs are much nicer.)

More than that, if you're using X11, you'll have to learn how to react to the user in the expected way. X11 is from the 1980s. Gtk, by comparison, gives your application a swath of appropriate defaults from Gtk's UI designers. UI design is work. And remember: you can mix X11 with Gtk just fine.

The summary: X11 programming is for programmers with lots of spare time.

Notes: The GtkGLExt adds an annoying linker flag, -Wl,--export-dynamic. My build scripts remove the flag from pkg-config's output.

X11 experiences: I think I spent about a week trying to get the whole thing working in X11, and I ended up following lots of dead ends in the process. Learn from my failures.

Anaclitic answered 13/2, 2013 at 4:57 Comment(10)
Hey, a big thank you! I will take a look at your code. I agree that the benefits of simplifying programming quickly outweighs the drawbacks of adding a fat dependency like GTK. I would prefer a small library that does the same thing however. (or to be honest, I would prefer that SDL did this..)Pentup
@darque: I also wish that SDL did this, but I think the unfortunate reality is that SDL 1.2's design is a relic from an earlier era. Maybe SDL 1.3 is better. And SDL is good enough for most people. There's definitely room for a modern replacement to SDL, but since it's 2013 it would have to work well on Android and iOS, which makes the undertaking so much more complicated.Anaclitic
SDL 1.3? Hmm I heard that SDL 2.0 was going to improve this, but I can't find it at Google (except this roadmap that cites improvements on mouse grab without elaborating).Pentup
Anyway there is also the issue on whether you can do any of those WM tricks if you are setting to a different resolution and color depth. I can't say whether you code is setting video mode like SDL_SetVideoMode does. F11-aware programs like Chromium does the WM trick of borderless-and-fill-whole-screen but doesn't set video mode. (but it should work anyway, like, I could set mode by calling xrandr without affecting whether alt+tab works)Pentup
I think for a modern game, it is usually inappropriate to change the video resolution. This is something you did in 2000 because the CPU couldn't push enough pixels, but it's mostly irrelevant in 2013 when everyone has tragically underutilized graphics cards and LCD screens that look ugly when not run at full resolution. My advice is that if you have players with low-end systems from 2005, tell them to change the resolution themselves rather than do it in-game. SDL 1.3 and 2.0 are basically the same thing, but 1.3 will have a compatibility layer for 1.2.Anaclitic
I think the last computer which I needed to adjust the video resolution on was a computer I got in 2001 with a 32 MB GeForce 2. I got it with a beautiful CRT which went to 1600x1200, but could do 800x600@125Hz. "They don't make 'em that way anymore" is an understatement. Your game will probably look better with software scaling anyway, especially since you can still do the menus at full resolution.Anaclitic
I am currently using a netbook. It can run some games but is sluggish with a lot of things. I agree that software scaling is better (if you mean: render to a smaller texture, interpolate it to the screen), mostly because of this annoying problem with LCDs, But in any case.. does this means your solution does not work if I set the video mode?Pentup
The solution does work. You will have to do the xrandr part yourself, I think. I also have a netbook. I have an Asus Eee 1000, from 2008, and I think games should mostly be run at full resolution. The sluggishness on my computer is mostly due to the slow SSD. Run some tests with your game before you decide if you want to waste your time with resolution-changing code.Anaclitic
If FTL doesn't let you change resolution, why should you spend your precious time coding such a feature?Anaclitic
let us continue this discussion in chatPentup

© 2022 - 2024 — McMap. All rights reserved.