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_mirwindow.h"
31 #include "SDL_video.h"
32
33 #include "SDL_mirframebuffer.h"
34 #include "SDL_mirmouse.h"
35 #include "SDL_miropengl.h"
36 #include "SDL_mirvideo.h"
37
38 #include "SDL_mirdyn.h"
39
40 #define MIR_DRIVER_NAME "mir"
41
42 static const Uint32 mir_pixel_format_to_sdl_format[] = {
43 SDL_PIXELFORMAT_UNKNOWN, /* mir_pixel_format_invalid */
44 SDL_PIXELFORMAT_ABGR8888, /* mir_pixel_format_abgr_8888 */
45 SDL_PIXELFORMAT_BGR888, /* mir_pixel_format_xbgr_8888 */
46 SDL_PIXELFORMAT_ARGB8888, /* mir_pixel_format_argb_8888 */
47 SDL_PIXELFORMAT_RGB888, /* mir_pixel_format_xrgb_8888 */
48 SDL_PIXELFORMAT_BGR24, /* mir_pixel_format_bgr_888 */
49 SDL_PIXELFORMAT_RGB24, /* mir_pixel_format_rgb_888 */
50 SDL_PIXELFORMAT_RGB565, /* mir_pixel_format_rgb_565 */
51 SDL_PIXELFORMAT_RGBA5551, /* mir_pixel_format_rgba_5551 */
52 SDL_PIXELFORMAT_RGBA4444 /* mir_pixel_format_rgba_4444 */
53 };
54
55 Uint32
MIR_GetSDLPixelFormat(MirPixelFormat format)56 MIR_GetSDLPixelFormat(MirPixelFormat format)
57 {
58 return mir_pixel_format_to_sdl_format[format];
59 }
60
61 static int
62 MIR_VideoInit(_THIS);
63
64 static void
65 MIR_VideoQuit(_THIS);
66
67 static int
68 MIR_GetDisplayBounds(_THIS, SDL_VideoDisplay* display, SDL_Rect* rect);
69
70 static void
71 MIR_GetDisplayModes(_THIS, SDL_VideoDisplay* sdl_display);
72
73 static int
74 MIR_SetDisplayMode(_THIS, SDL_VideoDisplay* sdl_display, SDL_DisplayMode* mode);
75
76 static SDL_WindowShaper*
MIR_CreateShaper(SDL_Window * window)77 MIR_CreateShaper(SDL_Window* window)
78 {
79 /* FIXME Im not sure if mir support this atm, will have to come back to this */
80 return NULL;
81 }
82
83 static int
MIR_SetWindowShape(SDL_WindowShaper * shaper,SDL_Surface * shape,SDL_WindowShapeMode * shape_mode)84 MIR_SetWindowShape(SDL_WindowShaper* shaper, SDL_Surface* shape, SDL_WindowShapeMode* shape_mode)
85 {
86 return SDL_Unsupported();
87 }
88
89 static int
MIR_ResizeWindowShape(SDL_Window * window)90 MIR_ResizeWindowShape(SDL_Window* window)
91 {
92 return SDL_Unsupported();
93 }
94
95 static int
MIR_Available()96 MIR_Available()
97 {
98 int available = 0;
99
100 if (SDL_MIR_LoadSymbols()) {
101 /* !!! FIXME: try to make a MirConnection here. */
102 available = 1;
103 SDL_MIR_UnloadSymbols();
104 }
105
106 return available;
107 }
108
109 static void
MIR_DeleteDevice(SDL_VideoDevice * device)110 MIR_DeleteDevice(SDL_VideoDevice* device)
111 {
112 SDL_free(device);
113 SDL_MIR_UnloadSymbols();
114 }
115
116 static void
MIR_PumpEvents(_THIS)117 MIR_PumpEvents(_THIS)
118 {
119 }
120
121 static SDL_VideoDevice*
MIR_CreateDevice(int device_index)122 MIR_CreateDevice(int device_index)
123 {
124 MIR_Data* mir_data;
125 SDL_VideoDevice* device = NULL;
126
127 if (!SDL_MIR_LoadSymbols()) {
128 return NULL;
129 }
130
131 device = SDL_calloc(1, sizeof(SDL_VideoDevice));
132 if (!device) {
133 SDL_MIR_UnloadSymbols();
134 SDL_OutOfMemory();
135 return NULL;
136 }
137
138 mir_data = SDL_calloc(1, sizeof(MIR_Data));
139 if (!mir_data) {
140 SDL_free(device);
141 SDL_MIR_UnloadSymbols();
142 SDL_OutOfMemory();
143 return NULL;
144 }
145
146 device->driverdata = mir_data;
147
148 /* mirvideo */
149 device->VideoInit = MIR_VideoInit;
150 device->VideoQuit = MIR_VideoQuit;
151 device->GetDisplayBounds = MIR_GetDisplayBounds;
152 device->GetDisplayModes = MIR_GetDisplayModes;
153 device->SetDisplayMode = MIR_SetDisplayMode;
154 device->free = MIR_DeleteDevice;
155
156 /* miropengles */
157 device->GL_SwapWindow = MIR_GL_SwapWindow;
158 device->GL_MakeCurrent = MIR_GL_MakeCurrent;
159 device->GL_CreateContext = MIR_GL_CreateContext;
160 device->GL_DeleteContext = MIR_GL_DeleteContext;
161 device->GL_LoadLibrary = MIR_GL_LoadLibrary;
162 device->GL_UnloadLibrary = MIR_GL_UnloadLibrary;
163 device->GL_GetSwapInterval = MIR_GL_GetSwapInterval;
164 device->GL_SetSwapInterval = MIR_GL_SetSwapInterval;
165 device->GL_GetProcAddress = MIR_GL_GetProcAddress;
166
167 /* mirwindow */
168 device->CreateWindow = MIR_CreateWindow;
169 device->DestroyWindow = MIR_DestroyWindow;
170 device->GetWindowWMInfo = MIR_GetWindowWMInfo;
171 device->SetWindowFullscreen = MIR_SetWindowFullscreen;
172 device->MaximizeWindow = MIR_MaximizeWindow;
173 device->MinimizeWindow = MIR_MinimizeWindow;
174 device->RestoreWindow = MIR_RestoreWindow;
175 device->ShowWindow = MIR_RestoreWindow;
176 device->HideWindow = MIR_HideWindow;
177 device->SetWindowSize = MIR_SetWindowSize;
178 device->SetWindowMinimumSize = MIR_SetWindowMinimumSize;
179 device->SetWindowMaximumSize = MIR_SetWindowMaximumSize;
180 device->SetWindowTitle = MIR_SetWindowTitle;
181 device->SetWindowGrab = MIR_SetWindowGrab;
182 device->SetWindowGammaRamp = MIR_SetWindowGammaRamp;
183 device->GetWindowGammaRamp = MIR_GetWindowGammaRamp;
184
185 device->CreateWindowFrom = NULL;
186 device->SetWindowIcon = NULL;
187 device->RaiseWindow = NULL;
188 device->SetWindowBordered = NULL;
189 device->SetWindowResizable = NULL;
190 device->OnWindowEnter = NULL;
191 device->SetWindowPosition = NULL;
192
193 /* mirframebuffer */
194 device->CreateWindowFramebuffer = MIR_CreateWindowFramebuffer;
195 device->UpdateWindowFramebuffer = MIR_UpdateWindowFramebuffer;
196 device->DestroyWindowFramebuffer = MIR_DestroyWindowFramebuffer;
197
198 device->shape_driver.CreateShaper = MIR_CreateShaper;
199 device->shape_driver.SetWindowShape = MIR_SetWindowShape;
200 device->shape_driver.ResizeWindowShape = MIR_ResizeWindowShape;
201
202 device->PumpEvents = MIR_PumpEvents;
203
204 device->SuspendScreenSaver = NULL;
205
206 device->StartTextInput = NULL;
207 device->StopTextInput = NULL;
208 device->SetTextInputRect = NULL;
209
210 device->HasScreenKeyboardSupport = NULL;
211 device->ShowScreenKeyboard = NULL;
212 device->HideScreenKeyboard = NULL;
213 device->IsScreenKeyboardShown = NULL;
214
215 device->SetClipboardText = NULL;
216 device->GetClipboardText = NULL;
217 device->HasClipboardText = NULL;
218
219 device->ShowMessageBox = NULL;
220
221 return device;
222 }
223
224 VideoBootStrap MIR_bootstrap = {
225 MIR_DRIVER_NAME, "SDL Mir video driver",
226 MIR_Available, MIR_CreateDevice
227 };
228
229 static SDL_DisplayMode
MIR_ConvertModeToSDLMode(MirOutputMode const * mode,MirPixelFormat format)230 MIR_ConvertModeToSDLMode(MirOutputMode const* mode, MirPixelFormat format)
231 {
232 SDL_DisplayMode sdl_mode = {
233 .format = MIR_GetSDLPixelFormat(format),
234 .w = MIR_mir_output_mode_get_width(mode),
235 .h = MIR_mir_output_mode_get_height(mode),
236 .refresh_rate = MIR_mir_output_mode_get_refresh_rate(mode),
237 .driverdata = NULL
238 };
239
240 return sdl_mode;
241 }
242
243 static void
MIR_AddModeToDisplay(SDL_VideoDisplay * display,MirOutputMode const * mode,MirPixelFormat format)244 MIR_AddModeToDisplay(SDL_VideoDisplay* display, MirOutputMode const* mode, MirPixelFormat format)
245 {
246 SDL_DisplayMode sdl_mode = MIR_ConvertModeToSDLMode(mode, format);
247 SDL_AddDisplayMode(display, &sdl_mode);
248 }
249
250 static void
MIR_InitDisplayFromOutput(_THIS,MirOutput * output)251 MIR_InitDisplayFromOutput(_THIS, MirOutput* output)
252 {
253 SDL_VideoDisplay display;
254 int m;
255
256 MirPixelFormat format = MIR_mir_output_get_current_pixel_format(output);
257 int num_modes = MIR_mir_output_get_num_modes(output);
258 SDL_DisplayMode current_mode = MIR_ConvertModeToSDLMode(mir_output_get_current_mode(output), format);
259
260 SDL_zero(display);
261
262 // Unfortunate cast, but SDL_AddVideoDisplay will strdup this pointer so its read-only in this case.
263 display.name = (char*)MIR_mir_output_type_name(MIR_mir_output_get_type(output));
264
265 for (m = 0; m < num_modes; m++) {
266 MirOutputMode const* mode = MIR_mir_output_get_mode(output, m);
267 MIR_AddModeToDisplay(&display, mode, format);
268 }
269
270 display.desktop_mode = current_mode;
271 display.current_mode = current_mode;
272
273 display.driverdata = output;
274 SDL_AddVideoDisplay(&display);
275 }
276
277 static void
MIR_InitDisplays(_THIS)278 MIR_InitDisplays(_THIS)
279 {
280 MIR_Data* mir_data = _this->driverdata;
281 int num_outputs = MIR_mir_display_config_get_num_outputs(mir_data->display_config);
282 int d;
283
284 for (d = 0; d < num_outputs; d++) {
285 MirOutput* output = MIR_mir_display_config_get_mutable_output(mir_data->display_config, d);
286 SDL_bool enabled = MIR_mir_output_is_enabled(output);
287 MirOutputConnectionState state = MIR_mir_output_get_connection_state(output);
288
289 if (enabled && state == mir_output_connection_state_connected) {
290 MIR_InitDisplayFromOutput(_this, output);
291 }
292 }
293 }
294
295 static int
MIR_VideoInit(_THIS)296 MIR_VideoInit(_THIS)
297 {
298 MIR_Data* mir_data = _this->driverdata;
299
300 mir_data->connection = MIR_mir_connect_sync(NULL, __PRETTY_FUNCTION__);
301 mir_data->current_window = NULL;
302 mir_data->software = SDL_FALSE;
303 mir_data->pixel_format = mir_pixel_format_invalid;
304
305 if (!MIR_mir_connection_is_valid(mir_data->connection)) {
306 return SDL_SetError("Failed to connect to the mir server: %s",
307 MIR_mir_connection_get_error_message(mir_data->connection));
308 }
309
310 mir_data->display_config = MIR_mir_connection_create_display_configuration(mir_data->connection);
311
312 MIR_InitDisplays(_this);
313 MIR_InitMouse();
314
315 return 0;
316 }
317
318 static void
MIR_CleanUpDisplayConfig(_THIS)319 MIR_CleanUpDisplayConfig(_THIS)
320 {
321 MIR_Data* mir_data = _this->driverdata;
322 int i;
323
324 // SDL_VideoQuit frees the display driverdata, we own it not them
325 for (i = 0; i < _this->num_displays; ++i) {
326 _this->displays[i].driverdata = NULL;
327 }
328
329 MIR_mir_display_config_release(mir_data->display_config);
330 }
331
332 static void
MIR_VideoQuit(_THIS)333 MIR_VideoQuit(_THIS)
334 {
335 MIR_Data* mir_data = _this->driverdata;
336
337 MIR_CleanUpDisplayConfig(_this);
338
339 MIR_FiniMouse();
340
341 MIR_GL_DeleteContext(_this, NULL);
342 MIR_GL_UnloadLibrary(_this);
343
344 MIR_mir_connection_release(mir_data->connection);
345
346 SDL_free(mir_data);
347 _this->driverdata = NULL;
348 }
349
350 static int
MIR_GetDisplayBounds(_THIS,SDL_VideoDisplay * display,SDL_Rect * rect)351 MIR_GetDisplayBounds(_THIS, SDL_VideoDisplay* display, SDL_Rect* rect)
352 {
353 MirOutput const* output = display->driverdata;
354
355 rect->x = MIR_mir_output_get_position_x(output);
356 rect->y = MIR_mir_output_get_position_y(output);
357 rect->w = display->current_mode.w;
358 rect->h = display->current_mode.h;
359
360 return 0;
361 }
362
363 static void
MIR_GetDisplayModes(_THIS,SDL_VideoDisplay * display)364 MIR_GetDisplayModes(_THIS, SDL_VideoDisplay* display)
365 {
366 }
367
368 static int
MIR_SetDisplayMode(_THIS,SDL_VideoDisplay * display,SDL_DisplayMode * mode)369 MIR_SetDisplayMode(_THIS, SDL_VideoDisplay* display, SDL_DisplayMode* mode)
370 {
371 int m;
372 MirOutput* output = display->driverdata;
373 int num_modes = MIR_mir_output_get_num_modes(output);
374 Uint32 sdl_format = MIR_GetSDLPixelFormat(
375 MIR_mir_output_get_current_pixel_format(output));
376
377 for (m = 0; m < num_modes; m++) {
378 MirOutputMode const* mir_mode = MIR_mir_output_get_mode(output, m);
379 int width = MIR_mir_output_mode_get_width(mir_mode);
380 int height = MIR_mir_output_mode_get_height(mir_mode);
381 double refresh_rate = MIR_mir_output_mode_get_refresh_rate(mir_mode);
382
383 if (mode->format == sdl_format &&
384 mode->w == width &&
385 mode->h == height &&
386 mode->refresh_rate == refresh_rate) {
387
388 // FIXME Currently wont actually *set* anything. Need to wait for applying display changes
389 MIR_mir_output_set_current_mode(output, mir_mode);
390 return 0;
391 }
392 }
393
394 return -1;
395 }
396
397 #endif /* SDL_VIDEO_DRIVER_MIR */
398
399 /* vi: set ts=4 sw=4 expandtab: */
400
401