X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktexthandle.c;h=bb0f8515353b0be0a0814648007d9d5ef513285d;hb=bb3c56abe2e7916126bd4f8234dee080b5381941;hp=3738d02c0c2735402f5b20800ef4a34a52a7cdd9;hpb=f9d77959a4518699a96b3c85ddc18d0ff01aeac5;p=~andy%2Fgtk diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c index 3738d02c0..bb0f85153 100644 --- a/gtk/gtktexthandle.c +++ b/gtk/gtktexthandle.c @@ -46,6 +46,9 @@ struct _HandleWindow gint dx; gint dy; guint dragged : 1; + guint mode_visible : 1; + guint user_visible : 1; + guint has_point : 1; }; struct _GtkTextHandlePrivate @@ -103,13 +106,22 @@ _gtk_text_handle_draw (GtkTextHandle *handle, 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); + gtk_style_context_save (priv->style_context); gtk_style_context_add_class (priv->style_context, GTK_STYLE_CLASS_CURSOR_HANDLE); if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END) - gtk_style_context_add_class (priv->style_context, - GTK_STYLE_CLASS_BOTTOM); + { + gtk_style_context_add_class (priv->style_context, + GTK_STYLE_CLASS_BOTTOM); + + if (priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR) + gtk_style_context_add_class (priv->style_context, + GTK_STYLE_CLASS_INSERTION_CURSOR); + } else gtk_style_context_add_class (priv->style_context, GTK_STYLE_CLASS_TOP); @@ -122,49 +134,53 @@ _gtk_text_handle_draw (GtkTextHandle *handle, } static void -_gtk_text_handle_update_shape (GtkTextHandle *handle, - GdkWindow *window) +_gtk_text_handle_update_shape (GtkTextHandle *handle, + GdkWindow *window, + GtkTextHandlePosition pos) { GtkTextHandlePrivate *priv; + cairo_rectangle_int_t rect; + cairo_surface_t *surface; + cairo_region_t *region; + cairo_t *cr; 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); else - { - GtkTextHandlePosition pos; - cairo_surface_t *surface; - cairo_region_t *region; - cairo_t *cr; - - if (window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window) - pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START; - else if (window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window) - pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END; - else - return; - - 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); - gdk_window_shape_combine_region (window, region, 0, 0); - - cairo_surface_destroy (surface); - cairo_region_destroy (region); - } + 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) +_gtk_text_handle_create_window (GtkTextHandle *handle, + GtkTextHandlePosition pos) { GtkTextHandlePrivate *priv; GdkRGBA bg = { 0, 0, 0, 0 }; @@ -197,10 +213,10 @@ _gtk_text_handle_create_window (GtkTextHandle *handle) window = gdk_window_new (gtk_widget_get_root_window (priv->parent), &attributes, mask); - gdk_window_set_user_data (window, priv->parent); + gtk_widget_register_window (priv->parent, window); gdk_window_set_background_rgba (window, &bg); - _gtk_text_handle_update_shape (handle, window); + _gtk_text_handle_update_shape (handle, window, pos); return window; } @@ -212,6 +228,7 @@ gtk_text_handle_widget_draw (GtkWidget *widget, { GtkTextHandlePrivate *priv; GtkTextHandlePosition pos; + HandleWindow *handle_window; priv = handle->priv; @@ -225,8 +242,11 @@ gtk_text_handle_widget_draw (GtkWidget *widget, else return FALSE; - _gtk_text_handle_draw (handle, cr, pos); - return TRUE; + handle_window = &priv->windows[pos]; + if (gdk_window_is_visible (handle_window->window)) + _gtk_text_handle_draw (handle, cr, pos); + + return FALSE; } static gboolean @@ -271,6 +291,8 @@ gtk_text_handle_widget_event (GtkWidget *widget, if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_START) y += height; + y += priv->windows[pos].pointing_to.height / 2; + g_signal_emit (handle, signals[HANDLE_DRAGGED], 0, pos, x, y); } @@ -278,13 +300,11 @@ gtk_text_handle_widget_event (GtkWidget *widget, } static void -_gtk_text_handle_update_window (GtkTextHandle *handle, - GtkTextHandlePosition pos) +_gtk_text_handle_update_window_state (GtkTextHandle *handle, + GtkTextHandlePosition pos) { GtkTextHandlePrivate *priv; HandleWindow *handle_window; - gboolean visible; - gint x, y; priv = handle->priv; handle_window = &priv->windows[pos]; @@ -292,29 +312,50 @@ _gtk_text_handle_update_window (GtkTextHandle *handle, if (!handle_window->window) return; - /* Get current state and destroy */ - visible = gdk_window_is_visible (handle_window->window); - - if (visible) + if (handle_window->has_point && + handle_window->mode_visible && handle_window->user_visible) { - gint width; + gint x, y, width, height; - _gtk_text_handle_get_size (handle, &width, NULL); - gdk_window_get_root_coords (handle_window->window, - width / 2, 0, &x, &y); + 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); } + else + gdk_window_hide (handle_window->window); +} + +static void +_gtk_text_handle_update_window (GtkTextHandle *handle, + GtkTextHandlePosition pos, + gboolean recreate) +{ + GtkTextHandlePrivate *priv; + HandleWindow *handle_window; - gdk_window_destroy (handle_window->window); + priv = handle->priv; + handle_window = &priv->windows[pos]; - /* Create new window and apply old state */ - handle_window->window = _gtk_text_handle_create_window (handle); + if (!handle_window->window) + return; - if (visible) + if (recreate) { - gdk_window_show (handle_window->window); - _gtk_text_handle_set_position (handle, pos, - &handle_window->pointing_to); + 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 @@ -323,8 +364,15 @@ _gtk_text_handle_update_windows (GtkTextHandle *handle) GtkTextHandlePrivate *priv = handle->priv; gtk_style_context_invalidate (priv->style_context); - _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START); - _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); + _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); +} + +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); } static void @@ -345,7 +393,7 @@ gtk_text_handle_constructed (GObject *object) object); priv->composited_changed_id = g_signal_connect_swapped (priv->parent, "composited-changed", - G_CALLBACK (_gtk_text_handle_update_windows), + G_CALLBACK (_gtk_text_handle_composited_changed), object); priv->style_updated_id = g_signal_connect_swapped (priv->parent, "style-updated", @@ -364,10 +412,18 @@ gtk_text_handle_finalize (GObject *object) g_object_unref (priv->relative_to); if (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_START].window); + gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); + } if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window) - gdk_window_destroy (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); @@ -522,7 +578,11 @@ _gtk_text_handle_set_relative_to (GtkTextHandle *handle, 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); } @@ -531,9 +591,9 @@ _gtk_text_handle_set_relative_to (GtkTextHandle *handle, { 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_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_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END); priv->realized = TRUE; } else @@ -560,26 +620,34 @@ _gtk_text_handle_set_mode (GtkTextHandle *handle, if (priv->mode == mode) return; + priv->mode = mode; + switch (mode) { case GTK_TEXT_HANDLE_MODE_CURSOR: - /* Only display one handle */ - gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window); - gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); + priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].mode_visible = TRUE; + priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE; break; - case GTK_TEXT_HANDLE_MODE_SELECTION: - /* Display both handles */ - gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); - gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); + case GTK_TEXT_HANDLE_MODE_SELECTION: + priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = TRUE; + priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = TRUE; break; case GTK_TEXT_HANDLE_MODE_NONE: default: - gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window); - gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window); + priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE; + priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = FALSE; break; } - priv->mode = mode; + _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); } GtkTextHandleMode @@ -599,14 +667,15 @@ _gtk_text_handle_set_position (GtkTextHandle *handle, GdkRectangle *rect) { GtkTextHandlePrivate *priv; - gint x, y, width, height; HandleWindow *handle_window; + gboolean size_changed; g_return_if_fail (GTK_IS_TEXT_HANDLE (handle)); priv = handle->priv; pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR, GTK_TEXT_HANDLE_POSITION_SELECTION_START); + handle_window = &priv->windows[pos]; if (!priv->realized) return; @@ -616,21 +685,20 @@ _gtk_text_handle_set_position (GtkTextHandle *handle, 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, - &x, &y); - _gtk_text_handle_get_size (handle, &width, &height); - handle_window = &priv->windows[pos]; - - if (pos == GTK_TEXT_HANDLE_POSITION_CURSOR) - y += rect->height; - else - y -= height; + &handle_window->pointing_to.x, + &handle_window->pointing_to.y); - x -= width / 2; + _gtk_text_handle_update_window_state (handle, pos); - gdk_window_move (handle_window->window, x, y); - handle_window->pointing_to = *rect; + if (size_changed) + _gtk_text_handle_update_shape (handle, handle_window->window, pos); } void @@ -655,18 +723,11 @@ _gtk_text_handle_set_visible (GtkTextHandle *handle, if (!window) return; - if (!visible) - gdk_window_hide (window); - else - { - if (priv->mode == GTK_TEXT_HANDLE_MODE_NONE || - (priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR && - pos != GTK_TEXT_HANDLE_POSITION_CURSOR)) - return; + if (!gdk_window_is_visible (window)) + _gtk_text_handle_update_shape (handle, window, pos); - if (!gdk_window_is_visible (window)) - gdk_window_show (window); - } + priv->windows[pos].user_visible = visible; + _gtk_text_handle_update_window_state (handle, pos); } gboolean