1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * runtime.h: Core surface.
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
17 #include <gtk/gtkwidget.h>
21 #include "uielement.h"
22 #include "dependencyobject.h"
30 #define MAXIMUM_CACHE_SIZE 6000000
32 #define FRONT_TO_BACK_STATS 0
35 #define DEBUG_MARKER_KEY 0
37 #define STARTTIMER(id,str) TimeSpan id##_t_start = get_now(); printf ("timing of '%s' started at %" G_GINT64_FORMAT "\n", str, id##_t_start)
38 #define ENDTIMER(id,str) TimeSpan id##_t_end = get_now(); printf ("timing of '%s' ended at %" G_GINT64_FORMAT " (%f seconds)\n", str, id##_t_end, (double)(id##_t_end - id##_t_start) / 10000000)
40 #define STARTTIMER(id,str)
41 #define ENDTIMER(id,str)
45 #define VERIFY_MAIN_THREAD \
46 if (!Surface::InMainThread ()) { \
47 printf ("Moonlight: This method should only be called from the main thread (%s)\n", __PRETTY_FUNCTION__); \
48 print_stack_trace (); \
51 #define VERIFY_MAIN_THREAD
54 enum RuntimeInitFlags
{
55 RUNTIME_INIT_PANGO_TEXT_LAYOUT
= 1 << 0,
56 // (not used) = 1 << 1,
57 RUNTIME_INIT_MANUAL_TIMESOURCE
= 1 << 2,
58 RUNTIME_INIT_DISABLE_AUDIO
= 1 << 3,
59 RUNTIME_INIT_SHOW_EXPOSE
= 1 << 4,
60 RUNTIME_INIT_SHOW_CLIPPING
= 1 << 5,
61 RUNTIME_INIT_SHOW_BOUNDING_BOXES
= 1 << 6,
62 RUNTIME_INIT_SHOW_TEXTBOXES
= 1 << 7,
63 RUNTIME_INIT_SHOW_FPS
= 1 << 8,
64 RUNTIME_INIT_RENDER_FRONT_TO_BACK
= 1 << 9,
65 RUNTIME_INIT_SHOW_CACHE_SIZE
= 1 << 10,
66 RUNTIME_INIT_FFMPEG_YUV_CONVERTER
= 1 << 11,
67 RUNTIME_INIT_USE_SHAPE_CACHE
= 1 << 12,
68 RUNTIME_INIT_USE_UPDATE_POSITION
= 1 << 13,
69 RUNTIME_INIT_ALLOW_WINDOWLESS
= 1 << 14,
70 RUNTIME_INIT_AUDIO_ALSA_MMAP
= 1 << 15,
71 RUNTIME_INIT_AUDIO_ALSA_RW
= 1 << 16,
72 RUNTIME_INIT_AUDIO_ALSA
= 1 << 17,
73 RUNTIME_INIT_AUDIO_PULSE
= 1 << 18,
74 RUNTIME_INIT_USE_IDLE_HINT
= 1 << 19,
75 RUNTIME_INIT_USE_BACKEND_XLIB
= 1 << 20,
76 RUNTIME_INIT_KEEP_MEDIA
= 1 << 21,
77 RUNTIME_INIT_ENABLE_MS_CODECS
= 1 << 22,
78 RUNTIME_INIT_DISABLE_FFMPEG_CODECS
= 1 << 23,
79 RUNTIME_INIT_ALL_IMAGE_FORMATS
= 1 << 24,
80 RUNTIME_INIT_CREATE_ROOT_DOMAIN
= 1 << 25,
81 RUNTIME_INIT_DESKTOP_EXTENSIONS
= 1 << 26,
84 extern guint32 moonlight_flags
;
88 enum RuntimeDebugFlags
{
89 RUNTIME_DEBUG_ALSA
= 1 << 0,
90 RUNTIME_DEBUG_AUDIO
= 1 << 1,
91 RUNTIME_DEBUG_PULSE
= 1 << 2,
92 RUNTIME_DEBUG_HTTPSTREAMING
= 1 << 3,
93 RUNTIME_DEBUG_MARKERS
= 1 << 4,
94 RUNTIME_DEBUG_MMS
= 1 << 5,
95 RUNTIME_DEBUG_MEDIAPLAYER
= 1 << 6,
96 RUNTIME_DEBUG_PIPELINE
= 1 << 7,
97 RUNTIME_DEBUG_PIPELINE_ERROR
= 1 << 8,
98 RUNTIME_DEBUG_FRAMEREADERLOOP
= 1 << 9,
99 RUNTIME_DEBUG_FFMPEG
= 1 << 10,
100 RUNTIME_DEBUG_UI
= 1 << 11,
101 RUNTIME_DEBUG_CODECS
= 1 << 12,
102 RUNTIME_DEBUG_DP
= 1 << 13,
103 RUNTIME_DEBUG_DOWNLOADER
= 1 << 14,
104 RUNTIME_DEBUG_FONT
= 1 << 15,
105 RUNTIME_DEBUG_LAYOUT
= 1 << 16,
106 RUNTIME_DEBUG_MEDIA
= 1 << 17,
107 RUNTIME_DEBUG_MEDIAELEMENT
= 1 << 18,
108 RUNTIME_DEBUG_BUFFERING
= 1 << 19,
109 RUNTIME_DEBUG_ASF
= 1 << 20,
110 RUNTIME_DEBUG_PLAYLIST
= 1 << 21,
111 RUNTIME_DEBUG_TEXT
= 1 << 22,
112 RUNTIME_DEBUG_XAML
= 1 << 23,
113 RUNTIME_DEBUG_DEPLOYMENT
= 1 << 24,
114 RUNTIME_DEBUG_MSI
= 1 << 25,
115 RUNTIME_DEBUG_MP3
= 1 << 26,
116 RUNTIME_DEBUG_VALUE
= 1 << 27,
119 enum RuntimeDebugFlagsExtra
{
120 RUNTIME_DEBUG_ALSA_EX
= 1 << 0,
121 RUNTIME_DEBUG_AUDIO_EX
= 1 << 1,
122 RUNTIME_DEBUG_PULSE_EX
= 1 << 2,
123 RUNTIME_DEBUG_MARKERS_EX
= 1 << 3,
124 RUNTIME_DEBUG_MEDIAPLAYER_EX
= 1 << 4,
125 RUNTIME_DEBUG_MEDIAELEMENT_EX
= 1 << 5,
126 RUNTIME_DEBUG_PLAYLIST_EX
= 1 << 6,
127 RUNTIME_DEBUG_PIPELINE_EX
= 1 << 7,
130 extern guint32 debug_flags_ex
;
131 extern guint32 debug_flags
;
139 typedef void (* MoonlightFPSReportFunc
) (Surface
*surface
, int nframes
, float nsecs
, void *user_data
);
140 typedef void (* MoonlightCacheReportFunc
) (Surface
*surface
, long size
, void *user_data
);
141 typedef bool (* MoonlightEventEmitFunc
) (UIElement
*element
, GdkEvent
*event
);
142 typedef void (* MoonlightExposeHandoffFunc
) (Surface
*surface
, TimeSpan time
, void *user_data
);
144 /* @Namespace=None,ManagedEvents=Manual */
145 class Surface
: public EventObject
{
147 /* @GenerateCBinding,GeneratePInvoke */
148 Surface (MoonWindow
*window
);
149 virtual void Dispose ();
151 /* @GenerateCBinding */
152 MoonWindow
*GetWindow () { return active_window
; }
153 MoonWindow
*DetachWindow ();
155 // allows you to redirect painting of the surface to an
156 // arbitrary cairo context.
157 void Paint (cairo_t
*ctx
, Region
*region
);
158 /* @GenerateCBinding,GeneratePInvoke */
159 void Paint (cairo_t
*ctx
, int x
, int y
, int width
, int height
);
161 /* @GenerateCBinding,GeneratePInvoke */
162 void Attach (UIElement
*toplevel
);
164 void AttachLayer (UIElement
*layer
);
166 void DetachLayer (UIElement
*layer
);
168 void SetCursor (MouseCursor cursor
);
170 void ReleaseMouseCapture (UIElement
*capture
);
171 bool SetMouseCapture (UIElement
*capture
);
173 /* @GenerateCBinding,GeneratePInvoke */
174 void Resize (int width
, int height
);
176 void EmitSourceDownloadComplete ();
177 void EmitSourceDownloadProgressChanged (DownloadProgressEventArgs
*args
);
178 void EmitError (ErrorEventArgs
*args
);
179 /* @GenerateCBinding,GeneratePInvoke */
180 void EmitError (int number
, int code
, const char *message
);
184 void SetBackgroundColor (Color
*color
);
185 /* @GenerateCBinding,GeneratePInvoke */
186 Color
*GetBackgroundColor ();
188 int GetFrameCount () { return frames
; }
189 void ResetFrameCount () { frames
= 0; }
191 virtual void Invalidate (Rect r
);
192 virtual void ProcessUpdates ();
194 /* @GenerateCBinding,GeneratePInvoke */
195 UIElement
*GetToplevel() { return toplevel
; }
196 bool IsTopLevel (UIElement
*top
);
198 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
199 UIElement
*GetFocusedElement () { return focused_element
; }
201 bool FocusElement (UIElement
*element
);
203 /* @GenerateCBinding,GeneratePInvoke */
204 bool IsLoaded () { return toplevel
!= NULL
&& ticked_after_attach
; }
206 /* @GenerateCBinding,GeneratePInvoke */
207 static bool IsVersionSupported (const char *version
);
209 const static int ResizeEvent
;
210 const static int FullScreenChangeEvent
;
211 const static int ErrorEvent
;
212 const static int LoadEvent
;
213 const static int SourceDownloadProgressChangedEvent
;
214 const static int SourceDownloadCompleteEvent
;
216 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
217 bool GetFullScreen () { return full_screen
; }
218 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
219 void SetFullScreen (bool value
);
221 void SetUserInitiatedEvent (bool value
);
223 bool FirstUserInitiatedEvent () { return first_user_initiated_event
; }
224 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
225 bool IsUserInitiatedEvent () { return user_initiated_event
; }
227 const char* GetSourceLocation ();
228 void SetSourceLocation (const char *location
);
229 bool FullScreenKeyHandled (GdkEventKey
*key
);
231 /* @GenerateCBinding,GeneratePInvoke */
232 TimeManager
*GetTimeManager () { return time_manager
; }
234 void SetDownloaderContext (gpointer context
) { downloader_context
= context
; }
235 gpointer
GetDownloaderContext () { return downloader_context
; }
237 /* @GenerateCBinding,GeneratePInvoke */
238 Downloader
*CreateDownloader ();
239 static Downloader
*CreateDownloader (EventObject
*obj
);
241 void SetFPSReportFunc (MoonlightFPSReportFunc report
, void *user_data
);
242 void SetCacheReportFunc (MoonlightCacheReportFunc report
, void *user_data
);
243 void SetExposeHandoffFunc (MoonlightExposeHandoffFunc func
, void *user_data
);
245 bool VerifyWithCacheSizeCounter (int w
, int h
);
246 gint64
AddToCacheSizeCounter (int w
, int h
);
247 void RemoveFromCacheSizeCounter (gint64 size
);
249 // called from the plugin if the surface is headed for death.
250 // stops event emission (since the plugin counterparts to xaml
251 // objects will be destroyed)
254 bool IsZombie () { return zombie
; }
256 void DetachDownloaders ();
258 #if FRONT_TO_BACK_STATS
259 int uielements_rendered_front_to_back
;
260 int uielements_rendered_back_to_front
;
264 UIElement
*debug_selected_element
;
267 void PaintToDrawable (GdkDrawable
*drawable
, GdkVisual
*visual
, GdkEventExpose
*event
, int off_x
, int off_y
, bool transparent
, bool clear_transparent
);
270 gboolean
HandleUIMotion (GdkEventMotion
*event
);
271 gboolean
HandleUICrossing (GdkEventCrossing
*event
);
272 gboolean
HandleUIKeyPress (GdkEventKey
*event
);
273 gboolean
HandleUIKeyRelease (GdkEventKey
*event
);
274 gboolean
HandleUIButtonRelease (GdkEventButton
*event
);
275 gboolean
HandleUIButtonPress (GdkEventButton
*event
);
276 gboolean
HandleUIScroll (GdkEventScroll
*event
);
277 gboolean
HandleUIFocusIn (GdkEventFocus
*event
);
278 gboolean
HandleUIFocusOut (GdkEventFocus
*event
);
279 void HandleUIWindowAllocation (bool emit_resize
);
280 void HandleUIWindowAvailable ();
281 void HandleUIWindowUnavailable ();
282 void HandleUIWindowDestroyed (MoonWindow
*window
);
284 // bad, but these live in dirty.cpp, not runtime.cpp
285 void AddDirtyElement (UIElement
*element
, DirtyType dirt
);
286 void UpdateLayout ();
287 void RemoveDirtyElement (UIElement
*element
);
288 bool ProcessDirtyElements ();
289 void PropagateDirtyFlagToChildren (UIElement
*element
, DirtyType dirt
);
291 static bool main_thread_inited
;
292 static pthread_t main_thread
;
293 /* @GenerateCBinding,GeneratePInvoke */
294 static bool InMainThread () { return (!main_thread_inited
|| pthread_equal (main_thread
, pthread_self ())); }
299 // The current window we are drawing to
300 MoonWindow
*active_window
;
305 // are we headed for death?
308 // bad, but these two live in dirty.cpp, not runtime.cpp
309 void ProcessDownDirtyElements ();
310 void ProcessUpDirtyElements ();
312 DirtyLists
*down_dirty
;
313 DirtyLists
*up_dirty
;
315 gpointer downloader_context
;
317 static void OnDownloaderDestroyed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
319 Color
*background_color
;
321 // This is the normal-sized window
322 MoonWindow
*normal_window
;
324 // We set active_window to this whenever we are in fullscreen mode.
325 MoonWindow
*fullscreen_window
;
327 // We can have multiple top level elements, these are stored as layers
328 HitTestCollection
*layers
;
332 // The element holding the keyboard focus, and the one that
333 // held it previously (so we can emit lostfocus events async)
334 UIElement
*focused_element
;
335 Queue
*focus_changed_events
;
337 // the list of elements (from most deeply nested to the
338 // toplevel) we've most recently sent a mouse event to.
341 // is the mouse captured? if it is, it'll be by the first element in input_list.
343 UIElement
*pendingCapture
;
344 bool pendingReleaseCapture
;
346 // are we currently emitting a mouse event?
347 bool emittingMouseEvent
;
349 // the currently shown cursor
352 // Fullscreen support
354 Canvas
*full_screen_message
;
355 char *source_location
;
357 Canvas
*incomplete_support_message
;
359 // True once we have received at least one user initiated event
360 bool first_user_initiated_event
;
361 // Should be set to true only while executing MouseLeftButtonDown,
362 // MouseLeftButtonUp, KeyDown, and KeyUp event handlers
363 bool user_initiated_event
;
365 void UpdateFullScreen (bool value
);
367 TimeManager
*time_manager
;
368 bool ticked_after_attach
;
369 static void tick_after_attach_reached (EventObject
*data
);
373 GdkEvent
*mouse_event
;
375 // Variables for reporting FPS
376 MoonlightFPSReportFunc fps_report
;
381 // Variables for reporting cache size
382 MoonlightCacheReportFunc cache_report
;
383 gint64 cache_size_in_bytes
;
384 int cache_size_ticker
;
386 int cache_size_multiplier
;
389 TimeSpan expose_handoff_last_timespan
;
390 MoonlightExposeHandoffFunc expose_handoff
;
391 void *expose_handoff_data
;
394 static void AutoFocusAsync (EventObject
*sender
);
398 void ShowFullScreenMessage ();
399 void HideFullScreenMessage ();
400 static void HideFullScreenMessageCallback (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
402 void ShowIncompleteSilverlightSupportMessage ();
403 void HideIncompleteSilverlightSupportMessage ();
404 static void HideIncompleteSilverlightSupportMessageCallback (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
406 void CreateSimilarSurface ();
408 static void render_cb (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
);
409 static void update_input_cb (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
);
410 static void widget_destroyed (GtkWidget
*w
, gpointer data
);
412 EventArgs
* CreateArgsForEvent (int event_id
, GdkEvent
*event
);
414 List
* ElementPathToRoot (UIElement
*source
);
415 void GenerateFocusChangeEvents();
417 void FindFirstCommonElement (List
*l1
, int *index1
, List
*l2
, int *index2
);
418 bool EmitEventOnList (int event_id
, List
*element_list
, GdkEvent
*event
, int end_idx
);
419 void UpdateCursorFromInputList ();
420 bool HandleMouseEvent (int event_id
, bool emit_leave
, bool emit_enter
, bool force_emit
, GdkEvent
*event
);
421 void PerformCapture (UIElement
*capture
);
422 void PerformReleaseCapture ();
424 static void toplevel_loaded (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
425 void ToplevelLoaded (UIElement
*element
);
428 /* for hit testing */
429 class UIElementNode
: public List::Node
{
431 UIElement
*uielement
;
433 UIElementNode (UIElement
*el
);
434 virtual ~UIElementNode ();
438 typedef void (*RenderFunc
) (cairo_t
*ctx
, UIElement
*uielement
, Region
*region
, bool front_to_back
);
440 class RenderNode
: public List::Node
{
442 RenderNode (UIElement
*el
, Region
*region
, bool render_element
, RenderFunc pre
, RenderFunc post
);
444 void Render (cairo_t
*cr
);
446 virtual ~RenderNode ();
449 UIElement
*uielement
;
452 RenderFunc pre_render
;
453 RenderFunc post_render
;
459 void runtime_init (const char *platform_dir
, guint32 flags
);
461 void runtime_init_browser (const char *plugin_dir
);
462 /* @GeneratePInvoke */
463 void runtime_init_desktop ();
465 GList
*runtime_get_surface_list (void);
467 void runtime_flags_set_manual_timesource (gboolean flag
);
468 void runtime_flags_set_show_fps (gboolean flag
);
469 void runtime_flags_set_use_shapecache (gboolean flag
);
471 void runtime_shutdown (void);