This patch adds MESA_screen_surface support to the egl_glx EGL->GLX
wrapper and egl_xlib Gallium state tracker.

With this patch applied, you should be able to just run eglgears from
an X11 terminal and get a maximized hardware accelerated gears window.

Screen surfaces are window surfaces where the X11 window is created by
the EGL driver. Showing a screen surface calls XMapWindow on it. The
window is automatically made maximized or fullscreen if the size makes
it necessary.
A single screen mode is advertised, which sized by default like the
size of the client area of a maximized window.
The EGL_FULLSCREEN=[WxH[xRATE]] and EGL_WINDOW=WxH options can be used
to force fullscreen or a window with the appropriate dimensions.

It also changes the default EGL driver for X11 to be egl_glx rather
than egl_softpipe, as this gives a good chance of being able to use
hardware acceleration.

The core X11 code is in src/egl/main/eglx11.[ch] and it is called both
by egl_x11 and Gallium egl_xlib.

It uses the WM protocol to determine work area and frame sizes and
(try to) compute the size of a maximized window and xrandr to change
fullscreen mode.

---
 configure.ac                           |    6 +-
 src/egl/drivers/glx/egl_glx.c          |  157 +++++++++-
 src/egl/main/Makefile                  |    6 +-
 src/egl/main/eglconfig.c               |    1 +
 src/egl/main/eglconfigutil.c           |    2 +-
 src/egl/main/egldriver.c               |    2 +-
 src/egl/main/eglsurface.c              |    2 +-
 src/egl/main/eglx11.c                  |  537 ++++++++++++++++++++++++++++++++
 src/egl/main/eglx11.h                  |   21 ++
 src/gallium/winsys/egl_xlib/Makefile   |   13 +-
 src/gallium/winsys/egl_xlib/egl_xlib.c |   95 ++++++-
 11 files changed, 815 insertions(+), 27 deletions(-)
 create mode 100644 src/egl/main/eglx11.c
 create mode 100644 src/egl/main/eglx11.h

diff --git a/configure.ac b/configure.ac
index d83dd43..83b14b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -890,11 +890,11 @@ if test "x$enable_egl" = xyes; then
     SRC_DIRS="$SRC_DIRS egl"

     if test "$x11_pkgconfig" = yes; then
-        PKG_CHECK_MODULES([EGL], [x11])
+        PKG_CHECK_MODULES([EGL], [x11 xrandr])
         EGL_LIB_DEPS="$EGL_LIBS"
     else
         # should check these...
-        EGL_LIB_DEPS="$X_LIBS -lX11"
+        EGL_LIB_DEPS="$X_LIBS -lX11 -lXrandr"
     fi
     EGL_LIB_DEPS="$EGL_LIB_DEPS $DLOPEN_LIBS"
 fi
diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c
index 96292b0..55f99b5 100644
--- a/src/egl/drivers/glx/egl_glx.c
+++ b/src/egl/drivers/glx/egl_glx.c
@@ -33,10 +33,13 @@
  * Authors: Alan Hourihane <al...@tungstengraphics.com>
  */

+#define GLX_GLXEXT_PROTOTYPES
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <X11/Xlib.h>
 #include <GL/glx.h>
+#include <GL/glxext.h>

 #include "eglconfigutil.h"
 #include "eglconfig.h"
@@ -46,6 +49,9 @@
 #include "eglglobals.h"
 #include "egllog.h"
 #include "eglsurface.h"
+#include "eglscreen.h"
+#include "eglmode.h"
+#include "eglx11.h"

 #define CALLOC_STRUCT(T)   (struct T *) calloc(1, sizeof(struct T))
 #define ARRAY_SIZE(a)      (sizeof(a) / sizeof(a[0]))
@@ -67,6 +73,7 @@ struct GLX_egl_driver
    _EGLDriver Base;   /**< base class */
 };

+struct GLX_egl_surface;

 /** driver data of _EGLDisplay */
 struct GLX_egl_display
@@ -91,6 +98,9 @@ struct GLX_egl_display
    EGLBoolean single_buffered_quirk;
    EGLBoolean glx_window_quirk;

+   _EGLX11Screen* x11;
+
+   struct GLX_egl_surface* screen_surface;
 };


@@ -200,7 +210,7 @@ static const struct {

 static EGLBoolean
 convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
-                 struct GLX_egl_config *GLX_conf)
+                 struct GLX_egl_config *GLX_conf, int force_rgba)
 {
    __GLcontextModes mode;
    int err = 0, attr, val, i;
@@ -223,10 +233,17 @@ convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
    if (err)
       return EGL_FALSE;

+   if(force_rgba)
+       mode.renderType = GLX_RGBA_BIT;
+
    /* must have rgba bit */
    if (!(mode.renderType & GLX_RGBA_BIT))
       return EGL_FALSE;

+   /* EGL doesn't support accumulation buffers and we don't want them
as their mode are marked "Slow" */
+   if(mode.accumRedBits || mode.accumGreenBits || mode.accumBlueBits
|| mode.accumAlphaBits)
+          return EGL_FALSE;
+
    /* pixmap and pbuffer surfaces must be single-buffered in EGL */
    if (mode.doubleBufferMode) {
       mode.drawableType &= ~(GLX_PIXMAP_BIT | GLX_PBUFFER_BIT);
@@ -377,7 +394,7 @@ fix_config(struct GLX_egl_display *GLX_dpy, struct
GLX_egl_config *GLX_conf)
    surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
    if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
       /* some GLX impls do not like single-buffered window surface */
-      surface_type &= ~EGL_WINDOW_BIT;
+      surface_type &= ~(EGL_WINDOW_BIT | EGL_SCREEN_BIT_MESA);
       /* pbuffer bit is usually not set */
       if (GLX_dpy->have_pbuffer)
          surface_type |= EGL_PBUFFER_BIT;
@@ -405,23 +422,47 @@ create_configs(_EGLDisplay *dpy, struct
GLX_egl_display *GLX_dpy,
 {
    EGLint num_configs = 0, i;
    EGLint id = 1;
+   int force_rgba = 0;
+   int db;

    if (GLX_dpy->have_fbconfig) {
       GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs);
+
+      if (!num_configs)
+          return EGL_FALSE;
+
+      GLX_dpy->visuals = calloc(sizeof(XVisualInfo), num_configs);
+      for(i = 0; i < num_configs; ++i)
+      {
+           XVisualInfo* vinfo;
+           vinfo = glXGetVisualFromFBConfig(GLX_dpy->dpy,
GLX_dpy->fbconfigs[i]);
+           if(vinfo)
+           {
+               memcpy(GLX_dpy->visuals + i, vinfo, sizeof(XVisualInfo));
+               XFree(vinfo);
+           }
+      }
    }
    else {
       XVisualInfo vinfo_template;
       long mask;
+      XVisualInfo* vinfo;

       vinfo_template.screen = screen;
       mask = VisualScreenMask;
-      GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
+      vinfo = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
                                         &num_configs);
-   }

-   if (!num_configs)
-      return EGL_FALSE;
+      if (!num_configs)
+          return EGL_FALSE;
+
+      GLX_dpy->visuals = malloc(sizeof(XVisualInfo) * num_configs);
+      memcpy(GLX_dpy->visuals, vinfo, sizeof(XVisualInfo) * num_configs);
+      XFree(vinfo);
+   }

+retry:
+  for(db = 1; db >= 0; --db) {
    for (i = 0; i < num_configs; i++) {
       struct GLX_egl_config *GLX_conf, template;
       EGLBoolean ok;
@@ -429,7 +470,7 @@ create_configs(_EGLDisplay *dpy, struct
GLX_egl_display *GLX_dpy,
       memset(&template, 0, sizeof(template));
       _eglInitConfig(&template.Base, id);
       if (GLX_dpy->have_fbconfig)
-         ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template);
+         ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i],
&template, force_rgba);
       else
          ok = convert_visual(GLX_dpy->dpy, &GLX_dpy->visuals[i], &template);
       if (!ok)
@@ -441,6 +482,8 @@ create_configs(_EGLDisplay *dpy, struct
GLX_egl_display *GLX_dpy,
          continue;
       }

+      if(template.double_buffered == db)
+      {
       GLX_conf = CALLOC_STRUCT(GLX_egl_config);
       if (GLX_conf) {
          memcpy(GLX_conf, &template, sizeof(template));
@@ -449,6 +492,15 @@ create_configs(_EGLDisplay *dpy, struct
GLX_egl_display *GLX_dpy,
          _eglAddConfig(dpy, &GLX_conf->Base);
          id++;
       }
+      }
+   }
+  }
+
+   if(id == 1 && !force_rgba)
+   {
+       /* nVidia GLX server + Mesa GLX library mistakenly reports all
FBConfigs as being color-indexed */
+       force_rgba = 1;
+       goto retry;
    }

    return EGL_TRUE;
@@ -558,9 +610,14 @@ GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
       return EGL_FALSE;
    }

+   /* TODO: support other screens */
+   GLX_dpy->x11 = _eglX11AddScreen(disp, GLX_dpy->dpy,
DefaultScreen(GLX_dpy->dpy));
+
    disp->DriverData = (void *) GLX_dpy;
    disp->ClientAPIsMask = GLX_EGL_APIS;

+   disp->Extensions.MESA_screen_surface = EGL_TRUE;
+
    /* we're supporting EGL 1.4 */
    *major = 1;
    *minor = 4;
@@ -580,10 +637,12 @@ GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp)
    _eglCleanupDisplay(disp);

    if (GLX_dpy->visuals)
-      XFree(GLX_dpy->visuals);
+      free(GLX_dpy->visuals);
    if (GLX_dpy->fbconfigs)
       XFree(GLX_dpy->fbconfigs);

+   _eglX11TerminateScreen(GLX_dpy->x11);
+
    if (!disp->NativeDisplay)
       XCloseDisplay(GLX_dpy->dpy);
    free(GLX_dpy);
@@ -841,6 +900,77 @@ GLX_eglCreatePbufferSurface(_EGLDriver *drv,
_EGLDisplay *disp,
    return &GLX_surf->Base;
 }

+static EGLSurface
+GLX_eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay disp,
EGLConfig conf,
+                               const EGLint *attrib_list)
+{
+   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+   struct GLX_egl_surface *GLX_surf;
+   XVisualInfo* vinfo;
+
+   vinfo = &GLX_dpy->visuals[GLX_egl_config_index(conf)];
+   if(!vinfo->visual)
+       return NULL;
+
+   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
+   if (!GLX_surf) {
+      _eglError(EGL_BAD_ALLOC, "eglCreateScreenSurfaceMESA");
+      return NULL;
+   }
+
+   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_SCREEN_BIT_MESA,
+                        conf, attrib_list)) {
+      free(GLX_surf);
+      return NULL;
+   }
+
+   GLX_surf->drawable = _eglX11CreateWindow(GLX_dpy->x11,
&GLX_surf->Base, vinfo);
+
+   if (GLX_dpy->have_1_3 && !GLX_dpy->glx_window_quirk)
+      GLX_surf->glx_drawable =
+         glXCreateWindow(GLX_dpy->dpy,
+                         GLX_dpy->fbconfigs[GLX_egl_config_index(conf)],
+                         GLX_surf->drawable, NULL);
+   else
+      GLX_surf->glx_drawable = GLX_surf->drawable;
+
+   if (!GLX_surf->glx_drawable) {
+      free(GLX_surf);
+      XDestroyWindow(GLX_dpy->dpy, GLX_surf->drawable);
+      return NULL;
+   }
+
+   return &GLX_surf->Base;
+}
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ * Called via eglShowSurfaceMESA().
+ */
+static EGLBoolean
+GLX_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay disp,
+                             EGLScreenMESA screen,
+                             EGLSurface surf, EGLModeMESA m)
+{
+   /* TODO: possibly resize window to support multiple modes */
+   struct GLX_egl_display *GLX_dpy = GLX_egl_display(disp);
+
+   if(GLX_dpy->screen_surface)
+       XUnmapWindow(GLX_dpy->dpy, GLX_dpy->screen_surface->drawable);
+
+   if(surf == EGL_NO_SURFACE)
+          GLX_dpy->screen_surface = 0;
+   else
+   {
+       struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
+       GLX_dpy->screen_surface = GLX_surf;
+       _eglX11MapWindow(GLX_dpy->x11, surf, GLX_surf->drawable);
+   }
+
+   return EGL_TRUE;
+}
+
 static EGLBoolean
 GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
 {
@@ -851,6 +981,7 @@ GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay
*disp, _EGLSurface *surf)
       if (GLX_dpy->have_1_3) {
          switch (surf->Type) {
          case EGL_WINDOW_BIT:
+         case EGL_SCREEN_BIT_MESA:
             if (!GLX_dpy->glx_window_quirk)
                glXDestroyWindow(GLX_dpy->dpy, GLX_surf->glx_drawable);
             break;
@@ -877,6 +1008,14 @@ GLX_eglDestroySurface(_EGLDriver *drv,
_EGLDisplay *disp, _EGLSurface *surf)
             break;
          }
       }
+
+      if(surf->Type == EGL_SCREEN_BIT_MESA)
+      {
+        if(GLX_dpy->screen_surface == GLX_surf)
+               GLX_dpy->screen_surface = 0;
+       XDestroyWindow(GLX_dpy->dpy, GLX_surf->drawable);
+      }
+
       free(surf);
    }

@@ -953,6 +1092,8 @@ _eglMain(const char *args)
    GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
    GLX_drv->Base.API.WaitClient = GLX_eglWaitClient;
    GLX_drv->Base.API.WaitNative = GLX_eglWaitNative;
+   GLX_drv->Base.API.CreateScreenSurfaceMESA = GLX_eglCreateScreenSurfaceMESA;
+   GLX_drv->Base.API.ShowScreenSurfaceMESA = GLX_eglShowScreenSurfaceMESA;

    GLX_drv->Base.Name = "GLX";
    GLX_drv->Base.Unload = GLX_Unload;
diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile
index c951b07..202bf20 100644
--- a/src/egl/main/Makefile
+++ b/src/egl/main/Makefile
@@ -22,7 +22,8 @@ HEADERS = \
        eglmutex.h \
        eglscreen.h \
        eglstring.h \
-       eglsurface.h
+       eglsurface.h \
+       eglx11.h

 SOURCES = \
        eglapi.c \
@@ -38,7 +39,8 @@ SOURCES = \
        eglmode.c \
        eglscreen.c \
        eglstring.c \
-       eglsurface.c
+       eglsurface.c \
+       eglx11.c

 OBJECTS = $(SOURCES:.c=.o)

diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c
index 31d69a7..6580d44 100644
--- a/src/egl/main/eglconfig.c
+++ b/src/egl/main/eglconfig.c
@@ -324,6 +324,7 @@ _eglValidateConfig(const _EGLConfig *conf,
EGLBoolean for_matching)
             mask = EGL_PBUFFER_BIT |
                    EGL_PIXMAP_BIT |
                    EGL_WINDOW_BIT |
+                   EGL_SCREEN_BIT_MESA |
                    EGL_VG_COLORSPACE_LINEAR_BIT |
                    EGL_VG_ALPHA_FORMAT_PRE_BIT |
                    EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
diff --git a/src/egl/main/eglconfigutil.c b/src/egl/main/eglconfigutil.c
index 36e94f0..a421cad 100644
--- a/src/egl/main/eglconfigutil.c
+++ b/src/egl/main/eglconfigutil.c
@@ -76,7 +76,7 @@ _eglConfigFromContextModesRec(_EGLConfig *conf,
const __GLcontextModes *m,

    surface_type = 0;
    if (m->drawableType & GLX_WINDOW_BIT)
-      surface_type |= EGL_WINDOW_BIT;
+      surface_type |= EGL_WINDOW_BIT | EGL_SCREEN_BIT_MESA;
    if (m->drawableType & GLX_PIXMAP_BIT)
       surface_type |= EGL_PIXMAP_BIT;
    if (m->drawableType & GLX_PBUFFER_BIT)
diff --git a/src/egl/main/egldriver.c b/src/egl/main/egldriver.c
index 018b06d..f9f0b43 100644
--- a/src/egl/main/egldriver.c
+++ b/src/egl/main/egldriver.c
@@ -52,7 +52,7 @@ close_library(HMODULE lib)
 #elif defined(_EGL_PLATFORM_X)


-static const char DefaultDriverName[] = "egl_softpipe";
+static const char DefaultDriverName[] = "egl_glx";

 typedef void * lib_handle;

diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c
index 940a1b7..fcee87f 100644
--- a/src/egl/main/eglsurface.c
+++ b/src/egl/main/eglsurface.c
@@ -63,7 +63,7 @@ _eglInitSurface(_EGLDriver *drv, _EGLSurface *surf,
EGLint type,
       break;
    case EGL_SCREEN_BIT_MESA:
       func = "eglCreateScreenSurface";
-      renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */
+      //renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? No! */
       break;
    default:
       _eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
diff --git a/src/egl/main/eglx11.c b/src/egl/main/eglx11.c
new file mode 100644
index 0000000..9e045ed
--- /dev/null
+++ b/src/egl/main/eglx11.c
@@ -0,0 +1,537 @@
+#include <stdlib.h>
+#include <memory.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include "eglx11.h"
+#include "eglscreen.h"
+#include "eglmode.h"
+
+struct _EGLX11Screen
+{
+       Display* dpy;
+       int screen;
+       unsigned width;
+       unsigned height;
+       unsigned work_x;
+       unsigned work_y;
+       unsigned work_width;
+       unsigned work_height;
+       unsigned frame_left;
+       unsigned frame_right;
+       unsigned frame_top;
+       unsigned frame_bottom;
+       unsigned client_width;
+       unsigned client_height;
+       unsigned max_width;
+       unsigned max_height;
+       
+       int def_fullscreen;
+       unsigned def_width;
+       unsigned def_height;
+       unsigned def_rate;
+       
+       int orig_size;
+       int orig_rate;
+};
+
+static int _eglX11GetWorkArea(_EGLX11Screen* x11, CARD32* area)
+{
+       Atom _NET_WORKAREA               = XInternAtom(x11->dpy,
"_NET_WORKAREA", False);
+        Atom type;
+        int format;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+                       
+       if(XGetWindowProperty(x11->dpy, RootWindow(x11->dpy, x11->screen),
_NET_WORKAREA, 0L, 0x7fffffff, False, XA_CARDINAL, &type, &format,
&nitems, &bytes_after, (unsigned char**)&data) == Success)
+       {
+               if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 4) && 
data)
+               {
+                       memcpy(area, data, sizeof(CARD32) * 4);
+                       XFree(data);
+                       return 1;
+               }
+               XFree(data);
+       }
+       return 0;
+}
+
+struct x11_property_notify_criteria
+{
+       Window window;
+       Atom atom;
+};
+       
+static Bool
+x11_property_notify_predicate (Display *xdisplay __attribute__((unused)),
+                           XEvent  *event,
+                           XPointer arg)
+{
+  struct x11_property_notify_criteria *criteria = (struct
x11_property_notify_criteria*)arg;
+
+  if (event->xany.type == PropertyNotify
+      && event->xany.window == criteria->window
+      && event->xproperty.atom == criteria->atom)
+        return True;
+  else
+  return False;
+}
+
+static int _eglX11WaitEventUntil(_EGLX11Screen* x11, struct timeval* deadline)
+{
+       int fd = ConnectionNumber(x11->dpy);
+       struct pollfd pfd;
+       struct timeval now;
+       
+       pfd.fd = fd;
+       pfd.events = POLLIN;
+       pfd.revents = 0;
+       gettimeofday(&now, 0);
+       if(now.tv_sec > deadline->tv_sec)
+               return 0;
+       
+       return poll(&pfd, 1, (int)(deadline->tv_sec - now.tv_sec) * 1000 +
(int)(deadline->tv_usec - now.tv_usec + 999) / 1000);
+}
+
+static int _eglX11SetWindowState(_EGLX11Screen* x11, Window win,
const char* name1, const char* name2)
+{
+        Atom _NET_WM_STATE = XInternAtom(x11->dpy, "_NET_WM_STATE", 0);
+       Atom _NET_WM_STATE_MAXIMIZED_HORZ = name1 ? XInternAtom(x11->dpy,
name1, 0) : 0;
+        Atom _NET_WM_STATE_MAXIMIZED_VERT = name2 ?
XInternAtom(x11->dpy, name2, 0) : 0;
+        XEvent xevent;
+        struct x11_property_notify_criteria criteria;
+        struct timeval deadline;
+
+       criteria.window = win;
+       criteria.atom = _NET_WM_STATE;
+       
+       while(XCheckIfEvent(x11->dpy, &xevent,
x11_property_notify_predicate, (XPointer) &criteria));
+       
+       xevent.xany.type = ClientMessage;
+        xevent.xany.window = win;
+        xevent.xclient.message_type = _NET_WM_STATE;
+        xevent.xclient.format = 32;
+        xevent.xclient.data.l[0] = 1;
+        xevent.xclient.data.l[1] = _NET_WM_STATE_MAXIMIZED_VERT;
+        xevent.xclient.data.l[2] = _NET_WM_STATE_MAXIMIZED_HORZ;
+        xevent.xclient.data.l[3] = 2;
+        xevent.xclient.data.l[4] = 0;
+
+        XSendEvent (x11->dpy, RootWindow(x11->dpy, x11->screen), False,
+                (SubstructureRedirectMask | SubstructureNotifyMask),
+                &xevent);
+
+       gettimeofday(&deadline, 0);
+       ++deadline.tv_sec;
+        while(!XCheckIfEvent(x11->dpy, &xevent,
x11_property_notify_predicate, (XPointer) &criteria))
+        {
+               if(!_eglX11WaitEventUntil(x11, &deadline))
+                       return 0;
+        }
+
+        return 1;
+}
+
+static int _eglX11MaximizeWindow(_EGLX11Screen* x11, Window win)
+{
+       return _eglX11SetWindowState(x11, win,
"_NET_WM_STATE_MAXIMIZED_HORZ", "_NET_WM_STATE_MAXIMIZED_VERT");
+}
+
+static int _eglX11MakeWindowFullscreen(_EGLX11Screen* x11, Window win)
+{
+       return _eglX11SetWindowState(x11, win, "_NET_WM_STATE_FULLSCREEN", 0);
+}
+
+static int _eglX11GetFrameExtents(_EGLX11Screen* x11, CARD32* extents)
+{
+       Atom _NET_REQUEST_FRAME_EXTENTS = XInternAtom(x11->dpy,
"_NET_REQUEST_FRAME_EXTENTS", 0);
+        Atom _NET_FRAME_EXTENTS = XInternAtom(x11->dpy,
"_NET_FRAME_EXTENTS", 0);
+
+        XEvent xevent;
+        Window root = RootWindow(x11->dpy, x11->screen);
+        Window win;
+        XSetWindowAttributes attrs;
+        Atom type;
+        int format;
+        unsigned long nitems, bytes_after;
+        unsigned char *data;
+        int ret = 0;
+        unsigned mask;
+        struct x11_property_notify_criteria criteria;
+
+       attrs.background_pixel = 0;
+       attrs.border_pixel = 0;
+       attrs.colormap = XCreateColormap(x11->dpy, root,
DefaultVisual(x11->dpy, x11->screen), AllocNone);
+       attrs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask
| PropertyChangeMask;
+       attrs.override_redirect = 0;
+       mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask |
CWOverrideRedirect;
+
+       win = XCreateWindow(x11->dpy, root, 0, 0, 64, 64,
+                             0, CopyFromParent, InputOutput,
+                             CopyFromParent, mask, &attrs);
+               
+       if(!win)
+               return 0;
+               
+       criteria.window = win;
+       criteria.atom = _NET_FRAME_EXTENTS;
+       
+        while(XCheckIfEvent(x11->dpy, &xevent,
x11_property_notify_predicate, (XPointer) &criteria));
+       
+        xevent.xclient.type = ClientMessage;
+        xevent.xclient.message_type = _NET_REQUEST_FRAME_EXTENTS;
+        xevent.xclient.display = x11->dpy;
+        xevent.xclient.window = win;
+        xevent.xclient.format = 32;
+        xevent.xclient.data.l[0] = 0;
+        xevent.xclient.data.l[1] = 0;
+        xevent.xclient.data.l[2] = 0;
+        xevent.xclient.data.l[3] = 0;
+        xevent.xclient.data.l[4] = 0;
+
+        XSendEvent (x11->dpy, root, False,
+                (SubstructureRedirectMask | SubstructureNotifyMask),
+                &xevent);
+
+       XFlush(x11->dpy);
+
+        XIfEvent(x11->dpy, &xevent, x11_property_notify_predicate,
(XPointer) &criteria);
+
+        if (XGetWindowProperty(x11->dpy, win, _NET_FRAME_EXTENTS, 0l,
+                sizeof (unsigned long) * 4, False, XA_CARDINAL, &type,
+                &format, &nitems, &bytes_after, &data) == Success)
+        {
+               if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 4)
&& (data))
+               {
+                       memcpy(extents, data, 4 * sizeof(long));
+                       ret = 1;
+               }
+                XFree(data);
+        }
+
+        XDestroyWindow(x11->dpy, win);
+       return ret;
+}
+
+_EGLX11Screen* _eglX11AddScreen(_EGLDisplay *disp, Display* dpy, int screen)
+{
+       _EGLX11Screen* x11;
+        CARD32 data[4];
+       _EGLScreen *scrn;
+       
+       x11 = (_EGLX11Screen*)malloc(sizeof(_EGLX11Screen));
+       x11->dpy = dpy;
+       x11->screen = screen;
+       
+       x11->width = DisplayWidth(x11->dpy, x11->screen);
+       x11->height = DisplayHeight(x11->dpy, x11->screen);
+
+       if(_eglX11GetWorkArea(x11, data))
+       {
+               x11->work_x = data[0];
+               x11->work_y = data[1];
+               x11->work_width = data[2];
+               x11->work_height = data[3];
+       }
+       else
+       {
+               x11->work_x = 0;
+               x11->work_y = 0;
+               x11->work_width = x11->width;
+               x11->work_height = x11->height;
+       }
+       
+       if(_eglX11GetFrameExtents(x11, data))
+       {
+               x11->frame_left = data[0];
+               x11->frame_right = data[1];
+               x11->frame_top = data[2];
+               x11->frame_bottom = data[3];
+       }
+       else
+       {
+               x11->frame_left = 0;
+               x11->frame_right = 0;
+               x11->frame_top = 0;
+               x11->frame_bottom = 0;
+       }
+       
+       x11->client_width = x11->work_width - x11->frame_left - 
x11->frame_right;
+       x11->client_height = x11->work_height - x11->frame_top - 
x11->frame_bottom;
+       
+       // XXX: this is true for my system, but possibly not elsewhere
+       // unfortunately, Metacity doesn't seem to allow to maximize
unmapped windows, so it's not clear how to do this properly
+       x11->max_width = x11->work_width;
+       x11->max_height = x11->work_height - x11->frame_top - 1;
+       
+       x11->orig_size = -1;
+       x11->orig_rate = -1;
+
+       {
+               char* p;
+               
+               x11->def_fullscreen = 0;
+               x11->def_width = 0;
+               x11->def_height = 0;
+               x11->def_rate = 0;
+               
+               if((p = getenv("EGL_WINDOW")))
+               {
+                       int w, h;
+                       
+                       w = strtoul(p, &p, 10);
+                       while(*p && !isdigit(*p))
+                               ++p;
+                       h = strtoul(p, &p, 10);
+                       if(w)
+                               x11->def_width = w;
+                       if(h)
+                               x11->def_height = h;
+               }
+
+               if((p = getenv("EGL_FULLSCREEN")))
+               {
+                       int w, h;
+                       x11->def_fullscreen = 1;
+                       
+                       w = strtoul(p, &p, 10);
+                       while(*p && !isdigit(*p))
+                               ++p;
+                       h = strtoul(p, &p, 10);
+                       while(*p && !isdigit(*p))
+                               ++p;
+                       x11->def_rate = strtoul(p, &p, 10);
+
+                       if(w)
+                               x11->def_width = w;
+                       if(h)
+                               x11->def_height = h;
+               }
+       
+               if(!x11->def_width)
+                       x11->def_width = x11->def_fullscreen ? x11->width : 
x11->max_width;
+
+               if(!x11->def_height)
+                       x11->def_height = x11->def_fullscreen ? x11->height : 
x11->max_height;
+               
+               if(!x11->def_rate)
+               {
+                       XRRScreenConfiguration* rrcfg;
+                       x11->def_rate = 60;
+                       rrcfg = XRRGetScreenInfo(x11->dpy, RootWindow(x11->dpy, 
x11->screen));
+                       if(rrcfg)
+                               x11->def_rate = XRRConfigCurrentRate(rrcfg);
+                       XRRFreeScreenConfigInfo(rrcfg);
+               }
+       }
+               
+       /* Create a screen */
+       scrn = calloc(1, sizeof(*scrn));
+       _eglAddScreen(disp, scrn);
+
+       _eglAddNewMode(scrn, x11->def_width, x11->def_height, x11->def_rate
* 1000, "x11");
+       
+       return x11;
+}
+
+static int _eglX11PlaceWindow(_EGLX11Screen* x11, int* x, int* y,
int* w, int* h)
+{
+       if (!*w || !*h)
+       {
+               if(!*w)
+                       *w = x11->def_width;
+               if (!*h)
+                       *h = x11->def_height;
+       }
+
+       if(!x11->def_fullscreen && *w <= x11->client_width && *h <=
x11->client_height)
+       {
+               *x = x11->work_x + ((int)(x11->client_width - *w) >> 1);
+               *y = x11->work_y + ((int)(x11->client_height - *h) >> 1);
+               return 0;
+       }
+       else if(!x11->def_fullscreen && *w <= x11->max_width && *h <= 
x11->max_height)
+       {
+               *x = x11->work_x + ((int)(x11->max_width - *w) >> 1);
+               *y = x11->work_y + ((int)(x11->max_height - *h) >> 1);
+               return 1;
+       }
+       /*
+       else if(*w <= x11->work_width && *h <= x11->work_height)
+       {
+               *x = x11->work_x + ((int)(x11->work_width - *w) >> 1);
+               *y = x11->work_y + ((int)(x11->work_height - *h) >> 1);
+               return 2;
+       }
+       */
+       else
+       {
+               *x = (int)(x11->width - *w) >> 1;
+               *y = (int)(x11->height - *h) >> 1;
+               return 2;
+       }
+}
+
+Window _eglX11CreateWindow(_EGLX11Screen* x11, _EGLSurface* surf,
XVisualInfo* vinfo)
+{
+   Window win;
+   Window root;
+   XSetWindowAttributes attrs;
+   int x, y;
+   unsigned mask;
+   const char* name;
+
+   _eglX11PlaceWindow(x11, &x, &y, &surf->Width, &surf->Height);
+
+   root = RootWindow(x11->dpy, vinfo->screen);
+
+   attrs.background_pixel = 0;
+   attrs.border_pixel = 0;
+   attrs.colormap = XCreateColormap(x11->dpy, root, vinfo->visual, AllocNone);
+   attrs.event_mask = PropertyChangeMask; //StructureNotifyMask |
ExposureMask | KeyPressMask;
+   attrs.override_redirect = 0;
+
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask |
CWOverrideRedirect;
+#ifdef __GLIBC__
+   name = program_invocation_short_name;
+#else
+   name = "EGL application";
+#endif
+
+   win = XCreateWindow(x11->dpy, root, x, y, surf->Width, surf->Height,
+                              0, vinfo->depth, InputOutput,
+                              vinfo->visual, mask, &attrs);
+
+   {
+      XSizeHints sizehints;
+      sizehints.x = x;
+      sizehints.y = y;
+      sizehints.width  = surf->Width;
+      sizehints.height = surf->Height;
+      sizehints.flags = USSize | USPosition;
+      XSetNormalHints(x11->dpy, win, &sizehints);
+      XSetStandardProperties(x11->dpy, win, name, name,
+                             None, (char **)NULL, 0, &sizehints);
+   }
+
+   return win;
+}
+
+static void _eglX11SetFullScreenMode(_EGLX11Screen* x11, int width,
int height, int rate)
+{
+       XRRScreenConfiguration* rrcfg;
+       Time last_change; // to make Xrandr happy
+       Time cur;
+       XRRScreenSize* sizes;
+       int cur_size;
+       Rotation cur_rot;
+       int cur_rate;
+       int nsizes;
+       int size = -1;
+       int size_area = INT_MAX;
+       
+retry:
+       rrcfg = XRRGetScreenInfo(x11->dpy, RootWindow(x11->dpy, x11->screen));
+       if(!rrcfg)
+               return;
+
+       cur = XRRConfigTimes(rrcfg, &last_change);
+       cur_size = XRRConfigCurrentConfiguration(rrcfg, &cur_rot);
+       cur_rate = XRRConfigCurrentRate(rrcfg);
+       
+       if(width < 0)
+               size = height;
+       else
+       {
+               sizes = XRRConfigSizes(rrcfg, &nsizes);
+               for(int i = 0; i < nsizes; ++i)
+               {
+                       if(x11->def_width <= sizes[i].width && x11->def_height 
<= sizes[i].height)
+                       {
+                               int area = sizes[i].width * sizes[i].height;
+                               if(area < size_area)
+                               {
+                                       size = i;
+                                       size_area = area;
+                               }
+                       }                       
+               }
+       }
+
+       if(size >= 0 && size != cur_size)
+       {
+               Status status = BadValue;
+               status = XRRSetScreenConfigAndRate(x11->dpy, rrcfg,
RootWindow(x11->dpy, x11->screen), size, cur_rot, rate, cur);
+               if(status != Success && status != RRSetConfigInvalidTime)
+                       status = XRRSetScreenConfig(x11->dpy, rrcfg, 
RootWindow(x11->dpy,
x11->screen), size, cur_rot, cur);
+               if(status == RRSetConfigInvalidTime)
+               {
+                       XRRFreeScreenConfigInfo(rrcfg);
+                       goto retry;
+               }
+               if(status == Success)
+               {
+                       if(x11->orig_size < 0)
+                               x11->orig_size = cur_size;
+                       if(x11->orig_rate < 0)
+                               x11->orig_rate = cur_rate;
+               }
+       }
+       XRRFreeScreenConfigInfo(rrcfg);
+}
+
+void _eglX11MapWindow(_EGLX11Screen* x11, _EGLSurface* surf, Window win)
+{
+       int x, y;
+       int type = _eglX11PlaceWindow(x11, &x, &y, &surf->Width, &surf->Height);
+       int res;
+       
+       if(x11->def_fullscreen)
+               _eglX11SetFullScreenMode(x11, surf->Width, surf->Height, 
x11->def_rate);
+       
+       XMapWindow(x11->dpy, win);
+       
+       if(type == 2)
+                res = _eglX11MakeWindowFullscreen(x11, win);
+       else if(type == 1)
+               res = _eglX11MaximizeWindow(x11, win);
+       else
+               res = 1;
+
+       if(!res)
+       {
+               /* the window manager ignored our request */
+               /* but we already promised the maximized size to the 
application */
+               /* so we bypass the window manager */
+               XSetWindowAttributes attrs;
+               attrs.override_redirect = 1;
+               XUnmapWindow(x11->dpy, win);
+               XChangeWindowAttributes(x11->dpy, win, CWOverrideRedirect, 
&attrs);
+               y = x11->work_height - surf->Height;
+               if(y < 0)
+                       y = 0;
+               else
+                       y += x11->work_y;
+               
+               XMoveResizeWindow(x11->dpy, win, x, y, surf->Width, 
surf->Height);
+               XMapWindow(x11->dpy, win);
+       }
+}
+
+void _eglX11TerminateScreen(_EGLX11Screen* x11)
+{
+       if(x11->orig_size >= 0)
+       {
+               _eglX11SetFullScreenMode(x11, -1, x11->orig_size, 
x11->orig_rate);
+               x11->orig_size = -1;
+               x11->orig_rate = -1;
+       }
+       free(x11);
+}
+
diff --git a/src/egl/main/eglx11.h b/src/egl/main/eglx11.h
new file mode 100644
index 0000000..f80e9ee
--- /dev/null
+++ b/src/egl/main/eglx11.h
@@ -0,0 +1,21 @@
+#ifndef EGLX11_INCLUDED
+#define EGLX11_INCLUDED
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "eglconfig.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglsurface.h"
+
+struct _EGLX11Screen;
+typedef struct _EGLX11Screen _EGLX11Screen;
+
+_EGLX11Screen* _eglX11AddScreen(_EGLDisplay *disp, Display* dpy, int screen);
+void _eglX11TerminateScreen(_EGLX11Screen* x11);
+
+Window _eglX11CreateWindow(_EGLX11Screen* x11, _EGLSurface* surf,
XVisualInfo* vinfo);
+void _eglX11MapWindow(_EGLX11Screen* x11, _EGLSurface* surf, Window win);
+
+#endif /* EGLX11_INCLUDED */
diff --git a/src/gallium/winsys/egl_xlib/Makefile
b/src/gallium/winsys/egl_xlib/Makefile
index 3efb7ed..5a50c8b 100644
--- a/src/gallium/winsys/egl_xlib/Makefile
+++ b/src/gallium/winsys/egl_xlib/Makefile
@@ -26,16 +26,9 @@ WINSYS_SOURCES = \
 WINSYS_OBJECTS = $(WINSYS_SOURCES:.c=.o)


-LIBS = \
-       $(GALLIUM_DRIVERS) \
-       $(GALLIUM_AUXILIARIES)
-
-# XXX temporary (should create a separate lib with the GL API funcs and
-# mesa code, as done for ES 1.x, 2.x, OpenVG, etc)
-UNUSED_LIBS = \
-       $(TOP)/src/mesa/libglapi.a \
-       $(TOP)/src/mesa/libmesagallium.a \
-
+LIBS =         $(GALLIUM_AUXILIARIES) \
+       $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
+       $(TOP)/src/mesa/libmesagallium.a

 LOCAL_CFLAGS =

diff --git a/src/gallium/winsys/egl_xlib/egl_xlib.c
b/src/gallium/winsys/egl_xlib/egl_xlib.c
index 599973c..25ca31c 100644
--- a/src/gallium/winsys/egl_xlib/egl_xlib.c
+++ b/src/gallium/winsys/egl_xlib/egl_xlib.c
@@ -53,6 +53,7 @@
 #include "eglglobals.h"
 #include "egllog.h"
 #include "eglsurface.h"
+#include "eglx11.h"

 #include "state_tracker/st_public.h"

@@ -66,6 +67,7 @@ struct xlib_egl_driver
    EGLint apis;
 };

+struct xlib_egl_surface;

 /** driver data of _EGLDisplay */
 struct xlib_egl_display
@@ -74,6 +76,9 @@ struct xlib_egl_display

    struct pipe_winsys *winsys;
    struct pipe_screen *screen;
+
+   _EGLX11Screen* x11;
+   struct xlib_egl_surface* screen_surface;
 };


@@ -190,7 +195,7 @@ create_configs(struct xlib_egl_display *xdpy,
_EGLDisplay *disp)
       SET_CONFIG_ATTRIB(config, EGL_NATIVE_RENDERABLE, EGL_FALSE);
       SET_CONFIG_ATTRIB(config, EGL_CONFORMANT, all_apis);
       SET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE, all_apis);
-      SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
EGL_PBUFFER_BIT);
+      SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
EGL_PBUFFER_BIT | EGL_SCREEN_BIT_MESA);
       SET_CONFIG_ATTRIB(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
       SET_CONFIG_ATTRIB(config, EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);

@@ -243,6 +248,8 @@ xlib_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy,

    create_configs(xdpy, dpy);

+   xdpy->x11 = _eglX11AddScreen(dpy, xdpy->Dpy, DefaultScreen(xdpy->Dpy));
+
    /* we're supporting EGL 1.4 */
    *major = 1;
    *minor = 4;
@@ -259,6 +266,8 @@ xlib_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy)
 {
    struct xlib_egl_display *xdpy = xlib_egl_display(dpy);

+   _eglX11TerminateScreen(xdpy->x11);
+
    _eglReleaseDisplayResources(drv, dpy);
    _eglCleanupDisplay(dpy);

@@ -646,6 +655,88 @@ xlib_eglCreatePbufferSurface(_EGLDriver *drv,
_EGLDisplay *disp, _EGLConfig *con
                                              choose_color_format(&visual),
                                              choose_depth_format(&visual),
                                              choose_stencil_format(&visual),
+/**
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ */
+static _EGLSurface *
+xlib_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *disp,
_EGLConfig *conf,
+                            const EGLint *attrib_list)
+{
+   struct xlib_egl_display *xdpy = xlib_egl_display(disp);
+   struct xlib_egl_surface *surf;
+   __GLcontextModes visual;
+   XVisualInfo vinfo_template;
+   int nvinfo;
+   XVisualInfo* vinfo;
+
+   surf = CALLOC_STRUCT(xlib_egl_surface);
+   if (!surf)
+      return NULL;
+
+   /* Let EGL lib init the common stuff */
+   if (!_eglInitSurface(drv, &surf->Base, EGL_SCREEN_BIT_MESA,
+                        conf, attrib_list)) {
+      free(surf);
+      return NULL;
+   }
+
+   vinfo_template.visualid = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID);
+   vinfo = XGetVisualInfo(xdpy->Dpy, VisualIDMask, &vinfo_template, &nvinfo);
+   if(!vinfo || !nvinfo)
+   {
+          free(surf);
+          return NULL;
+   }
+
+   memcpy(&surf->VisInfo, vinfo, sizeof(*vinfo));
+   XFree(vinfo);
+
+   /*
+    * Now init the Xlib and gallium stuff
+    */
+   surf->Dpy = xdpy->Dpy;  /* The X display */
+   surf->Win = _eglX11CreateWindow(xdpy->x11, &surf->Base, &surf->VisInfo);
+   surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
+   surf->winsys = xdpy->winsys;
+
+   _eglConfigToContextModesRec(conf, &visual);
+   /* Create GL statetracker framebuffer */
+   surf->Framebuffer = st_create_framebuffer(&visual,
+                                             choose_color_format(&visual),
+                                             choose_depth_format(&visual),
+                                             choose_stencil_format(&visual),
+                                             surf->Base.Width,
surf->Base.Height,
+                                             (void *) surf);
+
+   return &surf->Base;
+}
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ * Called via eglShowSurfaceMESA().
+ */
+static EGLBoolean
+xlib_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay disp,
+                             EGLScreenMESA screen,
+                             EGLSurface surf, EGLModeMESA m)
+{
+   struct xlib_egl_display *xdpy = xlib_egl_display(disp);
+
+   if(xdpy->screen_surface)
+       XUnmapWindow(xdpy->Dpy, xdpy->screen_surface->Win);
+
+   if(surf == EGL_NO_SURFACE)
+          xdpy->screen_surface = 0;
+   else
+   {
+       struct xlib_egl_surface *xsurf = lookup_surface(surf);
+       xdpy->screen_surface = xsurf;
+       _eglX11MapWindow(xdpy->x11, surf, xsurf->Win);
+   }
+
+   return EGL_TRUE;
+}
                                              width, height,
                                              (void *) surf);
    st_resize_framebuffer(surf->Framebuffer, width, height);
@@ -842,6 +933,8 @@ _eglMain(const char *args)
    xdrv->Base.API.ReleaseTexImage = xlib_eglReleaseTexImage;
    xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
    xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
+   xdrv->Base.API.CreateScreenSurfaceMESA = xlib_eglCreateScreenSurfaceMESA;
+   xdrv->Base.API.ShowScreenSurfaceMESA = xlib_eglShowScreenSurfaceMESA;

    xdrv->apis = find_supported_apis();
    if (xdrv->apis == 0x0) {
-- 
1.6.3.3

------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev 
_______________________________________________
Mesa3d-dev mailing list
Mesa3d-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to