SDL  2.0
SDL_mirvideo.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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_assert.h"
31 #include "SDL_log.h"
32 
33 #include "SDL_mirwindow.h"
34 #include "SDL_video.h"
35 
36 #include "SDL_mirframebuffer.h"
37 #include "SDL_mirmouse.h"
38 #include "SDL_miropengl.h"
39 #include "SDL_mirvideo.h"
40 #include "SDL_mirvulkan.h"
41 
42 #include "SDL_mirdyn.h"
43 
44 #define MIR_DRIVER_NAME "mir"
45 
46 static const Uint32 mir_pixel_format_to_sdl_format[] = {
47  SDL_PIXELFORMAT_UNKNOWN, /* mir_pixel_format_invalid */
48  SDL_PIXELFORMAT_ABGR8888, /* mir_pixel_format_abgr_8888 */
49  SDL_PIXELFORMAT_BGR888, /* mir_pixel_format_xbgr_8888 */
50  SDL_PIXELFORMAT_ARGB8888, /* mir_pixel_format_argb_8888 */
51  SDL_PIXELFORMAT_RGB888, /* mir_pixel_format_xrgb_8888 */
52  SDL_PIXELFORMAT_BGR24, /* mir_pixel_format_bgr_888 */
53  SDL_PIXELFORMAT_RGB24, /* mir_pixel_format_rgb_888 */
54  SDL_PIXELFORMAT_RGB565, /* mir_pixel_format_rgb_565 */
55  SDL_PIXELFORMAT_RGBA5551, /* mir_pixel_format_rgba_5551 */
56  SDL_PIXELFORMAT_RGBA4444 /* mir_pixel_format_rgba_4444 */
57 };
58 
59 Uint32
60 MIR_GetSDLPixelFormat(MirPixelFormat format)
61 {
62  return mir_pixel_format_to_sdl_format[format];
63 }
64 
65 static int
66 MIR_VideoInit(_THIS);
67 
68 static void
69 MIR_VideoQuit(_THIS);
70 
71 static int
72 MIR_GetDisplayBounds(_THIS, SDL_VideoDisplay* display, SDL_Rect* rect);
73 
74 static void
75 MIR_GetDisplayModes(_THIS, SDL_VideoDisplay* sdl_display);
76 
77 static int
78 MIR_SetDisplayMode(_THIS, SDL_VideoDisplay* sdl_display, SDL_DisplayMode* mode);
79 
80 static SDL_WindowShaper*
81 MIR_CreateShaper(SDL_Window* window)
82 {
83  /* FIXME Im not sure if mir support this atm, will have to come back to this */
84  return NULL;
85 }
86 
87 static int
88 MIR_SetWindowShape(SDL_WindowShaper* shaper, SDL_Surface* shape, SDL_WindowShapeMode* shape_mode)
89 {
90  return SDL_Unsupported();
91 }
92 
93 static int
94 MIR_ResizeWindowShape(SDL_Window* window)
95 {
96  return SDL_Unsupported();
97 }
98 
99 static int
100 MIR_Available()
101 {
102  int available = 0;
103 
104  if (SDL_MIR_LoadSymbols()) {
105 
106  /* Lets ensure we can connect to the mir server */
107  MirConnection* connection = MIR_mir_connect_sync(NULL, SDL_FUNCTION);
108 
109  if (!MIR_mir_connection_is_valid(connection)) {
110  SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Unable to connect to the mir server %s",
111  MIR_mir_connection_get_error_message(connection));
112 
113  return available;
114  }
115 
116  MIR_mir_connection_release(connection);
117 
118  available = 1;
120  }
121 
122  return available;
123 }
124 
125 static void
126 MIR_DeleteDevice(SDL_VideoDevice* device)
127 {
128  SDL_free(device);
130 }
131 
132 static void
133 MIR_PumpEvents(_THIS)
134 {
135 }
136 
137 static SDL_VideoDevice*
138 MIR_CreateDevice(int device_index)
139 {
140  MIR_Data* mir_data;
142 
143  if (!SDL_MIR_LoadSymbols()) {
144  return NULL;
145  }
146 
147  device = SDL_calloc(1, sizeof(SDL_VideoDevice));
148  if (!device) {
150  SDL_OutOfMemory();
151  return NULL;
152  }
153 
154  mir_data = SDL_calloc(1, sizeof(MIR_Data));
155  if (!mir_data) {
156  SDL_free(device);
158  SDL_OutOfMemory();
159  return NULL;
160  }
161 
162  device->driverdata = mir_data;
163 
164  /* mirvideo */
165  device->VideoInit = MIR_VideoInit;
166  device->VideoQuit = MIR_VideoQuit;
167  device->GetDisplayBounds = MIR_GetDisplayBounds;
168  device->GetDisplayModes = MIR_GetDisplayModes;
169  device->SetDisplayMode = MIR_SetDisplayMode;
170  device->free = MIR_DeleteDevice;
171 
172  /* miropengles */
182 
183  /* mirwindow */
191  device->ShowWindow = MIR_RestoreWindow;
192  device->HideWindow = MIR_HideWindow;
200 
201  device->CreateSDLWindowFrom = NULL;
202  device->SetWindowIcon = NULL;
203  device->RaiseWindow = NULL;
204  device->SetWindowBordered = NULL;
205  device->SetWindowResizable = NULL;
206  device->OnWindowEnter = NULL;
207  device->SetWindowPosition = NULL;
208 
209  /* mirframebuffer */
213 
214  device->shape_driver.CreateShaper = MIR_CreateShaper;
215  device->shape_driver.SetWindowShape = MIR_SetWindowShape;
216  device->shape_driver.ResizeWindowShape = MIR_ResizeWindowShape;
217 
218  device->PumpEvents = MIR_PumpEvents;
219 
220  device->SuspendScreenSaver = NULL;
221 
222  device->StartTextInput = NULL;
223  device->StopTextInput = NULL;
224  device->SetTextInputRect = NULL;
225 
226  device->HasScreenKeyboardSupport = NULL;
227  device->ShowScreenKeyboard = NULL;
228  device->HideScreenKeyboard = NULL;
229  device->IsScreenKeyboardShown = NULL;
230 
231  device->SetClipboardText = NULL;
232  device->GetClipboardText = NULL;
233  device->HasClipboardText = NULL;
234 
235  device->ShowMessageBox = NULL;
236 
237 #if SDL_VIDEO_VULKAN
238  device->Vulkan_LoadLibrary = MIR_Vulkan_LoadLibrary;
239  device->Vulkan_UnloadLibrary = MIR_Vulkan_UnloadLibrary;
240  device->Vulkan_GetInstanceExtensions = MIR_Vulkan_GetInstanceExtensions;
241  device->Vulkan_CreateSurface = MIR_Vulkan_CreateSurface;
242 #endif
243 
244  return device;
245 }
246 
248  MIR_DRIVER_NAME, "SDL Mir video driver",
249  MIR_Available, MIR_CreateDevice
250 };
251 
252 static SDL_DisplayMode
253 MIR_ConvertModeToSDLMode(MirOutputMode const* mode, MirPixelFormat format)
254 {
255  SDL_DisplayMode sdl_mode = {
256  .format = MIR_GetSDLPixelFormat(format),
257  .w = MIR_mir_output_mode_get_width(mode),
258  .h = MIR_mir_output_mode_get_height(mode),
259  .refresh_rate = MIR_mir_output_mode_get_refresh_rate(mode),
260  .driverdata = NULL
261  };
262 
263  return sdl_mode;
264 }
265 
266 static void
267 MIR_AddModeToDisplay(SDL_VideoDisplay* display, MirOutputMode const* mode, MirPixelFormat format)
268 {
269  SDL_DisplayMode sdl_mode = MIR_ConvertModeToSDLMode(mode, format);
270  SDL_AddDisplayMode(display, &sdl_mode);
271 }
272 
273 static void
274 MIR_InitDisplayFromOutput(_THIS, MirOutput* output)
275 {
276  SDL_VideoDisplay display;
277  int m;
278 
279  MirPixelFormat format = MIR_mir_output_get_current_pixel_format(output);
280  int num_modes = MIR_mir_output_get_num_modes(output);
281  SDL_DisplayMode current_mode = MIR_ConvertModeToSDLMode(MIR_mir_output_get_current_mode(output), format);
282 
283  SDL_zero(display);
284 
285  // Unfortunate cast, but SDL_AddVideoDisplay will strdup this pointer so its read-only in this case.
286  display.name = (char*)MIR_mir_output_type_name(MIR_mir_output_get_type(output));
287 
288  for (m = 0; m < num_modes; m++) {
289  MirOutputMode const* mode = MIR_mir_output_get_mode(output, m);
290  MIR_AddModeToDisplay(&display, mode, format);
291  }
292 
293  display.desktop_mode = current_mode;
294  display.current_mode = current_mode;
295 
296  display.driverdata = output;
297  SDL_AddVideoDisplay(&display);
298 }
299 
300 static void
301 MIR_InitDisplays(_THIS)
302 {
303  MIR_Data* mir_data = _this->driverdata;
304  int num_outputs = MIR_mir_display_config_get_num_outputs(mir_data->display_config);
305  int d;
306 
307  for (d = 0; d < num_outputs; d++) {
308  MirOutput* output = MIR_mir_display_config_get_mutable_output(mir_data->display_config, d);
309  SDL_bool enabled = MIR_mir_output_is_enabled(output);
310  MirOutputConnectionState state = MIR_mir_output_get_connection_state(output);
311 
312  if (enabled && state == mir_output_connection_state_connected) {
313  MIR_InitDisplayFromOutput(_this, output);
314  }
315  }
316 }
317 
318 static int
319 MIR_VideoInit(_THIS)
320 {
321  MIR_Data* mir_data = _this->driverdata;
322 
323  mir_data->connection = MIR_mir_connect_sync(NULL, SDL_FUNCTION);
324  mir_data->current_window = NULL;
325  mir_data->software = SDL_FALSE;
326  mir_data->pixel_format = mir_pixel_format_invalid;
327 
328  if (!MIR_mir_connection_is_valid(mir_data->connection)) {
329  return SDL_SetError("Failed to connect to the mir server: %s",
330  MIR_mir_connection_get_error_message(mir_data->connection));
331  }
332 
333  mir_data->display_config = MIR_mir_connection_create_display_configuration(mir_data->connection);
334 
335  MIR_InitDisplays(_this);
336  MIR_InitMouse();
337 
338  return 0;
339 }
340 
341 static void
342 MIR_CleanUpDisplayConfig(_THIS)
343 {
344  MIR_Data* mir_data = _this->driverdata;
345  int i;
346 
347  // SDL_VideoQuit frees the display driverdata, we own it not them
348  for (i = 0; i < _this->num_displays; ++i) {
350  }
351 
352  MIR_mir_display_config_release(mir_data->display_config);
353 }
354 
355 static void
356 MIR_VideoQuit(_THIS)
357 {
358  MIR_Data* mir_data = _this->driverdata;
359 
360  MIR_CleanUpDisplayConfig(_this);
361 
362  MIR_FiniMouse();
363 
366 
367  MIR_mir_connection_release(mir_data->connection);
368 
369  SDL_free(mir_data);
370  _this->driverdata = NULL;
371 }
372 
373 static int
374 MIR_GetDisplayBounds(_THIS, SDL_VideoDisplay* display, SDL_Rect* rect)
375 {
376  MirOutput const* output = display->driverdata;
377 
378  rect->x = MIR_mir_output_get_position_x(output);
379  rect->y = MIR_mir_output_get_position_y(output);
380  rect->w = display->current_mode.w;
381  rect->h = display->current_mode.h;
382 
383  return 0;
384 }
385 
386 static void
387 MIR_GetDisplayModes(_THIS, SDL_VideoDisplay* display)
388 {
389 }
390 
391 static int
392 MIR_SetDisplayMode(_THIS, SDL_VideoDisplay* display, SDL_DisplayMode* mode)
393 {
394  int m;
395  MirOutput* output = display->driverdata;
396  int num_modes = MIR_mir_output_get_num_modes(output);
397  Uint32 sdl_format = MIR_GetSDLPixelFormat(
398  MIR_mir_output_get_current_pixel_format(output));
399 
400  for (m = 0; m < num_modes; m++) {
401  MirOutputMode const* mir_mode = MIR_mir_output_get_mode(output, m);
402  int width = MIR_mir_output_mode_get_width(mir_mode);
403  int height = MIR_mir_output_mode_get_height(mir_mode);
404  double refresh_rate = MIR_mir_output_mode_get_refresh_rate(mir_mode);
405 
406  if (mode->format == sdl_format &&
407  mode->w == width &&
408  mode->h == height &&
409  mode->refresh_rate == refresh_rate) {
410 
411  // FIXME Currently wont actually *set* anything. Need to wait for applying display changes
412  MIR_mir_output_set_current_mode(output, mir_mode);
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