GCC Code Coverage Report


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