1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * window-gtk.cpp: MoonWindow implementation using gtk widgets.
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007-2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include "window-gtk.h"
15 #include "deployment.h"
16 #include "timemanager.h"
18 MoonWindowGtk::MoonWindowGtk (bool fullscreen
, int w
, int h
, MoonWindow
*parent
)
21 this->fullscreen
= fullscreen
;
22 this->deployment
= Deployment::GetCurrent ();
25 InitializeFullScreen(parent
);
30 MoonWindowGtk::~MoonWindowGtk ()
34 gtk_widget_destroy (widget
);
38 MoonWindowGtk::GetGdkWindow ()
40 GdkWindow
*parent_window
= gtk_widget_get_parent_window (widget
);
41 if (parent_window
== NULL
)
42 parent_window
= widget
->window
;
44 g_object_ref (parent_window
);
49 MoonWindowGtk::InitializeFullScreen (MoonWindow
*parent
)
51 widget
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
53 // only fullscreen on the monitor the plugin is on
54 GdkWindow
*gdk
= parent
->GetGdkWindow ();
55 int monitor
= gdk_screen_get_monitor_at_window (gdk_screen_get_default (), gdk
);
57 gdk_screen_get_monitor_geometry (gdk_screen_get_default (), monitor
, &bounds
);
59 height
= bounds
.height
;
60 gtk_window_move (GTK_WINDOW (widget
), bounds
.x
, bounds
.y
);
62 gtk_window_fullscreen (GTK_WINDOW (widget
));
72 MoonWindowGtk::InitializeNormal ()
74 if (width
== -1 || height
== -1) {
75 g_warning ("you must specify width and height when creating a non-fullscreen gtk window");
80 widget
= gtk_event_box_new ();
82 gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget
), false);
90 MoonWindowGtk::InitializeCommon ()
92 // don't let gtk clear the window we'll do all the drawing.
93 //gtk_widget_set_app_paintable (widget, true);
94 gtk_widget_set_double_buffered (widget
, false);
95 gtk_widget_set_size_request (widget
, width
, height
);
97 g_signal_connect (widget
, "size-allocate", G_CALLBACK (widget_size_allocate
), this);
98 g_signal_connect (widget
, "destroy", G_CALLBACK (widget_destroyed
), this);
100 gtk_widget_add_events (widget
,
101 GDK_POINTER_MOTION_MASK
|
102 //GDK_POINTER_MOTION_HINT_MASK |
104 GDK_KEY_RELEASE_MASK
|
105 GDK_BUTTON_PRESS_MASK
|
106 GDK_BUTTON_RELEASE_MASK
|
107 ((moonlight_flags
& RUNTIME_INIT_DESKTOP_EXTENSIONS
) != 0 ? GDK_SCROLL_MASK
: 0) |
108 GDK_FOCUS_CHANGE_MASK
);
110 GTK_WIDGET_SET_FLAGS (widget
, GTK_CAN_FOCUS
);
114 MoonWindowGtk::Resize (int width
, int height
)
116 gtk_widget_set_size_request (widget
, width
, height
);
117 gtk_widget_queue_resize (widget
);
121 static const char *dot
[] = {
148 static const char *eraser
[] = {
214 " b~,,,,,,,,,;$c ",
215 " de-,,,,,,,,,fg ",
222 MoonWindowGtk::SetBackgroundColor (Color
*color
)
225 gdk_color
.red
= color
->r
* 0xffff;
226 gdk_color
.green
= color
->g
* 0xffff;
227 gdk_color
.blue
= color
->b
* 0xffff;
229 gtk_widget_modify_bg (widget
, GTK_STATE_NORMAL
, &gdk_color
);
231 MoonWindow::SetBackgroundColor (color
);
235 MoonWindowGtk::SetCursor (MouseCursor cursor
)
237 if (widget
->window
) {
241 case MouseCursorDefault
:
244 case MouseCursorArrow
:
245 c
= gdk_cursor_new (GDK_LEFT_PTR
);
247 case MouseCursorHand
:
248 c
= gdk_cursor_new (GDK_HAND2
);
250 case MouseCursorWait
:
251 c
= gdk_cursor_new (GDK_WATCH
);
253 case MouseCursorIBeam
:
254 c
= gdk_cursor_new (GDK_XTERM
);
256 case MouseCursorStylus
:
257 c
= gdk_cursor_new_from_pixbuf (gdk_display_get_default (), gdk_pixbuf_new_from_xpm_data ((const char**) dot
), 0, 0);
259 case MouseCursorEraser
:
260 c
= gdk_cursor_new_from_pixbuf (gdk_display_get_default (), gdk_pixbuf_new_from_xpm_data ((const char**) eraser
), 8, 8);
262 case MouseCursorSizeNS
:
263 c
= gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW
);
265 case MouseCursorSizeWE
:
266 c
= gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW
);
268 case MouseCursorNone
:
269 // Silverlight display no cursor if the enumeration value is invalid (e.g. -1)
271 //from gdk-cursor doc :"To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create a cursor with no pixels in it."
272 GdkPixmap
*empty
= gdk_bitmap_create_from_data (NULL
, "0x00", 1, 1);
273 GdkColor empty_color
= {0, 0, 0, 0};
274 c
= gdk_cursor_new_from_pixmap (empty
, empty
, &empty_color
, &empty_color
, 0, 0);
275 g_object_unref (empty
);
280 gdk_window_set_cursor (widget
->window
, c
);
283 gdk_cursor_unref (c
);
288 MoonWindowGtk::Invalidate (Rect r
)
290 gtk_widget_queue_draw_area (widget
,
291 (int) (widget
->allocation
.x
+ r
.x
),
292 (int) (widget
->allocation
.y
+ r
.y
),
293 (int) r
.width
, (int)r
.height
);
297 MoonWindowGtk::ProcessUpdates ()
300 gdk_window_process_updates (widget
->window
, false);
304 MoonWindowGtk::HandleEvent (XEvent
*event
)
306 // nothing to do here, since we don't pump events into the gtk
307 // window, gtk calls our signal handlers directly.
312 MoonWindowGtk::Show ()
314 gtk_widget_show (widget
);
316 // The window has to be realized for this call to work
317 gtk_widget_set_extension_events (widget
, GDK_EXTENSION_EVENTS_CURSOR
);
318 /* we need to explicitly enable the devices */
319 for (GList
*l
= gdk_devices_list(); l
; l
= l
->next
) {
320 #if THIS_NOLONGER_BREAKS_LARRYS_MOUSE
321 GdkDevice
*device
= GDK_DEVICE(l
->data
);
322 //if (!device->has_cursor)
323 gdk_device_set_mode (device
, GDK_MODE_SCREEN
);
327 GTK_WIDGET_SET_FLAGS (widget
, GTK_CAN_FOCUS
);
331 MoonWindowGtk::Hide ()
333 gtk_widget_hide (widget
);
337 MoonWindowGtk::EnableEvents (bool first
)
339 g_signal_connect (widget
, "expose-event", G_CALLBACK (expose_event
), this);
340 g_signal_connect (widget
, "motion-notify-event", G_CALLBACK (motion_notify
), this);
341 g_signal_connect (widget
, "enter-notify-event", G_CALLBACK (crossing_notify
), this);
342 g_signal_connect (widget
, "leave-notify-event", G_CALLBACK (crossing_notify
), this);
343 g_signal_connect (widget
, "key-press-event", G_CALLBACK (key_press
), this);
344 g_signal_connect (widget
, "key-release-event", G_CALLBACK (key_release
), this);
345 g_signal_connect (widget
, "button-press-event", G_CALLBACK (button_press
), this);
346 g_signal_connect (widget
, "button-release-event", G_CALLBACK (button_release
), this);
347 if ((moonlight_flags
& RUNTIME_INIT_DESKTOP_EXTENSIONS
) != 0)
348 g_signal_connect (widget
, "scroll-event", G_CALLBACK (scroll
), this);
349 g_signal_connect (widget
, "focus-in-event", G_CALLBACK (focus_in
), this);
350 g_signal_connect (widget
, "focus-out-event", G_CALLBACK (focus_out
), this);
353 g_signal_connect (widget
, "realize", G_CALLBACK (realized
), this);
354 g_signal_connect (widget
, "unrealize", G_CALLBACK (unrealized
), this);
356 if (GTK_WIDGET_REALIZED (widget
))
357 realized (widget
, this);
362 MoonWindowGtk::DisableEvents ()
364 g_signal_handlers_disconnect_matched (widget
, G_SIGNAL_MATCH_DATA
,
365 0, 0, NULL
, NULL
, this);
369 MoonWindowGtk::GrabFocus ()
371 gtk_widget_grab_focus (widget
);
375 MoonWindowGtk::HasFocus ()
377 return GTK_WIDGET_HAS_FOCUS (widget
);
381 MoonWindowGtk::expose_event (GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
383 MoonWindowGtk
*window
= (MoonWindowGtk
*)data
;
385 Deployment::SetCurrent (window
->GetDeployment ());
387 if (!window
->surface
)
390 // we draw to a backbuffer pixmap, then transfer the contents
391 // to the widget's window.
392 GdkPixmap
*pixmap
= gdk_pixmap_new (widget
->window
,
393 MAX (event
->area
.width
, 1), MAX (event
->area
.height
, 1), -1);
395 window
->surface
->PaintToDrawable (pixmap
,
396 gdk_drawable_get_visual (widget
->window
),
398 widget
->allocation
.x
,
399 widget
->allocation
.y
,
400 window
->GetTransparent (),
403 GdkGC
*gc
= gdk_gc_new (pixmap
);
405 gdk_gc_set_clip_region (gc
, event
->region
);
407 gdk_draw_drawable (widget
->window
, gc
, pixmap
,
409 event
->area
.x
, event
->area
.y
,
410 event
->area
.width
, event
->area
.height
);
412 g_object_unref (pixmap
);
419 MoonWindowGtk::button_press (GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
421 MoonWindowGtk
*window
= (MoonWindowGtk
*)data
;
423 Deployment::SetCurrent (window
->GetDeployment ());
425 if (event
->button
!= 1 && event
->button
!= 3)
429 window
->surface
->HandleUIButtonPress (event
);
431 // If we don't support right clicks (i.e. inside the browser)
433 if (event
->button
== 3 && (moonlight_flags
& RUNTIME_INIT_DESKTOP_EXTENSIONS
) == 0)
436 // ignore HandleUIButtonPress's return value, and always
437 // return true here, or it gets bubbled up to firefox.
442 MoonWindowGtk::button_release (GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
444 MoonWindowGtk
*window
= (MoonWindowGtk
*)data
;
446 Deployment::SetCurrent (window
->GetDeployment ());
449 window
->surface
->HandleUIButtonRelease (event
);
450 // ignore HandleUIButtonRelease's return value, and always
451 // return true here, or it gets bubbled up to firefox.
456 MoonWindowGtk::scroll (GtkWidget
*widget
, GdkEventScroll
*event
, gpointer data
)
458 MoonWindowGtk
*window
= (MoonWindowGtk
*)data
;
460 Deployment::SetCurrent (window
->GetDeployment ());
463 window
->surface
->HandleUIScroll (event
);
464 // ignore HandleUIScroll's return value, and always
465 // return true here, or it gets bubbled up to firefox.
470 MoonWindowGtk::motion_notify (GtkWidget
*widget
, GdkEventMotion
*event
, gpointer user_data
)
472 MoonWindowGtk
*window
= (MoonWindowGtk
*)user_data
;
474 Deployment::SetCurrent (window
->GetDeployment ());
477 window
->surface
->HandleUIMotion (event
);
478 // ignore HandleUIMotion's return value, and always
479 // return true here, or it gets bubbled up to firefox.
484 MoonWindowGtk::crossing_notify (GtkWidget
*widget
, GdkEventCrossing
*event
, gpointer user_data
)
486 MoonWindowGtk
*window
= (MoonWindowGtk
*)user_data
;
488 Deployment::SetCurrent (window
->GetDeployment ());
490 if (window
->surface
) {
491 window
->surface
->HandleUICrossing (event
);
499 MoonWindowGtk::focus_in (GtkWidget
*widget
, GdkEventFocus
*event
, gpointer user_data
)
501 MoonWindowGtk
*window
= (MoonWindowGtk
*)user_data
;
503 Deployment::SetCurrent (window
->GetDeployment ());
505 if (window
->surface
) {
506 window
->surface
->HandleUIFocusIn (event
);
514 MoonWindowGtk::focus_out (GtkWidget
*widget
, GdkEventFocus
*event
, gpointer user_data
)
516 MoonWindowGtk
*window
= (MoonWindowGtk
*)user_data
;
518 Deployment::SetCurrent (window
->GetDeployment ());
520 if (window
->surface
) {
521 window
->surface
->HandleUIFocusOut (event
);
529 MoonWindowGtk::key_press (GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
)
531 MoonWindowGtk
*window
= (MoonWindowGtk
*)user_data
;
533 Deployment::SetCurrent (window
->GetDeployment ());
535 if (window
->surface
) {
536 window
->surface
->HandleUIKeyPress (event
);
544 MoonWindowGtk::key_release (GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
)
546 MoonWindowGtk
*window
= (MoonWindowGtk
*)user_data
;
548 Deployment::SetCurrent (window
->GetDeployment ());
550 if (window
->surface
) {
551 window
->surface
->HandleUIKeyRelease (event
);
559 MoonWindowGtk::widget_size_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
, gpointer data
)
561 MoonWindowGtk
*window
= (MoonWindowGtk
*)data
;
563 Deployment::SetCurrent (window
->GetDeployment ());
565 //printf ("Surface::size-allocate callback: current = %dx%d; new = %dx%d\n",
566 // s->width, s->height, allocation->width, allocation->height);
568 bool emit_resize
= false;
570 if (window
->width
!= allocation
->width
|| window
->height
!= allocation
->height
) {
571 window
->width
= allocation
->width
;
572 window
->height
= allocation
->height
;
578 window
->surface
->HandleUIWindowAllocation (emit_resize
);
582 MoonWindowGtk::widget_destroyed (GtkWidget
*widget
, gpointer user_data
)
584 MoonWindowGtk
* window
= (MoonWindowGtk
*)user_data
;
586 window
->widget
= NULL
;
588 window
->surface
->HandleUIWindowDestroyed (window
);
592 MoonWindowGtk::realized (GtkWidget
*widget
, gpointer user_data
)
594 MoonWindowGtk
* window
= (MoonWindowGtk
*)user_data
;
597 #if INTEL_DRIVERS_STOP_SUCKING
598 // apparently the i965 drivers blank external screens when
599 // getting the screen info (um, ugh?). needless to say, this
600 // annoyance is worse than not using the monitor's refresh as
601 // the upper bound for our fps.
603 // http://lists.freedesktop.org/archives/xorg/2007-August/027616.html
604 int event_base
, error_base
;
605 GdkWindow
*gdk_root
= gtk_widget_get_root_window (widget
);
606 Display
*dpy
= GDK_WINDOW_XDISPLAY(gdk_root
);
607 Window root
= GDK_WINDOW_XID (gdk_root
);
608 if (XRRQueryExtension (dpy
, &event_base
, &error_base
)) {
609 XRRScreenConfiguration
*info
= XRRGetScreenInfo (dpy
,
611 short rate
= XRRConfigCurrentRate (info
);
612 printf ("screen refresh rate = %d\n", rate
);
614 window
->surface
->GetTimeManager()->SetMaximumRefreshRate (rate
);
615 XRRFreeScreenConfigInfo (info
);
620 Deployment::SetCurrent (window
->GetDeployment ());
622 if (window
->surface
) {
623 window
->surface
->HandleUIWindowUnavailable ();
624 window
->surface
->HandleUIWindowAvailable ();
628 Deployment::SetCurrent (NULL
);
635 MoonWindowGtk::unrealized (GtkWidget
*widget
, gpointer user_data
)
637 MoonWindowGtk
* window
= (MoonWindowGtk
*)user_data
;
639 Deployment::SetCurrent (window
->GetDeployment ());
642 window
->surface
->HandleUIWindowUnavailable ();
645 Deployment::SetCurrent (NULL
);