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.
17 #include <gtk/gtkmessagedialog.h>
19 #include <sys/types.h>
25 #include "plugin-debug.h"
40 static void reflect_dependency_object_in_tree (DependencyObject
*obj
, GtkTreeStore
*store
,
41 GtkTreeIter
*node
, bool node_is_self
);
44 timespan_to_str (TimeSpan ts
)
52 double ts_frac
= (double)ts
;
56 ts_frac
/= 10000000.0;
58 days
= (int)(ts_frac
/ 86400);
59 ts_frac
-= days
* 86400;
60 hours
= (int)(ts_frac
/ 3600);
61 ts_frac
-= hours
* 3600;
62 minutes
= (int)(ts_frac
/ 60);
63 ts_frac
-= minutes
* 60;
66 // XXX someone who can remember printf specifiers should
67 // remove that %s from in there in such a way that we get a
68 // float zero padded to 2 spaces to the left of the decimal.
69 return g_strdup_printf ("%02d:%02d:%02d:%s%.4f", days
, hours
, minutes
, seconds
< 10.0 ? "0" : "", seconds
);
73 reflect_value (GtkTreeStore
*store
, GtkTreeIter
*node
, const char *name
, const char *type_name
, Value
*value
)
75 DependencyObject
*dobj
;
76 const char *str
= NULL
;
79 if (value
&& value
->Is (Type::DEPENDENCY_OBJECT
)) {
80 dobj
= value
->AsDependencyObject ();
82 gtk_tree_store_set (store
, node
,
84 COL_TYPE_NAME
, dobj
? dobj
->GetTypeName () : "null",
86 COL_ELEMENT_PTR
, NULL
,
90 reflect_dependency_object_in_tree (dobj
, store
, node
, true);
95 Type
*type
= Type::Find (value
->GetKind ());
96 type_name
= type
->GetName ();
98 switch (value
->GetKind()) {
100 str
= buf
= g_strdup_printf ("<b>%g</b>", value
->AsDouble ());
103 str
= buf
= g_strdup_printf ("<b>%d</b>", value
->AsInt32 ());
106 str
= buf
= g_strdup_printf ("<b>%lld</b>", (long long int) value
->AsInt64 ());
108 case Type::TIMESPAN
: {
109 char *ts_string
= timespan_to_str (value
->AsTimeSpan());
110 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
115 str
= buf
= g_strdup_printf ("<b>%llu</b>", (unsigned long long int) value
->AsUInt64 ());
118 str
= buf
= g_strdup_printf ("<b>%s</b>", value
->AsString ());
121 Rect
*rect
= value
->AsRect();
122 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>", rect
->x
, rect
->y
, rect
->width
, rect
->height
);
126 str
= buf
= g_strdup_printf ("<b>%g, %g</b>", value
->AsSize()->width
, value
->AsSize()->height
);
128 case Type::REPEATBEHAVIOR
: {
129 RepeatBehavior
*rb
= value
->AsRepeatBehavior();
130 if (rb
->IsForever ())
131 str
= "<b>Forever</b>";
132 else if (rb
->HasCount())
133 str
= buf
= g_strdup_printf ("<b>%gx</b>", rb
->GetCount());
134 else /*if (rb->HasDuration())*/ {
135 char *ts_string
= timespan_to_str (rb
->GetDuration());
136 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
141 case Type::DURATION
: {
142 Duration
*d
= value
->AsDuration();
144 str
= "<b>Forever</b>";
145 else if (d
->IsAutomatic())
146 str
= "<b>Automatic</b>";
147 else /*if (d->HasTimeSpan())*/ {
148 char *ts_string
= timespan_to_str (d
->GetTimeSpan());
149 str
= buf
= g_strdup_printf ("<b>%s</b>", ts_string
);
155 Color
*color
= value
->AsColor();
156 str
= buf
= g_strdup_printf ("<b>r=%g, g=%g, b=%g, a=%g</b>", color
->r
, color
->g
, color
->b
, color
->a
);
160 str
= value
->AsBool () ? "<b>true</b>" : "<b>false</b>";
162 case Type::GRIDLENGTH
: {
163 GridLength
*length
= value
->AsGridLength ();
164 str
= buf
= g_strdup_printf ("<b>%g (%s)</b>", length
->val
, length
->type
== GridUnitTypeAuto
?
165 "Auto" : length
->type
== GridUnitTypeStar
? "*" : "Pixel");
168 case Type::THICKNESS
: {
169 Thickness
*thickness
= value
->AsThickness ();
170 str
= buf
= g_strdup_printf ("<b>%g, %g, %g, %g</b>",
177 case Type::CORNERRADIUS
:
180 str
= "<i>(unknown)</i>";
184 str
= "<b><i>null</i></b>";
187 gtk_tree_store_set (store
, node
,
189 COL_TYPE_NAME
, type_name
,
191 COL_ELEMENT_PTR
, NULL
,
198 reflect_dependency_object_in_tree (DependencyObject
*obj
, GtkTreeStore
*store
, GtkTreeIter
*node
, bool node_is_self
)
206 gtk_tree_store_append (store
, &iter
, node
);
208 char *markup
= g_strdup_printf ("<b>%s</b>", obj
->GetName() ? obj
->GetName() : "");
209 gtk_tree_store_set (store
, &iter
,
211 COL_TYPE_NAME
, obj
->GetTypeName(),
212 COL_ELEMENT_PTR
, obj
,
219 DependencyProperty
**properties
= obj
->GetProperties (true);
221 if (properties
[0] != NULL
) {
222 GtkTreeIter prop_iter
, iter
;
228 gtk_tree_store_append (store
, &prop_iter
, node
);
230 gtk_tree_store_set (store
, &prop_iter
,
231 COL_NAME
, "Properties",
233 COL_ELEMENT_PTR
, obj
,
236 for (int i
= 0; properties
[i
]; i
++) {
237 owner_type
= Type::Find (properties
[i
]->GetOwnerType ());
238 markup
= g_strdup_printf ("<i>%s.%s</i>", owner_type
? owner_type
->GetName () : "(unknown)",
239 properties
[i
]->GetName ());
241 gtk_tree_store_append (store
, &iter
, &prop_iter
);
243 prop_type
= Type::Find (properties
[i
]->GetPropertyType ());
244 value
= obj
->GetValue (properties
[i
]);
246 reflect_value (store
, &iter
, markup
, prop_type
? prop_type
->GetName () : "(unknown)", value
);
254 if (obj
->Is(Type::COLLECTION
)) {
255 Collection
*col
= (Collection
*)obj
;
257 if (col
->GetCount() > 0) {
258 GtkTreeIter elements_iter
;
260 gtk_tree_store_append (store
, &elements_iter
, node
);
262 gtk_tree_store_set (store
, &elements_iter
,
263 COL_NAME
, "Elements",
265 COL_ELEMENT_PTR
, obj
,
268 for (int i
= 0; i
< col
->GetCount(); i
++) {
269 Value
*v
= col
->GetValueAt (i
);
272 if (v
->Is (Type::DEPENDENCY_OBJECT
))
273 markup
= g_strdup_printf ("<i>[%d]</i> <b>%s</b>", i
, v
->AsDependencyObject()->GetName() ? v
->AsDependencyObject()->GetName() : "");
275 markup
= g_strdup_printf ("<i>[%d]</i>", i
);
277 GtkTreeIter child_iter
;
279 gtk_tree_store_append (store
, &child_iter
, &elements_iter
);
281 reflect_value (store
, &child_iter
, markup
, NULL
, v
);
288 if (obj
->Is(Type::FRAMEWORKELEMENT
) && !obj
->Is(Type::PANEL
) && !obj
->Is (Type::BORDER
)) {
289 GtkTreeIter subobject_iter
;
291 gtk_tree_store_append (store
, &subobject_iter
, node
);
293 Value
v(((Control
*)obj
)->GetSubtreeObject());
295 reflect_value (store
, &subobject_iter
, "Visual Child", NULL
, &v
);
300 selection_changed (GtkTreeSelection
*selection
, PluginInstance
*plugin
)
304 DependencyObject
*el
;
306 Deployment::SetCurrent (plugin
->GetDeployment ());
308 if (plugin
->GetSurface()->debug_selected_element
) {
309 UIElement
*el
= plugin
->GetSurface()->debug_selected_element
;
310 el
->Invalidate (el
->GetSubtreeBounds().GrowBy(1).RoundOut());
312 plugin
->GetSurface()->debug_selected_element
= NULL
;
315 if (!gtk_tree_selection_get_selected (selection
,
321 gtk_tree_model_get (model
, &iter
,
322 COL_ELEMENT_PTR
, &el
,
325 if (el
&& el
->Is(Type::UIELEMENT
)) {
326 UIElement
*ui
= (UIElement
*)el
;
327 ui
->Invalidate (ui
->GetSubtreeBounds().GrowBy(1).RoundOut());
329 plugin
->GetSurface()->debug_selected_element
= ui
;
332 Deployment::SetCurrent (NULL
);
336 surface_destroyed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
338 gtk_widget_destroy ((GtkWidget
*) closure
);
342 remove_destroyed_handler (PluginInstance
*plugin
, GObject
*window
)
344 Deployment::SetCurrent (plugin
->GetDeployment ());
345 plugin
->GetSurface ()->RemoveHandler (EventObject::DestroyedEvent
, surface_destroyed
, window
);
346 Deployment::SetCurrent (NULL
);
350 plugin_debug (PluginInstance
*plugin
)
352 Surface
*surface
= plugin
->GetSurface ();
355 GtkWidget
*d
= gtk_message_dialog_new (NULL
,
356 GTK_DIALOG_NO_SEPARATOR
,
359 "The plugin hasn't been initialized with xaml content yet");
360 gtk_dialog_run (GTK_DIALOG (d
));
365 GtkWidget
*tree_win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
366 gtk_window_set_title (GTK_WINDOW (tree_win
), "Xaml contents");
367 gtk_window_set_default_size (GTK_WINDOW (tree_win
), 300, 400);
369 Deployment::SetCurrent (plugin
->GetDeployment ());
371 surface
->AddHandler (EventObject::DestroyedEvent
, surface_destroyed
, tree_win
);
372 g_object_weak_ref (G_OBJECT (tree_win
), (GWeakNotify
) remove_destroyed_handler
, plugin
);
374 GtkTreeStore
*tree_store
= gtk_tree_store_new (NUM_COLUMNS
,
380 reflect_dependency_object_in_tree (plugin
->GetSurface()->GetToplevel (), tree_store
, NULL
, false);
383 GtkTreeModel
*sorted_model
= gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree_store
));
385 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sorted_model
),
386 COL_NAME
, GTK_SORT_ASCENDING
);
388 GtkWidget
* tree_view
= gtk_tree_view_new_with_model (sorted_model
);
390 GtkWidget
* tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
393 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
395 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
397 g_signal_connect (G_OBJECT (selection
), "changed",
398 G_CALLBACK (selection_changed
), plugin
);
400 GtkCellRenderer
*renderer
= gtk_cell_renderer_text_new();
401 GtkTreeViewColumn
*col
;
403 /* The Name column */
404 col
= gtk_tree_view_column_new();
405 gtk_tree_view_column_set_title(col
, "Name");
406 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
408 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
409 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_NAME
);
410 gtk_tree_view_column_set_resizable (col
, TRUE
);
412 gtk_tree_view_column_set_sort_column_id (col
, COL_NAME
);
414 /* The Type column */
415 col
= gtk_tree_view_column_new();
416 gtk_tree_view_column_set_title(col
, "Type");
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_TYPE_NAME
);
421 gtk_tree_view_column_set_resizable (col
, TRUE
);
423 /* The Value column */
424 col
= gtk_tree_view_column_new();
425 gtk_tree_view_column_set_title(col
, "Value");
426 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
428 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
429 gtk_tree_view_column_add_attribute (col
, renderer
, "markup", COL_VALUE
);
430 gtk_tree_view_column_set_resizable (col
, TRUE
);
432 GtkWidget
*scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
433 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
434 GTK_POLICY_AUTOMATIC
,
435 GTK_POLICY_AUTOMATIC
);
437 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
438 gtk_container_add (GTK_CONTAINER (tree_win
), scrolled
);
440 gtk_widget_show_all (tree_win
);
442 Deployment::SetCurrent (NULL
);
446 populate_tree_from_surface (PluginInstance
*plugin
, GtkTreeStore
*store
, GtkTreeIter
*parent
)
453 PluginInstance::moon_source
*src
;
455 sources
= plugin
->GetSources ();
460 src
= (PluginInstance::moon_source
*) sources
->First ();
461 for (; src
!= NULL
; src
= (PluginInstance::moon_source
*) src
->next
) {
462 gtk_tree_store_append (store
, &iter
, parent
);
464 gtk_tree_store_set (store
, &iter
,
473 PluginInstance::moon_source
*selected_source
= NULL
;
476 selection_changed_sources (GtkTreeSelection
*selection
, PluginInstance
*plugin
)
481 selected_source
= NULL
;
483 if (!gtk_tree_selection_get_selected (selection
,
489 gtk_tree_model_get (model
, &iter
,
494 static void clicked_callback (GtkWidget
*widget
, gpointer data
)
496 if (selected_source
== NULL
) {
497 printf ("Select a source first.\n");
500 argv
[0] = (gchar
*) "xdg-open";
501 argv
[1] = (gchar
*) selected_source
->filename
;
503 g_spawn_async (NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
, NULL
, NULL
);
507 static void unxap_callback (GtkWidget
*widget
, gpointer data
)
509 if (selected_source
== NULL
) {
510 printf ("Select a source first.\n");
513 argv
[0] = (gchar
*) "munxap";
514 argv
[1] = (gchar
*) selected_source
->filename
;
516 g_spawn_async (NULL
, argv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
, NULL
, NULL
);
522 get_common_prefix_len (GtkTreeModel
*model
)
524 char *filename
, *path
, *url
, *buf
, *p
, *q
;
525 size_t max
= (size_t) -1;
529 if (!gtk_tree_model_get_iter_first (model
, &iter
))
532 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
535 if (!uri
->Parse (url
)) {
536 buf
= g_strdup (filename
);
538 buf
= (char*)uri
->GetPath();
542 if ((p
= strrchr (buf
, '/')))
549 while (gtk_tree_model_iter_next (model
, &iter
)) {
550 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
553 if (!uri
->Parse (url
))
556 path
= (char*)uri
->GetPath();
558 for (p
= buf
, q
= path
; *p
&& *q
; p
++, q
++) {
563 if ((size_t) (p
- buf
) < max
)
575 save_callback (GtkWidget
*widget
, gpointer data
)
577 GtkTreeModel
*model
= (GtkTreeModel
*) data
;
578 char *filename
, *dirname
, *url
, *path
;
584 if (mkdir ("/tmp/moon-dump", 0777) == -1 && errno
!= EEXIST
)
587 prelen
= get_common_prefix_len (model
);
589 if (!gtk_tree_model_get_iter_first (model
, &iter
))
593 gtk_tree_model_get (model
, &iter
, 0, &url
, 1, &filename
, -1);
596 if (uri
->Parse (url
))
597 path
= (char*)uri
->GetPath();
601 path
= g_build_filename ("/tmp/moon-dump", path
+ prelen
, NULL
);
604 dirname
= g_path_get_dirname (path
);
605 g_mkdir_with_parents (dirname
, 0777);
608 if ((fd
= open (path
, O_CREAT
| O_WRONLY
| O_EXCL
, 0644)) != -1) {
609 if (CopyFileTo (filename
, fd
) == -1)
610 printf (" Failed: Could not copy file `%s' to `%s': %s\n", filename
, path
, g_strerror (errno
));
611 } else if (errno
!= EEXIST
) {
612 printf (" Failed: Could not create file `%s': %s\n", path
, g_strerror (errno
));
616 } while (gtk_tree_model_iter_next (model
, &iter
));
620 plugin_sources (PluginInstance
*plugin
)
622 GtkWidget
*tree_win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
623 gtk_window_set_title (GTK_WINDOW (tree_win
), "Sources");
624 gtk_window_set_default_size (GTK_WINDOW (tree_win
), 600, 400);
625 GtkBox
*vbox
= GTK_BOX (gtk_vbox_new (false, 0));
627 GtkTreeStore
*tree_store
= gtk_tree_store_new (3,
632 populate_tree_from_surface (plugin
, tree_store
, NULL
);
634 GtkWidget
*tree_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store
));
636 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
638 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_SINGLE
);
640 g_signal_connect (G_OBJECT (selection
), "changed",
641 G_CALLBACK (selection_changed_sources
), plugin
);
643 GtkCellRenderer
*renderer
= gtk_cell_renderer_text_new();
644 GtkTreeViewColumn
*col
;
646 /* The Name column */
647 col
= gtk_tree_view_column_new();
648 gtk_tree_view_column_set_title(col
, "Uri");
649 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
651 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
652 gtk_tree_view_column_add_attribute (col
, renderer
, "text", 0);
654 /* The Type column */
655 col
= gtk_tree_view_column_new();
656 gtk_tree_view_column_set_title(col
, "Filename");
657 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view
), col
);
659 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
660 gtk_tree_view_column_add_attribute (col
, renderer
, "text", 1);
662 GtkWidget
*scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
663 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
664 GTK_POLICY_AUTOMATIC
,
665 GTK_POLICY_AUTOMATIC
);
667 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
668 //gtk_container_add (GTK_CONTAINER (tree_win), scrolled);
669 gtk_box_pack_start (vbox
, scrolled
, TRUE
, TRUE
, 0);
672 button
= gtk_button_new_with_label ("Open file");
673 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (clicked_callback
), NULL
);
674 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
676 button
= gtk_button_new_with_label ("Unxap");
677 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (unxap_callback
), tree_store
);
678 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
680 button
= gtk_button_new_with_label ("Save (to /tmp/moon-dump/)");
681 g_signal_connect (G_OBJECT (button
), "clicked", G_CALLBACK (save_callback
), tree_store
);
682 gtk_box_pack_start (vbox
, button
, FALSE
, FALSE
, 0);
684 gtk_container_add (GTK_CONTAINER (tree_win
), GTK_WIDGET (vbox
));
686 gtk_widget_show_all (tree_win
);