Merge pull request #30 from Tarnyko/git_master

Implement initial Wayland support
This commit is contained in:
Diederick C. Niehorster 2015-04-04 20:42:13 +02:00
commit 7fbdb4ea1e
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,6 +169,27 @@ 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
@ -196,7 +219,10 @@ ELSE()
)
ENDIF()
ENDIF()
IF(FREEGLUT_GLES)
ENDIF()
# 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,12 +538,18 @@ 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:
SET(PC_LIBNAME "glut")

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