[gtk+/composite-templates] Add GtkTextHandle
- From: Juan Pablo Ugarte <jpu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/composite-templates] Add GtkTextHandle
- Date: Fri, 14 Sep 2012 21:25:08 +0000 (UTC)
commit 5ae516bd8a0871581725922dc57aa7cbcd0087b9
Author: Carlos Garnacho <carlos lanedo com>
Date: Wed Jul 11 15:51:43 2012 +0200
Add GtkTextHandle
This is a helper object to allow text widgets to implement
text selection on touch devices. It allows for both cursor
placement and text selection, displaying draggable handles
on/around the cursor and selection bound positions.
Currently, this is private to GTK+, and only available to
GtkEntry and GtkTextView.
docs/reference/gtk/gtk3-sections.txt | 2 +
gtk/Makefile.am | 7 +-
gtk/gtkmarshalers.list | 1 +
gtk/gtkprivate.h | 1 +
gtk/gtkstylecontext.h | 16 +
gtk/gtktexthandle.c | 667 ++++++++++++++++++++++++++++++++++
gtk/gtktexthandleprivate.h | 90 +++++
gtk/gtkwidget.c | 13 +
8 files changed, 795 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 6649d9f..1f2f897 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -5767,6 +5767,8 @@ GTK_STYLE_CLASS_LINKED
GTK_STYLE_CLASS_ARROW
GTK_STYLE_CLASS_OSD
GTK_STYLE_CLASS_LEVEL_BAR
+GTK_STYLE_CLASS_CURSOR_HANDLE
+GTK_STYLE_CLASS_INVERTED_CURSOR_HANDLE
GTK_STYLE_REGION_COLUMN
GTK_STYLE_REGION_COLUMN_HEADER
GTK_STYLE_REGION_ROW
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 18979e2..f8bb13f 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -394,8 +394,9 @@ gtk_appchooser_impl_c_sources = \
gtkappchooseronlinepk.c
endif
-gtk_private_type_h_sources = \
- gtkcsstypesprivate.h
+gtk_private_type_h_sources = \
+ gtkcsstypesprivate.h \
+ gtktexthandleprivate.h
# GTK+ header files that don't get installed
@@ -525,6 +526,7 @@ gtk_private_h_sources = \
gtktextbtree.h \
gtktextbufferserialize.h \
gtktextchildprivate.h \
+ gtktexthandleprivate.h \
gtktextiterprivate.h \
gtktextmarkprivate.h \
gtktextsegment.h \
@@ -821,6 +823,7 @@ gtk_base_c_sources = \
gtktextbufferserialize.c \
gtktextchild.c \
gtktextdisplay.c \
+ gtktexthandle.c \
gtktextiter.c \
gtktextlayout.c \
gtktextmark.c \
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index e104d31..14d0519 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -69,6 +69,7 @@ VOID:ENUM,FLOAT
VOID:ENUM,FLOAT,BOOLEAN
VOID:ENUM,INT
VOID:ENUM,INT,BOOLEAN
+VOID:ENUM,INT,INT
VOID:ENUM,BOXED
VOID:ENUM,STRING
VOID:FLAGS
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 9114bd0..746103d 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -29,6 +29,7 @@
#include <gdk/gdk.h>
#include "gtkcsstypesprivate.h"
+#include "gtktexthandleprivate.h"
G_BEGIN_DECLS
diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h
index 456b5a1..05a49b4 100644
--- a/gtk/gtkstylecontext.h
+++ b/gtk/gtkstylecontext.h
@@ -701,6 +701,22 @@ struct _GtkStyleContextClass
*/
#define GTK_STYLE_CLASS_LEVEL_BAR "level-bar"
+/**
+ * GTK_STYLE_CLASS_CURSOR_HANDLE:
+ *
+ * A CSS class used when rendering a drag handle for
+ * text selection.
+ */
+#define GTK_STYLE_CLASS_CURSOR_HANDLE "cursor-handle"
+
+/**
+ * GTK_STYLE_CLASS_INVERTED_CURSOR_HANDLE:
+ *
+ * A CSS class used when rendering a drag handle for
+ * text selection.
+ */
+#define GTK_STYLE_CLASS_INVERTED_CURSOR_HANDLE "inverted-cursor-handle"
+
/* Predefined set of widget regions */
/**
diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c
new file mode 100644
index 0000000..3b298f3
--- /dev/null
+++ b/gtk/gtktexthandle.c
@@ -0,0 +1,667 @@
+/* GTK - The GIMP Toolkit
+ * Copyright  2012 Carlos Garnacho <carlosg gnome org>
+ *
+ * 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 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/>.
+ */
+
+#include "config.h"
+#include "gtkprivatetypebuiltins.h"
+#include "gtktexthandleprivate.h"
+#include "gtkmarshalers.h"
+#include "gtkprivate.h"
+#include "gtkintl.h"
+
+#include <gtk/gtk.h>
+
+typedef struct _GtkTextHandlePrivate GtkTextHandlePrivate;
+typedef struct _HandleWindow HandleWindow;
+
+enum {
+ HANDLE_DRAGGED,
+ DRAG_FINISHED,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_PARENT,
+ PROP_RELATIVE_TO
+};
+
+struct _HandleWindow
+{
+ GdkWindow *window;
+ GdkRectangle pointing_to;
+ gint dx;
+ gint dy;
+ guint dragged : 1;
+};
+
+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;
+};
+
+G_DEFINE_TYPE (GtkTextHandle, _gtk_text_handle, G_TYPE_OBJECT)
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+_gtk_text_handle_get_size (GtkTextHandle *handle,
+ gint *width,
+ gint *height)
+{
+ GtkTextHandlePrivate *priv;
+ gint w, h;
+
+ priv = handle->priv;
+
+ gtk_widget_style_get (priv->parent,
+ "text-handle-width", &w,
+ "text-handle-height", &h,
+ NULL);
+ if (width)
+ *width = w;
+
+ if (height)
+ *height = h;
+}
+
+static void
+_gtk_text_handle_draw (GtkTextHandle *handle,
+ cairo_t *cr,
+ GtkTextHandlePosition pos)
+{
+ GtkTextHandlePrivate *priv;
+ GtkStyleContext *context;
+ gint width, height;
+
+ priv = handle->priv;
+ cairo_save (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0);
+ cairo_paint (cr);
+
+ context = gtk_widget_get_style_context (priv->parent);
+ gtk_style_context_save (context);
+
+ if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_CURSOR_HANDLE);
+ else
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_INVERTED_CURSOR_HANDLE);
+
+ _gtk_text_handle_get_size (handle, &width, &height);
+ gtk_render_slider (context, cr, 0, 0, width, height,
+ GTK_ORIENTATION_HORIZONTAL);
+
+ gtk_style_context_restore (context);
+ cairo_restore (cr);
+}
+
+static void
+_gtk_text_handle_update_shape (GtkTextHandle *handle,
+ GdkWindow *window)
+{
+ GtkTextHandlePrivate *priv;
+
+ priv = handle->priv;
+
+ 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);
+ }
+}
+
+static GdkWindow *
+_gtk_text_handle_create_window (GtkTextHandle *handle)
+{
+ 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 (NULL, &attributes, mask);
+ gdk_window_set_user_data (window, priv->parent);
+ gdk_window_set_background_rgba (window, &bg);
+
+ _gtk_text_handle_update_shape (handle, window);
+
+ return window;
+}
+
+static gboolean
+gtk_text_handle_widget_draw (GtkWidget *widget,
+ cairo_t *cr,
+ GtkTextHandle *handle)
+{
+ GtkTextHandlePrivate *priv;
+ GtkTextHandlePosition pos;
+
+ priv = handle->priv;
+
+ if (!priv->realized)
+ return FALSE;
+
+ 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
+ return FALSE;
+
+ _gtk_text_handle_draw (handle, cr, pos);
+ return TRUE;
+}
+
+static gboolean
+gtk_text_handle_widget_event (GtkWidget *widget,
+ GdkEvent *event,
+ GtkTextHandle *handle)
+{
+ GtkTextHandlePrivate *priv;
+ GtkTextHandlePosition pos;
+
+ priv = handle->priv;
+
+ 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
+ return FALSE;
+
+ if (event->type == GDK_BUTTON_PRESS)
+ {
+ priv->windows[pos].dx = event->button.x;
+ priv->windows[pos].dy = event->button.y;
+ priv->windows[pos].dragged = TRUE;
+ }
+ 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)
+ {
+ 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_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)
+ y += height;
+
+ g_signal_emit (handle, signals[HANDLE_DRAGGED], 0, pos, x, y);
+ }
+
+ return TRUE;
+}
+
+static void
+_gtk_text_handle_update_window (GtkTextHandle *handle,
+ GtkTextHandlePosition pos)
+{
+ GtkTextHandlePrivate *priv;
+ HandleWindow *handle_window;
+ gboolean visible;
+ gint x, y;
+
+ priv = handle->priv;
+ handle_window = &priv->windows[pos];
+
+ if (!handle_window->window)
+ return;
+
+ /* Get current state and destroy */
+ visible = gdk_window_is_visible (handle_window->window);
+
+ if (visible)
+ {
+ gint width;
+
+ _gtk_text_handle_get_size (handle, &width, NULL);
+ gdk_window_get_root_coords (handle_window->window,
+ width / 2, 0, &x, &y);
+ }
+
+ gdk_window_destroy (handle_window->window);
+
+ /* Create new window and apply old state */
+ handle_window->window = _gtk_text_handle_create_window (handle);
+
+ if (visible)
+ {
+ gdk_window_show (handle_window->window);
+ _gtk_text_handle_set_position (handle, pos,
+ &handle_window->pointing_to);
+ }
+}
+
+static void
+_gtk_text_handle_update_windows (GtkTextHandle *handle)
+{
+ _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
+ _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
+}
+
+static void
+gtk_text_handle_constructed (GObject *object)
+{
+ GtkTextHandlePrivate *priv;
+
+ 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_update_windows),
+ object);
+ priv->style_updated_id =
+ g_signal_connect_swapped (priv->parent, "style-updated",
+ G_CALLBACK (_gtk_text_handle_update_windows),
+ object);
+}
+
+static void
+gtk_text_handle_finalize (GObject *object)
+{
+ GtkTextHandlePrivate *priv;
+
+ priv = GTK_TEXT_HANDLE (object)->priv;
+
+ if (priv->relative_to)
+ 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);
+
+ if (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 (g_signal_handler_is_connected (priv->parent, priv->style_updated_id))
+ g_signal_handler_disconnect (priv->parent, priv->style_updated_id);
+
+ G_OBJECT_CLASS (_gtk_text_handle_parent_class)->finalize (object);
+}
+
+static void
+gtk_text_handle_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkTextHandlePrivate *priv;
+ GtkTextHandle *handle;
+
+ handle = GTK_TEXT_HANDLE (object);
+ priv = handle->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PARENT:
+ priv->parent = g_value_get_object (value);
+ break;
+ case PROP_RELATIVE_TO:
+ _gtk_text_handle_set_relative_to (handle,
+ g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_text_handle_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkTextHandlePrivate *priv;
+
+ priv = GTK_TEXT_HANDLE (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PARENT:
+ g_value_set_object (value, priv->parent);
+ break;
+ case PROP_RELATIVE_TO:
+ g_value_set_object (value, priv->relative_to);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+_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;
+
+ signals[HANDLE_DRAGGED] =
+ g_signal_new (I_("handle-dragged"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkTextHandleClass, handle_dragged),
+ NULL, NULL,
+ _gtk_marshal_VOID__ENUM_INT_INT,
+ G_TYPE_NONE, 3,
+ GTK_TYPE_TEXT_HANDLE_POSITION,
+ G_TYPE_INT, G_TYPE_INT);
+ signals[DRAG_FINISHED] =
+ g_signal_new (I_("drag-finished"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST, 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_TEXT_HANDLE_POSITION);
+
+ g_object_class_install_property (object_class,
+ PROP_PARENT,
+ g_param_spec_object ("parent",
+ P_("Parent widget"),
+ P_("Parent widget"),
+ GTK_TYPE_WIDGET,
+ GTK_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_RELATIVE_TO,
+ g_param_spec_object ("relative-to",
+ P_("Window"),
+ P_("Window the coordinates are based upon"),
+ GDK_TYPE_WINDOW,
+ GTK_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (GtkTextHandlePrivate));
+}
+
+static void
+_gtk_text_handle_init (GtkTextHandle *handle)
+{
+ handle->priv = G_TYPE_INSTANCE_GET_PRIVATE (handle,
+ GTK_TYPE_TEXT_HANDLE,
+ GtkTextHandlePrivate);
+}
+
+GtkTextHandle *
+_gtk_text_handle_new (GtkWidget *parent)
+{
+ return g_object_new (GTK_TYPE_TEXT_HANDLE,
+ "parent", parent,
+ NULL);
+}
+
+void
+_gtk_text_handle_set_relative_to (GtkTextHandle *handle,
+ GdkWindow *window)
+{
+ GtkTextHandlePrivate *priv;
+
+ g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
+ g_return_if_fail (!window || GDK_IS_WINDOW (window));
+
+ priv = handle->priv;
+
+ if (priv->relative_to)
+ {
+ gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
+ gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
+ 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);
+ priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window =
+ _gtk_text_handle_create_window (handle);
+ 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_notify (G_OBJECT (handle), "relative-to");
+}
+
+void
+_gtk_text_handle_set_mode (GtkTextHandle *handle,
+ GtkTextHandleMode mode)
+{
+ GtkTextHandlePrivate *priv;
+
+ g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
+
+ priv = handle->priv;
+
+ if (priv->mode == mode)
+ return;
+
+ 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);
+ 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);
+ 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);
+ break;
+ }
+
+ priv->mode = mode;
+}
+
+GtkTextHandleMode
+_gtk_text_handle_get_mode (GtkTextHandle *handle)
+{
+ GtkTextHandlePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_TEXT_HANDLE (handle), GTK_TEXT_HANDLE_MODE_NONE);
+
+ priv = handle->priv;
+ return priv->mode;
+}
+
+void
+_gtk_text_handle_set_position (GtkTextHandle *handle,
+ GtkTextHandlePosition pos,
+ GdkRectangle *rect)
+{
+ GtkTextHandlePrivate *priv;
+ gint x, y, width, height;
+ HandleWindow *handle_window;
+
+ 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);
+
+ 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;
+
+ 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;
+
+ x -= width / 2;
+
+ gdk_window_move (handle_window->window, x, y);
+ handle_window->pointing_to = *rect;
+}
+
+void
+_gtk_text_handle_set_visible (GtkTextHandle *handle,
+ GtkTextHandlePosition pos,
+ gboolean visible)
+{
+ GtkTextHandlePrivate *priv;
+ GdkWindow *window;
+
+ 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);
+
+ if (!priv->realized)
+ return;
+
+ window = priv->windows[pos].window;
+
+ 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))
+ gdk_window_show (window);
+ }
+}
+
+gboolean
+_gtk_text_handle_get_is_dragged (GtkTextHandle *handle,
+ GtkTextHandlePosition pos)
+{
+ GtkTextHandlePrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_TEXT_HANDLE (handle), FALSE);
+
+ priv = handle->priv;
+ pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR,
+ GTK_TEXT_HANDLE_POSITION_SELECTION_START);
+
+ return priv->windows[pos].dragged;
+}
diff --git a/gtk/gtktexthandleprivate.h b/gtk/gtktexthandleprivate.h
new file mode 100644
index 0000000..220ee68
--- /dev/null
+++ b/gtk/gtktexthandleprivate.h
@@ -0,0 +1,90 @@
+/* GTK - The GIMP Toolkit
+ * Copyright  2012 Carlos Garnacho <carlosg gnome org>
+ *
+ * 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 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/>.
+ */
+
+#ifndef __GTK_TEXT_HANDLE_PRIVATE_H__
+#define __GTK_TEXT_HANDLE_PRIVATE_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_TEXT_HANDLE (_gtk_text_handle_get_type ())
+#define GTK_TEXT_HANDLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_TEXT_HANDLE, GtkTextHandle))
+#define GTK_TEXT_HANDLE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_TEXT_HANDLE, GtkTextHandleClass))
+#define GTK_IS_TEXT_HANDLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_TEXT_HANDLE))
+#define GTK_IS_TEXT_HANDLE_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_TEXT_HANDLE))
+#define GTK_TEXT_HANDLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_TEXT_HANDLE, GtkTextHandleClass))
+
+typedef struct _GtkTextHandle GtkTextHandle;
+typedef struct _GtkTextHandleClass GtkTextHandleClass;
+
+typedef enum
+{
+ GTK_TEXT_HANDLE_POSITION_CURSOR,
+ GTK_TEXT_HANDLE_POSITION_SELECTION_START,
+ GTK_TEXT_HANDLE_POSITION_SELECTION_END = GTK_TEXT_HANDLE_POSITION_CURSOR
+} GtkTextHandlePosition;
+
+typedef enum
+{
+ GTK_TEXT_HANDLE_MODE_NONE,
+ GTK_TEXT_HANDLE_MODE_CURSOR,
+ GTK_TEXT_HANDLE_MODE_SELECTION
+} GtkTextHandleMode;
+
+struct _GtkTextHandle
+{
+ GObject parent_instance;
+ gpointer priv;
+};
+
+struct _GtkTextHandleClass
+{
+ GObjectClass parent_class;
+
+ void (* handle_dragged) (GtkTextHandle *handle,
+ GtkTextHandlePosition pos,
+ gint x,
+ gint y);
+ void (* drag_finished) (GtkTextHandle *handle,
+ GtkTextHandlePosition pos);
+};
+
+GType _gtk_text_handle_get_type (void) G_GNUC_CONST;
+
+GtkTextHandle * _gtk_text_handle_new (GtkWidget *parent);
+
+void _gtk_text_handle_set_mode (GtkTextHandle *handle,
+ GtkTextHandleMode mode);
+GtkTextHandleMode
+ _gtk_text_handle_get_mode (GtkTextHandle *handle);
+void _gtk_text_handle_set_position (GtkTextHandle *handle,
+ GtkTextHandlePosition pos,
+ GdkRectangle *rect);
+void _gtk_text_handle_set_visible (GtkTextHandle *handle,
+ GtkTextHandlePosition pos,
+ gboolean visible);
+
+void _gtk_text_handle_set_relative_to (GtkTextHandle *handle,
+ GdkWindow *window);
+
+gboolean _gtk_text_handle_get_is_dragged (GtkTextHandle *handle,
+ GtkTextHandlePosition pos);
+
+G_END_DECLS
+
+#endif /* __GTK_TEXT_HANDLE_PRIVATE_H__ */
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index f624250..54a42ee 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -3292,6 +3292,19 @@ gtk_widget_class_init (GtkWidgetClass *klass)
1, G_MAXINT, 16,
GTK_PARAM_READABLE));
+ gtk_widget_class_install_style_property (klass,
+ g_param_spec_int ("text-handle-width",
+ P_("Width of text selection handles"),
+ P_("Width of text selection handles"),
+ 1, G_MAXINT, 16,
+ GTK_PARAM_READABLE));
+ gtk_widget_class_install_style_property (klass,
+ g_param_spec_int ("text-handle-height",
+ P_("Height of text selection handles"),
+ P_("Height of text selection handles"),
+ 1, G_MAXINT, 20,
+ GTK_PARAM_READABLE));
+
g_type_class_add_private (klass, sizeof (GtkWidgetPrivate));
gtk_widget_class_set_accessible_type (klass, GTK_TYPE_WIDGET_ACCESSIBLE);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]