[gtk+/parasite] parasite: Make flashing work better
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/parasite] parasite: Make flashing work better
- Date: Sat, 3 May 2014 05:10:05 +0000 (UTC)
commit 84cacd2a57214b6a323fba8aec09d6e665b4c945
Author: Matthias Clasen <mclasen redhat com>
Date: Sat May 3 01:08:22 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 | 361 +++++++++++++++++++++----------
modules/other/parasite/parasite.h | 6 +-
2 files changed, 254 insertions(+), 113 deletions(-)
---
diff --git a/modules/other/parasite/inspect-button.c b/modules/other/parasite/inspect-button.c
index 5bbcf27..bab556a 100644
--- a/modules/other/parasite/inspect-button.c
+++ b/modules/other/parasite/inspect-button.c
@@ -23,103 +23,247 @@
#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 (event->device, event->time);
- gtk_widget_hide (parasite->highlight_window);
+ GtkAllocation new_allocation;
+ gint x_offset = 0;
+ gint y_offset = 0;
+
+ gtk_widget_get_allocation (widget, &new_allocation);
+
+ if (data->found || !gtk_widget_get_mapped (widget))
+ return;
+
+ /* 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 (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)))
+ {
+ 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 (parasite->selected_window != NULL)
+ 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))
{
- GtkWidget *toplevel = NULL;
- GtkWidget *widget = NULL;
+ /* First, check if the drag is in a valid drop site in
+ * one of our children
+ */
+ if (GTK_IS_CONTAINER (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;
+ }
+ }
+}
- gdk_window_get_user_data (gdk_window_get_toplevel (parasite->selected_window),
- (gpointer *)&toplevel);
+static GtkWidget *
+find_widget_at_pointer (GdkDevice *device)
+{
+ GtkWidget *widget = NULL;
+ GdkWindow *pointer_window;
+ gint x, y;
+ FindWidgetData data;
- gdk_window_get_user_data (parasite->selected_window,
- (gpointer *)&widget);
+ pointer_window = gdk_device_get_window_at_position (device, NULL, NULL);
- if (toplevel)
- parasite_widget_tree_scan (PARASITE_WIDGET_TREE (parasite->widget_tree),
- toplevel);
+ if (pointer_window)
+ {
+ gpointer widget_ptr;
- if (widget)
- parasite_widget_tree_select_widget (PARASITE_WIDGET_TREE (parasite->widget_tree),
- widget);
+ gdk_window_get_user_data (pointer_window, &widget_ptr);
+ widget = widget_ptr;
+ }
+
+ if (widget)
+ {
+ 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
+clear_flash (ParasiteWindow *parasite)
+{
+ 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;
}
}
static void
-on_highlight_window_show (GtkWidget *window,
- ParasiteWindow *parasite)
+start_flash (ParasiteWindow *parasite,
+ GtkWidget *widget)
{
- gtk_widget_set_opacity (parasite->highlight_window, 0.2);
+ 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
-ensure_highlight_window (ParasiteWindow *parasite)
+on_inspect_widget (GtkWidget *button,
+ GdkEvent *event,
+ ParasiteWindow *parasite)
{
- GdkRGBA color;
+ GtkWidget *widget;
- if (parasite->highlight_window != NULL)
+ clear_flash (parasite);
+
+ widget = find_widget_at_pointer (gdk_event_get_device (event));
+
+ if (widget == NULL)
return;
- color.red = 0.0;
- color.green = 0.0;
- color.blue = 1.0;
- color.alpha = 1.0;
+ parasite->selected_widget = widget;
- parasite->highlight_window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_widget_override_background_color (parasite->highlight_window, 0, &color);
+ parasite_widget_tree_scan (PARASITE_WIDGET_TREE (parasite->widget_tree),
+ gtk_widget_get_toplevel (widget));
- g_signal_connect (G_OBJECT (parasite->highlight_window), "show",
- G_CALLBACK (on_highlight_window_show), parasite);
+ parasite_widget_tree_select_widget (PARASITE_WIDGET_TREE (parasite->widget_tree),
+ widget);
}
static void
-on_highlight_widget (GtkWidget *grab_window,
- GdkEventMotion *event,
+on_highlight_widget (GtkWidget *button,
+ GdkEvent *event,
ParasiteWindow *parasite)
{
- GdkDisplay *display;
- GdkDevice *device;
- 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));
- display = gtk_widget_get_display (grab_window);
- device = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
- selected_window = gdk_device_get_window_at_position (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;
}
- parasite->selected_window = selected_window;
+ if (parasite->flash_widget == widget)
+ {
+ /* Already selected */
+ return;
+ }
- gdk_window_get_origin (selected_window, &x, &y);
- height = gdk_window_get_height (selected_window);
- width = gdk_window_get_width (selected_window);
- 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);
+ clear_flash (parasite);
+ start_flash (parasite, widget);
+}
+
+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 TRUE;
}
static void
@@ -130,30 +274,20 @@ on_inspect_button_release (GtkWidget *button,
GdkCursor *cursor;
GdkEventMask events;
+ g_signal_connect (button, "event",
+ G_CALLBACK (property_query_event), parasite);
+
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 (G_OBJECT (parasite->grab_window), "button_release_event",
- G_CALLBACK (on_inspect_widget), parasite);
- g_signal_connect (G_OBJECT (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 (event->device,
- gtk_widget_get_window (parasite->grab_window),
- GDK_OWNERSHIP_WINDOW, FALSE,
- events, cursor, event->time);
+ gtk_widget_get_window (GTK_WIDGET (button)),
+ GDK_OWNERSHIP_NONE, TRUE,
+ events, cursor, GDK_CURRENT_TIME);
g_object_unref (cursor);
+ gtk_grab_add (GTK_WIDGET (button));
}
GtkWidget *
@@ -169,61 +303,70 @@ gtkparasite_inspect_button_new (ParasiteWindow *parasite)
}
static gboolean
+draw_flash (GtkWidget *widget,
+ cairo_t *cr,
+ ParasiteWindow *parasite)
+{
+ GtkAllocation alloc;
+
+ if (parasite->flash_count % 2 == 0)
+ return FALSE;
+
+ if (GTK_IS_WINDOW (widget))
+ {
+ /* 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);
+ }
+ 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 (ParasiteWindow *parasite)
{
+ gtk_widget_queue_draw (parasite->flash_widget);
+
parasite->flash_count++;
- if (parasite->flash_count == 8)
+ 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;
- return FALSE;
- }
- if (parasite->flash_count % 2 == 0)
- {
- if (gtk_widget_get_visible (parasite->highlight_window))
- gtk_widget_hide (parasite->highlight_window);
- else
- gtk_widget_show (parasite->highlight_window);
+ return G_SOURCE_REMOVE;
}
- return TRUE;
+ return G_SOURCE_CONTINUE;
}
void
gtkparasite_flash_widget (ParasiteWindow *parasite,
GtkWidget *widget)
{
- gint x, y, width, height;
- GdkWindow *parent_window;
+ if (parasite->flash_cnx != 0)
+ return;
if (!gtk_widget_get_visible (widget) || !gtk_widget_get_mapped (widget))
return;
- ensure_highlight_window (parasite);
-
- parent_window = gtk_widget_get_parent_window (widget);
- if (parent_window != NULL)
- {
- GtkAllocation allocation;
- gdk_window_get_origin (parent_window, &x, &y);
- gtk_widget_get_allocation (widget, &allocation);
- x += allocation.x;
- y += allocation.y;
-
- width = allocation.width;
- height = allocation.height;
-
- 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);
-
- if (parasite->flash_cnx != 0)
- g_source_remove (parasite->flash_cnx);
-
- 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=2 ts=2: */
diff --git a/modules/other/parasite/parasite.h b/modules/other/parasite/parasite.h
index 6bb751f..3a24b9c 100644
--- a/modules/other/parasite/parasite.h
+++ b/modules/other/parasite/parasite.h
@@ -39,16 +39,14 @@ typedef struct
GtkWidget *action_list;
GtkWidget *python_shell;
- GtkWidget *grab_window;
- GtkWidget *highlight_window;
-
GtkWidget *widget_popup;
GtkWidget *action_popup;
- GdkWindow *selected_window;
+ GtkWidget *selected_widget;
gboolean edit_mode_enabled;
+ GtkWidget *flash_widget;
int flash_count;
int flash_cnx;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]