Implement initial Wayland support

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>
This commit is contained in:
Manuel Bachmann 2015-03-26 03:28:33 +01:00
parent 27d5d26426
commit 9b30564b6d
13 changed files with 1825 additions and 37 deletions

View 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,7 +169,28 @@ ELSEIF(ANDROID OR BLACKBERRY)
src/blackberry/fg_window_blackberry.c
)
ENDIF()
ELSE()
# 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_cursor_x11.c
src/x11/fg_ext_x11.c
@ -195,8 +218,11 @@ ELSE()
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()
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:

View 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");

View File

@ -51,7 +51,11 @@
# define TARGET_HOST_BLACKBERRY 1
#elif defined(__posix__) || defined(__unix__) || defined(__linux__) || defined(__sun)
# 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 */
@ -81,6 +85,10 @@
# 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
#endif
@ -188,6 +196,9 @@
#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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 );
*/
}

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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 );
}
}

View File

@ -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;
}

View File

@ -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;
}
}