Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

X11, Change Resolution and Make Window Fullscreen

I'm pulling my hair out with this one.

I'm changing the resolution of the screen programatically using the following:

int FindBestVideoMode(int screen, unsigned int &width, unsigned int &height)
{
    int modeCount;
    XF86VidModeModeInfo** modes;

    if (XF86VidModeGetAllModeLines(display, screen, &modeCount, &modes))
    {
        int bestMode  = -1;
        int bestMatch = INT_MAX;
        for(int i = 0; i < modeCount; i ++)
        {
            int match = (width  - modes[i]->hdisplay) *
                        (width  - modes[i]->hdisplay) +
                        (height - modes[i]->vdisplay) *
                        (height - modes[i]->vdisplay);

            if(match < bestMatch)
            {
                bestMatch = match;
                bestMode  = i;
            }
        }

        width  = modes[bestMode]->hdisplay;
        height = modes[bestMode]->vdisplay;

        XFree(modes);

        return bestMode;
    }

    return -1;
}

void SwitchVideoMode(int screen, int mode)
{
    if (mode >= 0)
    {
        int modeCount;
        XF86VidModeModeInfo** modes;

        if (XF86VidModeGetAllModeLines(display, screen, &modeCount, &modes))
        {
            if (mode < modeCount)
            {
                XF86VidModeSwitchToMode(display, screen, modes[mode]);
                XF86VidModeSetViewPort(display, screen, 0, 0);


                XFlush(display);
            }

            XFree(modes);
        }
    }
}

void SwitchToBestVideoMode(int screen, unsigned int &width, unsigned int &height)
{
    SwitchVideoMode(screen, FindBestVideoMode(screen, width, height));
}

void RestoreVideoMode(int screen)
{
    auto iVideoMode = DefaultVideoModes.Find(screen);
    if (iVideoMode != nullptr)
    {
        XF86VidModeSwitchToMode(display, screen, &iVideoMode->value);
        XF86VidModeSetViewPort(display, screen, 0, 0);

        XFlush(display);
    }
}

This is working fine. I am then putting the window into fullscreen mode with the following:

XEvent e;
e.xclient.type         = ClientMessage;
e.xclient.window       = window;
e.xclient.message_type = _NET_WM_STATE;
e.xclient.format = 32;
e.xclient.data.l[0] = 2;    // _NET_WM_STATE_TOGGLE
e.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", True);
e.xclient.data.l[2] = 0;    // no second property to toggle
e.xclient.data.l[3] = 1;
e.xclient.data.l[4] = 0;

XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &e);
XMoveResizeWindow(display, window, 0, 0, width, height);

Now the problem is that the window is sized to that of the desktop resolution instead of the new resolution set when doing the programmatic resolution change. What I was expecting, and indeed what I'm after, is for the window to be sized to that of the new resolution.

I expect I'm just misunderstanding something simple here, but any ideas on this is greatly appreciated. I don't want to use external libraries here such SDL.

Thanks!

like image 259
David Reid Avatar asked Dec 07 '25 01:12

David Reid


1 Answers

The problem you're running into is, that you rely on the window manager to properly place your window. Unfortunately not all WMs care about XF86VidMode or RandR. The canonical solution to create a fullscreen window after a video mode change is to create the window as borderless and "override redirect", so that it does not get managed by the WM, and then position it explicitly to cover the area from (0, 0) to (vidmode width, vidmode height).

like image 145
datenwolf Avatar answered Dec 08 '25 13:12

datenwolf