medfall

A super great game engine
Log | Files | Refs

mir_window.cc (28878B)


      1 //========================================================================
      2 // GLFW 3.3 Mir - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2014-2017 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 
     41 static void deleteNode(EventQueue* queue, EventNode* node)
     42 {
     43     mir_event_unref(node->event);
     44     free(node);
     45 }
     46 
     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.
     55 static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
     56 {
     57     EventNode* newNode = calloc(1, sizeof(EventNode));
     58     newNode->event     = mir_event_ref(event);
     59     newNode->window    = context;
     60 
     61     return newNode;
     62 }
     63 
     64 static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
     65 {
     66     pthread_mutex_lock(&_glfw.mir.eventMutex);
     67 
     68     EventNode* newNode = newEventNode(event, context);
     69     TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries);
     70 
     71     pthread_cond_signal(&_glfw.mir.eventCond);
     72 
     73     pthread_mutex_unlock(&_glfw.mir.eventMutex);
     74 }
     75 
     76 static EventNode* dequeueEvent(EventQueue* queue)
     77 {
     78     EventNode* node = NULL;
     79 
     80     pthread_mutex_lock(&_glfw.mir.eventMutex);
     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.eventMutex);
     88 
     89     return node;
     90 }
     91 
     92 static MirPixelFormat findValidPixelFormat(void)
     93 {
     94     unsigned int i, validFormats, mirPixelFormats = 32;
     95     MirPixelFormat formats[mir_pixel_formats];
     96 
     97     mir_connection_get_available_surface_formats(_glfw.mir.connection, formats,
     98                                                  mirPixelFormats, &validFormats);
     99 
    100     for (i = 0;  i < validFormats;  i++)
    101     {
    102         if (formats[i] == mir_pixel_format_abgr_8888 ||
    103             formats[i] == mir_pixel_format_xbgr_8888 ||
    104             formats[i] == mir_pixel_format_argb_8888 ||
    105             formats[i] == mir_pixel_format_xrgb_8888)
    106         {
    107             return formats[i];
    108         }
    109     }
    110 
    111     return mir_pixel_format_invalid;
    112 }
    113 
    114 static int mirModToGLFWMod(uint32_t mods)
    115 {
    116     int publicMods = 0x0;
    117 
    118     if (mods & mir_input_event_modifier_alt)
    119         publicMods |= GLFW_MOD_ALT;
    120     else if (mods & mir_input_event_modifier_shift)
    121         publicMods |= GLFW_MOD_SHIFT;
    122     else if (mods & mir_input_event_modifier_ctrl)
    123         publicMods |= GLFW_MOD_CONTROL;
    124     else if (mods & mir_input_event_modifier_meta)
    125         publicMods |= GLFW_MOD_SUPER;
    126 
    127     return publicMods;
    128 }
    129 
    130 static int toGLFWKeyCode(uint32_t key)
    131 {
    132     if (key < sizeof(_glfw.mir.keycodes) / sizeof(_glfw.mir.keycodes[0]))
    133         return _glfw.mir.keycodes[key];
    134 
    135     return GLFW_KEY_UNKNOWN;
    136 }
    137 
    138 static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
    139 {
    140     const int action    = mir_keyboard_event_action   (key_event);
    141     const int scan_code = mir_keyboard_event_scan_code(key_event);
    142     const int key_code  = mir_keyboard_event_key_code (key_event);
    143     const int modifiers = mir_keyboard_event_modifiers(key_event);
    144 
    145     const int  pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS;
    146     const int  mods    = mirModToGLFWMod(modifiers);
    147     const long text    = _glfwKeySym2Unicode(key_code);
    148     const int  plain   = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
    149 
    150     _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
    151 
    152     if (text != -1)
    153         _glfwInputChar(window, text, mods, plain);
    154 }
    155 
    156 static void handlePointerButton(_GLFWwindow* window,
    157                               int pressed,
    158                               const MirPointerEvent* pointer_event)
    159 {
    160     int mods                = mir_pointer_event_modifiers(pointer_event);
    161     const int publicMods    = mirModToGLFWMod(mods);
    162     MirPointerButton button = mir_pointer_button_primary;
    163     static uint32_t oldButtonStates = 0;
    164     uint32_t newButtonStates        = mir_pointer_event_buttons(pointer_event);
    165     int publicButton                = GLFW_MOUSE_BUTTON_LEFT;
    166 
    167     // XOR our old button states our new states to figure out what was added or removed
    168     button = newButtonStates ^ oldButtonStates;
    169 
    170     switch (button)
    171     {
    172         case mir_pointer_button_primary:
    173             publicButton = GLFW_MOUSE_BUTTON_LEFT;
    174             break;
    175         case mir_pointer_button_secondary:
    176             publicButton = GLFW_MOUSE_BUTTON_RIGHT;
    177             break;
    178         case mir_pointer_button_tertiary:
    179             publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
    180             break;
    181         case mir_pointer_button_forward:
    182             // FIXME What is the forward button?
    183             publicButton = GLFW_MOUSE_BUTTON_4;
    184             break;
    185         case mir_pointer_button_back:
    186             // FIXME What is the back button?
    187             publicButton = GLFW_MOUSE_BUTTON_5;
    188             break;
    189         default:
    190             break;
    191     }
    192 
    193     oldButtonStates = newButtonStates;
    194 
    195     _glfwInputMouseClick(window, publicButton, pressed, publicMods);
    196 }
    197 
    198 static void handlePointerMotion(_GLFWwindow* window,
    199                                 const MirPointerEvent* pointer_event)
    200 {
    201     const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
    202     const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
    203 
    204     if (window->cursorMode == GLFW_CURSOR_DISABLED)
    205     {
    206         if (_glfw.mir.disabledCursorWindow != window)
    207             return;
    208 
    209         const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x);
    210         const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y);
    211         const int current_x = window->virtualCursorPosX;
    212         const int current_y = window->virtualCursorPosY;
    213 
    214         _glfwInputCursorPos(window, dx + current_x, dy + current_y);
    215     }
    216     else
    217     {
    218         const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
    219         const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
    220 
    221         _glfwInputCursorPos(window, x, y);
    222     }
    223 
    224     if (hscroll != 0 || vscroll != 0)
    225       _glfwInputScroll(window, hscroll, vscroll);
    226 }
    227 
    228 static void handlePointerEvent(const MirPointerEvent* pointer_event,
    229                              _GLFWwindow* window)
    230 {
    231     int action = mir_pointer_event_action(pointer_event);
    232 
    233     switch (action)
    234     {
    235           case mir_pointer_action_button_down:
    236               handlePointerButton(window, GLFW_PRESS, pointer_event);
    237               break;
    238           case mir_pointer_action_button_up:
    239               handlePointerButton(window, GLFW_RELEASE, pointer_event);
    240               break;
    241           case mir_pointer_action_motion:
    242               handlePointerMotion(window, pointer_event);
    243               break;
    244           case mir_pointer_action_enter:
    245           case mir_pointer_action_leave:
    246               break;
    247           default:
    248               break;
    249     }
    250 }
    251 
    252 static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
    253 {
    254     int type = mir_input_event_get_type(input_event);
    255 
    256     switch (type)
    257     {
    258         case mir_input_event_type_key:
    259             handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
    260             break;
    261         case mir_input_event_type_pointer:
    262             handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
    263             break;
    264         default:
    265             break;
    266     }
    267 }
    268 
    269 static void handleEvent(const MirEvent* event, _GLFWwindow* window)
    270 {
    271     int type = mir_event_get_type(event);
    272 
    273     switch (type)
    274     {
    275         case mir_event_type_input:
    276             handleInput(mir_event_get_input_event(event), window);
    277             break;
    278         default:
    279             break;
    280     }
    281 }
    282 
    283 static void addNewEvent(MirWindow* window, const MirEvent* event, void* context)
    284 {
    285     enqueueEvent(event, context);
    286 }
    287 
    288 static GLFWbool createWindow(_GLFWwindow* window)
    289 {
    290     MirWindowSpec* spec;
    291     MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
    292     MirPixelFormat pixel_format = findValidPixelFormat();
    293 
    294     if (pixel_format == mir_pixel_format_invalid)
    295     {
    296         _glfwInputError(GLFW_PLATFORM_ERROR,
    297                         "Mir: Unable to find a correct pixel format");
    298         return GLFW_FALSE;
    299     }
    300 
    301     spec = mir_create_normal_window_spec(_glfw.mir.connection,
    302                                          window->mir.width,
    303                                          window->mir.height);
    304 
    305     mir_window_spec_set_pixel_format(spec, pixel_format);
    306     mir_window_spec_set_buffer_usage(spec, buffer_usage);
    307 
    308     window->mir.window = mir_create_window_sync(spec);
    309     mir_window_spec_release(spec);
    310 
    311     if (!mir_window_is_valid(window->mir.window))
    312     {
    313         _glfwInputError(GLFW_PLATFORM_ERROR,
    314                         "Mir: Unable to create window: %s",
    315                         mir_window_get_error_message(window->mir.window));
    316 
    317         return GLFW_FALSE;
    318     }
    319 
    320     mir_window_set_event_handler(window->mir.window, addNewEvent, window);
    321 
    322     return GLFW_TRUE;
    323 }
    324 
    325 static void setWindowConfinement(_GLFWwindow* window, MirPointerConfinementState state)
    326 {
    327     MirWindowSpec* spec;
    328 
    329     spec = mir_create_window_spec(_glfw.mir.connection);
    330     mir_window_spec_set_pointer_confinement(spec, state);
    331 
    332     mir_window_apply_spec(window->mir.window, spec);
    333     mir_window_spec_release(spec);
    334 }
    335 
    336 //////////////////////////////////////////////////////////////////////////
    337 //////                       GLFW internal API                      //////
    338 //////////////////////////////////////////////////////////////////////////
    339 
    340 void _glfwInitEventQueueMir(EventQueue* queue)
    341 {
    342     TAILQ_INIT(&queue->head);
    343 }
    344 
    345 void _glfwDeleteEventQueueMir(EventQueue* queue)
    346 {
    347     if (queue)
    348     {
    349         EventNode* node, *node_next;
    350         node = queue->head.tqh_first;
    351 
    352         while (node != NULL)
    353         {
    354             node_next = node->entries.tqe_next;
    355 
    356             TAILQ_REMOVE(&queue->head, node, entries);
    357             deleteNode(queue, node);
    358 
    359             node = node_next;
    360         }
    361 
    362         free(queue);
    363     }
    364 }
    365 
    366 //////////////////////////////////////////////////////////////////////////
    367 //////                       GLFW platform API                      //////
    368 //////////////////////////////////////////////////////////////////////////
    369 
    370 int _glfwPlatformCreateWindow(_GLFWwindow* window,
    371                               const _GLFWwndconfig* wndconfig,
    372                               const _GLFWctxconfig* ctxconfig,
    373                               const _GLFWfbconfig* fbconfig)
    374 {
    375     if (window->monitor)
    376     {
    377         GLFWvidmode mode;
    378         _glfwPlatformGetVideoMode(window->monitor, &mode);
    379 
    380         mir_window_set_state(window->mir.window, mir_window_state_fullscreen);
    381 
    382         if (wndconfig->width > mode.width || wndconfig->height > mode.height)
    383         {
    384             _glfwInputError(GLFW_PLATFORM_ERROR,
    385                             "Mir: Requested window size too large: %ix%i",
    386                             wndconfig->width, wndconfig->height);
    387 
    388             return GLFW_FALSE;
    389         }
    390     }
    391 
    392     window->mir.width  = wndconfig->width;
    393     window->mir.height = wndconfig->height;
    394     window->mir.currentCursor = NULL;
    395 
    396     if (!createWindow(window))
    397         return GLFW_FALSE;
    398 
    399     window->mir.nativeWindow = mir_buffer_stream_get_egl_native_window(
    400         mir_window_get_buffer_stream(window->mir.window));
    401 
    402     if (ctxconfig->client != GLFW_NO_API)
    403     {
    404         if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
    405             ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
    406         {
    407             if (!_glfwInitEGL())
    408                 return GLFW_FALSE;
    409             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
    410                 return GLFW_FALSE;
    411         }
    412         else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
    413         {
    414             if (!_glfwInitOSMesa())
    415                 return GLFW_FALSE;
    416             if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
    417                 return GLFW_FALSE;
    418         }
    419     }
    420 
    421     return GLFW_TRUE;
    422 }
    423 
    424 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
    425 {
    426     if (_glfw.mir.disabledCursorWindow == window)
    427         _glfw.mir.disabledCursorWindow = NULL;
    428 
    429     if (mir_window_is_valid(window->mir.window))
    430     {
    431         mir_window_release_sync(window->mir.window);
    432         window->mir.window= NULL;
    433     }
    434 
    435     if (window->context.destroy)
    436         window->context.destroy(window);
    437 }
    438 
    439 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
    440 {
    441     MirWindowSpec* spec;
    442 
    443     spec = mir_create_window_spec(_glfw.mir.connection);
    444     mir_window_spec_set_name(spec, title);
    445     mir_window_apply_spec(window->mir.window, spec);
    446     mir_window_spec_release(spec);
    447 }
    448 
    449 void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
    450                                 int count, const GLFWimage* images)
    451 {
    452     _glfwInputError(GLFW_PLATFORM_ERROR,
    453                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    454 }
    455 
    456 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
    457 {
    458     MirWindowSpec* spec;
    459 
    460     spec = mir_create_window_spec(_glfw.mir.connection);
    461     mir_window_spec_set_width (spec, width);
    462     mir_window_spec_set_height(spec, height);
    463 
    464     mir_window_apply_spec(window->mir.window, spec);
    465     mir_window_spec_release(spec);
    466 }
    467 
    468 void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
    469                                       int minwidth, int minheight,
    470                                       int maxwidth, int maxheight)
    471 {
    472     MirWindowSpec* spec;
    473 
    474     spec = mir_create_window_spec(_glfw.mir.connection);
    475     mir_window_spec_set_max_width (spec, maxwidth);
    476     mir_window_spec_set_max_height(spec, maxheight);
    477     mir_window_spec_set_min_width (spec, minwidth);
    478     mir_window_spec_set_min_height(spec, minheight);
    479 
    480     mir_window_apply_spec(window->mir.window, spec);
    481     mir_window_spec_release(spec);
    482 }
    483 
    484 void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
    485 {
    486     _glfwInputError(GLFW_PLATFORM_ERROR,
    487                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    488 }
    489 
    490 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
    491 {
    492     _glfwInputError(GLFW_PLATFORM_ERROR,
    493                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    494 }
    495 
    496 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
    497                                      int* left, int* top,
    498                                      int* right, int* bottom)
    499 {
    500     _glfwInputError(GLFW_PLATFORM_ERROR,
    501                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    502 }
    503 
    504 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
    505 {
    506     _glfwInputError(GLFW_PLATFORM_ERROR,
    507                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    508 }
    509 
    510 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
    511 {
    512     if (width)
    513         *width  = window->mir.width;
    514     if (height)
    515         *height = window->mir.height;
    516 }
    517 
    518 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
    519 {
    520     MirWindowSpec* spec;
    521 
    522     spec = mir_create_window_spec(_glfw.mir.connection);
    523     mir_window_spec_set_state(spec, mir_window_state_minimized);
    524 
    525     mir_window_apply_spec(window->mir.window, spec);
    526     mir_window_spec_release(spec);
    527 }
    528 
    529 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
    530 {
    531     MirWindowSpec* spec;
    532 
    533     spec = mir_create_window_spec(_glfw.mir.connection);
    534     mir_window_spec_set_state(spec, mir_window_state_restored);
    535 
    536     mir_window_apply_spec(window->mir.window, spec);
    537     mir_window_spec_release(spec);
    538 }
    539 
    540 void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
    541 {
    542     MirWindowSpec* spec;
    543 
    544     spec = mir_create_window_spec(_glfw.mir.connection);
    545     mir_window_spec_set_state(spec, mir_window_state_maximized);
    546 
    547     mir_window_apply_spec(window->mir.window, spec);
    548     mir_window_spec_release(spec);
    549 }
    550 
    551 void _glfwPlatformHideWindow(_GLFWwindow* window)
    552 {
    553     MirWindowSpec* spec;
    554 
    555     spec = mir_create_window_spec(_glfw.mir.connection);
    556     mir_window_spec_set_state(spec, mir_window_state_hidden);
    557 
    558     mir_window_apply_spec(window->mir.window, spec);
    559     mir_window_spec_release(spec);
    560 }
    561 
    562 void _glfwPlatformShowWindow(_GLFWwindow* window)
    563 {
    564     MirWindowSpec* spec;
    565 
    566     spec = mir_create_window_spec(_glfw.mir.connection);
    567     mir_window_spec_set_state(spec, mir_window_state_restored);
    568 
    569     mir_window_apply_spec(window->mir.window, spec);
    570     mir_window_spec_release(spec);
    571 }
    572 
    573 void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
    574 {
    575     _glfwInputError(GLFW_PLATFORM_ERROR,
    576                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    577 }
    578 
    579 void _glfwPlatformFocusWindow(_GLFWwindow* window)
    580 {
    581     _glfwInputError(GLFW_PLATFORM_ERROR,
    582                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    583 }
    584 
    585 void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
    586                                    _GLFWmonitor* monitor,
    587                                    int xpos, int ypos,
    588                                    int width, int height,
    589                                    int refreshRate)
    590 {
    591     _glfwInputError(GLFW_PLATFORM_ERROR,
    592                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    593 }
    594 
    595 int _glfwPlatformWindowFocused(_GLFWwindow* window)
    596 {
    597     return mir_window_get_focus_state(window->mir.window) == mir_window_focus_state_focused;
    598 }
    599 
    600 int _glfwPlatformWindowIconified(_GLFWwindow* window)
    601 {
    602     _glfwInputError(GLFW_PLATFORM_ERROR,
    603                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    604     return GLFW_FALSE;
    605 }
    606 
    607 int _glfwPlatformWindowVisible(_GLFWwindow* window)
    608 {
    609     return mir_window_get_visibility(window->mir.window) == mir_window_visibility_exposed;
    610 }
    611 
    612 int _glfwPlatformWindowMaximized(_GLFWwindow* window)
    613 {
    614     return mir_window_get_state(window->mir.window) == mir_window_state_maximized;
    615 }
    616 
    617 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
    618 {
    619     _glfwInputError(GLFW_PLATFORM_ERROR,
    620                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    621 }
    622 
    623 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
    624 {
    625     _glfwInputError(GLFW_PLATFORM_ERROR,
    626                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    627 }
    628 
    629 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
    630 {
    631     _glfwInputError(GLFW_PLATFORM_ERROR,
    632                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    633 }
    634 
    635 void _glfwPlatformPollEvents(void)
    636 {
    637     EventNode* node = NULL;
    638 
    639     while ((node = dequeueEvent(_glfw.mir.eventQueue)))
    640     {
    641         handleEvent(node->event, node->window);
    642         deleteNode(_glfw.mir.eventQueue, node);
    643     }
    644 }
    645 
    646 void _glfwPlatformWaitEvents(void)
    647 {
    648     pthread_mutex_lock(&_glfw.mir.eventMutex);
    649 
    650     while (emptyEventQueue(_glfw.mir.eventQueue))
    651         pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex);
    652 
    653     pthread_mutex_unlock(&_glfw.mir.eventMutex);
    654 
    655     _glfwPlatformPollEvents();
    656 }
    657 
    658 void _glfwPlatformWaitEventsTimeout(double timeout)
    659 {
    660     pthread_mutex_lock(&_glfw.mir.eventMutex);
    661 
    662     if (emptyEventQueue(_glfw.mir.eventQueue))
    663     {
    664         struct timespec time;
    665         clock_gettime(CLOCK_REALTIME, &time);
    666         time.tv_sec += (long) timeout;
    667         time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
    668         pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time);
    669     }
    670 
    671     pthread_mutex_unlock(&_glfw.mir.eventMutex);
    672 
    673     _glfwPlatformPollEvents();
    674 }
    675 
    676 void _glfwPlatformPostEmptyEvent(void)
    677 {
    678 }
    679 
    680 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
    681 {
    682     if (width)
    683         *width  = window->mir.width;
    684     if (height)
    685         *height = window->mir.height;
    686 }
    687 
    688 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
    689                               const GLFWimage* image,
    690                               int xhot, int yhot)
    691 {
    692     MirBufferStream* stream;
    693 
    694     int i_w = image->width;
    695     int i_h = image->height;
    696 
    697     stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection,
    698                                                       i_w, i_h,
    699                                                       mir_pixel_format_argb_8888,
    700                                                       mir_buffer_usage_software);
    701 
    702     cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot);
    703 
    704     MirGraphicsRegion region;
    705     mir_buffer_stream_get_graphics_region(stream, &region);
    706 
    707     unsigned char* pixels = image->pixels;
    708     char* dest = region.vaddr;
    709     int i;
    710 
    711     for (i = 0; i < i_w * i_h; i++, pixels += 4)
    712     {
    713         unsigned int alpha = pixels[3];
    714         *dest++ = (char)(pixels[2] * alpha / 255);
    715         *dest++ = (char)(pixels[1] * alpha / 255);
    716         *dest++ = (char)(pixels[0] * alpha / 255);
    717         *dest++ = (char)alpha;
    718     }
    719 
    720     mir_buffer_stream_swap_buffers_sync(stream);
    721     cursor->mir.customCursor = stream;
    722 
    723     return GLFW_TRUE;
    724 }
    725 
    726 static const char* getSystemCursorName(int shape)
    727 {
    728     switch (shape)
    729     {
    730         case GLFW_ARROW_CURSOR:
    731             return mir_arrow_cursor_name;
    732         case GLFW_IBEAM_CURSOR:
    733             return mir_caret_cursor_name;
    734         case GLFW_CROSSHAIR_CURSOR:
    735             return mir_crosshair_cursor_name;
    736         case GLFW_HAND_CURSOR:
    737             return mir_open_hand_cursor_name;
    738         case GLFW_HRESIZE_CURSOR:
    739             return mir_horizontal_resize_cursor_name;
    740         case GLFW_VRESIZE_CURSOR:
    741             return mir_vertical_resize_cursor_name;
    742     }
    743 
    744     return NULL;
    745 }
    746 
    747 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
    748 {
    749     cursor->mir.conf         = NULL;
    750     cursor->mir.customCursor = NULL;
    751     cursor->mir.cursorName   = getSystemCursorName(shape);
    752 
    753     return cursor->mir.cursorName != NULL;
    754 }
    755 
    756 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
    757 {
    758     if (cursor->mir.conf)
    759         mir_cursor_configuration_destroy(cursor->mir.conf);
    760     if (cursor->mir.customCursor)
    761         mir_buffer_stream_release_sync(cursor->mir.customCursor);
    762 }
    763 
    764 static void setCursorNameForWindow(MirWindow* window, char const* name)
    765 {
    766     MirWindowSpec* spec = mir_create_window_spec(_glfw.mir.connection);
    767     mir_window_spec_set_cursor_name(spec, name);
    768     mir_window_apply_spec(window, spec);
    769     mir_window_spec_release(spec);
    770 }
    771 
    772 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
    773 {
    774     if (cursor)
    775     {
    776         window->mir.currentCursor = cursor;
    777 
    778         if (cursor->mir.cursorName)
    779         {
    780             setCursorNameForWindow(window->mir.window, cursor->mir.cursorName);
    781         }
    782         else if (cursor->mir.conf)
    783         {
    784             mir_window_configure_cursor(window->mir.window, cursor->mir.conf);
    785         }
    786     }
    787     else
    788     {
    789         setCursorNameForWindow(window->mir.window, mir_default_cursor_name);
    790     }
    791 }
    792 
    793 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
    794 {
    795     _glfwInputError(GLFW_PLATFORM_ERROR,
    796                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    797 }
    798 
    799 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
    800 {
    801     _glfwInputError(GLFW_PLATFORM_ERROR,
    802                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    803 }
    804 
    805 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
    806 {
    807     if (mode == GLFW_CURSOR_DISABLED)
    808     {
    809         _glfw.mir.disabledCursorWindow = window;
    810         setWindowConfinement(window, mir_pointer_confined_to_window);
    811         setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name);
    812     }
    813     else
    814     {
    815         // If we were disabled before lets undo that!
    816         if (_glfw.mir.disabledCursorWindow == window)
    817         {
    818             _glfw.mir.disabledCursorWindow = NULL;
    819             setWindowConfinement(window, mir_pointer_unconfined);
    820         }
    821 
    822         if (window->cursorMode == GLFW_CURSOR_NORMAL)
    823         {
    824             _glfwPlatformSetCursor(window, window->mir.currentCursor);
    825         }
    826         else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
    827         {
    828             setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name);
    829         }
    830     }
    831 }
    832 
    833 const char* _glfwPlatformGetScancodeName(int scancode)
    834 {
    835     _glfwInputError(GLFW_PLATFORM_ERROR,
    836                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    837     return NULL;
    838 }
    839 
    840 int _glfwPlatformGetKeyScancode(int key)
    841 {
    842     return _glfw.mir.scancodes[key];
    843 }
    844 
    845 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
    846 {
    847     _glfwInputError(GLFW_PLATFORM_ERROR,
    848                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    849 }
    850 
    851 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
    852 {
    853     _glfwInputError(GLFW_PLATFORM_ERROR,
    854                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
    855 
    856     return NULL;
    857 }
    858 
    859 void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
    860 {
    861     if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_mir_surface)
    862         return;
    863 
    864     extensions[0] = "VK_KHR_surface";
    865     extensions[1] = "VK_KHR_mir_surface";
    866 }
    867 
    868 int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
    869                                                       VkPhysicalDevice device,
    870                                                       uint32_t queuefamily)
    871 {
    872     PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR =
    873         (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
    874         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
    875     if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
    876     {
    877         _glfwInputError(GLFW_API_UNAVAILABLE,
    878                         "Mir: Vulkan instance missing VK_KHR_mir_surface extension");
    879         return GLFW_FALSE;
    880     }
    881 
    882     return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
    883                                                         queuefamily,
    884                                                         _glfw.mir.connection);
    885 }
    886 
    887 VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
    888                                           _GLFWwindow* window,
    889                                           const VkAllocationCallbacks* allocator,
    890                                           VkSurfaceKHR* surface)
    891 {
    892     VkResult err;
    893     VkMirWindowCreateInfoKHR sci;
    894     PFN_vkCreateMirWindowKHR vkCreateMirWindowKHR;
    895 
    896     vkCreateMirWindowKHR = (PFN_vkCreateMirWindowKHR)
    897         vkGetInstanceProcAddr(instance, "vkCreateMirWindowKHR");
    898     if (!vkCreateMirWindowKHR)
    899     {
    900         _glfwInputError(GLFW_API_UNAVAILABLE,
    901                         "Mir: Vulkan instance missing VK_KHR_mir_surface extension");
    902         return VK_ERROR_EXTENSION_NOT_PRESENT;
    903     }
    904 
    905     memset(&sci, 0, sizeof(sci));
    906     sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
    907     sci.connection = _glfw.mir.connection;
    908     sci.mirWindow  = window->mir.window;
    909 
    910     err = vkCreateMirWindowKHR(instance, &sci, allocator, surface);
    911     if (err)
    912     {
    913         _glfwInputError(GLFW_PLATFORM_ERROR,
    914                         "Mir: Failed to create Vulkan surface: %s",
    915                         _glfwGetVulkanResultString(err));
    916     }
    917 
    918     return err;
    919 }
    920 
    921 
    922 //////////////////////////////////////////////////////////////////////////
    923 //////                        GLFW native API                       //////
    924 //////////////////////////////////////////////////////////////////////////
    925 
    926 GLFWAPI MirConnection* glfwGetMirDisplay(void)
    927 {
    928     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
    929     return _glfw.mir.connection;
    930 }
    931 
    932 GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* handle)
    933 {
    934     _GLFWwindow* window = (_GLFWwindow*) handle;
    935     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
    936     return window->mir.window;
    937 }
    938