Implement initial Wayland support
authorManuel Bachmann <manuel.bachmann@open.eurogiciel.org>
Sat, 4 Apr 2015 18:43:27 +0000 (18:43 +0000)
committerDiederick Niehorster <dcnieho@gmail.com>
Sat, 4 Apr 2015 18:43:27 +0000 (18:43 +0000)
This commit creates a new "wayland" backend, which can be
activated at configure time with "-DFREEGLUT_WAYLAND=ON".

If done so, it will be used instead of X11 (building both
and doing runtime detection may become possible later).
Please note that if you choose to use GL instead of GLES
(by not specifying "-DFREEGLUT_GLES=ON"), then libX11
will still be pulled as an indirect dependency.

Following features are still WIP :
- menus (not implemented, TODO) ;
- client-side decorations (not implemented, required
  because Wayland shells do not draw title bars nor
  resize grips, TODO) ;
- game mode (code is commented out, depends on WIP
  protocols tested upstream, WAIT FOR UPSTREAM) ;
- window visibility states (code is commented out,
  depends on xdg-shell protocol, TODO).

Signed-off-by: Manuel Bachmann <tarnyko@tarnyko.net>

git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1758 7f0cb862-5218-0410-a997-914c9d46530a

13 files changed:
CMakeLists.txt
src/egl/fg_init_egl.c
src/fg_internal.h
src/wayland/fg_cursor_wl.c [new file with mode: 0644]
src/wayland/fg_ext_wl.c [new file with mode: 0644]
src/wayland/fg_gamemode_wl.c [new file with mode: 0644]
src/wayland/fg_init_wl.c [new file with mode: 0644]
src/wayland/fg_input_devices_wl.c [new file with mode: 0644]
src/wayland/fg_internal_wl.h [new file with mode: 0644]
src/wayland/fg_main_wl.c [new file with mode: 0644]
src/wayland/fg_state_wl.c [new file with mode: 0644]
src/wayland/fg_structure_wl.c [new file with mode: 0644]
src/wayland/fg_window_wl.c [new file with mode: 0644]

index 28f8651..34873c1 100644 (file)
@@ -52,8 +52,10 @@ ENDIF()
 # OpenGL ES support
 OPTION(FREEGLUT_GLES "Use OpenGL ES (requires EGL)" OFF)
 
-# option to build either as "glut" (ON) or "freeglut" (OFF)
 IF(NOT WIN32)
+    # Wayland support
+    OPTION(FREEGLUT_WAYLAND "Use Wayland (no X11)" OFF)
+    # option to build either as "glut" (ON) or "freeglut" (OFF)
     OPTION(FREEGLUT_REPLACE_GLUT "Be a replacement for GLUT" ON)
 ENDIF()
 
@@ -167,36 +169,60 @@ ELSEIF(ANDROID OR BLACKBERRY)
             src/blackberry/fg_window_blackberry.c
         )
     ENDIF()
+
 ELSE()
-    LIST(APPEND FREEGLUT_SRCS
-        src/x11/fg_cursor_x11.c
-        src/x11/fg_ext_x11.c
-        src/x11/fg_gamemode_x11.c
-        src/x11/fg_glutfont_definitions_x11.c
-        src/x11/fg_init_x11.c
-        src/x11/fg_internal_x11.h
-        src/x11/fg_input_devices_x11.c
-        src/x11/fg_joystick_x11.c
-        src/x11/fg_main_x11.c
-        src/x11/fg_menu_x11.c
-        src/x11/fg_spaceball_x11.c
-        src/x11/fg_state_x11.c
-        src/x11/fg_structure_x11.c
-        src/x11/fg_window_x11.c
-        src/x11/fg_xinput_x11.c
-    )
-    IF(NOT(FREEGLUT_GLES))
+    # UNIX (Wayland)
+    IF(FREEGLUT_WAYLAND)
+        LIST(APPEND FREEGLUT_SRCS
+            src/wayland/fg_cursor_wl.c
+            src/wayland/fg_ext_wl.c
+            src/wayland/fg_gamemode_wl.c
+            src/wayland/fg_init_wl.c
+            src/wayland/fg_internal_wl.h
+            src/wayland/fg_input_devices_wl.c
+            src/wayland/fg_main_wl.c
+            src/wayland/fg_state_wl.c
+            src/wayland/fg_structure_wl.c
+            src/wayland/fg_window_wl.c
+            # font, serial port & joystick code are agnostic
+            src/x11/fg_glutfont_definitions_x11.c
+            src/x11/fg_input_devices_x11.c
+            src/x11/fg_joystick_x11.c
+        )
+    # UNIX (X11)
+    ELSE()
         LIST(APPEND FREEGLUT_SRCS
-            src/x11/fg_internal_x11_glx.h
-            src/x11/fg_display_x11_glx.c
-            src/x11/fg_state_x11_glx.c
-            src/x11/fg_state_x11_glx.h
-            src/x11/fg_window_x11_glx.c
-            src/x11/fg_window_x11_glx.h
+            src/x11/fg_cursor_x11.c
+            src/x11/fg_ext_x11.c
+            src/x11/fg_gamemode_x11.c
+            src/x11/fg_glutfont_definitions_x11.c
+            src/x11/fg_init_x11.c
+            src/x11/fg_internal_x11.h
+            src/x11/fg_input_devices_x11.c
+            src/x11/fg_joystick_x11.c
+            src/x11/fg_main_x11.c
+            src/x11/fg_menu_x11.c
+            src/x11/fg_spaceball_x11.c
+            src/x11/fg_state_x11.c
+            src/x11/fg_structure_x11.c
+            src/x11/fg_window_x11.c
+            src/x11/fg_xinput_x11.c
         )
+        IF(NOT(FREEGLUT_GLES))
+            LIST(APPEND FREEGLUT_SRCS
+                src/x11/fg_internal_x11_glx.h
+                src/x11/fg_display_x11_glx.c
+                src/x11/fg_state_x11_glx.c
+                src/x11/fg_state_x11_glx.h
+                src/x11/fg_window_x11_glx.c
+                src/x11/fg_window_x11_glx.h
+            )
+        ENDIF()
     ENDIF()
 ENDIF()
-IF(FREEGLUT_GLES)
+
+# OpenGL ES requires EGL, and so does Wayland
+IF(FREEGLUT_GLES OR FREEGLUT_WAYLAND)
     LIST(APPEND FREEGLUT_SRCS
         src/egl/fg_internal_egl.h
         src/egl/fg_display_egl.c
@@ -226,6 +252,12 @@ ELSE()
   INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR})
 ENDIF()
 
+# For Wayland: compile with -DFREEGLUT_WAYLAND and pull EGL
+IF(FREEGLUT_WAYLAND)
+  ADD_DEFINITIONS(-DFREEGLUT_WAYLAND)
+  LIST(APPEND LIBS wayland-client wayland-cursor wayland-egl EGL xkbcommon)
+ENDIF()
+
 # lib m for math, not needed on windows
 IF (NOT WIN32)
     # For compilation:
@@ -248,14 +280,14 @@ ENDIF()
 
 IF(CMAKE_COMPILER_IS_GNUCC)
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-  IF(NOT(ANDROID OR BLACKBERRY))
+  IF(NOT(ANDROID OR BLACKBERRY OR FREEGLUT_WAYLAND))
     # not setting -ansi as EGL/KHR headers doesn't support it
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic")
   ENDIF()
 ENDIF(CMAKE_COMPILER_IS_GNUCC)
 
 INCLUDE(CheckIncludeFiles)
-IF(UNIX AND NOT(ANDROID OR BLACKBERRY))
+IF(UNIX AND NOT(ANDROID OR BLACKBERRY OR FREEGLUT_WAYLAND))
     FIND_PACKAGE(X11 REQUIRED)
     INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR})
     LIST(APPEND LIBS ${X11_LIBRARIES})
@@ -506,11 +538,17 @@ ELSEIF(FREEGLUT_GLES)
     ELSE()
       SET(PC_LIBS_PRIVATE "-lbps -lslog2 -lscreen -lGLESv2 -lGLESv1_CM -lEGL -lm")
     ENDIF()
+  ELSEIF(FREEGLUT_WAYLAND)
+    SET(PC_LIBS_PRIVATE "-lwayland-client -lwayland-cursor -lwayland-egl -lGLESv2 -lGLESv1_CM -lEGL -lxkbcommon -lm")
   ELSE()
     SET(PC_LIBS_PRIVATE "-lX11 -lXxf86vm -lXrandr -lGLESv2 -lGLESv1_CM -lEGL -lm")
   ENDIF()
 ELSE()
-  SET(PC_LIBS_PRIVATE "-lX11 -lXxf86vm -lXrandr -lGL -lm")
+  IF(FREEGLUT_WAYLAND)
+    SET(PC_LIBS_PRIVATE "-lwayland-client -lwayland-cursor -lwayland-egl -lGL -lxkbcommon -lm")
+  ELSE()
+    SET(PC_LIBS_PRIVATE "-lX11 -lXxf86vm -lXrandr -lGL -lm")
+  ENDIF()
 ENDIF()
 # Client applications need to define FreeGLUT GLES version to
 # bootstrap headers inclusion in freeglut_std.h:
index f0889a6..3c83fb2 100644 (file)
@@ -34,8 +34,13 @@ void fghPlatformInitializeEGL()
 {
   /* CreateDisplay */
   /* Using EGL_DEFAULT_DISPLAY, or a specific native display */
+#ifdef FREEGLUT_WAYLAND
+  fgDisplay.pDisplay.egl.Display = eglGetDisplay(
+              (EGLNativeDisplayType)fgDisplay.pDisplay.display);
+#else
   EGLNativeDisplayType nativeDisplay = EGL_DEFAULT_DISPLAY;
   fgDisplay.pDisplay.egl.Display = eglGetDisplay(nativeDisplay);
+#endif
 
   FREEGLUT_INTERNAL_ERROR_EXIT(fgDisplay.pDisplay.egl.Display != EGL_NO_DISPLAY,
                               "No display available", "fgPlatformInitialize");
index 3f0dc42..8006196 100644 (file)
 #   define  TARGET_HOST_BLACKBERRY  1
 
 #elif defined(__posix__) || defined(__unix__) || defined(__linux__) || defined(__sun)
-#   define  TARGET_HOST_POSIX_X11  1
+#   if defined(FREEGLUT_WAYLAND)
+#      define  TARGET_HOST_POSIX_WAYLAND  1
+#   else
+#      define  TARGET_HOST_POSIX_X11  1
+#   endif
 
 #elif defined(__APPLE__)
 /* This is a placeholder until we get native OSX support ironed out -- JFF 11/18/09 */
 #endif
 
 #ifndef TARGET_HOST_MS_WINDOWS
-#   define  TARGET_HOST_MS_WINDOWS 0
+#   define  TARGET_HOST_MS_WINDOWS     0
 #endif
 
 #ifndef TARGET_HOST_ANDROID
-#   define  TARGET_HOST_ANDROID    0
+#   define  TARGET_HOST_ANDROID        0
 #endif
 
 #ifndef TARGET_HOST_BLACKBERRY
-#   define  TARGET_HOST_BLACKBERRY 0
+#   define  TARGET_HOST_BLACKBERRY     0
+#endif
+
+#ifndef  TARGET_HOST_POSIX_WAYLAND
+#   define  TARGET_HOST_POSIX_WAYLAND  0
 #endif
 
 #ifndef  TARGET_HOST_POSIX_X11
-#   define  TARGET_HOST_POSIX_X11  0
+#   define  TARGET_HOST_POSIX_X11      0
 #endif
 
 #ifndef  TARGET_HOST_MAC_OSX
-#   define  TARGET_HOST_MAC_OSX    0
+#   define  TARGET_HOST_MAC_OSX        0
 #endif
 
 #ifndef  TARGET_HOST_SOLARIS
-#   define  TARGET_HOST_SOLARIS    0
+#   define  TARGET_HOST_SOLARIS        0
 #endif
 
 /* -- FIXED CONFIGURATION LIMITS ------------------------------------------- */
 
-#define  FREEGLUT_MAX_MENUS         3
+#define  FREEGLUT_MAX_MENUS            3
 
 /* These files should be available on every platform. */
 #include <stdio.h>
 #endif
 
 /* Platform-specific includes */
+#if TARGET_HOST_POSIX_WAYLAND
+#include "wayland/fg_internal_wl.h"
+#endif
 #if TARGET_HOST_POSIX_X11
 #include "x11/fg_internal_x11.h"
 #endif
diff --git a/src/wayland/fg_cursor_wl.c b/src/wayland/fg_cursor_wl.c
new file mode 100644 (file)
index 0000000..0543bcc
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * fg_cursor_wl.c
+ *
+ * The Wayland-specific mouse cursor related stuff.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Thur Mar 19, 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+
+/*
+ * Note: The arrangement of the table below depends on the fact that
+ * the "normal" GLUT_CURSOR_* values start a 0 and are consecutive.
+ */ 
+static char* cursorList[] = {
+    "UNSUPPORTED",          /* GLUT_CURSOR_RIGHT_ARROW */
+    "left_ptr",             /* GLUT_CURSOR_LEFT_ARROW */
+    "hand1",                /* GLUT_CURSOR_INFO */
+    "UNSUPPORTED",          /* GLUT_CURSOR_DESTROY */
+    "UNSUPPORTED",          /* GLUT_CURSOR_HELP */
+    "UNSUPPORTED",          /* GLUT_CURSOR_CYCLE */
+    "UNSUPPORTED",          /* GLUT_CURSOR_SPRAY */
+    "watch",                /* GLUT_CURSOR_WAIT */
+    "xterm",                /* GLUT_CURSOR_TEXT */
+    "grabbing",             /* GLUT_CURSOR_CROSSHAIR */
+    "UNSUPPORTED",          /* GLUT_CURSOR_UP_DOWN */
+    "UNSUPPORTED",          /* GLUT_CURSOR_LEFT_RIGHT */
+    "top_side",             /* GLUT_CURSOR_TOP_SIDE */
+    "bottom_side",          /* GLUT_CURSOR_BOTTOM_SIDE */
+    "left_side",            /* GLUT_CURSOR_LEFT_SIDE */
+    "right_side",           /* GLUT_CURSOR_RIGHT_SIDE */
+    "top_left_corner",      /* GLUT_CURSOR_TOP_LEFT_CORNER */
+    "top_right_corner",     /* GLUT_CURSOR_TOP_RIGHT_CORNER */
+    "bottom_right_corner",  /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */
+    "bottom_left_corner"    /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */
+};
+
+void fgPlatformSetCursor ( SFG_Window *window, int cursorID )
+{
+    /*
+     * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows
+     * for this, but if there is a system that easily supports a full-
+     * window (or full-screen) crosshair, we might consider it.
+     */
+    int cursorIDToUse =
+        ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID;
+
+    char* cursor;
+
+    if( ( cursorIDToUse >= 0 ) &&
+        ( cursorIDToUse < sizeof( cursorList ) / sizeof( cursorList[0] ) ) ) {
+
+        cursor = cursorList[cursorIDToUse];
+
+        /* if the type is UNSUPPORTED, fall back to GLUT_CURSOR_LEFT_ARROW */
+        if ( ! strcmp( cursor, "UNSUPPORTED" ) )
+        {
+            fgWarning( "glutSetCursor(): cursor type unsupported under Wayland : %d",
+                       cursorIDToUse );
+            cursor = "left_ptr";
+        }
+    } else {
+        switch( cursorIDToUse )
+        {
+        case GLUT_CURSOR_NONE:
+        case GLUT_CURSOR_INHERIT:
+            cursor = NULL;
+            break;
+
+        default:
+            fgError( "Unknown cursor type: %d", cursorIDToUse );
+            return;
+        }
+    }
+
+    if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) {
+        if( window->Parent )
+          window->Window.pContext.cursor =
+            window->Parent->Window.pContext.cursor;
+    } else {
+        window->Window.pContext.cursor = wl_cursor_theme_get_cursor(
+                                           fgDisplay.pDisplay.cursor_theme,
+                                           cursor );
+        if ( ! window->Window.pContext.cursor )
+          fgError( "Failed to create cursor" );
+    }
+}
+
+
+void fgPlatformWarpPointer ( int x, int y )
+{
+    /* unsupported under Wayland */
+    fgWarning( "glutWarpPointer(): function unsupported under Wayland" );
+}
+
+void fghPlatformGetCursorPos(const SFG_Window *window, GLboolean client, SFG_XYUse *mouse_pos)
+{
+    /* Get current pointer location relative to top-left of client area of window (if client is true and window is not NULL)
+     * We cannot get current pointer location in screen coordinates under Wayland, so inform the user and return -1 is this case
+     */
+
+    if (client && window)
+    {
+        mouse_pos->X = window->State.MouseX;
+        mouse_pos->Y = window->State.MouseY;
+    }
+    else
+    {
+        fgWarning( "glutGetCursorPos(): cannot get screen position under Wayland" );
+        mouse_pos->X = -1;
+        mouse_pos->Y = -1;
+    }
+
+    mouse_pos->Use = GL_TRUE;
+}
+
diff --git a/src/wayland/fg_ext_wl.c b/src/wayland/fg_ext_wl.c
new file mode 100644 (file)
index 0000000..f32f325
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * fg_ext_wl.c
+ *
+ * Wayland-specific functions related to OpenGL extensions.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Wed Mar 25 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+
+GLUTproc fgPlatformGetGLUTProcAddress( const char* procName )
+{
+    /* optimization: quick initial check */
+    if( strncmp( procName, "glut", 4 ) != 0 )
+        return NULL;
+
+#define CHECK_NAME(x) if( strcmp( procName, #x ) == 0) return (GLUTproc)x;
+    CHECK_NAME(glutJoystickFunc);
+    CHECK_NAME(glutForceJoystickFunc);
+    CHECK_NAME(glutGameModeString);
+    CHECK_NAME(glutEnterGameMode);
+    CHECK_NAME(glutLeaveGameMode);
+    CHECK_NAME(glutGameModeGet);
+#undef CHECK_NAME
+
+    return NULL;
+}
+
diff --git a/src/wayland/fg_gamemode_wl.c b/src/wayland/fg_gamemode_wl.c
new file mode 100644 (file)
index 0000000..293cf03
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * fg_gamemode_wl.c
+ *
+ * The game mode handling code.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Sun Mar 23 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+
+/* Pointer locking is a Weston-specific WIP protocol (for now)
+ *
+ * #include "pointer-lock-client-protocol.h"
+ * #include "relative-pointer-client-protocol.h"
+ *
+ * static struct _wl_relative_pointer_manager* relative_pointer_manager;
+ * static struct _wl_pointer_lock* pointer_lock;
+ *
+ * static struct _wl_relative_pointer* relative_pointer;
+ * static struct _wl_locked_pointer* locked_pointer;
+ *
+ *
+ * static void fghRelativeMotion( void* data, struct _wl_relative_pointer
+ *                                pointer, uint32_t time,
+ *                                wl_fixed_t x_w, wl_fixed_t y_w,
+ *                                wl_fixed_t x_noacc, wl_fixed_t y_noacc )
+ * {
+ *     SFG_Window* win = fgStructure.CurrentWindow;
+ *     win->State.MouseX = wl_fixed_to_int( x_w );
+ *     win->State.MouseY = wl_fixed_to_int( y_w );
+ *     INVOKE_WCB( *win, Passive, ( win->State.MouseX,
+ *                                  win->State.MouseY ) );
+ * }
+ * static const struct _wl_relative_pointer_listener
+ *                                fghRelativeListener =
+ * {
+ *   fghRelativeMotion
+ * };
+ *
+ * static void fghLockedLocked( void* data, struct _wl_locked_pointer
+ *                              pointer, uint32_t serial )
+ * {
+ *     fgPlatformRememberState();
+ *     fgPlatformSetCursor( win, GLUT_CURSOR_NONE ):
+ * }
+ * static void fghLockedUnlocked( void* data, struct _wl_locked_pointer
+ *                                pointer )
+ * {
+ *     fgPlatformRestoreState();
+ * }
+ * static const struct _wl_locked_pointer_listener
+ *                                 fghLockedListener =
+ * {
+ *   fghLockedLocked,
+ *   fghLockedUnlocked
+ * };
+ */
+
+
+static struct wl_cursor* saved_cursor;
+
+/*
+ * Remembers the current visual settings, so that
+ * we can change them and restore later...
+ */
+void fgPlatformRememberState( void )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    saved_cursor = win->Window.pContext.cursor;
+}
+
+/*
+ * Restores the previously remembered visual settings
+ */
+void fgPlatformRestoreState( void )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    win->Window.pContext.cursor = saved_cursor;
+}
+
+/*
+ *  * Private function to get the virtual maximum screen extent
+ *   */
+GLvoid fgPlatformGetGameModeVMaxExtent( SFG_Window* window, int* x, int* y )
+{
+    /*
+     * under Wayland, just return the size of the window,
+     * at least until we start messing with the outputs...
+     */
+    *x = window->State.Width;
+    *y = window->State.Height;
+}
+
+/*
+ * Changes the current display mode to match user's settings
+ */
+GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest )
+{
+    /* Such a protocol is being studied in Wayland */
+    return GL_FALSE;
+}
+
+
+void fgPlatformEnterGameMode( void )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    struct wl_region* region;
+
+    region = wl_compositor_create_region (
+                                 fgDisplay.pDisplay.compositor );
+    wl_region_add( region, 0, 0,
+                   win->State.Width,
+                   win->State.Height );
+   /*
+    * relative_pointer =
+    *      _wl_relative_pointer_manager_get_relative_pointer (
+    *                relative_pointer_manager,
+    *                fgDisplay.pDisplay.seat );
+    * _wl_relative_pointer_add_listener( relative_pointer,
+    *                                    &fghRelativeListener,
+    *                                    NULL );
+    * locked_pointer = _wl_pointer_lock_lock_pointer (
+    *                             pointer_lock,
+    *                             win->Window.pContext.surface,
+    *                             fgDisplay.pDisplay.seat,
+    *                             NULL);
+    * _wl_locked_pointer_add_listener( locked_pointer,
+    *                                  &fghLockedListener,
+    *                                  NULL );
+    */
+    wl_region_destroy( region );
+}
+
+void fgPlatformLeaveGameMode( void )
+{
+   /* 
+    * _wl_locked_pointer_destroy( locked_pointer );
+    * _wl_relative_pointer_release( relative_pointer );
+    */
+}
+
diff --git a/src/wayland/fg_init_wl.c b/src/wayland/fg_init_wl.c
new file mode 100644 (file)
index 0000000..7b7cd6a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * fg_init_wl.c
+ *
+ * Various freeglut Wayland initialization functions.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Tue Mar 17, 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define FREEGLUT_BUILDING_LIB
+#include <string.h>
+#include <GL/freeglut.h>
+#include "fg_internal.h"
+#include "egl/fg_init_egl.h"
+
+void fgPlatformInitialiseInputDevices( void );
+void fgPlatformCloseInputDevices( void );
+
+
+static void fghRegistryGlobal( void* data,
+                               struct wl_registry* registry,
+                               uint32_t id,
+                               const char* interface,
+                               uint32_t version )
+{
+    SFG_PlatformDisplay* pDisplay = data;
+
+    if ( ! strcmp( interface, "wl_compositor" ) )
+      pDisplay->compositor = wl_registry_bind ( registry, id,
+                                                &wl_compositor_interface, 1 );
+    else if ( ! strcmp( interface, "wl_shell" ) )
+      pDisplay->shell = wl_registry_bind ( registry, id,
+                                           &wl_shell_interface, 1 );
+    else if ( ! strcmp( interface, "wl_seat" ) )
+      pDisplay->seat = wl_registry_bind ( registry, id,
+                                          &wl_seat_interface, 1 );
+    else if ( ! strcmp( interface, "wl_shm" ) )
+      pDisplay->shm = wl_registry_bind ( registry, id,
+                                         &wl_shm_interface, 1 );
+}
+static void fghRegistryGlobalRemove( void* data,
+                                     struct wl_registry* registry,
+                                     uint32_t id )
+{
+}
+static const struct wl_registry_listener fghRegistryListener =
+{
+    fghRegistryGlobal,
+    fghRegistryGlobalRemove
+};
+
+
+static void fghInitialiseCursorTheme(void)
+{
+    fgDisplay.pDisplay.cursor_theme = wl_cursor_theme_load (
+                                        "default", 32,
+                                        fgDisplay.pDisplay.shm );
+};
+
+void fgPlatformInitialize( const char* displayName )
+{
+    fgDisplay.pDisplay.display = wl_display_connect( NULL );
+
+    if( fgDisplay.pDisplay.display == NULL )
+        fgError( "failed to connect to a Wayland compositor" );
+
+    fgDisplay.pDisplay.registry = wl_display_get_registry(
+                                    fgDisplay.pDisplay.display );
+    wl_registry_add_listener( fgDisplay.pDisplay.registry,
+                              &fghRegistryListener,
+                              &fgDisplay.pDisplay );
+    wl_display_roundtrip( fgDisplay.pDisplay.display );
+
+    if( fgDisplay.pDisplay.compositor == NULL ||
+        fgDisplay.pDisplay.shell == NULL ||
+        fgDisplay.pDisplay.seat == NULL ||
+        fgDisplay.pDisplay.shm == NULL )
+          fgError( "failed to discover all needed compositor interfaces" );
+
+    fghInitialiseCursorTheme();
+
+    fghPlatformInitializeEGL();
+
+    /* Get start time */
+    fgState.Time = fgSystemTime();
+
+    fgState.Initialised = GL_TRUE;
+
+    atexit(fgDeinitialize);
+
+    /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */
+    fgPlatformInitialiseInputDevices();
+}
+
+
+void fgPlatformDeinitialiseInputDevices ( void )
+{
+    fgPlatformCloseInputDevices();
+
+    fgState.InputDevsInitialised = GL_FALSE;
+}
+
+
+void fgPlatformCloseDisplay ( void )
+{
+    wl_cursor_theme_destroy( fgDisplay.pDisplay.cursor_theme );
+
+    wl_shm_destroy( fgDisplay.pDisplay.shm );
+    wl_seat_destroy( fgDisplay.pDisplay.seat );
+    wl_shell_destroy( fgDisplay.pDisplay.shell );
+    wl_compositor_destroy( fgDisplay.pDisplay.compositor );
+    wl_registry_destroy( fgDisplay.pDisplay.registry );
+
+    wl_display_disconnect( fgDisplay.pDisplay.display );
+}
+
diff --git a/src/wayland/fg_input_devices_wl.c b/src/wayland/fg_input_devices_wl.c
new file mode 100644 (file)
index 0000000..0aaa91e
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * fg_input_devices_wl.c
+ *
+ * Handles Wayland input devices : keyboard, pointer, touchscreen.
+ *
+ * Written by Manuel Bachmann <tarnyko@tarnyko.net> 2015
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Creation date: Thur Mar 19 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __linux__
+#include <linux/input.h>
+#else
+#define BTN_LEFT    0x110
+#define BTN_RIGHT   0x111
+#define BTN_MIDDLE  0x112
+#endif
+#include <sys/mman.h>
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+
+/*
+ * This function will effectively set the pointer (mouse) cursor
+ * depending on the GLUT_CURSOR_* choice.
+ */
+void fghPointerSetCursor( SFG_Window* window,
+                          struct wl_pointer* pointer,
+                          uint32_t serial )
+{
+    struct wl_cursor_image* image;
+    struct wl_buffer* buffer;
+
+    image = window->Window.pContext.cursor->images[0];
+    buffer = wl_cursor_image_get_buffer( image );
+
+    wl_surface_attach( window->Window.pContext.cursor_surface, buffer,
+                       0, 0 );
+    wl_surface_damage( window->Window.pContext.cursor_surface, 0, 0,
+                       image->width, image->height );
+    wl_surface_commit( window->Window.pContext.cursor_surface );
+
+    wl_pointer_set_cursor( pointer, serial,
+                           window->Window.pContext.cursor_surface,
+                           image->hotspot_x, image->hotspot_y );
+}
+
+/*
+ * This function will interpret a keyboard keysym, and call the
+ * possible callbacks accordingly.
+ */
+void fghKeyboardInterpretKeysym(  SFG_Window* window,
+                                  uint32_t key,
+                                  xkb_keysym_t sym,
+                                  uint32_t state )
+{
+    FGCBKeyboard keyboard_cb;
+    FGCBSpecial special_cb;
+    char string[16];
+    int special = -1;
+
+    /* GLUT API tells us to have two separate callbacks, one for
+     * the ASCII translateable keypresses, and one for all the
+     * others, which need to be translated to GLUT_KEY_Xs... */
+    if( state )
+    {
+        keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
+        special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, Special  ));
+    }
+    else
+    {
+        keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
+        special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp  ));
+    }
+
+    switch( sym )
+    {
+    case XKB_KEY_F1:        special = GLUT_KEY_F1;        break;
+    case XKB_KEY_F2:        special = GLUT_KEY_F2;        break;
+    case XKB_KEY_F3:        special = GLUT_KEY_F3;        break;
+    case XKB_KEY_F4:        special = GLUT_KEY_F4;        break;
+    case XKB_KEY_F5:        special = GLUT_KEY_F5;        break;
+    case XKB_KEY_F6:        special = GLUT_KEY_F6;        break;
+    case XKB_KEY_F7:        special = GLUT_KEY_F7;        break;
+    case XKB_KEY_F8:        special = GLUT_KEY_F8;        break;
+    case XKB_KEY_F9:        special = GLUT_KEY_F9;        break;
+    case XKB_KEY_F10:       special = GLUT_KEY_F10;       break;
+    case XKB_KEY_F11:       special = GLUT_KEY_F11;       break;
+    case XKB_KEY_F12:       special = GLUT_KEY_F12;       break;
+    case XKB_KEY_Left:      special = GLUT_KEY_LEFT;      break;
+    case XKB_KEY_Right:     special = GLUT_KEY_RIGHT;     break;
+    case XKB_KEY_Up:        special = GLUT_KEY_UP;        break;
+    case XKB_KEY_Down:      special = GLUT_KEY_DOWN;      break;
+    case XKB_KEY_Page_Up:   special = GLUT_KEY_PAGE_UP;   break;
+    case XKB_KEY_Page_Down: special = GLUT_KEY_PAGE_DOWN; break;
+    case XKB_KEY_Home:      special = GLUT_KEY_HOME;      break;
+    case XKB_KEY_End:       special = GLUT_KEY_END;       break;
+    case XKB_KEY_Insert:    special = GLUT_KEY_INSERT;    break;
+    case XKB_KEY_Num_Lock:  special = GLUT_KEY_NUM_LOCK;  break;
+    case XKB_KEY_Begin:     special = GLUT_KEY_BEGIN;     break;
+    case XKB_KEY_Delete:    special = GLUT_KEY_DELETE;    break;
+    case XKB_KEY_Shift_L:   special = GLUT_KEY_SHIFT_L;   break;
+    case XKB_KEY_Shift_R:   special = GLUT_KEY_SHIFT_R;   break;
+    case XKB_KEY_Control_L: special = GLUT_KEY_CTRL_L;    break;
+    case XKB_KEY_Control_R: special = GLUT_KEY_CTRL_R;    break;
+    case XKB_KEY_Alt_L:     special = GLUT_KEY_ALT_L;     break;
+    case XKB_KEY_Alt_R:     special = GLUT_KEY_ALT_R;     break;
+    }
+
+    if( special_cb && (special != -1) )
+    {
+        fgSetWindow( window );
+        special_cb( special, window->State.MouseX, window->State.MouseY );
+    }
+    else if( keyboard_cb && (special == -1) )
+    {
+        fgSetWindow( window );
+        xkb_keysym_to_utf8( sym, string, sizeof( string ) );
+        keyboard_cb( string[0], window->State.MouseX, window->State.MouseY );
+    }
+}
+
+
+/*
+ * Touchscreen section
+ * For now, let us pretend it is a mouse with only one button
+ */
+static void fghTouchDown( void* data, struct wl_touch* touch,
+                          uint32_t serial, uint32_t time,
+                          struct wl_surface* surface,
+                          int32_t id,
+                          wl_fixed_t x_w, wl_fixed_t y_w )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    win->State.MouseX = wl_fixed_to_int( x_w );
+    win->State.MouseY = wl_fixed_to_int( y_w );
+    INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
+                               GLUT_DOWN,
+                               win->State.MouseX,
+                               win->State.MouseY ) );
+}
+static void fghTouchUp( void* data, struct wl_touch* touch,
+                        uint32_t serial, uint32_t time,
+                        int32_t id )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    INVOKE_WCB( *win, Mouse, ( GLUT_LEFT_BUTTON,
+                               GLUT_UP,
+                               win->State.MouseX,
+                               win->State.MouseY ) );
+}
+static void fghTouchMotion( void* data, struct wl_touch* touch,
+                            uint32_t time, int32_t id,
+                            wl_fixed_t x_w, wl_fixed_t y_w )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    win->State.MouseX = wl_fixed_to_int( x_w );
+    win->State.MouseY = wl_fixed_to_int( y_w );
+    INVOKE_WCB( *win, Motion, ( win->State.MouseX,
+                                win->State.MouseY ) );
+}
+static void fghTouchFrame( void* data, struct wl_touch* touch )
+{
+}
+static void fghTouchCancel( void* data, struct wl_touch* touch )
+{
+}
+static const struct wl_touch_listener fghTouchListener =
+{
+       fghTouchDown,
+       fghTouchUp,
+       fghTouchMotion,
+       fghTouchFrame,
+       fghTouchCancel
+};
+
+
+/*
+ * Pointer (mouse) section
+ */
+static void fghPointerEnter( void* data, struct wl_pointer* pointer,
+                             uint32_t serial,
+                             struct wl_surface* surface,
+                             wl_fixed_t x_w, wl_fixed_t y_w )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    fghPointerSetCursor( win, pointer, serial );
+    win->State.MouseX = wl_fixed_to_int( x_w );
+    win->State.MouseY = wl_fixed_to_int( y_w );
+    INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
+}
+static void fghPointerLeave( void* data, struct wl_pointer* pointer,
+                             uint32_t serial,
+                             struct wl_surface* surface )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
+}
+static void fghPointerMotion( void* data, struct wl_pointer* pointer,
+                              uint32_t time,
+                              wl_fixed_t x_w, wl_fixed_t y_w )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    win->State.MouseX = wl_fixed_to_int( x_w );
+    win->State.MouseY = wl_fixed_to_int( y_w );
+
+    if ( win->Window.pContext.pointer_button_pressed )
+      INVOKE_WCB( *win, Motion, ( win->State.MouseX,
+                                  win->State.MouseY ) );
+    else
+      INVOKE_WCB( *win, Passive, ( win->State.MouseX,
+                                   win->State.MouseY ) );
+}
+static void fghPointerButton( void* data, struct wl_pointer* pointer,
+                              uint32_t serial, uint32_t time,
+                              uint32_t button, uint32_t state )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    int button_f;
+
+    switch( button )
+    {
+    case BTN_LEFT:
+        button_f = GLUT_LEFT_BUTTON;
+        break;
+    case BTN_RIGHT:
+        button_f = GLUT_RIGHT_BUTTON;
+        break;
+    case BTN_MIDDLE:
+        button_f = GLUT_MIDDLE_BUTTON;
+        break;
+    }
+
+    win->Window.pContext.pointer_button_pressed =
+      state ? GL_TRUE : GL_FALSE;
+
+    INVOKE_WCB( *win, Mouse, ( button_f,
+                               state ? GLUT_DOWN : GLUT_UP ,
+                               win->State.MouseX,
+                               win->State.MouseY ) );
+}
+static void fghPointerAxis( void* data, struct wl_pointer* pointer,
+                            uint32_t time, uint32_t axis,
+                            wl_fixed_t value )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    int direction = wl_fixed_to_int( value );
+
+    INVOKE_WCB( *win, MouseWheel, ( 0,
+                                    direction ,
+                                    win->State.MouseX,
+                                    win->State.MouseY ) );
+}
+static const struct wl_pointer_listener fghPointerListener =
+{
+       fghPointerEnter,
+       fghPointerLeave,
+       fghPointerMotion,
+       fghPointerButton,
+       fghPointerAxis
+};
+
+
+/*
+ * Keyboard section
+ */
+static void fghKeyboardKeymap( void* data, struct wl_keyboard* keyboard,
+                               uint32_t format, int fd, uint32_t size )
+{
+    SFG_PlatformDisplay* pDisplay = data;
+    char* keymap_str;
+    struct xkb_keymap* keymap;
+
+    keymap_str = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 );
+    keymap = xkb_keymap_new_from_string( pDisplay->xkb_context,
+                                         keymap_str,
+                                         XKB_KEYMAP_FORMAT_TEXT_V1,
+                                         0 );
+    munmap( keymap_str, size );
+
+    if( pDisplay->xkb_state )
+      xkb_state_unref( pDisplay->xkb_state );
+    pDisplay->xkb_state = xkb_state_new( keymap );
+}
+static void fghKeyboardEnter( void* data, struct wl_keyboard* keyboard,
+                              uint32_t serial, struct wl_surface* surface,
+                              struct wl_array* keys )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    INVOKE_WCB( *win, Entry, ( GLUT_ENTERED ) );
+}
+static void fghKeyboardLeave( void* data, struct wl_keyboard* keyboard,
+                              uint32_t serial, struct wl_surface* surface )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    INVOKE_WCB( *win, Entry, ( GLUT_LEFT ) );
+}
+static void fghKeyboardKey( void* data, struct wl_keyboard* keyboard,
+                            uint32_t serial, uint32_t time,
+                            uint32_t key, uint32_t state )
+{
+    SFG_PlatformDisplay* pDisplay = data;
+    SFG_Window* win = fgStructure.CurrentWindow;
+    const xkb_keysym_t* syms;
+
+    xkb_state_key_get_syms( pDisplay->xkb_state,
+                            key + 8, &syms );
+    fghKeyboardInterpretKeysym( win, key, syms[0], state );
+}
+static void fghKeyboardModifiers( void* data, struct wl_keyboard* keyboard,
+                                  uint32_t serial, uint32_t mods_depr,
+                                  uint32_t mods_latch, uint32_t mods_lock,
+                                  uint32_t group )
+{
+}
+static const struct wl_keyboard_listener fghKeyboardListener =
+{
+        fghKeyboardKeymap,
+       fghKeyboardEnter,
+       fghKeyboardLeave,
+       fghKeyboardKey,
+       fghKeyboardModifiers
+};
+
+
+/*
+ * Discover potential input device(s) (keyboard, pointer, touch)
+ */
+static void fghSeatCapabilities( void* data,
+                                 struct wl_seat* seat,
+                                 enum wl_seat_capability capabilities )
+{
+    SFG_PlatformDisplay* pDisplay = data;
+
+    if( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
+    {
+        pDisplay->xkb_context = xkb_context_new ( 0 );
+        pDisplay->keyboard = wl_seat_get_keyboard( seat );
+        wl_keyboard_add_listener( pDisplay->keyboard,
+                                  &fghKeyboardListener,
+                                  pDisplay );
+    }
+
+    if( capabilities & WL_SEAT_CAPABILITY_POINTER )
+    {
+        pDisplay->pointer = wl_seat_get_pointer( seat );
+        wl_pointer_add_listener( pDisplay->pointer,
+                                 &fghPointerListener,
+                                 pDisplay );
+    }
+
+    if( capabilities & WL_SEAT_CAPABILITY_TOUCH )
+    {
+        pDisplay->touch = wl_seat_get_touch( seat );
+        wl_touch_add_listener( pDisplay->touch,
+                               &fghTouchListener,
+                               pDisplay );
+    }
+}
+static const struct wl_seat_listener fghSeatListener =
+{
+    fghSeatCapabilities
+};
+
+
+/*
+ * Try initializing the input device(s)
+ */
+void fgPlatformInitialiseInputDevices( void )
+{
+    wl_seat_add_listener( fgDisplay.pDisplay.seat,
+                          &fghSeatListener,
+                          &fgDisplay.pDisplay );
+
+    wl_display_roundtrip( fgDisplay.pDisplay.display );
+}
+
+/*
+ * Try closing the input device(s)
+ */
+void fgPlatformCloseInputDevices( void )
+{
+    if( fgDisplay.pDisplay.touch )
+      wl_touch_destroy( fgDisplay.pDisplay.touch );
+    if( fgDisplay.pDisplay.pointer )
+      wl_pointer_destroy( fgDisplay.pDisplay.pointer );
+    if( fgDisplay.pDisplay.keyboard )
+      wl_keyboard_destroy( fgDisplay.pDisplay.keyboard );
+    if( fgDisplay.pDisplay.xkb_state )
+      xkb_state_unref( fgDisplay.pDisplay.xkb_state );
+    if( fgDisplay.pDisplay.xkb_context )
+      xkb_context_unref( fgDisplay.pDisplay.xkb_context );
+}
+
+
+/*
+ * Wayland backend will not be implementing spaceball at all
+ */
+void fgPlatformInitializeSpaceball( void )
+{
+}
+void fgPlatformSpaceballClose( void )
+{
+}
+void fgPlatformSpaceballSetWindow( SFG_Window *window )
+{
+}
+int fgPlatformHasSpaceball( void )
+{
+    return 0;
+}
+int fgPlatformSpaceballNumButtons( void )
+{
+    return 0;
+}
+
diff --git a/src/wayland/fg_internal_wl.h b/src/wayland/fg_internal_wl.h
new file mode 100644 (file)
index 0000000..81bd5bc
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * fg_internal_wl.h
+ *
+ * The freeglut library private include file.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Tue Mar 17, 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef  FREEGLUT_INTERNAL_WL_H
+#define  FREEGLUT_INTERNAL_WL_H
+
+
+/* -- PLATFORM-SPECIFIC INCLUDES ------------------------------------------- */
+#include "egl/fg_internal_egl.h"
+#include <wayland-egl.h>
+#include <wayland-client.h>
+#include <wayland-cursor.h>
+#include <xkbcommon/xkbcommon.h>
+
+
+/* -- GLOBAL TYPE DEFINITIONS ---------------------------------------------- */
+/* The structure used by display initialization in fg_init.c */
+typedef struct tagSFG_PlatformDisplay SFG_PlatformDisplay;
+struct tagSFG_PlatformDisplay
+{
+    struct tagSFG_PlatformDisplayEGL egl;
+
+    struct wl_display* display;        /* The display we are being run in    */
+    struct wl_registry* registry;      /* The global interface registry      */
+    struct wl_compositor* compositor;  /* The compositor                     */
+    struct wl_shell* shell;            /* The shell, AKA window manager      */
+    struct wl_seat* seat;              /* The seat, references input devices */
+
+    struct xkb_context* xkb_context;   /* The global XKB keyboard context    */
+    struct xkb_state* xkb_state;       /* The current XKB keyboard state     */
+    struct wl_keyboard* keyboard;      /* The keyboard input device          */
+    struct wl_pointer* pointer;        /* The pointer input device (mouse)   */
+    struct wl_touch* touch;            /* The touchscreen input device       */
+
+    struct wl_shm* shm;                    /* The software rendering engine  */
+    struct wl_cursor_theme* cursor_theme;  /* The pointer cursor theme       */
+};
+
+
+/* The structure used by window creation in fg_window.c */
+typedef struct tagSFG_PlatformContext SFG_PlatformContext;
+struct tagSFG_PlatformContext
+{
+    struct tagSFG_PlatformContextEGL egl;
+    GLboolean pointer_button_pressed;
+
+    struct wl_surface* surface;            /* The drawing surface             */
+    struct wl_shell_surface* shsurface;    /* The shell surface, has states   */
+    struct wl_egl_window* egl_window;      /* Binding between WL/EGL surfaces */
+
+    struct wl_cursor* cursor;              /* The active cursor */
+    struct wl_surface* cursor_surface;     /* The active cursor surface */
+};
+
+
+/* The window state description. This structure should be kept portable. */
+typedef struct tagSFG_PlatformWindowState SFG_PlatformWindowState;
+struct tagSFG_PlatformWindowState
+{
+    int OldWidth;                        /* Window width from before a resize */
+    int OldHeight;                       /*   "    height  "    "    "   "    */
+};
+
+
+/* -- JOYSTICK-SPECIFIC STRUCTURES AND TYPES ------------------------------- */
+/*
+ * Initial defines from "js.h" starting around line 33 with the existing "fg_joystick.c"
+ * interspersed
+ */
+#    ifdef HAVE_SYS_IOCTL_H
+#        include <sys/ioctl.h>
+#    endif
+#    ifdef HAVE_FCNTL_H
+#        include <fcntl.h>
+#    endif
+
+#include <errno.h>
+#include <string.h>
+
+#    if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
+/* XXX The below hack is done until freeglut's autoconf is updated. */
+#        define HAVE_USB_JS    1
+
+#        if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#            include <sys/joystick.h>
+#        else
+/*
+ * XXX NetBSD/amd64 systems may find that they have to steal the
+ * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
+ * XXX I cannot comment whether that works for the interface, but
+ * XXX it lets you compile...(^&  I do not think that we can do away
+ * XXX with this header.
+ */
+#            include <machine/joystick.h>         /* For analog joysticks */
+#        endif
+#        define JS_DATA_TYPE joystick
+#        define JS_RETURN (sizeof(struct JS_DATA_TYPE))
+#    endif
+
+#    if defined(__linux__)
+#        include <linux/joystick.h>
+
+/* check the joystick driver version */
+#        if defined(JS_VERSION) && JS_VERSION >= 0x010000
+#            define JS_NEW
+#        endif
+#    else  /* Not BSD or Linux */
+#        ifndef JS_RETURN
+
+  /*
+   * We'll put these values in and that should
+   * allow the code to at least compile when there is
+   * no support. The JS open routine should error out
+   * and shut off all the code downstream anyway and if
+   * the application doesn't use a joystick we'll be fine.
+   */
+
+  struct JS_DATA_TYPE
+  {
+    int buttons;
+    int x;
+    int y;
+  };
+
+#            define JS_RETURN (sizeof(struct JS_DATA_TYPE))
+#        endif
+#    endif
+
+/* XXX It might be better to poll the operating system for the numbers of buttons and
+ * XXX axes and then dynamically allocate the arrays.
+ */
+#    define _JS_MAX_AXES 16
+typedef struct tagSFG_PlatformJoystick SFG_PlatformJoystick;
+struct tagSFG_PlatformJoystick
+{
+#   if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
+       struct os_specific_s *os;
+#   endif
+
+#   ifdef JS_NEW
+       struct js_event     js;
+       int          tmp_buttons;
+       float        tmp_axes [ _JS_MAX_AXES ];
+#   else
+       struct JS_DATA_TYPE js;
+#   endif
+
+    char         fname [ 128 ];
+    int          fd;
+};
+
+
+/* Menu font and color definitions */
+#define  FREEGLUT_MENU_FONT    GLUT_BITMAP_HELVETICA_18
+
+#define  FREEGLUT_MENU_PEN_FORE_COLORS   {0.0f,  0.0f,  0.0f,  1.0f}
+#define  FREEGLUT_MENU_PEN_BACK_COLORS   {0.70f, 0.70f, 0.70f, 1.0f}
+#define  FREEGLUT_MENU_PEN_HFORE_COLORS  {0.0f,  0.0f,  0.0f,  1.0f}
+#define  FREEGLUT_MENU_PEN_HBACK_COLORS  {1.0f,  1.0f,  1.0f,  1.0f}
+
+
+#endif  /* FREEGLUT_INTERNAL_WL_H */
diff --git a/src/wayland/fg_main_wl.c b/src/wayland/fg_main_wl.c
new file mode 100644 (file)
index 0000000..f289c17
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * fg_main_wl.c
+ *
+ * The Wayland-specific windows message processing methods.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Sun Mar 22 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+#include <errno.h>
+#include <poll.h>
+
+void fgPlatformFullScreenToggle( SFG_Window *win );
+void fgPlatformPositionWindow( SFG_Window *window, int x, int y );
+void fgPlatformReshapeWindow( SFG_Window *window, int width, int height );
+void fgPlatformPushWindow( SFG_Window *window );
+void fgPlatformPopWindow( SFG_Window *window );
+void fgPlatformHideWindow( SFG_Window *window );
+void fgPlatformIconifyWindow( SFG_Window *window );
+void fgPlatformShowWindow( SFG_Window *window );
+
+
+fg_time_t fgPlatformSystemTime( void )
+{
+#ifdef CLOCK_MONOTONIC
+    struct timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return now.tv_nsec/1000000 + now.tv_sec*1000;
+#elif defined(HAVE_GETTIMEOFDAY)
+    struct timeval now;
+    gettimeofday( &now, NULL );
+    return now.tv_usec/1000 + now.tv_sec*1000;
+#endif
+}
+
+void fgPlatformSleepForEvents( fg_time_t msec )
+{
+    struct pollfd pfd;
+    int err;
+
+    pfd.fd = wl_display_get_fd( fgDisplay.pDisplay.display );
+    pfd.events = POLLIN | POLLERR | POLLHUP;
+
+    wl_display_dispatch_pending( fgDisplay.pDisplay.display );
+    if ( ! wl_display_flush( fgDisplay.pDisplay.display ) )
+    {
+        err = poll( &pfd, 1, msec );
+
+        if( ( -1 == err ) && ( errno != EINTR ) )
+          fgWarning ( "freeglut poll() error: %d", errno );
+    }
+}
+
+
+void fgPlatformProcessSingleEvent( void )
+{
+    SFG_Window *win = fgStructure.CurrentWindow;
+
+    wl_display_dispatch_pending( fgDisplay.pDisplay.display );
+    INVOKE_WCB( *win, Display, ( ) );
+}
+
+void fgPlatformMainLoopPreliminaryWork( void )
+{
+    /* Under Wayland, this is a no-op */
+}
+
+void fgPlatformInitWork( SFG_Window* window )
+{
+    /* Under Wayland, all events happen relative to input handlers
+     * -> this is a no-op
+     */
+     return;
+}
+
+void fgPlatformPosResZordWork( SFG_Window* window, unsigned int workMask )
+{
+    if( workMask & GLUT_FULL_SCREEN_WORK )
+        fgPlatformFullScreenToggle( window );
+    if( workMask & GLUT_POSITION_WORK )
+        fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
+    if( workMask & GLUT_SIZE_WORK )
+        fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
+    if( workMask & GLUT_ZORDER_WORK )
+    {
+        if( window->State.DesiredZOrder < 0 )
+            fgPlatformPushWindow( window );
+        else
+            fgPlatformPopWindow( window );
+    }
+}
+
+void fgPlatformVisibilityWork( SFG_Window* window )
+{
+    /* Visibility status of window gets updated in the window message handlers above 
+     */
+    SFG_Window *win = window;
+    switch (window->State.DesiredVisibility)
+    {
+    case DesireHiddenState:
+        fgPlatformHideWindow( window );
+        break;
+    case DesireIconicState:
+        /* Call on top-level window */
+        while (win->Parent)
+            win = win->Parent;
+        fgPlatformIconifyWindow( win );
+        break;
+    case DesireNormalState:
+        fgPlatformShowWindow( window );
+        break;
+    }
+}
+
diff --git a/src/wayland/fg_state_wl.c b/src/wayland/fg_state_wl.c
new file mode 100644 (file)
index 0000000..06b9906
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * fg_state_wl.c
+ *
+ * Wayland-specific freeglut state query methods.
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Sun Mar 23 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <GL/freeglut.h>
+#include "fg_internal.h"
+#include "egl/fg_state_egl.h"
+
+int fgPlatformGlutDeviceGet ( GLenum eWhat )
+{
+    switch( eWhat )
+    {
+    case GLUT_HAS_KEYBOARD:
+        if( fgDisplay.pDisplay.keyboard )
+          return 1;
+        else
+          return 0;
+
+    case GLUT_HAS_MOUSE:
+        /* we want the touchscreen to behave like a mouse,
+         * so let us pretend it is one.
+         */
+        if( fgDisplay.pDisplay.pointer ||
+            fgDisplay.pDisplay.touch )
+          return 1;
+        else
+          return 0;
+
+    case GLUT_NUM_MOUSE_BUTTONS:
+        /* Wayland has no way of telling us how much buttons
+         * a mouse has, unless the actual event gets sent to
+         * the client. As we are only handling 3 buttons
+         * currently, return this fixed number for now.
+         */
+        if( fgDisplay.pDisplay.pointer )
+          return 3;
+        /* touchscreen is considered as having one button */
+        else if( fgDisplay.pDisplay.touch )
+          return 1;
+        else
+          return 0;
+
+    default:
+        fgWarning( "glutDeviceGet(): missing enum handle %d", eWhat );
+        return -1;
+    }
+}
+
+
+int fgPlatformGlutGet ( GLenum eWhat )
+{
+    switch( eWhat )
+    {
+
+    /*
+     * Those calls are pointless under Wayland, so inform the user
+     */
+    case GLUT_WINDOW_X:
+    case GLUT_WINDOW_Y:
+    {
+        if( fgStructure.CurrentWindow == NULL )
+        {
+            return 0;
+        }
+        else
+        {
+            fgWarning( "glutGet(): GLUT_WINDOW_X/Y properties "
+                                   "unsupported under Wayland" );
+            return -1;
+        }
+    }
+
+    /*
+     * TODO : support this correctly once we will start drawing
+     *  client-side decorations
+     */
+    case GLUT_WINDOW_BORDER_WIDTH:
+    case GLUT_WINDOW_HEADER_HEIGHT:
+    {
+        if( fgStructure.CurrentWindow == NULL ||
+            fgStructure.CurrentWindow->Parent )
+            /* can't get widths/heights if no current window
+             * and child windows don't have borders */
+            return 0;
+
+        return 0;
+    }
+
+    case GLUT_WINDOW_WIDTH:
+    case GLUT_WINDOW_HEIGHT:
+    {
+        if( fgStructure.CurrentWindow == NULL )
+            return 0;
+
+        switch ( eWhat )
+        {
+        case GLUT_WINDOW_WIDTH:
+            return fgStructure.CurrentWindow->State.Width;
+        case GLUT_WINDOW_HEIGHT:
+            return fgStructure.CurrentWindow->State.Height;
+        }
+    }
+
+    /* Colormap size is handled in a bit different way than all the rest */
+    case GLUT_WINDOW_COLORMAP_SIZE:
+    {
+        if( fgStructure.CurrentWindow == NULL )
+        {
+            return 0;
+        }
+        else
+        {
+            int result = 0;
+           if ( ! eglGetConfigAttrib( fgDisplay.pDisplay.egl.Display,
+                     fgStructure.CurrentWindow->Window.pContext.egl.Config,
+                     EGL_BUFFER_SIZE, &result ) )
+             fgError( "eglGetConfigAttrib(EGL_BUFFER_SIZE) failed" );
+
+            return result;
+        }
+    }
+
+    default:
+      return fghPlatformGlutGetEGL( eWhat );
+    }
+}
+
diff --git a/src/wayland/fg_structure_wl.c b/src/wayland/fg_structure_wl.c
new file mode 100644 (file)
index 0000000..ad77cdd
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * fg_structure_wl.c
+ *
+ * Windows and menus need tree structure for Wayland
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Tue Mar 17, 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <GL/freeglut.h>
+#include "fg_internal.h"
+#include "egl/fg_structure_egl.h"
+
+extern SFG_Structure fgStructure;
+
+void fgPlatformCreateWindow( SFG_Window *window )
+{
+    fghPlatformCreateWindowEGL( window );
+
+    window->State.pWState.OldHeight = window->State.pWState.OldWidth = -1;
+}
+
diff --git a/src/wayland/fg_window_wl.c b/src/wayland/fg_window_wl.c
new file mode 100644 (file)
index 0000000..e4c3da4
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * fg_window_wl.c
+ *
+ * Window management methods for Wayland
+ *
+ * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
+ * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
+ * Creation date: Tue Mar 17, 2015
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define FREEGLUT_BUILDING_LIB
+#include <GL/freeglut.h>
+#include "../fg_internal.h"
+#include "egl/fg_window_egl.h"
+#define fghCreateNewContext fghCreateNewContextEGL
+
+extern void fghOnReshapeNotify( SFG_Window *window, int width, int height, GLboolean forceNotify );
+void fgPlatformReshapeWindow( SFG_Window *window, int width, int height );
+void fgPlatformIconifyWindow( SFG_Window *window );
+
+
+static void fghShSurfacePing( void* data,
+                           struct wl_shell_surface* shsurface,
+                           uint32_t serial )
+{
+    wl_shell_surface_pong( shsurface, serial );
+}
+static void fghShSurfaceConfigure( void* data,
+                                struct wl_shell_surface* shsurface,
+                                uint32_t edges,
+                                int32_t width, int32_t height )
+{
+    SFG_Window* window = data;
+    fgPlatformReshapeWindow( window, width, height );
+}
+static const struct wl_shell_surface_listener fghShSurfaceListener =
+{
+    fghShSurfacePing,
+    fghShSurfaceConfigure,
+    NULL
+};
+
+
+static int fghToggleFullscreen(void)
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+
+    if ( ! win->State.IsFullscreen )
+    {
+      win->State.pWState.OldWidth = win->State.Width;
+      win->State.pWState.OldHeight = win->State.Height;
+      wl_shell_surface_set_fullscreen( win->Window.pContext.shsurface,
+                                       WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+                                       0, NULL );
+    }
+    else
+    {
+      fgPlatformReshapeWindow( win, win->State.pWState.OldWidth,
+                                    win->State.pWState.OldHeight );
+      wl_shell_surface_set_toplevel( win->Window.pContext.shsurface );
+    }
+
+    return 0;
+}
+
+void fgPlatformOpenWindow( SFG_Window* window, const char* title,
+                           GLboolean positionUse, int x, int y,
+                           GLboolean sizeUse, int w, int h,
+                           GLboolean gameMode, GLboolean isSubWindow )
+{
+    /* Save the display mode if we are creating a menu window */
+    if( window->IsMenu && ( ! fgStructure.MenuContext ) )
+        fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
+
+    fghChooseConfig( &window->Window.pContext.egl.Config );
+
+    if( ! window->Window.pContext.egl.Config )
+    {
+        /*
+         * The "fghChooseConfig" returned a null meaning that the visual
+         * context is not available.
+         * Try a couple of variations to see if they will work.
+         */
+        if( fgState.DisplayMode & GLUT_MULTISAMPLE )
+        {
+            fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
+            fghChooseConfig( &window->Window.pContext.egl.Config );
+            fgState.DisplayMode |= GLUT_MULTISAMPLE;
+        }
+    }
+
+    FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.pContext.egl.Config != NULL,
+                                  "EGL configuration with necessary capabilities "
+                                  "not found", "fgOpenWindow" );
+
+    if( ! positionUse )
+        x = y = -1; /* default window position */
+    if( ! sizeUse )
+        w = h = 300; /* default window size */
+
+    /*  Create the cursor  */
+   window->Window.pContext.cursor = wl_cursor_theme_get_cursor(
+                                      fgDisplay.pDisplay.cursor_theme,
+                                      "left_ptr" ); 
+   window->Window.pContext.cursor_surface = wl_compositor_create_surface(
+                                              fgDisplay.pDisplay.compositor );
+
+    /*  Create the main surface  */
+    window->Window.pContext.surface = wl_compositor_create_surface(
+                                        fgDisplay.pDisplay.compositor );
+
+    /*  Create the shell surface with respects to the parent/child tree  */
+    window->Window.pContext.shsurface = wl_shell_get_shell_surface(
+                                          fgDisplay.pDisplay.shell,
+                                           window->Window.pContext.surface );
+    wl_shell_surface_add_listener( window->Window.pContext.shsurface,
+                                   &fghShSurfaceListener, window );
+
+    if( title)
+      wl_shell_surface_set_title( window->Window.pContext.shsurface, title );
+
+    if( gameMode )
+    {
+        window->State.IsFullscreen = GL_TRUE;
+        wl_shell_surface_set_fullscreen( window->Window.pContext.shsurface,
+                                         WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+                                         0, NULL );
+    }
+    else if( !isSubWindow && !window->IsMenu )
+    {
+        wl_shell_surface_set_toplevel( window->Window.pContext.shsurface );
+    }
+    else
+    {
+        wl_shell_surface_set_transient( window->Window.pContext.shsurface,
+                                        window->Parent->Window.pContext.surface,
+                                        x, y, 0 );
+    }
+
+    /*  Create the Wl_EGL_Window  */
+    window->Window.Context = fghCreateNewContext( window );
+    window->Window.pContext.egl_window = wl_egl_window_create( 
+                                           window->Window.pContext.surface,
+                                           w, h);
+    window->Window.pContext.egl.Surface = eglCreateWindowSurface( 
+                              fgDisplay.pDisplay.egl.Display,
+                              window->Window.pContext.egl.Config,
+                              (EGLNativeWindowType)window->Window.pContext.egl_window,
+                              NULL );
+    eglMakeCurrent( fgDisplay.pDisplay.egl.Display, window->Window.pContext.egl.Surface,
+                    window->Window.pContext.egl.Surface, window->Window.Context );
+
+   window->Window.pContext.pointer_button_pressed = GL_FALSE;
+}
+
+
+/*
+ * Request a window resize
+ */
+void fgPlatformReshapeWindow( SFG_Window *window, int width, int height )
+{
+    fghOnReshapeNotify(window, width, height, GL_FALSE);
+
+    if( window->Window.pContext.egl_window )
+      wl_egl_window_resize( window->Window.pContext.egl_window,
+                            width, height, 0, 0 );
+}
+
+
+/*
+ * Closes a window, destroying the frame and OpenGL context
+ */
+void fgPlatformCloseWindow( SFG_Window* window )
+{
+    fghPlatformCloseWindowEGL(window);
+
+    if ( window->Window.pContext.egl_window )
+      wl_egl_window_destroy( window->Window.pContext.egl_window );
+    if ( window->Window.pContext.shsurface )
+      wl_shell_surface_destroy( window->Window.pContext.shsurface );
+    if ( window->Window.pContext.surface )
+      wl_surface_destroy( window->Window.pContext.surface );
+    if ( window->Window.pContext.cursor_surface )
+      wl_surface_destroy( window->Window.pContext.cursor_surface );
+}
+
+
+/*
+ * This function re-creates the window assets if they
+ * have been destroyed
+ */
+void fgPlatformShowWindow( SFG_Window *window )
+{
+    if ( ! window->Window.pContext.egl_window ||
+         ! window->Window.pContext.shsurface ||
+         ! window->Window.pContext.surface)
+    {
+        fgPlatformCloseWindow( window );
+        fgPlatformOpenWindow( window, "", /* TODO : save the title for further use */
+                              GL_TRUE, window->State.Xpos, window->State.Ypos,
+                              GL_TRUE, window->State.Width, window->State.Height,
+                              (GLboolean)(window->State.IsFullscreen ? GL_TRUE : GL_FALSE),
+                              (GLboolean)(window->Parent ? GL_TRUE : GL_FALSE) );
+    }
+    else 
+    {
+    /*     TODO : support this once we start using xdg-shell
+     *
+     *     xdg_surface_present( window->Window.pContext.shsurface, 0 );
+     *     INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
+     *     window->State.Visible = GL_TRUE;
+     */
+        fgWarning( "glutShownWindow(): function unsupported for an already existing"
+                                     " window under Wayland" );
+    }
+}
+
+/*
+ * This function hides the specified window
+ */
+void fgPlatformHideWindow( SFG_Window *window )
+{
+    fgPlatformIconifyWindow( window );
+}
+
+/*
+ * Iconify the specified window (top-level windows only)
+ */
+void fgPlatformIconifyWindow( SFG_Window *window )
+{
+    /* TODO : support this once we start using xdg-shell
+     *
+     * xdg_surface_set_minimized( window->Window.pContext.shsurface );
+     * INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) );
+     * window->State.Visible = GL_FALSE;
+     */
+    fgWarning( "glutIconifyWindow(): function unsupported under Wayland" );
+}
+
+/*
+ * Set the current window's title
+ */
+void fgPlatformGlutSetWindowTitle( const char* title )
+{
+    SFG_Window* win = fgStructure.CurrentWindow;
+    wl_shell_surface_set_title( win->Window.pContext.shsurface, title );
+}
+
+/*
+ * Set the current window's iconified title
+ */
+void fgPlatformGlutSetIconTitle( const char* title )
+{
+    fgPlatformGlutSetWindowTitle( title );
+}
+
+/*
+ * Change the specified window's position
+ */
+void fgPlatformPositionWindow( SFG_Window *window, int x, int y )
+{
+    /* pointless under Wayland */
+    fgWarning( "glutPositionWindow(): function unsupported under Wayland" );
+}
+
+/*
+ * Lowers the specified window (by Z order change)
+ */
+void fgPlatformPushWindow( SFG_Window *window )
+{
+    /* pointless under Wayland */
+    fgWarning( "glutPushWindow(): function unsupported under Wayland" );
+}
+
+/*
+ * Raises the specified window (by Z order change)
+ */
+void fgPlatformPopWindow( SFG_Window *window )
+{
+    /* pointless under Wayland */
+    fgWarning( "glutPopWindow(): function unsupported under Wayland" );
+}
+
+/*
+ * Toggle the window's full screen state.
+ */
+void fgPlatformFullScreenToggle( SFG_Window *win )
+{
+    if(fghToggleFullscreen() != -1) {
+        win->State.IsFullscreen = !win->State.IsFullscreen;
+    }
+}
+