GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/paintsurfaces.c
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 55 106 51.9%
Functions: 4 5 80.0%
Branches: 13 54 24.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/ui/paintsurfaces.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33 #if defined(GATE_UI_WINAPI)
34
35 #include "gate/ui/gateui_winapi.h"
36 #include "gate/platforms.h"
37 #include <windowsx.h>
38
39 #ifndef WM_MOUSEWHEEL
40 #define WM_MOUSEWHEEL 0x020A
41 #endif
42
43 #ifndef GET_WHEEL_DELTA_WPARAM
44 #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam))
45 #endif
46
47 #ifndef WHEEL_DELTA
48 #define WHEEL_DELTA 120
49 #endif
50
51 #ifndef GET_X_LPARAM
52 #define GET_X_LPARAM(lparam) LOWORD(lparam)
53 #endif
54
55 #ifndef GET_Y_LPARAM
56 #define GET_Y_LPARAM(lparam) HIWORD(lparam)
57 #endif
58
59 static gate_bool_t gate_ui_paintsurface_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
60 {
61 if (ctrl != NULL)
62 {
63 HWND hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
64 if (hwnd == hwndCtrl)
65 {
66 gate_ui_paintsurface_t* surface = (gate_ui_paintsurface_t*)ctrl;
67 gate_ui_point_t coords;
68 gate_uint32_t btn;
69 gate_input_keycode_t kbd_key;
70 gate_input_keystates_t kbd_states;
71
72 switch (msg)
73 {
74 case WM_PAINT:
75 {
76 RECT rect;
77 if (GetUpdateRect(hwndCtrl, &rect, FALSE))
78 {
79 HDC hdc;
80 PAINTSTRUCT ps;
81 RECT client_rect;
82
83 gate_mem_clear(&client_rect, sizeof(client_rect));
84 GetClientRect((HWND)hwnd, &client_rect);
85 hdc = BeginPaint((HWND)hwnd, &ps);
86 if (hdc)
87 {
88 if (surface->on_paint)
89 {
90 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
91 gate_ui_graphics_t graph;
92 gate_result_t result;
93 gate_ui_position_t position;
94 position.pos.x = rect.left;
95 position.pos.y = rect.top;
96 position.size.width = rect.right - rect.left;
97 position.size.height = rect.bottom - rect.top;
98 if ((position.size.width) > 0 && (position.size.height > 0))
99 {
100 //++position.size.width;
101 //++position.size.height;
102 result = gate_ui_graphics_create_native(&graph, host, (void*)hdc, NULL, client_rect.right, client_rect.bottom);
103 surface->on_paint(ctrl, &graph, &position);
104 }
105 }
106 EndPaint(hwndCtrl, &ps);
107 *lresult = 0;
108 return true;
109 }
110 }
111 break;
112 }
113 case WM_SIZE:
114 {
115 gate_ui_size_t sz;
116 sz.width = (int)(short)LOWORD(lParam);
117 sz.height = (int)(short)HIWORD(lParam);
118 if (surface->on_resize != NULL)
119 {
120 surface->on_resize(ctrl, &sz);
121 }
122 break;
123 }
124 case WM_LBUTTONDOWN:
125 case WM_RBUTTONDOWN:
126 case WM_MBUTTONDOWN:
127 {
128 switch (msg)
129 {
130 case WM_LBUTTONDOWN: btn = GATE_UI_MOUSE_LEFT; break;
131 case WM_RBUTTONDOWN: btn = GATE_UI_MOUSE_RIGHT; break;
132 case WM_MBUTTONDOWN: btn = GATE_UI_MOUSE_MIDDLE; break;
133 }
134 coords.x = GET_X_LPARAM(lParam);
135 coords.y = GET_Y_LPARAM(lParam);
136 if (surface->on_mouse_down != NULL)
137 {
138 surface->on_mouse_down(&surface->ctrl, &coords, btn);
139 }
140 break;
141 }
142 case WM_LBUTTONUP:
143 case WM_RBUTTONUP:
144 case WM_MBUTTONUP:
145 {
146 switch (msg)
147 {
148 case WM_LBUTTONUP: btn = GATE_UI_MOUSE_LEFT; break;
149 case WM_RBUTTONUP: btn = GATE_UI_MOUSE_RIGHT; break;
150 case WM_MBUTTONUP: btn = GATE_UI_MOUSE_MIDDLE; break;
151 }
152 coords.x = GET_X_LPARAM(lParam);
153 coords.y = GET_Y_LPARAM(lParam);
154 if (surface->on_mouse_up != NULL)
155 {
156 surface->on_mouse_up(&surface->ctrl, &coords, btn);
157 }
158 break;
159 }
160 case WM_LBUTTONDBLCLK:
161 case WM_RBUTTONDBLCLK:
162 case WM_MBUTTONDBLCLK:
163 {
164 switch (msg)
165 {
166 case WM_LBUTTONDBLCLK: btn = GATE_UI_MOUSE_LEFT; break;
167 case WM_RBUTTONDBLCLK: btn = GATE_UI_MOUSE_RIGHT; break;
168 case WM_MBUTTONDBLCLK: btn = GATE_UI_MOUSE_MIDDLE; break;
169 }
170 coords.x = GET_X_LPARAM(lParam);
171 coords.y = GET_Y_LPARAM(lParam);
172 if (surface->on_mouse_dblclick != NULL)
173 {
174 surface->on_mouse_dblclick(&surface->ctrl, &coords, btn);
175 }
176 break;
177 }
178 case WM_MOUSEMOVE:
179 {
180 btn = 0;
181 if (GATE_FLAG_ENABLED(LOWORD(wParam), MK_LBUTTON)) btn |= GATE_UI_MOUSE_LEFT;
182 if (GATE_FLAG_ENABLED(LOWORD(wParam), MK_RBUTTON)) btn |= GATE_UI_MOUSE_RIGHT;
183 if (GATE_FLAG_ENABLED(LOWORD(wParam), MK_MBUTTON)) btn |= GATE_UI_MOUSE_MIDDLE;
184 coords.x = GET_X_LPARAM(lParam);
185 coords.y = GET_Y_LPARAM(lParam);
186 if (surface->on_mouse_move != NULL)
187 {
188 surface->on_mouse_move(&surface->ctrl, &coords, btn);
189 }
190 break;
191 }
192 case WM_MOUSEWHEEL:
193 {
194 gate_int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
195 btn = 0;
196 if (GATE_FLAG_ENABLED(LOWORD(wParam), MK_LBUTTON)) btn |= GATE_UI_MOUSE_LEFT;
197 if (GATE_FLAG_ENABLED(LOWORD(wParam), MK_RBUTTON)) btn |= GATE_UI_MOUSE_RIGHT;
198 if (GATE_FLAG_ENABLED(LOWORD(wParam), MK_MBUTTON)) btn |= GATE_UI_MOUSE_MIDDLE;
199 coords.x = GET_X_LPARAM(lParam);
200 coords.y = GET_Y_LPARAM(lParam);
201 if (surface->on_mouse_scroll != NULL)
202 {
203 surface->on_mouse_scroll(&surface->ctrl, &coords, btn, delta);
204 }
205 break;
206 }
207 case WM_KEYDOWN:
208 {
209 if (surface->on_key_down != NULL)
210 {
211 kbd_states = 0;
212 kbd_key = 0;
213 gate_ui_winapi_get_keystates(&kbd_states);
214 gate_keyboard_parse_native_key((gate_input_nativekeycode_t)wParam, &kbd_key, NULL);
215 surface->on_key_down(&surface->ctrl, kbd_key, kbd_states);
216 }
217 break;
218 }
219 case WM_KEYUP:
220 {
221 if (surface->on_key_up != NULL)
222 {
223 kbd_states = 0;
224 kbd_key = 0;
225 gate_ui_winapi_get_keystates(&kbd_states);
226 gate_keyboard_parse_native_key((gate_input_nativekeycode_t)wParam, &kbd_key, NULL);
227 surface->on_key_up(&surface->ctrl, kbd_key, kbd_states);
228 }
229 break;
230 }
231 case WM_CHAR:
232 {
233 if (surface->on_key_char != NULL)
234 {
235 kbd_states = 0;
236 gate_ui_winapi_get_keystates(&kbd_states);
237 surface->on_key_char(&surface->ctrl, (gate_char32_t)wParam, kbd_states);
238 }
239 break;
240 }
241 }
242 }
243 }
244 return false;
245 }
246
247 gate_result_t gate_ui_paintsurface_create(
248 gate_ui_paintsurface_t* paintsurface, gate_ui_ctrl_t* parent,
249 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
250 {
251 HWND hwndparent = (HWND)GATE_UI_WINAPI_GET_HWND(parent);
252 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(parent);
253 gate_result_t ret;
254 gate_uint32_t styles, exstyles;
255 gate_mem_clear(paintsurface, sizeof(gate_ui_paintsurface_t));
256
257 exstyles = 0;
258 styles = WS_CLIPSIBLINGS | WS_CHILD;
259
260 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
261 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
262
263 ret = gate_ui_winapi_create(&paintsurface->ctrl, host, hwndparent, NULL, position, styles, exstyles, NULL, userparam, false);
264 if (GATE_SUCCEEDED(ret))
265 {
266 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&paintsurface->ctrl);
267 gate_ui_winapi_register_event(host, hwnd, WM_SIZE, &gate_ui_paintsurface_events, &paintsurface->ctrl);
268 gate_ui_winapi_register_event(host, hwnd, WM_PAINT, &gate_ui_paintsurface_events, &paintsurface->ctrl);
269 gate_ui_winapi_register_event(host, hwnd, WM_LBUTTONDOWN, &gate_ui_paintsurface_events, &paintsurface->ctrl);
270 gate_ui_winapi_register_event(host, hwnd, WM_RBUTTONDOWN, &gate_ui_paintsurface_events, &paintsurface->ctrl);
271 gate_ui_winapi_register_event(host, hwnd, WM_MBUTTONDOWN, &gate_ui_paintsurface_events, &paintsurface->ctrl);
272 gate_ui_winapi_register_event(host, hwnd, WM_LBUTTONUP, &gate_ui_paintsurface_events, &paintsurface->ctrl);
273 gate_ui_winapi_register_event(host, hwnd, WM_RBUTTONUP, &gate_ui_paintsurface_events, &paintsurface->ctrl);
274 gate_ui_winapi_register_event(host, hwnd, WM_MBUTTONUP, &gate_ui_paintsurface_events, &paintsurface->ctrl);
275 gate_ui_winapi_register_event(host, hwnd, WM_LBUTTONDBLCLK, &gate_ui_paintsurface_events, &paintsurface->ctrl);
276 gate_ui_winapi_register_event(host, hwnd, WM_RBUTTONDBLCLK, &gate_ui_paintsurface_events, &paintsurface->ctrl);
277 gate_ui_winapi_register_event(host, hwnd, WM_MBUTTONDBLCLK, &gate_ui_paintsurface_events, &paintsurface->ctrl);
278 gate_ui_winapi_register_event(host, hwnd, WM_MOUSEMOVE, &gate_ui_paintsurface_events, &paintsurface->ctrl);
279 gate_ui_winapi_register_event(host, hwnd, WM_MOUSEWHEEL, &gate_ui_paintsurface_events, &paintsurface->ctrl);
280 gate_ui_winapi_register_event(host, hwnd, WM_KEYDOWN, &gate_ui_paintsurface_events, &paintsurface->ctrl);
281 gate_ui_winapi_register_event(host, hwnd, WM_KEYUP, &gate_ui_paintsurface_events, &paintsurface->ctrl);
282 gate_ui_winapi_register_event(host, hwnd, WM_CHAR, &gate_ui_paintsurface_events, &paintsurface->ctrl);
283 }
284 return ret;
285 }
286
287 gate_result_t gate_ui_paintsurface_redraw(gate_ui_paintsurface_t* paintsurface)
288 {
289 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&paintsurface->ctrl);
290 if (!RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_NOERASE))
291 {
292 return GATE_RESULT_FAILED;
293 }
294 else
295 {
296 return GATE_RESULT_OK;
297 }
298 }
299
300 gate_result_t gate_ui_paintsurface_set_cursor(gate_ui_paintsurface_t* paintsurface, gate_ui_cursor_t const* cursor)
301 {
302 return GATE_RESULT_NOTIMPLEMENTED;
303 }
304
305
306
307 #endif /* GATE_UI_WINAPI */
308
309
310 #if defined(GATE_UI_GTK)
311
312 #include "gate/ui/gateui_gtk.h"
313
314 static gate_result_t gate_ui_gtk_paintsurface_refresh(gate_ui_ctrl_t* ctrl)
315 {
316 gate_result_t ret = GATE_RESULT_FAILED;
317 return ret;
318 }
319 static gate_result_t gate_ui_gtk_paintsurface_destroy(gate_ui_ctrl_t* ctrl)
320 {
321 gate_result_t ret = GATE_RESULT_FAILED;
322 return ret;
323 }
324
325 static gboolean gate_ui_gdk_paintsurface_button_press_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
326 {
327 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
328
329 if (paintsurface->on_mouse_down)
330 {
331 gate_ui_point_t point;
332 gate_uint32_t btn = 0;
333 switch (evt->button.button)
334 {
335 case 1: btn = GATE_UI_MOUSE_LEFT; break;
336 case 2: btn = GATE_UI_MOUSE_MIDDLE; break;
337 case 3: btn = GATE_UI_MOUSE_LEFT; break;
338 case 4: btn = GATE_UI_MOUSE_SPECIAL1; break;
339 case 5: btn = GATE_UI_MOUSE_SPECIAL2; break;
340 default: btn = GATE_UI_MOUSE_UNKNOWN; break;
341 }
342 point.x = (gate_int32_t)evt->button.x;
343 point.y = (gate_int32_t)evt->button.y;
344
345 paintsurface->on_mouse_down(&paintsurface->ctrl, &point, btn);
346 }
347 return FALSE;
348 }
349 static gboolean gate_ui_gdk_paintsurface_button_release_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
350 {
351 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
352
353 if (paintsurface->on_mouse_up)
354 {
355 gate_ui_point_t point;
356 gate_uint32_t btn = GATE_UI_MOUSE_UNKNOWN;
357 switch (evt->button.button)
358 {
359 case 1: btn = GATE_UI_MOUSE_LEFT; break;
360 case 2: btn = GATE_UI_MOUSE_MIDDLE; break;
361 case 3: btn = GATE_UI_MOUSE_LEFT; break;
362 case 4: btn = GATE_UI_MOUSE_SPECIAL1; break;
363 case 5: btn = GATE_UI_MOUSE_SPECIAL2; break;
364 }
365 point.x = (gate_int32_t)evt->button.x;
366 point.y = (gate_int32_t)evt->button.y;
367
368 paintsurface->on_mouse_up(&paintsurface->ctrl, &point, btn);
369 }
370 return FALSE;
371 }
372 static gboolean gate_ui_gdk_paintsurface_enter_notify_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
373 {
374 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
375 (void)evt;
376 if (paintsurface->on_mouse_enter)
377 {
378 paintsurface->on_mouse_enter(&paintsurface->ctrl);
379 }
380 return FALSE;
381 }
382 static gboolean gate_ui_gdk_paintsurface_leave_notify_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
383 {
384 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
385 (void)evt;
386 if (paintsurface->on_mouse_leave)
387 {
388 paintsurface->on_mouse_leave(&paintsurface->ctrl);
389 }
390 return FALSE;
391 }
392
393 static gboolean gate_ui_gdk_paintsurface_focus_in_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
394 {
395 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
396 (void)evt;
397 if (paintsurface->on_focus_changed)
398 {
399 paintsurface->on_focus_changed(&paintsurface->ctrl, true);
400 }
401 return FALSE;
402 }
403 static gboolean gate_ui_gdk_paintsurface_focus_out_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
404 {
405 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
406 if (paintsurface->on_focus_changed)
407 {
408 paintsurface->on_focus_changed(&paintsurface->ctrl, false);
409 }
410 return FALSE;
411 }
412
413 static gboolean gate_ui_gdk_paintsurface_key_press_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
414 {
415 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
416 gate_input_keycode_t key_code = 0;
417 gate_input_keystates_t ctrl_keys = 0;
418 gate_char32_t chr32 = 0;
419
420 if (GATE_FLAG_ENABLED(evt->key.state, GDK_SHIFT_MASK)) ctrl_keys |= GATE_UI_KEY_SHIFT;
421 if (GATE_FLAG_ENABLED(evt->key.state, GDK_CONTROL_MASK)) ctrl_keys |= GATE_UI_KEY_CTRL;
422 if (GATE_FLAG_ENABLED(evt->key.state, GDK_MOD1_MASK)) ctrl_keys |= GATE_UI_KEY_ALT;
423
424 if (paintsurface->on_key_down)
425 {
426 gate_ui_gtk_convert_keyval(evt->key.keyval, &key_code);
427 paintsurface->on_key_down(&paintsurface->ctrl, key_code, ctrl_keys);
428 }
429 if (paintsurface->on_key_char)
430 {
431 chr32 = gdk_keyval_to_unicode(evt->key.keyval);
432 paintsurface->on_key_char(&paintsurface->ctrl, chr32, ctrl_keys);
433 }
434 return FALSE;
435 }
436 static gboolean gate_ui_gdk_paintsurface_key_release_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
437 {
438 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
439 gate_uint32_t key_code = 0;
440 gate_uint32_t ctrl_keys = 0;
441 gate_char32_t chr32 = 0;
442
443 if (GATE_FLAG_ENABLED(evt->key.state, GDK_SHIFT_MASK)) ctrl_keys |= GATE_UI_KEY_SHIFT;
444 if (GATE_FLAG_ENABLED(evt->key.state, GDK_CONTROL_MASK)) ctrl_keys |= GATE_UI_KEY_CTRL;
445 if (GATE_FLAG_ENABLED(evt->key.state, GDK_MOD1_MASK)) ctrl_keys |= GATE_UI_KEY_ALT;
446
447 if (paintsurface->on_key_up)
448 {
449 gate_ui_gtk_convert_keyval(evt->key.keyval, &key_code);
450 paintsurface->on_key_up(&paintsurface->ctrl, key_code, ctrl_keys);
451 }
452 return FALSE;
453 }
454 static gboolean gate_ui_gdk_paintsurface_scroll_event(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
455 {
456 return FALSE;
457 }
458 static void gate_ui_gdk_paintsurface_destroy(GtkWidget* object, gpointer user_data)
459 {
460
461 }
462
463 static gboolean gate_ui_gdk_paintsurface_draw(GtkWidget* widget, cairo_t* cr, gpointer user_data)
464 {
465 gate_ui_paintsurface_t* paintsurface = (gate_ui_paintsurface_t*)user_data;
466 gate_ui_graphics_t graph = GATE_INIT_EMPTY;
467
468 if (paintsurface && paintsurface->on_paint)
469 {
470 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&paintsurface->ctrl);
471 GtkWidget* w = GATE_UI_GTK_GET_CTRL_WIDGET(&paintsurface->ctrl);
472 int width = gtk_widget_get_allocated_width(w);
473 int height = gtk_widget_get_allocated_height(w);
474 gate_result_t result = gate_ui_graphics_create_native(&graph, host, cr, NULL, width, height);
475 if (GATE_SUCCEEDED(result))
476 {
477 gate_ui_position_t position;
478 position.pos.x = 0;
479 position.pos.y = 0;
480 position.size.width = width;
481 position.size.height = height,
482 paintsurface->on_paint(&paintsurface->ctrl, &graph, &position);
483 }
484 }
485 return FALSE;
486 }
487
488
489
490 static gate_ui_gtk_dispatcher_t gate_ui_gtk_paintsurface_dispatcher =
491 {
492 NULL,
493 NULL,
494 NULL,
495 NULL,
496 NULL,
497 &gate_ui_gtk_paintsurface_refresh,
498 &gate_ui_gtk_paintsurface_destroy
499 };
500
501 #include "gtk/gtkdrawingarea.h"
502
503 gate_result_t gate_ui_paintsurface_create(
504 gate_ui_paintsurface_t* paintsurface, gate_ui_ctrl_t* parent,
505 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
506 {
507 gate_result_t ret = GATE_RESULT_OK;
508 GtkWidget* widget;
509 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
510
511 gate_mem_clear(paintsurface, sizeof(gate_ui_paintsurface_t));
512 widget = gtk_drawing_area_new();
513 if (widget == NULL)
514 {
515 return GATE_RESULT_FAILED;
516 }
517
518 ret = gate_ui_gtk_ctrl_init(&paintsurface->ctrl, widget, host, userparam, parent,
519 &gate_ui_gtk_paintsurface_dispatcher, false, false, position, &flags);
520
521 if (GATE_SUCCEEDED(ret))
522 {
523 gint desired_events = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK
524 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
525 | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
526 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
527 | GDK_FOCUS_CHANGE_MASK | GDK_SCROLL_MASK;
528
529 gtk_widget_add_events(widget, desired_events);
530
531 g_signal_connect(G_OBJECT(widget), "button-press-event", G_CALLBACK(gate_ui_gdk_paintsurface_button_press_event), (gpointer)paintsurface);
532 g_signal_connect(G_OBJECT(widget), "button-release-event", G_CALLBACK(gate_ui_gdk_paintsurface_button_release_event), (gpointer)paintsurface);
533 g_signal_connect(G_OBJECT(widget), "scroll-event", G_CALLBACK(gate_ui_gdk_paintsurface_scroll_event), (gpointer)paintsurface);
534 g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(gate_ui_gdk_paintsurface_key_press_event), (gpointer)paintsurface);
535 g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(gate_ui_gdk_paintsurface_key_release_event), (gpointer)paintsurface);
536 g_signal_connect(G_OBJECT(widget), "enter-notify-event", G_CALLBACK(gate_ui_gdk_paintsurface_enter_notify_event), (gpointer)paintsurface);
537 g_signal_connect(G_OBJECT(widget), "leave-notify-event", G_CALLBACK(gate_ui_gdk_paintsurface_leave_notify_event), (gpointer)paintsurface);
538 g_signal_connect(G_OBJECT(widget), "focus-in-event", G_CALLBACK(gate_ui_gdk_paintsurface_focus_in_event), (gpointer)paintsurface);
539 g_signal_connect(G_OBJECT(widget), "focus-out-event", G_CALLBACK(gate_ui_gdk_paintsurface_focus_out_event), (gpointer)paintsurface);
540 g_signal_connect(G_OBJECT(widget), "draw", G_CALLBACK(gate_ui_gdk_paintsurface_draw), (gpointer)paintsurface);
541 g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(gate_ui_gdk_paintsurface_destroy), (gpointer)paintsurface);
542 }
543
544 return ret;
545 }
546
547 gate_result_t gate_ui_paintsurface_redraw(gate_ui_paintsurface_t* paintsurface)
548 {
549 gate_result_t ret = gate_ui_gtk_ctrl_refresh(&paintsurface->ctrl);
550 return ret;
551 }
552
553 gate_result_t gate_ui_paintsurface_set_cursor(gate_ui_paintsurface_t* paintsurface, gate_ui_cursor_t const* cursor)
554 {
555 return GATE_RESULT_NOTIMPLEMENTED;
556 }
557
558 #endif /* GATE_UI_GTK */
559
560
561
562 #if defined(GATE_UI_MOTIF)
563
564 #include "gate/ui/gateui_motif.h"
565 #include <Xm/DrawingA.h>
566
567 2 static void motif_paintsurface_on_expose(gate_ui_paintsurface_t* surface, gate_ui_position_t const* pos)
568 {
569 gate_result_t result;
570 2 gate_ui_graphics_t graph = GATE_INIT_EMPTY;
571
572 2 result = gate_ui_graphics_create_ctrl(&graph, &surface->ctrl);
573
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(result))
574 {
575 2 surface->on_paint(&surface->ctrl, &graph, pos);
576 2 gate_ui_graphics_destroy(&graph);
577 }
578 2 }
579
580 1 static void drawing_area_callback(Widget widget, XtPointer client_data, XtPointer call_data)
581 {
582 1 XmDrawingAreaCallbackStruct* cbs = (XmDrawingAreaCallbackStruct*)call_data;
583 1 gate_ui_paintsurface_t* surface = (gate_ui_paintsurface_t*)client_data;
584 XEvent* xevt;
585 Display* dpy;
586 1 gate_ui_graphics_t graph = GATE_INIT_EMPTY;
587 1 gate_ui_position_t pos = GATE_INIT_EMPTY;
588 1 Widget w = NULL;
589 gate_result_t result;
590 gate_enumint_t mousebtn;
591
592
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!cbs || !surface)
593 {
594 return;
595 }
596
597 1 xevt = cbs->event;
598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!xevt)
599 {
600 return;
601 }
602 1 dpy = xevt->xany.display;
603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!dpy)
604 {
605 return;
606 }
607 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&surface->ctrl);
608
609
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 switch (cbs->reason)
610 {
611 case XmCR_INPUT:
612 {
613 switch (xevt->xany.type)
614 {
615 case ButtonPress:
616 {
617 pos.pos.x = xevt->xbutton.x;
618 pos.pos.y = xevt->xbutton.y;
619 mousebtn = GATE_UI_MOUSE_UNKNOWN;
620 if (xevt->xbutton.button & Button1Mask) mousebtn = GATE_UI_MOUSE_LEFT;
621 if (xevt->xbutton.button & Button2Mask) mousebtn = GATE_UI_MOUSE_MIDDLE;
622 if (xevt->xbutton.button & Button3Mask) mousebtn = GATE_UI_MOUSE_RIGHT;
623 surface->on_mouse_down(&surface->ctrl, &pos.pos, mousebtn);
624 break;
625 }
626 case ButtonRelease:
627 {
628 pos.pos.x = xevt->xbutton.x;
629 pos.pos.y = xevt->xbutton.y;
630 mousebtn = GATE_UI_MOUSE_UNKNOWN;
631 if (xevt->xbutton.button & Button1Mask) mousebtn = GATE_UI_MOUSE_LEFT;
632 if (xevt->xbutton.button & Button2Mask) mousebtn = GATE_UI_MOUSE_MIDDLE;
633 if (xevt->xbutton.button & Button3Mask) mousebtn = GATE_UI_MOUSE_RIGHT;
634 surface->on_mouse_up(&surface->ctrl, &pos.pos, mousebtn);
635 break;
636 }
637 case MotionNotify:
638 {
639 pos.pos.x = xevt->xmotion.x;
640 pos.pos.y = xevt->xmotion.y;
641 mousebtn = 0;
642 if (xevt->xmotion.state & Button1Mask) mousebtn |= GATE_UI_MOUSE_LEFT;
643 if (xevt->xmotion.state & Button2Mask) mousebtn |= GATE_UI_MOUSE_MIDDLE;
644 if (xevt->xmotion.state & Button3Mask) mousebtn |= GATE_UI_MOUSE_RIGHT;
645 surface->on_mouse_move(&surface->ctrl, &pos.pos, mousebtn);
646 break;
647 }
648 case EnterNotify:
649 {
650 surface->on_mouse_enter(&surface->ctrl);
651 break;
652 }
653 case LeaveNotify:
654 {
655 surface->on_mouse_leave(&surface->ctrl);
656 break;
657 }
658 case KeyPress:
659 {
660 surface->on_key_down(&surface->ctrl, xevt->xkey.keycode, 0);
661 break;
662 }
663 case KeyRelease:
664 {
665 surface->on_key_up(&surface->ctrl, xevt->xkey.keycode, 0);
666 break;
667 }
668 }
669 break;
670 }
671 1 case XmCR_EXPOSE:
672 {
673 1 pos.pos.x = xevt->xexpose.x;
674 1 pos.pos.y = xevt->xexpose.y;
675 1 pos.size.width = xevt->xexpose.width;
676 1 pos.size.height = xevt->xexpose.height;
677 1 motif_paintsurface_on_expose(surface, &pos);
678 1 break;
679 }
680 case XmCR_ACTIVATE:
681 {
682 break;
683 }
684 }
685 1 }
686
687
688 1 gate_result_t gate_ui_paintsurface_create(gate_ui_paintsurface_t* paintsurface, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
689 gate_uint32_t flags, void* userparam)
690 {
691 1 gate_result_t ret = GATE_RESULT_FAILED;
692
693 do
694 {
695 1 Widget w = NULL;
696 Arg args[8];
697 1 unsigned args_count = 0;
698
699
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!paintsurface || !parent)
700 {
701 ret = GATE_RESULT_INVALIDARG;
702 break;
703 }
704
705 1 XtSetArg(args[args_count], XmNrecomputeSize, 0); ++args_count;
706 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
707 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
708
709 1 ret = gate_ui_motif_ctrl_create(&paintsurface->ctrl, xmDrawingAreaWidgetClass, userparam, NULL, parent,
710 position, &flags, false, NULL, args, args_count);
711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
712
713 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&paintsurface->ctrl);
714 1 XtAddCallback(w, XmNinputCallback, &drawing_area_callback, paintsurface);
715 1 XtAddCallback(w, XmNresizeCallback, &drawing_area_callback, paintsurface);
716 1 XtAddCallback(w, XmNexposeCallback, &drawing_area_callback, paintsurface);
717 } while (0);
718
719 1 return ret;
720 }
721
722 1 gate_result_t gate_ui_paintsurface_redraw(gate_ui_paintsurface_t* paintsurface)
723 {
724 Widget w;
725 XExposeEvent xevt;
726 1 gate_ui_host_t* host = NULL;
727 gate_ui_position_t pos;
728 Display* dpy;
729
730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(paintsurface != NULL);
731 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&paintsurface->ctrl);
732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(w != NULL);
733 1 host = GATE_UI_MOTIF_GET_CTRL_HOST(&paintsurface->ctrl);
734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(host != NULL);
735 1 dpy = GATE_UI_MOTIF_GET_HOST_DISPLAY(host);
736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(dpy != NULL);
737
738 1 gate_ui_ctrl_get_position(&paintsurface->ctrl, &pos);
739 1 motif_paintsurface_on_expose(paintsurface, &pos);
740
741 /*
742 xevt.type = Expose;
743 xevt.display = dpy;
744 xevt.window = XtWindow(w);
745 xevt.x = 0;
746 xevt.y = 0;
747 xevt.width = pos.size.width;
748 xevt.height = pos.size.height;
749 xevt.count = 0;
750
751 XSendEvent(dpy, xevt.window, False, ExposureMask, (XEvent*)&xevt);
752 XFlush(dpy);
753 */
754 1 return GATE_RESULT_OK;
755 }
756
757 gate_result_t gate_ui_paintsurface_set_cursor(gate_ui_paintsurface_t* paintsurface, gate_ui_cursor_t const* cursor)
758 {
759 /* TODO */
760 return GATE_RESULT_OK;
761 }
762
763 #endif /* GATE_UI_MOTIF */
764