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
, Surface
*surface
)
19 : MoonWindow (w
, h
, surface
)
21 this->fullscreen
= fullscreen
;
24 InitializeFullScreen(parent
);
29 MoonWindowGtk::~MoonWindowGtk ()
31 /* gtk_widget_destroy can cause reentry (into another plugin if this destruction causes layout changes) */
32 DeploymentStack deployment_push_pop
;
35 gtk_widget_destroy (widget
);
39 MoonWindowGtk::GetGdkWindow ()
41 GdkWindow
*parent_window
= gtk_widget_get_parent_window (widget
);
42 if (parent_window
== NULL
)
43 parent_window
= widget
->window
;
45 g_object_ref (parent_window
);
50 MoonWindowGtk::InitializeFullScreen (MoonWindow
*parent
)
52 widget
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
54 // only fullscreen on the monitor the plugin is on
55 GdkWindow
*gdk
= parent
->GetGdkWindow ();
56 int monitor
= gdk_screen_get_monitor_at_window (gdk_screen_get_default (), gdk
);
58 gdk_screen_get_monitor_geometry (gdk_screen_get_default (), monitor
, &bounds
);
60 height
= bounds
.height
;
61 gtk_window_move (GTK_WINDOW (widget
), bounds
.x
, bounds
.y
);
63 gtk_window_fullscreen (GTK_WINDOW (widget
));
73 MoonWindowGtk::InitializeNormal ()
75 if (width
== -1 || height
== -1) {
76 g_warning ("you must specify width and height when creating a non-fullscreen gtk window");
81 widget
= gtk_event_box_new ();
83 gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget
), false);
91 MoonWindowGtk::InitializeCommon ()
93 // don't let gtk clear the window we'll do all the drawing.
94 //gtk_widget_set_app_paintable (widget, true);
95 gtk_widget_set_double_buffered (widget
, false);
96 gtk_widget_set_size_request (widget
, width
, height
);
98 g_signal_connect (widget
, "size-allocate", G_CALLBACK (widget_size_allocate
), this);
99 g_signal_connect (widget
, "destroy", G_CALLBACK (widget_destroyed
), this);
101 gtk_widget_add_events (widget
,
102 GDK_POINTER_MOTION_MASK
|
103 //GDK_POINTER_MOTION_HINT_MASK |
105 GDK_KEY_RELEASE_MASK
|
106 GDK_BUTTON_PRESS_MASK
|
107 GDK_BUTTON_RELEASE_MASK
|
108 ((moonlight_flags
& RUNTIME_INIT_DESKTOP_EXTENSIONS
) != 0 ? GDK_SCROLL_MASK
: 0) |
109 GDK_FOCUS_CHANGE_MASK
);
111 GTK_WIDGET_SET_FLAGS (widget
, GTK_CAN_FOCUS
);
115 MoonWindowGtk::Resize (int width
, int height
)
117 gtk_widget_set_size_request (widget
, width
, height
);
118 gtk_widget_queue_resize (widget
);
122 static const char *dot
[] = {
149 static const char *eraser
[] = {
215 " b~,,,,,,,,,;$c ",
216 " de-,,,,,,,,,fg ",
223 MoonWindowGtk::SetBackgroundColor (Color
*color
)
226 gdk_color
.red
= color
->r
* 0xffff;
227 gdk_color
.green
= color
->g
* 0xffff;
228 gdk_color
.blue
= color
->b
* 0xffff;
230 gtk_widget_modify_bg (widget
, GTK_STATE_NORMAL
, &gdk_color
);
232 MoonWindow::SetBackgroundColor (color
);
236 MoonWindowGtk::SetCursor (MouseCursor cursor
)
238 if (widget
->window
) {
242 case MouseCursorDefault
:
245 case MouseCursorArrow
:
246 c
= gdk_cursor_new (GDK_LEFT_PTR
);
248 case MouseCursorHand
:
249 c
= gdk_cursor_new (GDK_HAND2
);
251 case MouseCursorWait
:
252 c
= gdk_cursor_new (GDK_WATCH
);
254 case MouseCursorIBeam
:
255 c
= gdk_cursor_new (GDK_XTERM
);
257 case MouseCursorStylus
:
258 c
= gdk_cursor_new_from_pixbuf (gdk_display_get_default (), gdk_pixbuf_new_from_xpm_data ((const char**) dot
), 0, 0);
260 case MouseCursorEraser
:
261 c
= gdk_cursor_new_from_pixbuf (gdk_display_get_default (), gdk_pixbuf_new_from_xpm_data ((const char**) eraser
), 8, 8);
263 case MouseCursorSizeNS
:
264 c
= gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW
);
266 case MouseCursorSizeWE
:
267 c
= gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW
);
269 case MouseCursorNone
:
270 // Silverlight display no cursor if the enumeration value is invalid (e.g. -1)
272 //from gdk-cursor doc :"To make the cursor invisible, use gdk_cursor_new_from_pixmap() to create a cursor with no pixels in it."
273 GdkPixmap
*empty
= gdk_bitmap_create_from_data (NULL
, "0x00", 1, 1);
274 GdkColor empty_color
= {0, 0, 0, 0};
275 c
= gdk_cursor_new_from_pixmap (empty
, empty
, &empty_color
, &empty_color
, 0, 0);
276 g_object_unref (empty
);
281 gdk_window_set_cursor (widget
->window
, c
);
284 gdk_cursor_unref (c
);
289 MoonWindowGtk::Invalidate (Rect r
)
291 gtk_widget_queue_draw_area (widget
,
292 (int) (widget
->allocation
.x
+ r
.x
),
293 (int) (widget
->allocation
.y
+ r
.y
),
294 (int) r
.width
, (int)r
.height
);
298 MoonWindowGtk::ProcessUpdates ()
301 gdk_window_process_updates (widget
->window
, false);
305 MoonWindowGtk::HandleEvent (XEvent
*event
)
307 // nothing to do here, since we don't pump events into the gtk
308 // window, gtk calls our signal handlers directly.
313 MoonWindowGtk::Show ()
315 gtk_widget_show (widget
);
317 // The window has to be realized for this call to work
318 gtk_widget_set_extension_events (widget
, GDK_EXTENSION_EVENTS_CURSOR
);
319 /* we need to explicitly enable the devices */
320 for (GList
*l
= gdk_devices_list(); l
; l
= l
->next
) {
321 #if THIS_NOLONGER_BREAKS_LARRYS_MOUSE
322 GdkDevice
*device
= GDK_DEVICE(l
->data
);
323 //if (!device->has_cursor)
324 gdk_device_set_mode (device
, GDK_MODE_SCREEN
);
328 GTK_WIDGET_SET_FLAGS (widget
, GTK_CAN_FOCUS
);
332 MoonWindowGtk::Hide ()
334 gtk_widget_hide (widget
);
338 MoonWindowGtk::EnableEvents (bool first
)
340 g_signal_connect (widget
, "expose-event", G_CALLBACK (expose_event
), this);
341 g_signal_connect (widget
, "motion-notify-event", G_CALLBACK (motion_notify
), this);
342 g_signal_connect (widget
, "enter-notify-event", G_CALLBACK (crossing_notify
), this);
343 g_signal_connect (widget
, "leave-notify-event", G_CALLBACK (crossing_notify
), this);
344 g_signal_connect (widget
, "key-press-event", G_CALLBACK (key_press
), this);
345 g_signal_connect (widget
, "key-release-event", G_CALLBACK (key_release
), this);
346 g_signal_connect (widget
, "button-press-event", G_CALLBACK (button_press
), this);
347 g_signal_connect (widget
, "button-release-event", G_CALLBACK (button_release
), this);
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
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 window
->SetCurrentDeployment ();
642 window
->surface
->HandleUIWindowUnavailable ();
645 Deployment::SetCurrent (NULL
);