1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
15 #include <gtk/gtkmessagedialog.h>
17 #include <sys/types.h>
23 #include "plugin-debug.h"
38 static void reflect_dependency_object_in_tree (DependencyObject
*obj
, GtkTreeStore
*store
,
39 GtkTreeIter
*node
, bool node_is_self
);
42 timespan_to_str (TimeSpan ts
)
50 double ts_frac
= (double)ts
;
54 ts_frac
/= 10000000.0;
56 days
= (int)(ts_frac
/ 86400);
57 ts_frac
-= days
* 86400;
58 hours
= (int)(ts_frac
/ 3600);
59 ts_frac
-= hours
* 3600;
60 minutes
= (int)(ts_frac
/ 60);
61 ts_frac
-= minutes
* 60;
64 // XXX someone who can remember printf specifiers should
65 // remove that %s from in there in such a way that we get a
66 // float zero padded to 2 spaces to the left of the decimal.
67 return g_strdup_printf ("%02d:%02d:%02d:%s%.4f", days
, hours
, minutes
, seconds
< 10.0 ? "0" : "", seconds
);
71 reflect_value (GtkTreeStore
*store
, GtkTreeIter
*node
, const char *name
, const char *type_name
, Value
*value
)
73 DependencyObject
*dobj
;
74 const char *str
= NULL
;
77 if (value
&& value
->Is (Type::DEPENDENCY_OBJECT
)) {
78 dobj
= value
->AsDependencyObject ();
80 gtk_tree_store_set (store
, node
,
82 COL_TYPE_NAME
, dobj
? dobj
->GetTypeName () : "null",
84 COL_ELEMENT_PTR
, NULL
,
88 reflect_dependency_object_in_tree (dobj
, store
, node
, true);
93 Type
*type
= Type::Find (value
->GetKind ());
94 type_name
= type
->GetName ();
96 switch (value
->GetKind()) {
98 str
= buf
= g_strdup_printf ("<b>%g</b>", value
->AsDouble ());
101 str
= buf
= g_strdup_printf ("<b>%d</b>", value
->AsInt32 ());
104 str
= buf
= g_strdup_printf ("<b>%lld</b>", (long long int) value
->AsInt64 ());
106 case Type::TIMESPAN
: {
107 char *ts_string
= timespan_to_str (value
->AsTimeSpan());
108 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
113 str
= buf
= g_strdup_printf ("<b>%llu</b>", (unsigned long long int) value
->AsUInt64 ());
116 str
= buf
= g_strdup_printf ("<b>%s</b>", value
->AsString ());
119 Rect
*rect
= value
->AsRect();
120 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>", rect
->x
, rect
->y
, rect
->width
, rect
->height
);
124 str
= buf
= g_strdup_printf ("<b>%g, %g</b>", value
->AsSize()->width
, value
->AsSize()->height
);
126 case Type::REPEATBEHAVIOR
: {
127 RepeatBehavior
*rb
= value
->AsRepeatBehavior();
128 if (rb
->IsForever ())
129 str
= "<b>Forever</b>";
130 else if (rb
->HasCount())
131 str
= buf
= g_strdup_printf ("<b>%gx</b>", rb
->GetCount());
132 else /*if (rb->HasDuration())*/ {
133 char *ts_string
= timespan_to_str (rb
->GetDuration());
134 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
139 case Type::DURATION
: {
140 Duration
*d
= value
->AsDuration();
142 str
= "<b>Forever</b>";
143 else if (d
->IsAutomatic())
144 str
= "<b>Automatic</b>";
145 else /*if (d->HasTimeSpan())*/ {
146 char *ts_string
= timespan_to_str (d
->GetTimeSpan());
147 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
153 Color
*color
= value
->AsColor();
154 str
= buf
= g_strdup_printf ("<b>r=%g, g=%g, b=%g, a=%g</b>", color
->r
, color
->g
, color
->b
, color
->a
);
158 str
= value
->AsBool () ? "<b>true</b>" : "<b>false</b>";
160 case Type::GRIDLENGTH
: {
161 GridLength
*length
= value
->AsGridLength ();
162 str
= buf
= g_strdup_printf ("<b>%g (%s)</b>", length
->val
, length
->type
== GridUnitTypeAuto
?
163 "Auto" : length
->type
== GridUnitTypeStar
? "*" : "Pixel");
166 case Type::THICKNESS
: {
167 Thickness
*thickness
= value
->AsThickness ();
168 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>",
176 Point
*point
= value
->AsPoint ();
177 str
= buf
= g_strdup_printf ("<b>(%g, %g)</b>", point
->x
, point
->y
);
180 case Type::CORNERRADIUS
: {
181 CornerRadius
*CornerRadius
= value
->AsCornerRadius ();
182 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>",
183 CornerRadius
->topLeft
,
184 CornerRadius
->topRight
,
185 CornerRadius
->bottomLeft
,
186 CornerRadius
->bottomRight
);
191 str
= "<i>(unknown)</i>";
195 str
= "<b><i>null</i></b>";
198 gtk_tree_store_set (store
, node
,
200 COL_TYPE_NAME
, type_name
,
202 COL_ELEMENT_PTR
, NULL
,
209 reflect_dependency_object_in_tree (DependencyObject
*obj
, GtkTreeStore
*store
, GtkTreeIter
*node
, bool node_is_self
)
217 gtk_tree_store_append (store
, &iter
, node
);
219 char *markup
= g_strdup_printf ("<b>%s</b>", obj
->GetName() ? obj
->GetName() : "");
220 gtk_tree_store_set (store
, &iter
,
222 COL_TYPE_NAME
, obj
->GetTypeName(),
223 COL_ELEMENT_PTR
, obj
,
230 DependencyProperty
**properties
= obj
->GetProperties (true);
232 if (properties
[0] != NULL
) {
233 GtkTreeIter prop_iter
, iter
;
239 gtk_tree_store_append (store
, &prop_iter
, node
);
241 gtk_tree_store_set (store
, &prop_iter
,
242 COL_NAME
, "Properties",
244 COL_ELEMENT_PTR
, obj
,
247 for (int i
= 0; properties
[i
]; i
++) {
248 owner_type
= Type::Find (properties
[i
]->GetOwnerType ());
249 markup
= g_strdup_printf ("<i>%s.%s</i>", owner_type
? owner_type
->GetName () : "(unknown)",
250 properties
[i
]->GetName ());
252 gtk_tree_store_append (store
, &iter
, &prop_iter
);
254 prop_type
= Type::Find (properties
[i
]->GetPropertyType ());
255 value
= obj
->GetValue (properties
[i
]);
257 reflect_value (store
, &iter
, markup
, prop_type
? prop_type
->GetName () : "(unknown)", value
);
265 if (obj
->Is(Type::COLLECTION
)) {
266 Collection
*col
= (Collection
*)obj
;
268 if (col
->GetCount() > 0) {
269 GtkTreeIter elements_iter
;
271 gtk_tree_store_append (store
, &elements_iter
, node
);
273 gtk_tree_store_set (store
, &elements_iter
,
274 COL_NAME
, "Elements",
276 COL_ELEMENT_PTR
, obj
,
279 for (int i
= 0; i
< col
->GetCount(); i
++) {
280 Value
*v
= col
->GetValueAt (i
);
283 if (v
->Is (Type::DEPENDENCY_OBJECT
))
284 markup
= g_strdup_printf ("<i>[%d]</i> <b>%s</b>", i
, v
->AsDependencyObject()->GetName() ? v
->AsDependencyObject()->GetName() : "");
286 markup
= g_strdup_printf ("<i>[%d]</i>", i
);
288 GtkTreeIter child_iter
;
290 gtk_tree_store_append (store
, &child_iter
, &elements_iter
);
292 reflect_value (store
, &child_iter
, markup
, NULL
, v
);
299 if (obj
->Is(Type::FRAMEWORKELEMENT
) && !obj
->Is(Type::PANEL
) && !obj
->Is (Type::BORDER
)) {
300 GtkTreeIter subobject_iter
;
302 gtk_tree_store_append (store
, &subobject_iter
, node
);
304 Value
v(((Control
*)obj
)->GetSubtreeObject());
306 reflect_value (store
, &subobject_iter
, "Visual Child", NULL
, &v
);
311 selection_changed (GtkTreeSelection
*selection
, PluginInstance
*plugin
)
315 DependencyObject
*el
;
317 Deployment::SetCurrent (plugin
->GetDeployment ());
319 if (plugin
->GetSurface()->debug_selected_element
) {
320 UIElement
*el
= plugin
->GetSurface()->debug_selected_element
;
321 el
->Invalidate (el
->GetSubtreeBounds().GrowBy(1).RoundOut());
323 plugin
->GetSurface()->debug_selected_element
= NULL
;
326 if (!gtk_tree_selection_get_selected (selection
,
332 gtk_tree_model_get (model
, &iter
,
333 COL_ELEMENT_PTR
, &el
,
336 if (el
&& el
->Is(Type::UIELEMENT
)) {
337 UIElement
*ui
= (UIElement
*)el
;
338 ui
->Invalidate (ui
->GetSubtreeBounds().GrowBy(1).RoundOut());
340 plugin
->GetSurface()->debug_selected_element
= ui
;
343 Deployment::SetCurrent (NULL
);
347 surface_destroyed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
349 gtk_widget_destroy ((GtkWidget
*) closure
);
353 remove_destroyed_handler (PluginInstance
*plugin
, GObject
*window
)
355 Deployment::SetCurrent (plugin
->GetDeployment ());
356 plugin
->GetSurface ()->RemoveHandler (EventObject::DestroyedEvent
, surface_destroyed
, window
);
357 Deployment::SetCurrent (NULL
);
361 plugin_debug (PluginInstance
*plugin
)
363 Surface
*surface
= plugin
->GetSurface ();
366 GtkWidget
*d
= gtk_message_dialog_new (NULL
,
367 GTK_DIALOG_NO_SEPARATOR
,
370 "The plugin hasn't been initialized with xaml content yet");
371 gtk_dialog_run (GTK_DIALOG (d
));
376 GtkWidget
*tree_win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
377 gtk_window_set_title (GTK_WINDOW (tree_win
), "Xaml contents");
378 gtk_window_set_default_size (GTK_WINDOW (tree_win
), 300, 400);
380 Deployment::SetCurrent (plugin
->GetDeployment ());
382 surface
->AddHandler (EventObject::DestroyedEvent
, surface_destroyed
, tree_win
);
383 g_object_weak_ref (G_OBJECT (tree_win
), (GWeakNotify
) remove_destroyed_handler
, plugin
);
385 GtkTreeStore
*tree_store
= gtk_tree_store_new (NUM_COLUMNS
,
391 reflect_dependency_object_in_tree (plugin
->GetSurface()->GetToplevel (), tree_store
, NULL
, false);
394 GtkTreeModel
*sorted_model
= gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree_store
));
396 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sorted_model
),
397 COL_NAME
, GTK_SORT_ASCENDING
);
399 GtkWidget
* tree_view
= gtk_tree_view_new_with_model (sorted_model
);
401 GtkWidget
* tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
404 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
406 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
408 g_signal_connect (G_OBJECT (selection
), "changed",
409 G_CALLBACK (selection_changed
), plugin
);
411 GtkCellRenderer
*renderer
= gtk_cell_renderer_text_new();
412 GtkTreeViewColumn
*col
;
414 /* The Name column */
415 col
= gtk_tree_view_column_new();
416 gtk_tree_view_column_set_title(col
, "Name");
417 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
419 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
420 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_NAME
);
421 gtk_tree_view_column_set_resizable (col
, TRUE
);
423 gtk_tree_view_column_set_sort_column_id (col
, COL_NAME
);
425 /* The Type column */
426 col
= gtk_tree_view_column_new();
427 gtk_tree_view_column_set_title(col
, "Type");
428 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
430 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
431 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_TYPE_NAME
);
432 gtk_tree_view_column_set_resizable (col
, TRUE
);
434 /* The Value column */
435 col
= gtk_tree_view_column_new();
436 gtk_tree_view_column_set_title(col
, "Value");
437 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
439 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
440 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_VALUE
);
441 gtk_tree_view_column_set_resizable (col
, TRUE
);
443 GtkWidget
*scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
444 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
445 GTK_POLICY_AUTOMATIC
,
446 GTK_POLICY_AUTOMATIC
);
448 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
449 gtk_container_add (GTK_CONTAINER (tree_win
), scrolled
);
451 gtk_widget_show_all (tree_win
);
453 Deployment::SetCurrent (NULL
);
457 populate_tree_from_surface (PluginInstance
*plugin
, GtkTreeStore
*store
, GtkTreeIter
*parent
)
464 PluginInstance::moon_source
*src
;
466 sources
= plugin
->GetSources ();
471 src
= (PluginInstance::moon_source
*) sources
->First ();
472 for (; src
!= NULL
; src
= (PluginInstance::moon_source
*) src
->next
) {
473 gtk_tree_store_append (store
, &iter
, parent
);
475 gtk_tree_store_set (store
, &iter
,
484 PluginInstance::moon_source
*selected_source
= NULL
;
487 selection_changed_sources (GtkTreeSelection
*selection
, PluginInstance
*plugin
)
492 selected_source
= NULL
;
494 if (!gtk_tree_selection_get_selected (selection
,
500 gtk_tree_model_get (model
, &iter
,
505 static void clicked_callback (GtkWidget
*widget
, gpointer data
)
507 if (selected_source
== NULL
) {
508 printf ("Select a source first.\n");
511 argv
[0] = (gchar
*) "xdg-open";
512 argv
[1] = (gchar
*) selected_source
->filename
;
514 g_spawn_async (NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
, NULL
, NULL
);
518 static void unxap_callback (GtkWidget
*widget
, gpointer data
)
520 if (selected_source
== NULL
) {
521 printf ("Select a source first.\n");
524 argv
[0] = (gchar
*) "munxap";
525 argv
[1] = (gchar
*) selected_source
->filename
;
527 g_spawn_async (NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
, NULL
, NULL
);
533 get_common_prefix_len (GtkTreeModel
*model
)
535 char *filename
, *path
, *url
, *buf
, *p
, *q
;
536 size_t max
= (size_t) -1;
540 if (!gtk_tree_model_get_iter_first (model
, &iter
))
543 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
546 if (!uri
->Parse (url
)) {
547 buf
= g_strdup (filename
);
549 buf
= (char*)uri
->GetPath();
553 if ((p
= strrchr (buf
, '/')))
560 while (gtk_tree_model_iter_next (model
, &iter
)) {
561 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
564 if (!uri
->Parse (url
))
567 path
= (char*)uri
->GetPath();
569 for (p
= buf
, q
= path
; *p
&& *q
; p
++, q
++) {
574 if ((size_t) (p
- buf
) < max
)
586 save_callback (GtkWidget
*widget
, gpointer data
)
588 GtkTreeModel
*model
= (GtkTreeModel
*) data
;
589 char *filename
, *dirname
, *url
, *path
;
595 if (mkdir ("/tmp/moon-dump", 0777) == -1 && errno
!= EEXIST
)
598 prelen
= get_common_prefix_len (model
);
600 if (!gtk_tree_model_get_iter_first (model
, &iter
))
604 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
607 if (uri
->Parse (url
))
608 path
= (char*)uri
->GetPath();
612 path
= g_build_filename ("/tmp/moon-dump", path
+ prelen
, NULL
);
615 dirname
= g_path_get_dirname (path
);
616 g_mkdir_with_parents (dirname
, 0777);
619 if ((fd
= open (path
, O_CREAT
| O_WRONLY
| O_EXCL
, 0644)) != -1) {
620 if (CopyFileTo (filename
, fd
) == -1)
621 printf (" Failed: Could not copy file `%s' to `%s': %s\n", filename
, path
, g_strerror (errno
));
622 } else if (errno
!= EEXIST
) {
623 printf (" Failed: Could not create file `%s': %s\n", path
, g_strerror (errno
));
627 } while (gtk_tree_model_iter_next (model
, &iter
));
631 plugin_sources (PluginInstance
*plugin
)
633 GtkWidget
*tree_win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
634 gtk_window_set_title (GTK_WINDOW (tree_win
), "Sources");
635 gtk_window_set_default_size (GTK_WINDOW (tree_win
), 600, 400);
636 GtkBox
*vbox
= GTK_BOX (gtk_vbox_new (false, 0));
638 GtkTreeStore
*tree_store
= gtk_tree_store_new (3,
643 populate_tree_from_surface (plugin
, tree_store
, NULL
);
645 GtkWidget
*tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
647 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
649 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
651 g_signal_connect (G_OBJECT (selection
), "changed",
652 G_CALLBACK (selection_changed_sources
), plugin
);
654 GtkCellRenderer
*renderer
= gtk_cell_renderer_text_new();
655 GtkTreeViewColumn
*col
;
657 /* The Name column */
658 col
= gtk_tree_view_column_new();
659 gtk_tree_view_column_set_title(col
, "Uri");
660 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
662 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
663 gtk_tree_view_column_add_attribute (col
, renderer
, "text", 0);
665 /* The Type column */
666 col
= gtk_tree_view_column_new();
667 gtk_tree_view_column_set_title(col
, "Filename");
668 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
670 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
671 gtk_tree_view_column_add_attribute (col
, renderer
, "text", 1);
673 GtkWidget
*scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
674 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
675 GTK_POLICY_AUTOMATIC
,
676 GTK_POLICY_AUTOMATIC
);
678 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
679 //gtk_container_add (GTK_CONTAINER (tree_win), scrolled);
680 gtk_box_pack_start (vbox
, scrolled
, TRUE
, TRUE
, 0);
683 button
= gtk_button_new_with_label ("Open file");
684 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (clicked_callback
), NULL
);
685 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
687 button
= gtk_button_new_with_label ("Unxap");
688 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (unxap_callback
), tree_store
);
689 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
691 button
= gtk_button_new_with_label ("Save (to /tmp/moon-dump/)");
692 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (save_callback
), tree_store
);
693 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
695 gtk_container_add (GTK_CONTAINER (tree_win
), GTK_WIDGET (vbox
));
697 gtk_widget_show_all (tree_win
);