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
);
41 struct AddNamescopeItemData
{
45 AddNamescopeItemData (GtkTreeStore
*store
, GtkTreeIter
*node
)
53 add_namescope_item (gpointer key
, gpointer value
, gpointer user_data
);
56 timespan_to_str (TimeSpan ts
)
64 double ts_frac
= (double)ts
;
68 ts_frac
/= 10000000.0;
70 days
= (int)(ts_frac
/ 86400);
71 ts_frac
-= days
* 86400;
72 hours
= (int)(ts_frac
/ 3600);
73 ts_frac
-= hours
* 3600;
74 minutes
= (int)(ts_frac
/ 60);
75 ts_frac
-= minutes
* 60;
78 // XXX someone who can remember printf specifiers should
79 // remove that %s from in there in such a way that we get a
80 // float zero padded to 2 spaces to the left of the decimal.
81 return g_strdup_printf ("%02d:%02d:%02d:%s%.4f", days
, hours
, minutes
, seconds
< 10.0 ? "0" : "", seconds
);
85 reflect_value (GtkTreeStore
*store
, GtkTreeIter
*node
, const char *name
, const char *type_name
, Value
*value
)
87 DependencyObject
*dobj
;
88 const char *str
= NULL
;
90 Deployment
*deployment
= Deployment::GetCurrent ();
92 if (value
&& value
->Is (deployment
, Type::DEPENDENCY_OBJECT
)) {
93 dobj
= value
->AsDependencyObject ();
95 gtk_tree_store_set (store
, node
,
97 COL_TYPE_NAME
, dobj
? dobj
->GetTypeName () : "null",
99 COL_ELEMENT_PTR
, NULL
,
103 reflect_dependency_object_in_tree (dobj
, store
, node
, true);
108 Type
*type
= Type::Find (deployment
, value
->GetKind ());
109 type_name
= type
->GetName ();
111 switch (value
->GetKind()) {
113 str
= buf
= g_strdup_printf ("<b>%g</b>", value
->AsDouble ());
116 str
= buf
= g_strdup_printf ("<b>%d</b>", value
->AsInt32 ());
119 str
= buf
= g_strdup_printf ("<b>%lld</b>", (long long int) value
->AsInt64 ());
121 case Type::TIMESPAN
: {
122 char *ts_string
= timespan_to_str (value
->AsTimeSpan());
123 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
128 str
= buf
= g_strdup_printf ("<b>%llu</b>", (unsigned long long int) value
->AsUInt64 ());
131 str
= buf
= g_strdup_printf ("<b>%s</b>", value
->AsString ());
134 Rect
*rect
= value
->AsRect();
135 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>", rect
->x
, rect
->y
, rect
->width
, rect
->height
);
139 str
= buf
= g_strdup_printf ("<b>%g, %g</b>", value
->AsSize()->width
, value
->AsSize()->height
);
141 case Type::REPEATBEHAVIOR
: {
142 RepeatBehavior
*rb
= value
->AsRepeatBehavior();
143 if (rb
->IsForever ())
144 str
= "<b>Forever</b>";
145 else if (rb
->HasCount())
146 str
= buf
= g_strdup_printf ("<b>%gx</b>", rb
->GetCount());
147 else /*if (rb->HasDuration())*/ {
148 char *ts_string
= timespan_to_str (rb
->GetDuration());
149 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
154 case Type::DURATION
: {
155 Duration
*d
= value
->AsDuration();
157 str
= "<b>Forever</b>";
158 else if (d
->IsAutomatic())
159 str
= "<b>Automatic</b>";
160 else /*if (d->HasTimeSpan())*/ {
161 char *ts_string
= timespan_to_str (d
->GetTimeSpan());
162 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
168 Color
*color
= value
->AsColor();
169 str
= buf
= g_strdup_printf ("<b>r=%g, g=%g, b=%g, a=%g</b>", color
->r
, color
->g
, color
->b
, color
->a
);
173 str
= value
->AsBool () ? "<b>true</b>" : "<b>false</b>";
175 case Type::GRIDLENGTH
: {
176 GridLength
*length
= value
->AsGridLength ();
177 str
= buf
= g_strdup_printf ("<b>%g (%s)</b>", length
->val
, length
->type
== GridUnitTypeAuto
?
178 "Auto" : length
->type
== GridUnitTypeStar
? "*" : "Pixel");
181 case Type::THICKNESS
: {
182 Thickness
*thickness
= value
->AsThickness ();
183 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>",
191 Point
*point
= value
->AsPoint ();
192 str
= buf
= g_strdup_printf ("<b>(%g, %g)</b>", point
->x
, point
->y
);
195 case Type::CORNERRADIUS
: {
196 CornerRadius
*CornerRadius
= value
->AsCornerRadius ();
197 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>",
198 CornerRadius
->topLeft
,
199 CornerRadius
->topRight
,
200 CornerRadius
->bottomLeft
,
201 CornerRadius
->bottomRight
);
206 str
= "<i>(unknown)</i>";
210 str
= "<b><i>null</i></b>";
213 gtk_tree_store_set (store
, node
,
215 COL_TYPE_NAME
, type_name
,
217 COL_ELEMENT_PTR
, NULL
,
224 reflect_dependency_object_in_tree (DependencyObject
*obj
, GtkTreeStore
*store
, GtkTreeIter
*node
, bool node_is_self
)
232 gtk_tree_store_append (store
, &iter
, node
);
234 char *markup
= g_strdup_printf ("<b>%s</b>", obj
->GetName() ? obj
->GetName() : "");
235 gtk_tree_store_set (store
, &iter
,
237 COL_TYPE_NAME
, obj
->GetTypeName(),
238 COL_ELEMENT_PTR
, obj
,
245 DependencyProperty
**properties
= obj
->GetProperties (true);
247 if (properties
[0] != NULL
) {
248 GtkTreeIter prop_iter
, iter
;
254 gtk_tree_store_append (store
, &prop_iter
, node
);
256 gtk_tree_store_set (store
, &prop_iter
,
257 COL_NAME
, "Properties",
259 COL_ELEMENT_PTR
, obj
,
262 for (int i
= 0; properties
[i
]; i
++) {
263 owner_type
= Type::Find (obj
->GetDeployment (), properties
[i
]->GetOwnerType ());
264 markup
= g_strdup_printf ("<i>%s.%s</i>", owner_type
? owner_type
->GetName () : "(unknown)",
265 properties
[i
]->GetName ());
267 gtk_tree_store_append (store
, &iter
, &prop_iter
);
269 prop_type
= Type::Find (obj
->GetDeployment (), properties
[i
]->GetPropertyType ());
270 value
= obj
->GetValue (properties
[i
]);
272 reflect_value (store
, &iter
, markup
, prop_type
? prop_type
->GetName () : "(unknown)", value
);
280 if (obj
->Is(Type::COLLECTION
)) {
281 Collection
*col
= (Collection
*)obj
;
283 if (col
->GetCount() > 0) {
284 GtkTreeIter elements_iter
;
286 gtk_tree_store_append (store
, &elements_iter
, node
);
288 gtk_tree_store_set (store
, &elements_iter
,
289 COL_NAME
, "Elements",
291 COL_ELEMENT_PTR
, obj
,
294 for (int i
= 0; i
< col
->GetCount(); i
++) {
295 Value
*v
= col
->GetValueAt (i
);
298 if (v
->Is (col
->GetDeployment (), Type::DEPENDENCY_OBJECT
))
299 markup
= g_strdup_printf ("<i>[%d]</i> <b>%s</b>", i
, v
->AsDependencyObject()->GetName() ? v
->AsDependencyObject()->GetName() : "");
301 markup
= g_strdup_printf ("<i>[%d]</i>", i
);
303 GtkTreeIter child_iter
;
305 gtk_tree_store_append (store
, &child_iter
, &elements_iter
);
307 reflect_value (store
, &child_iter
, markup
, NULL
, v
);
314 if (obj
->Is(Type::FRAMEWORKELEMENT
) && !obj
->Is(Type::PANEL
) && !obj
->Is (Type::BORDER
)) {
315 GtkTreeIter subobject_iter
;
317 gtk_tree_store_append (store
, &subobject_iter
, node
);
319 Value
v(((Control
*)obj
)->GetSubtreeObject());
321 reflect_value (store
, &subobject_iter
, "Visual Child", NULL
, &v
);
324 if (obj
->Is (Type::NAMESCOPE
)) {
325 NameScope
*scope
= (NameScope
*) obj
;
327 GHashTable
*names
= scope
->GetNames ();
328 if (names
&& g_hash_table_size (names
) > 0) {
330 AddNamescopeItemData
*anid
= new AddNamescopeItemData (store
, node
);
332 g_hash_table_foreach (names
, add_namescope_item
, anid
);
340 add_namescope_item (gpointer key
, gpointer value
, gpointer user_data
)
342 AddNamescopeItemData
*anid
= (AddNamescopeItemData
*) user_data
;
343 char *name
= (char *) key
;
344 DependencyObject
*dob
= (DependencyObject
*) value
;
346 GtkTreeIter elements_iter
;
347 gtk_tree_store_append (anid
->store
, &elements_iter
, anid
->node
);
349 char *markup
= g_strdup_printf (" <b>%s</b>", name
);
351 gtk_tree_store_set (anid
->store
, &elements_iter
,
353 COL_TYPE_NAME
, dob
->GetType ()->GetName (),
355 COL_ELEMENT_PTR
, dob
,
362 selection_changed (GtkTreeSelection
*selection
, PluginInstance
*plugin
)
366 DependencyObject
*el
;
368 Deployment::SetCurrent (plugin
->GetDeployment ());
370 if (plugin
->GetSurface()->debug_selected_element
) {
371 UIElement
*el
= plugin
->GetSurface()->debug_selected_element
;
372 el
->Invalidate (el
->GetSubtreeBounds().GrowBy(1).RoundOut());
374 plugin
->GetSurface()->debug_selected_element
= NULL
;
377 if (!gtk_tree_selection_get_selected (selection
,
383 gtk_tree_model_get (model
, &iter
,
384 COL_ELEMENT_PTR
, &el
,
387 if (el
&& el
->Is(Type::UIELEMENT
)) {
388 UIElement
*ui
= (UIElement
*)el
;
389 ui
->Invalidate (ui
->GetSubtreeBounds().GrowBy(1).RoundOut());
391 plugin
->GetSurface()->debug_selected_element
= ui
;
394 Deployment::SetCurrent (NULL
);
398 surface_destroyed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
400 gtk_widget_destroy ((GtkWidget
*) closure
);
404 remove_destroyed_handler (PluginInstance
*plugin
, GObject
*window
)
406 Deployment::SetCurrent (plugin
->GetDeployment ());
407 plugin
->GetSurface ()->RemoveHandler (EventObject::DestroyedEvent
, surface_destroyed
, window
);
408 Deployment::SetCurrent (NULL
);
412 plugin_debug (PluginInstance
*plugin
)
414 Surface
*surface
= plugin
->GetSurface ();
417 GtkWidget
*d
= gtk_message_dialog_new (NULL
,
418 GTK_DIALOG_NO_SEPARATOR
,
421 "The plugin hasn't been initialized with xaml content yet");
422 gtk_dialog_run (GTK_DIALOG (d
));
427 GtkWidget
*tree_win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
428 gtk_window_set_title (GTK_WINDOW (tree_win
), "Xaml contents");
429 gtk_window_set_default_size (GTK_WINDOW (tree_win
), 300, 400);
431 Deployment::SetCurrent (plugin
->GetDeployment ());
433 surface
->AddHandler (EventObject::DestroyedEvent
, surface_destroyed
, tree_win
);
434 g_object_weak_ref (G_OBJECT (tree_win
), (GWeakNotify
) remove_destroyed_handler
, plugin
);
436 GtkTreeStore
*tree_store
= gtk_tree_store_new (NUM_COLUMNS
,
442 reflect_dependency_object_in_tree (plugin
->GetSurface()->GetToplevel (), tree_store
, NULL
, false);
445 GtkTreeModel
*sorted_model
= gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree_store
));
447 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sorted_model
),
448 COL_NAME
, GTK_SORT_ASCENDING
);
450 GtkWidget
* tree_view
= gtk_tree_view_new_with_model (sorted_model
);
452 GtkWidget
* tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
455 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
457 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
459 g_signal_connect (G_OBJECT (selection
), "changed",
460 G_CALLBACK (selection_changed
), plugin
);
462 GtkCellRenderer
*renderer
= gtk_cell_renderer_text_new();
463 GtkTreeViewColumn
*col
;
465 /* The Name column */
466 col
= gtk_tree_view_column_new();
467 gtk_tree_view_column_set_title(col
, "Name");
468 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
470 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
471 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_NAME
);
472 gtk_tree_view_column_set_resizable (col
, TRUE
);
474 gtk_tree_view_column_set_sort_column_id (col
, COL_NAME
);
476 /* The Type column */
477 col
= gtk_tree_view_column_new();
478 gtk_tree_view_column_set_title(col
, "Type");
479 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
481 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
482 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_TYPE_NAME
);
483 gtk_tree_view_column_set_resizable (col
, TRUE
);
485 /* The Value column */
486 col
= gtk_tree_view_column_new();
487 gtk_tree_view_column_set_title(col
, "Value");
488 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
490 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
491 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_VALUE
);
492 gtk_tree_view_column_set_resizable (col
, TRUE
);
494 GtkWidget
*scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
495 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
496 GTK_POLICY_AUTOMATIC
,
497 GTK_POLICY_AUTOMATIC
);
499 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
500 gtk_container_add (GTK_CONTAINER (tree_win
), scrolled
);
502 gtk_widget_show_all (tree_win
);
504 Deployment::SetCurrent (NULL
);
508 populate_tree_from_surface (PluginInstance
*plugin
, GtkTreeStore
*store
, GtkTreeIter
*parent
)
515 PluginInstance::moon_source
*src
;
517 sources
= plugin
->GetSources ();
522 src
= (PluginInstance::moon_source
*) sources
->First ();
523 for (; src
!= NULL
; src
= (PluginInstance::moon_source
*) src
->next
) {
524 gtk_tree_store_append (store
, &iter
, parent
);
526 gtk_tree_store_set (store
, &iter
,
535 PluginInstance::moon_source
*selected_source
= NULL
;
538 selection_changed_sources (GtkTreeSelection
*selection
, PluginInstance
*plugin
)
543 selected_source
= NULL
;
545 if (!gtk_tree_selection_get_selected (selection
,
551 gtk_tree_model_get (model
, &iter
,
556 static void clicked_callback (GtkWidget
*widget
, gpointer data
)
558 if (selected_source
== NULL
) {
559 printf ("Select a source first.\n");
562 argv
[0] = (gchar
*) "xdg-open";
563 argv
[1] = (gchar
*) selected_source
->filename
;
565 g_spawn_async (NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
, NULL
, NULL
);
569 static void unxap_callback (GtkWidget
*widget
, gpointer data
)
571 if (selected_source
== NULL
) {
572 printf ("Select a source first.\n");
575 argv
[0] = (gchar
*) "munxap";
576 argv
[1] = (gchar
*) selected_source
->filename
;
578 g_spawn_async (NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
, NULL
, NULL
);
584 get_common_prefix_len (GtkTreeModel
*model
)
586 char *filename
, *path
, *url
, *buf
, *p
, *q
;
587 size_t max
= (size_t) -1;
591 if (!gtk_tree_model_get_iter_first (model
, &iter
))
594 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
597 if (!uri
->Parse (url
)) {
598 buf
= g_strdup (filename
);
600 buf
= (char*)uri
->GetPath();
604 if ((p
= strrchr (buf
, '/')))
611 while (gtk_tree_model_iter_next (model
, &iter
)) {
612 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
615 if (!uri
->Parse (url
))
618 path
= (char*)uri
->GetPath();
620 for (p
= buf
, q
= path
; *p
&& *q
; p
++, q
++) {
625 if ((size_t) (p
- buf
) < max
)
637 save_callback (GtkWidget
*widget
, gpointer data
)
639 GtkTreeModel
*model
= (GtkTreeModel
*) data
;
640 char *filename
, *dirname
, *url
, *path
;
646 if (mkdir ("/tmp/moon-dump", 0777) == -1 && errno
!= EEXIST
)
649 prelen
= get_common_prefix_len (model
);
651 if (!gtk_tree_model_get_iter_first (model
, &iter
))
655 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
658 if (uri
->Parse (url
))
659 path
= (char*)uri
->GetPath();
663 path
= g_build_filename ("/tmp/moon-dump", path
+ prelen
, NULL
);
666 dirname
= g_path_get_dirname (path
);
667 g_mkdir_with_parents (dirname
, 0777);
670 if ((fd
= open (path
, O_CREAT
| O_WRONLY
| O_EXCL
, 0644)) != -1) {
671 if (CopyFileTo (filename
, fd
) == -1)
672 printf (" Failed: Could not copy file `%s' to `%s': %s\n", filename
, path
, g_strerror (errno
));
673 } else if (errno
!= EEXIST
) {
674 printf (" Failed: Could not create file `%s': %s\n", path
, g_strerror (errno
));
678 } while (gtk_tree_model_iter_next (model
, &iter
));
682 plugin_sources (PluginInstance
*plugin
)
684 GtkWidget
*tree_win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
685 gtk_window_set_title (GTK_WINDOW (tree_win
), "Sources");
686 gtk_window_set_default_size (GTK_WINDOW (tree_win
), 600, 400);
687 GtkBox
*vbox
= GTK_BOX (gtk_vbox_new (false, 0));
689 GtkTreeStore
*tree_store
= gtk_tree_store_new (3,
694 populate_tree_from_surface (plugin
, tree_store
, NULL
);
696 GtkWidget
*tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
698 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
700 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
702 g_signal_connect (G_OBJECT (selection
), "changed",
703 G_CALLBACK (selection_changed_sources
), plugin
);
705 GtkCellRenderer
*renderer
= gtk_cell_renderer_text_new();
706 GtkTreeViewColumn
*col
;
708 /* The Name column */
709 col
= gtk_tree_view_column_new();
710 gtk_tree_view_column_set_title(col
, "Uri");
711 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
713 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
714 gtk_tree_view_column_add_attribute (col
, renderer
, "text", 0);
716 /* The Type column */
717 col
= gtk_tree_view_column_new();
718 gtk_tree_view_column_set_title(col
, "Filename");
719 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
721 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
722 gtk_tree_view_column_add_attribute (col
, renderer
, "text", 1);
724 GtkWidget
*scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
725 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
726 GTK_POLICY_AUTOMATIC
,
727 GTK_POLICY_AUTOMATIC
);
729 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
730 //gtk_container_add (GTK_CONTAINER (tree_win), scrolled);
731 gtk_box_pack_start (vbox
, scrolled
, TRUE
, TRUE
, 0);
734 button
= gtk_button_new_with_label ("Open file");
735 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (clicked_callback
), NULL
);
736 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
738 button
= gtk_button_new_with_label ("Unxap");
739 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (unxap_callback
), tree_store
);
740 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
742 button
= gtk_button_new_with_label ("Save (to /tmp/moon-dump/)");
743 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (save_callback
), tree_store
);
744 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
746 gtk_container_add (GTK_CONTAINER (tree_win
), GTK_WIDGET (vbox
));
748 gtk_widget_show_all (tree_win
);