diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2013-12-23 19:09:10 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2014-01-22 17:10:05 +0100 |
commit | 844c6b8951feeb85bb8d3496401a34dc722edccb (patch) | |
tree | 39c48f96043dd223dabc66583b88ffa4c037a6ca /gtk/gtktexthandle.c | |
parent | db9e1d36d0f1f188c484d6cb25fcd4b8be8b94e5 (diff) | |
download | gtk+-844c6b8951feeb85bb8d3496401a34dc722edccb.tar.gz |
texthandles: Use GtkWindow popovers API
This offers the same behavior, but GDK_WINDOW_TEMP windows aren't used
anymore, involving less translations from/to root coordinates, plus no
glitches in having handles snap to content as windows move.
Diffstat (limited to 'gtk/gtktexthandle.c')
-rw-r--r-- | gtk/gtktexthandle.c | 393 |
1 files changed, 110 insertions, 283 deletions
diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c index b8be99e58a..decf14fb4b 100644 --- a/gtk/gtktexthandle.c +++ b/gtk/gtktexthandle.c @@ -41,7 +41,7 @@ enum { struct _HandleWindow { - GdkWindow *window; + GtkWidget *widget; GdkRectangle pointing_to; gint dx; gint dy; @@ -56,12 +56,6 @@ struct _GtkTextHandlePrivate HandleWindow windows[2]; GtkWidget *parent; GdkWindow *relative_to; - - gulong draw_signal_id; - gulong event_signal_id; - gulong style_updated_id; - gulong composited_changed_id; - guint realized : 1; guint mode : 2; }; @@ -69,6 +63,9 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkTextHandle, _gtk_text_handle, G_TYPE_OBJECT) static guint signals[LAST_SIGNAL] = { 0 }; +static void _gtk_text_handle_update (GtkTextHandle *handle, + GtkTextHandlePosition pos); + static void _gtk_text_handle_get_size (GtkTextHandle *handle, gint *width, @@ -104,10 +101,6 @@ _gtk_text_handle_draw (GtkTextHandle *handle, cairo_save (cr); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba (cr, 0, 0, 0, 0); - cairo_paint (cr); - if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END) cairo_translate (cr, 0, priv->windows[pos].pointing_to.height); @@ -135,92 +128,18 @@ _gtk_text_handle_draw (GtkTextHandle *handle, cairo_restore (cr); } -static void -_gtk_text_handle_update_shape (GtkTextHandle *handle, - GdkWindow *window, - GtkTextHandlePosition pos) +static gint +_text_handle_pos_from_widget (GtkTextHandle *handle, + GtkWidget *widget) { - GtkTextHandlePrivate *priv; - cairo_rectangle_int_t rect; - cairo_surface_t *surface; - cairo_region_t *region; - cairo_t *cr; - - priv = handle->priv; + GtkTextHandlePrivate *priv = handle->priv; - surface = - gdk_window_create_similar_surface (window, - CAIRO_CONTENT_COLOR_ALPHA, - gdk_window_get_width (window), - gdk_window_get_height (window)); - - cr = cairo_create (surface); - _gtk_text_handle_draw (handle, cr, pos); - cairo_destroy (cr); - - region = gdk_cairo_region_create_from_surface (surface); - - if (gtk_widget_is_composited (priv->parent)) - gdk_window_shape_combine_region (window, NULL, 0, 0); + if (widget == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget) + return GTK_TEXT_HANDLE_POSITION_SELECTION_START; + else if (widget == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget) + return GTK_TEXT_HANDLE_POSITION_SELECTION_END; else - gdk_window_shape_combine_region (window, region, 0, 0); - - cairo_region_get_extents (region, &rect); - cairo_region_destroy (region); - - /* Preserve x/width, but extend input shape - * vertically to all window height */ - rect.y = 0; - rect.height = gdk_window_get_height (window); - region = cairo_region_create_rectangle (&rect); - - gdk_window_input_shape_combine_region (window, region, 0, 0); - - cairo_surface_destroy (surface); - cairo_region_destroy (region); -} - -static GdkWindow * -_gtk_text_handle_create_window (GtkTextHandle *handle, - GtkTextHandlePosition pos) -{ - GtkTextHandlePrivate *priv; - GdkRGBA bg = { 0, 0, 0, 0 }; - GdkWindowAttr attributes; - GdkWindow *window; - GdkVisual *visual; - gint mask; - - priv = handle->priv; - - attributes.x = 0; - attributes.y = 0; - _gtk_text_handle_get_size (handle, &attributes.width, &attributes.height); - attributes.window_type = GDK_WINDOW_TEMP; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.event_mask = (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON1_MOTION_MASK); - - mask = GDK_WA_X | GDK_WA_Y; - - visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (priv->parent)); - - if (visual) - { - attributes.visual = visual; - mask |= GDK_WA_VISUAL; - } - - window = gdk_window_new (gtk_widget_get_root_window (priv->parent), - &attributes, mask); - gtk_widget_register_window (priv->parent, window); - gdk_window_set_background_rgba (window, &bg); - - _gtk_text_handle_update_shape (handle, window, pos); - - return window; + return -1; } static gboolean @@ -228,27 +147,15 @@ gtk_text_handle_widget_draw (GtkWidget *widget, cairo_t *cr, GtkTextHandle *handle) { - GtkTextHandlePrivate *priv; - GtkTextHandlePosition pos; - HandleWindow *handle_window; - - priv = handle->priv; + gint pos; - if (!priv->realized) - return FALSE; + pos = _text_handle_pos_from_widget (handle, widget); - if (gtk_cairo_should_draw_window (cr, priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window)) - pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START; - else if (gtk_cairo_should_draw_window (cr, priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window)) - pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END; - else + if (pos < 0) return FALSE; - handle_window = &priv->windows[pos]; - if (gdk_window_is_visible (handle_window->window)) - _gtk_text_handle_draw (handle, cr, pos); - - return FALSE; + _gtk_text_handle_draw (handle, cr, pos); + return TRUE; } static gboolean @@ -257,15 +164,12 @@ gtk_text_handle_widget_event (GtkWidget *widget, GtkTextHandle *handle) { GtkTextHandlePrivate *priv; - GtkTextHandlePosition pos; + gint pos; priv = handle->priv; + pos = _text_handle_pos_from_widget (handle, widget); - if (event->any.window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window) - pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START; - else if (event->any.window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window) - pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END; - else + if (pos < 0) return FALSE; if (event->type == GDK_BUTTON_PRESS) @@ -277,24 +181,24 @@ gtk_text_handle_widget_event (GtkWidget *widget, else if (event->type == GDK_BUTTON_RELEASE) { g_signal_emit (handle, signals[DRAG_FINISHED], 0, pos); - priv->windows[pos].dx = priv->windows[pos].dy = 0; priv->windows[pos].dragged = FALSE; } - else if (event->type == GDK_MOTION_NOTIFY && priv->windows[pos].dragged) + else if (event->type == GDK_MOTION_NOTIFY && + event->motion.state & GDK_BUTTON1_MASK && + priv->windows[pos].dragged) { gint x, y, width, height; _gtk_text_handle_get_size (handle, &width, &height); - gdk_window_get_origin (priv->relative_to, &x, &y); + x = event->motion.x - priv->windows[pos].dx + (width / 2); + y = event->motion.y - priv->windows[pos].dy; - x = event->motion.x_root - priv->windows[pos].dx + (width / 2) - x; - y = event->motion.y_root - priv->windows[pos].dy - y; - - if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_START) + if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR) y += height; y += priv->windows[pos].pointing_to.height / 2; + gtk_widget_translate_coordinates (widget, priv->parent, x, y, &x, &y); g_signal_emit (handle, signals[HANDLE_DRAGGED], 0, pos, x, y); } @@ -302,44 +206,49 @@ gtk_text_handle_widget_event (GtkWidget *widget, } static void -_gtk_text_handle_update_window_state (GtkTextHandle *handle, - GtkTextHandlePosition pos) +gtk_text_handle_widget_style_updated (GtkTextHandle *handle) +{ + _gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); + _gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); +} + +static GtkWidget * +_gtk_text_handle_ensure_widget (GtkTextHandle *handle, + GtkTextHandlePosition pos) { GtkTextHandlePrivate *priv; - HandleWindow *handle_window; priv = handle->priv; - handle_window = &priv->windows[pos]; - - if (!handle_window->window) - return; - if (handle_window->has_point && - handle_window->mode_visible && handle_window->user_visible) + if (!priv->windows[pos].widget) { - gint x, y, width, height; - - x = handle_window->pointing_to.x; - y = handle_window->pointing_to.y; - _gtk_text_handle_get_size (handle, &width, &height); - - if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR) - y -= height; - - height += handle_window->pointing_to.height; - x -= width / 2; - - gdk_window_move_resize (handle_window->window, x, y, width, height); - gdk_window_show (handle_window->window); + GtkWidget *widget, *window; + + widget = gtk_event_box_new (); + gtk_widget_set_events (widget, + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK); + + g_signal_connect (widget, "draw", + G_CALLBACK (gtk_text_handle_widget_draw), handle); + g_signal_connect (widget, "event", + G_CALLBACK (gtk_text_handle_widget_event), handle); + g_signal_connect (widget, "style-updated", + G_CALLBACK (gtk_text_handle_widget_style_updated), + handle); + + priv->windows[pos].widget = widget; + window = gtk_widget_get_ancestor (priv->parent, GTK_TYPE_WINDOW); + gtk_window_add_popover (GTK_WINDOW (window), widget); } - else - gdk_window_hide (handle_window->window); + + return priv->windows[pos].widget; } static void -_gtk_text_handle_update_window (GtkTextHandle *handle, - GtkTextHandlePosition pos, - gboolean recreate) +_gtk_text_handle_update (GtkTextHandle *handle, + GtkTextHandlePosition pos) { GtkTextHandlePrivate *priv; HandleWindow *handle_window; @@ -347,57 +256,47 @@ _gtk_text_handle_update_window (GtkTextHandle *handle, priv = handle->priv; handle_window = &priv->windows[pos]; - if (!handle_window->window) + if (!priv->parent || !gtk_widget_is_drawable (priv->parent)) return; - if (recreate) + if (handle_window->has_point && + handle_window->mode_visible && handle_window->user_visible) { - gtk_widget_unregister_window (priv->parent, handle_window->window); - gdk_window_destroy (handle_window->window); - handle_window->window = _gtk_text_handle_create_window (handle, pos); - } - - _gtk_text_handle_update_window_state (handle, pos); -} - -static void -_gtk_text_handle_update_windows (GtkTextHandle *handle) -{ - _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, FALSE); - _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, FALSE); -} + cairo_rectangle_int_t rect; + GtkPositionType handle_pos; + gint width, height; + GtkWidget *window; + + _gtk_text_handle_ensure_widget (handle, pos); + rect.x = handle_window->pointing_to.x; + rect.y = handle_window->pointing_to.y; + _gtk_text_handle_get_size (handle, &width, &height); -static void -_gtk_text_handle_composited_changed (GtkTextHandle *handle) -{ - _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, TRUE); - _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, TRUE); -} + window = gtk_widget_get_parent (handle_window->widget); + gtk_widget_translate_coordinates (priv->parent, window, + rect.x, rect.y, &rect.x, &rect.y); -static void -gtk_text_handle_constructed (GObject *object) -{ - GtkTextHandlePrivate *priv; + if (pos == GTK_TEXT_HANDLE_POSITION_CURSOR) + handle_pos = GTK_POS_BOTTOM; + else + { + handle_pos = GTK_POS_TOP; + rect.y += handle_window->pointing_to.height; + } - priv = GTK_TEXT_HANDLE (object)->priv; - g_assert (priv->parent != NULL); - - priv->draw_signal_id = - g_signal_connect (priv->parent, "draw", - G_CALLBACK (gtk_text_handle_widget_draw), - object); - priv->event_signal_id = - g_signal_connect (priv->parent, "event", - G_CALLBACK (gtk_text_handle_widget_event), - object); - priv->composited_changed_id = - g_signal_connect_swapped (priv->parent, "composited-changed", - G_CALLBACK (_gtk_text_handle_composited_changed), - object); - priv->style_updated_id = - g_signal_connect_swapped (priv->parent, "style-updated", - G_CALLBACK (_gtk_text_handle_update_windows), - object); + height += handle_window->pointing_to.height; + rect.width = width; + rect.height = 0; + rect.x -= rect.width / 2; + + gtk_widget_set_size_request (handle_window->widget, width, height); + gtk_widget_show (handle_window->widget); + gtk_window_set_popover_position (GTK_WINDOW (window), + handle_window->widget, + handle_pos, &rect); + } + else if (handle_window->widget) + gtk_widget_hide (handle_window->widget); } static void @@ -410,31 +309,11 @@ gtk_text_handle_finalize (GObject *object) if (priv->relative_to) g_object_unref (priv->relative_to); - if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window) - { - gtk_widget_unregister_window (priv->parent, - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); - gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); - } - - if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window) - { - gtk_widget_unregister_window (priv->parent, - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); - gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); - } - - if (g_signal_handler_is_connected (priv->parent, priv->draw_signal_id)) - g_signal_handler_disconnect (priv->parent, priv->draw_signal_id); - - if (g_signal_handler_is_connected (priv->parent, priv->event_signal_id)) - g_signal_handler_disconnect (priv->parent, priv->event_signal_id); - - if (g_signal_handler_is_connected (priv->parent, priv->composited_changed_id)) - g_signal_handler_disconnect (priv->parent, priv->composited_changed_id); + if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget) + gtk_widget_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget); - if (g_signal_handler_is_connected (priv->parent, priv->style_updated_id)) - g_signal_handler_disconnect (priv->parent, priv->style_updated_id); + if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget) + gtk_widget_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget); G_OBJECT_CLASS (_gtk_text_handle_parent_class)->finalize (object); } @@ -493,7 +372,6 @@ _gtk_text_handle_class_init (GtkTextHandleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->constructed = gtk_text_handle_constructed; object_class->finalize = gtk_text_handle_finalize; object_class->set_property = gtk_text_handle_set_property; object_class->get_property = gtk_text_handle_get_property; @@ -560,33 +438,12 @@ _gtk_text_handle_set_relative_to (GtkTextHandle *handle, priv = handle->priv; if (priv->relative_to) - { - gtk_widget_unregister_window (priv->parent, - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); - gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); - gtk_widget_unregister_window (priv->parent, - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); - gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); - g_object_unref (priv->relative_to); - } + g_object_unref (priv->relative_to); if (window) - { - priv->relative_to = g_object_ref (window); - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window = - _gtk_text_handle_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window = - _gtk_text_handle_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); - priv->realized = TRUE; - } - else - { - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window = NULL; - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window = NULL; - priv->relative_to = NULL; - priv->realized = FALSE; - } + g_object_ref (window); + priv->relative_to = window; g_object_notify (G_OBJECT (handle), "relative-to"); } @@ -622,15 +479,8 @@ _gtk_text_handle_set_mode (GtkTextHandle *handle, break; } - _gtk_text_handle_update_shape (handle, - priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window, - GTK_TEXT_HANDLE_POSITION_CURSOR); - _gtk_text_handle_update_shape (handle, - priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window, - GTK_TEXT_HANDLE_POSITION_SELECTION_START); - - _gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); - _gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); + _gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); + _gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); } GtkTextHandleMode @@ -651,7 +501,6 @@ _gtk_text_handle_set_position (GtkTextHandle *handle, { GtkTextHandlePrivate *priv; HandleWindow *handle_window; - gboolean size_changed; g_return_if_fail (GTK_IS_TEXT_HANDLE (handle)); @@ -660,28 +509,16 @@ _gtk_text_handle_set_position (GtkTextHandle *handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); handle_window = &priv->windows[pos]; - if (!priv->realized) - return; - if (priv->mode == GTK_TEXT_HANDLE_MODE_NONE || (priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR && pos != GTK_TEXT_HANDLE_POSITION_CURSOR)) return; - size_changed = (rect->width != handle_window->pointing_to.width || - rect->height != handle_window->pointing_to.height); - handle_window->pointing_to = *rect; handle_window->has_point = TRUE; - gdk_window_get_root_coords (priv->relative_to, - rect->x, rect->y, - &handle_window->pointing_to.x, - &handle_window->pointing_to.y); - - _gtk_text_handle_update_window_state (handle, pos); - if (size_changed) - _gtk_text_handle_update_shape (handle, handle_window->window, pos); + if (gtk_widget_is_visible (priv->parent)) + _gtk_text_handle_update (handle, pos); } void @@ -690,7 +527,6 @@ _gtk_text_handle_set_visible (GtkTextHandle *handle, gboolean visible) { GtkTextHandlePrivate *priv; - GdkWindow *window; g_return_if_fail (GTK_IS_TEXT_HANDLE (handle)); @@ -698,19 +534,10 @@ _gtk_text_handle_set_visible (GtkTextHandle *handle, pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR, GTK_TEXT_HANDLE_POSITION_SELECTION_START); - if (!priv->realized) - return; - - window = priv->windows[pos].window; - - if (!window) - return; - - if (!gdk_window_is_visible (window)) - _gtk_text_handle_update_shape (handle, window, pos); - priv->windows[pos].user_visible = visible; - _gtk_text_handle_update_window_state (handle, pos); + + if (gtk_widget_is_visible (priv->parent)) + _gtk_text_handle_update (handle, pos); } gboolean |