[gtk+/parasite2] parasite: Make flashing work better
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/parasite2] parasite: Make flashing work better
- Date: Sat, 3 May 2014 20:44:30 +0000 (UTC)
commit 58c5d4ab637c276fd03b3f2a11b0b5d6668dc2b3
Author: Matthias Clasen <mclasen redhat com>
Date: Sat May 3 16:43:04 2014 -0400
parasite: Make flashing work better
The positioning of the highlight window was not reliable; instead
just use a after-handler for the draw signal, in the same way that
drag highlights are drawn by GTK+ itself.
And copy the code for grabbing a widget via pointer from testgtk;
that code is known to work.
modules/other/parasite/inspect-button.c | 404 ++++++++++++++++++++-----------
modules/other/parasite/parasite.h | 6 +-
modules/other/parasite/prop-list.c | 11 +-
modules/other/parasite/prop-list.h | 2 +-
modules/other/parasite/window.c | 4 +-
5 files changed, 280 insertions(+), 147 deletions(-)
---
diff --git a/modules/other/parasite/inspect-button.c b/modules/other/parasite/inspect-button.c
index b875ef6..225f4c2 100644
--- a/modules/other/parasite/inspect-button.c
+++ b/modules/other/parasite/inspect-button.c
@@ -20,223 +20,351 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
#include "parasite.h"
#include "widget-tree.h"
+typedef struct
+{
+ gint x;
+ gint y;
+ gboolean found;
+ gboolean first;
+ GtkWidget *res_widget;
+} FindWidgetData;
+
static void
-on_inspect_widget(GtkWidget *grab_window,
- GdkEventButton *event,
- ParasiteWindow *parasite)
+find_widget (GtkWidget *widget,
+ FindWidgetData *data)
{
- gdk_device_ungrab (gtk_get_current_event_device (), event->time);
- gtk_widget_hide(parasite->highlight_window);
+ GtkAllocation new_allocation;
+ gint x_offset = 0;
+ gint y_offset = 0;
- if (parasite->selected_window != NULL)
- {
- GtkWidget *toplevel = NULL;
- GtkWidget *widget = NULL;
+ gtk_widget_get_allocation (widget, &new_allocation);
- gdk_window_get_user_data(
- gdk_window_get_toplevel(parasite->selected_window),
- (gpointer*)&toplevel);
+ if (data->found || !gtk_widget_get_mapped (widget))
+ return;
- gdk_window_get_user_data (parasite->selected_window, (gpointer*)&widget);
+ /* Note that in the following code, we only count the
+ * position as being inside a WINDOW widget if it is inside
+ * widget->window; points that are outside of widget->window
+ * but within the allocation are not counted. This is consistent
+ * with the way we highlight drag targets.
+ */
+ if (gtk_widget_get_has_window (widget))
+ {
+ new_allocation.x = 0;
+ new_allocation.y = 0;
+ }
- if (toplevel)
+ if (gtk_widget_get_parent (widget) && !data->first)
+ {
+ GdkWindow *window = gtk_widget_get_window (widget);
+ while (window != gtk_widget_get_window (gtk_widget_get_parent (widget)))
{
- parasite_widget_tree_scan (PARASITE_WIDGET_TREE (parasite->widget_tree),
- toplevel);
+ gint tx, ty, twidth, theight;
+
+ twidth = gdk_window_get_width (window);
+ theight = gdk_window_get_height (window);
+
+ if (new_allocation.x < 0)
+ {
+ new_allocation.width += new_allocation.x;
+ new_allocation.x = 0;
+ }
+ if (new_allocation.y < 0)
+ {
+ new_allocation.height += new_allocation.y;
+ new_allocation.y = 0;
+ }
+ if (new_allocation.x + new_allocation.width > twidth)
+ new_allocation.width = twidth - new_allocation.x;
+ if (new_allocation.y + new_allocation.height > theight)
+ new_allocation.height = theight - new_allocation.y;
+
+ gdk_window_get_position (window, &tx, &ty);
+ new_allocation.x += tx;
+ x_offset += tx;
+ new_allocation.y += ty;
+ y_offset += ty;
+
+ window = gdk_window_get_parent (window);
}
+ }
- if (widget)
+ if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
+ (data->x < new_allocation.x + new_allocation.width) &&
+ (data->y < new_allocation.y + new_allocation.height))
+ {
+ /* First, check if the drag is in a valid drop site in
+ * one of our children
+ */
+ if (GTK_IS_CONTAINER (widget))
{
- parasite_widget_tree_select_object (PARASITE_WIDGET_TREE (parasite->widget_tree),
- G_OBJECT (widget));
+ FindWidgetData new_data = *data;
+
+ new_data.x -= x_offset;
+ new_data.y -= y_offset;
+ new_data.found = FALSE;
+ new_data.first = FALSE;
+
+ gtk_container_forall (GTK_CONTAINER (widget),
+ (GtkCallback)find_widget,
+ &new_data);
+
+ data->found = new_data.found;
+ if (data->found)
+ data->res_widget = new_data.res_widget;
+ }
+
+ /* If not, and this widget is registered as a drop site, check to
+ * emit "drag_motion" to check if we are actually in
+ * a drop site.
+ */
+ if (!data->found)
+ {
+ data->found = TRUE;
+ data->res_widget = widget;
}
}
}
-static void
-on_highlight_window_show (GtkWidget *window, ParasiteWindow *parasite)
+static GtkWidget *
+find_widget_at_pointer (GdkDevice *device)
{
- if (gtk_widget_is_composited (parasite->window))
+ GtkWidget *widget = NULL;
+ GdkWindow *pointer_window;
+ gint x, y;
+ FindWidgetData data;
+
+ pointer_window = gdk_device_get_window_at_position (device, NULL, NULL);
+
+ if (pointer_window)
{
- gtk_widget_set_opacity (parasite->highlight_window, 0.2);
+ gpointer widget_ptr;
+
+ gdk_window_get_user_data (pointer_window, &widget_ptr);
+ widget = widget_ptr;
}
- else
+
+ if (widget)
{
- /*
- * TODO: Do something different when there's no compositing manager.
- * Draw a border or something.
- */
+ gdk_window_get_device_position (gtk_widget_get_window (widget),
+ device, &x, &y, NULL);
+
+ data.x = x;
+ data.y = y;
+ data.found = FALSE;
+ data.first = TRUE;
+
+ find_widget (widget, &data);
+ if (data.found)
+ return data.res_widget;
+
+ return widget;
}
+
+ return NULL;
}
+static gboolean draw_flash (GtkWidget *widget,
+ cairo_t *cr,
+ ParasiteWindow *parasite);
+
static void
-ensure_highlight_window (ParasiteWindow *parasite)
+clear_flash (ParasiteWindow *parasite)
{
- GdkRGBA color;
+ if (parasite->flash_widget)
+ {
+ gtk_widget_queue_draw (parasite->flash_widget);
+ g_signal_handlers_disconnect_by_func (parasite->flash_widget, draw_flash, parasite);
+ parasite->flash_widget = NULL;
+ }
+}
- if (parasite->highlight_window != NULL)
+static void
+start_flash (ParasiteWindow *parasite,
+ GtkWidget *widget)
+{
+ parasite->flash_count = 1;
+ parasite->flash_widget = widget;
+ g_signal_connect_after (widget, "draw", G_CALLBACK (draw_flash), parasite);
+ gtk_widget_queue_draw (widget);
+}
+
+static void
+on_inspect_widget (GtkWidget *button,
+ GdkEvent *event,
+ ParasiteWindow *parasite)
+{
+ GtkWidget *widget;
+
+ clear_flash (parasite);
+
+ widget = find_widget_at_pointer (gdk_event_get_device (event));
+
+ if (widget == NULL)
return;
- color.red = 0;
- color.green = 0;
- color.blue = 65535;
- color.alpha = 1;
+ parasite->selected_widget = widget;
- parasite->highlight_window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_widget_override_background_color (parasite->highlight_window,
- GTK_STATE_NORMAL,
- &color);
+ parasite_widget_tree_scan (PARASITE_WIDGET_TREE (parasite->widget_tree),
+ gtk_widget_get_toplevel (widget));
- g_signal_connect (parasite->highlight_window, "show", G_CALLBACK (on_highlight_window_show), parasite);
+ parasite_widget_tree_select_object (PARASITE_WIDGET_TREE (parasite->widget_tree),
+ G_OBJECT (widget));
}
static void
-on_highlight_widget(GtkWidget *grab_window,
- GdkEventMotion *event,
- ParasiteWindow *parasite)
+on_highlight_widget (GtkWidget *button,
+ GdkEvent *event,
+ ParasiteWindow *parasite)
{
- GdkWindow *selected_window;
- gint x, y, width, height;
-
- ensure_highlight_window (parasite);
+ GtkWidget *widget;
- gtk_widget_hide (parasite->highlight_window);
+ widget = find_widget_at_pointer (gdk_event_get_device (event));
- selected_window = gdk_device_get_window_at_position (gtk_get_current_event_device (),
- NULL,
- NULL);
- if (selected_window == NULL)
+ if (widget == NULL)
{
/* This window isn't in-process. Ignore it. */
- parasite->selected_window = NULL;
return;
}
- if (gdk_window_get_toplevel(selected_window) == gtk_widget_get_window(parasite->window))
+ if (gtk_widget_get_toplevel (widget) == parasite->window)
{
- /* Don't hilight things in the parasite window */
- parasite->selected_window = NULL;
- return;
+ /* Don't hilight things in the parasite window */
+ return;
}
- parasite->selected_window = selected_window;
+ if (parasite->flash_widget == widget)
+ {
+ /* Already selected */
+ return;
+ }
- gdk_window_get_origin (selected_window, &x, &y);
- width = gdk_window_get_width (selected_window);
- height = gdk_window_get_height (selected_window);
+ clear_flash (parasite);
+ start_flash (parasite, widget);
+}
- gtk_window_move (GTK_WINDOW (parasite->highlight_window), x, y);
- gtk_window_resize (GTK_WINDOW (parasite->highlight_window), width, height);
- gtk_widget_show (parasite->highlight_window);
+static gboolean
+property_query_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
+{
+ if (event->type == GDK_BUTTON_RELEASE)
+ {
+ g_signal_handlers_disconnect_by_func (widget, property_query_event, data);
+ gtk_grab_remove (widget);
+ gdk_device_ungrab (gdk_event_get_device (event), GDK_CURRENT_TIME);
+ on_inspect_widget (widget, event, data);
+ }
+ else if (event->type == GDK_MOTION_NOTIFY)
+ {
+ on_highlight_widget (widget, event, data);
+ }
+
+ return FALSE;
}
static void
-on_inspect_button_release (GtkWidget *button,
- GdkEventButton *event,
- ParasiteWindow *parasite)
+on_inspect (GtkWidget *button,
+ ParasiteWindow *parasite)
{
+ GdkDisplay *display;
+ GdkDevice *device;
GdkCursor *cursor;
- GdkEventMask events;
- events = GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
-
- if (parasite->grab_window == NULL)
- {
- parasite->grab_window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_widget_show(parasite->grab_window);
- gtk_window_resize (GTK_WINDOW (parasite->grab_window), 1, 1);
- gtk_window_move (GTK_WINDOW (parasite->grab_window), -100, -100);
- gtk_widget_add_events (parasite->grab_window, events);
-
- g_signal_connect (parasite->grab_window, "button_release_event", G_CALLBACK (on_inspect_widget),
parasite);
- g_signal_connect (parasite->grab_window, "motion_notify_event", G_CALLBACK(on_highlight_widget),
parasite);
- }
-
- cursor = gdk_cursor_new_for_display (gtk_widget_get_display (button), GDK_CROSSHAIR);
- gdk_device_grab (gtk_get_current_event_device (),
- gtk_widget_get_window (parasite->grab_window),
- GDK_OWNERSHIP_WINDOW,
- FALSE,
- events,
- cursor,
- event->time);
+ g_signal_connect (button, "event",
+ G_CALLBACK (property_query_event), parasite);
+
+ display = gtk_widget_get_display (button);
+ cursor = gdk_cursor_new_for_display (display, GDK_CROSSHAIR);
+ device = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
+ gdk_device_grab (device,
+ gtk_widget_get_window (GTK_WIDGET (button)),
+ GDK_OWNERSHIP_NONE, TRUE,
+ GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
+ cursor, GDK_CURRENT_TIME);
g_object_unref (cursor);
+ gtk_grab_add (GTK_WIDGET (button));
}
-
GtkWidget *
-gtkparasite_inspect_button_new(ParasiteWindow *parasite)
+gtkparasite_inspect_button_new (ParasiteWindow *parasite)
{
- GtkWidget *button;
+ GtkWidget *button;
- button = gtk_button_new_from_icon_name ("find", GTK_ICON_SIZE_BUTTON);
- gtk_widget_set_tooltip_text (button, "Inspect");
- g_signal_connect(G_OBJECT(button), "button_release_event",
- G_CALLBACK(on_inspect_button_release), parasite);
+ button = gtk_button_new_with_label ("Inspect");
+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (on_inspect), parasite);
- return button;
+ return button;
}
static gboolean
-on_flash_timeout(ParasiteWindow *parasite)
+draw_flash (GtkWidget *widget,
+ cairo_t *cr,
+ ParasiteWindow *parasite)
{
- parasite->flash_count++;
+ GtkAllocation alloc;
- if (parasite->flash_count == 8)
+ if (parasite->flash_count % 2 == 0)
+ return FALSE;
+
+ if (GTK_IS_WINDOW (widget))
{
- parasite->flash_cnx = 0;
- return FALSE;
+ /* We don't want to draw the drag highlight around the
+ * CSD window decorations
+ */
+ gtk_widget_get_allocation (gtk_bin_get_child (GTK_BIN (widget)), &alloc);
}
-
- if (parasite->flash_count % 2 == 0)
+ else
{
- if (gtk_widget_get_visible(parasite->highlight_window))
- gtk_widget_hide(parasite->highlight_window);
- else
- gtk_widget_show(parasite->highlight_window);
+ alloc.x = 0;
+ alloc.y = 0;
+ alloc.width = gtk_widget_get_allocated_width (widget);
+ alloc.height = gtk_widget_get_allocated_height (widget);
}
- return TRUE;
+ 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;
}
-void
-gtkparasite_flash_widget(ParasiteWindow *parasite, GtkWidget *widget)
+static gboolean
+on_flash_timeout (ParasiteWindow *parasite)
{
- gint x, y, width, height;
- GdkWindow *parent_window;
+ gtk_widget_queue_draw (parasite->flash_widget);
- if (!gtk_widget_get_visible(widget) || !gtk_widget_get_mapped(widget))
- return;
+ parasite->flash_count++;
- ensure_highlight_window(parasite);
+ if (parasite->flash_count == 6)
+ {
+ g_signal_handlers_disconnect_by_func (parasite->flash_widget, draw_flash, parasite);
+ parasite->flash_widget = NULL;
+ parasite->flash_cnx = 0;
- parent_window = gtk_widget_get_parent_window(widget);
- if (parent_window != NULL) {
- GtkAllocation alloc;
- gtk_widget_get_allocation(widget, &alloc);
-
- gdk_window_get_origin(parent_window, &x, &y);
- x += alloc.x;
- y += alloc.y;
+ return G_SOURCE_REMOVE;
+ }
- width = alloc.width;
- height = alloc.height;
+ return G_SOURCE_CONTINUE;
+}
- gtk_window_move(GTK_WINDOW(parasite->highlight_window), x, y);
- gtk_window_resize(GTK_WINDOW(parasite->highlight_window), width, height);
- gtk_widget_show(parasite->highlight_window);
+void
+gtkparasite_flash_widget (ParasiteWindow *parasite,
+ GtkWidget *widget)
+{
+ if (parasite->flash_cnx != 0)
+ return;
- if (parasite->flash_cnx != 0)
- g_source_remove(parasite->flash_cnx);
+ if (!gtk_widget_get_visible (widget) || !gtk_widget_get_mapped (widget))
+ return;
- parasite->flash_count = 0;
- parasite->flash_cnx = g_timeout_add(150, (GSourceFunc)on_flash_timeout,
- parasite);
- }
+ start_flash (parasite, widget);
+ parasite->flash_cnx = g_timeout_add (150, (GSourceFunc) on_flash_timeout, parasite);
}
-// vim: set et sw=4 ts=4:
+/* vim: set et sw=2 ts=2: */
diff --git a/modules/other/parasite/parasite.h b/modules/other/parasite/parasite.h
index cc69bf2..140ad4e 100644
--- a/modules/other/parasite/parasite.h
+++ b/modules/other/parasite/parasite.h
@@ -43,12 +43,10 @@ typedef struct
GtkWidget *widget_css_editor;
GtkWidget *oh;
- GtkWidget *grab_window;
- GtkWidget *highlight_window;
-
GtkWidget *widget_popup;
- GdkWindow *selected_window;
+ GtkWidget *selected_widget;
+ GtkWidget *flash_widget;
int flash_count;
int flash_cnx;
diff --git a/modules/other/parasite/prop-list.c b/modules/other/parasite/prop-list.c
index 8d042f1..b5370d8 100644
--- a/modules/other/parasite/prop-list.c
+++ b/modules/other/parasite/prop-list.c
@@ -338,7 +338,7 @@ parasite_proplist_new (GtkWidget *widget_tree,
NULL);
}
-void
+gboolean
parasite_proplist_set_object (ParasitePropList* pl, GObject *object)
{
GtkTreeIter iter;
@@ -347,6 +347,9 @@ parasite_proplist_set_object (ParasitePropList* pl, GObject *object)
guint i;
GList *l;
+ if (pl->priv->object == object)
+ return FALSE;
+
pl->priv->object = object;
for (l = pl->priv->signal_cnxs; l != NULL; l = l->next)
@@ -369,11 +372,11 @@ parasite_proplist_set_object (ParasitePropList* pl, GObject *object)
GtkWidget *parent;
if (!GTK_IS_WIDGET (object))
- return;
+ return TRUE;
parent = gtk_widget_get_parent (GTK_WIDGET (object));
if (!parent)
- return;
+ return TRUE;
props = gtk_container_class_list_child_properties (G_OBJECT_GET_CLASS (parent), &num_properties);
}
@@ -409,6 +412,8 @@ parasite_proplist_set_object (ParasitePropList* pl, GObject *object)
g_free (signal_name);
}
+
+ return TRUE;
}
diff --git a/modules/other/parasite/prop-list.h b/modules/other/parasite/prop-list.h
index efc75b5..2343988 100644
--- a/modules/other/parasite/prop-list.h
+++ b/modules/other/parasite/prop-list.h
@@ -51,7 +51,7 @@ G_BEGIN_DECLS
GType parasite_proplist_get_type (void);
GtkWidget *parasite_proplist_new (GtkWidget *widget_tree,
gboolean child_properties);
-void parasite_proplist_set_object (ParasitePropList *proplist,
+gboolean parasite_proplist_set_object (ParasitePropList *proplist,
GObject *object);
G_END_DECLS
diff --git a/modules/other/parasite/window.c b/modules/other/parasite/window.c
index fd7dc87..8edcc4b 100644
--- a/modules/other/parasite/window.c
+++ b/modules/other/parasite/window.c
@@ -42,7 +42,9 @@ on_widget_tree_selection_changed (ParasiteWidgetTree *widget_tree,
if (selected != NULL)
{
- parasite_proplist_set_object (PARASITE_PROPLIST (parasite->prop_list), selected);
+ if (!parasite_proplist_set_object (PARASITE_PROPLIST (parasite->prop_list), selected))
+ return;
+
parasite_proplist_set_object (PARASITE_PROPLIST (parasite->child_prop_list), selected);
parasite_objecthierarchy_set_object (PARASITE_OBJECTHIERARCHY (parasite->oh), selected);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]