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 /*
23   Contributed by Brandon Schaefer, <brandon.schaefer@canonical.com>
24 */
25 
26 #include "../../SDL_internal.h"
27 
28 #if SDL_VIDEO_DRIVER_MIR
29 
30 #include "../SDL_egl_c.h"
31 #include "../SDL_sysvideo.h"
32 #include "../../events/SDL_keyboard_c.h"
33 
34 #include "SDL_mirevents.h"
35 #include "SDL_mirwindow.h"
36 
37 #include "SDL_mirdyn.h"
38 
39 int
IsSurfaceValid(MIR_Window * mir_window)40 IsSurfaceValid(MIR_Window* mir_window)
41 {
42     if (!MIR_mir_surface_is_valid(mir_window->surface)) {
43         const char* error = MIR_mir_surface_get_error_message(mir_window->surface);
44         return SDL_SetError("Failed to created a mir surface: %s", error);
45     }
46 
47     return 0;
48 }
49 
50 MirPixelFormat
FindValidPixelFormat(MIR_Data * mir_data)51 FindValidPixelFormat(MIR_Data* mir_data)
52 {
53     unsigned int pf_size = 32;
54     unsigned int valid_formats;
55     unsigned int f;
56 
57     MirPixelFormat formats[pf_size];
58     MIR_mir_connection_get_available_surface_formats(mir_data->connection, formats,
59                                                      pf_size, &valid_formats);
60 
61     for (f = 0; f < valid_formats; f++) {
62         MirPixelFormat cur_pf = formats[f];
63 
64         if (cur_pf == mir_pixel_format_abgr_8888 ||
65             cur_pf == mir_pixel_format_xbgr_8888 ||
66             cur_pf == mir_pixel_format_argb_8888 ||
67             cur_pf == mir_pixel_format_xrgb_8888) {
68 
69             return cur_pf;
70         }
71     }
72 
73     return mir_pixel_format_invalid;
74 }
75 
76 int
MIR_CreateWindow(_THIS,SDL_Window * window)77 MIR_CreateWindow(_THIS, SDL_Window* window)
78 {
79     MIR_Window* mir_window;
80     MIR_Data* mir_data;
81     MirPixelFormat pixel_format;
82     MirBufferUsage buffer_usage;
83 
84     MirSurfaceSpec* spec;
85 
86     mir_window = SDL_calloc(1, sizeof(MIR_Window));
87     if (!mir_window)
88         return SDL_OutOfMemory();
89 
90     mir_data = _this->driverdata;
91     window->driverdata = mir_window;
92 
93     if (window->x == SDL_WINDOWPOS_UNDEFINED)
94         window->x = 0;
95 
96     if (window->y == SDL_WINDOWPOS_UNDEFINED)
97         window->y = 0;
98 
99     mir_window->mir_data = mir_data;
100     mir_window->sdl_window = window;
101 
102     if (window->flags & SDL_WINDOW_OPENGL) {
103         pixel_format = MIR_mir_connection_get_egl_pixel_format(mir_data->connection,
104                                                                _this->egl_data->egl_display,
105                                                                _this->egl_data->egl_config);
106     }
107     else {
108         pixel_format = FindValidPixelFormat(mir_data);
109     }
110 
111     mir_data->pixel_format = pixel_format;
112     if (pixel_format == mir_pixel_format_invalid) {
113         return SDL_SetError("Failed to find a valid pixel format.");
114     }
115 
116     buffer_usage = mir_buffer_usage_hardware;
117     if (mir_data->software)
118         buffer_usage = mir_buffer_usage_software;
119 
120     spec = MIR_mir_connection_create_spec_for_normal_surface(mir_data->connection,
121                                                              window->w,
122                                                              window->h,
123                                                              pixel_format);
124 
125     MIR_mir_surface_spec_set_buffer_usage(spec, buffer_usage);
126     MIR_mir_surface_spec_set_name(spec, "Mir surface");
127 
128     if (window->flags & SDL_WINDOW_INPUT_FOCUS)
129         SDL_SetKeyboardFocus(window);
130 
131     mir_window->surface = MIR_mir_surface_create_sync(spec);
132     MIR_mir_surface_set_event_handler(mir_window->surface, MIR_HandleEvent, window);
133 
134     MIR_mir_surface_spec_release(spec);
135 
136     if (!MIR_mir_surface_is_valid(mir_window->surface)) {
137         return SDL_SetError("Failed to created a mir surface: %s",
138             MIR_mir_surface_get_error_message(mir_window->surface));
139     }
140 
141     if (window->flags & SDL_WINDOW_OPENGL) {
142         EGLNativeWindowType egl_native_window =
143                         (EGLNativeWindowType)MIR_mir_buffer_stream_get_egl_native_window(
144                                                        MIR_mir_surface_get_buffer_stream(mir_window->surface));
145 
146         mir_window->egl_surface = SDL_EGL_CreateSurface(_this, egl_native_window);
147 
148         if (mir_window->egl_surface == EGL_NO_SURFACE) {
149             return SDL_SetError("Failed to created a window surface %p",
150                                 _this->egl_data->egl_display);
151         }
152     }
153     else {
154         mir_window->egl_surface = EGL_NO_SURFACE;
155     }
156 
157     mir_data->current_window = mir_window;
158 
159     return 0;
160 }
161 
162 void
MIR_DestroyWindow(_THIS,SDL_Window * window)163 MIR_DestroyWindow(_THIS, SDL_Window* window)
164 {
165     MIR_Data* mir_data     = _this->driverdata;
166     MIR_Window* mir_window = window->driverdata;
167 
168     if (mir_data) {
169         SDL_EGL_DestroySurface(_this, mir_window->egl_surface);
170         MIR_mir_surface_release_sync(mir_window->surface);
171 
172         mir_data->current_window = NULL;
173 
174         SDL_free(mir_window);
175     }
176     window->driverdata = NULL;
177 }
178 
179 SDL_bool
MIR_GetWindowWMInfo(_THIS,SDL_Window * window,SDL_SysWMinfo * info)180 MIR_GetWindowWMInfo(_THIS, SDL_Window* window, SDL_SysWMinfo* info)
181 {
182     if (info->version.major == SDL_MAJOR_VERSION &&
183         info->version.minor == SDL_MINOR_VERSION) {
184         MIR_Window* mir_window = window->driverdata;
185 
186         info->subsystem = SDL_SYSWM_MIR;
187         info->info.mir.connection = mir_window->mir_data->connection;
188         info->info.mir.surface = mir_window->surface;
189 
190         return SDL_TRUE;
191     }
192 
193     return SDL_FALSE;
194 }
195 
196 void
MIR_SetWindowFullscreen(_THIS,SDL_Window * window,SDL_VideoDisplay * display,SDL_bool fullscreen)197 MIR_SetWindowFullscreen(_THIS, SDL_Window* window,
198                         SDL_VideoDisplay* display,
199                         SDL_bool fullscreen)
200 {
201     MIR_Data*   mir_data   = _this->driverdata;
202     MIR_Window* mir_window = window->driverdata;
203     MirSurfaceSpec* spec;
204     MirSurfaceState state;
205 
206     if (IsSurfaceValid(mir_window) < 0)
207         return;
208 
209     if (fullscreen) {
210         state = mir_surface_state_fullscreen;
211     } else {
212         state = mir_surface_state_restored;
213     }
214 
215     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
216     MIR_mir_surface_spec_set_state(spec, state);
217 
218     MIR_mir_surface_apply_spec(mir_window->surface, spec);
219     MIR_mir_surface_spec_release(spec);
220 }
221 
222 void
MIR_MaximizeWindow(_THIS,SDL_Window * window)223 MIR_MaximizeWindow(_THIS, SDL_Window* window)
224 {
225     MIR_Data*   mir_data   = _this->driverdata;
226     MIR_Window* mir_window = window->driverdata;
227     MirSurfaceSpec* spec;
228 
229     if (IsSurfaceValid(mir_window) < 0)
230         return;
231 
232     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
233     MIR_mir_surface_spec_set_state(spec, mir_surface_state_maximized);
234 
235     MIR_mir_surface_apply_spec(mir_window->surface, spec);
236     MIR_mir_surface_spec_release(spec);
237 }
238 
239 void
MIR_MinimizeWindow(_THIS,SDL_Window * window)240 MIR_MinimizeWindow(_THIS, SDL_Window* window)
241 {
242     MIR_Data*   mir_data   = _this->driverdata;
243     MIR_Window* mir_window = window->driverdata;
244     MirSurfaceSpec* spec;
245 
246     if (IsSurfaceValid(mir_window) < 0)
247         return;
248 
249     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
250     MIR_mir_surface_spec_set_state(spec, mir_surface_state_minimized);
251 
252     MIR_mir_surface_apply_spec(mir_window->surface, spec);
253     MIR_mir_surface_spec_release(spec);
254 }
255 
256 void
MIR_RestoreWindow(_THIS,SDL_Window * window)257 MIR_RestoreWindow(_THIS, SDL_Window * window)
258 {
259     MIR_Data*   mir_data   = _this->driverdata;
260     MIR_Window* mir_window = window->driverdata;
261     MirSurfaceSpec* spec;
262 
263     if (IsSurfaceValid(mir_window) < 0)
264         return;
265 
266     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
267     MIR_mir_surface_spec_set_state(spec, mir_surface_state_restored);
268 
269     MIR_mir_surface_apply_spec(mir_window->surface, spec);
270     MIR_mir_surface_spec_release(spec);
271 }
272 
273 void
MIR_HideWindow(_THIS,SDL_Window * window)274 MIR_HideWindow(_THIS, SDL_Window* window)
275 {
276     MIR_Data*   mir_data   = _this->driverdata;
277     MIR_Window* mir_window = window->driverdata;
278     MirSurfaceSpec* spec;
279 
280     if (IsSurfaceValid(mir_window) < 0)
281         return;
282 
283     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
284     MIR_mir_surface_spec_set_state(spec, mir_surface_state_hidden);
285 
286     MIR_mir_surface_apply_spec(mir_window->surface, spec);
287     MIR_mir_surface_spec_release(spec);
288 }
289 
290 void
MIR_SetWindowSize(_THIS,SDL_Window * window)291 MIR_SetWindowSize(_THIS, SDL_Window* window)
292 {
293     MIR_Data*   mir_data   = _this->driverdata;
294     MIR_Window* mir_window = window->driverdata;
295     MirSurfaceSpec* spec;
296 
297     if (IsSurfaceValid(mir_window) < 0)
298         return;
299 
300     /* You cannot set the x/y of a mir window! So only update w/h */
301     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
302     MIR_mir_surface_spec_set_width (spec, window->w);
303     MIR_mir_surface_spec_set_height(spec, window->h);
304 
305     MIR_mir_surface_apply_spec(mir_window->surface, spec);
306     MIR_mir_surface_spec_release(spec);
307 }
308 
309 void
MIR_SetWindowMinimumSize(_THIS,SDL_Window * window)310 MIR_SetWindowMinimumSize(_THIS, SDL_Window* window)
311 {
312     MIR_Data*   mir_data   = _this->driverdata;
313     MIR_Window* mir_window = window->driverdata;
314     MirSurfaceSpec* spec;
315 
316     if (IsSurfaceValid(mir_window) < 0)
317         return;
318 
319     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
320     MIR_mir_surface_spec_set_min_width (spec, window->min_w);
321     MIR_mir_surface_spec_set_min_height(spec, window->min_h);
322 
323     MIR_mir_surface_apply_spec(mir_window->surface, spec);
324     MIR_mir_surface_spec_release(spec);
325 }
326 
327 void
MIR_SetWindowMaximumSize(_THIS,SDL_Window * window)328 MIR_SetWindowMaximumSize(_THIS, SDL_Window* window)
329 {
330     MIR_Data*   mir_data   = _this->driverdata;
331     MIR_Window* mir_window = window->driverdata;
332     MirSurfaceSpec* spec;
333 
334     if (IsSurfaceValid(mir_window) < 0)
335         return;
336 
337     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
338     MIR_mir_surface_spec_set_max_width (spec, window->max_w);
339     MIR_mir_surface_spec_set_max_height(spec, window->max_h);
340 
341     MIR_mir_surface_apply_spec(mir_window->surface, spec);
342     MIR_mir_surface_spec_release(spec);
343 }
344 
345 void
MIR_SetWindowTitle(_THIS,SDL_Window * window)346 MIR_SetWindowTitle(_THIS, SDL_Window* window)
347 {
348     MIR_Data*   mir_data   = _this->driverdata;
349     MIR_Window* mir_window = window->driverdata;
350     char const* title = window->title ? window->title : "";
351     MirSurfaceSpec* spec;
352 
353     if (IsSurfaceValid(mir_window) < 0)
354         return;
355 
356     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
357     MIR_mir_surface_spec_set_name(spec, title);
358 
359     MIR_mir_surface_apply_spec(mir_window->surface, spec);
360     MIR_mir_surface_spec_release(spec);
361 }
362 
363 void
MIR_SetWindowGrab(_THIS,SDL_Window * window,SDL_bool grabbed)364 MIR_SetWindowGrab(_THIS, SDL_Window* window, SDL_bool grabbed)
365 {
366     MIR_Data*   mir_data   = _this->driverdata;
367     MIR_Window* mir_window = window->driverdata;
368     MirPointerConfinementState confined = mir_pointer_unconfined;
369     MirSurfaceSpec* spec;
370 
371     if (grabbed)
372         confined = mir_pointer_confined_to_surface;
373 
374     spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection);
375     MIR_mir_surface_spec_set_pointer_confinement(spec, confined);
376 
377     MIR_mir_surface_apply_spec(mir_window->surface, spec);
378     MIR_mir_surface_spec_release(spec);
379 }
380 
381 int
MIR_SetWindowGammaRamp(_THIS,SDL_Window * window,Uint16 const * ramp)382 MIR_SetWindowGammaRamp(_THIS, SDL_Window* window, Uint16 const* ramp)
383 {
384     MirOutput* output = SDL_GetDisplayForWindow(window)->driverdata;
385     Uint32 ramp_size = 256;
386 
387     // FIXME Need to apply the changes to the output, once that public API function is around
388     if (MIR_mir_output_is_gamma_supported(output) == mir_output_gamma_supported) {
389         MIR_mir_output_set_gamma(output,
390                                  ramp + ramp_size * 0,
391                                  ramp + ramp_size * 1,
392                                  ramp + ramp_size * 2,
393                                  ramp_size);
394         return 0;
395     }
396 
397     return -1;
398 }
399 
400 int
MIR_GetWindowGammaRamp(_THIS,SDL_Window * window,Uint16 * ramp)401 MIR_GetWindowGammaRamp(_THIS, SDL_Window* window, Uint16* ramp)
402 {
403     MirOutput* output = SDL_GetDisplayForWindow(window)->driverdata;
404     Uint32 ramp_size = 256;
405 
406     if (MIR_mir_output_is_gamma_supported(output) == mir_output_gamma_supported) {
407         if (MIR_mir_output_get_gamma_size(output) == ramp_size) {
408             MIR_mir_output_get_gamma(output,
409                                      ramp + ramp_size * 0,
410                                      ramp + ramp_size * 1,
411                                      ramp + ramp_size * 2,
412                                      ramp_size);
413             return 0;
414         }
415     }
416 
417     return -1;
418 }
419 
420 #endif /* SDL_VIDEO_DRIVER_MIR */
421 
422 /* vi: set ts=4 sw=4 expandtab: */
423