forked from AuroraMiddleware/gtk
0eb09ac0f2
This improves both interaction and theming, as it allows arbitrary handle shapes while just being draggable from the visible areas. This way themes can set up handles with the hotspot visually displaced from the horizontal center, as long as the hotspot lies centered in the image/svg asset.
684 lines
20 KiB
C
684 lines
20 KiB
C
/* 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;
|
|
GtkStyleContext *style_context;
|
|
|
|
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;
|
|
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);
|
|
|
|
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);
|
|
else
|
|
gtk_style_context_add_class (priv->style_context,
|
|
GTK_STYLE_CLASS_TOP);
|
|
|
|
_gtk_text_handle_get_size (handle, &width, &height);
|
|
gtk_render_background (priv->style_context, cr, 0, 0, width, height);
|
|
|
|
gtk_style_context_restore (priv->style_context);
|
|
cairo_restore (cr);
|
|
}
|
|
|
|
static void
|
|
_gtk_text_handle_update_shape (GtkTextHandle *handle,
|
|
GdkWindow *window,
|
|
GtkTextHandlePosition pos)
|
|
{
|
|
GtkTextHandlePrivate *priv;
|
|
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
|
|
gdk_window_shape_combine_region (window, region, 0, 0);
|
|
|
|
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);
|
|
gdk_window_set_user_data (window, priv->parent);
|
|
gdk_window_set_background_rgba (window, &bg);
|
|
|
|
_gtk_text_handle_update_shape (handle, window, pos);
|
|
|
|
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, pos);
|
|
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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_unref (priv->style_context);
|
|
|
|
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)
|
|
{
|
|
GtkTextHandlePrivate *priv;
|
|
GtkWidgetPath *path;
|
|
|
|
handle->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (handle,
|
|
GTK_TYPE_TEXT_HANDLE,
|
|
GtkTextHandlePrivate);
|
|
|
|
path = gtk_widget_path_new ();
|
|
gtk_widget_path_append_type (path, GTK_TYPE_TEXT_HANDLE);
|
|
|
|
priv->style_context = gtk_style_context_new ();
|
|
gtk_style_context_set_path (priv->style_context, path);
|
|
gtk_widget_path_free (path);
|
|
}
|
|
|
|
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, 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_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;
|
|
|
|
_gtk_text_handle_update_shape (handle,
|
|
priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window,
|
|
GTK_TEXT_HANDLE_POSITION_CURSOR);
|
|
}
|
|
|
|
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;
|
|
}
|