gtk2/gtk/inspector/misc-info.c

579 lines
18 KiB
C
Raw Normal View History

/*
* Copyright (c) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include "misc-info.h"
#include "window.h"
#include "type-info.h"
#include "gtktypebuiltins.h"
#include "gtktreeview.h"
#include "gtkbuildable.h"
#include "gtklabel.h"
#include "gtkframe.h"
#include "gtkbutton.h"
#include "gtkmenubutton.h"
#include "gtkwidgetprivate.h"
#include "gtkbinlayout.h"
struct _GtkInspectorMiscInfo
{
GtkWidget parent;
GObject *object;
GtkWidget *swin;
GtkWidget *address;
GtkWidget *type;
GtkWidget *type_popover;
GtkWidget *refcount_row;
GtkWidget *refcount;
GtkWidget *state_row;
GtkWidget *state;
GtkWidget *buildable_id_row;
GtkWidget *buildable_id;
GtkWidget *mnemonic_label_row;
GtkWidget *mnemonic_label;
GtkWidget *request_mode_row;
GtkWidget *request_mode;
GtkWidget *allocated_size_row;
GtkWidget *allocated_size;
GtkWidget *baseline_row;
GtkWidget *baseline;
2019-05-28 19:43:01 +00:00
GtkWidget *surface_row;
GtkWidget *surface;
GtkWidget *surface_button;
GtkWidget *renderer_row;
GtkWidget *renderer;
GtkWidget *renderer_button;
GtkWidget *frame_clock_row;
GtkWidget *frame_clock;
GtkWidget *frame_clock_button;
GtkWidget *tick_callback_row;
GtkWidget *tick_callback;
GtkWidget *framerate_row;
GtkWidget *framerate;
GtkWidget *framecount_row;
GtkWidget *framecount;
GtkWidget *mapped_row;
GtkWidget *mapped;
GtkWidget *realized_row;
GtkWidget *realized;
GtkWidget *is_toplevel_row;
GtkWidget *is_toplevel;
GtkWidget *child_visible_row;
GtkWidget *child_visible;
guint update_source_id;
gint64 last_frame;
};
typedef struct _GtkInspectorMiscInfoClass
{
GtkWidgetClass parent_class;
} GtkInspectorMiscInfoClass;
G_DEFINE_TYPE (GtkInspectorMiscInfo, gtk_inspector_misc_info, GTK_TYPE_WIDGET)
2020-07-24 18:40:36 +00:00
static char *
format_state_flags (GtkStateFlags state)
{
GFlagsClass *fclass;
GString *str;
2020-07-24 13:54:49 +00:00
int i;
str = g_string_new ("");
if (state)
{
fclass = g_type_class_ref (GTK_TYPE_STATE_FLAGS);
for (i = 0; i < fclass->n_values; i++)
{
if (state & fclass->values[i].value)
{
if (str->len)
g_string_append (str, " | ");
g_string_append (str, fclass->values[i].value_nick);
}
}
g_type_class_unref (fclass);
}
else
g_string_append (str, "normal");
return g_string_free (str, FALSE);
}
static void
state_flags_changed (GtkWidget *w, GtkStateFlags old_flags, GtkInspectorMiscInfo *sl)
{
2020-07-24 18:40:36 +00:00
char *s;
s = format_state_flags (gtk_widget_get_state_flags (w));
gtk_label_set_label (GTK_LABEL (sl->state), s);
g_free (s);
}
static void
update_allocation (GtkWidget *w,
GtkInspectorMiscInfo *sl)
{
GtkAllocation alloc;
2020-07-24 18:40:36 +00:00
char *size_label;
GEnumClass *class;
GEnumValue *value;
gtk_widget_get_allocation (w, &alloc);
size_label = g_strdup_printf ("%d×%d+%d+%d",
alloc.width, alloc.height,
alloc.x, alloc.y);
gtk_label_set_label (GTK_LABEL (sl->allocated_size), size_label);
g_free (size_label);
size_label = g_strdup_printf ("%d", gtk_widget_get_allocated_baseline (w));
gtk_label_set_label (GTK_LABEL (sl->baseline), size_label);
g_free (size_label);
class = G_ENUM_CLASS (g_type_class_ref (GTK_TYPE_SIZE_REQUEST_MODE));
value = g_enum_get_value (class, gtk_widget_get_request_mode (w));
gtk_label_set_label (GTK_LABEL (sl->request_mode), value->value_nick);
g_type_class_unref (class);
}
static void
disconnect_each_other (gpointer still_alive,
GObject *for_science)
{
if (GTK_INSPECTOR_IS_MISC_INFO (still_alive))
{
GtkInspectorMiscInfo *self = GTK_INSPECTOR_MISC_INFO (still_alive);
self->object = NULL;
}
g_signal_handlers_disconnect_matched (still_alive, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, for_science);
g_object_weak_unref (still_alive, disconnect_each_other, for_science);
}
static void
show_mnemonic_label (GtkWidget *button, GtkInspectorMiscInfo *sl)
{
GtkInspectorWindow *iw;
GtkWidget *widget;
iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (sl), GTK_TYPE_INSPECTOR_WINDOW));
widget = g_object_get_data (G_OBJECT (button), "mnemonic-label");
if (widget)
gtk_inspector_window_push_object (iw, G_OBJECT (widget), CHILD_KIND_OTHER, 0);
}
2019-05-28 19:43:01 +00:00
static void
show_surface (GtkWidget *button, GtkInspectorMiscInfo *sl)
{
GtkInspectorWindow *iw;
2019-05-28 19:43:01 +00:00
GObject *surface;
iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (sl), GTK_TYPE_INSPECTOR_WINDOW));
surface = (GObject *)gtk_native_get_surface (GTK_NATIVE (sl->object));
2019-05-28 19:43:01 +00:00
if (surface)
gtk_inspector_window_push_object (iw, surface, CHILD_KIND_OTHER, 0);
2019-05-28 19:43:01 +00:00
}
static void
show_renderer (GtkWidget *button, GtkInspectorMiscInfo *sl)
{
GtkInspectorWindow *iw;
2019-05-28 19:43:01 +00:00
GObject *renderer;
iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (sl), GTK_TYPE_INSPECTOR_WINDOW));
renderer = (GObject *)gtk_native_get_renderer (GTK_NATIVE (sl->object));
2019-05-28 19:43:01 +00:00
if (renderer)
gtk_inspector_window_push_object (iw, renderer, CHILD_KIND_OTHER, 0);
2019-05-28 19:43:01 +00:00
}
static void
show_frame_clock (GtkWidget *button, GtkInspectorMiscInfo *sl)
{
GtkInspectorWindow *iw;
GObject *clock;
iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (sl), GTK_TYPE_INSPECTOR_WINDOW));
clock = (GObject *)gtk_widget_get_frame_clock (GTK_WIDGET (sl->object));
if (clock)
gtk_inspector_window_push_object (iw, clock, CHILD_KIND_OTHER, 0);
}
static void
2019-05-28 19:43:01 +00:00
update_surface (GtkInspectorMiscInfo *sl)
{
if (GTK_IS_NATIVE (sl->object))
2019-05-28 19:43:01 +00:00
{
GObject *obj;
char *tmp;
gtk_widget_show (sl->surface_row);
2019-05-28 19:43:01 +00:00
obj = (GObject *)gtk_native_get_surface (GTK_NATIVE (sl->object));
2019-05-28 19:43:01 +00:00
tmp = g_strdup_printf ("%p", obj);
gtk_label_set_label (GTK_LABEL (sl->surface), tmp);
2019-05-28 19:43:01 +00:00
g_free (tmp);
}
else
{
gtk_widget_hide (sl->surface_row);
2019-05-28 19:43:01 +00:00
}
}
static void
update_renderer (GtkInspectorMiscInfo *sl)
{
if (GTK_IS_NATIVE (sl->object))
{
2019-05-28 19:43:01 +00:00
GObject *obj;
char *tmp;
gtk_widget_show (sl->renderer_row);
2019-05-28 19:43:01 +00:00
obj = (GObject *)gtk_native_get_surface (GTK_NATIVE (sl->object));
2019-05-28 19:43:01 +00:00
tmp = g_strdup_printf ("%p", obj);
gtk_label_set_label (GTK_LABEL (sl->renderer), tmp);
g_free (tmp);
}
else
{
gtk_widget_hide (sl->renderer_row);
2019-05-28 19:43:01 +00:00
}
}
static void
update_frame_clock (GtkInspectorMiscInfo *sl)
{
if (GTK_IS_ROOT (sl->object))
2019-05-28 19:43:01 +00:00
{
GObject *clock;
gtk_widget_show (sl->frame_clock_row);
2019-05-28 19:43:01 +00:00
clock = (GObject *)gtk_widget_get_frame_clock (GTK_WIDGET (sl->object));
2019-05-28 19:43:01 +00:00
if (clock)
{
2020-07-24 18:40:36 +00:00
char *tmp;
2019-05-28 19:43:01 +00:00
tmp = g_strdup_printf ("%p", clock);
gtk_label_set_label (GTK_LABEL (sl->frame_clock), tmp);
2019-05-28 19:43:01 +00:00
g_free (tmp);
gtk_widget_set_sensitive (sl->frame_clock_button, TRUE);
2019-05-28 19:43:01 +00:00
}
else
{
gtk_label_set_label (GTK_LABEL (sl->frame_clock), "NULL");
gtk_widget_set_sensitive (sl->frame_clock_button, FALSE);
2019-05-28 19:43:01 +00:00
}
}
else
{
gtk_widget_hide (sl->frame_clock_row);
}
}
static gboolean
update_info (gpointer data)
{
GtkInspectorMiscInfo *sl = data;
2020-07-24 18:40:36 +00:00
char *tmp;
GType gtype;
tmp = g_strdup_printf ("%p", sl->object);
gtk_label_set_text (GTK_LABEL (sl->address), tmp);
g_free (tmp);
gtype = G_TYPE_FROM_INSTANCE (sl->object);
gtk_menu_button_set_label (GTK_MENU_BUTTON (sl->type), g_type_name (gtype));
gtk_inspector_type_popover_set_gtype (GTK_INSPECTOR_TYPE_POPOVER (sl->type_popover),
gtype);
if (G_IS_OBJECT (sl->object))
{
tmp = g_strdup_printf ("%d", sl->object->ref_count);
gtk_label_set_text (GTK_LABEL (sl->refcount), tmp);
g_free (tmp);
}
if (GTK_IS_WIDGET (sl->object))
{
GtkWidget *child;
GList *list, *l;
while ((child = gtk_widget_get_first_child (sl->mnemonic_label)))
gtk_box_remove (GTK_BOX (sl->mnemonic_label), child);
list = gtk_widget_list_mnemonic_labels (GTK_WIDGET (sl->object));
for (l = list; l; l = l->next)
{
GtkWidget *button;
tmp = g_strdup_printf ("%p (%s)", l->data, g_type_name_from_instance ((GTypeInstance*)l->data));
button = gtk_button_new_with_label (tmp);
g_free (tmp);
gtk_widget_show (button);
gtk_box_append (GTK_BOX (sl->mnemonic_label), button);
g_object_set_data (G_OBJECT (button), "mnemonic-label", l->data);
g_signal_connect (button, "clicked", G_CALLBACK (show_mnemonic_label), sl);
}
g_list_free (list);
gtk_widget_set_visible (sl->tick_callback, gtk_widget_has_tick_callback (GTK_WIDGET (sl->object)));
}
2019-05-28 19:43:01 +00:00
update_surface (sl);
update_renderer (sl);
update_frame_clock (sl);
if (GTK_IS_BUILDABLE (sl->object))
{
gtk_label_set_text (GTK_LABEL (sl->buildable_id),
gtk_buildable_get_buildable_id (GTK_BUILDABLE (sl->object)));
}
if (GDK_IS_FRAME_CLOCK (sl->object))
{
GdkFrameClock *clock;
gint64 frame;
gint64 frame_time;
gint64 history_start;
gint64 history_len;
gint64 previous_frame_time;
GdkFrameTimings *previous_timings;
clock = GDK_FRAME_CLOCK (sl->object);
frame = gdk_frame_clock_get_frame_counter (clock);
frame_time = gdk_frame_clock_get_frame_time (clock);
tmp = g_strdup_printf ("%"G_GINT64_FORMAT, frame);
gtk_label_set_label (GTK_LABEL (sl->framecount), tmp);
g_free (tmp);
history_start = gdk_frame_clock_get_history_start (clock);
history_len = frame - history_start;
if (history_len > 0 && sl->last_frame != frame)
{
previous_timings = gdk_frame_clock_get_timings (clock, history_start);
previous_frame_time = gdk_frame_timings_get_frame_time (previous_timings);
tmp = g_strdup_printf ("%4.1fs", (G_USEC_PER_SEC * history_len) / (double) (frame_time - previous_frame_time));
gtk_label_set_label (GTK_LABEL (sl->framerate), tmp);
g_free (tmp);
}
else
{
gtk_label_set_label (GTK_LABEL (sl->framerate), "");
}
sl->last_frame = frame;
}
return G_SOURCE_CONTINUE;
}
void
gtk_inspector_misc_info_set_object (GtkInspectorMiscInfo *sl,
GObject *object)
{
if (sl->object)
{
g_signal_handlers_disconnect_by_func (sl->object, state_flags_changed, sl);
disconnect_each_other (sl->object, G_OBJECT (sl));
disconnect_each_other (sl, sl->object);
sl->object = NULL;
}
gtk_widget_show (GTK_WIDGET (sl));
sl->object = object;
g_object_weak_ref (G_OBJECT (sl), disconnect_each_other, object);
g_object_weak_ref (object, disconnect_each_other, sl);
if (GTK_IS_WIDGET (object))
{
gtk_widget_show (sl->refcount_row);
gtk_widget_show (sl->state_row);
gtk_widget_show (sl->request_mode_row);
gtk_widget_show (sl->allocated_size_row);
gtk_widget_show (sl->baseline_row);
gtk_widget_show (sl->mnemonic_label_row);
gtk_widget_show (sl->tick_callback_row);
gtk_widget_show (sl->mapped_row);
gtk_widget_show (sl->realized_row);
gtk_widget_show (sl->is_toplevel_row);
gtk_widget_show (sl->is_toplevel_row);
gtk_widget_show (sl->frame_clock_row);
g_signal_connect_object (object, "state-flags-changed", G_CALLBACK (state_flags_changed), sl, 0);
state_flags_changed (GTK_WIDGET (sl->object), 0, sl);
update_allocation (GTK_WIDGET (sl->object), sl);
}
else
{
gtk_widget_hide (sl->state_row);
gtk_widget_hide (sl->request_mode_row);
gtk_widget_hide (sl->mnemonic_label_row);
gtk_widget_hide (sl->allocated_size_row);
gtk_widget_hide (sl->baseline_row);
gtk_widget_hide (sl->tick_callback_row);
gtk_widget_hide (sl->mapped_row);
gtk_widget_hide (sl->realized_row);
gtk_widget_hide (sl->is_toplevel_row);
gtk_widget_hide (sl->child_visible_row);
gtk_widget_hide (sl->frame_clock_row);
}
if (GTK_IS_BUILDABLE (object))
{
gtk_widget_show (sl->buildable_id_row);
}
else
{
gtk_widget_hide (sl->buildable_id_row);
}
if (GDK_IS_FRAME_CLOCK (object))
{
gtk_widget_show (sl->framecount_row);
gtk_widget_show (sl->framerate_row);
}
else
{
gtk_widget_hide (sl->framecount_row);
gtk_widget_hide (sl->framerate_row);
}
update_info (sl);
}
static void
gtk_inspector_misc_info_init (GtkInspectorMiscInfo *sl)
{
gtk_widget_init_template (GTK_WIDGET (sl));
sl->type_popover = g_object_new (GTK_TYPE_INSPECTOR_TYPE_POPOVER, NULL);
gtk_menu_button_set_popover (GTK_MENU_BUTTON (sl->type),
sl->type_popover);
}
static void
map (GtkWidget *widget)
{
GtkInspectorMiscInfo *sl = GTK_INSPECTOR_MISC_INFO (widget);
GTK_WIDGET_CLASS (gtk_inspector_misc_info_parent_class)->map (widget);
sl->update_source_id = g_timeout_add_seconds (1, update_info, sl);
update_info (sl);
}
static void
unmap (GtkWidget *widget)
{
GtkInspectorMiscInfo *sl = GTK_INSPECTOR_MISC_INFO (widget);
g_source_remove (sl->update_source_id);
sl->update_source_id = 0;
GTK_WIDGET_CLASS (gtk_inspector_misc_info_parent_class)->unmap (widget);
}
static void
dispose (GObject *o)
{
GtkInspectorMiscInfo *sl = GTK_INSPECTOR_MISC_INFO (o);
g_clear_pointer (&sl->swin, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_inspector_misc_info_parent_class)->dispose (o);
}
static void
gtk_inspector_misc_info_class_init (GtkInspectorMiscInfoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = dispose;
widget_class->map = map;
widget_class->unmap = unmap;
2014-11-30 20:59:53 +00:00
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/misc-info.ui");
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, swin);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, address);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, type);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, refcount_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, refcount);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, state_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, state);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, buildable_id_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, buildable_id);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, mnemonic_label_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, mnemonic_label);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, request_mode_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, request_mode);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, allocated_size_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, allocated_size);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, baseline_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, baseline);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, surface_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, surface);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, surface_button);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, renderer_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, renderer);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, renderer_button);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, frame_clock_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, frame_clock);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, frame_clock_button);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, tick_callback_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, tick_callback);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, framecount_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, framecount);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, framerate_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, framerate);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, mapped_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, mapped);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, realized_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, realized);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, is_toplevel_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, is_toplevel);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, child_visible_row);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorMiscInfo, child_visible);
2019-05-28 19:43:01 +00:00
gtk_widget_class_bind_template_callback (widget_class, show_surface);
gtk_widget_class_bind_template_callback (widget_class, show_renderer);
gtk_widget_class_bind_template_callback (widget_class, show_frame_clock);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}
// vim: set et sw=2 ts=2: