1 /*
2 * fg_window_wl.c
3 *
4 * Window management methods for Wayland
5 *
6 * Copyright (c) 2015 Manuel Bachmann. All Rights Reserved.
7 * Written by Manuel Bachmann, <tarnyko@tarnyko.net>
8 * Creation date: Tue Mar 17, 2015
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * MANUEL BACHMANN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 #define FREEGLUT_BUILDING_LIB
29 #include <GL/freeglut.h>
30 #include "../fg_internal.h"
31 #include "egl/fg_window_egl.h"
32 #define fghCreateNewContext fghCreateNewContextEGL
33
34 extern void fghOnReshapeNotify( SFG_Window *window, int width, int height, GLboolean forceNotify );
35 void fgPlatformReshapeWindow( SFG_Window *window, int width, int height );
36 void fgPlatformIconifyWindow( SFG_Window *window );
37
38
fghShSurfacePing(void * data,struct wl_shell_surface * shsurface,uint32_t serial)39 static void fghShSurfacePing( void* data,
40 struct wl_shell_surface* shsurface,
41 uint32_t serial )
42 {
43 wl_shell_surface_pong( shsurface, serial );
44 }
fghShSurfaceConfigure(void * data,struct wl_shell_surface * shsurface,uint32_t edges,int32_t width,int32_t height)45 static void fghShSurfaceConfigure( void* data,
46 struct wl_shell_surface* shsurface,
47 uint32_t edges,
48 int32_t width, int32_t height )
49 {
50 SFG_Window* window = data;
51 fgPlatformReshapeWindow( window, width, height );
52 }
53 static const struct wl_shell_surface_listener fghShSurfaceListener =
54 {
55 fghShSurfacePing,
56 fghShSurfaceConfigure,
57 NULL
58 };
59
60
fghToggleFullscreen(void)61 static int fghToggleFullscreen(void)
62 {
63 SFG_Window* win = fgStructure.CurrentWindow;
64
65 if ( ! win->State.IsFullscreen )
66 {
67 win->State.pWState.OldWidth = win->State.Width;
68 win->State.pWState.OldHeight = win->State.Height;
69 wl_shell_surface_set_fullscreen( win->Window.pContext.shsurface,
70 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
71 0, NULL );
72 }
73 else
74 {
75 fgPlatformReshapeWindow( win, win->State.pWState.OldWidth,
76 win->State.pWState.OldHeight );
77 wl_shell_surface_set_toplevel( win->Window.pContext.shsurface );
78 }
79
80 return 0;
81 }
82
fgPlatformOpenWindow(SFG_Window * window,const char * title,GLboolean positionUse,int x,int y,GLboolean sizeUse,int w,int h,GLboolean gameMode,GLboolean isSubWindow)83 void fgPlatformOpenWindow( SFG_Window* window, const char* title,
84 GLboolean positionUse, int x, int y,
85 GLboolean sizeUse, int w, int h,
86 GLboolean gameMode, GLboolean isSubWindow )
87 {
88 /* Save the display mode if we are creating a menu window */
89 if( window->IsMenu && ( ! fgStructure.MenuContext ) )
90 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ;
91
92 fghChooseConfig( &window->Window.pContext.egl.Config );
93
94 if( ! window->Window.pContext.egl.Config )
95 {
96 /*
97 * The "fghChooseConfig" returned a null meaning that the visual
98 * context is not available.
99 * Try a couple of variations to see if they will work.
100 */
101 if( fgState.DisplayMode & GLUT_MULTISAMPLE )
102 {
103 fgState.DisplayMode &= ~GLUT_MULTISAMPLE ;
104 fghChooseConfig( &window->Window.pContext.egl.Config );
105 fgState.DisplayMode |= GLUT_MULTISAMPLE;
106 }
107 }
108
109 FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.pContext.egl.Config != NULL,
110 "EGL configuration with necessary capabilities "
111 "not found", "fgOpenWindow" );
112
113 if( ! positionUse )
114 x = y = -1; /* default window position */
115 if( ! sizeUse )
116 w = h = 300; /* default window size */
117
118 /* Create the cursor */
119 window->Window.pContext.cursor = wl_cursor_theme_get_cursor(
120 fgDisplay.pDisplay.cursor_theme,
121 "left_ptr" );
122 window->Window.pContext.cursor_surface = wl_compositor_create_surface(
123 fgDisplay.pDisplay.compositor );
124
125 /* Create the main surface */
126 window->Window.pContext.surface = wl_compositor_create_surface(
127 fgDisplay.pDisplay.compositor );
128
129 /* Create the shell surface with respects to the parent/child tree */
130 window->Window.pContext.shsurface = wl_shell_get_shell_surface(
131 fgDisplay.pDisplay.shell,
132 window->Window.pContext.surface );
133 wl_shell_surface_add_listener( window->Window.pContext.shsurface,
134 &fghShSurfaceListener, window );
135
136 if( title)
137 wl_shell_surface_set_title( window->Window.pContext.shsurface, title );
138
139 if( gameMode )
140 {
141 window->State.IsFullscreen = GL_TRUE;
142 wl_shell_surface_set_fullscreen( window->Window.pContext.shsurface,
143 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
144 0, NULL );
145 }
146 else if( !isSubWindow && !window->IsMenu )
147 {
148 wl_shell_surface_set_toplevel( window->Window.pContext.shsurface );
149 }
150 else
151 {
152 wl_shell_surface_set_transient( window->Window.pContext.shsurface,
153 window->Parent->Window.pContext.surface,
154 x, y, 0 );
155 }
156
157 /* Create the Wl_EGL_Window */
158 window->Window.Context = fghCreateNewContext( window );
159 window->Window.pContext.egl_window = wl_egl_window_create(
160 window->Window.pContext.surface,
161 w, h);
162 window->Window.pContext.egl.Surface = eglCreateWindowSurface(
163 fgDisplay.pDisplay.egl.Display,
164 window->Window.pContext.egl.Config,
165 (EGLNativeWindowType)window->Window.pContext.egl_window,
166 NULL );
167 eglMakeCurrent( fgDisplay.pDisplay.egl.Display, window->Window.pContext.egl.Surface,
168 window->Window.pContext.egl.Surface, window->Window.Context );
169
170 window->Window.pContext.pointer_button_pressed = GL_FALSE;
171 }
172
173
174 /*
175 * Request a window resize
176 */
fgPlatformReshapeWindow(SFG_Window * window,int width,int height)177 void fgPlatformReshapeWindow( SFG_Window *window, int width, int height )
178 {
179 fghOnReshapeNotify(window, width, height, GL_FALSE);
180
181 if( window->Window.pContext.egl_window )
182 wl_egl_window_resize( window->Window.pContext.egl_window,
183 width, height, 0, 0 );
184 }
185
186
187 /*
188 * Closes a window, destroying the frame and OpenGL context
189 */
fgPlatformCloseWindow(SFG_Window * window)190 void fgPlatformCloseWindow( SFG_Window* window )
191 {
192 fghPlatformCloseWindowEGL(window);
193
194 if ( window->Window.pContext.egl_window )
195 wl_egl_window_destroy( window->Window.pContext.egl_window );
196 if ( window->Window.pContext.shsurface )
197 wl_shell_surface_destroy( window->Window.pContext.shsurface );
198 if ( window->Window.pContext.surface )
199 wl_surface_destroy( window->Window.pContext.surface );
200 if ( window->Window.pContext.cursor_surface )
201 wl_surface_destroy( window->Window.pContext.cursor_surface );
202 }
203
204
205 /*
206 * This function re-creates the window assets if they
207 * have been destroyed
208 */
fgPlatformShowWindow(SFG_Window * window)209 void fgPlatformShowWindow( SFG_Window *window )
210 {
211 if ( ! window->Window.pContext.egl_window ||
212 ! window->Window.pContext.shsurface ||
213 ! window->Window.pContext.surface)
214 {
215 fgPlatformCloseWindow( window );
216 fgPlatformOpenWindow( window, "", /* TODO : save the title for further use */
217 GL_TRUE, window->State.Xpos, window->State.Ypos,
218 GL_TRUE, window->State.Width, window->State.Height,
219 (GLboolean)(window->State.IsFullscreen ? GL_TRUE : GL_FALSE),
220 (GLboolean)(window->Parent ? GL_TRUE : GL_FALSE) );
221 }
222 else
223 {
224 /* TODO : support this once we start using xdg-shell
225 *
226 * xdg_surface_present( window->Window.pContext.shsurface, 0 );
227 * INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
228 * window->State.Visible = GL_TRUE;
229 */
230 fgWarning( "glutShownWindow(): function unsupported for an already existing"
231 " window under Wayland" );
232 }
233 }
234
235 /*
236 * This function hides the specified window
237 */
fgPlatformHideWindow(SFG_Window * window)238 void fgPlatformHideWindow( SFG_Window *window )
239 {
240 fgPlatformIconifyWindow( window );
241 }
242
243 /*
244 * Iconify the specified window (top-level windows only)
245 */
fgPlatformIconifyWindow(SFG_Window * window)246 void fgPlatformIconifyWindow( SFG_Window *window )
247 {
248 /* TODO : support this once we start using xdg-shell
249 *
250 * xdg_surface_set_minimized( window->Window.pContext.shsurface );
251 * INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) );
252 * window->State.Visible = GL_FALSE;
253 */
254 fgWarning( "glutIconifyWindow(): function unsupported under Wayland" );
255 }
256
257 /*
258 * Set the current window's title
259 */
fgPlatformGlutSetWindowTitle(const char * title)260 void fgPlatformGlutSetWindowTitle( const char* title )
261 {
262 SFG_Window* win = fgStructure.CurrentWindow;
263 wl_shell_surface_set_title( win->Window.pContext.shsurface, title );
264 }
265
266 /*
267 * Set the current window's iconified title
268 */
fgPlatformGlutSetIconTitle(const char * title)269 void fgPlatformGlutSetIconTitle( const char* title )
270 {
271 fgPlatformGlutSetWindowTitle( title );
272 }
273
274 /*
275 * Change the specified window's position
276 */
fgPlatformPositionWindow(SFG_Window * window,int x,int y)277 void fgPlatformPositionWindow( SFG_Window *window, int x, int y )
278 {
279 /* pointless under Wayland */
280 fgWarning( "glutPositionWindow(): function unsupported under Wayland" );
281 }
282
283 /*
284 * Lowers the specified window (by Z order change)
285 */
fgPlatformPushWindow(SFG_Window * window)286 void fgPlatformPushWindow( SFG_Window *window )
287 {
288 /* pointless under Wayland */
289 fgWarning( "glutPushWindow(): function unsupported under Wayland" );
290 }
291
292 /*
293 * Raises the specified window (by Z order change)
294 */
fgPlatformPopWindow(SFG_Window * window)295 void fgPlatformPopWindow( SFG_Window *window )
296 {
297 /* pointless under Wayland */
298 fgWarning( "glutPopWindow(): function unsupported under Wayland" );
299 }
300
301 /*
302 * Toggle the window's full screen state.
303 */
fgPlatformFullScreenToggle(SFG_Window * win)304 void fgPlatformFullScreenToggle( SFG_Window *win )
305 {
306 if(fghToggleFullscreen() != -1) {
307 win->State.IsFullscreen = !win->State.IsFullscreen;
308 }
309 }
310
311