# 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()
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
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:
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})
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:
{
/* 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");
# 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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 );
+ */
+}
+
--- /dev/null
+/*
+ * 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 );
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+ }
+}
+
--- /dev/null
+/*
+ * 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 );
+ }
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+ }
+}
+