Opening a fullscreen OpenGL window
Asked Answered
L

2

6

I am tring to open an OpenGL full screen window using GLFW on linux red-hat. I have a desktop that spans two monitors with total resolution of 3840*1080.

I have two problems: 1. The window is opened just on one monitor with maximum window width of 1920 (the width of a single monitor). 2. The maximum height of the window is 1003 (which I think is the height of the screen minus the height of the task bar and the top bar).

This is the code I use to open the window:

if (glfwInit() == GL_FALSE)
    std::cout<< "Unable to initialize GLFW\n";
glfwOpenWindowHint(GLFW_STEREO, GL_FALSE);
if (glfwOpenWindow(3840,1080,8,8,8,0,24,0,GLFW_FULLSCREEN) == GL_FALSE)
    std::cout<< "Unable to open window\n";
int width, height;
glfwGetWindowSize(&width, &height);
std::cout << "width = " << width << " height = " << height << "\n";

output: width = 1920 height = 1003

EDIT: I used xrandr to check available screen mode and got:

Screen 0: minimum 3840 x 1080, current 3840 x 1080, maximum 3840 x 1080 default connected 3840x1080+0+0 0mm x 0mm 3840x1080 50.0*

EDIT2: I have changed my code to open the window using X11

int doubleBufferAttributes[] = {
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE,   GLX_RGBA_BIT,
GLX_DOUBLEBUFFER,  True,  /* Request a double-buffered color buffer with */
GLX_RED_SIZE,      1,     /* the maximum number of bits per component    */
GLX_GREEN_SIZE,    1, 
    GLX_BLUE_SIZE,     1,
    None
};

static Bool WaitForNotify( Display *dpy, XEvent *event, XPointer arg ) {
    return (event->type == MapNotify) && (event->xmap.window == (Window) arg);
}
int main( int argc, char *argv[] )
{
    Display              *dpy;
    Window                xWin;
    XEvent                event;
    XVisualInfo          *vInfo;
    XSetWindowAttributes  swa;
    GLXFBConfig          *fbConfigs;
    GLXContext            context;
    GLXWindow             glxWin;
    int                   swaMask;
    int                   numReturned;
    int                   swapFlag = True;

    /* Open a connection to the X server */

dpy = XOpenDisplay( NULL );
if ( dpy == NULL ) {
    printf( "Unable to open a connection to the X server\n" );
    exit( EXIT_FAILURE );
}

/* Request a suitable framebuffer configuration - try for a double 
** buffered configuration first */
fbConfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy),
                               doubleBufferAttributes, &numReturned );

/* Create an X colormap and window with a visual matching the first
** returned framebuffer config */
vInfo = glXGetVisualFromFBConfig( dpy, fbConfigs[0] );

swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
swa.colormap = XCreateColormap( dpy, RootWindow(dpy, vInfo->screen),
                                vInfo->visual, AllocNone );

swaMask = CWBorderPixel | CWColormap | CWEventMask;

xWin = XCreateWindow( dpy, RootWindow(dpy, vInfo->screen), 0, 0, 3840, 1080,
                      0, vInfo->depth, InputOutput, vInfo->visual,
                      swaMask, &swa );
XWindowAttributes attt;

XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "he = " << attt.height << " wi = " << attt.width << "\n";

/* Create a GLX context for OpenGL rendering */
context = glXCreateNewContext( dpy, fbConfigs[0], GLX_RGBA_TYPE,
             NULL, True );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "2he = " << attt.height << " wi = " << attt.width << "\n";


/* Create a GLX window to associate the frame buffer configuration
** with the created X window */
glxWin = glXCreateWindow( dpy, fbConfigs[0], xWin, NULL );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "3he = " << attt.height << " wi = " << attt.width << "\n";

/* Map the window to the screen, and wait for it to appear */
XMapWindow( dpy, xWin );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "4he = " << attt.height << " wi = " << attt.width << "\n";

XIfEvent( dpy, &event, WaitForNotify, (XPointer) xWin );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "5he = " << attt.height << " wi = " << attt.width << "\n";


/* Bind the GLX context to the Window */
glXMakeContextCurrent( dpy, glxWin, glxWin, context );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "6he = " << attt.height << " wi = " << attt.width << "\n";

the output is:

he = 1080 wi = 3840
2he = 1080 wi = 3840
3he = 1080 wi = 3840
4he = 1080 wi = 3840
5he = 1003 wi = 1920
6he = 1003 wi = 1920

it seems that when the window is get displayed its size shrinks.

Lacerate answered 5/6, 2012 at 12:41 Comment(4)
Have you tried enumerating the available video modes and checking what is available?Lentz
I use GLFW to open the window, so no. I used 'xrandr' to query the video mode: Screen 0: minimum 3840 x 1080, current 3840 x 1080, maximum 3840 x 1080. I am currently changing the code to directly opening the window using X. Can you point me to a function that enumerates available video modes? default connected 3840x1080+0+0 0mm x 0mm 3840x1080 50.0*Lacerate
@NicolBolas please see latest edit of the question.Lacerate
If your window gets resized after creation, then your window manager thinks it knows better than you what to do. In that case I'd just change the WM or file a bug report to the WM developer(s).Sotted
R
20

Don't know about GLFW, perhaps it's buggy, but X11 fullscreen windows don't work like that. Any window manager worth its salt will force the window to fit the (single, non-virtual) screen.

You want to either bypass the window manager completely (use OverrideRedirect window attribute), or ask your WM to cooperate (use window property _NET_WM_STATE_FULLSCREEN). The first approach has numerous drawbacks, so let's use the second one. The following program will display a window on your display, and then toggle it to the full-screen mode:

#include <X11/X.h>
#include <X11/Xlib.h>
#include <strings.h>
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>

int main ()
{
    Display* dis = XOpenDisplay(NULL);
    Window win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 0, 0, 10, 10,
                                     0, BlackPixel (dis, 0), BlackPixel(dis, 0));

    Atom wm_state = XInternAtom(dis, "_NET_WM_STATE", False);
    Atom fullscreen = XInternAtom(dis, "_NET_WM_STATE_FULLSCREEN", False);

    XEvent xev;
    memset(&xev, 0, sizeof(xev));
    xev.type = ClientMessage;
    xev.xclient.window = win;
    xev.xclient.message_type = wm_state;
    xev.xclient.format = 32;
    xev.xclient.data.l[0] = 1;
    xev.xclient.data.l[1] = fullscreen;
    xev.xclient.data.l[2] = 0;

    XMapWindow(dis, win);

    XSendEvent (dis, DefaultRootWindow(dis), False,
                    SubstructureRedirectMask | SubstructureNotifyMask, &xev);

    XFlush(dis);
    /*Sleep 5 seconds before closing.*/
    sleep(5);
    return(0);

}

You probably to use your real screen dimensions for the window from the start, in order to avoid any resize animation effect.

I didn't try this on a multihead system because I don't have one, but on a single display system it works properly (covers the panel, removes window decorations etc). Please let me know if it works for you.

Update They say for multihead to work, you need to use _NET_WM_FULLSCREEN_MONITORS property (see here). It's an array of 4 integers that should be set like this:

    Atom fullmons = XInternAtom(dis, "_NET_WM_FULLSCREEN_MONITORS", False);
    XEvent xev;
    memset(&xev, 0, sizeof(xev));
    xev.type = ClientMessage;
    xev.xclient.window = win;
    xev.xclient.message_type = fullmons;
    xev.xclient.format = 32;
    xev.xclient.data.l[0] = 0; /* your topmost monitor number */
    xev.xclient.data.l[1] = 0; /* bottommost */
    xev.xclient.data.l[2] = 0; /* leftmost */
    xev.xclient.data.l[3] = 1; /* rightmost */
    xev.xclient.data.l[4] = 0; /* source indication */

    XSendEvent (dis, DefaultRootWindow(dis), False,
                    SubstructureRedirectMask | SubstructureNotifyMask, &xev);

With this, you should be able to set your fullscreen windows to occupy a single monitor, the entire desktop, or (for more than 2 monitors) anything in between.

I have not checked this because I don't have a multihead system.

Raynard answered 5/6, 2012 at 15:43 Comment(2)
Thanks for the detailed answer. Before I saw your answer I tried using OverrideRedirect (your first suggested approach). In the end I turned on Xinerama mode in the xorg.conf (a mode that tricks the WM into thinking that there is just one big monitor).Lacerate
Thanks very much, that's the only answer works for me on X11 fullscreen problem, in addition: xev.xclient.data.l[0] = 1; can be changed to =0 for restore or =2 for toggle.Passel
R
0

xcb version:

    xcb_connection_t *xcbConnection = xcb_connect(":0", &screenp);
    xcb_intern_atom_cookie_t type = xcb_intern_atom(xcbConnection, false, strlen("_NET_WM_FULLSCREEN_MONITORS"), "_NET_WM_FULLSCREEN_MONITORS");
    xcb_intern_atom_reply_t *reply_st = xcb_intern_atom_reply(xcbConnection, type, NULL);

    xcb_client_message_event_t event;
    memset(&event, 0, sizeof(event));
    event.response_type = XCB_CLIENT_MESSAGE;
    event.type = reply_st->atom;
    event.window =  this->winId();
    event.format = 32;
    event.data.data32[0] =  0; // top
    event.data.data32[1] =  0; // bottom
    event.data.data32[2] =  0; // left
    event.data.data32[3] =  1; // right

    event.data.data32[4] = 1;
    uint32_t eventMask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT|XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
    xcb_send_event(xcbConnection, false, pScreen0->root, eventMask, reinterpret_cast<const char*>(&event));
    xcb_flush(xcbConnection);
Royroyal answered 19/2, 2021 at 7:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.