1 /* $Id: gtk-mouse.c,v 1.3 2007/03/03 15:33:22 fredette Exp $ */
2
3 /* host/gtk/gtk-mouse.c - GTK mouse support: */
4
5 /*
6 * Copyright (c) 2003 Matt Fredette
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Matt Fredette.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <tme/common.h>
37 _TME_RCSID("$Id: gtk-mouse.c,v 1.3 2007/03/03 15:33:22 fredette Exp $");
38
39 /* includes: */
40 #include "gtk-display.h"
41 #include <gdk/gdkkeysyms.h>
42
43 /* macros: */
44 #define TME_GTK_MOUSE_CURSOR_WIDTH (16)
45 #define TME_GTK_MOUSE_CURSOR_HEIGHT (16)
46
47 /* types: */
48
49 /* globals: */
50
51 /* our invisible cursor: */
52 static const gchar _tme_gtk_mouse_cursor_source[(TME_GTK_MOUSE_CURSOR_WIDTH
53 * TME_GTK_MOUSE_CURSOR_HEIGHT
54 / 8)] =
55 {
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 };
61 static const gchar _tme_gtk_mouse_cursor_mask[(TME_GTK_MOUSE_CURSOR_WIDTH
62 * TME_GTK_MOUSE_CURSOR_HEIGHT
63 / 8)] =
64 {
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 };
70 static GdkColor _tme_gtk_mouse_cursor_color = { 0, 0, 0, 0 };
71
72 /* if X11 support is present: */
73 #ifndef X_DISPLAY_MISSING
74
75 /* includes: */
76 #include <gdk/gdkx.h>
77 #include <X11/Xlib.h>
78
79 #if TME_MOUSE_EVENT_TIME_UNDEF != CurrentTime
80 #error "TME_MOUSE_EVENT_TIME_UNDEF and CurrentTime disagree"
81 #endif
82
83 /* this warps the pointer to the middle of the GtkImage: */
84 static void
_tme_gtk_mouse_warp_pointer(struct tme_gtk_screen * screen)85 _tme_gtk_mouse_warp_pointer(struct tme_gtk_screen *screen)
86 {
87 XWarpPointer(GDK_DISPLAY(),
88 None,
89 GDK_WINDOW_XWINDOW(screen->tme_gtk_screen_gtkimage->window),
90 0, 0, 0, 0,
91 screen->tme_gtk_screen_mouse_warp_x,
92 screen->tme_gtk_screen_mouse_warp_y);
93 }
94
95 #endif /* !X_DISPLAY_MISSING */
96
97 /* this is for debugging only: */
98 #if 0
99 #include <stdio.h>
100 void
101 _tme_gtk_mouse_debug(const struct tme_mouse_event *event)
102 {
103 fprintf(stderr,
104 "buttons = 0x%02x dx=%d dy=%d\n",
105 event->tme_mouse_event_buttons,
106 event->tme_mouse_event_delta_x,
107 event->tme_mouse_event_delta_y);
108 }
109 #else
110 #define _tme_gtk_mouse_debug(e) do { } while (/* CONSTCOND */ 0)
111 #endif
112
113 /* this is a GTK callback for a mouse event in the framebuffer event box: */
114 static int
_tme_gtk_mouse_mouse_event(GtkWidget * widget,GdkEvent * gdk_event_raw,struct tme_gtk_screen * screen)115 _tme_gtk_mouse_mouse_event(GtkWidget *widget,
116 GdkEvent *gdk_event_raw,
117 struct tme_gtk_screen *screen)
118 {
119 struct tme_gtk_display *display;
120 struct tme_mouse_event tme_event;
121 gint x;
122 gint y;
123 guint state, button;
124 unsigned int buttons;
125 int was_empty;
126 int new_callouts;
127 int rc;
128
129 /* start the tme event: */
130 tme_event.tme_mouse_event_delta_units
131 = TME_MOUSE_UNITS_UNKNOWN;
132
133 /* recover our data structure: */
134 display = screen->tme_gtk_screen_display;
135
136 /* lock the mutex: */
137 tme_mutex_lock(&display->tme_gtk_display_mutex);
138
139 /* if this is motion: */
140 if (gdk_event_raw->type == GDK_MOTION_NOTIFY) {
141
142 /* this event must have happened in the gtkimage: */
143 assert (gdk_event_raw->motion.window
144 == screen->tme_gtk_screen_gtkimage->window);
145
146 /* set the event time: */
147 tme_event.tme_mouse_event_time
148 = gdk_event_raw->motion.time;
149
150 /* the buttons haven't changed: */
151 tme_event.tme_mouse_event_buttons =
152 screen->tme_gtk_screen_mouse_buttons_last;
153
154 /* if the pointer position hasn't changed either, return now.
155 every time we warp the pointer we will get a motion event, and
156 this should ignore those events: */
157 x = gdk_event_raw->motion.x;
158 y = gdk_event_raw->motion.y;
159 if (x == screen->tme_gtk_screen_mouse_warp_x
160 && y == screen->tme_gtk_screen_mouse_warp_y) {
161
162 /* unlock the mutex: */
163 tme_mutex_unlock(&display->tme_gtk_display_mutex);
164
165 /* stop propagating this event: */
166 return (TRUE);
167 }
168
169 /* warp the pointer back to center: */
170 _tme_gtk_mouse_warp_pointer(screen);
171 }
172
173 /* otherwise, if this is a double- or triple-click: */
174 else if (gdk_event_raw->type == GDK_2BUTTON_PRESS
175 || gdk_event_raw->type == GDK_3BUTTON_PRESS) {
176
177 /* we ignore double- and triple-click events, since normal button
178 press and release events are always generated also: */
179
180 /* unlock the mutex: */
181 tme_mutex_unlock(&display->tme_gtk_display_mutex);
182
183 /* stop propagating this event: */
184 return (TRUE);
185 }
186
187 /* otherwise, this must be a button press or a release: */
188 else {
189 assert (gdk_event_raw->type == GDK_BUTTON_PRESS
190 || gdk_event_raw->type == GDK_BUTTON_RELEASE);
191
192 /* this event must have happened in the gtkimage: */
193 assert (gdk_event_raw->button.window
194 == screen->tme_gtk_screen_gtkimage->window);
195
196 /* set the event time: */
197 tme_event.tme_mouse_event_time
198 = gdk_event_raw->button.time;
199
200 /* get the pointer position: */
201 x = gdk_event_raw->button.x;
202 y = gdk_event_raw->button.y;
203
204 /* make the buttons mask: */
205 buttons = 0;
206 button = gdk_event_raw->button.button;
207 state = gdk_event_raw->button.state;
208 #define _TME_GTK_MOUSE_BUTTON(i, gdk, tme) \
209 if ((button == i) \
210 ? (gdk_event_raw->type == GDK_BUTTON_PRESS) \
211 : (state & gdk)) \
212 buttons |= tme
213 _TME_GTK_MOUSE_BUTTON(1, GDK_BUTTON1_MASK, TME_MOUSE_BUTTON_0);
214 _TME_GTK_MOUSE_BUTTON(2, GDK_BUTTON2_MASK, TME_MOUSE_BUTTON_1);
215 _TME_GTK_MOUSE_BUTTON(3, GDK_BUTTON3_MASK, TME_MOUSE_BUTTON_2);
216 _TME_GTK_MOUSE_BUTTON(4, GDK_BUTTON4_MASK, TME_MOUSE_BUTTON_3);
217 _TME_GTK_MOUSE_BUTTON(5, GDK_BUTTON5_MASK, TME_MOUSE_BUTTON_4);
218 #undef _TME_GTK_MOUSE_BUTTON
219 tme_event.tme_mouse_event_buttons = buttons;
220 screen->tme_gtk_screen_mouse_buttons_last = buttons;
221 }
222
223 /* make the deltas: */
224 tme_event.tme_mouse_event_delta_x =
225 (((int) x)
226 - ((int) screen->tme_gtk_screen_mouse_warp_x));
227 tme_event.tme_mouse_event_delta_y =
228 (((int) y)
229 - ((int) screen->tme_gtk_screen_mouse_warp_y));
230
231 /* assume that we won't need any new callouts: */
232 new_callouts = 0;
233
234 /* remember if the mouse buffer was empty: */
235 was_empty
236 = tme_mouse_buffer_is_empty(display->tme_gtk_display_mouse_buffer);
237
238 /* add this tme event to the mouse buffer: */
239 _tme_gtk_mouse_debug(&tme_event);
240 rc = tme_mouse_buffer_copyin(display->tme_gtk_display_mouse_buffer,
241 &tme_event);
242 assert (rc == TME_OK);
243
244 /* if the mouse buffer was empty and now it isn't,
245 call out the mouse controls: */
246 if (was_empty
247 && !tme_mouse_buffer_is_empty(display->tme_gtk_display_mouse_buffer)) {
248 new_callouts |= TME_GTK_DISPLAY_CALLOUT_MOUSE_CTRL;
249 }
250
251 /* run any callouts: */
252 _tme_gtk_display_callout(display, new_callouts);
253
254 /* unlock the mutex: */
255 tme_mutex_unlock(&display->tme_gtk_display_mutex);
256
257 /* stop propagating this event: */
258 return (TRUE);
259 }
260
261 /* this is a GTK callback for an event in the event box containing the
262 mouse label: */
263 static int
_tme_gtk_mouse_ebox_event(GtkWidget * widget,GdkEvent * gdk_event_raw,struct tme_gtk_screen * screen)264 _tme_gtk_mouse_ebox_event(GtkWidget *widget,
265 GdkEvent *gdk_event_raw,
266 struct tme_gtk_screen *screen)
267 {
268 struct tme_gtk_display *display;
269 int rc;
270 gint junk;
271 char *status;
272
273 /* if this is an enter notify event, grab the focus and continue
274 propagating the event: */
275 if (gdk_event_raw->type == GDK_ENTER_NOTIFY) {
276 gtk_widget_grab_focus(widget);
277 return (FALSE);
278 }
279
280 /* if this is not a key press event, continue propagating it now: */
281 if (gdk_event_raw->type != GDK_KEY_PRESS) {
282 return (FALSE);
283 }
284
285 /* recover our data structure: */
286 display = screen->tme_gtk_screen_display;
287
288 /* lock the mutex: */
289 tme_mutex_lock(&display->tme_gtk_display_mutex);
290
291 /* the mouse must not be on already: */
292 assert (screen->tme_gtk_screen_mouse_keyval
293 == GDK_VoidSymbol);
294
295 /* this keyval must not be GDK_VoidSymbol: */
296 assert (gdk_event_raw->key.keyval
297 != GDK_VoidSymbol);
298
299 /* set the text on the mouse label: */
300 gtk_label_set_text(GTK_LABEL(screen->tme_gtk_screen_mouse_label),
301 _("Mouse is on"));
302
303 /* push the mouse status onto the statusbar: */
304 status = NULL;
305 tme_output_append(&status,
306 _("Press the %s key to turn the mouse off"),
307 gdk_keyval_name(gdk_event_raw->key.keyval));
308 gtk_statusbar_push(GTK_STATUSBAR(screen->tme_gtk_screen_mouse_statusbar),
309 screen->tme_gtk_screen_mouse_statusbar_cid,
310 status);
311 tme_free(status);
312
313 /* if the original events mask on the framebuffer event box have
314 never been saved, save them now, and add the mouse events: */
315 if (screen->tme_gtk_screen_mouse_events_old == 0) {
316 screen->tme_gtk_screen_mouse_events_old
317 = gdk_window_get_events(screen->tme_gtk_screen_event_box->window);
318 gtk_widget_add_events(screen->tme_gtk_screen_event_box,
319 GDK_POINTER_MOTION_MASK
320 | GDK_BUTTON_PRESS_MASK
321 | GDK_BUTTON_RELEASE_MASK);
322 }
323
324 /* get the current width and height of the framebuffer gtkimage, and
325 halve them to get the warp center: */
326 gdk_window_get_geometry(screen->tme_gtk_screen_gtkimage->window,
327 &junk,
328 &junk,
329 &screen->tme_gtk_screen_mouse_warp_x,
330 &screen->tme_gtk_screen_mouse_warp_y,
331 &junk);
332 screen->tme_gtk_screen_mouse_warp_x >>= 1;
333 screen->tme_gtk_screen_mouse_warp_y >>= 1;
334
335 /* warp the pointer to center: */
336 _tme_gtk_mouse_warp_pointer(screen);
337
338 /* grab the pointer: */
339 rc
340 = gdk_pointer_grab(screen->tme_gtk_screen_gtkimage->window,
341 TRUE,
342 GDK_POINTER_MOTION_MASK
343 | GDK_BUTTON_PRESS_MASK
344 | GDK_BUTTON_RELEASE_MASK,
345 screen->tme_gtk_screen_gtkimage->window,
346 display->tme_gtk_display_mouse_cursor,
347 gdk_event_raw->key.time);
348 assert (rc == 0);
349
350 /* we are now in mouse mode: */
351 screen->tme_gtk_screen_mouse_keyval
352 = gdk_event_raw->key.keyval;
353
354 /* unlock the mutex: */
355 tme_mutex_unlock(&display->tme_gtk_display_mutex);
356
357 /* stop propagating this event: */
358 return (TRUE);
359 }
360
361 /* this turns mouse mode off. it is called with the mutex locked: */
362 void
_tme_gtk_mouse_mode_off(struct tme_gtk_screen * screen,guint32 time)363 _tme_gtk_mouse_mode_off(struct tme_gtk_screen *screen,
364 guint32 time)
365 {
366 /* the mouse must be on: */
367 assert (screen->tme_gtk_screen_mouse_keyval
368 != GDK_VoidSymbol);
369
370 /* ungrab the pointer: */
371 gdk_pointer_ungrab(time);
372
373 /* restore the old events mask on the event box: */
374 gdk_window_set_events(screen->tme_gtk_screen_event_box->window,
375 screen->tme_gtk_screen_mouse_events_old);
376
377 /* pop our message off of the statusbar: */
378 gtk_statusbar_pop(GTK_STATUSBAR(screen->tme_gtk_screen_mouse_statusbar),
379 screen->tme_gtk_screen_mouse_statusbar_cid);
380
381 /* restore the text on the mouse label: */
382 gtk_label_set_text(GTK_LABEL(screen->tme_gtk_screen_mouse_label),
383 _("Mouse is off"));
384
385 /* the mouse is now off: */
386 screen->tme_gtk_screen_mouse_keyval = GDK_VoidSymbol;
387 }
388
389 /* this is called when the mouse controls change: */
390 static int
_tme_gtk_mouse_ctrl(struct tme_mouse_connection * conn_mouse,unsigned int ctrl)391 _tme_gtk_mouse_ctrl(struct tme_mouse_connection *conn_mouse,
392 unsigned int ctrl)
393 {
394 struct tme_gtk_display *display;
395
396 /* recover our data structure: */
397 display = conn_mouse
398 ->tme_mouse_connection.tme_connection_element->tme_element_private;
399
400 /* XXX TBD */
401 abort();
402
403 return (TME_OK);
404 }
405
406 /* this is called to read the mouse: */
407 static int
_tme_gtk_mouse_read(struct tme_mouse_connection * conn_mouse,struct tme_mouse_event * event,unsigned int count)408 _tme_gtk_mouse_read(struct tme_mouse_connection *conn_mouse,
409 struct tme_mouse_event *event,
410 unsigned int count)
411 {
412 struct tme_gtk_display *display;
413 int rc;
414
415 /* recover our data structure: */
416 display = conn_mouse
417 ->tme_mouse_connection.tme_connection_element->tme_element_private;
418
419 /* lock the mutex: */
420 tme_mutex_lock(&display->tme_gtk_display_mutex);
421
422 /* copy an event out of the mouse buffer: */
423 rc = tme_mouse_buffer_copyout(display->tme_gtk_display_mouse_buffer,
424 event,
425 count);
426
427 /* unlock the mutex: */
428 tme_mutex_unlock(&display->tme_gtk_display_mutex);
429
430 return (rc);
431 }
432
433 /* this breaks a mouse connection: */
434 static int
_tme_gtk_mouse_connection_break(struct tme_connection * conn,unsigned int state)435 _tme_gtk_mouse_connection_break(struct tme_connection *conn,
436 unsigned int state)
437 {
438 abort();
439 }
440
441 /* this makes a new mouse connection: */
442 static int
_tme_gtk_mouse_connection_make(struct tme_connection * conn,unsigned int state)443 _tme_gtk_mouse_connection_make(struct tme_connection *conn,
444 unsigned int state)
445 {
446 struct tme_gtk_display *display;
447
448 /* recover our data structure: */
449 display = conn->tme_connection_element->tme_element_private;
450
451 /* both sides must be mouse connections: */
452 assert(conn->tme_connection_type
453 == TME_CONNECTION_MOUSE);
454 assert(conn->tme_connection_other->tme_connection_type
455 == TME_CONNECTION_MOUSE);
456
457 /* we are always set up to answer calls across the connection, so we
458 only have to do work when the connection has gone full, namely
459 taking the other side of the connection: */
460 if (state == TME_CONNECTION_FULL) {
461
462 /* save our connection: */
463 tme_mutex_lock(&display->tme_gtk_display_mutex);
464 display->tme_gtk_display_mouse_connection
465 = (struct tme_mouse_connection *) conn->tme_connection_other;
466 tme_mutex_unlock(&display->tme_gtk_display_mutex);
467 }
468
469 return (TME_OK);
470 }
471
472 /* this scores a mouse connection: */
473 static int
_tme_gtk_mouse_connection_score(struct tme_connection * conn,unsigned int * _score)474 _tme_gtk_mouse_connection_score(struct tme_connection *conn,
475 unsigned int *_score)
476 {
477 struct tme_mouse_connection *conn_mouse;
478
479 /* both sides must be mouse connections: */
480 assert(conn->tme_connection_type == TME_CONNECTION_MOUSE);
481 assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_MOUSE);
482
483 /* the other side cannot be a real mouse: */
484 conn_mouse
485 = (struct tme_mouse_connection *) conn->tme_connection_other;
486 *_score = (conn_mouse->tme_mouse_connection_read == NULL);
487 return (TME_OK);
488 }
489
490 /* this makes a new connection side for a GTK mouse: */
491 int
_tme_gtk_mouse_connections_new(struct tme_gtk_display * display,struct tme_connection ** _conns)492 _tme_gtk_mouse_connections_new(struct tme_gtk_display *display,
493 struct tme_connection **_conns)
494 {
495 struct tme_mouse_connection *conn_mouse;
496 struct tme_connection *conn;
497
498 /* if we don't have a mouse connection yet: */
499 if (display->tme_gtk_display_mouse_connection == NULL) {
500
501 /* create our side of a mouse connection: */
502 conn_mouse = tme_new0(struct tme_mouse_connection, 1);
503 conn = &conn_mouse->tme_mouse_connection;
504
505 /* fill in the generic connection: */
506 conn->tme_connection_next = *_conns;
507 conn->tme_connection_type = TME_CONNECTION_MOUSE;
508 conn->tme_connection_score = _tme_gtk_mouse_connection_score;
509 conn->tme_connection_make = _tme_gtk_mouse_connection_make;
510 conn->tme_connection_break = _tme_gtk_mouse_connection_break;
511
512 /* fill in the mouse connection: */
513 conn_mouse->tme_mouse_connection_ctrl = _tme_gtk_mouse_ctrl;
514 conn_mouse->tme_mouse_connection_read = _tme_gtk_mouse_read;
515
516 /* return the connection side possibility: */
517 *_conns = conn;
518 }
519
520 /* done: */
521 return (TME_OK);
522 }
523
524 /* this attaches the GTK mouse to a new screen: */
525 void
_tme_gtk_mouse_attach(struct tme_gtk_screen * screen)526 _tme_gtk_mouse_attach(struct tme_gtk_screen *screen)
527 {
528 struct tme_gtk_display *display;
529 GtkWidget *hbox0;
530 GtkWidget *ebox;
531
532 /* get the display: */
533 display = screen->tme_gtk_screen_display;
534
535 /* create the horizontal packing box for the mouse controls: */
536 hbox0 = gtk_hbox_new(FALSE, 0);
537
538 /* pack the horizontal packing box into the outer vertical packing box: */
539 gtk_box_pack_start(GTK_BOX(screen->tme_gtk_screen_vbox0),
540 hbox0,
541 FALSE, FALSE, 0);
542
543 /* show the horizontal packing box: */
544 gtk_widget_show(hbox0);
545
546 /* create the event box for the mouse on label: */
547 ebox = gtk_event_box_new();
548
549 /* pack the event box into the horizontal packing box: */
550 gtk_box_pack_start(GTK_BOX(hbox0),
551 ebox,
552 FALSE, FALSE, 0);
553
554 /* set the tip on the event box, which will eventually contain the mouse on label: */
555 gtk_tooltips_set_tip(GTK_TOOLTIPS(display->tme_gtk_display_tooltips),
556 ebox,
557 "Press a key here to turn the mouse on. The same key " \
558 "will turn the mouse off.",
559 NULL);
560
561 /* make sure the event box gets key_press events: */
562 gtk_widget_add_events(ebox,
563 GDK_KEY_PRESS_MASK);
564
565 /* set a signal handler for the event box events: */
566 gtk_signal_connect(GTK_OBJECT(ebox),
567 "event",
568 GTK_SIGNAL_FUNC(_tme_gtk_mouse_ebox_event),
569 screen);
570
571 /* the event box can focus: */
572 GTK_WIDGET_SET_FLAGS(ebox, GTK_CAN_FOCUS);
573
574 /* show the event box: */
575 gtk_widget_show(ebox);
576
577 /* create the mouse on label: */
578 screen->tme_gtk_screen_mouse_label
579 = gtk_label_new(_("Mouse is off"));
580
581 /* add the mouse on label to the event box: */
582 gtk_container_add(GTK_CONTAINER(ebox),
583 screen->tme_gtk_screen_mouse_label);
584
585 /* show the mouse on label: */
586 gtk_widget_show(screen->tme_gtk_screen_mouse_label);
587
588 /* create the mouse statusbar: */
589 screen->tme_gtk_screen_mouse_statusbar
590 = gtk_statusbar_new();
591
592 /* pack the mouse statusbar into the horizontal packing box: */
593 gtk_box_pack_start(GTK_BOX(hbox0),
594 screen->tme_gtk_screen_mouse_statusbar,
595 TRUE, TRUE, 10);
596
597 /* show the mouse statusbar: */
598 gtk_widget_show(screen->tme_gtk_screen_mouse_statusbar);
599
600 /* push an initial message onto the statusbar: */
601 screen->tme_gtk_screen_mouse_statusbar_cid
602 = gtk_statusbar_get_context_id(GTK_STATUSBAR(screen->tme_gtk_screen_mouse_statusbar),
603 "mouse context");
604 gtk_statusbar_push(GTK_STATUSBAR(screen->tme_gtk_screen_mouse_statusbar),
605 screen->tme_gtk_screen_mouse_statusbar_cid,
606 _("The Machine Emulator"));
607
608 /* although the event mask doesn't include these events yet,
609 set a signal handler for the mouse events: */
610 gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
611 "motion_notify_event",
612 GTK_SIGNAL_FUNC(_tme_gtk_mouse_mouse_event),
613 screen);
614 gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
615 "button_press_event",
616 GTK_SIGNAL_FUNC(_tme_gtk_mouse_mouse_event),
617 screen);
618 gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
619 "button_release_event",
620 GTK_SIGNAL_FUNC(_tme_gtk_mouse_mouse_event),
621 screen);
622
623 /* mouse mode is off: */
624 screen->tme_gtk_screen_mouse_keyval = GDK_VoidSymbol;
625 }
626
627 /* this initializes mouse part of the display: */
628 void
_tme_gtk_mouse_new(struct tme_gtk_display * display)629 _tme_gtk_mouse_new(struct tme_gtk_display *display)
630 {
631 GdkPixmap *source, *mask;
632
633 /* we have no mouse connection: */
634 display->tme_gtk_display_mouse_connection = NULL;
635
636 /* allocate the mouse buffer: */
637 display->tme_gtk_display_mouse_buffer
638 = tme_mouse_buffer_new(1024);
639
640 /* create the mouse cursor: */
641 source
642 = gdk_bitmap_create_from_data(NULL,
643 _tme_gtk_mouse_cursor_source,
644 TME_GTK_MOUSE_CURSOR_WIDTH,
645 TME_GTK_MOUSE_CURSOR_HEIGHT);
646 mask
647 = gdk_bitmap_create_from_data (NULL,
648 _tme_gtk_mouse_cursor_mask,
649 TME_GTK_MOUSE_CURSOR_WIDTH,
650 TME_GTK_MOUSE_CURSOR_HEIGHT);
651 display->tme_gtk_display_mouse_cursor
652 = gdk_cursor_new_from_pixmap(source,
653 mask,
654 &_tme_gtk_mouse_cursor_color,
655 &_tme_gtk_mouse_cursor_color,
656 0,
657 0);
658 gdk_pixmap_unref(source);
659 gdk_pixmap_unref(mask);
660 }
661