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