17

I am trying to create a Linux application - a screensaver, in this case - and it is proving remarkably difficult to find information on the simple task of making a window full-screen. Even the code of existing screensavers makes no mention of how they manage it, and I've yet to see any obvious function like XRemoveDecoration().

After much fumbling around, I did manage to create a window that's the same size as the desktop, with this:

Window win = DefaultRootWindow(disp);
XWindowAttributes getWinAttr;
XGetWindowAttributes(disp, win, &getWinAttr);
win = XCreateWindow(disp, win, 0, 0, getWinAttr.width, getWinAttr.height, 0, vInfo->depth, InputOutput, vInfo->visual, CWBorderPixel|CWColormap|CWEventMask|CWOverrideRedirect, &winAttr );

But that doesn't do anything to get rid of the titlebar and borders. I know there's a way, obviously - but I have yet to find anything even pointing in that direction that doesn't rely on some other massive library being thrown on top (which existing screensavers are definitely not using).

EDIT: Please don't remove information from my posts. There is a very good reason I explicitly pointed out that existing screensavers aren't using optional libraries, and that is because I have been analyzing source code for most of the past day.

I have chosen the answer that most directly answers the question, and applies to applications in general.

If you have found this question researching xscreensavers... the same still applies. Yes, xscreensaver has its own API - which is complicated, and actually involves writing more lines of code (yes, seriously). If you want OpenGL in your screensaver, you'll need to go through another API (xlockmore, a competing system) and a compatibility layer that translates it to xscreensaver.

However, xscreensaver is capable of running any program that can use virtual root windows (look into vroot.h) as a screensaver. So my advice is to just do that - you'll have more control, no limiting API, and greater portability. (One example I looked at can even compile for Linux or Windows, with the same file!)

DigitalMan
  • 2,440
  • 5
  • 26
  • 32

6 Answers6

13

One way is to bypass the window manager:

XSetWindowAttributes wa;                                                     
wa.override_redirect = True;                                           
XCreateWindow( ..., &wa );
eile
  • 1,153
  • 6
  • 18
  • You may want GrabKeyboard with this to get key events. – eile Jan 30 '12 at 14:52
  • 4
    That... actually works. Trying to trace your steps, I still find practically no resources relating to the use of that toggle, and none of the X Screensavers seem to have it... but by jove, it actually works! – DigitalMan Jan 30 '12 at 15:14
  • It works after adding CWOverrideRedirect flag to 2nd param from last, but bad news is Key stroke is not responding any more after that. – TingQian LI Mar 19 '18 at 06:06
  • 1
    This solution does not work for me. The window stays exactly the same as it used to be. It is possible to resize it and there still is a title bar on the top of it – MinuxLint Aug 02 '20 at 14:06
4

Best and easier way to achieve it is to use the ICCCM Specification atom which will work for most recent Window Managers. Just use the following code:

Atom wm_state   = XInternAtom (display, "_NET_WM_STATE", true );
Atom wm_fullscreen = XInternAtom (display, "_NET_WM_STATE_FULLSCREEN", true );

XChangeProperty(display, window, wm_state, XA_ATOM, 32,
                PropModeReplace, (unsigned char *)&wm_fullscreen, 1);

Your window might be transparent, if so, just use XSetBackground() function where you need it and it's done.

4

The piece of information you lack is, that the screensavers are not responsible for going fullscreen. The screensaver daemon will manage the screensaver window, put it into the dedicated screensaver window layer and make it full screen.

So for writing a screensaver you're in the clear. If you were about writing a fullscreen game, you's have to set the Override Redirect attribute to prevent the window from getting managed by the WM and make it cover the whole screen.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • That seems to be the case in the default xscreensaver modules, yes, but the OpenGL add-ons seem to universally be creating their own windows. – DigitalMan Jan 31 '12 at 04:01
  • 1
    @DigitalMan: Window Creation != Window Management. Effectively the xscreensaver daemon acts like a window manager, but just for the screensaver window. The X-Screensaver extension declares an additional sort-of root window, which is always top of all other windows and the screensaver daemon is responsible for moving the effect program's window there. – datenwolf Jan 31 '12 at 11:18
1

I found freeglut fullscreen works well, even when hosting shader based opengl application inside. Here the internal code that get called (X11 branch...). HTH

#define _NET_WM_STATE_TOGGLE    2
static int fghResizeFullscrToggle(void)
{
    XWindowAttributes attributes;

    if(glutGet(GLUT_FULL_SCREEN)) {
        /* restore original window size */
        SFG_Window *win = fgStructure.CurrentWindow;
        fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
        fgStructure.CurrentWindow->State.Width  = win->State.OldWidth;
        fgStructure.CurrentWindow->State.Height = win->State.OldHeight;

    } else {
        /* resize the window to cover the entire screen */
        XGetWindowAttributes(fgDisplay.Display,
                fgStructure.CurrentWindow->Window.Handle,
                &attributes);

        /*
         * The "x" and "y" members of "attributes" are the window's coordinates
         * relative to its parent, i.e. to the decoration window.
         */
        XMoveResizeWindow(fgDisplay.Display,
                fgStructure.CurrentWindow->Window.Handle,
                -attributes.x,
                -attributes.y,
                fgDisplay.ScreenWidth,
                fgDisplay.ScreenHeight);
    }
    return 0;
}

static int fghEwmhFullscrToggle(void)
{
    XEvent xev;
    long evmask = SubstructureRedirectMask | SubstructureNotifyMask;

    if(!fgDisplay.State || !fgDisplay.StateFullScreen) {
        return -1;
    }

    xev.type = ClientMessage;
    xev.xclient.window = fgStructure.CurrentWindow->Window.Handle;
    xev.xclient.message_type = fgDisplay.State;
    xev.xclient.format = 32;
    xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE;
    xev.xclient.data.l[1] = fgDisplay.StateFullScreen;
    xev.xclient.data.l[2] = 0;  /* no second property to toggle */
    xev.xclient.data.l[3] = 1;  /* source indication: application */
    xev.xclient.data.l[4] = 0;  /* unused */

    if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) {
        return -1;
    }
    return 0;
}

static int fghToggleFullscreen(void)
{
    /* first try the EWMH (_NET_WM_STATE) method ... */
    if(fghEwmhFullscrToggle() != -1) {
        return 0;
    }

    /* fall back to resizing the window */
    if(fghResizeFullscrToggle() != -1) {
        return 0;
    }
    return -1;
}


#endif  /* TARGET_HOST_POSIX_X11 */
CapelliC
  • 59,646
  • 5
  • 47
  • 90
1

Try looking at this for an example:

Really Slick Screensavers Port to GLX http://rss-glx.sourceforge.net/

Look at the createWindow() function in driver.c.

fdk1342
  • 3,274
  • 1
  • 16
  • 17
  • Unfortunately, that doesn't seem much different from what I tried (and lacks the override_redirect that ended up working), and somehow seems to have even less commentary on what's going on than usual. – DigitalMan Jan 30 '12 at 16:14
  • @DigitalMan Read the INSTALL.xscreensaver. Also checkout this FAQ http://www.jwz.org/xscreensaver/faq.html#popup-windows. Like datenwolf posted it sounds like you are creating your own full screen application instead of plugging into the screen saver deamon. – fdk1342 Jan 30 '12 at 21:12
1

It's absolutely not difficult. You just have to add the right atom to the right list as described here.

moongoal
  • 2,847
  • 22
  • 23