Révision | 68ce6f59e103467a3cf6beaee19c388b2d2f3d22 (tree) |
---|---|
l'heure | 2022-08-28 20:28:50 |
Auteur | phabrics <phabrics@phab...> |
Commiter | phabrics |
Work to add SDL driver to display host framework.
@@ -225,15 +225,37 @@ _tme_keyboard_keyval_name(tme_keyboard_keyval_t keyval) | ||
225 | 225 | } |
226 | 226 | #endif |
227 | 227 | |
228 | -/* this is a callback for a key press or release event: */ | |
228 | +/* this is a generic callback for a key press or release event: */ | |
229 | 229 | int |
230 | -_tme_keyboard_key_event(struct tme_keyboard_event *tme_event, | |
231 | - struct tme_display *display) | |
230 | +_tme_keyboard_key_press(int down, tme_keyboard_keyval_t key, void *disp) | |
231 | +{ | |
232 | + struct tme_keyboard_event tme_event; | |
233 | + struct tme_display *display = (_tme_display_get) ? (_tme_display_get(disp)) : (disp); | |
234 | + | |
235 | + /* make a tme event from this key event: */ | |
236 | + tme_event.tme_keyboard_event_type | |
237 | + = (down | |
238 | + ? TME_KEYBOARD_EVENT_PRESS | |
239 | + : TME_KEYBOARD_EVENT_RELEASE); | |
240 | + tme_event.tme_keyboard_event_modifiers | |
241 | + = TME_KEYBOARD_MODIFIER_NONE; | |
242 | + tme_event.tme_keyboard_event_keyval | |
243 | + = key; | |
244 | + tme_event.tme_keyboard_event_time = tme_thread_get_time(); | |
245 | + | |
246 | + return _tme_keyboard_key_event(&tme_event, display); | |
247 | +} | |
248 | + | |
249 | +int | |
250 | +_tme_keyboard_key_event(struct tme_keyboard_event *tme_event, struct tme_display *display) | |
232 | 251 | { |
233 | 252 | int was_empty; |
234 | 253 | int new_callouts; |
235 | 254 | int rc; |
236 | 255 | |
256 | + /* lock the mutex: */ | |
257 | + tme_mutex_lock(&display->tme_display_mutex); | |
258 | + | |
237 | 259 | /* assume that we won't need any new callouts: */ |
238 | 260 | new_callouts = 0; |
239 | 261 |
@@ -264,6 +286,9 @@ _tme_keyboard_key_event(struct tme_keyboard_event *tme_event, | ||
264 | 286 | /* run any callouts: */ |
265 | 287 | //_tme_display_callout(display, new_callouts); |
266 | 288 | |
289 | + /* unlock the mutex: */ | |
290 | + tme_mutex_unlock(&display->tme_display_mutex); | |
291 | + | |
267 | 292 | /* don't process this event any further: */ |
268 | 293 | return (TRUE); |
269 | 294 | } |
@@ -52,15 +52,71 @@ _tme_mouse_debug(const struct tme_mouse_event *event) | ||
52 | 52 | #define _tme_mouse_debug(e) do { } while (/* CONSTCOND */ 0) |
53 | 53 | #endif |
54 | 54 | |
55 | -/* this is a callback for a mouse event in the framebuffer event box: */ | |
55 | +/* this is a generic callback for a mouse event: */ | |
56 | 56 | int |
57 | -_tme_mouse_mouse_event(struct tme_keyboard_event *tme_event, | |
58 | - struct tme_display *display) | |
57 | +_tme_mouse_button_press(int button, int x, int y, struct tme_display *display) | |
59 | 58 | { |
59 | + int state; | |
60 | + | |
61 | + /* make the buttons mask: */ | |
62 | + state = display->tme_screen_mouse_buttons_last; | |
63 | + | |
64 | + if(button>0) | |
65 | + state |= TME_BIT(button-1); | |
66 | + else if(button) { | |
67 | + button = -button; | |
68 | + state &= ~TME_BIT(button-1); | |
69 | + } | |
70 | + | |
71 | + return _tme_mouse_buttons_event(state, x, y, display); | |
72 | +} | |
73 | + | |
74 | +int _tme_mouse_buttons_event(int buttons, int x, int y, void *disp) | |
75 | +{ | |
76 | + struct tme_mouse_event tme_event; | |
60 | 77 | int was_empty; |
61 | - int new_callouts; | |
62 | - int rc; | |
78 | + int new_callouts, rc; | |
79 | + struct tme_display *display = (_tme_display_get) ? (_tme_display_get(disp)) : (disp); | |
80 | + | |
81 | + /* start the tme event: */ | |
82 | + tme_event.tme_mouse_event_delta_units | |
83 | + = TME_MOUSE_UNITS_UNKNOWN; | |
84 | + | |
85 | + /* lock the mutex: */ | |
86 | + tme_mutex_lock(&display->tme_display_mutex); | |
63 | 87 | |
88 | + /* set the event time: */ | |
89 | + tme_event.tme_mouse_event_time = tme_thread_get_time(); | |
90 | + | |
91 | + /* if the button mask and pointer position haven't changed, return now. | |
92 | + every time we warp the pointer we will get a motion event, and | |
93 | + this should ignore those events: */ | |
94 | + | |
95 | + if (buttons == display->tme_screen_mouse_buttons_last | |
96 | + && x == display->tme_screen_mouse_warp_x | |
97 | + && y == display->tme_screen_mouse_warp_y) { | |
98 | + | |
99 | + /* unlock the mutex: */ | |
100 | + tme_mutex_unlock(&display->tme_display_mutex); | |
101 | + | |
102 | + /* stop propagating this event: */ | |
103 | + return (TRUE); | |
104 | + } | |
105 | + | |
106 | + tme_event.tme_mouse_event_buttons = | |
107 | + display->tme_screen_mouse_buttons_last = buttons; | |
108 | + | |
109 | + /* make the deltas: */ | |
110 | + tme_event.tme_mouse_event_delta_x = | |
111 | + (((int) x) | |
112 | + - ((int) display->tme_screen_mouse_warp_x)); | |
113 | + tme_event.tme_mouse_event_delta_y = | |
114 | + (((int) y) | |
115 | + - ((int) display->tme_screen_mouse_warp_y)); | |
116 | + | |
117 | + display->tme_screen_mouse_warp_x = x; | |
118 | + display->tme_screen_mouse_warp_y = y; | |
119 | + | |
64 | 120 | /* assume that we won't need any new callouts: */ |
65 | 121 | new_callouts = 0; |
66 | 122 |
@@ -69,9 +125,9 @@ _tme_mouse_mouse_event(struct tme_keyboard_event *tme_event, | ||
69 | 125 | = tme_mouse_buffer_is_empty(display->tme_display_mouse_buffer); |
70 | 126 | |
71 | 127 | /* add this tme event to the mouse buffer: */ |
72 | - _tme_mouse_debug(tme_event); | |
128 | + _tme_mouse_debug(&tme_event); | |
73 | 129 | rc = tme_mouse_buffer_copyin(display->tme_display_mouse_buffer, |
74 | - tme_event); | |
130 | + &tme_event); | |
75 | 131 | assert (rc == TME_OK); |
76 | 132 | |
77 | 133 | /* if the mouse buffer was empty and now it isn't, |
@@ -87,6 +143,9 @@ _tme_mouse_mouse_event(struct tme_keyboard_event *tme_event, | ||
87 | 143 | /* run any callouts: */ |
88 | 144 | //_tme_display_callout(display, new_callouts); |
89 | 145 | |
146 | + /* unlock the mutex: */ | |
147 | + tme_mutex_unlock(&display->tme_display_mutex); | |
148 | + | |
90 | 149 | /* don't process this event any further: */ |
91 | 150 | return (TRUE); |
92 | 151 | } |
@@ -111,8 +170,8 @@ _tme_mouse_ctrl(struct tme_mouse_connection *conn_mouse, | ||
111 | 170 | /* this is called to read the mouse: */ |
112 | 171 | static int |
113 | 172 | _tme_mouse_read(struct tme_mouse_connection *conn_mouse, |
114 | - struct tme_mouse_event *event, | |
115 | - unsigned int count) | |
173 | + struct tme_mouse_event *event, | |
174 | + unsigned int count) | |
116 | 175 | { |
117 | 176 | struct tme_display *display; |
118 | 177 | int rc; |
@@ -203,6 +203,8 @@ int | ||
203 | 203 | tme_display_update(void *disp) { |
204 | 204 | struct tme_display *display; |
205 | 205 | struct tme_screen *screen; |
206 | + struct tme_fb_connection *conn_fb; | |
207 | + int width, height; | |
206 | 208 | int rc; |
207 | 209 | |
208 | 210 | display = (struct tme_display *)disp; |
@@ -219,6 +221,9 @@ tme_display_update(void *disp) { | ||
219 | 221 | |
220 | 222 | _tme_display_callout(display, 0); |
221 | 223 | |
224 | + width = screen->tme_screen_fb->tme_fb_connection_width; | |
225 | + height = screen->tme_screen_fb->tme_fb_connection_height; | |
226 | + | |
222 | 227 | /* loop over all screens: */ |
223 | 228 | for (screen = display->tme_display_screens; |
224 | 229 | screen != NULL; |
@@ -227,7 +232,7 @@ tme_display_update(void *disp) { | ||
227 | 232 | switch(screen->tme_screen_update) { |
228 | 233 | case TME_SCREEN_UPDATE_REDRAW: |
229 | 234 | if(display->tme_screen_redraw) |
230 | - display->tme_screen_redraw(screen); | |
235 | + display->tme_screen_redraw(screen, 0, 0, width, height); | |
231 | 236 | break; |
232 | 237 | case TME_SCREEN_UPDATE_RESIZE: |
233 | 238 | if(display->tme_screen_resize) |
@@ -555,6 +560,9 @@ _tme_screen_add(struct tme_display *display, | ||
555 | 560 | /* save our connection: */ |
556 | 561 | screen->tme_screen_fb = conn; |
557 | 562 | |
563 | + /* default screen scale: */ | |
564 | + screen->tme_screen_scale = 1; | |
565 | + | |
558 | 566 | /* the user hasn't specified a scaling yet: */ |
559 | 567 | screen->tme_screen_fb_scale |
560 | 568 | = -TME_FB_XLAT_SCALE_NONE; |
@@ -598,7 +606,7 @@ _tme_display_connection_make(struct tme_connection *conn, | ||
598 | 606 | if (state == TME_CONNECTION_FULL) { |
599 | 607 | |
600 | 608 | /* lock our mutex: */ |
601 | - //tme_mutex_lock(&display->tme_display_mutex); | |
609 | + tme_mutex_lock(&display->tme_display_mutex); | |
602 | 610 | |
603 | 611 | /* if our initial screen is already connected, make a new screen: */ |
604 | 612 | screen = (display->tme_screen_add) ? |
@@ -606,10 +614,10 @@ _tme_display_connection_make(struct tme_connection *conn, | ||
606 | 614 | tme_screen_new(display, struct tme_screen, conn); |
607 | 615 | |
608 | 616 | /* unlock our mutex: */ |
609 | - //tme_mutex_unlock(&display->tme_display_mutex); | |
617 | + tme_mutex_unlock(&display->tme_display_mutex); | |
610 | 618 | |
611 | 619 | /* call our mode change function: */ |
612 | - // _tme_screen_mode_change((struct tme_fb_connection *) conn); | |
620 | + _tme_screen_mode_change((struct tme_fb_connection *) conn); | |
613 | 621 | } |
614 | 622 | |
615 | 623 | return (TME_OK); |
@@ -669,9 +677,14 @@ _tme_display_connections_new(struct tme_element *element, | ||
669 | 677 | int tme_display_init(struct tme_element *element, |
670 | 678 | struct tme_display *display) { |
671 | 679 | |
680 | + if(!display) display = tme_new0(struct tme_display, 1); | |
681 | + | |
672 | 682 | /* start our data structure: */ |
673 | 683 | display->tme_display_element = element; |
674 | 684 | |
685 | + /* default display: */ | |
686 | + _tme_display_get = 0; | |
687 | + | |
675 | 688 | /* create the keyboard: */ |
676 | 689 | _tme_keyboard_new(display); |
677 | 690 |
@@ -70,7 +70,7 @@ struct tme_screen { | ||
70 | 70 | struct tme_display *tme_screen_display; |
71 | 71 | |
72 | 72 | /* the framebuffer connection. unlike many other elements, this is |
73 | - *our* side of the framebuffer connection, not the peer's side: */ | |
73 | + *our* side of the framebuffer connection, not the peer's side: */ | |
74 | 74 | struct tme_fb_connection *tme_screen_fb; |
75 | 75 | |
76 | 76 | /* the current scaling. if this is < 0, the user has not forced a |
@@ -152,16 +152,38 @@ struct tme_display { | ||
152 | 152 | int tme_screen_width; |
153 | 153 | int tme_screen_height; |
154 | 154 | |
155 | + /* screen mouse data: */ | |
156 | + int tme_screen_mouse_buttons_last, | |
157 | + tme_screen_mouse_warp_x, | |
158 | + tme_screen_mouse_warp_y; | |
159 | + | |
160 | + /* a convenience pointer for any platform-specific host data: */ | |
161 | + void *tme_screen_data; | |
162 | + | |
155 | 163 | /* implementation-specific callback functions: */ |
156 | 164 | int (*tme_display_bell) _TME_P((struct tme_display *)); |
157 | 165 | int (*tme_display_update) _TME_P((struct tme_display *)); |
158 | 166 | struct tme_screen *(*tme_screen_add) _TME_P((struct tme_display *, struct tme_connection *)); |
159 | 167 | int (*tme_screen_resize) _TME_P((struct tme_screen *)); |
160 | - int (*tme_screen_redraw) _TME_P((struct tme_screen *)); | |
168 | + int (*tme_screen_redraw) _TME_P((struct tme_screen *, int x, int y, int w, int h)); | |
161 | 169 | int (*tme_screen_update) _TME_P((struct tme_screen *)); |
162 | 170 | }; |
163 | 171 | |
164 | 172 | /* prototypes: */ |
173 | +/* this recovers the scanline-pad value for an image buffer: */ | |
174 | +inline unsigned int | |
175 | +_tme_scanline_pad(int bpl) | |
176 | +{ | |
177 | + if ((bpl % sizeof(tme_uint32_t)) == 0) { | |
178 | + return (32); | |
179 | + } | |
180 | + if ((bpl % sizeof(tme_uint16_t)) == 0) { | |
181 | + return (16); | |
182 | + } | |
183 | + return (8); | |
184 | +} | |
185 | + | |
186 | +struct tme_display *(*_tme_display_get) _TME_P((void *)); | |
165 | 187 | struct tme_screen *_tme_screen_add _TME_P((struct tme_display *, |
166 | 188 | size_t, |
167 | 189 | struct tme_connection *)); |
@@ -172,10 +194,12 @@ void _tme_screen_xlat_set _TME_P((struct tme_screen *screen)); | ||
172 | 194 | void _tme_keyboard_new _TME_P((struct tme_display *)); |
173 | 195 | int _tme_keyboard_connections_new _TME_P((struct tme_display *, |
174 | 196 | struct tme_connection **)); |
197 | +int _tme_keyboard_key_press _TME_P((int down, tme_keyboard_keyval_t key, void *disp)); | |
175 | 198 | void _tme_mouse_new _TME_P((struct tme_display *)); |
176 | 199 | void _tme_mouse_mode_off _TME_P((struct tme_screen *, tme_uint32_t)); |
177 | 200 | int _tme_mouse_connections_new _TME_P((struct tme_display *, |
178 | 201 | struct tme_connection **)); |
202 | +int _tme_mouse_buttons_event _TME_P((int buttons, int x, int y, void *disp)); | |
179 | 203 | |
180 | 204 | #endif /* _HOST_DISPLAY_H */ |
181 | 205 |
@@ -6,7 +6,7 @@ AUTOMAKE_OPTIONS = 1.4 gnu | ||
6 | 6 | AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir) -I$(top_srcdir)/lib -I$(srcdir)/.. -I. -D_TME_IMPL $(GTK_CFLAGS) |
7 | 7 | |
8 | 8 | pkglib_LTLIBRARIES = tme_host_gtk.la |
9 | -tme_host_gtk_la_SOURCES = gtk-mouse.c gtk-keyboard.c gtk-screen.c gtk-display.h | |
9 | +tme_host_gtk_la_SOURCES = gtk-mouse.c gtk-keyboard.c gtk-display.c gtk-display.h | |
10 | 10 | tme_host_gtk_la_LDFLAGS = -module -version-info 0:0:0 |
11 | 11 | tme_host_gtk_la_LIBADD = ../libtme-display.la $(GTK_LIBS) |
12 | 12 |
@@ -52,19 +52,6 @@ _tme_gtk_display_update(struct tme_display *display) { | ||
52 | 52 | return TME_OK; |
53 | 53 | } |
54 | 54 | |
55 | -/* this recovers the scanline-pad value for an image buffer: */ | |
56 | -static unsigned int | |
57 | -_tme_gtk_scanline_pad(int bpl) | |
58 | -{ | |
59 | - if ((bpl % sizeof(tme_uint32_t)) == 0) { | |
60 | - return (32); | |
61 | - } | |
62 | - if ((bpl % sizeof(tme_uint16_t)) == 0) { | |
63 | - return (16); | |
64 | - } | |
65 | - return (8); | |
66 | -} | |
67 | - | |
68 | 55 | /* this sets the screen scaling to that indicated by the Scale menu: */ |
69 | 56 | static void |
70 | 57 | _tme_gtk_screen_scale_default(GtkWidget *widget, |
@@ -297,7 +284,7 @@ _tme_gtk_screen_configure(GtkWidget *widget, | ||
297 | 284 | conn_fb->tme_fb_connection_width = cairo_image_surface_get_width(screen->tme_gtk_screen_surface); |
298 | 285 | conn_fb->tme_fb_connection_height = cairo_image_surface_get_height(screen->tme_gtk_screen_surface); |
299 | 286 | conn_fb->tme_fb_connection_skipx = 0; |
300 | - conn_fb->tme_fb_connection_scanline_pad = _tme_gtk_scanline_pad(cairo_image_surface_get_stride(screen->tme_gtk_screen_surface)); | |
287 | + conn_fb->tme_fb_connection_scanline_pad = _tme_scanline_pad(cairo_image_surface_get_stride(screen->tme_gtk_screen_surface)); | |
301 | 288 | conn_fb->tme_fb_connection_order = TME_ENDIAN_NATIVE; |
302 | 289 | conn_fb->tme_fb_connection_buffer = cairo_image_surface_get_data(screen->tme_gtk_screen_surface); |
303 | 290 | conn_fb->tme_fb_connection_buffsz = cairo_image_surface_get_stride(screen->tme_gtk_screen_surface) * conn_fb->tme_fb_connection_height; |
@@ -317,7 +304,7 @@ _tme_gtk_screen_configure(GtkWidget *widget, | ||
317 | 304 | |
318 | 305 | /* this is called before the screen's display is updated: */ |
319 | 306 | static void |
320 | -_tme_gtk_screen_redraw(struct tme_gtk_screen *screen) | |
307 | +_tme_gtk_screen_redraw(struct tme_gtk_screen *screen, int x, int y, int w, int h) | |
321 | 308 | { |
322 | 309 | cairo_surface_flush(screen->tme_gtk_screen_surface); |
323 | 310 | cairo_surface_mark_dirty(screen->tme_gtk_screen_surface); |
@@ -367,9 +354,6 @@ _tme_gtk_screen_new(struct tme_gdk_display *display, | ||
367 | 354 | GtkWidget *menu_item; |
368 | 355 | char title[sizeof(PACKAGE_STRING) + 16]; |
369 | 356 | |
370 | - /* lock our mutex: */ | |
371 | - tme_mutex_lock(&display->display.tme_display_mutex); | |
372 | - | |
373 | 357 | screen = tme_screen_new(display, struct tme_gtk_screen, conn); |
374 | 358 | |
375 | 359 | screen->screen.tme_screen_scale = gdk_monitor_get_scale_factor(display->tme_gdk_display_monitor); |
@@ -455,14 +439,15 @@ _tme_gtk_screen_new(struct tme_gdk_display *display, | ||
455 | 439 | snprintf(title, sizeof(title), "%s (%s)", PACKAGE_STRING, conn->tme_connection_other->tme_connection_element->tme_element_args[0]); |
456 | 440 | gtk_window_set_title(GTK_WINDOW(screen->tme_gtk_screen_window), title); |
457 | 441 | |
458 | - _tme_gtk_screen_resize(screen); | |
459 | - | |
460 | 442 | /* unlock our mutex: */ |
461 | 443 | tme_mutex_unlock(&display->display.tme_display_mutex); |
462 | 444 | |
463 | 445 | /* show the top-level window: */ |
464 | 446 | gtk_widget_show_all(screen->tme_gtk_screen_window); |
465 | 447 | |
448 | + /* lock our mutex: */ | |
449 | + tme_mutex_lock(&display->display.tme_display_mutex); | |
450 | + | |
466 | 451 | return (screen); |
467 | 452 | } |
468 | 453 |
@@ -97,12 +97,6 @@ struct tme_gtk_screen { | ||
97 | 97 | for the framebuffer event box: */ |
98 | 98 | GdkEventMask tme_gtk_screen_mouse_events_old; |
99 | 99 | |
100 | - /* when mouse mode is on, this is the warp center: */ | |
101 | - gint tme_gtk_screen_mouse_warp_x; | |
102 | - gint tme_gtk_screen_mouse_warp_y; | |
103 | - | |
104 | - /* when mouse mode is on, the last tme buttons state: */ | |
105 | - unsigned int tme_gtk_screen_mouse_buttons_last; | |
106 | 100 | }; |
107 | 101 | |
108 | 102 | /* a menu item: */ |
@@ -40,6 +40,7 @@ _TME_RCSID("$Id: gtk-mouse.c,v 1.3 2007/03/03 15:33:22 fredette Exp $"); | ||
40 | 40 | #include "gtk-display.h" |
41 | 41 | #include <gdk/gdkkeysyms.h> |
42 | 42 | |
43 | +#if 0 | |
43 | 44 | /* this warps the pointer to the middle of the Gtkframe: */ |
44 | 45 | void |
45 | 46 | _tme_gtk_mouse_warp_pointer(struct tme_gtk_screen *screen) |
@@ -51,133 +52,56 @@ _tme_gtk_mouse_warp_pointer(struct tme_gtk_screen *screen) | ||
51 | 52 | |
52 | 53 | gdk_device_warp(gdk_seat_get_pointer(display->tme_gdk_display_seat), |
53 | 54 | gdk_screen_get_default(), |
54 | - screen->tme_gtk_screen_mouse_warp_x, | |
55 | - screen->tme_gtk_screen_mouse_warp_y); | |
55 | + screen->screen.tme_screen_mouse_warp_x, | |
56 | + screen->screen.tme_screen_mouse_warp_y); | |
56 | 57 | } |
57 | - | |
58 | +#endif | |
58 | 59 | /* this is a GTK callback for a mouse event in the framebuffer event box: */ |
59 | 60 | static int |
60 | 61 | _tme_gtk_mouse_mouse_event(GtkWidget *widget, |
61 | 62 | GdkEvent *gdk_event_raw, |
62 | - struct tme_gtk_screen *screen) | |
63 | + struct tme_gtk_screen *display) | |
63 | 64 | { |
64 | - struct tme_display *display; | |
65 | - struct tme_mouse_event tme_event; | |
66 | 65 | gint x; |
67 | 66 | gint y; |
68 | - guint state, button; | |
69 | - unsigned int buttons; | |
70 | - int was_empty; | |
71 | - int new_callouts; | |
72 | - int rc; | |
73 | - | |
74 | - /* start the tme event: */ | |
75 | - tme_event.tme_mouse_event_delta_units | |
76 | - = TME_MOUSE_UNITS_UNKNOWN; | |
77 | - | |
78 | - /* recover our data structure: */ | |
79 | - display = screen->screen.tme_screen_display; | |
80 | - | |
81 | - /* lock the mutex: */ | |
82 | - tme_mutex_lock(&display->tme_display_mutex); | |
67 | + int button=0; | |
83 | 68 | |
84 | 69 | /* if this is motion: */ |
85 | 70 | if (gdk_event_raw->type == GDK_MOTION_NOTIFY) { |
86 | 71 | |
87 | - /* this event must have happened in the gtkframe: */ | |
88 | - assert (gdk_event_raw->motion.window | |
89 | - == gtk_widget_get_window(screen->tme_gtk_screen_gtkframe)); | |
90 | - | |
91 | - /* set the event time: */ | |
92 | - tme_event.tme_mouse_event_time | |
93 | - = gdk_event_raw->motion.time; | |
94 | - | |
95 | - /* the buttons haven't changed: */ | |
96 | - tme_event.tme_mouse_event_buttons = | |
97 | - screen->tme_gtk_screen_mouse_buttons_last; | |
98 | - | |
99 | 72 | /* if the pointer position hasn't changed either, return now. |
100 | 73 | every time we warp the pointer we will get a motion event, and |
101 | 74 | this should ignore those events: */ |
102 | 75 | x = gdk_event_raw->motion.x_root; |
103 | 76 | y = gdk_event_raw->motion.y_root; |
104 | - if (x == screen->tme_gtk_screen_mouse_warp_x | |
105 | - && y == screen->tme_gtk_screen_mouse_warp_y) { | |
106 | - | |
107 | - /* unlock the mutex: */ | |
108 | - tme_mutex_unlock(&display->tme_display_mutex); | |
109 | - | |
110 | - /* stop propagating this event: */ | |
111 | - return (TRUE); | |
112 | - } | |
113 | - | |
114 | - } | |
115 | - | |
116 | - /* otherwise, if this is a double- or triple-click: */ | |
117 | - else if (gdk_event_raw->type == GDK_2BUTTON_PRESS | |
118 | - || gdk_event_raw->type == GDK_3BUTTON_PRESS) { | |
119 | - | |
120 | - /* we ignore double- and triple-click events, since normal button | |
121 | - press and release events are always generated also: */ | |
122 | - | |
123 | - /* unlock the mutex: */ | |
124 | - tme_mutex_unlock(&display->tme_display_mutex); | |
125 | 77 | |
126 | - /* stop propagating this event: */ | |
127 | - return (TRUE); | |
128 | 78 | } |
129 | 79 | |
130 | 80 | /* otherwise, this must be a button press or a release: */ |
131 | 81 | else { |
132 | - assert (gdk_event_raw->type == GDK_BUTTON_PRESS | |
133 | - || gdk_event_raw->type == GDK_BUTTON_RELEASE); | |
134 | - | |
135 | - /* this event must have happened in the gtkframe: */ | |
136 | - assert (gdk_event_raw->button.window | |
137 | - == gtk_widget_get_window(screen->tme_gtk_screen_gtkframe)); | |
138 | - | |
139 | - /* set the event time: */ | |
140 | - tme_event.tme_mouse_event_time | |
141 | - = gdk_event_raw->button.time; | |
142 | 82 | |
143 | 83 | /* get the pointer position: */ |
144 | 84 | x = gdk_event_raw->button.x_root; |
145 | 85 | y = gdk_event_raw->button.y_root; |
146 | 86 | |
147 | 87 | /* make the buttons mask: */ |
148 | - buttons = 0; | |
149 | 88 | button = gdk_event_raw->button.button; |
150 | - state = gdk_event_raw->button.state; | |
151 | -#define _TME_GTK_MOUSE_BUTTON(i, gdk, tme) \ | |
152 | - if ((button == i) \ | |
153 | - ? (gdk_event_raw->type == GDK_BUTTON_PRESS) \ | |
154 | - : (state & gdk)) \ | |
155 | - buttons |= tme | |
156 | - _TME_GTK_MOUSE_BUTTON(1, GDK_BUTTON1_MASK, TME_MOUSE_BUTTON_0); | |
157 | - _TME_GTK_MOUSE_BUTTON(2, GDK_BUTTON2_MASK, TME_MOUSE_BUTTON_1); | |
158 | - _TME_GTK_MOUSE_BUTTON(3, GDK_BUTTON3_MASK, TME_MOUSE_BUTTON_2); | |
159 | - _TME_GTK_MOUSE_BUTTON(4, GDK_BUTTON4_MASK, TME_MOUSE_BUTTON_3); | |
160 | - _TME_GTK_MOUSE_BUTTON(5, GDK_BUTTON5_MASK, TME_MOUSE_BUTTON_4); | |
161 | -#undef _TME_GTK_MOUSE_BUTTON | |
162 | - tme_event.tme_mouse_event_buttons = buttons; | |
163 | - screen->tme_gtk_screen_mouse_buttons_last = buttons; | |
89 | + if(gdk_event_raw->type == GDK_BUTTON_RELEASE) | |
90 | + button = -button; | |
164 | 91 | } |
165 | 92 | |
166 | - /* make the deltas: */ | |
167 | - tme_event.tme_mouse_event_delta_x = | |
168 | - (((int) x) | |
169 | - - ((int) screen->tme_gtk_screen_mouse_warp_x)); | |
170 | - tme_event.tme_mouse_event_delta_y = | |
171 | - (((int) y) | |
172 | - - ((int) screen->tme_gtk_screen_mouse_warp_y)); | |
93 | + /* otherwise, if this is a double- or triple-click: */ | |
94 | + if (gdk_event_raw->type != GDK_2BUTTON_PRESS | |
95 | + && gdk_event_raw->type != GDK_3BUTTON_PRESS) { | |
173 | 96 | |
174 | - screen->tme_gtk_screen_mouse_warp_x = x; | |
175 | - screen->tme_gtk_screen_mouse_warp_y = y; | |
176 | - | |
177 | - _tme_mouse_mouse_event(&tme_event, display); | |
97 | + /* we ignore double- and triple-click events, since normal button | |
98 | + press and release events are always generated also: */ | |
99 | + assert (gdk_event_raw->type == GDK_BUTTON_PRESS | |
100 | + || gdk_event_raw->type == GDK_BUTTON_RELEASE); | |
101 | + | |
102 | + _tme_mouse_button_press(button, x, y, display); | |
178 | 103 | |
179 | - /* unlock the mutex: */ | |
180 | - tme_mutex_unlock(&display->tme_display_mutex); | |
104 | + } | |
181 | 105 | |
182 | 106 | /* stop propagating this event: */ |
183 | 107 | return (TRUE); |
@@ -267,8 +191,8 @@ _tme_gtk_mouse_ebox_event(GtkWidget *widget, | ||
267 | 191 | |
268 | 192 | gdk_device_get_position(gdk_seat_get_pointer(display->tme_gdk_display_seat), |
269 | 193 | NULL, |
270 | - &screen->tme_gtk_screen_mouse_warp_x, | |
271 | - &screen->tme_gtk_screen_mouse_warp_y); | |
194 | + &display->display.tme_screen_mouse_warp_x, | |
195 | + &display->display.tme_screen_mouse_warp_y); | |
272 | 196 | |
273 | 197 | /* we are now in mouse mode: */ |
274 | 198 | screen->tme_gtk_screen_mouse_keyval |
@@ -319,13 +243,9 @@ _tme_gtk_mouse_mode_off(struct tme_gtk_screen *screen, | ||
319 | 243 | void |
320 | 244 | _tme_gtk_mouse_attach(struct tme_gtk_screen *screen) |
321 | 245 | { |
322 | - struct tme_display *display; | |
323 | 246 | GtkWidget *hbox0; |
324 | 247 | GtkWidget *ebox; |
325 | 248 | |
326 | - /* get the display: */ | |
327 | - display = screen->screen.tme_screen_display; | |
328 | - | |
329 | 249 | /* create the horizontal packing box for the mouse controls: */ |
330 | 250 | hbox0 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); |
331 | 251 |
@@ -402,15 +322,15 @@ _tme_gtk_mouse_attach(struct tme_gtk_screen *screen) | ||
402 | 322 | g_signal_connect(screen->tme_gtk_screen_gtkframe, |
403 | 323 | "motion_notify_event", |
404 | 324 | G_CALLBACK(_tme_gtk_mouse_mouse_event), |
405 | - screen); | |
325 | + screen->screen.tme_screen_display); | |
406 | 326 | g_signal_connect(screen->tme_gtk_screen_gtkframe, |
407 | 327 | "button_press_event", |
408 | 328 | G_CALLBACK(_tme_gtk_mouse_mouse_event), |
409 | - screen); | |
329 | + screen->screen.tme_screen_display); | |
410 | 330 | g_signal_connect(screen->tme_gtk_screen_gtkframe, |
411 | 331 | "button_release_event", |
412 | 332 | G_CALLBACK(_tme_gtk_mouse_mouse_event), |
413 | - screen); | |
333 | + screen->screen.tme_screen_display); | |
414 | 334 | |
415 | 335 | /* mouse mode is off: */ |
416 | 336 | screen->tme_gtk_screen_mouse_keyval = GDK_KEY_VoidSymbol; |
@@ -41,44 +41,18 @@ | ||
41 | 41 | #include <stdlib.h> |
42 | 42 | |
43 | 43 | static const int bpp=4; |
44 | -static struct tme_display *_display; | |
45 | -/* TODO: odd maxx doesn't work (vncviewer bug) */ | |
46 | - | |
47 | -typedef struct tme_rfb_screen { | |
48 | - int tme_rfb_screen_mouse_buttons_last, | |
49 | - tme_rfb_screen_mouse_warp_x, | |
50 | - tme_rfb_screen_mouse_warp_y; | |
51 | -} tme_rfb_screen; | |
52 | - | |
53 | -typedef struct tme_rfb_display { | |
54 | - /* the generic display structure */ | |
55 | - struct tme_display display; | |
56 | - | |
57 | - rfbScreenInfoPtr server; | |
58 | -} tme_rfb_display; | |
59 | - | |
60 | -static void _tme_rfb_clientgone(rfbClientPtr cl) | |
61 | -{ | |
62 | - free(cl->clientData); | |
63 | - cl->clientData = NULL; | |
64 | -} | |
65 | 44 | |
66 | -static enum rfbNewClientAction _tme_rfb_newclient(rfbClientPtr cl) | |
67 | -{ | |
68 | - cl->clientData = tme_new0(struct tme_rfb_screen, 1); | |
69 | - cl->clientGoneHook = _tme_rfb_clientgone; | |
70 | - return RFB_CLIENT_ACCEPT; | |
71 | -} | |
45 | +/* TODO: odd maxx doesn't work (vncviewer bug) */ | |
72 | 46 | |
73 | 47 | static void |
74 | -_tme_rfb_display_bell(struct tme_rfb_display *display) { | |
75 | - rfbSendBell(display->server); | |
48 | +_tme_rfb_display_bell(struct tme_display *display) { | |
49 | + rfbSendBell(display->tme_screen_data); | |
76 | 50 | } |
77 | 51 | |
78 | 52 | static int |
79 | 53 | _tme_rfb_display_update(struct tme_display *display) { |
80 | 54 | long usec; |
81 | - rfbScreenInfoPtr server = ((tme_rfb_display *)display)->server; | |
55 | + rfbScreenInfoPtr server = display->tme_screen_data; | |
82 | 56 | |
83 | 57 | if(!rfbIsActive(server)) return 1; |
84 | 58 |
@@ -89,15 +63,12 @@ _tme_rfb_display_update(struct tme_display *display) { | ||
89 | 63 | |
90 | 64 | /* this is called before the screen's display is updated: */ |
91 | 65 | static void |
92 | -_tme_rfb_screen_redraw(struct tme_screen *screen) | |
66 | +_tme_rfb_screen_redraw(struct tme_screen *screen, int x, int y, int w, int h) | |
93 | 67 | { |
94 | - struct tme_fb_connection *conn_fb = screen->tme_screen_fb; | |
95 | - rfbScreenInfoPtr server = ((tme_rfb_display *)screen->tme_screen_display)->server; | |
68 | + rfbScreenInfoPtr server = screen->tme_screen_display->tme_screen_data; | |
96 | 69 | |
97 | - if((char *)conn_fb->tme_fb_connection_buffer == server->frameBuffer) | |
98 | - rfbMarkRectAsModified(server, 0, 0, | |
99 | - conn_fb->tme_fb_connection_width, | |
100 | - conn_fb->tme_fb_connection_height); | |
70 | + if((char *)screen->tme_screen_fb->tme_fb_connection_buffer == server->frameBuffer) | |
71 | + rfbMarkRectAsModified(server, x, y, w, h); | |
101 | 72 | } |
102 | 73 | |
103 | 74 | /* switch to new framebuffer contents */ |
@@ -107,9 +78,10 @@ static void _tme_rfb_screen_resize(struct tme_screen *screen) | ||
107 | 78 | struct tme_fb_connection *conn_fb = screen->tme_screen_fb; |
108 | 79 | int width = conn_fb->tme_fb_connection_width; |
109 | 80 | int height = conn_fb->tme_fb_connection_height; |
110 | - rfbScreenInfoPtr server = ((tme_rfb_display *)screen->tme_screen_display)->server; | |
81 | + rfbScreenInfoPtr server = screen->tme_screen_display->tme_screen_data; | |
111 | 82 | |
112 | 83 | conn_fb->tme_fb_connection_buffsz = width * height * bpp; |
84 | + conn_fb->tme_fb_connection_scanline_pad = _tme_scanline_pad(width * bpp); | |
113 | 85 | newfb = (unsigned char*)tme_malloc(conn_fb->tme_fb_connection_buffsz); |
114 | 86 | if(!conn_fb->tme_fb_connection_buffer || |
115 | 87 | (char *)conn_fb->tme_fb_connection_buffer == server->frameBuffer) { |
@@ -122,25 +94,19 @@ static void _tme_rfb_screen_resize(struct tme_screen *screen) | ||
122 | 94 | |
123 | 95 | /* this makes a new screen: */ |
124 | 96 | struct tme_screen * |
125 | -_tme_rfb_screen_new(struct tme_rfb_display *display, | |
97 | +_tme_rfb_screen_new(struct tme_display *display, | |
126 | 98 | struct tme_connection *conn) |
127 | 99 | { |
128 | 100 | struct tme_screen *screen; |
129 | 101 | struct tme_fb_connection *conn_fb; |
130 | - rfbPixelFormat* format=&display->server->serverFormat; | |
131 | - | |
132 | - /* lock our mutex: */ | |
133 | - tme_mutex_lock(&display->display.tme_display_mutex); | |
102 | + rfbPixelFormat* format=&((rfbScreenInfoPtr)display->tme_screen_data)->serverFormat; | |
134 | 103 | |
135 | 104 | screen = tme_screen_new(display, struct tme_screen, conn); |
136 | 105 | |
137 | - screen->tme_screen_scale = 1; | |
138 | - | |
139 | 106 | conn_fb = screen->tme_screen_fb; |
140 | 107 | |
141 | 108 | /* update our framebuffer connection: */ |
142 | 109 | conn_fb->tme_fb_connection_skipx = 0; |
143 | - conn_fb->tme_fb_connection_scanline_pad = 4 * bpp; | |
144 | 110 | conn_fb->tme_fb_connection_order = (format->bigEndian) ? (TME_ENDIAN_BIG) : (TME_ENDIAN_LITTLE); |
145 | 111 | conn_fb->tme_fb_connection_bits_per_pixel = format->bitsPerPixel; |
146 | 112 | conn_fb->tme_fb_connection_depth = format->depth; |
@@ -149,144 +115,69 @@ _tme_rfb_screen_new(struct tme_rfb_display *display, | ||
149 | 115 | conn_fb->tme_fb_connection_mask_b = format->blueMax << format->blueShift; |
150 | 116 | conn_fb->tme_fb_connection_mask_r = format->redMax << format->redShift; |
151 | 117 | |
152 | - _tme_screen_configure(screen); | |
153 | - | |
154 | - /* unlock our mutex: */ | |
155 | - tme_mutex_unlock(&display->display.tme_display_mutex); | |
156 | - | |
157 | 118 | /* We've handled the configure event, no need for further processing. */ |
158 | 119 | return (screen); |
159 | 120 | } |
160 | 121 | |
161 | -/* this is a VNC callback for a key press or release event: */ | |
162 | -static void | |
163 | -_tme_rfb_key_event(rfbBool down, rfbKeySym key, rfbClientPtr cl) | |
164 | -{ | |
165 | - struct tme_keyboard_event tme_event; | |
166 | - | |
167 | - /* make a tme event from this rfb event: */ | |
168 | - tme_event.tme_keyboard_event_type | |
169 | - = (down | |
170 | - ? TME_KEYBOARD_EVENT_PRESS | |
171 | - : TME_KEYBOARD_EVENT_RELEASE); | |
172 | - tme_event.tme_keyboard_event_modifiers | |
173 | - = TME_KEYBOARD_MODIFIER_NONE; | |
174 | - tme_event.tme_keyboard_event_keyval | |
175 | - = key; | |
176 | - tme_event.tme_keyboard_event_time = tme_thread_get_time(); | |
177 | - | |
178 | - /* lock the mutex: */ | |
179 | - tme_mutex_lock(&_display->tme_display_mutex); | |
180 | - | |
181 | - _tme_keyboard_key_event(&tme_event, _display); | |
182 | - | |
183 | - /* unlock the mutex: */ | |
184 | - tme_mutex_unlock(&_display->tme_display_mutex); | |
122 | +static struct tme_display *display; | |
185 | 123 | |
124 | +static void _tme_rfb_clientgone(rfbClientPtr cl) | |
125 | +{ | |
126 | + cl->clientData = NULL; | |
186 | 127 | } |
187 | 128 | |
188 | -/* this is a VNC callback for a mouse event: */ | |
189 | -static int | |
190 | -_tme_rfb_mouse_event(int buttonMask, int x, int y, rfbClientPtr cl) | |
129 | +static enum rfbNewClientAction _tme_rfb_newclient(rfbClientPtr cl) | |
191 | 130 | { |
192 | - struct tme_mouse_event tme_event; | |
193 | - struct tme_rfb_screen *screen = (tme_rfb_screen *)cl->clientData; | |
194 | - | |
195 | - /* start the tme event: */ | |
196 | - tme_event.tme_mouse_event_delta_units | |
197 | - = TME_MOUSE_UNITS_UNKNOWN; | |
198 | - | |
199 | - /* lock the mutex: */ | |
200 | - tme_mutex_lock(&_display->tme_display_mutex); | |
201 | - | |
202 | - /* set the event time: */ | |
203 | - tme_event.tme_mouse_event_time = tme_thread_get_time(); | |
204 | - | |
205 | - /* if the button mask and pointer position haven't changed, return now. | |
206 | - every time we warp the pointer we will get a motion event, and | |
207 | - this should ignore those events: */ | |
208 | - | |
209 | - if (buttonMask == screen->tme_rfb_screen_mouse_buttons_last | |
210 | - && x == screen->tme_rfb_screen_mouse_warp_x | |
211 | - && y == screen->tme_rfb_screen_mouse_warp_y) { | |
212 | - | |
213 | - /* unlock the mutex: */ | |
214 | - tme_mutex_unlock(&_display->tme_display_mutex); | |
215 | - | |
216 | - /* stop propagating this event: */ | |
217 | - return (TRUE); | |
218 | - } | |
219 | - | |
220 | - /* make the buttons mask: */ | |
221 | - tme_event.tme_mouse_event_buttons = | |
222 | - screen->tme_rfb_screen_mouse_buttons_last = buttonMask; | |
223 | - | |
224 | - /* make the deltas: */ | |
225 | - tme_event.tme_mouse_event_delta_x = | |
226 | - (((int) x) | |
227 | - - ((int) screen->tme_rfb_screen_mouse_warp_x)); | |
228 | - tme_event.tme_mouse_event_delta_y = | |
229 | - (((int) y) | |
230 | - - ((int) screen->tme_rfb_screen_mouse_warp_y)); | |
231 | - | |
232 | - screen->tme_rfb_screen_mouse_warp_x = x; | |
233 | - screen->tme_rfb_screen_mouse_warp_y = y; | |
234 | - | |
235 | - _tme_mouse_mouse_event(&tme_event, _display); | |
236 | - | |
237 | - /* unlock the mutex: */ | |
238 | - tme_mutex_unlock(&_display->tme_display_mutex); | |
239 | - | |
240 | - rfbDefaultPtrAddEvent(buttonMask, x, y, cl); | |
241 | - | |
242 | - /* stop propagating this event: */ | |
243 | - return (TRUE); | |
131 | + cl->clientData = display; | |
132 | + cl->clientGoneHook = _tme_rfb_clientgone; | |
133 | + return RFB_CLIENT_ACCEPT; | |
244 | 134 | } |
245 | 135 | |
136 | +static struct tme_display *tme_rfb_display(rfbClientPtr cl) { return cl->clientData; } | |
137 | + | |
246 | 138 | /* the new RFB display function: */ |
247 | 139 | TME_ELEMENT_SUB_NEW_DECL(tme_host_rfb,display) { |
248 | 140 | rfbScreenInfoPtr server; |
249 | - struct tme_rfb_display *display; | |
250 | 141 | int arg_i = 0; |
251 | 142 | |
252 | 143 | while(args[++arg_i] != NULL); |
253 | 144 | |
254 | 145 | /* start our data structure: */ |
255 | - display = tme_new0(struct tme_rfb_display, 1); | |
256 | - tme_display_init(element, display); | |
146 | + tme_display_init(element, 0); | |
257 | 147 | |
148 | + _tme_display_get = tme_rfb_display; | |
149 | + | |
258 | 150 | /* recover our data structure: */ |
259 | 151 | display = element->tme_element_private; |
260 | 152 | |
261 | 153 | /* allocate initial screen structure of the given size: */ |
262 | 154 | // rfbProcessSizeArguments(&maxx, &maxy, &bpp, &arg_i, args); |
263 | 155 | server=rfbGetScreen(&arg_i,args, |
264 | - display->display.tme_screen_width, | |
265 | - display->display.tme_screen_height, | |
156 | + display->tme_screen_width, | |
157 | + display->tme_screen_height, | |
266 | 158 | 8,3,bpp); |
267 | 159 | if(!server) |
268 | 160 | return 1; |
269 | 161 | server->desktopName = "The Machine Emulator"; |
270 | - server->frameBuffer = (char*)tme_malloc(display->display.tme_screen_width * | |
271 | - display->display.tme_screen_height * | |
162 | + server->frameBuffer = (char*)tme_malloc(display->tme_screen_width * | |
163 | + display->tme_screen_height * | |
272 | 164 | bpp); |
273 | 165 | server->alwaysShared = TRUE; |
274 | - server->ptrAddEvent = _tme_rfb_mouse_event; | |
275 | - server->kbdAddEvent = _tme_rfb_key_event; | |
166 | + server->ptrAddEvent = _tme_mouse_buttons_event; | |
167 | + server->kbdAddEvent = _tme_keyboard_key_press; | |
276 | 168 | server->newClientHook = _tme_rfb_newclient; |
277 | 169 | // server->httpDir = "../webclients"; |
278 | 170 | // server->httpEnableProxyConnect = TRUE; |
279 | 171 | rfbInitServer(server); |
280 | 172 | |
281 | - display->server = server; | |
173 | + display->tme_screen_data = server; | |
282 | 174 | |
283 | 175 | /* set the display-specific functions: */ |
284 | - display->display.tme_display_bell = _tme_rfb_display_bell; | |
285 | - display->display.tme_display_update = _tme_rfb_display_update; | |
286 | - display->display.tme_screen_add = _tme_rfb_screen_new; | |
287 | - display->display.tme_screen_resize = _tme_rfb_screen_resize; | |
288 | - display->display.tme_screen_redraw = _tme_rfb_screen_redraw; | |
176 | + display->tme_display_bell = _tme_rfb_display_bell; | |
177 | + display->tme_display_update = _tme_rfb_display_update; | |
178 | + display->tme_screen_add = _tme_rfb_screen_new; | |
179 | + display->tme_screen_resize = _tme_rfb_screen_resize; | |
180 | + display->tme_screen_redraw = _tme_rfb_screen_redraw; | |
289 | 181 | |
290 | - _display = display; | |
291 | 182 | return (TME_OK); |
292 | 183 | } |
@@ -0,0 +1,385 @@ | ||
1 | +/* host/sdl/sdl-display.c - SDL2 support: */ | |
2 | + | |
3 | +/* | |
4 | + * Copyright (c) 2022 Ruben Agin | |
5 | + * All rights reserved. | |
6 | + * | |
7 | + * Redistribution and use in source and binary forms, with or without | |
8 | + * modification, are permitted provided that the following conditions | |
9 | + * are met: | |
10 | + * 1. Redistributions of source code must retain the above copyright | |
11 | + * notice, this list of conditions and the following disclaimer. | |
12 | + * 2. Redistributions in binary form must reproduce the above copyright | |
13 | + * notice, this list of conditions and the following disclaimer in the | |
14 | + * documentation and/or other materials provided with the distribution. | |
15 | + * 3. All advertising materials mentioning features or use of this software | |
16 | + * must display the following acknowledgement: | |
17 | + * This product includes software developed by Matt Fredette. | |
18 | + * 4. The name of the author may not be used to endorse or promote products | |
19 | + * derived from this software without specific prior written permission. | |
20 | + * | |
21 | + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
22 | + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
25 | + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
27 | + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
29 | + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
30 | + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | + * POSSIBILITY OF SUCH DAMAGE. | |
32 | + */ | |
33 | + | |
34 | +#include <tme/common.h> | |
35 | + | |
36 | +/* includes: */ | |
37 | +#include "display.h" | |
38 | +#include <SDL.h> | |
39 | +#include <signal.h> | |
40 | + | |
41 | +struct { char mask; int bits_stored; } utf8Mapping[]= { | |
42 | + {0b00111111, 6}, | |
43 | + {0b01111111, 7}, | |
44 | + {0b00011111, 5}, | |
45 | + {0b00001111, 4}, | |
46 | + {0b00000111, 3}, | |
47 | + {0,0} | |
48 | +}; | |
49 | + | |
50 | +/* TODO: odd maxx doesn't work (vncviewer bug) */ | |
51 | + | |
52 | +static int enableResizable = 1, viewOnly, listenLoop; | |
53 | +struct tme_sdl_screen { | |
54 | + /* the generic screen structure */ | |
55 | + struct tme_screen screen; | |
56 | + int sdlFlags; | |
57 | + SDL_Surface* sdl; | |
58 | + SDL_Texture *sdlTexture; | |
59 | + SDL_Renderer *sdlRenderer; | |
60 | + SDL_Window *sdlWindow; | |
61 | +}; | |
62 | + | |
63 | +/* client's pointer position */ | |
64 | +int x,y; | |
65 | +static int rightAltKeyDown, leftAltKeyDown; | |
66 | +/* switch to new framebuffer contents */ | |
67 | +static void _tme_sdl_screen_resize(struct tme_sdl_screen *screen) | |
68 | +{ | |
69 | + unsigned char *oldfb, *newfb; | |
70 | + struct tme_fb_connection *conn_fb = screen->screen.tme_screen_fb; | |
71 | + int width = conn_fb->tme_fb_connection_width; | |
72 | + int height = conn_fb->tme_fb_connection_height; | |
73 | + int depth = SDL_BITSPERPIXEL(SDL_PIXELFORMAT_RGBA32); | |
74 | + | |
75 | + if (enableResizable) | |
76 | + screen->sdlFlags |= SDL_WINDOW_RESIZABLE; | |
77 | + | |
78 | + /* (re)create the surface used as the client's framebuffer */ | |
79 | + SDL_FreeSurface(screen->sdl); | |
80 | + screen->sdl=SDL_CreateRGBSurface(0, | |
81 | + width, | |
82 | + height, | |
83 | + depth, | |
84 | + 0,0,0,0); | |
85 | + if(!screen->sdl) | |
86 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
87 | + (&display->tme_display_element->tme_element_log_handle, | |
88 | + _("resize: error creating surface: %s\n", SDL_GetError()))); | |
89 | + | |
90 | + /* update our framebuffer connection: */ | |
91 | + conn_fb->tme_fb_connection_width = screen->sdl->pitch / (depth / 8); | |
92 | + conn_fb->tme_fb_connection_buffer = screen->sdl->pixels; | |
93 | + conn_fb->tme_fb_connection_buffsz = screen->sdl->pitch * height; | |
94 | + conn_fb->tme_fb_connection_skipx = 0; | |
95 | + conn_fb->tme_fb_connection_scanline_pad = _tme_scanline_pad(screen->sdl->pitch); | |
96 | + conn_fb->tme_fb_connection_order = TME_ENDIAN_LITTLE; | |
97 | + conn_fb->tme_fb_connection_bits_per_pixel = depth; | |
98 | + conn_fb->tme_fb_connection_depth = 24; | |
99 | + conn_fb->tme_fb_connection_class = TME_FB_XLAT_CLASS_COLOR; | |
100 | + conn_fb->tme_fb_connection_mask_g = screen->sdl->format->Gmask >> screen->sdl->format->Gshift; | |
101 | + conn_fb->tme_fb_connection_mask_b = screen->sdl->format->Bmask >> screen->sdl->format->Bshift; | |
102 | + conn_fb->tme_fb_connection_mask_r = screen->sdl->format->Rmask >> screen->sdl->format->Rshift; | |
103 | + /* create or resize the window */ | |
104 | + if(!screen->sdlWindow) { | |
105 | + screen->sdlWindow = SDL_CreateWindow(display->desktopName, | |
106 | + SDL_WINDOWPOS_UNDEFINED, | |
107 | + SDL_WINDOWPOS_UNDEFINED, | |
108 | + width, | |
109 | + height, | |
110 | + screen->sdlFlags); | |
111 | + if(!screen->sdlWindow) | |
112 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
113 | + (&display->tme_display_element->tme_element_log_handle, | |
114 | + _("resize: error creating window: %s\n", SDL_GetError()))); | |
115 | + } else { | |
116 | + SDL_SetWindowSize(screen->sdlWindow, width, height); | |
117 | + } | |
118 | + /* create the renderer if it does not already exist */ | |
119 | + if(!screen->sdlRenderer) { | |
120 | + screen->sdlRenderer = SDL_CreateRenderer(screen->sdlWindow, -1, 0); | |
121 | + if(!screen->sdlRenderer) | |
122 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
123 | + (&display->tme_display_element->tme_element_log_handle, | |
124 | + _("resize: error creating renderer: %s\n", SDL_GetError()))); | |
125 | + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); /* make the scaled rendering look smoother. */ | |
126 | + } | |
127 | + SDL_RenderSetLogicalSize(screen->sdlRenderer, width, height); /* this is a departure from the SDL1.2-based version, but more in the sense of a VNC viewer in keeeping aspect ratio */ | |
128 | + /* (re)create the texture that sits in between the surface->pixels and the renderer */ | |
129 | + if(screen->sdlTexture) | |
130 | + SDL_DestroyTexture(screen->sdlTexture); | |
131 | + screen->sdlTexture = SDL_CreateTexture(screen->sdlRenderer, | |
132 | + SDL_PIXELFORMAT_ARGB8888, | |
133 | + SDL_TEXTUREACCESS_STREAMING, | |
134 | + width, height); | |
135 | + if(!screen->sdlTexture) | |
136 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
137 | + (&display->tme_display_element->tme_element_log_handle, | |
138 | + _("resize: error creating texture: %s\n", SDL_GetError()))); | |
139 | + return TRUE; | |
140 | +} | |
141 | +#if 0 | |
142 | +static tme_keyboard_keyval_t SDL_key2rfbKeySym(SDL_KeyboardEvent* e) { | |
143 | + tme_keyboard_keyval_t k = 0; | |
144 | + SDL_Keycode sym = e->keysym.sym; | |
145 | + switch (sym) { | |
146 | + case SDLK_BACKSPACE: k = XK_BackSpace; break; | |
147 | + case SDLK_TAB: k = XK_Tab; break; | |
148 | + case SDLK_CLEAR: k = XK_Clear; break; | |
149 | + case SDLK_RETURN: k = XK_Return; break; | |
150 | + case SDLK_PAUSE: k = XK_Pause; break; | |
151 | + case SDLK_ESCAPE: k = XK_Escape; break; | |
152 | + case SDLK_DELETE: k = XK_Delete; break; | |
153 | + case SDLK_KP_0: k = XK_KP_0; break; | |
154 | + case SDLK_KP_1: k = XK_KP_1; break; | |
155 | + case SDLK_KP_2: k = XK_KP_2; break; | |
156 | + case SDLK_KP_3: k = XK_KP_3; break; | |
157 | + case SDLK_KP_4: k = XK_KP_4; break; | |
158 | + case SDLK_KP_5: k = XK_KP_5; break; | |
159 | + case SDLK_KP_6: k = XK_KP_6; break; | |
160 | + case SDLK_KP_7: k = XK_KP_7; break; | |
161 | + case SDLK_KP_8: k = XK_KP_8; break; | |
162 | + case SDLK_KP_9: k = XK_KP_9; break; | |
163 | + case SDLK_KP_PERIOD: k = XK_KP_Decimal; break; | |
164 | + case SDLK_KP_DIVIDE: k = XK_KP_Divide; break; | |
165 | + case SDLK_KP_MULTIPLY: k = XK_KP_Multiply; break; | |
166 | + case SDLK_KP_MINUS: k = XK_KP_Subtract; break; | |
167 | + case SDLK_KP_PLUS: k = XK_KP_Add; break; | |
168 | + case SDLK_KP_ENTER: k = XK_KP_Enter; break; | |
169 | + case SDLK_KP_EQUALS: k = XK_KP_Equal; break; | |
170 | + case SDLK_UP: k = XK_Up; break; | |
171 | + case SDLK_DOWN: k = XK_Down; break; | |
172 | + case SDLK_RIGHT: k = XK_Right; break; | |
173 | + case SDLK_LEFT: k = XK_Left; break; | |
174 | + case SDLK_INSERT: k = XK_Insert; break; | |
175 | + case SDLK_HOME: k = XK_Home; break; | |
176 | + case SDLK_END: k = XK_End; break; | |
177 | + case SDLK_PAGEUP: k = XK_Page_Up; break; | |
178 | + case SDLK_PAGEDOWN: k = XK_Page_Down; break; | |
179 | + case SDLK_F1: k = XK_F1; break; | |
180 | + case SDLK_F2: k = XK_F2; break; | |
181 | + case SDLK_F3: k = XK_F3; break; | |
182 | + case SDLK_F4: k = XK_F4; break; | |
183 | + case SDLK_F5: k = XK_F5; break; | |
184 | + case SDLK_F6: k = XK_F6; break; | |
185 | + case SDLK_F7: k = XK_F7; break; | |
186 | + case SDLK_F8: k = XK_F8; break; | |
187 | + case SDLK_F9: k = XK_F9; break; | |
188 | + case SDLK_F10: k = XK_F10; break; | |
189 | + case SDLK_F11: k = XK_F11; break; | |
190 | + case SDLK_F12: k = XK_F12; break; | |
191 | + case SDLK_F13: k = XK_F13; break; | |
192 | + case SDLK_F14: k = XK_F14; break; | |
193 | + case SDLK_F15: k = XK_F15; break; | |
194 | + case SDLK_NUMLOCKCLEAR: k = XK_Num_Lock; break; | |
195 | + case SDLK_CAPSLOCK: k = XK_Caps_Lock; break; | |
196 | + case SDLK_SCROLLLOCK: k = XK_Scroll_Lock; break; | |
197 | + case SDLK_RSHIFT: k = XK_Shift_R; break; | |
198 | + case SDLK_LSHIFT: k = XK_Shift_L; break; | |
199 | + case SDLK_RCTRL: k = XK_Control_R; break; | |
200 | + case SDLK_LCTRL: k = XK_Control_L; break; | |
201 | + case SDLK_RALT: k = XK_Alt_R; break; | |
202 | + case SDLK_LALT: k = XK_Alt_L; break; | |
203 | + case SDLK_LGUI: k = XK_Super_L; break; | |
204 | + case SDLK_RGUI: k = XK_Super_R; break; | |
205 | +#if 0 | |
206 | + case SDLK_COMPOSE: k = XK_Compose; break; | |
207 | +#endif | |
208 | + case SDLK_MODE: k = XK_Mode_switch; break; | |
209 | + case SDLK_HELP: k = XK_Help; break; | |
210 | + case SDLK_PRINTSCREEN: k = XK_Print; break; | |
211 | + case SDLK_SYSREQ: k = XK_Sys_Req; break; | |
212 | + default: break; | |
213 | + } | |
214 | + /* SDL_TEXTINPUT does not generate characters if ctrl is down, so handle those here */ | |
215 | + if (k == 0 && sym > 0x0 && sym < 0x100 && e->keysym.mod & KMOD_CTRL) | |
216 | + k = sym; | |
217 | + return k; | |
218 | +} | |
219 | +#endif | |
220 | +/* UTF-8 decoding is from https://rosettacode.org/wiki/UTF-8_encode_and_decode which is under GFDL 1.2 */ | |
221 | +static tme_keyboard_keyval_t utf8char2rfbKeySym(const char chr[4]) { | |
222 | + int bytes = strlen(chr); | |
223 | + int shift = utf8Mapping[0].bits_stored * (bytes - 1); | |
224 | + tme_keyboard_keyval_t codep = (*chr++ & utf8Mapping[bytes].mask) << shift; | |
225 | + int i; | |
226 | + for(i = 1; i < bytes; ++i, ++chr) { | |
227 | + shift -= utf8Mapping[0].bits_stored; | |
228 | + codep |= ((char)*chr & utf8Mapping[0].mask) << shift; | |
229 | + } | |
230 | + return codep; | |
231 | +} | |
232 | +static void | |
233 | +_tme_sdl_screen_redraw(struct tme_sdl_screen *screen, int x, int y, int w, int h) | |
234 | +{ | |
235 | + SDL_Surface *sdl = screen->sdl; | |
236 | + /* update texture from surface->pixels */ | |
237 | + SDL_Rect r = {x,y,w,h}; | |
238 | + if(SDL_UpdateTexture(screen->sdlTexture, &r, sdl->pixels + y*sdl->pitch + x*4, sdl->pitch) < 0) | |
239 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
240 | + (&display->tme_display_element->tme_element_log_handle, | |
241 | + _("update: failed to update texture: %s\n", SDL_GetError()))); | |
242 | + /* copy texture to renderer and show */ | |
243 | + if(SDL_RenderClear(screen->sdlRenderer) < 0) | |
244 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
245 | + (&display->tme_display_element->tme_element_log_handle, | |
246 | + _("update: failed to clear renderer: %s\n", SDL_GetError()))); | |
247 | + if(SDL_RenderCopy(screen->sdlRenderer, screen->sdlTexture, NULL, NULL) < 0) | |
248 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
249 | + (&display->tme_display_element->tme_element_log_handle, | |
250 | + _("update: failed to copy texture to renderer: %s\n", SDL_GetError()))); | |
251 | + SDL_RenderPresent(screen->sdlRenderer); | |
252 | +} | |
253 | +static int | |
254 | +_tme_sdl_display_update(struct tme_display *display) { | |
255 | + SDL_Event e; | |
256 | + | |
257 | + if(SDL_PollEvent(&e)) { | |
258 | + | |
259 | + switch(e->type) { | |
260 | + case SDL_WINDOWEVENT: | |
261 | + switch (e->window.event) { | |
262 | + case SDL_WINDOWEVENT_EXPOSED: | |
263 | + SendFramebufferUpdateRequest(cl, 0, 0, | |
264 | + cl->width, cl->height, FALSE); | |
265 | + break; | |
266 | + case SDL_WINDOWEVENT_FOCUS_LOST: | |
267 | + if (rightAltKeyDown) { | |
268 | + _tme_keyboard_key_press(FALSE, SDLK_RALT, display); | |
269 | + rightAltKeyDown = FALSE; | |
270 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
271 | + (&display->tme_display_element->tme_element_log_handle, | |
272 | + _("released right Alt key\n"))); | |
273 | + } | |
274 | + if (leftAltKeyDown) { | |
275 | + _tme_keyboard_key_press(FALSE, SDLK_LALT, display); | |
276 | + leftAltKeyDown = FALSE; | |
277 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
278 | + (&display->tme_display_element->tme_element_log_handle, | |
279 | + _("released left Alt key\n"))); | |
280 | + } | |
281 | + break; | |
282 | + } | |
283 | + break; | |
284 | + case SDL_MOUSEWHEEL: | |
285 | + { | |
286 | + int steps; | |
287 | + if (viewOnly) | |
288 | + break; | |
289 | + if(e->wheel.y > 0) | |
290 | + for(steps = 0; steps < e->wheel.y; ++steps) { | |
291 | + _tme_mouse_button_press(4, x, y, display); | |
292 | + _tme_mouse_button_press(-4, x, y, display); | |
293 | + } | |
294 | + if(e->wheel.y < 0) | |
295 | + for(steps = 0; steps > e->wheel.y; --steps) { | |
296 | + _tme_mouse_button_press(5, x, y, display); | |
297 | + _tme_mouse_button_press(-5, x, y, display); | |
298 | + } | |
299 | + if(e->wheel.x > 0) | |
300 | + for(steps = 0; steps < e->wheel.x; ++steps) { | |
301 | + _tme_mouse_button_press(7, x, y, display); | |
302 | + _tme_mouse_button_press(-7, x, y, display); | |
303 | + } | |
304 | + if(e->wheel.x < 0) | |
305 | + for(steps = 0; steps > e->wheel.x; --steps) { | |
306 | + _tme_mouse_button_press(6, x, y, display); | |
307 | + _tme_mouse_button_press(-6, x, y, display); | |
308 | + } | |
309 | + break; | |
310 | + } | |
311 | + case SDL_MOUSEBUTTONUP: | |
312 | + case SDL_MOUSEBUTTONDOWN: | |
313 | + case SDL_MOUSEMOTION: | |
314 | + { | |
315 | + int button, i; | |
316 | + if (viewOnly) | |
317 | + break; | |
318 | + if (e->type == SDL_MOUSEMOTION) { | |
319 | + x = e->motion.x; | |
320 | + y = e->motion.y; | |
321 | + button = 0; // e->motion.state; | |
322 | + } | |
323 | + else { | |
324 | + x = e->button.x; | |
325 | + y = e->button.y; | |
326 | + button = e->button.button; | |
327 | + if (e->type == SDL_MOUSEBUTTONUP) | |
328 | + button = -button; | |
329 | + } | |
330 | + _tme_mouse_button_press(button, x, y, display); | |
331 | + break; | |
332 | + } | |
333 | + case SDL_KEYUP: | |
334 | + case SDL_KEYDOWN: | |
335 | + if (viewOnly) | |
336 | + break; | |
337 | + _tme_keyboard_key_press(e->type == SDL_KEYDOWN ? TRUE : FALSE, | |
338 | + e->keysym.sym, display); | |
339 | + if (e->key.keysym.sym == SDLK_RALT) | |
340 | + rightAltKeyDown = e->type == SDL_KEYDOWN; | |
341 | + if (e->key.keysym.sym == SDLK_LALT) | |
342 | + leftAltKeyDown = e->type == SDL_KEYDOWN; | |
343 | + break; | |
344 | + case SDL_TEXTINPUT: | |
345 | + if (viewOnly) | |
346 | + break; | |
347 | + tme_keyboard_keyval_t sym = utf8char2rfbKeySym(e->text.text); | |
348 | + _tme_keyboard_key_press(TRUE, sym, display); | |
349 | + _tme_keyboard_key_press(FALSE, sym, display); | |
350 | + break; | |
351 | + default: | |
352 | + tme_log(&display->tme_display_element->tme_element_log_handle, 0, TME_OK, | |
353 | + (&display->tme_display_element->tme_element_log_handle, | |
354 | + _("ignore SDL event: 0x%x\n", e->type))); | |
355 | + } | |
356 | + return TRUE; | |
357 | + } | |
358 | +} | |
359 | + | |
360 | +/* the new SDL display function: */ | |
361 | +TME_ELEMENT_SUB_NEW_DECL(tme_host_sdl,display) { | |
362 | + struct tme_display *display; | |
363 | + int arg_i = 0; | |
364 | + | |
365 | + while(args[++arg_i] != NULL); | |
366 | + | |
367 | + /* start our data structure: */ | |
368 | + display = tme_new0(struct tme_display, 1); | |
369 | + tme_display_init(element, display); | |
370 | + | |
371 | + /* recover our data structure: */ | |
372 | + display = element->tme_element_private; | |
373 | + | |
374 | + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE); | |
375 | + atexit(SDL_Quit); | |
376 | + signal(SIGINT, exit); | |
377 | + | |
378 | + /* set the display-specific functions: */ | |
379 | + // display->tme_display_bell = _tme_sdl_display_bell; | |
380 | + display->tme_display_update = _tme_sdl_display_update; | |
381 | + display->tme_screen_resize = _tme_sdl_screen_resize; | |
382 | + display->tme_screen_redraw = _tme_sdl_screen_redraw; | |
383 | + | |
384 | + return (TME_OK); | |
385 | +} |