X11/GLX - полноэкранный режим?
Я пытаюсь создать приложение для Linux - в данном случае скринсейвер - и очень сложно найти информацию о простой задаче сделать окно полноэкранным. Даже код существующих заставок не упоминает о том, как они управляют этим, и я еще не видел какой-либо очевидной функции, такой как XRemoveDecoration()
,
После долгих раздумий мне удалось создать окно того же размера, что и рабочий стол, с помощью этого:
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 );
Но это ничего не делает, чтобы избавиться от заголовка и границ. Очевидно, я знаю, что есть способ, но мне еще предстоит найти что-то, даже указывающее в этом направлении, которое бы не зависело от какой-то другой массивной библиотеки, которую бросают сверху (которую уже не используют существующие заставки).
РЕДАКТИРОВАТЬ: Пожалуйста, не удаляйте информацию из моих сообщений. Есть очень веская причина, по которой я недвусмысленно указал, что на существующих заставках не используются необязательные библиотеки, и это потому, что я анализировал исходный код большую часть прошедшего дня.
Я выбрал ответ, который наиболее прямо отвечает на вопрос и относится к приложениям в целом.
Если вы нашли этот вопрос, исследуя xscreensavers... то же самое относится и к. Да, у xscreensaver есть собственный API - который сложен и на самом деле включает в себя написание большего количества строк кода (да, серьезно). Если вы хотите использовать OpenGL в своей заставке, вам нужно пройти через другой API (xlockmore, конкурирующая система) и уровень совместимости, который переводит его в xscreensaver.
Тем не менее, xscreensaver способен запускать любую программу, которая может использовать виртуальные корневые окна (смотрите vroot.h) в качестве заставки. Поэтому я советую просто сделать это - у вас будет больше контроля, нет ограничений API и улучшена переносимость. (Один из примеров, который я рассмотрел, может даже скомпилироваться для Linux или Windows с одним и тем же файлом!)
6 ответов
Один из способов - обойти оконный менеджер:
XSetWindowAttributes wa;
wa.override_redirect = True;
XCreateWindow( ..., &wa );
Лучший и более простой способ добиться этого - использовать спецификацию ICCCM atom
который будет работать для самых последних оконных менеджеров. Просто используйте следующий код:
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);
Ваше окно может быть прозрачным, если это так, просто используйте XSetBackground()
Функция, где вам это нужно, и это сделано.
Часть информации, которой вам не хватает, заключается в том, что заставки не несут ответственности за переход в полноэкранный режим. Демон заставки управляет окном заставки, помещает его в выделенный слой окна заставки и делает его полноэкранным.
Так что для написания скринсейвера вы в чистоте. Если вы собирались написать полноэкранную игру, вам нужно установить атрибут Override Redirect, чтобы предотвратить управление окном с помощью WM и сделать так, чтобы оно покрывало весь экран.
Я обнаружил, что полноэкранный режим freeglut хорошо работает, даже если внутри него размещено шейдерное приложение opengl. Вот внутренний код, который вызывается (ветка X11...). НТН
#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 */
Это абсолютно не сложно. Вам просто нужно добавить правильный атом в правильный список, как описано здесь.
Попробуйте посмотреть на это для примера:
Действительно Заставка Портал Заставки для GLX http://rss-glx.sourceforge.net/
Посмотрите на функцию createWindow() в driver.c.