forked from AuroraMiddleware/gtk
inspector: Add a clipboard page
Shows all the formats supported by the clipboard (and primary clipboard) and allows displaying them (by potentially downloading them)
This commit is contained in:
parent
17c903e246
commit
600ab5ba5f
316
gtk/inspector/clipboard.c
Normal file
316
gtk/inspector/clipboard.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Benjamin Otte
|
||||
*
|
||||
* 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 "clipboard.h"
|
||||
#include "gtkdataviewer.h"
|
||||
#include "window.h"
|
||||
|
||||
#include "gtkbinlayout.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtklabel.h"
|
||||
#include "gtklistbox.h"
|
||||
#include "gtktogglebutton.h"
|
||||
|
||||
struct _GtkInspectorClipboard
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GdkDisplay *display;
|
||||
|
||||
GtkWidget *swin;
|
||||
|
||||
GtkWidget *clipboard_formats;
|
||||
GtkWidget *clipboard_info;
|
||||
|
||||
GtkWidget *primary_formats;
|
||||
GtkWidget *primary_info;
|
||||
};
|
||||
|
||||
typedef struct _GtkInspectorClipboardClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
} GtkInspectorClipboardClass;
|
||||
|
||||
G_DEFINE_TYPE (GtkInspectorClipboard, gtk_inspector_clipboard, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
load_gtype_value (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GdkClipboard *clipboard = GDK_CLIPBOARD (source);
|
||||
GtkDataViewer *viewer = data;
|
||||
const GValue *value;
|
||||
GError *error = NULL;
|
||||
|
||||
value = gdk_clipboard_read_value_finish (clipboard, res, &error);
|
||||
if (value == NULL)
|
||||
gtk_data_viewer_load_error (viewer, error);
|
||||
else
|
||||
gtk_data_viewer_load_value (viewer, value);
|
||||
|
||||
g_object_unref (viewer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_gtype (GtkDataViewer *viewer,
|
||||
GCancellable *cancellable,
|
||||
gpointer gtype)
|
||||
{
|
||||
GdkClipboard *clipboard = g_object_get_data (G_OBJECT (viewer), "clipboard");
|
||||
|
||||
gdk_clipboard_read_value_async (clipboard,
|
||||
GPOINTER_TO_SIZE (gtype),
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
load_gtype_value,
|
||||
g_object_ref (viewer));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
load_mime_type_stream (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GdkClipboard *clipboard = GDK_CLIPBOARD (source);
|
||||
GtkDataViewer *viewer = data;
|
||||
GInputStream *stream;
|
||||
GError *error = NULL;
|
||||
const char *mime_type;
|
||||
|
||||
stream = gdk_clipboard_read_finish (clipboard, res, &mime_type, &error);
|
||||
if (stream == NULL)
|
||||
gtk_data_viewer_load_error (viewer, error);
|
||||
else
|
||||
gtk_data_viewer_load_stream (viewer, stream, mime_type);
|
||||
|
||||
g_object_unref (viewer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_mime_type (GtkDataViewer *viewer,
|
||||
GCancellable *cancellable,
|
||||
gpointer mime_type)
|
||||
{
|
||||
GdkClipboard *clipboard = g_object_get_data (G_OBJECT (viewer), "clipboard");
|
||||
|
||||
gdk_clipboard_read_async (clipboard,
|
||||
(const char *[2]) { mime_type, NULL },
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
load_mime_type_stream,
|
||||
g_object_ref (viewer));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_content_type_row (GtkInspectorClipboard *self,
|
||||
GtkListBox *list,
|
||||
const char *type_name,
|
||||
GdkClipboard *clipboard,
|
||||
GCallback load_func,
|
||||
gpointer load_func_data)
|
||||
{
|
||||
GtkWidget *row, *vbox, *hbox, *label, *viewer, *button;
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
|
||||
label = gtk_label_new (type_name);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_box_append (GTK_BOX (hbox), label);
|
||||
|
||||
button = gtk_toggle_button_new_with_label (_("Show"));
|
||||
gtk_widget_set_halign (button, GTK_ALIGN_END);
|
||||
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
|
||||
viewer = gtk_data_viewer_new ();
|
||||
g_signal_connect (viewer, "load", load_func, load_func_data);
|
||||
g_object_set_data (G_OBJECT (viewer), "clipboard", clipboard);
|
||||
g_object_bind_property (G_OBJECT (button), "active",
|
||||
G_OBJECT (viewer), "visible",
|
||||
G_BINDING_SYNC_CREATE);
|
||||
gtk_box_append (GTK_BOX (vbox), viewer);
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), vbox);
|
||||
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
|
||||
|
||||
gtk_list_box_insert (list, row, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
init_formats (GtkInspectorClipboard *self,
|
||||
GtkListBox *list,
|
||||
GdkClipboard *clipboard)
|
||||
{
|
||||
GtkListBoxRow *row;
|
||||
GdkContentFormats *formats;
|
||||
const char * const *mime_types;
|
||||
const GType *gtypes;
|
||||
gsize i, n;
|
||||
|
||||
while ((row = gtk_list_box_get_row_at_index (list, 1)))
|
||||
gtk_list_box_remove (list, GTK_WIDGET (row));
|
||||
|
||||
formats = gdk_clipboard_get_formats (clipboard);
|
||||
|
||||
gtypes = gdk_content_formats_get_gtypes (formats, &n);
|
||||
for (i = 0; i < n; i++)
|
||||
add_content_type_row (self, list, g_type_name (gtypes[i]), clipboard, G_CALLBACK (load_gtype), GSIZE_TO_POINTER (gtypes[i]));
|
||||
|
||||
mime_types = gdk_content_formats_get_mime_types (formats, &n);
|
||||
for (i = 0; i < n; i++)
|
||||
add_content_type_row (self, list, mime_types[i], clipboard, G_CALLBACK (load_mime_type), (gpointer) mime_types[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
init_info (GtkInspectorClipboard *self,
|
||||
GtkLabel *label,
|
||||
GdkClipboard *clipboard)
|
||||
{
|
||||
GdkContentFormats *formats;
|
||||
|
||||
formats = gdk_clipboard_get_formats (clipboard);
|
||||
if (gdk_content_formats_get_gtypes (formats, NULL) == NULL &&
|
||||
gdk_content_formats_get_mime_types (formats, NULL) == NULL)
|
||||
{
|
||||
gtk_label_set_text (label, C_("clipboard", "empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_clipboard_is_local (clipboard))
|
||||
gtk_label_set_text (label, C_("clipboard", "local"));
|
||||
else
|
||||
gtk_label_set_text (label, C_("clipboard", "remote"));
|
||||
}
|
||||
|
||||
static void
|
||||
clipboard_notify (GdkClipboard *clipboard,
|
||||
GParamSpec *pspec,
|
||||
GtkInspectorClipboard *self)
|
||||
{
|
||||
if (g_str_equal (pspec->name, "formats"))
|
||||
{
|
||||
init_formats (self, GTK_LIST_BOX (self->clipboard_formats), clipboard);
|
||||
}
|
||||
|
||||
init_info (self, GTK_LABEL (self->clipboard_info), clipboard);
|
||||
}
|
||||
|
||||
static void
|
||||
primary_notify (GdkClipboard *clipboard,
|
||||
GParamSpec *pspec,
|
||||
GtkInspectorClipboard *self)
|
||||
{
|
||||
if (g_str_equal (pspec->name, "formats"))
|
||||
{
|
||||
init_formats (self, GTK_LIST_BOX (self->primary_formats), clipboard);
|
||||
}
|
||||
|
||||
g_print ("%s: %s\n", pspec->name, gdk_content_formats_to_string (gdk_clipboard_get_formats (clipboard)));
|
||||
init_info (self, GTK_LABEL (self->primary_info), clipboard);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_inspector_clipboard_unset_display (GtkInspectorClipboard *self)
|
||||
{
|
||||
GdkClipboard *clipboard;
|
||||
|
||||
if (self->display == NULL)
|
||||
return;
|
||||
|
||||
clipboard = gdk_display_get_clipboard (self->display);
|
||||
g_signal_handlers_disconnect_by_func (clipboard, clipboard_notify, self);
|
||||
|
||||
clipboard = gdk_display_get_primary_clipboard (self->display);
|
||||
g_signal_handlers_disconnect_by_func (clipboard, primary_notify, self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_inspector_clipboard_init (GtkInspectorClipboard *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_inspector_clipboard_dispose (GObject *object)
|
||||
{
|
||||
GtkInspectorClipboard *self = GTK_INSPECTOR_CLIPBOARD (object);
|
||||
|
||||
gtk_inspector_clipboard_unset_display (self);
|
||||
|
||||
g_clear_pointer (&self->swin, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (gtk_inspector_clipboard_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_inspector_clipboard_class_init (GtkInspectorClipboardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_inspector_clipboard_dispose;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/clipboard.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorClipboard, swin);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorClipboard, clipboard_formats);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorClipboard, clipboard_info);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorClipboard, primary_formats);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorClipboard, primary_info);
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_inspector_clipboard_set_display (GtkInspectorClipboard *self,
|
||||
GdkDisplay *display)
|
||||
{
|
||||
GdkClipboard *clipboard;
|
||||
|
||||
gtk_inspector_clipboard_unset_display (self);
|
||||
|
||||
self->display = display;
|
||||
|
||||
if (display == NULL)
|
||||
return;
|
||||
|
||||
clipboard = gdk_display_get_clipboard (display);
|
||||
g_signal_connect (clipboard, "notify", G_CALLBACK (clipboard_notify), self);
|
||||
init_formats (self, GTK_LIST_BOX (self->clipboard_formats), clipboard);
|
||||
init_info (self, GTK_LABEL (self->clipboard_info), clipboard);
|
||||
|
||||
clipboard = gdk_display_get_primary_clipboard (display);
|
||||
g_signal_connect (clipboard, "notify", G_CALLBACK (primary_notify), self);
|
||||
init_formats (self, GTK_LIST_BOX (self->primary_formats), clipboard);
|
||||
init_info (self, GTK_LABEL (self->primary_info), clipboard);
|
||||
}
|
||||
|
38
gtk/inspector/clipboard.h
Normal file
38
gtk/inspector/clipboard.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Benjamin Otte
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _GTK_INSPECTOR_CLIPBOARD_H_
|
||||
#define _GTK_INSPECTOR_CLIPBOARD_H_
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
#define GTK_TYPE_INSPECTOR_CLIPBOARD (gtk_inspector_clipboard_get_type())
|
||||
#define GTK_INSPECTOR_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_INSPECTOR_CLIPBOARD, GtkInspectorClipboard))
|
||||
#define GTK_INSPECTOR_IS_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_INSPECTOR_CLIPBOARD))
|
||||
|
||||
typedef struct _GtkInspectorClipboard GtkInspectorClipboard;
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GType gtk_inspector_clipboard_get_type (void);
|
||||
|
||||
void gtk_inspector_clipboard_set_display (GtkInspectorClipboard *self,
|
||||
GdkDisplay *display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif // _GTK_INSPECTOR_CLIPBOARD_H_
|
98
gtk/inspector/clipboard.ui
Normal file
98
gtk/inspector/clipboard.ui
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface domain="gtk40">
|
||||
<template class="GtkInspectorClipboard" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="swin">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-start">60</property>
|
||||
<property name="margin-end">60</property>
|
||||
<property name="margin-top">60</property>
|
||||
<property name="margin-bottom">60</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<child>
|
||||
<object class="GtkListBox" id="clipboard_formats">
|
||||
<property name="selection-mode">none</property>
|
||||
<style>
|
||||
<class name="rich-list"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkListBoxRow">
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">40</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Clipboard</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="clipboard_info">
|
||||
<property name="selectable">1</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<child>
|
||||
<object class="GtkListBox" id="primary_formats">
|
||||
<property name="selection-mode">none</property>
|
||||
<style>
|
||||
<class name="rich-list"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkListBoxRow">
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">40</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Primary</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="primary_info">
|
||||
<property name="selectable">1</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
368
gtk/inspector/gtkdataviewer.c
Normal file
368
gtk/inspector/gtkdataviewer.c
Normal file
@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright © 2021 Benjamin Otte
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkdataviewer.h"
|
||||
|
||||
#include "gtkbinlayout.h"
|
||||
#include "gtklabel.h"
|
||||
#include "gtkpicture.h"
|
||||
|
||||
struct _GtkDataViewer
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *contents;
|
||||
GCancellable *cancellable;
|
||||
GError *error;
|
||||
|
||||
enum {
|
||||
NOT_LOADED = 0,
|
||||
LOADING_DONE,
|
||||
LOADING_EXTERNALLY,
|
||||
LOADING_INTERNALLY,
|
||||
LOADING_FAILED
|
||||
} loading;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LOADING,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
enum {
|
||||
LOAD,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkDataViewer, gtk_data_viewer, GTK_TYPE_WIDGET)
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
static void
|
||||
gtk_data_viewer_ensure_loaded (GtkDataViewer *self)
|
||||
{
|
||||
gboolean started_loading;
|
||||
|
||||
if (self->loading != NOT_LOADED)
|
||||
return;
|
||||
|
||||
self->loading = LOADING_EXTERNALLY;
|
||||
self->cancellable = g_cancellable_new ();
|
||||
g_signal_emit (self, signals[LOAD], 0, self->cancellable, &started_loading);
|
||||
|
||||
if (!started_loading)
|
||||
{
|
||||
self->loading = LOADING_FAILED; /* avoid notify::is_loading */
|
||||
gtk_data_viewer_load_error (self, g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "Nothing to load"));
|
||||
}
|
||||
|
||||
g_assert (self->loading != NOT_LOADED);
|
||||
|
||||
if (gtk_data_viewer_is_loading (self))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_realize (GtkWidget *widget)
|
||||
{
|
||||
GtkDataViewer *self = GTK_DATA_VIEWER (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_data_viewer_parent_class)->realize (widget);
|
||||
|
||||
gtk_data_viewer_ensure_loaded (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_unrealize (GtkWidget *widget)
|
||||
{
|
||||
GtkDataViewer *self = GTK_DATA_VIEWER (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_data_viewer_parent_class)->unrealize (widget);
|
||||
|
||||
gtk_data_viewer_reset (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_dispose (GObject *object)
|
||||
{
|
||||
//GtkDataViewer *self = GTK_DATA_VIEWER (object);
|
||||
|
||||
G_OBJECT_CLASS (gtk_data_viewer_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkDataViewer *self = GTK_DATA_VIEWER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_LOADING:
|
||||
g_value_set_boolean (value, gtk_data_viewer_is_loading (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
//GtkDataViewer *self = GTK_DATA_VIEWER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_class_init (GtkDataViewerClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
widget_class->realize = gtk_data_viewer_realize;
|
||||
widget_class->unrealize = gtk_data_viewer_unrealize;
|
||||
|
||||
gobject_class->dispose = gtk_data_viewer_dispose;
|
||||
gobject_class->get_property = gtk_data_viewer_get_property;
|
||||
gobject_class->set_property = gtk_data_viewer_set_property;
|
||||
|
||||
properties[PROP_LOADING] =
|
||||
g_param_spec_boolean ("loading",
|
||||
"Loading",
|
||||
"If the widget is currently loading the data to display",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
signals[LOAD] =
|
||||
g_signal_new ("load",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
g_signal_accumulator_first_wins, NULL,
|
||||
NULL,
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
G_TYPE_CANCELLABLE);
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
gtk_widget_class_set_css_name (widget_class, "frame");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_init (GtkDataViewer *self)
|
||||
{
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_data_viewer_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_DATA_VIEWER, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_data_viewer_is_loading (GtkDataViewer *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_DATA_VIEWER (self), FALSE);
|
||||
|
||||
return self->loading == LOADING_EXTERNALLY ||
|
||||
self->loading == LOADING_INTERNALLY;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_data_viewer_reset (GtkDataViewer *self)
|
||||
{
|
||||
gboolean was_loading;
|
||||
|
||||
g_return_if_fail (GTK_IS_DATA_VIEWER (self));
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
|
||||
was_loading = gtk_data_viewer_is_loading (self);
|
||||
|
||||
g_clear_pointer (&self->contents, gtk_widget_unparent);
|
||||
g_clear_error (&self->error);
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
|
||||
self->loading = NOT_LOADED;
|
||||
|
||||
if (gtk_widget_get_realized (GTK_WIDGET (self)))
|
||||
gtk_data_viewer_ensure_loaded (self);
|
||||
|
||||
if (was_loading != gtk_data_viewer_is_loading (self))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (self));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_data_viewer_load_value (GtkDataViewer *self,
|
||||
const GValue *value)
|
||||
{
|
||||
gboolean was_loading;
|
||||
|
||||
g_return_if_fail (GTK_IS_DATA_VIEWER (self));
|
||||
|
||||
was_loading = gtk_data_viewer_is_loading (self);
|
||||
self->loading = LOADING_DONE;
|
||||
|
||||
g_clear_pointer (&self->contents, gtk_widget_unparent);
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
|
||||
if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_STRING))
|
||||
{
|
||||
self->contents = gtk_label_new (g_value_get_string (value));
|
||||
gtk_label_set_wrap (GTK_LABEL (self->contents), TRUE);
|
||||
gtk_widget_set_parent (self->contents, GTK_WIDGET (self));
|
||||
}
|
||||
else if (g_type_is_a (G_VALUE_TYPE (value), GDK_TYPE_PAINTABLE))
|
||||
{
|
||||
self->contents = gtk_picture_new_for_paintable (g_value_get_object (value));
|
||||
gtk_widget_set_size_request (self->contents, 256, 256);
|
||||
gtk_widget_set_parent (self->contents, GTK_WIDGET (self));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_data_viewer_load_error (self,
|
||||
g_error_new (G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Cannot display objects of type \"%s\"", G_VALUE_TYPE_NAME (value)));
|
||||
}
|
||||
|
||||
if (was_loading)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_data_viewer_load_stream_done (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDataViewer *self = data;
|
||||
GError *error = NULL;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
if (!gdk_content_deserialize_finish (res, &value, &error))
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
gtk_data_viewer_load_error (self, error);
|
||||
else
|
||||
g_clear_error (&error);
|
||||
|
||||
g_object_unref (self);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_data_viewer_load_value (self, &value);
|
||||
g_object_unref (self);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_data_viewer_load_stream (GtkDataViewer *self,
|
||||
GInputStream *stream,
|
||||
const char *mime_type)
|
||||
{
|
||||
GdkContentFormats *formats;
|
||||
const GType *gtypes;
|
||||
gboolean was_loading;
|
||||
|
||||
g_return_if_fail (GTK_IS_DATA_VIEWER (self));
|
||||
g_return_if_fail (G_IS_INPUT_STREAM (stream));
|
||||
g_return_if_fail (mime_type != NULL);
|
||||
|
||||
was_loading = gtk_data_viewer_is_loading (self);
|
||||
self->loading = LOADING_INTERNALLY;
|
||||
if (self->cancellable == NULL)
|
||||
self->cancellable = g_cancellable_new ();
|
||||
|
||||
formats = gdk_content_formats_new (&mime_type, 1);
|
||||
formats = gdk_content_formats_union_deserialize_gtypes (formats);
|
||||
gtypes = gdk_content_formats_get_gtypes (formats, NULL);
|
||||
if (gtypes)
|
||||
{
|
||||
gdk_content_deserialize_async (stream,
|
||||
mime_type,
|
||||
gtypes[0],
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->cancellable,
|
||||
gtk_data_viewer_load_stream_done,
|
||||
g_object_ref (self));
|
||||
|
||||
if (!was_loading)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_data_viewer_load_error (self,
|
||||
g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Cannot display data of type \"%s\"", mime_type));
|
||||
}
|
||||
|
||||
gdk_content_formats_unref (formats);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_data_viewer_load_error (GtkDataViewer *self,
|
||||
GError *error)
|
||||
{
|
||||
gboolean was_loading;
|
||||
|
||||
g_return_if_fail (GTK_IS_DATA_VIEWER (self));
|
||||
|
||||
was_loading = gtk_data_viewer_is_loading (self);
|
||||
self->loading = LOADING_FAILED;
|
||||
|
||||
g_clear_pointer (&self->contents, gtk_widget_unparent);
|
||||
g_clear_error (&self->error);
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
|
||||
self->error = error;
|
||||
self->contents = gtk_label_new (error->message);
|
||||
gtk_widget_add_css_class (self->contents, "error");
|
||||
gtk_widget_set_halign (self->contents, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (self->contents, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_parent (self->contents, GTK_WIDGET (self));
|
||||
|
||||
if (was_loading)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
}
|
||||
|
47
gtk/inspector/gtkdataviewer.h
Normal file
47
gtk/inspector/gtkdataviewer.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © 2021 Benjamin Otte
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DATA_VIEWER_H__
|
||||
#define __GTK_DATA_VIEWER_H__
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_DATA_VIEWER (gtk_data_viewer_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkDataViewer, gtk_data_viewer, GTK, DATA_VIEWER, GtkWidget)
|
||||
|
||||
GtkWidget * gtk_data_viewer_new (void);
|
||||
|
||||
gboolean gtk_data_viewer_is_loading (GtkDataViewer *self);
|
||||
|
||||
void gtk_data_viewer_reset (GtkDataViewer *self);
|
||||
|
||||
void gtk_data_viewer_load_value (GtkDataViewer *self,
|
||||
const GValue *value);
|
||||
void gtk_data_viewer_load_stream (GtkDataViewer *self,
|
||||
GInputStream *stream,
|
||||
const char *mime_type);
|
||||
void gtk_data_viewer_load_error (GtkDataViewer *self,
|
||||
GError *error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_DATA_VIEWER_H__ */
|
@ -27,6 +27,7 @@
|
||||
#include "a11y.h"
|
||||
#include "actions.h"
|
||||
#include "cellrenderergraph.h"
|
||||
#include "clipboard.h"
|
||||
#include "controllers.h"
|
||||
#include "css-editor.h"
|
||||
#include "css-node-tree.h"
|
||||
@ -64,6 +65,7 @@ gtk_inspector_init (void)
|
||||
g_type_ensure (GTK_TYPE_GRAPH_DATA);
|
||||
g_type_ensure (GTK_TYPE_INSPECTOR_A11Y);
|
||||
g_type_ensure (GTK_TYPE_INSPECTOR_ACTIONS);
|
||||
g_type_ensure (GTK_TYPE_INSPECTOR_CLIPBOARD);
|
||||
g_type_ensure (GTK_TYPE_INSPECTOR_CONTROLLERS);
|
||||
g_type_ensure (GTK_TYPE_INSPECTOR_CSS_EDITOR);
|
||||
g_type_ensure (GTK_TYPE_INSPECTOR_CSS_NODE_TREE);
|
||||
|
@ -5,6 +5,7 @@ inspector_sources = files(
|
||||
'actions.c',
|
||||
'baselineoverlay.c',
|
||||
'cellrenderergraph.c',
|
||||
'clipboard.c',
|
||||
'controllers.c',
|
||||
'css-editor.c',
|
||||
'css-node-tree.c',
|
||||
@ -13,6 +14,7 @@ inspector_sources = files(
|
||||
'general.c',
|
||||
'graphdata.c',
|
||||
'gtktreemodelcssnode.c',
|
||||
'gtkdataviewer.c',
|
||||
'highlightoverlay.c',
|
||||
'init.c',
|
||||
'inspect-button.c',
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "init.h"
|
||||
#include "window.h"
|
||||
#include "prop-list.h"
|
||||
#include "clipboard.h"
|
||||
#include "controllers.h"
|
||||
#include "css-editor.h"
|
||||
#include "css-node-tree.h"
|
||||
@ -298,6 +299,7 @@ gtk_inspector_window_constructed (GObject *object)
|
||||
gtk_inspector_css_editor_set_display (GTK_INSPECTOR_CSS_EDITOR (iw->css_editor), iw->inspected_display);
|
||||
gtk_inspector_visual_set_display (GTK_INSPECTOR_VISUAL (iw->visual), iw->inspected_display);
|
||||
gtk_inspector_general_set_display (GTK_INSPECTOR_GENERAL (iw->general), iw->inspected_display);
|
||||
gtk_inspector_clipboard_set_display (GTK_INSPECTOR_CLIPBOARD (iw->clipboard), iw->inspected_display);
|
||||
gtk_inspector_logs_set_display (GTK_INSPECTOR_LOGS (iw->logs), iw->inspected_display);
|
||||
gtk_inspector_css_node_tree_set_display (GTK_INSPECTOR_CSS_NODE_TREE (iw->widget_css_node_tree), iw->inspected_display);
|
||||
}
|
||||
@ -652,6 +654,7 @@ gtk_inspector_window_class_init (GtkInspectorWindowClass *klass)
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, css_editor);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, visual);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, general);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, clipboard);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, logs);
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, go_up_button);
|
||||
|
@ -76,6 +76,7 @@ typedef struct
|
||||
GtkWidget *sidebar_revealer;
|
||||
GtkWidget *css_editor;
|
||||
GtkWidget *visual;
|
||||
GtkWidget *clipboard;
|
||||
GtkWidget *general;
|
||||
GtkWidget *logs;
|
||||
|
||||
|
@ -130,6 +130,14 @@
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">clipboard</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">statistics</property>
|
||||
@ -560,6 +568,16 @@
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">clipboard</property>
|
||||
<property name="title" translatable="yes">Clipboard</property>
|
||||
<property name="child">
|
||||
<object class="GtkInspectorClipboard" id="clipboard">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">statistics</property>
|
||||
|
Loading…
Reference in New Issue
Block a user