1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #include "../../SDL_internal.h"
23 
24 #if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
25 
26 #include "../SDL_sysvideo.h"
27 #include "../../events/SDL_windowevents_c.h"
28 #include "../SDL_egl_c.h"
29 #include "SDL_waylandevents_c.h"
30 #include "SDL_waylandwindow.h"
31 #include "SDL_waylandvideo.h"
32 #include "SDL_waylandtouch.h"
33 #include "SDL_waylanddyn.h"
34 
35 static void
handle_ping(void * data,struct wl_shell_surface * shell_surface,uint32_t serial)36 handle_ping(void *data, struct wl_shell_surface *shell_surface,
37             uint32_t serial)
38 {
39     wl_shell_surface_pong(shell_surface, serial);
40 }
41 
42 static void
handle_configure(void * data,struct wl_shell_surface * shell_surface,uint32_t edges,int32_t width,int32_t height)43 handle_configure(void *data, struct wl_shell_surface *shell_surface,
44                  uint32_t edges, int32_t width, int32_t height)
45 {
46     SDL_WindowData *wind = (SDL_WindowData *)data;
47     SDL_Window *window = wind->sdlwindow;
48     struct wl_region *region;
49 
50     /* wl_shell_surface spec states that this is a suggestion.
51        Ignore if less than or greater than max/min size. */
52 
53     if (width == 0 || height == 0) {
54         return;
55     }
56 
57     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
58         if ((window->flags & SDL_WINDOW_RESIZABLE)) {
59             if (window->max_w > 0) {
60                 width = SDL_min(width, window->max_w);
61             }
62             width = SDL_max(width, window->min_w);
63 
64             if (window->max_h > 0) {
65                 height = SDL_min(height, window->max_h);
66             }
67             height = SDL_max(height, window->min_h);
68         } else {
69             return;
70         }
71     }
72 
73     if (width == window->w && height == window->h) {
74         return;
75     }
76 
77     window->w = width;
78     window->h = height;
79     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
80 
81     region = wl_compositor_create_region(wind->waylandData->compositor);
82     wl_region_add(region, 0, 0, window->w, window->h);
83     wl_surface_set_opaque_region(wind->surface, region);
84     wl_region_destroy(region);
85     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
86 }
87 
88 static void
handle_popup_done(void * data,struct wl_shell_surface * shell_surface)89 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
90 {
91 }
92 
93 static const struct wl_shell_surface_listener shell_surface_listener = {
94     handle_ping,
95     handle_configure,
96     handle_popup_done
97 };
98 
99 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
100 static void
handle_onscreen_visibility(void * data,struct qt_extended_surface * qt_extended_surface,int32_t visible)101 handle_onscreen_visibility(void *data,
102         struct qt_extended_surface *qt_extended_surface, int32_t visible)
103 {
104 }
105 
106 static void
handle_set_generic_property(void * data,struct qt_extended_surface * qt_extended_surface,const char * name,struct wl_array * value)107 handle_set_generic_property(void *data,
108         struct qt_extended_surface *qt_extended_surface, const char *name,
109         struct wl_array *value)
110 {
111 }
112 
113 static void
handle_close(void * data,struct qt_extended_surface * qt_extended_surface)114 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
115 {
116     SDL_WindowData *window = (SDL_WindowData *)data;
117     SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
118 }
119 
120 static const struct qt_extended_surface_listener extended_surface_listener = {
121     handle_onscreen_visibility,
122     handle_set_generic_property,
123     handle_close,
124 };
125 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
126 
127 SDL_bool
Wayland_GetWindowWMInfo(_THIS,SDL_Window * window,SDL_SysWMinfo * info)128 Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
129 {
130     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
131 
132     info->info.wl.display = data->waylandData->display;
133     info->info.wl.surface = data->surface;
134     info->info.wl.shell_surface = data->shell_surface;
135     info->subsystem = SDL_SYSWM_WAYLAND;
136 
137     return SDL_TRUE;
138 }
139 
140 int
Wayland_SetWindowHitTest(SDL_Window * window,SDL_bool enabled)141 Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
142 {
143     return 0;  /* just succeed, the real work is done elsewhere. */
144 }
145 
Wayland_ShowWindow(_THIS,SDL_Window * window)146 void Wayland_ShowWindow(_THIS, SDL_Window *window)
147 {
148     SDL_WindowData *wind = window->driverdata;
149 
150     if (window->flags & SDL_WINDOW_FULLSCREEN)
151         wl_shell_surface_set_fullscreen(wind->shell_surface,
152                                         WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
153                                         0, (struct wl_output *)window->fullscreen_mode.driverdata);
154     else
155         wl_shell_surface_set_toplevel(wind->shell_surface);
156 
157     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
158 }
159 
160 void
Wayland_SetWindowFullscreen(_THIS,SDL_Window * window,SDL_VideoDisplay * _display,SDL_bool fullscreen)161 Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
162                             SDL_VideoDisplay * _display, SDL_bool fullscreen)
163 {
164     SDL_WindowData *wind = window->driverdata;
165 
166     if (fullscreen)
167         wl_shell_surface_set_fullscreen(wind->shell_surface,
168                                         WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
169                                         0, (struct wl_output *)_display->driverdata);
170     else
171         wl_shell_surface_set_toplevel(wind->shell_surface);
172 
173     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
174 }
175 
176 void
Wayland_RestoreWindow(_THIS,SDL_Window * window)177 Wayland_RestoreWindow(_THIS, SDL_Window * window)
178 {
179     SDL_WindowData *wind = window->driverdata;
180 
181     wl_shell_surface_set_toplevel(wind->shell_surface);
182 
183     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
184 }
185 
186 void
Wayland_MaximizeWindow(_THIS,SDL_Window * window)187 Wayland_MaximizeWindow(_THIS, SDL_Window * window)
188 {
189     SDL_WindowData *wind = window->driverdata;
190 
191     wl_shell_surface_set_maximized(wind->shell_surface, NULL);
192 
193     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
194 }
195 
Wayland_CreateWindow(_THIS,SDL_Window * window)196 int Wayland_CreateWindow(_THIS, SDL_Window *window)
197 {
198     SDL_WindowData *data;
199     SDL_VideoData *c;
200     struct wl_region *region;
201 
202     data = calloc(1, sizeof *data);
203     if (data == NULL)
204         return SDL_OutOfMemory();
205 
206     c = _this->driverdata;
207     window->driverdata = data;
208 
209     if (!(window->flags & SDL_WINDOW_OPENGL)) {
210         SDL_GL_LoadLibrary(NULL);
211         window->flags |= SDL_WINDOW_OPENGL;
212     }
213 
214     if (window->x == SDL_WINDOWPOS_UNDEFINED) {
215         window->x = 0;
216     }
217     if (window->y == SDL_WINDOWPOS_UNDEFINED) {
218         window->y = 0;
219     }
220 
221     data->waylandData = c;
222     data->sdlwindow = window;
223 
224     data->surface =
225         wl_compositor_create_surface(c->compositor);
226     wl_surface_set_user_data(data->surface, data);
227     data->shell_surface = wl_shell_get_shell_surface(c->shell,
228                                                      data->surface);
229     wl_shell_surface_set_class (data->shell_surface, c->classname);
230 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
231     if (c->surface_extension) {
232         data->extended_surface = qt_surface_extension_get_extended_surface(
233                 c->surface_extension, data->surface);
234     }
235 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
236 
237     data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
238                                             window->w, window->h);
239 
240     /* Create the GLES window surface */
241     data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
242 
243     if (data->egl_surface == EGL_NO_SURFACE) {
244         return SDL_SetError("failed to create a window surface");
245     }
246 
247     if (data->shell_surface) {
248         wl_shell_surface_set_user_data(data->shell_surface, data);
249         wl_shell_surface_add_listener(data->shell_surface,
250                                       &shell_surface_listener, data);
251     }
252 
253 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
254     if (data->extended_surface) {
255         qt_extended_surface_set_user_data(data->extended_surface, data);
256         qt_extended_surface_add_listener(data->extended_surface,
257                                          &extended_surface_listener, data);
258     }
259 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
260 
261     region = wl_compositor_create_region(c->compositor);
262     wl_region_add(region, 0, 0, window->w, window->h);
263     wl_surface_set_opaque_region(data->surface, region);
264     wl_region_destroy(region);
265 
266     if (c->relative_mouse_mode) {
267         Wayland_input_lock_pointer(c->input);
268     }
269 
270     WAYLAND_wl_display_flush(c->display);
271 
272     return 0;
273 }
274 
Wayland_SetWindowSize(_THIS,SDL_Window * window)275 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
276 {
277     SDL_VideoData *data = _this->driverdata;
278     SDL_WindowData *wind = window->driverdata;
279     struct wl_region *region;
280 
281     WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
282 
283     region =wl_compositor_create_region(data->compositor);
284     wl_region_add(region, 0, 0, window->w, window->h);
285     wl_surface_set_opaque_region(wind->surface, region);
286     wl_region_destroy(region);
287 }
288 
Wayland_SetWindowTitle(_THIS,SDL_Window * window)289 void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
290 {
291     SDL_WindowData *wind = window->driverdata;
292 
293     if (window->title != NULL) {
294         wl_shell_surface_set_title(wind->shell_surface, window->title);
295     }
296 
297     WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
298 }
299 
Wayland_DestroyWindow(_THIS,SDL_Window * window)300 void Wayland_DestroyWindow(_THIS, SDL_Window *window)
301 {
302     SDL_VideoData *data = _this->driverdata;
303     SDL_WindowData *wind = window->driverdata;
304 
305     if (data) {
306         SDL_EGL_DestroySurface(_this, wind->egl_surface);
307         WAYLAND_wl_egl_window_destroy(wind->egl_window);
308 
309         if (wind->shell_surface)
310             wl_shell_surface_destroy(wind->shell_surface);
311 
312 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
313         if (wind->extended_surface)
314             qt_extended_surface_destroy(wind->extended_surface);
315 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
316         wl_surface_destroy(wind->surface);
317 
318         SDL_free(wind);
319         WAYLAND_wl_display_flush(data->display);
320     }
321     window->driverdata = NULL;
322 }
323 
324 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
325 
326 /* vi: set ts=4 sw=4 expandtab: */
327