GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/paintsurfaces.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 106 0.0%
Functions: 0 5 0.0%
Branches: 0 46 0.0%

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