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, ®ion);
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