• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //========================================================================
2 // GLFW 3.2 Mir - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
5 //
6 // This software is provided 'as-is', without any express or implied
7 // warranty. In no event will the authors be held liable for any damages
8 // arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it
12 // freely, subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented; you must not
15 //    claim that you wrote the original software. If you use this software
16 //    in a product, an acknowledgment in the product documentation would
17 //    be appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such, and must not
20 //    be misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source
23 //    distribution.
24 //
25 //========================================================================
26 
27 #include "internal.h"
28 
29 #include <linux/input.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 
34 typedef struct EventNode
35 {
36     TAILQ_ENTRY(EventNode) entries;
37     const MirEvent*        event;
38     _GLFWwindow*           window;
39 } EventNode;
40 
deleteNode(EventQueue * queue,EventNode * node)41 static void deleteNode(EventQueue* queue, EventNode* node)
42 {
43     mir_event_unref(node->event);
44     free(node);
45 }
46 
emptyEventQueue(EventQueue * queue)47 static GLFWbool emptyEventQueue(EventQueue* queue)
48 {
49     return queue->head.tqh_first == NULL;
50 }
51 
52 // TODO The mir_event_ref is not supposed to be used but ... its needed
53 //      in this case. Need to wait until we can read from an FD set up by mir
54 //      for single threaded event handling.
newEventNode(const MirEvent * event,_GLFWwindow * context)55 static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
56 {
57     EventNode* new_node = calloc(1, sizeof(EventNode));
58     new_node->event     = mir_event_ref(event);
59     new_node->window    = context;
60 
61     return new_node;
62 }
63 
enqueueEvent(const MirEvent * event,_GLFWwindow * context)64 static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
65 {
66     pthread_mutex_lock(&_glfw.mir.event_mutex);
67 
68     EventNode* new_node = newEventNode(event, context);
69     TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries);
70 
71     pthread_cond_signal(&_glfw.mir.event_cond);
72 
73     pthread_mutex_unlock(&_glfw.mir.event_mutex);
74 }
75 
dequeueEvent(EventQueue * queue)76 static EventNode* dequeueEvent(EventQueue* queue)
77 {
78     EventNode* node = NULL;
79 
80     pthread_mutex_lock(&_glfw.mir.event_mutex);
81 
82     node = queue->head.tqh_first;
83 
84     if (node)
85         TAILQ_REMOVE(&queue->head, node, entries);
86 
87     pthread_mutex_unlock(&_glfw.mir.event_mutex);
88 
89     return node;
90 }
91 
92 /* FIXME Soon to be changed upstream mir! So we can use an egl config to figure out
93          the best pixel format!
94 */
findValidPixelFormat(void)95 static MirPixelFormat findValidPixelFormat(void)
96 {
97     unsigned int i, validFormats, mirPixelFormats = 32;
98     MirPixelFormat formats[mir_pixel_formats];
99 
100     mir_connection_get_available_surface_formats(_glfw.mir.connection, formats,
101                                                  mirPixelFormats, &validFormats);
102 
103     for (i = 0;  i < validFormats;  i++)
104     {
105         if (formats[i] == mir_pixel_format_abgr_8888 ||
106             formats[i] == mir_pixel_format_xbgr_8888 ||
107             formats[i] == mir_pixel_format_argb_8888 ||
108             formats[i] == mir_pixel_format_xrgb_8888)
109         {
110             return formats[i];
111         }
112     }
113 
114     return mir_pixel_format_invalid;
115 }
116 
mirModToGLFWMod(uint32_t mods)117 static int mirModToGLFWMod(uint32_t mods)
118 {
119     int publicMods = 0x0;
120 
121     if (mods & mir_input_event_modifier_alt)
122         publicMods |= GLFW_MOD_ALT;
123     else if (mods & mir_input_event_modifier_shift)
124         publicMods |= GLFW_MOD_SHIFT;
125     else if (mods & mir_input_event_modifier_ctrl)
126         publicMods |= GLFW_MOD_CONTROL;
127     else if (mods & mir_input_event_modifier_meta)
128         publicMods |= GLFW_MOD_SUPER;
129 
130     return publicMods;
131 }
132 
toGLFWKeyCode(uint32_t key)133 static int toGLFWKeyCode(uint32_t key)
134 {
135     if (key < sizeof(_glfw.mir.publicKeys) / sizeof(_glfw.mir.publicKeys[0]))
136         return _glfw.mir.publicKeys[key];
137 
138     return GLFW_KEY_UNKNOWN;
139 }
140 
handleKeyEvent(const MirKeyboardEvent * key_event,_GLFWwindow * window)141 static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
142 {
143     const int action    = mir_keyboard_event_action   (key_event);
144     const int scan_code = mir_keyboard_event_scan_code(key_event);
145     const int key_code  = mir_keyboard_event_key_code (key_event);
146     const int modifiers = mir_keyboard_event_modifiers(key_event);
147 
148     const int  pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS;
149     const int  mods    = mirModToGLFWMod(modifiers);
150     const long text    = _glfwKeySym2Unicode(key_code);
151     const int  plain   = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
152 
153     _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
154 
155     if (text != -1)
156         _glfwInputChar(window, text, mods, plain);
157 }
158 
handlePointerButton(_GLFWwindow * window,int pressed,const MirPointerEvent * pointer_event)159 static void handlePointerButton(_GLFWwindow* window,
160                               int pressed,
161                               const MirPointerEvent* pointer_event)
162 {
163     int mods                = mir_pointer_event_modifiers(pointer_event);
164     const int publicMods    = mirModToGLFWMod(mods);
165     MirPointerButton button = mir_pointer_button_primary;
166     static uint32_t oldButtonStates = 0;
167     uint32_t newButtonStates        = mir_pointer_event_buttons(pointer_event);
168     int publicButton                = GLFW_MOUSE_BUTTON_LEFT;
169 
170     // XOR our old button states our new states to figure out what was added or removed
171     button = newButtonStates ^ oldButtonStates;
172 
173     switch (button)
174     {
175         case mir_pointer_button_primary:
176             publicButton = GLFW_MOUSE_BUTTON_LEFT;
177             break;
178         case mir_pointer_button_secondary:
179             publicButton = GLFW_MOUSE_BUTTON_RIGHT;
180             break;
181         case mir_pointer_button_tertiary:
182             publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
183             break;
184         case mir_pointer_button_forward:
185             // FIXME What is the forward button?
186             publicButton = GLFW_MOUSE_BUTTON_4;
187             break;
188         case mir_pointer_button_back:
189             // FIXME What is the back button?
190             publicButton = GLFW_MOUSE_BUTTON_5;
191             break;
192         default:
193             break;
194     }
195 
196     oldButtonStates = newButtonStates;
197 
198     _glfwInputMouseClick(window, publicButton, pressed, publicMods);
199 }
200 
handlePointerMotion(_GLFWwindow * window,const MirPointerEvent * pointer_event)201 static void handlePointerMotion(_GLFWwindow* window,
202                                 const MirPointerEvent* pointer_event)
203 {
204     int current_x = window->virtualCursorPosX;
205     int current_y = window->virtualCursorPosY;
206     int x  = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
207     int y  = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
208     int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
209     int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
210 
211     _glfwInputCursorPos(window, x, y);
212     if (dx != 0 || dy != 0)
213       _glfwInputScroll(window, dx, dy);
214 }
215 
handlePointerEvent(const MirPointerEvent * pointer_event,_GLFWwindow * window)216 static void handlePointerEvent(const MirPointerEvent* pointer_event,
217                              _GLFWwindow* window)
218 {
219     int action = mir_pointer_event_action(pointer_event);
220 
221     switch (action)
222     {
223           case mir_pointer_action_button_down:
224               handlePointerButton(window, GLFW_PRESS, pointer_event);
225               break;
226           case mir_pointer_action_button_up:
227               handlePointerButton(window, GLFW_RELEASE, pointer_event);
228               break;
229           case mir_pointer_action_motion:
230               handlePointerMotion(window, pointer_event);
231               break;
232           case mir_pointer_action_enter:
233           case mir_pointer_action_leave:
234               break;
235           default:
236               break;
237 
238     }
239 }
240 
handleInput(const MirInputEvent * input_event,_GLFWwindow * window)241 static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
242 {
243     int type = mir_input_event_get_type(input_event);
244 
245     switch (type)
246     {
247         case mir_input_event_type_key:
248             handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
249             break;
250         case mir_input_event_type_pointer:
251             handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
252             break;
253         default:
254             break;
255     }
256 }
257 
handleEvent(const MirEvent * event,_GLFWwindow * window)258 static void handleEvent(const MirEvent* event, _GLFWwindow* window)
259 {
260     int type = mir_event_get_type(event);
261 
262     switch (type)
263     {
264         case mir_event_type_input:
265             handleInput(mir_event_get_input_event(event), window);
266             break;
267         default:
268             break;
269     }
270 }
271 
addNewEvent(MirSurface * surface,const MirEvent * event,void * context)272 static void addNewEvent(MirSurface* surface, const MirEvent* event, void* context)
273 {
274     enqueueEvent(event, context);
275 }
276 
createSurface(_GLFWwindow * window)277 static GLFWbool createSurface(_GLFWwindow* window)
278 {
279     MirSurfaceSpec* spec;
280     MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
281     MirPixelFormat pixel_format = findValidPixelFormat();
282 
283     if (pixel_format == mir_pixel_format_invalid)
284     {
285         _glfwInputError(GLFW_PLATFORM_ERROR,
286                         "Mir: Unable to find a correct pixel format");
287         return GLFW_FALSE;
288     }
289 
290     spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection,
291                                                          window->mir.width,
292                                                          window->mir.height,
293                                                          pixel_format);
294 
295     mir_surface_spec_set_buffer_usage(spec, buffer_usage);
296     mir_surface_spec_set_name(spec, "MirSurface");
297 
298     window->mir.surface = mir_surface_create_sync(spec);
299     mir_surface_spec_release(spec);
300 
301     if (!mir_surface_is_valid(window->mir.surface))
302     {
303         _glfwInputError(GLFW_PLATFORM_ERROR,
304                         "Mir: Unable to create surface: %s",
305                         mir_surface_get_error_message(window->mir.surface));
306 
307         return GLFW_FALSE;
308     }
309 
310     mir_surface_set_event_handler(window->mir.surface, addNewEvent, window);
311 
312     return GLFW_TRUE;
313 }
314 
315 //////////////////////////////////////////////////////////////////////////
316 //////                       GLFW internal API                      //////
317 //////////////////////////////////////////////////////////////////////////
318 
_glfwInitEventQueueMir(EventQueue * queue)319 void _glfwInitEventQueueMir(EventQueue* queue)
320 {
321     TAILQ_INIT(&queue->head);
322 }
323 
_glfwDeleteEventQueueMir(EventQueue * queue)324 void _glfwDeleteEventQueueMir(EventQueue* queue)
325 {
326     if (queue)
327     {
328         EventNode* node, *node_next;
329         node = queue->head.tqh_first;
330 
331         while (node != NULL)
332         {
333             node_next = node->entries.tqe_next;
334 
335             TAILQ_REMOVE(&queue->head, node, entries);
336             deleteNode(queue, node);
337 
338             node = node_next;
339         }
340 
341         free(queue);
342     }
343 }
344 
345 //////////////////////////////////////////////////////////////////////////
346 //////                       GLFW platform API                      //////
347 //////////////////////////////////////////////////////////////////////////
348 
_glfwPlatformCreateWindow(_GLFWwindow * window,const _GLFWwndconfig * wndconfig,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)349 int _glfwPlatformCreateWindow(_GLFWwindow* window,
350                               const _GLFWwndconfig* wndconfig,
351                               const _GLFWctxconfig* ctxconfig,
352                               const _GLFWfbconfig* fbconfig)
353 {
354     if (window->monitor)
355     {
356         GLFWvidmode mode;
357         _glfwPlatformGetVideoMode(window->monitor, &mode);
358 
359         mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen);
360 
361         if (wndconfig->width > mode.width || wndconfig->height > mode.height)
362         {
363             _glfwInputError(GLFW_PLATFORM_ERROR,
364                             "Mir: Requested surface size too large: %ix%i",
365                             wndconfig->width, wndconfig->height);
366 
367             return GLFW_FALSE;
368         }
369     }
370 
371     window->mir.width  = wndconfig->width;
372     window->mir.height = wndconfig->height;
373 
374     if (!createSurface(window))
375         return GLFW_FALSE;
376 
377     window->mir.window = mir_buffer_stream_get_egl_native_window(
378                                    mir_surface_get_buffer_stream(window->mir.surface));
379 
380     if (ctxconfig->client != GLFW_NO_API)
381     {
382         if (!_glfwInitEGL())
383             return GLFW_FALSE;
384         if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
385             return GLFW_FALSE;
386     }
387 
388     return GLFW_TRUE;
389 }
390 
_glfwPlatformDestroyWindow(_GLFWwindow * window)391 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
392 {
393     if (mir_surface_is_valid(window->mir.surface))
394     {
395         mir_surface_release_sync(window->mir.surface);
396         window->mir.surface = NULL;
397     }
398 
399     if (window->context.destroy)
400         window->context.destroy(window);
401 }
402 
_glfwPlatformSetWindowTitle(_GLFWwindow * window,const char * title)403 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
404 {
405     MirSurfaceSpec* spec;
406     const char* e_title = title ? title : "";
407 
408     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
409     mir_surface_spec_set_name(spec, e_title);
410 
411     mir_surface_apply_spec(window->mir.surface, spec);
412     mir_surface_spec_release(spec);
413 }
414 
_glfwPlatformSetWindowIcon(_GLFWwindow * window,int count,const GLFWimage * images)415 void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
416                                 int count, const GLFWimage* images)
417 {
418     _glfwInputError(GLFW_PLATFORM_ERROR,
419                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
420 }
421 
_glfwPlatformSetWindowSize(_GLFWwindow * window,int width,int height)422 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
423 {
424     MirSurfaceSpec* spec;
425 
426     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
427     mir_surface_spec_set_width (spec, width);
428     mir_surface_spec_set_height(spec, height);
429 
430     mir_surface_apply_spec(window->mir.surface, spec);
431     mir_surface_spec_release(spec);
432 }
433 
_glfwPlatformSetWindowSizeLimits(_GLFWwindow * window,int minwidth,int minheight,int maxwidth,int maxheight)434 void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
435                                       int minwidth, int minheight,
436                                       int maxwidth, int maxheight)
437 {
438     _glfwInputError(GLFW_PLATFORM_ERROR,
439                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
440 }
441 
_glfwPlatformSetWindowAspectRatio(_GLFWwindow * window,int numer,int denom)442 void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
443 {
444     _glfwInputError(GLFW_PLATFORM_ERROR,
445                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
446 }
447 
_glfwPlatformSetWindowPos(_GLFWwindow * window,int xpos,int ypos)448 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
449 {
450     _glfwInputError(GLFW_PLATFORM_ERROR,
451                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
452 }
453 
_glfwPlatformGetWindowFrameSize(_GLFWwindow * window,int * left,int * top,int * right,int * bottom)454 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
455                                      int* left, int* top,
456                                      int* right, int* bottom)
457 {
458     _glfwInputError(GLFW_PLATFORM_ERROR,
459                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
460 }
461 
_glfwPlatformGetWindowPos(_GLFWwindow * window,int * xpos,int * ypos)462 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
463 {
464     _glfwInputError(GLFW_PLATFORM_ERROR,
465                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
466 }
467 
_glfwPlatformGetWindowSize(_GLFWwindow * window,int * width,int * height)468 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
469 {
470     if (width)
471         *width  = window->mir.width;
472     if (height)
473         *height = window->mir.height;
474 }
475 
_glfwPlatformIconifyWindow(_GLFWwindow * window)476 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
477 {
478     mir_surface_set_state(window->mir.surface, mir_surface_state_minimized);
479 }
480 
_glfwPlatformRestoreWindow(_GLFWwindow * window)481 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
482 {
483     mir_surface_set_state(window->mir.surface, mir_surface_state_restored);
484 }
485 
_glfwPlatformMaximizeWindow(_GLFWwindow * window)486 void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
487 {
488     _glfwInputError(GLFW_PLATFORM_ERROR,
489                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
490 }
491 
_glfwPlatformHideWindow(_GLFWwindow * window)492 void _glfwPlatformHideWindow(_GLFWwindow* window)
493 {
494     MirSurfaceSpec* spec;
495 
496     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
497     mir_surface_spec_set_state(spec, mir_surface_state_hidden);
498 
499     mir_surface_apply_spec(window->mir.surface, spec);
500     mir_surface_spec_release(spec);
501 }
502 
_glfwPlatformShowWindow(_GLFWwindow * window)503 void _glfwPlatformShowWindow(_GLFWwindow* window)
504 {
505     MirSurfaceSpec* spec;
506 
507     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
508     mir_surface_spec_set_state(spec, mir_surface_state_restored);
509 
510     mir_surface_apply_spec(window->mir.surface, spec);
511     mir_surface_spec_release(spec);
512 }
513 
_glfwPlatformFocusWindow(_GLFWwindow * window)514 void _glfwPlatformFocusWindow(_GLFWwindow* window)
515 {
516     _glfwInputError(GLFW_PLATFORM_ERROR,
517                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
518 }
519 
_glfwPlatformSetWindowMonitor(_GLFWwindow * window,_GLFWmonitor * monitor,int xpos,int ypos,int width,int height,int refreshRate)520 void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
521                                    _GLFWmonitor* monitor,
522                                    int xpos, int ypos,
523                                    int width, int height,
524                                    int refreshRate)
525 {
526     _glfwInputError(GLFW_PLATFORM_ERROR,
527                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
528 }
529 
_glfwPlatformWindowFocused(_GLFWwindow * window)530 int _glfwPlatformWindowFocused(_GLFWwindow* window)
531 {
532     _glfwInputError(GLFW_PLATFORM_ERROR,
533                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
534     return GLFW_FALSE;
535 }
536 
_glfwPlatformWindowIconified(_GLFWwindow * window)537 int _glfwPlatformWindowIconified(_GLFWwindow* window)
538 {
539     _glfwInputError(GLFW_PLATFORM_ERROR,
540                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
541     return GLFW_FALSE;
542 }
543 
_glfwPlatformWindowVisible(_GLFWwindow * window)544 int _glfwPlatformWindowVisible(_GLFWwindow* window)
545 {
546     return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed;
547 }
548 
_glfwPlatformWindowMaximized(_GLFWwindow * window)549 int _glfwPlatformWindowMaximized(_GLFWwindow* window)
550 {
551     _glfwInputError(GLFW_PLATFORM_ERROR,
552                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
553     return GLFW_FALSE;
554 }
555 
_glfwPlatformPollEvents(void)556 void _glfwPlatformPollEvents(void)
557 {
558     EventNode* node = NULL;
559 
560     while ((node = dequeueEvent(_glfw.mir.event_queue)))
561     {
562         handleEvent(node->event, node->window);
563         deleteNode(_glfw.mir.event_queue, node);
564     }
565 }
566 
_glfwPlatformWaitEvents(void)567 void _glfwPlatformWaitEvents(void)
568 {
569     pthread_mutex_lock(&_glfw.mir.event_mutex);
570 
571     if (emptyEventQueue(_glfw.mir.event_queue))
572         pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex);
573 
574     pthread_mutex_unlock(&_glfw.mir.event_mutex);
575 
576     _glfwPlatformPollEvents();
577 }
578 
_glfwPlatformWaitEventsTimeout(double timeout)579 void _glfwPlatformWaitEventsTimeout(double timeout)
580 {
581     pthread_mutex_lock(&_glfw.mir.event_mutex);
582 
583     if (emptyEventQueue(_glfw.mir.event_queue))
584     {
585         struct timespec time;
586         clock_gettime(CLOCK_REALTIME, &time);
587         time.tv_sec += (long) timeout;
588         time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
589         pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time);
590     }
591 
592     pthread_mutex_unlock(&_glfw.mir.event_mutex);
593 
594     _glfwPlatformPollEvents();
595 }
596 
_glfwPlatformPostEmptyEvent(void)597 void _glfwPlatformPostEmptyEvent(void)
598 {
599 }
600 
_glfwPlatformGetFramebufferSize(_GLFWwindow * window,int * width,int * height)601 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
602 {
603     if (width)
604         *width  = window->mir.width;
605     if (height)
606         *height = window->mir.height;
607 }
608 
609 // FIXME implement
_glfwPlatformCreateCursor(_GLFWcursor * cursor,const GLFWimage * image,int xhot,int yhot)610 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
611                               const GLFWimage* image,
612                               int xhot, int yhot)
613 {
614     MirBufferStream* stream;
615     MirPixelFormat pixel_format = findValidPixelFormat();
616 
617     int i_w = image->width;
618     int i_h = image->height;
619 
620     if (pixel_format == mir_pixel_format_invalid)
621     {
622         _glfwInputError(GLFW_PLATFORM_ERROR,
623                         "Mir: Unable to find a correct pixel format");
624         return GLFW_FALSE;
625     }
626 
627     stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection,
628                                                       i_w, i_h,
629                                                       pixel_format,
630                                                       mir_buffer_usage_software);
631 
632     cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot);
633 
634     char* dest;
635     unsigned char *pixels;
636     int i, r_stride, bytes_per_pixel, bytes_per_row;
637 
638     MirGraphicsRegion region;
639     mir_buffer_stream_get_graphics_region(stream, &region);
640 
641     // FIXME Figure this out based on the current_pf
642     bytes_per_pixel = 4;
643     bytes_per_row   = bytes_per_pixel * i_w;
644 
645     dest   = region.vaddr;
646     pixels = image->pixels;
647 
648     r_stride = region.stride;
649 
650     for (i = 0; i < i_h; i++)
651     {
652         memcpy(dest, pixels, bytes_per_row);
653         dest   += r_stride;
654         pixels += r_stride;
655     }
656 
657     cursor->mir.custom_cursor = stream;
658 
659     return GLFW_TRUE;
660 }
661 
getSystemCursorName(int shape)662 const char* getSystemCursorName(int shape)
663 {
664     switch (shape)
665     {
666         case GLFW_ARROW_CURSOR:
667             return mir_arrow_cursor_name;
668         case GLFW_IBEAM_CURSOR:
669             return mir_caret_cursor_name;
670         case GLFW_CROSSHAIR_CURSOR:
671             return mir_crosshair_cursor_name;
672         case GLFW_HAND_CURSOR:
673             return mir_open_hand_cursor_name;
674         case GLFW_HRESIZE_CURSOR:
675             return mir_horizontal_resize_cursor_name;
676         case GLFW_VRESIZE_CURSOR:
677             return mir_vertical_resize_cursor_name;
678     }
679 
680     return NULL;
681 }
682 
_glfwPlatformCreateStandardCursor(_GLFWcursor * cursor,int shape)683 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
684 {
685     const char* cursor_name = getSystemCursorName(shape);
686 
687     if (cursor_name)
688     {
689         cursor->mir.conf          = mir_cursor_configuration_from_name(cursor_name);
690         cursor->mir.custom_cursor = NULL;
691 
692         return GLFW_TRUE;
693     }
694 
695     return GLFW_FALSE;
696 }
697 
_glfwPlatformDestroyCursor(_GLFWcursor * cursor)698 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
699 {
700     if (cursor->mir.conf)
701         mir_cursor_configuration_destroy(cursor->mir.conf);
702     if (cursor->mir.custom_cursor)
703         mir_buffer_stream_release_sync(cursor->mir.custom_cursor);
704 }
705 
_glfwPlatformSetCursor(_GLFWwindow * window,_GLFWcursor * cursor)706 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
707 {
708     if (cursor && cursor->mir.conf)
709     {
710         mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf));
711         if (cursor->mir.custom_cursor)
712         {
713             mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor);
714         }
715     }
716     else
717     {
718         mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf));
719     }
720 }
721 
_glfwPlatformGetCursorPos(_GLFWwindow * window,double * xpos,double * ypos)722 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
723 {
724     _glfwInputError(GLFW_PLATFORM_ERROR,
725                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
726 }
727 
_glfwPlatformSetCursorPos(_GLFWwindow * window,double xpos,double ypos)728 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
729 {
730     _glfwInputError(GLFW_PLATFORM_ERROR,
731                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
732 }
733 
_glfwPlatformSetCursorMode(_GLFWwindow * window,int mode)734 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
735 {
736     _glfwInputError(GLFW_PLATFORM_ERROR,
737                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
738 }
739 
_glfwPlatformGetKeyName(int key,int scancode)740 const char* _glfwPlatformGetKeyName(int key, int scancode)
741 {
742     _glfwInputError(GLFW_PLATFORM_ERROR,
743                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
744     return NULL;
745 }
746 
_glfwPlatformSetClipboardString(_GLFWwindow * window,const char * string)747 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
748 {
749     _glfwInputError(GLFW_PLATFORM_ERROR,
750                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
751 }
752 
_glfwPlatformGetClipboardString(_GLFWwindow * window)753 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
754 {
755     _glfwInputError(GLFW_PLATFORM_ERROR,
756                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
757 
758     return NULL;
759 }
760 
_glfwPlatformGetRequiredInstanceExtensions(uint32_t * count)761 char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
762 {
763     char** extensions;
764 
765     *count = 0;
766 
767     if (!_glfw.vk.KHR_mir_surface)
768         return NULL;
769 
770     extensions = calloc(2, sizeof(char*));
771     extensions[0] = strdup("VK_KHR_surface");
772     extensions[1] = strdup("VK_KHR_mir_surface");
773 
774     *count = 2;
775     return extensions;
776 }
777 
_glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,VkPhysicalDevice device,uint32_t queuefamily)778 int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
779                                                       VkPhysicalDevice device,
780                                                       uint32_t queuefamily)
781 {
782     PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR =
783         (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
784         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
785     if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
786     {
787         _glfwInputError(GLFW_API_UNAVAILABLE,
788                         "Mir: Vulkan instance missing VK_KHR_mir_surface extension");
789         return GLFW_FALSE;
790     }
791 
792     return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
793                                                         queuefamily,
794                                                         _glfw.mir.connection);
795 }
796 
_glfwPlatformCreateWindowSurface(VkInstance instance,_GLFWwindow * window,const VkAllocationCallbacks * allocator,VkSurfaceKHR * surface)797 VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
798                                           _GLFWwindow* window,
799                                           const VkAllocationCallbacks* allocator,
800                                           VkSurfaceKHR* surface)
801 {
802     VkResult err;
803     VkMirSurfaceCreateInfoKHR sci;
804     PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR;
805 
806     vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)
807         vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR");
808     if (!vkCreateMirSurfaceKHR)
809     {
810         _glfwInputError(GLFW_API_UNAVAILABLE,
811                         "Mir: Vulkan instance missing VK_KHR_mir_surface extension");
812         return VK_ERROR_EXTENSION_NOT_PRESENT;
813     }
814 
815     memset(&sci, 0, sizeof(sci));
816     sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
817     sci.connection = _glfw.mir.connection;
818     sci.mirSurface = window->mir.surface;
819 
820     err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface);
821     if (err)
822     {
823         _glfwInputError(GLFW_PLATFORM_ERROR,
824                         "Mir: Failed to create Vulkan surface: %s",
825                         _glfwGetVulkanResultString(err));
826     }
827 
828     return err;
829 }
830 
831 
832 //////////////////////////////////////////////////////////////////////////
833 //////                        GLFW native API                       //////
834 //////////////////////////////////////////////////////////////////////////
835 
glfwGetMirDisplay(void)836 GLFWAPI MirConnection* glfwGetMirDisplay(void)
837 {
838     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
839     return _glfw.mir.connection;
840 }
841 
glfwGetMirWindow(GLFWwindow * handle)842 GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* handle)
843 {
844     _GLFWwindow* window = (_GLFWwindow*) handle;
845     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
846     return window->mir.surface;
847 }
848 
849