]> Pileus Git - ~andy/gtk/blob - gtk/gtktexthandle.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtktexthandle.c
1 /* GTK - The GIMP Toolkit
2  * Copyright © 2012 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19 #include "gtkprivatetypebuiltins.h"
20 #include "gtktexthandleprivate.h"
21 #include "gtkmarshalers.h"
22 #include "gtkprivate.h"
23 #include "gtkintl.h"
24
25 #include <gtk/gtk.h>
26
27 typedef struct _GtkTextHandlePrivate GtkTextHandlePrivate;
28 typedef struct _HandleWindow HandleWindow;
29
30 enum {
31   HANDLE_DRAGGED,
32   DRAG_FINISHED,
33   LAST_SIGNAL
34 };
35
36 enum {
37   PROP_0,
38   PROP_PARENT,
39   PROP_RELATIVE_TO
40 };
41
42 struct _HandleWindow
43 {
44   GdkWindow *window;
45   GdkRectangle pointing_to;
46   gint dx;
47   gint dy;
48   guint dragged : 1;
49   guint mode_visible : 1;
50   guint user_visible : 1;
51   guint has_point : 1;
52 };
53
54 struct _GtkTextHandlePrivate
55 {
56   HandleWindow windows[2];
57   GtkWidget *parent;
58   GdkWindow *relative_to;
59   GtkStyleContext *style_context;
60
61   gulong draw_signal_id;
62   gulong event_signal_id;
63   gulong style_updated_id;
64   gulong composited_changed_id;
65   guint realized : 1;
66   guint mode : 2;
67 };
68
69 G_DEFINE_TYPE (GtkTextHandle, _gtk_text_handle, G_TYPE_OBJECT)
70
71 static guint signals[LAST_SIGNAL] = { 0 };
72
73 static void
74 _gtk_text_handle_get_size (GtkTextHandle *handle,
75                            gint          *width,
76                            gint          *height)
77 {
78   GtkTextHandlePrivate *priv;
79   gint w, h;
80
81   priv = handle->priv;
82
83   gtk_widget_style_get (priv->parent,
84                         "text-handle-width", &w,
85                         "text-handle-height", &h,
86                         NULL);
87   if (width)
88     *width = w;
89
90   if (height)
91     *height = h;
92 }
93
94 static void
95 _gtk_text_handle_draw (GtkTextHandle         *handle,
96                        cairo_t               *cr,
97                        GtkTextHandlePosition  pos)
98 {
99   GtkTextHandlePrivate *priv;
100   gint width, height;
101
102   priv = handle->priv;
103   cairo_save (cr);
104
105   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
106   cairo_set_source_rgba (cr, 0, 0, 0, 0);
107   cairo_paint (cr);
108
109   if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
110     cairo_translate (cr, 0, priv->windows[pos].pointing_to.height);
111
112   gtk_style_context_save (priv->style_context);
113   gtk_style_context_add_class (priv->style_context,
114                                GTK_STYLE_CLASS_CURSOR_HANDLE);
115
116   if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
117     {
118       gtk_style_context_add_class (priv->style_context,
119                                    GTK_STYLE_CLASS_BOTTOM);
120
121       if (priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR)
122         gtk_style_context_add_class (priv->style_context,
123                                      GTK_STYLE_CLASS_INSERTION_CURSOR);
124     }
125   else
126     gtk_style_context_add_class (priv->style_context,
127                                  GTK_STYLE_CLASS_TOP);
128
129   _gtk_text_handle_get_size (handle, &width, &height);
130   gtk_render_background (priv->style_context, cr, 0, 0, width, height);
131
132   gtk_style_context_restore (priv->style_context);
133   cairo_restore (cr);
134 }
135
136 static void
137 _gtk_text_handle_update_shape (GtkTextHandle         *handle,
138                                GdkWindow             *window,
139                                GtkTextHandlePosition  pos)
140 {
141   GtkTextHandlePrivate *priv;
142   cairo_rectangle_int_t rect;
143   cairo_surface_t *surface;
144   cairo_region_t *region;
145   cairo_t *cr;
146
147   priv = handle->priv;
148
149   surface =
150     gdk_window_create_similar_surface (window,
151                                        CAIRO_CONTENT_COLOR_ALPHA,
152                                        gdk_window_get_width (window),
153                                        gdk_window_get_height (window));
154
155   cr = cairo_create (surface);
156   _gtk_text_handle_draw (handle, cr, pos);
157   cairo_destroy (cr);
158
159   region = gdk_cairo_region_create_from_surface (surface);
160
161   if (gtk_widget_is_composited (priv->parent))
162     gdk_window_shape_combine_region (window, NULL, 0, 0);
163   else
164     gdk_window_shape_combine_region (window, region, 0, 0);
165
166   cairo_region_get_extents (region, &rect);
167   cairo_region_destroy (region);
168
169   /* Preserve x/width, but extend input shape
170    * vertically to all window height */
171   rect.y = 0;
172   rect.height = gdk_window_get_height (window);
173   region = cairo_region_create_rectangle (&rect);
174
175   gdk_window_input_shape_combine_region (window, region, 0, 0);
176
177   cairo_surface_destroy (surface);
178   cairo_region_destroy (region);
179 }
180
181 static GdkWindow *
182 _gtk_text_handle_create_window (GtkTextHandle         *handle,
183                                 GtkTextHandlePosition  pos)
184 {
185   GtkTextHandlePrivate *priv;
186   GdkRGBA bg = { 0, 0, 0, 0 };
187   GdkWindowAttr attributes;
188   GdkWindow *window;
189   GdkVisual *visual;
190   gint mask;
191
192   priv = handle->priv;
193
194   attributes.x = 0;
195   attributes.y = 0;
196   _gtk_text_handle_get_size (handle, &attributes.width, &attributes.height);
197   attributes.window_type = GDK_WINDOW_TEMP;
198   attributes.wclass = GDK_INPUT_OUTPUT;
199   attributes.event_mask = (GDK_EXPOSURE_MASK |
200                            GDK_BUTTON_PRESS_MASK |
201                            GDK_BUTTON_RELEASE_MASK |
202                            GDK_BUTTON1_MOTION_MASK);
203
204   mask = GDK_WA_X | GDK_WA_Y;
205
206   visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (priv->parent));
207
208   if (visual)
209     {
210       attributes.visual = visual;
211       mask |= GDK_WA_VISUAL;
212     }
213
214   window = gdk_window_new (gtk_widget_get_root_window (priv->parent),
215                            &attributes, mask);
216   gtk_widget_register_window (priv->parent, window);
217   gdk_window_set_background_rgba (window, &bg);
218
219   _gtk_text_handle_update_shape (handle, window, pos);
220
221   return window;
222 }
223
224 static gboolean
225 gtk_text_handle_widget_draw (GtkWidget     *widget,
226                              cairo_t       *cr,
227                              GtkTextHandle *handle)
228 {
229   GtkTextHandlePrivate *priv;
230   GtkTextHandlePosition pos;
231   HandleWindow *handle_window;
232
233   priv = handle->priv;
234
235   if (!priv->realized)
236     return FALSE;
237
238   if (gtk_cairo_should_draw_window (cr, priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window))
239     pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
240   else if (gtk_cairo_should_draw_window (cr, priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window))
241     pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END;
242   else
243     return FALSE;
244
245   handle_window = &priv->windows[pos];
246   if (gdk_window_is_visible (handle_window->window))
247     _gtk_text_handle_draw (handle, cr, pos);
248
249   return FALSE;
250 }
251
252 static gboolean
253 gtk_text_handle_widget_event (GtkWidget     *widget,
254                               GdkEvent      *event,
255                               GtkTextHandle *handle)
256 {
257   GtkTextHandlePrivate *priv;
258   GtkTextHandlePosition pos;
259
260   priv = handle->priv;
261
262   if (event->any.window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window)
263     pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
264   else if (event->any.window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window)
265     pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END;
266   else
267     return FALSE;
268
269   if (event->type == GDK_BUTTON_PRESS)
270     {
271       priv->windows[pos].dx = event->button.x;
272       priv->windows[pos].dy = event->button.y;
273       priv->windows[pos].dragged = TRUE;
274     }
275   else if (event->type == GDK_BUTTON_RELEASE)
276     {
277       g_signal_emit (handle, signals[DRAG_FINISHED], 0, pos);
278       priv->windows[pos].dx =  priv->windows[pos].dy = 0;
279       priv->windows[pos].dragged = FALSE;
280     }
281   else if (event->type == GDK_MOTION_NOTIFY && priv->windows[pos].dragged)
282     {
283       gint x, y, width, height;
284
285       _gtk_text_handle_get_size (handle, &width, &height);
286       gdk_window_get_origin (priv->relative_to, &x, &y);
287
288       x = event->motion.x_root - priv->windows[pos].dx + (width / 2) - x;
289       y = event->motion.y_root - priv->windows[pos].dy - y;
290
291       if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_START)
292         y += height;
293
294       y += priv->windows[pos].pointing_to.height / 2;
295
296       g_signal_emit (handle, signals[HANDLE_DRAGGED], 0, pos, x, y);
297     }
298
299   return TRUE;
300 }
301
302 static void
303 _gtk_text_handle_update_window_state (GtkTextHandle         *handle,
304                                       GtkTextHandlePosition  pos)
305 {
306   GtkTextHandlePrivate *priv;
307   HandleWindow *handle_window;
308
309   priv = handle->priv;
310   handle_window = &priv->windows[pos];
311
312   if (!handle_window->window)
313     return;
314
315   if (handle_window->has_point &&
316       handle_window->mode_visible && handle_window->user_visible)
317     {
318       gint x, y, width, height;
319
320       x = handle_window->pointing_to.x;
321       y = handle_window->pointing_to.y;
322       _gtk_text_handle_get_size (handle, &width, &height);
323
324       if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR)
325         y -= height;
326
327       height += handle_window->pointing_to.height;
328       x -= width / 2;
329
330       gdk_window_move_resize (handle_window->window, x, y, width, height);
331       gdk_window_show (handle_window->window);
332     }
333   else
334     gdk_window_hide (handle_window->window);
335 }
336
337 static void
338 _gtk_text_handle_update_window (GtkTextHandle         *handle,
339                                 GtkTextHandlePosition  pos,
340                                 gboolean               recreate)
341 {
342   GtkTextHandlePrivate *priv;
343   HandleWindow *handle_window;
344
345   priv = handle->priv;
346   handle_window = &priv->windows[pos];
347
348   if (!handle_window->window)
349     return;
350
351   if (recreate)
352     {
353       gtk_widget_unregister_window (priv->parent, handle_window->window);
354       gdk_window_destroy (handle_window->window);
355       handle_window->window = _gtk_text_handle_create_window (handle, pos);
356     }
357
358   _gtk_text_handle_update_window_state (handle, pos);
359 }
360
361 static void
362 _gtk_text_handle_update_windows (GtkTextHandle *handle)
363 {
364   GtkTextHandlePrivate *priv = handle->priv;
365
366   gtk_style_context_invalidate (priv->style_context);
367   _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, FALSE);
368   _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, FALSE);
369 }
370
371 static void
372 _gtk_text_handle_composited_changed (GtkTextHandle *handle)
373 {
374   _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, TRUE);
375   _gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, TRUE);
376 }
377
378 static void
379 gtk_text_handle_constructed (GObject *object)
380 {
381   GtkTextHandlePrivate *priv;
382
383   priv = GTK_TEXT_HANDLE (object)->priv;
384   g_assert (priv->parent != NULL);
385
386   priv->draw_signal_id =
387     g_signal_connect (priv->parent, "draw",
388                       G_CALLBACK (gtk_text_handle_widget_draw),
389                       object);
390   priv->event_signal_id =
391     g_signal_connect (priv->parent, "event",
392                       G_CALLBACK (gtk_text_handle_widget_event),
393                       object);
394   priv->composited_changed_id =
395     g_signal_connect_swapped (priv->parent, "composited-changed",
396                               G_CALLBACK (_gtk_text_handle_composited_changed),
397                               object);
398   priv->style_updated_id =
399     g_signal_connect_swapped (priv->parent, "style-updated",
400                               G_CALLBACK (_gtk_text_handle_update_windows),
401                               object);
402 }
403
404 static void
405 gtk_text_handle_finalize (GObject *object)
406 {
407   GtkTextHandlePrivate *priv;
408
409   priv = GTK_TEXT_HANDLE (object)->priv;
410
411   if (priv->relative_to)
412     g_object_unref (priv->relative_to);
413
414   if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window)
415     {
416       gtk_widget_unregister_window (priv->parent,
417                                     priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
418       gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
419     }
420
421   if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window)
422     {
423       gtk_widget_unregister_window (priv->parent,
424                                     priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
425       gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
426     }
427
428   if (g_signal_handler_is_connected (priv->parent, priv->draw_signal_id))
429     g_signal_handler_disconnect (priv->parent, priv->draw_signal_id);
430
431   if (g_signal_handler_is_connected (priv->parent, priv->event_signal_id))
432     g_signal_handler_disconnect (priv->parent, priv->event_signal_id);
433
434   if (g_signal_handler_is_connected (priv->parent, priv->composited_changed_id))
435     g_signal_handler_disconnect (priv->parent, priv->composited_changed_id);
436
437   if (g_signal_handler_is_connected (priv->parent, priv->style_updated_id))
438     g_signal_handler_disconnect (priv->parent, priv->style_updated_id);
439
440   g_object_unref (priv->style_context);
441
442   G_OBJECT_CLASS (_gtk_text_handle_parent_class)->finalize (object);
443 }
444
445 static void
446 gtk_text_handle_set_property (GObject      *object,
447                               guint         prop_id,
448                               const GValue *value,
449                               GParamSpec   *pspec)
450 {
451   GtkTextHandlePrivate *priv;
452   GtkTextHandle *handle;
453
454   handle = GTK_TEXT_HANDLE (object);
455   priv = handle->priv;
456
457   switch (prop_id)
458     {
459     case PROP_PARENT:
460       priv->parent = g_value_get_object (value);
461       break;
462     case PROP_RELATIVE_TO:
463       _gtk_text_handle_set_relative_to (handle,
464                                         g_value_get_object (value));
465       break;
466     default:
467       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
468     }
469 }
470
471 static void
472 gtk_text_handle_get_property (GObject    *object,
473                               guint       prop_id,
474                               GValue     *value,
475                               GParamSpec *pspec)
476 {
477   GtkTextHandlePrivate *priv;
478
479   priv = GTK_TEXT_HANDLE (object)->priv;
480
481   switch (prop_id)
482     {
483     case PROP_PARENT:
484       g_value_set_object (value, priv->parent);
485       break;
486     case PROP_RELATIVE_TO:
487       g_value_set_object (value, priv->relative_to);
488       break;
489     default:
490       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
491     }
492 }
493
494 static void
495 _gtk_text_handle_class_init (GtkTextHandleClass *klass)
496 {
497   GObjectClass *object_class = G_OBJECT_CLASS (klass);
498
499   object_class->constructed = gtk_text_handle_constructed;
500   object_class->finalize = gtk_text_handle_finalize;
501   object_class->set_property = gtk_text_handle_set_property;
502   object_class->get_property = gtk_text_handle_get_property;
503
504   signals[HANDLE_DRAGGED] =
505     g_signal_new (I_("handle-dragged"),
506                   G_OBJECT_CLASS_TYPE (object_class),
507                   G_SIGNAL_RUN_LAST,
508                   G_STRUCT_OFFSET (GtkTextHandleClass, handle_dragged),
509                   NULL, NULL,
510                   _gtk_marshal_VOID__ENUM_INT_INT,
511                   G_TYPE_NONE, 3,
512                   GTK_TYPE_TEXT_HANDLE_POSITION,
513                   G_TYPE_INT, G_TYPE_INT);
514   signals[DRAG_FINISHED] =
515     g_signal_new (I_("drag-finished"),
516                   G_OBJECT_CLASS_TYPE (object_class),
517                   G_SIGNAL_RUN_LAST, 0,
518                   NULL, NULL,
519                   g_cclosure_marshal_VOID__ENUM,
520                   G_TYPE_NONE, 1,
521                   GTK_TYPE_TEXT_HANDLE_POSITION);
522
523   g_object_class_install_property (object_class,
524                                    PROP_PARENT,
525                                    g_param_spec_object ("parent",
526                                                         P_("Parent widget"),
527                                                         P_("Parent widget"),
528                                                         GTK_TYPE_WIDGET,
529                                                         GTK_PARAM_READWRITE |
530                                                         G_PARAM_CONSTRUCT_ONLY));
531   g_object_class_install_property (object_class,
532                                    PROP_RELATIVE_TO,
533                                    g_param_spec_object ("relative-to",
534                                                         P_("Window"),
535                                                         P_("Window the coordinates are based upon"),
536                                                         GDK_TYPE_WINDOW,
537                                                         GTK_PARAM_READWRITE));
538
539   g_type_class_add_private (object_class, sizeof (GtkTextHandlePrivate));
540 }
541
542 static void
543 _gtk_text_handle_init (GtkTextHandle *handle)
544 {
545   GtkTextHandlePrivate *priv;
546   GtkWidgetPath *path;
547
548   handle->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (handle,
549                                                      GTK_TYPE_TEXT_HANDLE,
550                                                      GtkTextHandlePrivate);
551
552   path = gtk_widget_path_new ();
553   gtk_widget_path_append_type (path, GTK_TYPE_TEXT_HANDLE);
554
555   priv->style_context = gtk_style_context_new ();
556   gtk_style_context_set_path (priv->style_context, path);
557   gtk_widget_path_free (path);
558 }
559
560 GtkTextHandle *
561 _gtk_text_handle_new (GtkWidget *parent)
562 {
563   return g_object_new (GTK_TYPE_TEXT_HANDLE,
564                        "parent", parent,
565                        NULL);
566 }
567
568 void
569 _gtk_text_handle_set_relative_to (GtkTextHandle *handle,
570                                   GdkWindow     *window)
571 {
572   GtkTextHandlePrivate *priv;
573
574   g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
575   g_return_if_fail (!window || GDK_IS_WINDOW (window));
576
577   priv = handle->priv;
578
579   if (priv->relative_to)
580     {
581       gtk_widget_unregister_window (priv->parent,
582                                     priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
583       gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
584       gtk_widget_unregister_window (priv->parent,
585                                     priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
586       gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
587       g_object_unref (priv->relative_to);
588     }
589
590   if (window)
591     {
592       priv->relative_to = g_object_ref (window);
593       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window =
594         _gtk_text_handle_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
595       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window =
596         _gtk_text_handle_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
597       priv->realized = TRUE;
598     }
599   else
600     {
601       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window = NULL;
602       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window = NULL;
603       priv->relative_to = NULL;
604       priv->realized = FALSE;
605     }
606
607   g_object_notify (G_OBJECT (handle), "relative-to");
608 }
609
610 void
611 _gtk_text_handle_set_mode (GtkTextHandle     *handle,
612                            GtkTextHandleMode  mode)
613 {
614   GtkTextHandlePrivate *priv;
615
616   g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
617
618   priv = handle->priv;
619
620   if (priv->mode == mode)
621     return;
622
623   priv->mode = mode;
624
625   switch (mode)
626     {
627     case GTK_TEXT_HANDLE_MODE_CURSOR:
628       priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].mode_visible = TRUE;
629       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE;
630       break;
631     case GTK_TEXT_HANDLE_MODE_SELECTION:
632       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = TRUE;
633       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = TRUE;
634       break;
635     case GTK_TEXT_HANDLE_MODE_NONE:
636     default:
637       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE;
638       priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = FALSE;
639       break;
640     }
641
642   _gtk_text_handle_update_shape (handle,
643                                  priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window,
644                                  GTK_TEXT_HANDLE_POSITION_CURSOR);
645   _gtk_text_handle_update_shape (handle,
646                                  priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window,
647                                  GTK_TEXT_HANDLE_POSITION_SELECTION_START);
648
649   _gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
650   _gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
651 }
652
653 GtkTextHandleMode
654 _gtk_text_handle_get_mode (GtkTextHandle *handle)
655 {
656   GtkTextHandlePrivate *priv;
657
658   g_return_val_if_fail (GTK_IS_TEXT_HANDLE (handle), GTK_TEXT_HANDLE_MODE_NONE);
659
660   priv = handle->priv;
661   return priv->mode;
662 }
663
664 void
665 _gtk_text_handle_set_position (GtkTextHandle         *handle,
666                                GtkTextHandlePosition  pos,
667                                GdkRectangle          *rect)
668 {
669   GtkTextHandlePrivate *priv;
670   HandleWindow *handle_window;
671   gboolean size_changed;
672
673   g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
674
675   priv = handle->priv;
676   pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR,
677                GTK_TEXT_HANDLE_POSITION_SELECTION_START);
678   handle_window = &priv->windows[pos];
679
680   if (!priv->realized)
681     return;
682
683   if (priv->mode == GTK_TEXT_HANDLE_MODE_NONE ||
684       (priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR &&
685        pos != GTK_TEXT_HANDLE_POSITION_CURSOR))
686     return;
687
688   size_changed = (rect->width != handle_window->pointing_to.width ||
689                   rect->height != handle_window->pointing_to.height);
690
691   handle_window->pointing_to = *rect;
692   handle_window->has_point = TRUE;
693   gdk_window_get_root_coords (priv->relative_to,
694                               rect->x, rect->y,
695                               &handle_window->pointing_to.x,
696                               &handle_window->pointing_to.y);
697
698   _gtk_text_handle_update_window_state (handle, pos);
699
700   if (size_changed)
701     _gtk_text_handle_update_shape (handle, handle_window->window, pos);
702 }
703
704 void
705 _gtk_text_handle_set_visible (GtkTextHandle         *handle,
706                               GtkTextHandlePosition  pos,
707                               gboolean               visible)
708 {
709   GtkTextHandlePrivate *priv;
710   GdkWindow *window;
711
712   g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
713
714   priv = handle->priv;
715   pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR,
716                GTK_TEXT_HANDLE_POSITION_SELECTION_START);
717
718   if (!priv->realized)
719     return;
720
721   window = priv->windows[pos].window;
722
723   if (!window)
724     return;
725
726   if (!gdk_window_is_visible (window))
727     _gtk_text_handle_update_shape (handle, window, pos);
728
729   priv->windows[pos].user_visible = visible;
730   _gtk_text_handle_update_window_state (handle, pos);
731 }
732
733 gboolean
734 _gtk_text_handle_get_is_dragged (GtkTextHandle         *handle,
735                                  GtkTextHandlePosition  pos)
736 {
737   GtkTextHandlePrivate *priv;
738
739   g_return_val_if_fail (GTK_IS_TEXT_HANDLE (handle), FALSE);
740
741   priv = handle->priv;
742   pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR,
743                GTK_TEXT_HANDLE_POSITION_SELECTION_START);
744
745   return priv->windows[pos].dragged;
746 }