Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opening a fullscreen OpenGL window

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.

like image 405
Tal Darom Avatar asked Jun 05 '12 12:06

Tal Darom


1 Answers

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.

like image 131
n. 1.8e9-where's-my-share m. Avatar answered Sep 28 '22 00:09

n. 1.8e9-where's-my-share m.