X11 Fullscreen - howto?


ptitSeb

Serial Porter
Joined
Aug 15, 2012
Messages
9,307
Age
51
Location
France, near Lyon
I'm porting the "Emu EX Plus Alpha" serie of emulator. They are all based on the same GUI (android like) and use GLES. All is working fine except the X11 Windows beneath that is not fullscreen, so taskbar or minimize button are still accessible. I want to avoid that because Context Loss is not handleled by the emu, so I added the code between /*SEB*/ marks


        XSetWindowAttributes attr = { 0 };
        attr.event_mask = event_mask;
        xres=800; yres=480;   //Pandora res
        X11Window win = XCreateWindow(dpy, RootWindow(dpy, screen),
                      0, 0, xres, yres, 0,
                      CopyFromParent, InputOutput,
                      CopyFromParent, CWEventMask,
                      &attr);
        if(!win)
        {
            return 0;
        }
        /*SEB*/
        //Try to switch to fullscreen
        XEvent xev;
        Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
        Atom fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
        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;
        XSendEvent(dpy, RootWindow(dpy, screen), False,
            SubstructureNotifyMask, &xev);
        /*SEB*/


But it doesn't works. Any idea?

Here is the resulting PND for the Atari 2600 Emu.Fixed version will be on the repo.
 
Last edited by a moderator:
Fullscreen X window is tricky to do, you need to wait for various events and set flags at correct time, else it just won't work. Have you thought about just using SDL with SDL_GetWMInfo() to get the window handle?
 
I don't know if I understand the question fully, but if it helps my code is below which creates a full screen window that I draw GLES stuff in. Used for KAMI RETRO.

Code:
int PandoraGraphics::InitialiseX11( int w, int h, bool fullscreen, bool vsync, bool fsaa, bool hideCursor )
{
	Window                  sRootWindow;
	XSetWindowAttributes    sWA;
	unsigned int            ui32Mask;
	int                     i32Depth;
	int						x11Screen;
	XVisualInfo *			x11Visual;
	Colormap				x11Colormap;
	EGLConfig				eglConfig;

	m_Display = XOpenDisplay( ":0" );
	if (!m_Display)
	{
		Pi.Error( EVeryHigh, "Unable to open X display" );
		return false;
	}
	x11Screen = XDefaultScreen( m_Display );

	sRootWindow     = RootWindow(m_Display, x11Screen);
	i32Depth        = DefaultDepth(m_Display, x11Screen);
	x11Visual       = (XVisualInfo *)Pi.Memory.Allocate(
		PI_DEBUG,
		sizeof(XVisualInfo)
	);
	XMatchVisualInfo( m_Display, x11Screen, i32Depth, TrueColor, x11Visual);
	if (!x11Visual)
	{
		Pi.Error( EVeryHigh, "Unable to acquire visual" );
		return false;
	}

	// Colormap of the specified visual type for the display.
	x11Colormap = XCreateColormap( m_Display, sRootWindow, x11Visual->visual, AllocNone );
	sWA.colormap = x11Colormap;

	// List of events to be handled by the application. Add to these for handling other events.
	sWA.event_mask = StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | KeyPressMask | KeyReleaseMask;

	// Display capabilities list.
	ui32Mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap;

	// Creates the X11 window
	m_Window = XCreateWindow( m_Display, RootWindow(m_Display, x11Screen), 0, 0, w, h,
		0, CopyFromParent, InputOutput, CopyFromParent, ui32Mask, &sWA);

	// Make the window viewable and flush the output buffer.
	XMapWindow(m_Display, m_Window);
	XFlush(m_Display);

	// Hide cursor if required.
	if ( hideCursor )
	{
		// Hide pointer by creating an empty cursor
		XColor black = XColor( );
		char buff[ 64 ] = { 0 };
		Pixmap bmp = XCreateBitmapFromData( m_Display, m_Window, buff, 8, 8 );
		Cursor cursor = XCreatePixmapCursor( m_Display, bmp, bmp, &black, &black, 0, 0 );
		XDefineCursor( m_Display, m_Window, cursor );
		XFreeCursor( m_Display, cursor );
		XFreePixmap( m_Display, bmp );

	//	XUndefineCursor( m_Display, m_Window );
	//	XMapRaised( m_Display, m_Window );
	//	XFlush( m_Display );
	}

	// Generate full screen event if required.
	if ( fullscreen )
	{
		XEvent	x11_event;
		Atom	x11_state_atom;
		Atom	x11_fs_atom;

		x11_state_atom	= XInternAtom( m_Display, "_NET_WM_STATE", False );
		x11_fs_atom		= XInternAtom( m_Display, "_NET_WM_STATE_FULLSCREEN", False );

		x11_event.xclient.type			= ClientMessage;
		x11_event.xclient.serial		= 0;
		x11_event.xclient.send_event	= True;
		x11_event.xclient.window		= m_Window;
		x11_event.xclient.message_type	= x11_state_atom;
		x11_event.xclient.format		= 32;
		x11_event.xclient.data.l[ 0 ]	= 1;
		x11_event.xclient.data.l[ 1 ]	= x11_fs_atom;
		x11_event.xclient.data.l[ 2 ]	= 0;

		XSendEvent( m_Display, sRootWindow, False, SubstructureRedirectMask | SubstructureNotifyMask, &x11_event );
	}

	m_EglDisplay = eglGetDisplay( ( NativeDisplayType ) m_Display );

	EGLint iMajorVersion, iMinorVersion;
	if ( ! eglInitialize( m_EglDisplay, &iMajorVersion, &iMinorVersion ) )
	{
		Pi.Error( EVeryHigh, "eglInitialize() failed" );
		return false;
	}

	EGLint pi32ConfigAttribs[5];
	int attrib = 0;
	pi32ConfigAttribs[attrib++] = EGL_SURFACE_TYPE;
	pi32ConfigAttribs[attrib++] = EGL_WINDOW_BIT;
	pi32ConfigAttribs[attrib++] = EGL_NONE;
	if ( fsaa )
	{
		pi32ConfigAttribs[attrib++] = EGL_SAMPLE_BUFFERS, 1;
		pi32ConfigAttribs[attrib++] = EGL_SAMPLES, 4;
	}
	pi32ConfigAttribs[attrib++] = EGL_NONE;


	int iConfigs;
	if (!eglChooseConfig(m_EglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1))
	{
		Pi.Error( EVeryHigh, "eglChooseConfig() failed" );
		return false;
	}

	m_EglSurface = eglCreateWindowSurface(m_EglDisplay, eglConfig, (NativeWindowType)m_Window, NULL);
	if ( ! CheckIfEglSurfaceValid( true ) )
	{
		Pi.Error( EVeryHigh, "eglCreateWindowSurface() failed" );
		return false;
	}

	m_EglContext = eglCreateContext(m_EglDisplay, eglConfig, NULL, NULL);
	if ( ! CheckIfEglContextValid( true ) )
	{
		Pi.Error( EVeryHigh, "eglCreateContext( ) failed" );
		return false;
	}

	eglMakeCurrent(m_EglDisplay, m_EglSurface, m_EglSurface, m_EglContext);
	// TODO: error check.

	if ( vsync )
	{
#ifdef _PANDORA
#else
		eglSwapInterval( m_EglDisplay, 1 );
#endif
	}

	// Find out what size window we actually got.
	XWindowAttributes xWindowAttributes;
	XGetWindowAttributes( m_Display, m_Window, &xWindowAttributes );
	m_Width = xWindowAttributes.width;
	m_Height = xWindowAttributes.height;


	return true;
}
 
Last edited by a moderator:
Yes, that was the answer of my question :) thanks for the code

I had solved my problem, but yes, X11 and Fullscreen are not easly mixed !

Here is the code I ed, for reference

 
X11Window init(Display *dpy, int screen, uint xres, uint yres, bool multisample, long event_mask)

{
logMsg("setting up EGL window");
XSetWindowAttributes attr = { 0 };
attr.event_mask = event_mask;
xres=800; yres=480;   //Pandora full res
X11Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, 0), 0, 0, xres, yres,
           0, BlackPixel (dpy, 0), BlackPixel(dpy, 0));

if(!win)
{
return 0;
}
//Try to switch to fullscreen
XEvent xev;
Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
Atom fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);

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(dpy, win);
XSendEvent (dpy, DefaultRootWindow(dpy), False,                    SubstructureRedirectMask | SubstructureNotifyMask, &xev);
XFlush(dpy);display  =  eglGetDisplay((EGLNativeDisplayType)NULL);

if(display == EGL_NO_DISPLAY)
{
logErr("error getting EGL display");
return 0;
}
if(!eglInitialize(display, nullptr, nullptr))
{
logErr("error initializing EGL");
return 0;
}

eglBindAPI(EGL_OPENGL_API);
const EGLint *attribs = useMaxColorBits ? eglAttrWinMaxRGB : eglAttrWinLowColor;

EGLConfig config;
EGLint configs;
if(!eglChooseConfig(display, attribs, &config, 1, &configs))
{
logErr("error choosing config: 0x%X", (int)eglGetError());
return 0;
}
surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)EGL_DEFAULT_DISPLAY, nullptr);
if(surface == EGL_NO_SURFACE)
{
logErr("error creating window surface: 0x%X", (int)eglGetError());
return 0;
}
EGLint ctxAttr[] = {
EGL_CONTEXT_CLIENT_VERSION, 1,
EGL_NONE
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttr);
if(context == EGL_NO_CONTEXT)
{
logErr("error creating context: 0x%X", (int)eglGetError());
return 0;
}
return win;
}

Expect some new emulators soon on the repo...
 
Last edited by a moderator:
Back
Top