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!)
One way is to bypass the window manager:
XSetWindowAttributes wa;
wa.override_redirect = True;
XCreateWindow( ..., &wa );
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.
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.
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 */
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.
It's absolutely not difficult. You just have to add the right atom to the right list as described here.
来源:https://stackoverflow.com/questions/9065669/x11-glx-fullscreen-mode