inspector: Introduce so-called "overlays"

Overlays are drawings that get rendered on top of the inspected window.

The only overlay in existence so far is the highlight overlay, which is
used to highlight widgets and replaces the "draw" signal handler used
previously.
This commit is contained in:
Benjamin Otte 2018-04-04 12:38:09 +02:00
parent cbf26fbd02
commit de990614d7
9 changed files with 361 additions and 77 deletions

View File

@ -0,0 +1,122 @@
/*
* Copyright © 2018 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 "highlightoverlay.h"
#include "gtkintl.h"
#include "gtkwidget.h"
struct _GtkHighlightOverlay
{
GtkInspectorOverlay parent_instance;
GtkWidget *widget;
GdkRGBA color;
};
struct _GtkHighlightOverlayClass
{
GtkInspectorOverlayClass parent_class;
};
G_DEFINE_TYPE (GtkHighlightOverlay, gtk_highlight_overlay, GTK_TYPE_INSPECTOR_OVERLAY)
static void
gtk_highlight_overlay_snapshot (GtkInspectorOverlay *overlay,
GtkSnapshot *snapshot,
GtkWidget *widget)
{
GtkHighlightOverlay *self = GTK_HIGHLIGHT_OVERLAY (overlay);
graphene_rect_t bounds;
if (!gtk_widget_compute_bounds (self->widget, widget, &bounds))
return;
gtk_snapshot_append_color (snapshot,
&self->color,
&bounds,
"InspectorHighlight");
}
static void
gtk_highlight_overlay_queue_draw (GtkInspectorOverlay *overlay)
{
GtkHighlightOverlay *self = GTK_HIGHLIGHT_OVERLAY (overlay);
gtk_widget_queue_draw (self->widget);
}
static void
gtk_highlight_overlay_dispose (GObject *object)
{
GtkHighlightOverlay *self = GTK_HIGHLIGHT_OVERLAY (object);
g_clear_object (&self->widget);
G_OBJECT_CLASS (gtk_highlight_overlay_parent_class)->dispose (object);
}
static void
gtk_highlight_overlay_class_init (GtkHighlightOverlayClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkInspectorOverlayClass *overlay_class = GTK_INSPECTOR_OVERLAY_CLASS (klass);
overlay_class->snapshot = gtk_highlight_overlay_snapshot;
overlay_class->queue_draw = gtk_highlight_overlay_queue_draw;
gobject_class->dispose = gtk_highlight_overlay_dispose;
}
static void
gtk_highlight_overlay_init (GtkHighlightOverlay *self)
{
self->color = (GdkRGBA) { 0.0, 0.0, 1.0, 0.2 };
}
GtkInspectorOverlay *
gtk_highlight_overlay_new (GtkWidget *widget)
{
GtkHighlightOverlay *self;
self = g_object_new (GTK_TYPE_HIGHLIGHT_OVERLAY, NULL);
self->widget = g_object_ref (widget);
return GTK_INSPECTOR_OVERLAY (self);
}
GtkWidget *
gtk_highlight_overlay_get_widget (GtkHighlightOverlay *self)
{
return self->widget;
}
void
gtk_highlight_overlay_set_color (GtkHighlightOverlay *self,
const GdkRGBA *color)
{
if (gdk_rgba_equal (&self->color, color))
return;
self->color = *color;
gtk_inspector_overlay_queue_draw (GTK_INSPECTOR_OVERLAY (self));
}

View File

@ -0,0 +1,38 @@
/*
* Copyright © 2018 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_HIGHLIGHT_OVERLAY_H__
#define __GTK_HIGHLIGHT_OVERLAY_H__
#include "inspectoroverlay.h"
G_BEGIN_DECLS
#define GTK_TYPE_HIGHLIGHT_OVERLAY (gtk_highlight_overlay_get_type ())
G_DECLARE_FINAL_TYPE (GtkHighlightOverlay, gtk_highlight_overlay, GTK, HIGHLIGHT_OVERLAY, GtkInspectorOverlay)
GtkInspectorOverlay * gtk_highlight_overlay_new (GtkWidget *widget);
GtkWidget * gtk_highlight_overlay_get_widget (GtkHighlightOverlay *self);
void gtk_highlight_overlay_set_color (GtkHighlightOverlay *self,
const GdkRGBA *color);
G_END_DECLS
#endif /* __GTK_HIGHLIGHT_OVERLAY_H__ */

View File

@ -25,6 +25,8 @@
#include <glib/gi18n-lib.h>
#include "window.h"
#include "highlightoverlay.h"
#include "object-tree.h"
#include "gtkstack.h"
@ -124,19 +126,13 @@ find_widget_at_pointer (GdkDevice *device)
return widget;
}
static gboolean draw_flash (GtkWidget *widget,
cairo_t *cr,
GtkInspectorWindow *iw);
static void
clear_flash (GtkInspectorWindow *iw)
{
if (iw->flash_widget)
if (iw->flash_overlay)
{
gtk_widget_queue_draw (iw->flash_widget);
g_signal_handlers_disconnect_by_func (iw->flash_widget, draw_flash, iw);
g_signal_handlers_disconnect_by_func (iw->flash_widget, clear_flash, iw);
iw->flash_widget = NULL;
gtk_inspector_window_remove_overlay (iw, iw->flash_overlay);
g_clear_object (&iw->flash_overlay);
}
}
@ -147,10 +143,8 @@ start_flash (GtkInspectorWindow *iw,
clear_flash (iw);
iw->flash_count = 1;
iw->flash_widget = widget;
g_signal_connect_after (widget, "draw", G_CALLBACK (draw_flash), iw);
g_signal_connect_swapped (widget, "unmap", G_CALLBACK (clear_flash), iw);
gtk_widget_queue_draw (widget);
iw->flash_overlay = gtk_highlight_overlay_new (widget);
gtk_inspector_window_add_overlay (iw, iw->flash_overlay);
}
static void
@ -206,7 +200,8 @@ on_highlight_widget (GtkWidget *button,
return;
}
if (iw->flash_widget == widget)
if (iw->flash_overlay &&
gtk_highlight_overlay_get_widget (GTK_HIGHLIGHT_OVERLAY (iw->flash_overlay)) == widget)
{
/* Already selected */
return;
@ -332,56 +327,20 @@ gtk_inspector_on_inspect (GtkWidget *button,
deemphasize_window (GTK_WIDGET (iw));
}
static gboolean
draw_flash (GtkWidget *widget,
cairo_t *cr,
GtkInspectorWindow *iw)
{
GtkAllocation alloc;
if (iw && iw->flash_count % 2 == 0)
return FALSE;
if (GTK_IS_WINDOW (widget))
{
GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
/* We don't want to draw the drag highlight around the
* CSD window decorations
*/
if (child == NULL)
return FALSE;
gtk_widget_get_allocation (child, &alloc);
}
else
{
alloc.x = 0;
alloc.y = 0;
alloc.width = gtk_widget_get_allocated_width (widget);
alloc.height = gtk_widget_get_allocated_height (widget);
}
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.2);
cairo_rectangle (cr,
alloc.x + 0.5, alloc.y + 0.5,
alloc.width - 1, alloc.height - 1);
cairo_fill (cr);
return FALSE;
}
static gboolean
on_flash_timeout (GtkInspectorWindow *iw)
{
gtk_widget_queue_draw (iw->flash_widget);
iw->flash_count++;
gtk_highlight_overlay_set_color (GTK_HIGHLIGHT_OVERLAY (iw->flash_overlay),
&(GdkRGBA) {
0.0, 0.0, 1.0,
(iw && iw->flash_count % 2 == 0) ? 0.0 : 0.2
});
if (iw->flash_count == 6)
{
g_signal_handlers_disconnect_by_func (iw->flash_widget, draw_flash, iw);
g_signal_handlers_disconnect_by_func (iw->flash_widget, clear_flash, iw);
iw->flash_widget = NULL;
clear_flash (iw);
iw->flash_cnx = 0;
return G_SOURCE_REMOVE;
@ -407,21 +366,6 @@ gtk_inspector_flash_widget (GtkInspectorWindow *iw,
iw->flash_cnx = g_timeout_add (150, (GSourceFunc) on_flash_timeout, iw);
}
void
gtk_inspector_start_highlight (GtkWidget *widget)
{
g_signal_connect_after (widget, "draw", G_CALLBACK (draw_flash), NULL);
gtk_widget_queue_draw (widget);
}
void
gtk_inspector_stop_highlight (GtkWidget *widget)
{
g_signal_handlers_disconnect_by_func (widget, draw_flash, NULL);
g_signal_handlers_disconnect_by_func (widget, clear_flash, NULL);
gtk_widget_queue_draw (widget);
}
void
gtk_inspector_window_select_widget_under_pointer (GtkInspectorWindow *iw)
{

View File

@ -0,0 +1,71 @@
/*
* Copyright © 2018 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 "inspectoroverlay.h"
#include "gtkintl.h"
typedef struct _GtkInspectorOverlayPrivate GtkInspectorOverlayPrivate;
struct _GtkInspectorOverlayPrivate
{
};
G_DEFINE_ABSTRACT_TYPE (GtkInspectorOverlay, gtk_inspector_overlay, G_TYPE_OBJECT)
static void
gtk_inspector_overlay_default_snapshot (GtkInspectorOverlay *self,
GtkSnapshot *snapshot,
GtkWidget *widget)
{
}
static void
gtk_inspector_overlay_default_queue_draw (GtkInspectorOverlay *self)
{
}
static void
gtk_inspector_overlay_class_init (GtkInspectorOverlayClass *class)
{
class->snapshot = gtk_inspector_overlay_default_snapshot;
class->queue_draw = gtk_inspector_overlay_default_queue_draw;
}
static void
gtk_inspector_overlay_init (GtkInspectorOverlay *self)
{
}
void
gtk_inspector_overlay_snapshot (GtkInspectorOverlay *self,
GtkSnapshot *snapshot,
GtkWidget *widget)
{
GTK_INSPECTOR_OVERLAY_GET_CLASS (self)->snapshot (self, snapshot, widget);
}
void
gtk_inspector_overlay_queue_draw (GtkInspectorOverlay *self)
{
GTK_INSPECTOR_OVERLAY_GET_CLASS (self)->queue_draw (self);
}

View File

@ -0,0 +1,48 @@
/*
* Copyright © 2018 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_INSPECTOR_OVERLAY_H__
#define __GTK_INSPECTOR_OVERLAY_H__
#include <gtk/gtksnapshot.h>
G_BEGIN_DECLS
#define GTK_TYPE_INSPECTOR_OVERLAY (gtk_inspector_overlay_get_type ())
G_DECLARE_DERIVABLE_TYPE (GtkInspectorOverlay, gtk_inspector_overlay, GTK, INSPECTOR_OVERLAY, GObject)
struct _GtkInspectorOverlayClass
{
GObjectClass parent_class;
void (* snapshot) (GtkInspectorOverlay *self,
GtkSnapshot *snapshot,
GtkWidget *widget);
void (* queue_draw) (GtkInspectorOverlay *self);
};
void gtk_inspector_overlay_snapshot (GtkInspectorOverlay *self,
GtkSnapshot *snapshot,
GtkWidget *widget);
void gtk_inspector_overlay_queue_draw (GtkInspectorOverlay *self);
G_END_DECLS
#endif /* __GTK_INSPECTOR_OVERLAY_H__ */

View File

@ -11,8 +11,10 @@ inspector_sources = files(
'gtkstackcombo.c',
'gtktreemodelcssnode.c',
'gtktreemodelrendernode.c',
'highlightoverlay.c',
'init.c',
'inspect-button.c',
'inspectoroverlay.c',
'logs.c',
'magnifier.c',
'menu.c',

View File

@ -19,6 +19,8 @@
#include <glib/gi18n-lib.h>
#include "size-groups.h"
#include "highlightoverlay.h"
#include "window.h"
#include "gtkcomboboxtext.h"
@ -32,6 +34,7 @@
typedef struct {
GtkListBoxRow parent;
GtkInspectorOverlay *highlight;
GtkWidget *widget;
} SizeGroupRow;
@ -139,10 +142,18 @@ size_group_state_flags_changed (GtkWidget *widget,
state = gtk_widget_get_state_flags (widget);
if ((state & GTK_STATE_FLAG_PRELIGHT) != (old_state & GTK_STATE_FLAG_PRELIGHT))
{
GtkInspectorWindow *iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_toplevel (widget));
if (state & GTK_STATE_FLAG_PRELIGHT)
gtk_inspector_start_highlight (row->widget);
{
row->highlight = gtk_highlight_overlay_new (row->widget);
gtk_inspector_window_add_overlay (iw, row->highlight);
}
else
gtk_inspector_stop_highlight (row->widget);
{
gtk_inspector_window_remove_overlay (iw, row->highlight);
g_clear_object (&row->highlight);
}
}
}

View File

@ -355,6 +355,30 @@ gtk_inspector_window_new (void)
NULL));
}
void
gtk_inspector_window_add_overlay (GtkInspectorWindow *iw,
GtkInspectorOverlay *overlay)
{
iw->overlays = g_list_prepend (iw->overlays, g_object_ref (overlay));
gtk_inspector_overlay_queue_draw (overlay);
}
void
gtk_inspector_window_remove_overlay (GtkInspectorWindow *iw,
GtkInspectorOverlay *overlay)
{
GList *item;
item = g_list_find (iw->overlays, overlay);
if (item == NULL)
return;
gtk_inspector_overlay_queue_draw (overlay);
iw->overlays = g_list_delete_link (iw->overlays, item);
}
void
gtk_inspector_window_rescan (GtkWidget *widget)
{
@ -393,6 +417,23 @@ gtk_inspector_prepare_render (GtkWidget *widget,
region,
node);
if (iw->overlays)
{
GtkSnapshot *snapshot;
GList *l;
snapshot = gtk_snapshot_new (FALSE, "Inspector Overlay");
gtk_snapshot_append_node (snapshot, node);
for (l = iw->overlays; l; l = l->next)
{
gtk_inspector_overlay_snapshot (l->data, snapshot, widget);
}
gsk_render_node_unref (node);
node = gtk_snapshot_free_to_node (snapshot);
}
return node;
}

View File

@ -26,6 +26,8 @@
#include <gtk/gtkwindow.h>
#include "inspectoroverlay.h"
#define GTK_TYPE_INSPECTOR_WINDOW (gtk_inspector_window_get_type())
#define GTK_INSPECTOR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_INSPECTOR_WINDOW, GtkInspectorWindow))
#define GTK_INSPECTOR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_INSPECTOR_WINDOW, GtkInspectorWindowClass))
@ -72,15 +74,17 @@ typedef struct
GtkWidget *invisible;
GtkWidget *selected_widget;
GtkWidget *flash_widget;
GList *extra_pages;
gboolean grabbed;
GtkInspectorOverlay *flash_overlay;
gint flash_count;
gint flash_cnx;
GList *overlays;
} GtkInspectorWindow;
typedef struct
@ -96,12 +100,15 @@ GtkWidget *gtk_inspector_window_new (void);
void gtk_inspector_flash_widget (GtkInspectorWindow *iw,
GtkWidget *widget);
void gtk_inspector_start_highlight (GtkWidget *widget);
void gtk_inspector_stop_highlight (GtkWidget *widget);
void gtk_inspector_on_inspect (GtkWidget *widget,
GtkInspectorWindow *iw);
void gtk_inspector_window_add_overlay (GtkInspectorWindow *iw,
GtkInspectorOverlay *overlay);
void gtk_inspector_window_remove_overlay (GtkInspectorWindow *iw,
GtkInspectorOverlay *overlay);
void gtk_inspector_window_select_widget_under_pointer (GtkInspectorWindow *iw);
void gtk_inspector_window_rescan (GtkWidget *iw);