From: stormreaver
Written: 2008-05-31 16:58:57.299783
Subject: Setting An X11 Window to Full Screen

One of the best-kept secrets of the X-Window System is how to toggle an existing window between full screen and windowed mode, such as is needed for video games. "Secret" may be too harsh a word since we're talking about Free Software, but the technique is not easy to track down -- even when it's in plain sight in source code such as SDL, Qt, GTK, and others. The underlying code sequence is usually so spread out among source code files that it's extremely difficult to identify unless you already know exactly what you're looking for. This page exists to document the minimum code needed to make an existing window full screen -- no borders, no title bar, no nothing but exclusive use of the video display. I'm not going to present a complete X11 program, as you should already be able to create one of your own before this full screen technique will be of any use to you.

The core of the technique involves simply changing the window hints to tell the window manager to not draw window borders. As this implies, it is a hint to the window manager that it is free to ignore if it so chooses. However, I think all modern window managers respect the hint (KWin does). Changing the hint does indeed get rid of the window borders, but that is only half of what we want. The second half involves changing the resolution of the display so the newly borderless window occupies the entire screen area. I'll cover both of these features below.

An important thing to remember is that the size of your window's client area must be exactly the same as the resolution of the full screen mode you want to set. If they don't match, then you won't get a true full screen display.

Getting Rid of The Borders

The first thing we need to do is get rid of the window borders. This involves setting Motif hints within the window manager. Don't worry if you don't have or use Motif, as it is not required. My understanding is that the window manager hints originated within Motif, and the naming stuck in the general vernacular. The actual code I'm presenting below for setting a borderless window came from the GLUT source code. I've cleaned it up, reduced it to its necessary code, and annotated it to the best of my ability; but I'm no X11 expert, so it's possible that my explanations may not be exactly correct.

First, you need the following structure that will be used later:


typedef struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
} Hints;


I think this structure came from Motif, but I'm not certain. This structure is required by the XChangeProperty() function which is the key to getting rid of the window borders. You also need an Atom (Atoms are declared in X11/Xatom.h). Don't worry if you don't know what an Atom is, as it's not important knowledge in order to get a borderless window.


Hints hints;
Atom property;


Now with those preliminaries out of the way, we can start to get to the core of what we want: a borderless window. You need to set a couple fields in the structure:


hints.flags = 2; // Specify that we're changing the window decorations.
hints.decorations = 0; // 0 (false) means that window decorations should go bye-bye.


Now we need the Atom that identifies the window manager Motif hints. If you've ever looked at the Xlib header files, you may have seen the XA_WM_HINTS atom that seems to indicate the ability to set window manager hints. Whatever it's used for, setting window manager border hints isn't it. We need to use the "_MOTIF_WM_HINTS" atom instead.


property = XInternAtom(display,"_MOTIF_WM_HINTS",True);


The "display" parameter is the X11 Display variable returned from XOpenDisplay, as you may have guessed. If XInternAtom() returns 0, then something went wrong and you should stop here. Otherwise you're ready to get rid of the borders with the following line of code:


XChangeProperty(display,window,property,property,32,PropModeReplace,(unsigned char *)&hints,5);


Again, "display" is your Display variable, while "window" is the Window variable that identifies your already-existing window. If your window manager isn't from the stone age, then that window will now be nothing more than client-area goodness. If it still has borders, check for errors you made entering the code.

Changing The Display Resolution

That's the end of the code I found in GLUT. The second part of a full screen display is something I had to figure out on my own. It amounts to only a few lines of code, though they were some hard-won lines:


XF86VidModeSwitchToMode(display,defaultscreen,video_mode);
XF86VidModeSetViewPort(display,DefaultScreen,0,0);
XMoveResizeWindow(display,window,0,0,width,height);
XMapRaised(display,window);
XGrabPointer(display,window,True,0,GrabModeAsync,GrabModeAsync,window,0L,CurrentTime);
XGrabKeyboard(display,window,False,GrabModeAsync,GrabModeAsync,CurrentTime);


The only part of the above code block that isn't self-explanatory is the "video_mode" variable. This is one of the entries in the array returned by a call to XF86VidModeGetAllModeLines(), something which I'm not going to cover here. Grabbing the pointer and keyboard within the window is necessary to keep the virtual desktop from scrolling, and to make sure that the window has exclusive use of the keyboard and mouse.

There you have it: all the code needed to make an existing window become full screen. While not self-evident, the code isn't complex at all. The technique is just not well documented.
From: jadorecesite
Written: 2020-10-25 19:33:23.176988
This page right here saved me a lot of time.
Your website is gold man gg wp
From: stormreaver
Written: 2021-01-05 21:37:58.211003
Thanks for the kudos. Sorry it took so long to acknowledge this. No one ever registers to comment, so I don't login very often.
From: ssnf
Written: 2022-02-02 15:10:12.944483
Thank you very much for sharing this with us.

Would it be possible to add another method for setting a window
to fullscreen? This method unfortunately does not work with dwm,
my current window manager.

I used the Extended Window Manager Hints specification instead, and
it worked nicely.
(https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html)

The idea is that your client is going to send a message to another
client (the window manager) telling it that you wish to become a
fullscreen window. It is up to the window manager to comply with the
EWMH specification. Or you could go full nuts and use override-redirect
and ignore everything and everyone else, but I don't know how to get it
working properly.

I came up with this function (tried to make it as minimal as possible):

void
setfullscreen(uint i)
{
XEvent ev;
Atom atom;

ev.type = ClientMessage;
ev.xclient.window = win;
ev.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False);
ev.xclient.format = 32;
ev.xclient.data.l[0] = i;
atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
ev.xclient.data.l[1] = atom;
ev.xclient.data.l[2] = atom;
XSendEvent(dpy, root, False, ClientMessage, &ev);
}

Basically, this function sends a message of type _NET_WM_STATE to your
window manager, where data.l[0] is a boolean and data.l[1] OR data.l[2]
specify the _NET_WM_STATE hint that you want to use. In this case, I
used the fullscreen hint, but there are a few other hints for _NET_WM_STATE,
which are specified in the page I linked to up there.

I could have set only data.l[1]. I set data.l[2] just to be safe.
From: stormreaver
Written: 2022-03-15 16:23:32.714659
When I first wrote this article 14 years ago, the technique I wrote about was already considered obsolete. However, I haven't kept up with the changes, so I'm afraid I can't give any specific advise at this time.

My best suggestion at this point, though, is to look at how the Godot game engine puts the Linux version into full screen mode. It uses the modern approach.
You must register an account before you can reply.