nautilus-3.6.3/eel/eel-editable-label.c

Location Tool Test ID Function Issue
eel-editable-label.c:2595:7 clang-analyzer Function call argument is an uninitialized value
eel-editable-label.c:3777:3 clang-analyzer Function call argument is an uninitialized value
eel-editable-label.c:3800:11 clang-analyzer Function call argument is an uninitialized value
   1 /* GTK - The GIMP Toolkit
   2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
   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, write to the Free
  16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17  */
  18 
  19 /*
  20  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  21  * file for a list of people on the GTK+ Team.  See the ChangeLog
  22  * files for a list of changes.  These files are distributed with
  23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  24  */
  25 
  26 #include <config.h>
  27 #include <math.h>
  28 #include <string.h>
  29 
  30 #include "eel-editable-label.h"
  31 #include "eel-accessibility.h"
  32 #include <libgail-util/gailmisc.h>
  33 
  34 #include <glib/gi18n-lib.h>
  35 #include <pango/pango.h>
  36 #include <gtk/gtk.h>
  37 #include <gdk/gdkkeysyms.h>
  38 
  39 enum {
  40   MOVE_CURSOR,
  41   POPULATE_POPUP,
  42   DELETE_FROM_CURSOR,
  43   CUT_CLIPBOARD,
  44   COPY_CLIPBOARD,
  45   PASTE_CLIPBOARD,
  46   TOGGLE_OVERWRITE,
  47   LAST_SIGNAL
  48 };
  49 
  50 enum {
  51   PROP_0,
  52   PROP_TEXT,
  53   PROP_JUSTIFY,
  54   PROP_WRAP,
  55   PROP_CURSOR_POSITION,
  56   PROP_SELECTION_BOUND
  57 };
  58 
  59 static guint signals[LAST_SIGNAL] = { 0 };
  60 
  61 static void     eel_editable_label_editable_init           (GtkEditableInterface  *iface);
  62 static void     eel_editable_label_class_init              (EelEditableLabelClass *klass);
  63 static void     eel_editable_label_init                    (EelEditableLabel      *label);
  64 static void     eel_editable_label_set_property            (GObject               *object,
  65 							    guint                  prop_id,
  66 							    const GValue          *value,
  67 							    GParamSpec            *pspec);
  68 static void     eel_editable_label_get_property            (GObject               *object,
  69 							    guint                  prop_id,
  70 							    GValue                *value,
  71 							    GParamSpec            *pspec);
  72 static void     eel_editable_label_finalize                (GObject               *object);
  73 static void     eel_editable_label_get_preferred_width     (GtkWidget             *widget,
  74                                                             gint                  *minimum,
  75                                                             gint                  *natural);
  76 static void     eel_editable_label_get_preferred_height    (GtkWidget             *widget,
  77                                                             gint                  *minimum,
  78                                                             gint                  *natural);
  79 static void     eel_editable_label_size_allocate           (GtkWidget             *widget,
  80 							    GtkAllocation         *allocation);
  81 static void     eel_editable_label_state_changed           (GtkWidget             *widget,
  82 							    GtkStateType           state);
  83 static void     eel_editable_label_style_updated           (GtkWidget             *widget);
  84 static void     eel_editable_label_direction_changed       (GtkWidget             *widget,
  85 							    GtkTextDirection       previous_dir);
  86 static gint     eel_editable_label_draw                    (GtkWidget             *widget,
  87 							    cairo_t               *cr);
  88 static void     eel_editable_label_realize                 (GtkWidget             *widget);
  89 static void     eel_editable_label_unrealize               (GtkWidget             *widget);
  90 static void     eel_editable_label_map                     (GtkWidget             *widget);
  91 static void     eel_editable_label_unmap                   (GtkWidget             *widget);
  92 static gint     eel_editable_label_button_press            (GtkWidget             *widget,
  93 							    GdkEventButton        *event);
  94 static gint     eel_editable_label_button_release          (GtkWidget             *widget,
  95 							    GdkEventButton        *event);
  96 static gint     eel_editable_label_motion                  (GtkWidget             *widget,
  97 							    GdkEventMotion        *event);
  98 static gint     eel_editable_label_key_press               (GtkWidget             *widget,
  99 							    GdkEventKey           *event);
 100 static gint     eel_editable_label_key_release             (GtkWidget             *widget,
 101 							    GdkEventKey           *event);
 102 static gint     eel_editable_label_focus_in                (GtkWidget             *widget,
 103 							    GdkEventFocus         *event);
 104 static gint     eel_editable_label_focus_out               (GtkWidget             *widget,
 105 							    GdkEventFocus         *event);
 106 static AtkObject *eel_editable_label_get_accessible        (GtkWidget             *widget);
 107 static void     eel_editable_label_commit_cb               (GtkIMContext          *context,
 108 							    const gchar           *str,
 109 							    EelEditableLabel      *label);
 110 static void     eel_editable_label_preedit_changed_cb      (GtkIMContext          *context,
 111 							    EelEditableLabel      *label);
 112 static gboolean eel_editable_label_retrieve_surrounding_cb (GtkIMContext          *context,
 113 							    EelEditableLabel      *label);
 114 static gboolean eel_editable_label_delete_surrounding_cb   (GtkIMContext          *slave,
 115 							    gint                   offset,
 116 							    gint                   n_chars,
 117 							    EelEditableLabel      *label);
 118 static void     eel_editable_label_clear_layout            (EelEditableLabel      *label);
 119 static void     eel_editable_label_recompute               (EelEditableLabel      *label);
 120 static void     eel_editable_label_ensure_layout           (EelEditableLabel      *label,
 121 							    gboolean               include_preedit);
 122 static void     eel_editable_label_select_region_index     (EelEditableLabel      *label,
 123 							    gint                   anchor_index,
 124 							    gint                   end_index);
 125 static gboolean eel_editable_label_focus                   (GtkWidget             *widget,
 126 							    GtkDirectionType       direction);
 127 static void     eel_editable_label_move_cursor             (EelEditableLabel      *label,
 128 							    GtkMovementStep        step,
 129 							    gint                   count,
 130 							    gboolean               extend_selection);
 131 static void     eel_editable_label_delete_from_cursor      (EelEditableLabel      *label,
 132 							    GtkDeleteType          type,
 133 							    gint                   count);
 134 static void     eel_editable_label_copy_clipboard          (EelEditableLabel      *label);
 135 static void     eel_editable_label_cut_clipboard           (EelEditableLabel      *label);
 136 static void     eel_editable_label_paste                   (EelEditableLabel      *label,
 137 							    GdkAtom                selection);
 138 static void     eel_editable_label_paste_clipboard         (EelEditableLabel      *label);
 139 static void     eel_editable_label_select_all              (EelEditableLabel      *label);
 140 static void     eel_editable_label_do_popup                (EelEditableLabel      *label,
 141 							    GdkEventButton        *event);
 142 static void     eel_editable_label_toggle_overwrite        (EelEditableLabel      *label);
 143 static gint     eel_editable_label_move_forward_word       (EelEditableLabel      *label,
 144 							    gint                   start);
 145 static gint     eel_editable_label_move_backward_word      (EelEditableLabel      *label,
 146 							    gint                   start);
 147 static void     eel_editable_label_reset_im_context        (EelEditableLabel      *label);
 148 static void     eel_editable_label_check_cursor_blink      (EelEditableLabel      *label);
 149 static void     eel_editable_label_pend_cursor_blink       (EelEditableLabel      *label);
 150 
 151 /* Editable implementation: */
 152 static void     editable_insert_text_emit     (GtkEditable *editable,
 153 					       const gchar *new_text,
 154 					       gint         new_text_length,
 155 					       gint        *position);
 156 static void     editable_delete_text_emit     (GtkEditable *editable,
 157 					       gint         start_pos,
 158 					       gint         end_pos);
 159 static void     editable_insert_text          (GtkEditable *editable,
 160 					       const gchar *new_text,
 161 					       gint         new_text_length,
 162 					       gint        *position);
 163 static void     editable_delete_text          (GtkEditable *editable,
 164 					       gint         start_pos,
 165 					       gint         end_pos);
 166 static gchar *  editable_get_chars            (GtkEditable *editable,
 167 					       gint         start_pos,
 168 					       gint         end_pos);
 169 static void     editable_set_selection_bounds (GtkEditable *editable,
 170 					       gint         start,
 171 					       gint         end);
 172 static gboolean editable_get_selection_bounds (GtkEditable *editable,
 173 					       gint        *start,
 174 					       gint        *end);
 175 static void     editable_real_set_position    (GtkEditable *editable,
 176 					       gint         position);
 177 static gint     editable_get_position         (GtkEditable *editable);
 178 
 179 G_DEFINE_TYPE_WITH_CODE (EelEditableLabel, eel_editable_label, GTK_TYPE_MISC,
 180 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, eel_editable_label_editable_init));
 181 
 182 static void
 183 add_move_binding (GtkBindingSet  *binding_set,
 184 		  guint           keyval,
 185 		  guint           modmask,
 186 		  GtkMovementStep step,
 187 		  gint            count)
 188 {
 189   g_assert ((modmask & GDK_SHIFT_MASK) == 0);
 190   
 191   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
 192 				"move_cursor", 3,
 193 				G_TYPE_ENUM, step,
 194 				G_TYPE_INT, count,
 195                                 G_TYPE_BOOLEAN, FALSE);
 196 
 197   /* Selection-extending version */
 198   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
 199 				"move_cursor", 3,
 200 				G_TYPE_ENUM, step,
 201 				G_TYPE_INT, count,
 202                                 G_TYPE_BOOLEAN, TRUE);
 203 }
 204 
 205 static void
 206 eel_editable_label_class_init (EelEditableLabelClass *class)
 207 {
 208   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 209   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 210   GtkBindingSet *binding_set;
 211 
 212   gobject_class->set_property = eel_editable_label_set_property;
 213   gobject_class->get_property = eel_editable_label_get_property;
 214   gobject_class->finalize = eel_editable_label_finalize;
 215 
 216   widget_class->get_preferred_width = eel_editable_label_get_preferred_width;
 217   widget_class->get_preferred_height = eel_editable_label_get_preferred_height;
 218   widget_class->size_allocate = eel_editable_label_size_allocate;
 219   widget_class->state_changed = eel_editable_label_state_changed;
 220   widget_class->style_updated = eel_editable_label_style_updated;
 221   widget_class->direction_changed = eel_editable_label_direction_changed;
 222   widget_class->draw = eel_editable_label_draw;
 223   widget_class->realize = eel_editable_label_realize;
 224   widget_class->unrealize = eel_editable_label_unrealize;
 225   widget_class->map = eel_editable_label_map;
 226   widget_class->unmap = eel_editable_label_unmap;
 227   widget_class->button_press_event = eel_editable_label_button_press;
 228   widget_class->button_release_event = eel_editable_label_button_release;
 229   widget_class->motion_notify_event = eel_editable_label_motion;
 230   widget_class->focus = eel_editable_label_focus;
 231   widget_class->key_press_event = eel_editable_label_key_press;
 232   widget_class->key_release_event = eel_editable_label_key_release;
 233   widget_class->focus_in_event = eel_editable_label_focus_in;
 234   widget_class->focus_out_event = eel_editable_label_focus_out;
 235   widget_class->get_accessible = eel_editable_label_get_accessible;
 236 
 237   class->move_cursor = eel_editable_label_move_cursor;
 238   class->delete_from_cursor = eel_editable_label_delete_from_cursor;
 239   class->copy_clipboard = eel_editable_label_copy_clipboard;
 240   class->cut_clipboard = eel_editable_label_cut_clipboard;
 241   class->paste_clipboard = eel_editable_label_paste_clipboard;
 242   class->toggle_overwrite = eel_editable_label_toggle_overwrite;
 243   
 244   signals[MOVE_CURSOR] = 
 245     g_signal_new ("move_cursor",
 246 		  G_TYPE_FROM_CLASS (class),
 247 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 248 		  G_STRUCT_OFFSET (EelEditableLabelClass, move_cursor),
 249 		  NULL, NULL,
 250 		  g_cclosure_marshal_generic,
 251 		  G_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, G_TYPE_INT, G_TYPE_BOOLEAN);
 252   
 253   signals[COPY_CLIPBOARD] =
 254     g_signal_new ("copy_clipboard",
 255 		  G_TYPE_FROM_CLASS (class),
 256 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 257 		  G_STRUCT_OFFSET  (EelEditableLabelClass, copy_clipboard),
 258 		  NULL, NULL, 
 259 		  g_cclosure_marshal_VOID__VOID,
 260 		  G_TYPE_NONE, 0);
 261   
 262   signals[POPULATE_POPUP] =
 263     g_signal_new ("populate_popup",
 264 		  G_TYPE_FROM_CLASS (class),
 265 		  G_SIGNAL_RUN_LAST,
 266 		  G_STRUCT_OFFSET (EelEditableLabelClass, populate_popup),
 267 		  NULL, NULL, 
 268 		  g_cclosure_marshal_VOID__OBJECT,
 269 		  G_TYPE_NONE, 1, GTK_TYPE_MENU);
 270 
 271   signals[DELETE_FROM_CURSOR] = 
 272     g_signal_new ("delete_from_cursor",
 273 		  G_TYPE_FROM_CLASS (class),
 274 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 275 		  G_STRUCT_OFFSET (EelEditableLabelClass, delete_from_cursor),
 276 		  NULL, NULL, 
 277 		  g_cclosure_marshal_generic,
 278 		  G_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, G_TYPE_INT);
 279   
 280   signals[CUT_CLIPBOARD] =
 281     g_signal_new ("cut_clipboard",
 282 		  G_TYPE_FROM_CLASS (class),
 283 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 284 		  G_STRUCT_OFFSET (EelEditableLabelClass, cut_clipboard),
 285 		  NULL, NULL, 
 286 		  g_cclosure_marshal_VOID__VOID,
 287 		  G_TYPE_NONE, 0);
 288 
 289   signals[PASTE_CLIPBOARD] =
 290     g_signal_new ("paste_clipboard",
 291 		  G_TYPE_FROM_CLASS (class),
 292 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 293 		  G_STRUCT_OFFSET (EelEditableLabelClass, paste_clipboard),
 294 		  NULL, NULL, 
 295 		  g_cclosure_marshal_VOID__VOID,
 296 		  G_TYPE_NONE, 0);
 297 
 298   signals[TOGGLE_OVERWRITE] =
 299     g_signal_new ("toggle_overwrite",
 300 		  G_TYPE_FROM_CLASS (class),
 301 		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 302 		  G_STRUCT_OFFSET (EelEditableLabelClass, toggle_overwrite),
 303 		  NULL, NULL, 
 304 		  g_cclosure_marshal_VOID__VOID,
 305 		  G_TYPE_NONE, 0);
 306 
 307   
 308   g_object_class_install_property (gobject_class,
 309                                    PROP_TEXT,
 310                                    g_param_spec_string ("text",
 311                                                         _("Text"),
 312                                                         _("The text of the label."),
 313                                                         NULL,
 314                                                         G_PARAM_READWRITE));
 315   g_object_class_install_property (gobject_class,
 316 				   PROP_JUSTIFY,
 317                                    g_param_spec_enum ("justify",
 318                                                       _("Justification"),
 319                                                       _("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that."),
 320 						      GTK_TYPE_JUSTIFICATION,
 321 						      GTK_JUSTIFY_LEFT,
 322                                                       G_PARAM_READWRITE));
 323 
 324   g_object_class_install_property (gobject_class,
 325                                    PROP_WRAP,
 326                                    g_param_spec_boolean ("wrap",
 327                                                         _("Line wrap"),
 328                                                         _("If set, wrap lines if the text becomes too wide."),
 329                                                         FALSE,
 330                                                         G_PARAM_READWRITE));
 331 
 332   g_object_class_install_property (gobject_class,
 333                                    PROP_CURSOR_POSITION,
 334                                    g_param_spec_int ("cursor_position",
 335                                                      _("Cursor Position"),
 336                                                      _("The current position of the insertion cursor in chars."),
 337                                                      0,
 338                                                      G_MAXINT,
 339                                                      0,
 340                                                      G_PARAM_READABLE));
 341   
 342   g_object_class_install_property (gobject_class,
 343                                    PROP_SELECTION_BOUND,
 344                                    g_param_spec_int ("selection_bound",
 345                                                      _("Selection Bound"),
 346                                                      _("The position of the opposite end of the selection from the cursor in chars."),
 347                                                      0,
 348                                                      G_MAXINT,
 349                                                      0,
 350                                                      G_PARAM_READABLE));
 351   
 352   /*
 353    * Key bindings
 354    */
 355 
 356   binding_set = gtk_binding_set_by_class (class);
 357 
 358   /* Moving the insertion point */
 359   add_move_binding (binding_set, GDK_KEY_Right, 0,
 360 		    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
 361   
 362   add_move_binding (binding_set, GDK_KEY_Left, 0,
 363 		    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
 364 
 365   add_move_binding (binding_set, GDK_KEY_KP_Right, 0,
 366 		    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
 367   
 368   add_move_binding (binding_set, GDK_KEY_KP_Left, 0,
 369 		    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
 370   
 371   add_move_binding (binding_set, GDK_KEY_f, GDK_CONTROL_MASK,
 372 		    GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
 373   
 374   add_move_binding (binding_set, GDK_KEY_b, GDK_CONTROL_MASK,
 375 		    GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
 376   
 377   add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
 378 		    GTK_MOVEMENT_WORDS, 1);
 379 
 380   add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
 381 		    GTK_MOVEMENT_WORDS, -1);
 382 
 383   add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
 384 		    GTK_MOVEMENT_WORDS, 1);
 385 
 386   add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
 387 		    GTK_MOVEMENT_WORDS, -1);
 388   
 389   add_move_binding (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
 390 		    GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
 391 
 392   add_move_binding (binding_set, GDK_KEY_e, GDK_CONTROL_MASK,
 393 		    GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
 394 
 395   add_move_binding (binding_set, GDK_KEY_f, GDK_MOD1_MASK,
 396 		    GTK_MOVEMENT_WORDS, 1);
 397 
 398   add_move_binding (binding_set, GDK_KEY_b, GDK_MOD1_MASK,
 399 		    GTK_MOVEMENT_WORDS, -1);
 400 
 401   add_move_binding (binding_set, GDK_KEY_Home, 0,
 402 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
 403 
 404   add_move_binding (binding_set, GDK_KEY_End, 0,
 405 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
 406 
 407   add_move_binding (binding_set, GDK_KEY_KP_Home, 0,
 408 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
 409 
 410   add_move_binding (binding_set, GDK_KEY_KP_End, 0,
 411 		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
 412   
 413   add_move_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK,
 414 		    GTK_MOVEMENT_BUFFER_ENDS, -1);
 415 
 416   add_move_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK,
 417 		    GTK_MOVEMENT_BUFFER_ENDS, 1);
 418 
 419   add_move_binding (binding_set, GDK_KEY_KP_Home, GDK_CONTROL_MASK,
 420 		    GTK_MOVEMENT_BUFFER_ENDS, -1);
 421 
 422   add_move_binding (binding_set, GDK_KEY_KP_End, GDK_CONTROL_MASK,
 423 		    GTK_MOVEMENT_BUFFER_ENDS, 1);
 424 
 425   add_move_binding (binding_set, GDK_KEY_Up, 0,
 426                     GTK_MOVEMENT_DISPLAY_LINES, -1);
 427 
 428   add_move_binding (binding_set, GDK_KEY_KP_Up, 0,
 429                     GTK_MOVEMENT_DISPLAY_LINES, -1);
 430   
 431   add_move_binding (binding_set, GDK_KEY_Down, 0,
 432                     GTK_MOVEMENT_DISPLAY_LINES, 1);
 433 
 434   add_move_binding (binding_set, GDK_KEY_KP_Down, 0,
 435                     GTK_MOVEMENT_DISPLAY_LINES, 1);
 436   
 437   /* Select all
 438    */
 439   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
 440                                 "move_cursor", 3,
 441                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
 442                                 G_TYPE_INT, -1,
 443 				G_TYPE_BOOLEAN, FALSE);
 444   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK,
 445                                 "move_cursor", 3,
 446                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
 447                                 G_TYPE_INT, 1,
 448 				G_TYPE_BOOLEAN, TRUE);
 449   
 450   /* Deleting text */
 451   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
 452 				"delete_from_cursor", 2,
 453 				G_TYPE_ENUM, GTK_DELETE_CHARS,
 454 				G_TYPE_INT, 1);
 455 
 456   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
 457 				"delete_from_cursor", 2,
 458 				G_TYPE_ENUM, GTK_DELETE_CHARS,
 459 				G_TYPE_INT, 1);
 460   
 461   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0,
 462 				"delete_from_cursor", 2,
 463 				G_TYPE_ENUM, GTK_DELETE_CHARS,
 464 				G_TYPE_INT, -1);
 465 
 466   /* Make this do the same as Backspace, to help with mis-typing */
 467   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_SHIFT_MASK,
 468                                 "delete_from_cursor", 2,
 469                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
 470                                 G_TYPE_INT, -1);
 471 
 472   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_CONTROL_MASK,
 473 				"delete_from_cursor", 2,
 474 				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
 475 				G_TYPE_INT, 1);
 476 
 477   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_CONTROL_MASK,
 478 				"delete_from_cursor", 2,
 479 				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
 480 				G_TYPE_INT, 1);
 481   
 482   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK,
 483 				"delete_from_cursor", 2,
 484 				G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
 485 				G_TYPE_INT, -1);
 486 
 487   /* Cut/copy/paste */
 488 
 489   gtk_binding_entry_add_signal (binding_set, GDK_KEY_x, GDK_CONTROL_MASK,
 490 				"cut_clipboard", 0);
 491   gtk_binding_entry_add_signal (binding_set, GDK_KEY_c, GDK_CONTROL_MASK,
 492 				"copy_clipboard", 0);
 493   gtk_binding_entry_add_signal (binding_set, GDK_KEY_v, GDK_CONTROL_MASK,
 494 				"paste_clipboard", 0);
 495 
 496   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
 497 				"cut_clipboard", 0);
 498   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_CONTROL_MASK,
 499 				"copy_clipboard", 0);
 500   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, GDK_SHIFT_MASK,
 501 				"paste_clipboard", 0);
 502 
 503   /* Overwrite */
 504   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Insert, 0,
 505 				"toggle_overwrite", 0);
 506   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Insert, 0,
 507 				"toggle_overwrite", 0);
 508 }
 509 
 510 static void
 511 eel_editable_label_editable_init (GtkEditableInterface *iface)
 512 {
 513   iface->do_insert_text = editable_insert_text_emit;
 514   iface->do_delete_text = editable_delete_text_emit;
 515   iface->insert_text = editable_insert_text;
 516   iface->delete_text = editable_delete_text;
 517   iface->get_chars = editable_get_chars;
 518   iface->set_selection_bounds = editable_set_selection_bounds;
 519   iface->get_selection_bounds = editable_get_selection_bounds;
 520   iface->set_position = editable_real_set_position;
 521   iface->get_position = editable_get_position;
 522 }
 523 
 524 
 525 static void 
 526 eel_editable_label_set_property (GObject      *object,
 527 				 guint         prop_id,
 528 				 const GValue *value,
 529 				 GParamSpec   *pspec)
 530 {
 531   EelEditableLabel *label;
 532 
 533   label = EEL_EDITABLE_LABEL (object);
 534   
 535   switch (prop_id)
 536     {
 537     case PROP_TEXT:
 538       eel_editable_label_set_text (label, g_value_get_string (value));
 539       break;
 540     case PROP_JUSTIFY:
 541       eel_editable_label_set_justify (label, g_value_get_enum (value));
 542       break;
 543     case PROP_WRAP:
 544       eel_editable_label_set_line_wrap (label, g_value_get_boolean (value));
 545       break;	  
 546     default:
 547       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 548       break;
 549     }
 550 }
 551 
 552 static void 
 553 eel_editable_label_get_property (GObject     *object,
 554 				 guint        prop_id,
 555 				 GValue      *value,
 556 				 GParamSpec  *pspec)
 557 {
 558   EelEditableLabel *label;
 559   gint offset;
 560   
 561   label = EEL_EDITABLE_LABEL (object);
 562   
 563   switch (prop_id)
 564     {
 565     case PROP_TEXT:
 566       g_value_set_string (value, label->text);
 567       break;
 568     case PROP_JUSTIFY:
 569       g_value_set_enum (value, label->jtype);
 570       break;
 571     case PROP_WRAP:
 572       g_value_set_boolean (value, label->wrap);
 573       break;
 574     case PROP_CURSOR_POSITION:
 575       offset = g_utf8_pointer_to_offset (label->text,
 576 					 label->text + label->selection_end);
 577       g_value_set_int (value, offset);
 578       break;
 579     case PROP_SELECTION_BOUND:
 580       offset = g_utf8_pointer_to_offset (label->text,
 581 					 label->text + label->selection_anchor);
 582       g_value_set_int (value, offset);
 583       break;
 584 
 585     default:
 586       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 587       break;
 588     }
 589 }
 590 
 591 static void
 592 eel_editable_label_init (EelEditableLabel *label)
 593 {
 594   label->jtype = GTK_JUSTIFY_LEFT;
 595   label->wrap = FALSE;
 596   label->wrap_mode = PANGO_WRAP_WORD;
 597 
 598   label->layout = NULL;
 599   label->text_size = 1;
 600   label->text = g_malloc (label->text_size);
 601   label->text[0] = '\0';
 602   label->n_bytes = 0;
 603   
 604   gtk_widget_set_can_focus (GTK_WIDGET (label), TRUE);
 605   gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (label)),
 606                                GTK_STYLE_CLASS_ENTRY);
 607 
 608     /* This object is completely private. No external entity can gain a reference
 609    * to it; so we create it here and destroy it in finalize().
 610    */
 611   label->im_context = gtk_im_multicontext_new ();
 612 
 613   g_signal_connect (G_OBJECT (label->im_context), "commit",
 614 		    G_CALLBACK (eel_editable_label_commit_cb), label);
 615   g_signal_connect (G_OBJECT (label->im_context), "preedit_changed",
 616 		    G_CALLBACK (eel_editable_label_preedit_changed_cb), label);
 617   g_signal_connect (G_OBJECT (label->im_context), "retrieve_surrounding",
 618 		    G_CALLBACK (eel_editable_label_retrieve_surrounding_cb), label);
 619   g_signal_connect (G_OBJECT (label->im_context), "delete_surrounding",
 620 		    G_CALLBACK (eel_editable_label_delete_surrounding_cb), label);
 621 }
 622 
 623 /**
 624  * eel_editable_label_new:
 625  * @str: The text of the label
 626  *
 627  * Creates a new label with the given text inside it. You can
 628  * pass %NULL to get an empty label widget.
 629  *
 630  * Return value: the new #EelEditableLabel
 631  **/
 632 GtkWidget*
 633 eel_editable_label_new (const gchar *str)
 634 {
 635   EelEditableLabel *label;
 636   
 637   label = g_object_new (EEL_TYPE_EDITABLE_LABEL, NULL);
 638 
 639   if (str && *str)
 640     eel_editable_label_set_text (label, str);
 641   
 642   return GTK_WIDGET (label);
 643 }
 644 
 645 /**
 646  * eel_editable_label_set_text:
 647  * @label: a #EelEditableLabel
 648  * @str: The text you want to set.
 649  *
 650  * Sets the text within the #EelEditableLabel widget.  It overwrites any text that
 651  * was there before.  
 652  *
 653  * This will also clear any previously set mnemonic accelerators.
 654  **/
 655 void
 656 eel_editable_label_set_text (EelEditableLabel *label,
 657 			     const gchar *str)
 658 {
 659   GtkEditable *editable;
 660   int tmp_pos;
 661   
 662   g_return_if_fail (EEL_IS_EDITABLE_LABEL (label));
 663   g_return_if_fail (str != NULL);
 664   
 665   if (strcmp (label->text, str) == 0)
 666     return;
 667 
 668   editable = GTK_EDITABLE (label);
 669   gtk_editable_delete_text (editable, 0, -1);
 670   tmp_pos = 0;
 671   gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
 672 }
 673 
 674 /**
 675  * eel_editable_label_get_text:
 676  * @label: a #EelEditableLabel
 677  * 
 678  * Fetches the text from a label widget, as displayed on the
 679  * screen. This does not include any embedded underlines
 680  * indicating mnemonics or Pango markup. (See eel_editable_label_get_label())
 681  * 
 682  * Return value: the text in the label widget. This is the internal
 683  *   string used by the label, and must not be modified.
 684  **/
 685 const gchar *
 686 eel_editable_label_get_text (EelEditableLabel *label)
 687 {
 688   g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), NULL);
 689 
 690   return label->text;
 691 }
 692 
 693 /**
 694  * eel_editable_label_set_justify:
 695  * @label: a #EelEditableLabel
 696  * @jtype: a #GtkJustification
 697  *
 698  * Sets the alignment of the lines in the text of the label relative to
 699  * each other.  %GTK_JUSTIFY_LEFT is the default value when the
 700  * widget is first created with eel_editable_label_new(). If you instead want
 701  * to set the alignment of the label as a whole, use
 702  * gtk_misc_set_alignment() instead. eel_editable_label_set_justify() has no
 703  * effect on labels containing only a single line.
 704  **/
 705 void
 706 eel_editable_label_set_justify (EelEditableLabel        *label,
 707 				GtkJustification jtype)
 708 {
 709   g_return_if_fail (EEL_IS_EDITABLE_LABEL (label));
 710   g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
 711   
 712   if ((GtkJustification) label->jtype != jtype)
 713     {
 714       label->jtype = jtype;
 715 
 716       /* No real need to be this drastic, but easier than duplicating the code */
 717       eel_editable_label_recompute (label);
 718       
 719       g_object_notify (G_OBJECT (label), "justify");
 720       gtk_widget_queue_resize (GTK_WIDGET (label));
 721     }
 722 }
 723 
 724 /**
 725  * eel_editable_label_get_justify:
 726  * @label: a #EelEditableLabel
 727  *
 728  * Returns the justification of the label. See eel_editable_label_set_justify ().
 729  *
 730  * Return value: #GtkJustification
 731  **/
 732 GtkJustification
 733 eel_editable_label_get_justify (EelEditableLabel *label)
 734 {
 735   g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), 0);
 736 
 737   return label->jtype;
 738 }
 739 
 740 void
 741 eel_editable_label_set_draw_outline (EelEditableLabel *label,
 742 				     gboolean          draw_outline)
 743 {
 744     draw_outline = draw_outline != FALSE;
 745 
 746     if (label->draw_outline != draw_outline)
 747     {
 748       label->draw_outline = draw_outline;
 749       
 750       gtk_widget_queue_draw (GTK_WIDGET (label));
 751     }
 752 
 753 }
 754 
 755 
 756 /**
 757  * eel_editable_label_set_line_wrap:
 758  * @label: a #EelEditableLabel
 759  * @wrap: the setting
 760  *
 761  * Toggles line wrapping within the #EelEditableLabel widget.  %TRUE makes it break
 762  * lines if text exceeds the widget's size.  %FALSE lets the text get cut off
 763  * by the edge of the widget if it exceeds the widget size.
 764  **/
 765 void
 766 eel_editable_label_set_line_wrap (EelEditableLabel *label,
 767 				  gboolean  wrap)
 768 {
 769   g_return_if_fail (EEL_IS_EDITABLE_LABEL (label));
 770   
 771   wrap = wrap != FALSE;
 772   
 773   if (label->wrap != wrap)
 774     {
 775       label->wrap = wrap;
 776       g_object_notify (G_OBJECT (label), "wrap");
 777       
 778       gtk_widget_queue_resize (GTK_WIDGET (label));
 779     }
 780 }
 781 
 782 
 783 void
 784 eel_editable_label_set_line_wrap_mode (EelEditableLabel *label,
 785 				       PangoWrapMode     mode)
 786 {
 787   g_return_if_fail (EEL_IS_EDITABLE_LABEL (label));
 788   
 789   if (label->wrap_mode != mode)
 790     {
 791       label->wrap_mode = mode;
 792       
 793       gtk_widget_queue_resize (GTK_WIDGET (label));
 794     }
 795   
 796 }
 797 
 798 
 799 /**
 800  * eel_editable_label_get_line_wrap:
 801  * @label: a #EelEditableLabel
 802  *
 803  * Returns whether lines in the label are automatically wrapped. See eel_editable_label_set_line_wrap ().
 804  *
 805  * Return value: %TRUE if the lines of the label are automatically wrapped.
 806  */
 807 gboolean
 808 eel_editable_label_get_line_wrap (EelEditableLabel *label)
 809 {
 810   g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), FALSE);
 811 
 812   return label->wrap;
 813 }
 814 
 815 PangoFontDescription *
 816 eel_editable_label_get_font_description (EelEditableLabel *label)
 817 {
 818   if (label->font_desc)
 819     return pango_font_description_copy (label->font_desc);
 820 
 821   return NULL;
 822 }
 823 
 824 void
 825 eel_editable_label_set_font_description (EelEditableLabel *label,
 826 					 const PangoFontDescription *desc)
 827 {
 828   if (label->font_desc)
 829     pango_font_description_free (label->font_desc);
 830 
 831   if (desc)
 832     label->font_desc = pango_font_description_copy (desc);
 833   else
 834     label->font_desc = NULL;
 835 
 836   eel_editable_label_clear_layout (label);
 837 }
 838 
 839 static void
 840 eel_editable_label_finalize (GObject *object)
 841 {
 842   EelEditableLabel *label;
 843   
 844   g_assert (EEL_IS_EDITABLE_LABEL (object));
 845   
 846   label = EEL_EDITABLE_LABEL (object);
 847 
 848   if (label->font_desc)
 849     {
 850       pango_font_description_free (label->font_desc);
 851       label->font_desc = NULL;
 852     }
 853   
 854   g_object_unref (G_OBJECT (label->im_context));
 855   label->im_context = NULL;
 856   
 857   g_free (label->text);
 858   label->text = NULL;
 859 
 860   if (label->layout)
 861     {
 862       g_object_unref (G_OBJECT (label->layout));
 863       label->layout = NULL;
 864     }
 865 
 866   G_OBJECT_CLASS (eel_editable_label_parent_class)->finalize (object);
 867 }
 868 
 869 static void
 870 eel_editable_label_clear_layout (EelEditableLabel *label)
 871 {
 872   if (label->layout)
 873     {
 874       g_object_unref (G_OBJECT (label->layout));
 875       label->layout = NULL;
 876     }
 877 }
 878 
 879 static void
 880 eel_editable_label_recompute (EelEditableLabel *label)
 881 {
 882   eel_editable_label_clear_layout (label);
 883   eel_editable_label_check_cursor_blink (label);
 884 }
 885 
 886 typedef struct _LabelWrapWidth LabelWrapWidth;
 887 struct _LabelWrapWidth
 888 {
 889   gint width;
 890   PangoFontDescription *font_desc;
 891 };
 892 
 893 static void
 894 label_wrap_width_free (gpointer data)
 895 {
 896   LabelWrapWidth *wrap_width = data;
 897   pango_font_description_free (wrap_width->font_desc);
 898   g_free (wrap_width);
 899 }
 900 
 901 static gint
 902 get_label_wrap_width (EelEditableLabel *label)
 903 {
 904   PangoLayout *layout;
 905   GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET (label));
 906   PangoFontDescription *desc;
 907 
 908   LabelWrapWidth *wrap_width = g_object_get_data (G_OBJECT (style), "gtk-label-wrap-width");
 909   if (!wrap_width)
 910     {
 911       wrap_width = g_new0 (LabelWrapWidth, 1);
 912       g_object_set_data_full (G_OBJECT (style), "gtk-label-wrap-width",
 913 			      wrap_width, label_wrap_width_free);
 914     }
 915 
 916   gtk_style_context_get (style, gtk_widget_get_state_flags (GTK_WIDGET (label)),
 917                          GTK_STYLE_PROPERTY_FONT, &desc,
 918                          NULL);
 919 
 920   if (wrap_width->font_desc && pango_font_description_equal (wrap_width->font_desc, desc))
 921     goto out;
 922 
 923   if (wrap_width->font_desc)
 924     pango_font_description_free (wrap_width->font_desc);
 925 
 926   wrap_width->font_desc = pango_font_description_copy (desc);
 927 
 928   layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), 
 929 					   "This long string gives a good enough length for any line to have.");
 930   pango_layout_get_size (layout, &wrap_width->width, NULL);
 931   g_object_unref (layout);
 932 
 933  out:
 934   pango_font_description_free (desc);
 935 
 936   return wrap_width->width;
 937 }
 938 
 939 static void
 940 eel_editable_label_ensure_layout (EelEditableLabel *label,
 941 				  gboolean        include_preedit)
 942 {
 943   GtkWidget *widget;
 944   PangoRectangle logical_rect;
 945 
 946   /* Normalize for comparisons */
 947   include_preedit = include_preedit != 0;
 948 
 949   if (label->preedit_length > 0 &&
 950       include_preedit != label->layout_includes_preedit)
 951     eel_editable_label_clear_layout (label);
 952   
 953   widget = GTK_WIDGET (label);
 954 
 955   if (label->layout == NULL)
 956     {
 957       gchar *preedit_string = NULL;
 958       gint preedit_length = 0;
 959       PangoAttrList *preedit_attrs = NULL;
 960       PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
 961       PangoAttrList *tmp_attrs = pango_attr_list_new ();
 962 
 963       if (include_preedit)
 964 	{
 965 	  gtk_im_context_get_preedit_string (label->im_context,
 966 					     &preedit_string, &preedit_attrs, NULL);
 967 	  preedit_length = label->preedit_length;
 968 	}
 969 
 970       if (preedit_length)
 971 	{
 972 	  GString *tmp_string = g_string_new (NULL);
 973 	  
 974 	  g_string_prepend_len (tmp_string, label->text, label->n_bytes);
 975 	  g_string_insert (tmp_string, label->selection_anchor, preedit_string);
 976       
 977 	  label->layout = gtk_widget_create_pango_layout (widget, tmp_string->str);
 978       
 979 	  pango_attr_list_splice (tmp_attrs, preedit_attrs,
 980 				  label->selection_anchor, preedit_length);
 981 	  
 982 	  g_string_free (tmp_string, TRUE);
 983 	}
 984       else
 985 	{
 986 	  label->layout = gtk_widget_create_pango_layout (widget, label->text);
 987 	}
 988       label->layout_includes_preedit = include_preedit;
 989 
 990       if (label->font_desc != NULL)
 991 	pango_layout_set_font_description (label->layout, label->font_desc);
 992       
 993       pango_layout_set_attributes (label->layout, tmp_attrs);
 994       
 995       if (preedit_string)
 996 	g_free (preedit_string);
 997       if (preedit_attrs)
 998 	pango_attr_list_unref (preedit_attrs);
 999       pango_attr_list_unref (tmp_attrs);
1000 
1001       switch (label->jtype)
1002 	{
1003 	case GTK_JUSTIFY_LEFT:
1004 	  align = PANGO_ALIGN_LEFT;
1005 	  break;
1006 	case GTK_JUSTIFY_RIGHT:
1007 	  align = PANGO_ALIGN_RIGHT;
1008 	  break;
1009 	case GTK_JUSTIFY_CENTER:
1010 	  align = PANGO_ALIGN_CENTER;
1011 	  break;
1012 	case GTK_JUSTIFY_FILL:
1013 	  /* FIXME: This just doesn't work to do this */
1014 	  align = PANGO_ALIGN_LEFT;
1015 	  pango_layout_set_justify (label->layout, TRUE);
1016 	  break;
1017 	default:
1018 	  g_assert_not_reached();
1019 	}
1020 
1021       pango_layout_set_alignment (label->layout, align);
1022 
1023       if (label->wrap)
1024 	{
1025 	  gint longest_paragraph;
1026 	  gint width, height;
1027 	  gint set_width;
1028 
1029 	  gtk_widget_get_size_request (widget, &set_width, NULL);
1030 	  if (set_width > 0)
1031 	    pango_layout_set_width (label->layout, set_width * PANGO_SCALE);
1032 	  else
1033 	    {
1034 	      gint wrap_width;
1035 	      
1036 	      pango_layout_set_width (label->layout, -1);
1037 	      pango_layout_get_extents (label->layout, NULL, &logical_rect);
1038 
1039 	      width = logical_rect.width;
1040 	      
1041 	      /* Try to guess a reasonable maximum width */
1042 	      longest_paragraph = width;
1043 
1044 	      wrap_width = get_label_wrap_width (label);
1045 	      width = MIN (width, wrap_width);
1046 	      width = MIN (width,
1047 			   PANGO_SCALE * (gdk_screen_width () + 1) / 2);
1048 	      
1049 	      pango_layout_set_width (label->layout, width);
1050 	      pango_layout_get_extents (label->layout, NULL, &logical_rect);
1051 	      width = logical_rect.width;
1052 	      height = logical_rect.height;
1053 	      
1054 	      /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
1055 	       * so we try short search for a narrower width that leaves us with the same height
1056 	       */
1057 	      if (longest_paragraph > 0)
1058 		{
1059 		  gint nlines, perfect_width;
1060 		  
1061 		  nlines = pango_layout_get_line_count (label->layout);
1062 		  perfect_width = (longest_paragraph + nlines - 1) / nlines;
1063 		  
1064 		  if (perfect_width < width)
1065 		    {
1066 		      pango_layout_set_width (label->layout, perfect_width);
1067 		      pango_layout_get_extents (label->layout, NULL, &logical_rect);
1068 		      
1069 		      if (logical_rect.height <= height)
1070 			width = logical_rect.width;
1071 		      else
1072 			{
1073 			  gint mid_width = (perfect_width + width) / 2;
1074 			  
1075 			  if (mid_width > perfect_width)
1076 			    {
1077 			      pango_layout_set_width (label->layout, mid_width);
1078 			      pango_layout_get_extents (label->layout, NULL, &logical_rect);
1079 			      
1080 			      if (logical_rect.height <= height)
1081 				width = logical_rect.width;
1082 			    }
1083 			}
1084 		    }
1085 		}
1086 	      pango_layout_set_width (label->layout, width);
1087 	    }
1088 	  pango_layout_set_wrap (label->layout, label->wrap_mode);
1089 	}
1090       else		/* !label->wrap */
1091 	pango_layout_set_width (label->layout, -1);
1092     }
1093 }
1094 
1095 static void
1096 eel_editable_label_size_request (GtkWidget      *widget,
1097 				 GtkRequisition *requisition)
1098 {
1099   EelEditableLabel *label;
1100   gint width, height;
1101   PangoRectangle logical_rect;
1102   gint set_width;
1103   gint xpad, ypad;
1104 
1105   g_assert (EEL_IS_EDITABLE_LABEL (widget));
1106   g_assert (requisition != NULL);
1107   
1108   label = EEL_EDITABLE_LABEL (widget);
1109 
1110   /*  
1111    * If word wrapping is on, then the height requisition can depend
1112    * on:
1113    *
1114    *   - Any width set on the widget via gtk_widget_set_size_request().
1115    *   - The padding of the widget (xpad, set by gtk_misc_set_padding)
1116    *
1117    * Instead of trying to detect changes to these quantities, if we
1118    * are wrapping, we just rewrap for each size request. Since
1119    * size requisitions are cached by the GTK+ core, this is not
1120    * expensive.
1121    */
1122 
1123   if (label->wrap)
1124     eel_editable_label_recompute (label);
1125 
1126   eel_editable_label_ensure_layout (label, TRUE);
1127 
1128   gtk_misc_get_padding (&label->misc,
1129                         &xpad, &ypad);
1130   width = xpad * 2;
1131   height = ypad * 2;
1132 
1133   pango_layout_get_extents (label->layout, NULL, &logical_rect);
1134   
1135   gtk_widget_get_size_request (widget, &set_width, NULL);
1136   if (label->wrap && set_width > 0)
1137     width += set_width;
1138   else 
1139     width += PANGO_PIXELS (logical_rect.width);
1140   
1141   height += PANGO_PIXELS (logical_rect.height);
1142 
1143   requisition->width = width;
1144   requisition->height = height;
1145 }
1146 
1147 static void
1148 eel_editable_label_get_preferred_width (GtkWidget *widget,
1149                                         gint      *minimum,
1150                                         gint      *natural)
1151 {
1152   GtkRequisition requisition;
1153 
1154   eel_editable_label_size_request (widget, &requisition);
1155 
1156   *minimum = *natural = requisition.width;
1157 }
1158 
1159 static void
1160 eel_editable_label_get_preferred_height (GtkWidget *widget,
1161                                          gint      *minimum,
1162                                          gint      *natural)
1163 {
1164   GtkRequisition requisition;
1165 
1166   eel_editable_label_size_request (widget, &requisition);
1167 
1168   *minimum = *natural = requisition.height;
1169 }
1170 
1171 static void
1172 eel_editable_label_size_allocate (GtkWidget     *widget,
1173 				  GtkAllocation *allocation)
1174 {
1175   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
1176 
1177   (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->size_allocate) (widget, allocation);
1178 
1179   gdk_window_move_resize (label->text_area, allocation->x, allocation->y,
1180                           allocation->width, allocation->height);
1181 }
1182 
1183 static void
1184 eel_editable_label_state_changed (GtkWidget   *widget,
1185 				  GtkStateType prev_state)
1186 {
1187   EelEditableLabel *label;
1188   
1189   label = EEL_EDITABLE_LABEL (widget);
1190 
1191   /* clear any selection if we're insensitive */
1192   if (!gtk_widget_is_sensitive (widget))
1193     eel_editable_label_select_region (label, 0, 0);
1194 
1195   if (GTK_WIDGET_CLASS (eel_editable_label_parent_class)->state_changed)
1196     GTK_WIDGET_CLASS (eel_editable_label_parent_class)->state_changed (widget, prev_state);
1197 }
1198 
1199 static void 
1200 eel_editable_label_style_updated (GtkWidget *widget)
1201 {
1202   EelEditableLabel *label;
1203 
1204   g_assert (EEL_IS_EDITABLE_LABEL (widget));
1205   
1206   label = EEL_EDITABLE_LABEL (widget);
1207 
1208   GTK_WIDGET_CLASS (eel_editable_label_parent_class)->style_updated (widget);
1209 
1210   /* We have to clear the layout, fonts etc. may have changed */
1211   eel_editable_label_recompute (label);
1212 }
1213 
1214 static void 
1215 eel_editable_label_direction_changed (GtkWidget        *widget,
1216 				      GtkTextDirection previous_dir)
1217 {
1218   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
1219 
1220   if (label->layout)
1221     pango_layout_context_changed (label->layout);
1222 
1223   GTK_WIDGET_CLASS (eel_editable_label_parent_class)->direction_changed (widget, previous_dir);
1224 }
1225 
1226 static void
1227 get_layout_location (EelEditableLabel  *label,
1228                      gint      *xp,
1229                      gint      *yp)
1230 {
1231   GtkMisc *misc;
1232   GtkWidget *widget;
1233   gfloat xalign, yalign;
1234   GtkRequisition req;
1235   gint x, y, xpad, ypad;
1236   GtkAllocation allocation;
1237   
1238   misc = GTK_MISC (label);
1239   widget = GTK_WIDGET (label);
1240   gtk_misc_get_alignment (misc, &xalign, &yalign);
1241   
1242   if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
1243     xalign = 1.0 - xalign;
1244 
1245   gtk_widget_get_preferred_size (widget, &req, NULL);
1246   gtk_misc_get_padding (misc, &xpad, &ypad);
1247 
1248   gtk_widget_get_allocation (widget, &allocation);
1249   x = floor (xpad
1250              + ((allocation.width - req.width) * xalign)
1251              + 0.5);
1252   
1253   y = floor (ypad
1254              + ((allocation.height - req.height) * yalign)
1255              + 0.5);
1256 
1257   if (xp)
1258     *xp = x;
1259 
1260   if (yp)
1261     *yp = y;
1262 }
1263 
1264 static gint
1265 eel_editable_label_get_cursor_pos (EelEditableLabel  *label,
1266 				   PangoRectangle *strong_pos,
1267 				   PangoRectangle *weak_pos)
1268 {
1269   const gchar *text;
1270   const gchar *preedit_text;
1271   gint index;
1272   
1273   eel_editable_label_ensure_layout (label, TRUE);
1274   
1275   text = pango_layout_get_text (label->layout);
1276   preedit_text = text + label->selection_anchor;
1277   index = label->selection_anchor +
1278     g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor) - preedit_text;
1279       
1280   pango_layout_get_cursor_pos (label->layout, index, strong_pos, weak_pos);
1281 
1282   return index;
1283 }
1284 
1285 /* Copied from gtkutil private function */
1286 static gboolean
1287 eel_editable_label_get_block_cursor_location (EelEditableLabel  *label,
1288 					      gint *index,
1289 					      PangoRectangle *pos,
1290 					      gboolean *at_line_end)
1291 {
1292   const gchar *text;
1293   const gchar *preedit_text;
1294   PangoLayoutLine *layout_line;
1295   PangoRectangle strong_pos, weak_pos;
1296   gint line_no;
1297   gboolean rtl;
1298   PangoContext *context;
1299   PangoFontMetrics *metrics;
1300   const PangoFontDescription *font_desc;
1301   
1302   eel_editable_label_ensure_layout (label, TRUE);
1303   
1304   text = pango_layout_get_text (label->layout);
1305   preedit_text = text + label->selection_anchor;
1306   text = g_utf8_offset_to_pointer (preedit_text, label->preedit_cursor);
1307   index[0] = label->selection_anchor + text - preedit_text;
1308 
1309   pango_layout_index_to_pos (label->layout, index[0], pos);
1310 
1311   index[1] = label->selection_anchor + g_utf8_next_char (text) - preedit_text;
1312 
1313   if (pos->width != 0)
1314     {
1315       if (at_line_end)
1316 	*at_line_end = FALSE;
1317       if (pos->width < 0) /* RTL char, shift x value back to top left of rect */
1318 	{
1319 	  pos->x += pos->width;
1320 	  pos->width = -pos->width;
1321 	}
1322       return TRUE;
1323     }
1324 
1325   pango_layout_index_to_line_x (label->layout, index[0], FALSE, &line_no, NULL);
1326   layout_line = pango_layout_get_line_readonly (label->layout, line_no);
1327   if (layout_line == NULL)
1328     return FALSE;
1329 
1330     text = pango_layout_get_text (label->layout);
1331   if (index[0] < layout_line->start_index + layout_line->length)
1332     {
1333       /* this may be a zero-width character in the middle of the line,
1334        * or it could be a character where line is wrapped, we do want
1335        * block cursor in latter case */
1336       if (g_utf8_next_char (text + index[0]) - text !=
1337 	  layout_line->start_index + layout_line->length)
1338 	{
1339 	  /* zero-width character in the middle of the line, do not
1340 	   * bother with block cursor */
1341 	  return FALSE;
1342 	}
1343     }
1344 
1345   /* Cursor is at the line end. It may be an empty line, or it could
1346    * be on the left or on the right depending on text direction, or it
1347    * even could be in the middle of visual layout in bidi text. */
1348 
1349   pango_layout_get_cursor_pos (label->layout, index[0], &strong_pos, &weak_pos);
1350 
1351   if (strong_pos.x != weak_pos.x)
1352     {
1353       /* do not show block cursor in this case, since the character typed
1354        * in may or may not appear at the cursor position */
1355       return FALSE;
1356     }
1357 
1358   context = pango_layout_get_context (label->layout);
1359 
1360   /* In case when index points to the end of line, pos->x is always most right
1361    * pixel of the layout line, so we need to correct it for RTL text. */
1362   if (layout_line->length)
1363     {
1364       if (layout_line->resolved_dir == PANGO_DIRECTION_RTL)
1365 	{
1366 	  PangoLayoutIter *iter;
1367 	  PangoRectangle line_rect;
1368 	  gint i;
1369 	  gint left, right;
1370 	  const gchar *p;
1371 
1372 	  p = g_utf8_prev_char (text + index[0]);
1373 
1374 	  pango_layout_line_index_to_x (layout_line, p - text, FALSE, &left);
1375 	  pango_layout_line_index_to_x (layout_line, p - text, TRUE, &right);
1376 	  pos->x = MIN (left, right);
1377 
1378 	  iter = pango_layout_get_iter (label->layout);
1379 	  for (i = 0; i < line_no; i++)
1380 	    pango_layout_iter_next_line (iter);
1381 	  pango_layout_iter_get_line_extents (iter, NULL, &line_rect);
1382 	  pango_layout_iter_free (iter);
1383 
1384           rtl = TRUE;
1385 	  pos->x += line_rect.x;
1386 	}
1387       else
1388 	rtl = FALSE;
1389     }
1390   else
1391     {
1392       rtl = pango_context_get_base_dir (context) == PANGO_DIRECTION_RTL;
1393     }
1394   
1395   font_desc = pango_layout_get_font_description (label->layout);
1396   if (!font_desc)
1397     font_desc = pango_context_get_font_description (context);
1398 
1399   metrics = pango_context_get_metrics (context, font_desc, NULL);
1400   pos->width = pango_font_metrics_get_approximate_char_width (metrics);
1401   pango_font_metrics_unref (metrics);
1402 
1403   if (rtl)
1404     pos->x -= pos->width - 1;
1405 
1406   if (at_line_end)
1407     *at_line_end = TRUE;
1408 
1409   return pos->width != 0;
1410 }
1411 
1412 
1413 /* These functions are copies from gtk+, as they are not exported from gtk+ */
1414 
1415 static void
1416 eel_editable_label_draw_cursor (EelEditableLabel  *label, cairo_t *cr, gint xoffset, gint yoffset)
1417 {
1418   if (gtk_widget_is_drawable (GTK_WIDGET (label)))
1419     {
1420       GtkWidget *widget = GTK_WIDGET (label);
1421 
1422       gboolean block;
1423       gboolean block_at_line_end;
1424       gint range[2];
1425       gint index;
1426       GtkStyleContext *context;
1427       PangoRectangle strong_pos;
1428 
1429       context = gtk_widget_get_style_context (widget);
1430       index = eel_editable_label_get_cursor_pos (label, NULL, NULL);
1431 
1432       if (label->overwrite_mode &&
1433 	  eel_editable_label_get_block_cursor_location (label, range,
1434 							&strong_pos,
1435 							&block_at_line_end))
1436 	block = TRUE;
1437       else
1438 	block = FALSE;
1439 
1440       if (!block)
1441 	{
1442           gtk_render_insertion_cursor (context, cr,
1443                                        xoffset, yoffset,
1444                                        label->layout, index,
1445                                        gdk_keymap_get_direction (gdk_keymap_get_default ()));
1446 	}
1447       else /* Block cursor */
1448 	{
1449           GdkRGBA fg_color;
1450 	  cairo_region_t *clip;
1451 
1452           gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg_color);
1453 
1454 	  cairo_save (cr);
1455           gdk_cairo_set_source_rgba (cr, &fg_color);
1456 
1457 	  cairo_rectangle (cr,
1458 			   xoffset + PANGO_PIXELS (strong_pos.x),
1459 			   yoffset + PANGO_PIXELS (strong_pos.y),
1460 			   PANGO_PIXELS (strong_pos.width),
1461 			   PANGO_PIXELS (strong_pos.height));
1462 	  cairo_fill (cr);
1463 
1464 	  if (!block_at_line_end)
1465 	    {
1466               GdkRGBA color;
1467 
1468 	      clip = gdk_pango_layout_get_clip_region (label->layout,
1469 						       xoffset, yoffset,
1470 						       range, 1);
1471 
1472 	      gdk_cairo_region (cr, clip);
1473 	      cairo_clip (cr);
1474 
1475               gtk_style_context_get_background_color (context, GTK_STATE_FLAG_FOCUSED,
1476                                                       &color);
1477 
1478 	      gdk_cairo_set_source_rgba (cr,
1479                                          &color);
1480 	      cairo_move_to (cr, xoffset, yoffset);
1481 	      pango_cairo_show_layout (cr, label->layout);
1482 
1483 	      cairo_region_destroy (clip);
1484 	    }
1485 
1486 	  cairo_restore (cr);
1487 	}
1488     }
1489 }
1490 
1491 
1492 static gint
1493 eel_editable_label_draw (GtkWidget *widget,
1494                          cairo_t   *cr)
1495 {
1496   EelEditableLabel *label;
1497   GtkStyleContext *style;
1498   gint x, y;
1499   
1500   g_assert (EEL_IS_EDITABLE_LABEL (widget));
1501   
1502   label = EEL_EDITABLE_LABEL (widget);
1503   style = gtk_widget_get_style_context (widget);
1504 
1505   eel_editable_label_ensure_layout (label, TRUE);
1506   
1507   if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) &&
1508       label->text)
1509     {
1510       get_layout_location (label, &x, &y);
1511       
1512       gtk_render_layout (style,
1513                          cr,
1514                          x, y,
1515                          label->layout);
1516 
1517       if (label->selection_anchor != label->selection_end)
1518         {
1519           gint range[2];
1520 	  const char *text;
1521           cairo_region_t *clip;
1522 	  GtkStateType state;
1523           GdkRGBA background_color;
1524 
1525           range[0] = label->selection_anchor;
1526           range[1] = label->selection_end;
1527 
1528 	  /* Handle possible preedit string */
1529 	  if (label->preedit_length > 0 &&
1530 	      range[1] > label->selection_anchor)
1531 	    {
1532 	      text = pango_layout_get_text (label->layout) + label->selection_anchor;
1533 	      range[1] += g_utf8_offset_to_pointer (text, label->preedit_length) - text;
1534 	    }
1535 	  
1536           if (range[0] > range[1])
1537             {
1538               gint tmp = range[0];
1539               range[0] = range[1];
1540               range[1] = tmp;
1541             }
1542 
1543           clip = gdk_pango_layout_get_clip_region (label->layout,
1544                                                    x, y,
1545                                                    range,
1546                                                    1);
1547 
1548           cairo_save (cr);
1549 
1550 	  gdk_cairo_region (cr, clip);
1551 	  cairo_clip (cr);
1552 
1553           state = gtk_widget_get_state_flags (widget);
1554 	  state |= GTK_STATE_FLAG_SELECTED;
1555 
1556           gtk_style_context_get_background_color (style, state, &background_color);
1557 	  gdk_cairo_set_source_rgba (cr, &background_color);
1558 	  cairo_paint (cr);
1559 
1560           gtk_style_context_save (style);
1561           gtk_style_context_set_state (style, state);
1562 
1563           gtk_render_layout (style, cr,
1564                              x, y, label->layout);
1565 
1566           gtk_style_context_restore (style);
1567           cairo_restore (cr);
1568 
1569           cairo_region_destroy (clip);
1570         }
1571       else if (gtk_widget_has_focus (widget))
1572 	eel_editable_label_draw_cursor (label, cr, x, y);
1573 
1574       if (label->draw_outline) {
1575         gtk_style_context_save (style);
1576         gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget));
1577 
1578         gtk_render_frame (style, cr,
1579                           0, 0,
1580                           gtk_widget_get_allocated_width (widget),
1581                           gtk_widget_get_allocated_height (widget));
1582 
1583         gtk_style_context_restore (style);
1584       }
1585     }
1586 
1587   return FALSE;
1588 }
1589 
1590 static void
1591 eel_editable_label_realize (GtkWidget *widget)
1592 {
1593   EelEditableLabel *label;
1594   GdkWindowAttr attributes;
1595   gint attributes_mask;
1596   GtkAllocation allocation;
1597   GdkWindow *window;
1598   GtkStyleContext *style;
1599 
1600   gtk_widget_set_realized (widget, TRUE);
1601   label = EEL_EDITABLE_LABEL (widget);
1602   gtk_widget_get_allocation (widget, &allocation);
1603 
1604   attributes.wclass = GDK_INPUT_OUTPUT;
1605   attributes.window_type = GDK_WINDOW_CHILD;
1606   attributes.x = allocation.x;
1607   attributes.y = allocation.y;
1608   attributes.width = allocation.width;
1609   attributes.height = allocation.height;
1610   attributes.visual = gtk_widget_get_visual (widget);
1611   attributes.event_mask = gtk_widget_get_events (widget) |
1612     (GDK_EXPOSURE_MASK |
1613      GDK_BUTTON_PRESS_MASK |
1614      GDK_BUTTON_RELEASE_MASK |
1615      GDK_BUTTON1_MOTION_MASK |
1616      GDK_BUTTON3_MOTION_MASK |
1617      GDK_POINTER_MOTION_HINT_MASK |
1618      GDK_POINTER_MOTION_MASK |
1619      GDK_ENTER_NOTIFY_MASK |
1620      GDK_LEAVE_NOTIFY_MASK);
1621 
1622   attributes_mask = GDK_WA_X | GDK_WA_Y  | GDK_WA_VISUAL;
1623 
1624   window = gdk_window_new (gtk_widget_get_parent_window (widget),
1625 			   &attributes, attributes_mask);
1626   gtk_widget_set_window (widget, window);
1627   gdk_window_set_user_data (window, widget);
1628 
1629   attributes.cursor = gdk_cursor_new (GDK_XTERM);
1630   attributes.window_type = GDK_WINDOW_CHILD;
1631   attributes.wclass = GDK_INPUT_ONLY;
1632   attributes.event_mask = gtk_widget_get_events (widget);
1633   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1634                             GDK_BUTTON_RELEASE_MASK |
1635                             GDK_BUTTON1_MOTION_MASK |
1636                             GDK_BUTTON3_MOTION_MASK |
1637                             GDK_POINTER_MOTION_HINT_MASK |
1638                             GDK_POINTER_MOTION_MASK |
1639                             GDK_ENTER_NOTIFY_MASK |
1640                             GDK_LEAVE_NOTIFY_MASK);
1641   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1642 
1643   label->text_area = gdk_window_new (gtk_widget_get_parent_window (widget),
1644                                      &attributes, attributes_mask);
1645   gdk_window_set_user_data (label->text_area, widget);
1646   gtk_im_context_set_client_window (label->im_context, label->text_area);
1647   g_object_unref (attributes.cursor);
1648 
1649   style = gtk_widget_get_style_context (widget);
1650   gtk_style_context_set_background (style, gtk_widget_get_window (widget));
1651 }
1652 
1653 static void
1654 eel_editable_label_unrealize (GtkWidget *widget)
1655 {
1656   EelEditableLabel *label;
1657 
1658   label = EEL_EDITABLE_LABEL (widget);
1659 
1660   gtk_im_context_set_client_window (label->im_context, NULL);
1661 
1662   if (label->text_area)
1663     {
1664       gdk_window_set_user_data (label->text_area, NULL);
1665       gdk_window_destroy (label->text_area);
1666       label->text_area = NULL;
1667     }
1668   
1669   (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->unrealize) (widget);
1670 }
1671 
1672 static void
1673 eel_editable_label_map (GtkWidget *widget)
1674 {
1675   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
1676 
1677   (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->map) (widget);
1678 
1679   gdk_window_show (label->text_area);
1680 }
1681 
1682 static void
1683 eel_editable_label_unmap (GtkWidget *widget)
1684 {
1685   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
1686 
1687   gdk_window_hide (label->text_area);
1688 
1689   (* GTK_WIDGET_CLASS (eel_editable_label_parent_class)->unmap) (widget);
1690 }
1691 
1692 static void
1693 window_to_layout_coords (EelEditableLabel *label,
1694                          gint     *x,
1695                          gint     *y)
1696 {
1697   gint lx, ly;
1698 
1699   /* get layout location in gtk_widget_get_window (widget) coords */
1700   get_layout_location (label, &lx, &ly);
1701   
1702   if (x)
1703     *x -= lx;                   /* go to layout */
1704 
1705   if (y)
1706     *y -= ly;                   /* go to layout */
1707 }
1708 
1709 static void
1710 get_layout_index (EelEditableLabel *label,
1711                   gint      x,
1712                   gint      y,
1713                   gint     *index)
1714 {
1715   gint trailing = 0;
1716   const gchar *cluster;
1717   const gchar *cluster_end;
1718 
1719   *index = 0;
1720   
1721   eel_editable_label_ensure_layout (label, TRUE);
1722   
1723   window_to_layout_coords (label, &x, &y);
1724 
1725   x *= PANGO_SCALE;
1726   y *= PANGO_SCALE;
1727   
1728   pango_layout_xy_to_index (label->layout,
1729                             x, y,
1730                             index, &trailing);
1731 
1732   if (*index >= label->selection_anchor && label->preedit_length)
1733     {
1734       if (*index >= label->selection_anchor + label->preedit_length)
1735 	*index -= label->preedit_length;
1736       else
1737 	{
1738 	  *index = label->selection_anchor;
1739 	  trailing = 0;
1740 	}
1741     }
1742   
1743   cluster = label->text + *index;
1744   cluster_end = cluster;
1745   while (trailing)
1746     {
1747       cluster_end = g_utf8_next_char (cluster_end);
1748       --trailing;
1749     }
1750 
1751   *index += (cluster_end - cluster);
1752 }
1753 
1754 static void
1755 eel_editable_label_select_word (EelEditableLabel *label)
1756 {
1757   gint min, max;
1758   
1759   gint start_index = eel_editable_label_move_backward_word (label, label->selection_end);
1760   gint end_index = eel_editable_label_move_forward_word (label, label->selection_end);
1761 
1762   min = MIN (label->selection_anchor,
1763 	     label->selection_end);
1764   max = MAX (label->selection_anchor,
1765 	     label->selection_end);
1766 
1767   min = MIN (min, start_index);
1768   max = MAX (max, end_index);
1769 
1770   eel_editable_label_select_region_index (label, min, max);
1771 }
1772 
1773 static gint
1774 eel_editable_label_button_press (GtkWidget      *widget,
1775 				 GdkEventButton *event)
1776 {
1777   EelEditableLabel *label;
1778   gint index = 0;
1779   
1780   label = EEL_EDITABLE_LABEL (widget);
1781 
1782   if (event->button == 1)
1783     {
1784       if (!gtk_widget_has_focus (widget))
1785 	gtk_widget_grab_focus (widget);
1786 
1787       if (event->type == GDK_3BUTTON_PRESS)
1788 	{
1789 	  eel_editable_label_select_region_index (label, 0, strlen (label->text));
1790 	  return TRUE;
1791 	}
1792       
1793       if (event->type == GDK_2BUTTON_PRESS)
1794 	{
1795 	  eel_editable_label_select_word (label);
1796 	  return TRUE;
1797 	}
1798       
1799       get_layout_index (label, event->x, event->y, &index);
1800       
1801       if ((label->selection_anchor !=
1802 	   label->selection_end) &&
1803 	  (event->state & GDK_SHIFT_MASK))
1804 	{
1805 	  gint min, max;
1806 	  
1807 	  /* extend (same as motion) */
1808 	  min = MIN (label->selection_anchor,
1809 		     label->selection_end);
1810 	  max = MAX (label->selection_anchor,
1811 		     label->selection_end);
1812 	  
1813 	  min = MIN (min, index);
1814 	  max = MAX (max, index);
1815 	  
1816 	  /* ensure the anchor is opposite index */
1817 	  if (index == min)
1818 	    {
1819 	      gint tmp = min;
1820 	      min = max;
1821 	      max = tmp;
1822 	    }
1823 	  
1824 	  eel_editable_label_select_region_index (label, min, max);
1825 	}
1826       else
1827 	{
1828 	  if (event->type == GDK_3BUTTON_PRESS)
1829 	      eel_editable_label_select_region_index (label, 0, strlen (label->text));
1830 	  else if (event->type == GDK_2BUTTON_PRESS)
1831 	      eel_editable_label_select_word (label);
1832 	  else 
1833 	    /* start a replacement */
1834 	    eel_editable_label_select_region_index (label, index, index);
1835 	}
1836   
1837       return TRUE;
1838     }
1839   else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
1840     {
1841       get_layout_index (label, event->x, event->y, &index);
1842       
1843       eel_editable_label_select_region_index (label, index, index);
1844       eel_editable_label_paste (label, GDK_SELECTION_PRIMARY);
1845       
1846       return TRUE;
1847     }
1848   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1849     {
1850       eel_editable_label_do_popup (label, event);
1851 
1852       return TRUE;
1853       
1854     }
1855   return FALSE;
1856 }
1857 
1858 static gint
1859 eel_editable_label_button_release (GtkWidget      *widget,
1860 				   GdkEventButton *event)
1861 
1862 {
1863   if (event->button != 1)
1864     return FALSE;
1865   
1866   /* The goal here is to return TRUE iff we ate the
1867    * button press to start selecting.
1868    */
1869   
1870   return TRUE;
1871 }
1872 
1873 static gint
1874 eel_editable_label_motion (GtkWidget      *widget,
1875 			   GdkEventMotion *event)
1876 {
1877   EelEditableLabel *label;
1878   gint index;
1879   gint x, y;
1880   
1881   label = EEL_EDITABLE_LABEL (widget);
1882   
1883   if ((event->state & GDK_BUTTON1_MASK) == 0)
1884     return FALSE;
1885 
1886   gdk_window_get_device_position (label->text_area,
1887                                   event->device,
1888                                   &x, &y, NULL);
1889 
1890   get_layout_index (label, x, y, &index);
1891 
1892   eel_editable_label_select_region_index (label,
1893 					  label->selection_anchor,
1894 					  index);
1895   
1896   return TRUE;
1897 }
1898 
1899 static void
1900 get_text_callback (GtkClipboard     *clipboard,
1901                    GtkSelectionData *selection_data,
1902                    guint             info,
1903                    gpointer          user_data_or_owner)
1904 {
1905   EelEditableLabel *label;
1906   
1907   label = EEL_EDITABLE_LABEL (user_data_or_owner);
1908   
1909   if ((label->selection_anchor != label->selection_end) &&
1910       label->text)
1911     {
1912       gint start, end;
1913       gint len;
1914       
1915       start = MIN (label->selection_anchor,
1916                    label->selection_end);
1917       end = MAX (label->selection_anchor,
1918                  label->selection_end);
1919 
1920       len = strlen (label->text);
1921 
1922       if (end > len)
1923         end = len;
1924 
1925       if (start > len)
1926         start = len;
1927 
1928       gtk_selection_data_set_text (selection_data,
1929 				   label->text + start,
1930 				   end - start);
1931     }
1932 }
1933 
1934 static void
1935 clear_text_callback (GtkClipboard     *clipboard,
1936                      gpointer          user_data_or_owner)
1937 {
1938   EelEditableLabel *label;
1939 
1940   label = EEL_EDITABLE_LABEL (user_data_or_owner);
1941 
1942   label->selection_anchor = label->selection_end;
1943       
1944   gtk_widget_queue_draw (GTK_WIDGET (label));
1945 }
1946 
1947 static void
1948 eel_editable_label_select_region_index (EelEditableLabel *label,
1949 					gint      anchor_index,
1950 					gint      end_index)
1951 {
1952   GtkClipboard *clipboard;
1953 
1954   g_assert (EEL_IS_EDITABLE_LABEL (label));
1955   
1956 
1957   if (label->selection_anchor == anchor_index &&
1958       label->selection_end == end_index)
1959     return;
1960 
1961   eel_editable_label_reset_im_context (label);
1962 
1963   label->selection_anchor = anchor_index;
1964   label->selection_end = end_index;
1965 
1966   clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);      
1967       
1968   if (anchor_index != end_index)
1969     {
1970       GtkTargetList *list;
1971       GtkTargetEntry *targets;
1972       gint n_targets;
1973 
1974       list = gtk_target_list_new (NULL, 0);
1975       gtk_target_list_add_text_targets (list, 0);
1976       targets = gtk_target_table_new_from_list (list, &n_targets);
1977 
1978       gtk_clipboard_set_with_owner (clipboard,
1979 				    targets, n_targets,
1980 				    get_text_callback,
1981 				    clear_text_callback,
1982 				    G_OBJECT (label));
1983 
1984       gtk_clipboard_set_can_store (clipboard, NULL, 0);
1985       gtk_target_table_free (targets, n_targets);
1986       gtk_target_list_unref (list);
1987     }
1988   else
1989     {
1990       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (label))
1991 	gtk_clipboard_clear (clipboard);
1992     }
1993   
1994   gtk_widget_queue_draw (GTK_WIDGET (label));
1995   
1996   g_object_freeze_notify (G_OBJECT (label));
1997   g_object_notify (G_OBJECT (label), "cursor_position");
1998   g_object_notify (G_OBJECT (label), "selection_bound");
1999   g_object_thaw_notify (G_OBJECT (label));
2000 }
2001 
2002 /**
2003  * eel_editable_label_select_region:
2004  * @label: a #EelEditableLabel
2005  * @start_offset: start offset (in characters not bytes)
2006  * @end_offset: end offset (in characters not bytes)
2007  *
2008  * Selects a range of characters in the label, if the label is selectable.
2009  * See eel_editable_label_set_selectable(). If the label is not selectable,
2010  * this function has no effect. If @start_offset or
2011  * @end_offset are -1, then the end of the label will be substituted.
2012  * 
2013  **/
2014 void
2015 eel_editable_label_select_region  (EelEditableLabel *label,
2016 				   gint      start_offset,
2017 				   gint      end_offset)
2018 {
2019   g_return_if_fail (EEL_IS_EDITABLE_LABEL (label));
2020   
2021   if (label->text)
2022     {
2023       if (start_offset < 0)
2024         start_offset = g_utf8_strlen (label->text, -1);
2025       
2026       if (end_offset < 0)
2027         end_offset = g_utf8_strlen (label->text, -1);
2028       
2029       eel_editable_label_select_region_index (label,
2030 					      g_utf8_offset_to_pointer (label->text, start_offset) - label->text,
2031 					      g_utf8_offset_to_pointer (label->text, end_offset) - label->text);
2032     }
2033 }
2034 
2035 /**
2036  * eel_editable_label_get_selection_bounds:
2037  * @label: a #EelEditableLabel
2038  * @start: return location for start of selection, as a character offset
2039  * @end: return location for end of selection, as a character offset
2040  * 
2041  * Gets the selected range of characters in the label, returning %TRUE
2042  * if there's a selection.
2043  * 
2044  * Return value: %TRUE if selection is non-empty
2045  **/
2046 gboolean
2047 eel_editable_label_get_selection_bounds (EelEditableLabel  *label,
2048 					 gint      *start,
2049 					 gint      *end)
2050 {
2051   gint start_index, end_index;
2052   gint start_offset, end_offset;
2053   gint len;
2054   
2055   g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), FALSE);
2056 
2057       
2058   start_index = MIN (label->selection_anchor,
2059 		     label->selection_end);
2060   end_index = MAX (label->selection_anchor,
2061 		   label->selection_end);
2062 
2063   len = strlen (label->text);
2064   
2065   if (end_index > len)
2066     end_index = len;
2067   
2068   if (start_index > len)
2069     start_index = len;
2070   
2071   start_offset = g_utf8_strlen (label->text, start_index);
2072   end_offset = g_utf8_strlen (label->text, end_index);
2073   
2074   if (start_offset > end_offset)
2075     {
2076       gint tmp = start_offset;
2077       start_offset = end_offset;
2078       end_offset = tmp;
2079     }
2080   
2081   if (start)
2082     *start = start_offset;
2083   
2084   if (end)
2085     *end = end_offset;
2086   
2087   return start_offset != end_offset;
2088 }
2089 
2090 
2091 /**
2092  * eel_editable_label_get_layout:
2093  * @label: a #EelEditableLabel
2094  * 
2095  * Gets the #PangoLayout used to display the label.
2096  * The layout is useful to e.g. convert text positions to
2097  * pixel positions, in combination with eel_editable_label_get_layout_offsets().
2098  * The returned layout is owned by the label so need not be
2099  * freed by the caller.
2100  * 
2101  * Return value: the #PangoLayout for this label
2102  **/
2103 PangoLayout*
2104 eel_editable_label_get_layout (EelEditableLabel *label)
2105 {
2106   g_return_val_if_fail (EEL_IS_EDITABLE_LABEL (label), NULL);
2107 
2108   eel_editable_label_ensure_layout (label, TRUE);
2109 
2110   return label->layout;
2111 }
2112 
2113 /**
2114  * eel_editable_label_get_layout_offsets:
2115  * @label: a #EelEditableLabel
2116  * @x: location to store X offset of layout, or %NULL
2117  * @y: location to store Y offset of layout, or %NULL
2118  *
2119  * Obtains the coordinates where the label will draw the #PangoLayout
2120  * representing the text in the label; useful to convert mouse events
2121  * into coordinates inside the #PangoLayout, e.g. to take some action
2122  * if some part of the label is clicked. Of course you will need to
2123  * create a #GtkEventBox to receive the events, and pack the label
2124  * inside it, since labels are a #GTK_NO_WINDOW widget. Remember
2125  * when using the #PangoLayout functions you need to convert to
2126  * and from pixels using PANGO_PIXELS() or #PANGO_SCALE.
2127  * 
2128  **/
2129 void
2130 eel_editable_label_get_layout_offsets (EelEditableLabel *label,
2131 				       gint     *x,
2132 				       gint     *y)
2133 {
2134   g_return_if_fail (EEL_IS_EDITABLE_LABEL (label));
2135   
2136   get_layout_location (label, x, y);
2137 }
2138 
2139 static void
2140 eel_editable_label_pend_cursor_blink (EelEditableLabel *label)
2141 {
2142   /* TODO */
2143 }
2144 
2145 static void
2146 eel_editable_label_check_cursor_blink (EelEditableLabel *label)
2147 {
2148   /* TODO */
2149 }
2150 
2151 static gint
2152 eel_editable_label_key_press (GtkWidget   *widget,
2153 			      GdkEventKey *event)
2154 {
2155   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
2156 
2157   eel_editable_label_pend_cursor_blink (label);
2158 
2159   if (gtk_im_context_filter_keypress (label->im_context, event))
2160     {
2161       /*TODO eel_editable_label_obscure_mouse_cursor (label);*/
2162       label->need_im_reset = TRUE;
2163       return TRUE;
2164     }
2165 
2166   if (GTK_WIDGET_CLASS (eel_editable_label_parent_class)->key_press_event (widget, event))
2167     /* Activate key bindings
2168      */
2169     return TRUE;
2170 
2171   return FALSE;
2172 }
2173 
2174 static gint
2175 eel_editable_label_key_release (GtkWidget   *widget,
2176 				GdkEventKey *event)
2177 {
2178   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
2179 
2180   if (gtk_im_context_filter_keypress (label->im_context, event))
2181     {
2182       label->need_im_reset = TRUE;
2183       return TRUE;
2184     }
2185 
2186   return GTK_WIDGET_CLASS (eel_editable_label_parent_class)->key_release_event (widget, event);
2187 }
2188 
2189 static void
2190 eel_editable_label_keymap_direction_changed (GdkKeymap *keymap,
2191 					     EelEditableLabel  *label)
2192 {
2193   gtk_widget_queue_draw (GTK_WIDGET (label));
2194 }
2195 
2196 static gint
2197 eel_editable_label_focus_in (GtkWidget     *widget,
2198 			     GdkEventFocus *event)
2199 {
2200   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
2201   
2202   gtk_widget_queue_draw (widget);
2203   
2204   label->need_im_reset = TRUE;
2205   gtk_im_context_focus_in (label->im_context);
2206 
2207   g_signal_connect (gdk_keymap_get_default (),
2208 		    "direction_changed",
2209 		    G_CALLBACK (eel_editable_label_keymap_direction_changed), label);
2210 
2211   eel_editable_label_check_cursor_blink (label);
2212 
2213   return FALSE;
2214 }
2215 
2216 static gint
2217 eel_editable_label_focus_out (GtkWidget     *widget,
2218 			      GdkEventFocus *event)
2219 {
2220   EelEditableLabel *label = EEL_EDITABLE_LABEL (widget);
2221   
2222   gtk_widget_queue_draw (widget);
2223 
2224   label->need_im_reset = TRUE;
2225   gtk_im_context_focus_out (label->im_context);
2226 
2227   eel_editable_label_check_cursor_blink (label);
2228   
2229   g_signal_handlers_disconnect_by_func (gdk_keymap_get_default (),
2230                                         (gpointer) eel_editable_label_keymap_direction_changed,
2231                                         label);
2232   
2233   return FALSE;
2234 }
2235 
2236 static void
2237 eel_editable_label_delete_text (EelEditableLabel *label,
2238 				int start_pos,
2239 				int end_pos)
2240 {
2241   int anchor, end;
2242   
2243   if (start_pos < 0)
2244     start_pos = 0;
2245   if (end_pos < 0 || end_pos > label->n_bytes)
2246     end_pos = label->n_bytes;
2247   
2248   if (start_pos < end_pos)
2249     {
2250       g_memmove (label->text + start_pos, label->text + end_pos, label->n_bytes + 1 - end_pos);
2251       label->n_bytes -= (end_pos - start_pos);
2252 
2253       anchor = label->selection_anchor;
2254       if (anchor > start_pos)
2255 	anchor -= MIN (anchor, end_pos) - start_pos;
2256 
2257       end = label->selection_end;
2258       if (end > start_pos)
2259 	end -= MIN (end, end_pos) - start_pos;
2260       
2261       /* We might have changed the selection */
2262       eel_editable_label_select_region_index (label, anchor, end);
2263       
2264       eel_editable_label_recompute (label);  
2265       gtk_widget_queue_resize (GTK_WIDGET (label));
2266       
2267       g_object_notify (G_OBJECT (label), "text");
2268       g_signal_emit_by_name (GTK_EDITABLE (label), "changed");
2269     }
2270 }
2271 
2272 static void
2273 eel_editable_label_insert_text (EelEditableLabel *label,
2274 				const gchar *new_text,
2275 				gint         new_text_length,
2276 				gint        *index)
2277 {
2278   if (new_text_length + label->n_bytes + 1 > label->text_size)
2279     {
2280       while (new_text_length + label->n_bytes + 1 > label->text_size)
2281 	{
2282 	  if (label->text_size == 0)
2283 	    label->text_size = 16;
2284 	  else
2285 	    label->text_size *= 2;
2286 	}
2287 
2288       label->text = g_realloc (label->text, label->text_size);
2289     }
2290 
2291   g_object_freeze_notify (G_OBJECT (label));
2292 
2293   g_memmove (label->text + *index + new_text_length, label->text + *index, label->n_bytes - *index);
2294   memcpy (label->text + *index, new_text, new_text_length);
2295   
2296   label->n_bytes += new_text_length;
2297 
2298   /* NUL terminate for safety and convenience */
2299   label->text[label->n_bytes] = '\0';
2300 
2301   g_object_notify (G_OBJECT (label), "text");
2302 
2303   if (label->selection_anchor > *index)
2304     {
2305       g_object_notify (G_OBJECT (label), "cursor_position");
2306       g_object_notify (G_OBJECT (label), "selection_bound");
2307       label->selection_anchor += new_text_length;
2308     }
2309   
2310   if (label->selection_end > *index)
2311     {
2312       label->selection_end += new_text_length;
2313       g_object_notify (G_OBJECT (label), "selection_bound");
2314     }
2315 
2316   *index += new_text_length;
2317 
2318   eel_editable_label_recompute (label);  
2319   gtk_widget_queue_resize (GTK_WIDGET (label));
2320 
2321   g_object_thaw_notify (G_OBJECT (label));
2322   g_signal_emit_by_name (GTK_EDITABLE (label), "changed");
2323 }
2324 
2325 /* Used for im_commit_cb and inserting Unicode chars */
2326 static void
2327 eel_editable_label_enter_text (EelEditableLabel *label,
2328 			       const gchar    *str)
2329 {
2330   GtkEditable *editable = GTK_EDITABLE (label);
2331   gint tmp_pos;
2332   gboolean old_need_im_reset;
2333 
2334   /* Never reset the im while commiting, as that resets possible im state */
2335   old_need_im_reset = label->need_im_reset;
2336   label->need_im_reset = FALSE;
2337 
2338   if (label->selection_end != label->selection_anchor)
2339     gtk_editable_delete_selection (editable);
2340   else
2341     {
2342       if (label->overwrite_mode)
2343         eel_editable_label_delete_from_cursor (label, GTK_DELETE_CHARS, 1);
2344     }
2345   
2346   tmp_pos = g_utf8_pointer_to_offset (label->text,
2347                                       label->text + label->selection_anchor);
2348   gtk_editable_insert_text (GTK_EDITABLE (label), str, strlen (str), &tmp_pos);
2349   tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text;
2350   eel_editable_label_select_region_index (label, tmp_pos, tmp_pos);
2351 
2352   label->need_im_reset = old_need_im_reset;
2353 }
2354 
2355 /* IM Context Callbacks
2356  */
2357 
2358 static void
2359 eel_editable_label_commit_cb (GtkIMContext *context,
2360 			      const gchar  *str,
2361 			      EelEditableLabel  *label)
2362 {
2363   eel_editable_label_enter_text (label, str);
2364 }
2365 
2366 static void 
2367 eel_editable_label_preedit_changed_cb (GtkIMContext *context,
2368 				       EelEditableLabel  *label)
2369 {
2370   gchar *preedit_string;
2371   gint cursor_pos;
2372   
2373   gtk_im_context_get_preedit_string (label->im_context,
2374 				     &preedit_string, NULL,
2375 				     &cursor_pos);
2376   label->preedit_length = strlen (preedit_string);
2377   cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
2378   label->preedit_cursor = cursor_pos;
2379   g_free (preedit_string);
2380 
2381   eel_editable_label_recompute (label);  
2382   gtk_widget_queue_resize (GTK_WIDGET (label));
2383 }
2384 
2385 static gboolean
2386 eel_editable_label_retrieve_surrounding_cb (GtkIMContext *context,
2387 					    EelEditableLabel  *label)
2388 {
2389   gtk_im_context_set_surrounding (context,
2390 				  label->text,
2391 				  strlen (label->text) + 1,
2392 				  label->selection_end);
2393 
2394   return TRUE;
2395 }
2396 
2397 static gboolean
2398 eel_editable_label_delete_surrounding_cb (GtkIMContext *slave,
2399 					  gint          offset,
2400 					  gint          n_chars,
2401 					  EelEditableLabel  *label)
2402 {
2403   gint current_pos;
2404 
2405   current_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor);
2406   gtk_editable_delete_text (GTK_EDITABLE (label), 
2407 			    current_pos + offset, 
2408 			    current_pos + offset + n_chars);
2409 
2410   return TRUE;
2411 }
2412 
2413 static gboolean
2414 eel_editable_label_focus (GtkWidget         *widget,
2415 			  GtkDirectionType   direction)
2416 {
2417   /* We never want to be in the tab chain */
2418   return FALSE;
2419 }
2420 
2421 /* Compute the X position for an offset that corresponds to the "more important
2422  * cursor position for that offset. We use this when trying to guess to which
2423  * end of the selection we should go to when the user hits the left or
2424  * right arrow key.
2425  */
2426 static void
2427 get_better_cursor (EelEditableLabel *label,
2428 		   gint      index,
2429 		   gint      *x,
2430 		   gint      *y)
2431 {
2432   GtkTextDirection keymap_direction =
2433     (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2434     GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2435   GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
2436   gboolean split_cursor;
2437   PangoRectangle strong_pos, weak_pos;
2438   
2439   g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2440 		"gtk-split-cursor", &split_cursor,
2441 		NULL);
2442 
2443   eel_editable_label_get_cursor_pos (label, &strong_pos, &weak_pos);
2444 
2445   if (split_cursor)
2446     {
2447       *x = strong_pos.x / PANGO_SCALE;
2448       *y = strong_pos.y / PANGO_SCALE;
2449     }
2450   else
2451     {
2452       if (keymap_direction == widget_direction)
2453 	{
2454 	  *x = strong_pos.x / PANGO_SCALE;
2455 	  *y = strong_pos.y / PANGO_SCALE;
2456 	}
2457       else
2458 	{
2459 	  *x = weak_pos.x / PANGO_SCALE;
2460 	  *y = weak_pos.y / PANGO_SCALE;
2461 	}
2462     }
2463 }
2464 
2465 
2466 static gint
2467 eel_editable_label_move_logically (EelEditableLabel *label,
2468 				   gint      start,
2469 				   gint      count)
2470 {
2471   gint offset = g_utf8_pointer_to_offset (label->text,
2472 					  label->text + start);
2473 
2474   if (label->text)
2475     {
2476       PangoLogAttr *log_attrs;
2477       gint n_attrs;
2478       gint length;
2479 
2480       eel_editable_label_ensure_layout (label, FALSE);
2481       
2482       length = g_utf8_strlen (label->text, -1);
2483 
2484       pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
2485 
2486       while (count > 0 && offset < length)
2487 	{
2488 	  do
2489 	    offset++;
2490 	  while (offset < length && !log_attrs[offset].is_cursor_position);
2491 	  
2492 	  count--;
2493 	}
2494       while (count < 0 && offset > 0)
2495 	{
2496 	  do
2497 	    offset--;
2498 	  while (offset > 0 && !log_attrs[offset].is_cursor_position);
2499 	  
2500 	  count++;
2501 	}
2502       
2503       g_free (log_attrs);
2504     }
2505 
2506   return g_utf8_offset_to_pointer (label->text, offset) - label->text;
2507 }
2508 
2509 static gint
2510 eel_editable_label_move_visually (EelEditableLabel *label,
2511 				  gint      start,
2512 				  gint      count)
2513 {
2514   gint index;
2515 
2516   index = start;
2517   
2518   while (count != 0)
2519     {
2520       int new_index, new_trailing;
2521       gboolean split_cursor;
2522       gboolean strong;
2523 
2524       eel_editable_label_ensure_layout (label, FALSE);
2525 
2526       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
2527 		    "gtk-split-cursor", &split_cursor,
2528 		    NULL);
2529 
2530       if (split_cursor)
2531 	strong = TRUE;
2532       else
2533 	{
2534 	  GtkTextDirection keymap_direction =
2535 	    (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
2536 	    GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
2537 
2538 	  strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
2539 	}
2540       
2541       if (count > 0)
2542 	{
2543 	  pango_layout_move_cursor_visually (label->layout, strong, index, 0, 1, &new_index, &new_trailing);
2544 	  count--;
2545 	}
2546       else
2547 	{
2548 	  pango_layout_move_cursor_visually (label->layout, strong, index, 0, -1, &new_index, &new_trailing);
2549 	  count++;
2550 	}
2551 
2552       if (new_index < 0 || new_index == G_MAXINT)
2553 	break;
2554 
2555       index = new_index;
2556       
2557       while (new_trailing--)
2558 	index = g_utf8_next_char (label->text + new_index) - label->text;
2559     }
2560   
2561   return index;
2562 }
2563 
2564 static gint
2565 eel_editable_label_move_line (EelEditableLabel *label,
2566 			      gint      start,
2567 			      gint      count)
2568 {
2569   int n_lines, i;
2570   int x;
2571   PangoLayoutLine *line;
2572   int index;
2573   
2574   eel_editable_label_ensure_layout (label, FALSE);
2575 
2576   n_lines = pango_layout_get_line_count (label->layout);
2577 
2578   for (i = 0; i < n_lines; i++)
2579     {
2580       line = pango_layout_get_line (label->layout, i);
2581       if (start >= line->start_index &&
2582 	  start <= line->start_index + line->length)
2583 	{
2584 	  pango_layout_line_index_to_x (line, start, FALSE, &x);
2585 	  break;
2586 	}
2587     }
2588   if (i == n_lines)
2589     i = n_lines - 1;
2590   
2591   i += count;
2592   i = CLAMP (i, 0, n_lines - 1);
2593 
2594   line = pango_layout_get_line (label->layout, i);
2595   if (pango_layout_line_x_to_index (line,
Function call argument is an uninitialized value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

2596 x, 2597 &index, NULL)) 2598 return index; 2599 else 2600 { 2601 if (i == n_lines - 1) 2602 return line->start_index + line->length; 2603 else 2604 return line->start_index + line->length - 1; 2605 } 2606 } 2607 2608 static gint 2609 eel_editable_label_move_forward_word (EelEditableLabel *label, 2610 gint start) 2611 { 2612 gint new_pos = g_utf8_pointer_to_offset (label->text, 2613 label->text + start); 2614 gint length; 2615 2616 length = g_utf8_strlen (label->text, -1); 2617 if (new_pos < length) 2618 { 2619 PangoLogAttr *log_attrs; 2620 gint n_attrs; 2621 2622 eel_editable_label_ensure_layout (label, FALSE); 2623 2624 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); 2625 2626 /* Find the next word end, 2627 (remember, n_attrs is one more than the number of of chars) */ 2628 new_pos++; 2629 while (new_pos < (n_attrs - 1) && !log_attrs[new_pos].is_word_end) 2630 new_pos++; 2631 2632 g_free (log_attrs); 2633 } 2634 2635 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text; 2636 } 2637 2638 2639 static gint 2640 eel_editable_label_move_backward_word (EelEditableLabel *label, 2641 gint start) 2642 { 2643 gint new_pos = g_utf8_pointer_to_offset (label->text, 2644 label->text + start); 2645 2646 if (new_pos > 0) 2647 { 2648 PangoLogAttr *log_attrs; 2649 gint n_attrs; 2650 2651 eel_editable_label_ensure_layout (label, FALSE); 2652 2653 pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs); 2654 2655 new_pos -= 1; 2656 2657 /* Find the previous word beginning */ 2658 while (new_pos > 0 && !log_attrs[new_pos].is_word_start) 2659 new_pos--; 2660 2661 g_free (log_attrs); 2662 } 2663 2664 return g_utf8_offset_to_pointer (label->text, new_pos) - label->text; 2665 } 2666 2667 static void 2668 eel_editable_label_move_cursor (EelEditableLabel *label, 2669 GtkMovementStep step, 2670 gint count, 2671 gboolean extend_selection) 2672 { 2673 gint new_pos; 2674 2675 new_pos = label->selection_end; 2676 2677 if (label->selection_end != label->selection_anchor && 2678 !extend_selection) 2679 { 2680 /* If we have a current selection and aren't extending it, move to the 2681 * start/or end of the selection as appropriate 2682 */ 2683 switch (step) 2684 { 2685 case GTK_MOVEMENT_DISPLAY_LINES: 2686 case GTK_MOVEMENT_VISUAL_POSITIONS: 2687 { 2688 gint end_x, end_y; 2689 gint anchor_x, anchor_y; 2690 gboolean end_is_left; 2691 2692 get_better_cursor (label, label->selection_end, &end_x, &end_y); 2693 get_better_cursor (label, label->selection_anchor, &anchor_x, &anchor_y); 2694 2695 end_is_left = (end_y < anchor_y) || (end_y == anchor_y && end_x < anchor_x); 2696 2697 if (count < 0) 2698 new_pos = end_is_left ? label->selection_end : label->selection_anchor; 2699 else 2700 new_pos = !end_is_left ? label->selection_end : label->selection_anchor; 2701 2702 break; 2703 } 2704 case GTK_MOVEMENT_LOGICAL_POSITIONS: 2705 case GTK_MOVEMENT_WORDS: 2706 if (count < 0) 2707 new_pos = MIN (label->selection_end, label->selection_anchor); 2708 else 2709 new_pos = MAX (label->selection_end, label->selection_anchor); 2710 break; 2711 case GTK_MOVEMENT_DISPLAY_LINE_ENDS: 2712 case GTK_MOVEMENT_PARAGRAPH_ENDS: 2713 case GTK_MOVEMENT_BUFFER_ENDS: 2714 /* FIXME: Can do better here */ 2715 new_pos = count < 0 ? 0 : strlen (label->text); 2716 break; 2717 case GTK_MOVEMENT_PARAGRAPHS: 2718 case GTK_MOVEMENT_PAGES: 2719 break; 2720 default: 2721 g_assert_not_reached (); 2722 break; 2723 } 2724 } 2725 else 2726 { 2727 switch (step) 2728 { 2729 case GTK_MOVEMENT_LOGICAL_POSITIONS: 2730 new_pos = eel_editable_label_move_logically (label, new_pos, count); 2731 break; 2732 case GTK_MOVEMENT_VISUAL_POSITIONS: 2733 new_pos = eel_editable_label_move_visually (label, new_pos, count); 2734 break; 2735 case GTK_MOVEMENT_WORDS: 2736 while (count > 0) 2737 { 2738 new_pos = eel_editable_label_move_forward_word (label, new_pos); 2739 count--; 2740 } 2741 while (count < 0) 2742 { 2743 new_pos = eel_editable_label_move_backward_word (label, new_pos); 2744 count++; 2745 } 2746 break; 2747 case GTK_MOVEMENT_DISPLAY_LINE_ENDS: 2748 case GTK_MOVEMENT_PARAGRAPH_ENDS: 2749 case GTK_MOVEMENT_BUFFER_ENDS: 2750 /* FIXME: Can do better here */ 2751 new_pos = count < 0 ? 0 : strlen (label->text); 2752 break; 2753 case GTK_MOVEMENT_DISPLAY_LINES: 2754 new_pos = eel_editable_label_move_line (label, new_pos, count); 2755 break; 2756 break; 2757 case GTK_MOVEMENT_PARAGRAPHS: 2758 case GTK_MOVEMENT_PAGES: 2759 break; 2760 default: 2761 g_assert_not_reached (); 2762 break; 2763 } 2764 } 2765 2766 if (extend_selection) 2767 eel_editable_label_select_region_index (label, 2768 label->selection_anchor, 2769 new_pos); 2770 else 2771 eel_editable_label_select_region_index (label, new_pos, new_pos); 2772 } 2773 2774 static void 2775 eel_editable_label_reset_im_context (EelEditableLabel *label) 2776 { 2777 if (label->need_im_reset) 2778 { 2779 label->need_im_reset = 0; 2780 gtk_im_context_reset (label->im_context); 2781 } 2782 } 2783 2784 2785 static void 2786 eel_editable_label_delete_from_cursor (EelEditableLabel *label, 2787 GtkDeleteType type, 2788 gint count) 2789 { 2790 GtkEditable *editable = GTK_EDITABLE (label); 2791 gint start_pos = label->selection_anchor; 2792 gint end_pos = label->selection_anchor; 2793 2794 eel_editable_label_reset_im_context (label); 2795 2796 if (label->selection_anchor != label->selection_end) 2797 { 2798 gtk_editable_delete_selection (editable); 2799 return; 2800 } 2801 2802 switch (type) 2803 { 2804 case GTK_DELETE_CHARS: 2805 end_pos = eel_editable_label_move_logically (label, start_pos, count); 2806 start_pos = g_utf8_pointer_to_offset (label->text, label->text + start_pos); 2807 end_pos = g_utf8_pointer_to_offset (label->text, label->text + end_pos); 2808 gtk_editable_delete_text (GTK_EDITABLE (label), MIN (start_pos, end_pos), MAX (start_pos, end_pos)); 2809 break; 2810 case GTK_DELETE_WORDS: 2811 if (count < 0) 2812 { 2813 /* Move to end of current word, or if not on a word, end of previous word */ 2814 end_pos = eel_editable_label_move_backward_word (label, end_pos); 2815 end_pos = eel_editable_label_move_forward_word (label, end_pos); 2816 } 2817 else if (count > 0) 2818 { 2819 /* Move to beginning of current word, or if not on a word, begining of next word */ 2820 start_pos = eel_editable_label_move_forward_word (label, start_pos); 2821 start_pos = eel_editable_label_move_backward_word (label, start_pos); 2822 } 2823 2824 /* Fall through */ 2825 case GTK_DELETE_WORD_ENDS: 2826 while (count < 0) 2827 { 2828 start_pos = eel_editable_label_move_backward_word (label, start_pos); 2829 count++; 2830 } 2831 while (count > 0) 2832 { 2833 end_pos = eel_editable_label_move_forward_word (label, end_pos); 2834 count--; 2835 } 2836 start_pos = g_utf8_pointer_to_offset (label->text, label->text + start_pos); 2837 end_pos = g_utf8_pointer_to_offset (label->text, label->text + end_pos); 2838 2839 gtk_editable_delete_text (GTK_EDITABLE (label), start_pos, end_pos); 2840 break; 2841 case GTK_DELETE_DISPLAY_LINE_ENDS: 2842 case GTK_DELETE_PARAGRAPH_ENDS: 2843 end_pos = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); 2844 if (count < 0) 2845 gtk_editable_delete_text (GTK_EDITABLE (label), 0, end_pos); 2846 else 2847 gtk_editable_delete_text (GTK_EDITABLE (label), end_pos, -1); 2848 break; 2849 case GTK_DELETE_DISPLAY_LINES: 2850 case GTK_DELETE_PARAGRAPHS: 2851 gtk_editable_delete_text (GTK_EDITABLE (label), 0, -1); 2852 break; 2853 case GTK_DELETE_WHITESPACE: 2854 /* TODO eel_editable_label_delete_whitespace (label); */ 2855 break; 2856 } 2857 2858 eel_editable_label_pend_cursor_blink (label); 2859 } 2860 2861 2862 static void 2863 eel_editable_label_copy_clipboard (EelEditableLabel *label) 2864 { 2865 if (label->text) 2866 { 2867 gint start, end; 2868 gint len; 2869 2870 start = MIN (label->selection_anchor, 2871 label->selection_end); 2872 end = MAX (label->selection_anchor, 2873 label->selection_end); 2874 2875 len = strlen (label->text); 2876 2877 if (end > len) 2878 end = len; 2879 2880 if (start > len) 2881 start = len; 2882 2883 if (start != end) 2884 gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 2885 label->text + start, end - start); 2886 } 2887 } 2888 2889 static void 2890 eel_editable_label_cut_clipboard (EelEditableLabel *label) 2891 { 2892 if (label->text) 2893 { 2894 gint start, end; 2895 gint len; 2896 2897 start = MIN (label->selection_anchor, 2898 label->selection_end); 2899 end = MAX (label->selection_anchor, 2900 label->selection_end); 2901 2902 len = strlen (label->text); 2903 2904 if (end > len) 2905 end = len; 2906 2907 if (start > len) 2908 start = len; 2909 2910 if (start != end) 2911 { 2912 gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), 2913 label->text + start, end - start); 2914 start = g_utf8_pointer_to_offset (label->text, label->text + start); 2915 end = g_utf8_pointer_to_offset (label->text, label->text + end); 2916 gtk_editable_delete_text (GTK_EDITABLE (label), start, end); 2917 } 2918 } 2919 } 2920 2921 static void 2922 paste_received (GtkClipboard *clipboard, 2923 const gchar *text, 2924 gpointer data) 2925 { 2926 EelEditableLabel *label = EEL_EDITABLE_LABEL (data); 2927 GtkEditable *editable = GTK_EDITABLE (label); 2928 gint tmp_pos; 2929 2930 if (text) 2931 { 2932 if (label->selection_end != label->selection_anchor) 2933 gtk_editable_delete_selection (editable); 2934 2935 tmp_pos = g_utf8_pointer_to_offset (label->text, 2936 label->text + label->selection_anchor); 2937 gtk_editable_insert_text (GTK_EDITABLE (label), text, strlen (text), &tmp_pos); 2938 tmp_pos = g_utf8_offset_to_pointer (label->text, tmp_pos) - label->text; 2939 eel_editable_label_select_region_index (label, tmp_pos, tmp_pos); 2940 } 2941 2942 g_object_unref (G_OBJECT (label)); 2943 } 2944 2945 static void 2946 eel_editable_label_paste (EelEditableLabel *label, 2947 GdkAtom selection) 2948 { 2949 g_object_ref (G_OBJECT (label)); 2950 gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (label), selection), 2951 paste_received, label); 2952 } 2953 2954 static void 2955 eel_editable_label_paste_clipboard (EelEditableLabel *label) 2956 { 2957 eel_editable_label_paste (label, GDK_NONE); 2958 } 2959 2960 static void 2961 eel_editable_label_select_all (EelEditableLabel *label) 2962 { 2963 eel_editable_label_select_region_index (label, 0, strlen (label->text)); 2964 } 2965 2966 /* Quick hack of a popup menu 2967 */ 2968 static void 2969 activate_cb (GtkWidget *menuitem, 2970 EelEditableLabel *label) 2971 { 2972 const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal"); 2973 g_signal_emit_by_name (label, signal); 2974 } 2975 2976 static void 2977 append_action_signal (EelEditableLabel *label, 2978 GtkWidget *menu, 2979 const gchar *stock_id, 2980 const gchar *signal, 2981 gboolean sensitive) 2982 { 2983 GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL); 2984 2985 g_object_set_data (G_OBJECT (menuitem), "gtk-signal", (char *)signal); 2986 g_signal_connect (menuitem, "activate", 2987 G_CALLBACK (activate_cb), label); 2988 2989 gtk_widget_set_sensitive (menuitem, sensitive); 2990 2991 gtk_widget_show (menuitem); 2992 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); 2993 } 2994 2995 static void 2996 popup_menu_detach (GtkWidget *attach_widget, 2997 GtkMenu *menu) 2998 { 2999 EelEditableLabel *label; 3000 label = EEL_EDITABLE_LABEL (attach_widget); 3001 3002 label->popup_menu = NULL; 3003 } 3004 3005 static void 3006 popup_position_func (GtkMenu *menu, 3007 gint *x, 3008 gint *y, 3009 gboolean *push_in, 3010 gpointer user_data) 3011 { 3012 EelEditableLabel *label; 3013 GtkWidget *widget; 3014 GtkRequisition req; 3015 GtkAllocation allocation; 3016 3017 label = EEL_EDITABLE_LABEL (user_data); 3018 widget = GTK_WIDGET (label); 3019 3020 g_assert (gtk_widget_get_realized (widget)); 3021 3022 gdk_window_get_origin (label->text_area, x, y); 3023 3024 /*gtk_widget_size_request (label->popup_menu, &req);*/ 3025 gtk_widget_get_requisition (widget, &req); 3026 gtk_widget_get_allocation (widget, &allocation); 3027 3028 *x += allocation.width / 2; 3029 *y += allocation.height; 3030 3031 *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width)); 3032 *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height)); 3033 } 3034 3035 static void 3036 eel_editable_label_toggle_overwrite (EelEditableLabel *label) 3037 { 3038 label->overwrite_mode = !label->overwrite_mode; 3039 gtk_widget_queue_draw (GTK_WIDGET (label)); 3040 } 3041 3042 typedef struct 3043 { 3044 EelEditableLabel *label; 3045 gint button; 3046 guint time; 3047 } PopupInfo; 3048 3049 static void 3050 popup_targets_received (GtkClipboard *clipboard, 3051 GtkSelectionData *data, 3052 gpointer user_data) 3053 { 3054 GtkWidget *menuitem, *submenu; 3055 gboolean have_selection; 3056 gboolean clipboard_contains_text; 3057 PopupInfo *info; 3058 EelEditableLabel *label; 3059 3060 info = user_data; 3061 label = info->label; 3062 3063 if (gtk_widget_get_realized (GTK_WIDGET (label))) 3064 { 3065 if (label->popup_menu) 3066 gtk_widget_destroy (label->popup_menu); 3067 3068 label->popup_menu = gtk_menu_new (); 3069 3070 gtk_menu_attach_to_widget (GTK_MENU (label->popup_menu), 3071 GTK_WIDGET (label), 3072 popup_menu_detach); 3073 3074 have_selection = 3075 label->selection_anchor != label->selection_end; 3076 3077 clipboard_contains_text = gtk_selection_data_targets_include_text (data); 3078 3079 append_action_signal (label, label->popup_menu, GTK_STOCK_CUT, "cut_clipboard", 3080 have_selection); 3081 append_action_signal (label, label->popup_menu, GTK_STOCK_COPY, "copy_clipboard", 3082 have_selection); 3083 append_action_signal (label, label->popup_menu, GTK_STOCK_PASTE, "paste_clipboard", 3084 clipboard_contains_text); 3085 3086 menuitem = gtk_menu_item_new_with_label (_("Select All")); 3087 g_signal_connect_object (menuitem, "activate", 3088 G_CALLBACK (eel_editable_label_select_all), label, 3089 G_CONNECT_SWAPPED); 3090 gtk_widget_show (menuitem); 3091 gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); 3092 3093 menuitem = gtk_separator_menu_item_new (); 3094 gtk_widget_show (menuitem); 3095 gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); 3096 3097 menuitem = gtk_menu_item_new_with_label (_("Input Methods")); 3098 gtk_widget_show (menuitem); 3099 submenu = gtk_menu_new (); 3100 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); 3101 3102 gtk_menu_shell_append (GTK_MENU_SHELL (label->popup_menu), menuitem); 3103 3104 gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (label->im_context), 3105 GTK_MENU_SHELL (submenu)); 3106 3107 g_signal_emit (label, 3108 signals[POPULATE_POPUP], 0, 3109 label->popup_menu); 3110 3111 if (info->button) 3112 gtk_menu_popup (GTK_MENU (label->popup_menu), NULL, NULL, 3113 NULL, NULL, 3114 info->button, info->time); 3115 else 3116 { 3117 gtk_menu_popup (GTK_MENU (label->popup_menu), NULL, NULL, 3118 popup_position_func, label, 3119 info->button, info->time); 3120 gtk_menu_shell_select_first (GTK_MENU_SHELL (label->popup_menu), FALSE); 3121 } 3122 } 3123 3124 g_object_unref (label); 3125 g_free (info); 3126 } 3127 3128 static void 3129 eel_editable_label_do_popup (EelEditableLabel *label, 3130 GdkEventButton *event) 3131 { 3132 PopupInfo *info = g_new (PopupInfo, 1); 3133 3134 /* In order to know what entries we should make sensitive, we 3135 * ask for the current targets of the clipboard, and when 3136 * we get them, then we actually pop up the menu. 3137 */ 3138 info->label = g_object_ref (label); 3139 3140 if (event) 3141 { 3142 info->button = event->button; 3143 info->time = event->time; 3144 } 3145 else 3146 { 3147 info->button = 0; 3148 info->time = gtk_get_current_event_time (); 3149 } 3150 3151 gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (label), GDK_SELECTION_CLIPBOARD), 3152 gdk_atom_intern ("TARGETS", FALSE), 3153 popup_targets_received, 3154 info); 3155 } 3156 3157 /************ Editable implementation ****************/ 3158 3159 static void 3160 editable_insert_text_emit (GtkEditable *editable, 3161 const gchar *new_text, 3162 gint new_text_length, 3163 gint *position) 3164 { 3165 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3166 gchar buf[64]; 3167 gchar *text; 3168 int text_length; 3169 3170 text_length = g_utf8_strlen (label->text, -1); 3171 3172 if (*position < 0 || *position > text_length) 3173 *position = text_length; 3174 3175 g_object_ref (G_OBJECT (editable)); 3176 3177 if (new_text_length <= 63) 3178 text = buf; 3179 else 3180 text = g_new (gchar, new_text_length + 1); 3181 3182 text[new_text_length] = '\0'; 3183 strncpy (text, new_text, new_text_length); 3184 3185 g_signal_emit_by_name (editable, "insert_text", text, new_text_length, position); 3186 3187 if (new_text_length > 63) 3188 g_free (text); 3189 3190 g_object_unref (G_OBJECT (editable)); 3191 } 3192 3193 static void 3194 editable_delete_text_emit (GtkEditable *editable, 3195 gint start_pos, 3196 gint end_pos) 3197 { 3198 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3199 int text_length; 3200 3201 text_length = g_utf8_strlen (label->text, -1); 3202 3203 if (end_pos < 0 || end_pos > text_length) 3204 end_pos = text_length; 3205 if (start_pos < 0) 3206 start_pos = 0; 3207 if (start_pos > end_pos) 3208 start_pos = end_pos; 3209 3210 g_object_ref (G_OBJECT (editable)); 3211 3212 g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos); 3213 3214 g_object_unref (G_OBJECT (editable)); 3215 } 3216 3217 static void 3218 editable_insert_text (GtkEditable *editable, 3219 const gchar *new_text, 3220 gint new_text_length, 3221 gint *position) 3222 { 3223 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3224 gint index; 3225 3226 if (new_text_length < 0) 3227 new_text_length = strlen (new_text); 3228 3229 index = g_utf8_offset_to_pointer (label->text, *position) - label->text; 3230 3231 eel_editable_label_insert_text (label, 3232 new_text, 3233 new_text_length, 3234 &index); 3235 3236 *position = g_utf8_pointer_to_offset (label->text, label->text + index); 3237 } 3238 3239 static void 3240 editable_delete_text (GtkEditable *editable, 3241 gint start_pos, 3242 gint end_pos) 3243 { 3244 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3245 int text_length; 3246 gint start_index, end_index; 3247 3248 text_length = g_utf8_strlen (label->text, -1); 3249 3250 if (end_pos < 0 || end_pos > text_length) 3251 end_pos = text_length; 3252 if (start_pos < 0) 3253 start_pos = 0; 3254 if (start_pos > end_pos) 3255 start_pos = end_pos; 3256 3257 start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text; 3258 end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text; 3259 3260 eel_editable_label_delete_text (label, start_index, end_index); 3261 } 3262 3263 static gchar * 3264 editable_get_chars (GtkEditable *editable, 3265 gint start_pos, 3266 gint end_pos) 3267 { 3268 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3269 int text_length; 3270 gint start_index, end_index; 3271 3272 text_length = g_utf8_strlen (label->text, -1); 3273 3274 if (end_pos < 0 || end_pos > text_length) 3275 end_pos = text_length; 3276 if (start_pos < 0) 3277 start_pos = 0; 3278 if (start_pos > end_pos) 3279 start_pos = end_pos; 3280 3281 start_index = g_utf8_offset_to_pointer (label->text, start_pos) - label->text; 3282 end_index = g_utf8_offset_to_pointer (label->text, end_pos) - label->text; 3283 3284 return g_strndup (label->text + start_index, end_index - start_index); 3285 } 3286 3287 static void 3288 editable_set_selection_bounds (GtkEditable *editable, 3289 gint start, 3290 gint end) 3291 { 3292 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3293 int text_length; 3294 gint start_index, end_index; 3295 3296 text_length = g_utf8_strlen (label->text, -1); 3297 3298 if (end < 0 || end > text_length) 3299 end = text_length; 3300 if (start < 0) 3301 start = text_length; 3302 if (start > text_length) 3303 start = text_length; 3304 3305 eel_editable_label_reset_im_context (label); 3306 3307 start_index = g_utf8_offset_to_pointer (label->text, start) - label->text; 3308 end_index = g_utf8_offset_to_pointer (label->text, end) - label->text; 3309 3310 eel_editable_label_select_region_index (label, start_index, end_index); 3311 } 3312 3313 static gboolean 3314 editable_get_selection_bounds (GtkEditable *editable, 3315 gint *start, 3316 gint *end) 3317 { 3318 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3319 3320 *start = g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); 3321 *end = g_utf8_pointer_to_offset (label->text, label->text + label->selection_end); 3322 3323 return (label->selection_anchor != label->selection_end); 3324 } 3325 3326 static void 3327 editable_real_set_position (GtkEditable *editable, 3328 gint position) 3329 { 3330 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3331 int text_length; 3332 int index; 3333 3334 text_length = g_utf8_strlen (label->text, -1); 3335 3336 if (position < 0 || position > text_length) 3337 position = text_length; 3338 3339 index = g_utf8_offset_to_pointer (label->text, position) - label->text; 3340 3341 if (index != label->selection_anchor || 3342 index != label->selection_end) 3343 { 3344 eel_editable_label_select_region_index (label, index, index); 3345 } 3346 } 3347 3348 static gint 3349 editable_get_position (GtkEditable *editable) 3350 { 3351 EelEditableLabel *label = EEL_EDITABLE_LABEL (editable); 3352 3353 return g_utf8_pointer_to_offset (label->text, label->text + label->selection_anchor); 3354 } 3355 3356 3357 static AtkObjectClass *a11y_parent_class = NULL; 3358 3359 static const char* eel_editable_label_accessible_data = "eel-editable-label-accessible-data"; 3360 3361 /************ Accessible implementation ****************/ 3362 3363 typedef struct { 3364 GailTextUtil *textutil; 3365 gint selection_anchor; 3366 gint selection_end; 3367 gchar *signal_name; 3368 gint position; 3369 gint length; 3370 } EelEditableLabelAccessiblePrivate; 3371 3372 typedef struct 3373 { 3374 EelEditableLabel* label; 3375 gint position; 3376 } EelEditableLabelAccessiblePaste; 3377 3378 3379 static gchar* 3380 eel_editable_label_accessible_get_text (AtkText *text, 3381 gint start_pos, 3382 gint end_pos) 3383 { 3384 GtkWidget *widget; 3385 EelEditableLabelAccessiblePrivate *priv; 3386 3387 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3388 if (widget == NULL) 3389 /* State is defunct */ 3390 return NULL; 3391 3392 priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); 3393 return gail_text_util_get_substring (priv->textutil, start_pos, end_pos); 3394 } 3395 3396 static gunichar 3397 eel_editable_label_accessible_get_character_at_offset (AtkText *text, 3398 gint offset) 3399 { 3400 GtkWidget *widget; 3401 EelEditableLabelAccessiblePrivate *priv; 3402 gchar *string; 3403 gchar *index; 3404 gunichar unichar; 3405 3406 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3407 if (widget == NULL) 3408 /* State is defunct */ 3409 return '\0'; 3410 3411 priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); 3412 string = gail_text_util_get_substring (priv->textutil, 0, -1); 3413 if (offset >= g_utf8_strlen (string, -1)) 3414 { 3415 unichar = '\0'; 3416 } 3417 else 3418 { 3419 index = g_utf8_offset_to_pointer (string, offset); 3420 3421 unichar = g_utf8_get_char(index); 3422 } 3423 3424 g_free(string); 3425 return unichar; 3426 } 3427 3428 static gchar* 3429 eel_editable_label_accessible_get_text_before_offset (AtkText *text, 3430 gint offset, 3431 AtkTextBoundary boundary_type, 3432 gint *start_offset, 3433 gint *end_offset) 3434 { 3435 GtkWidget *widget; 3436 EelEditableLabel *label; 3437 EelEditableLabelAccessiblePrivate *priv; 3438 3439 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3440 if (widget == NULL) 3441 /* State is defunct */ 3442 return NULL; 3443 3444 label = EEL_EDITABLE_LABEL (widget); 3445 priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); 3446 3447 return gail_text_util_get_text (priv->textutil, 3448 eel_editable_label_get_layout (label), 3449 GAIL_BEFORE_OFFSET, 3450 boundary_type, offset, 3451 start_offset, end_offset); 3452 } 3453 3454 static gchar* 3455 eel_editable_label_accessible_get_text_at_offset (AtkText *text, 3456 gint offset, 3457 AtkTextBoundary boundary_type, 3458 gint *start_offset, 3459 gint *end_offset) 3460 { 3461 GtkWidget *widget; 3462 EelEditableLabel *label; 3463 EelEditableLabelAccessiblePrivate *priv; 3464 3465 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3466 if (widget == NULL) 3467 /* State is defunct */ 3468 return NULL; 3469 3470 3471 label = EEL_EDITABLE_LABEL (widget); 3472 priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); 3473 return gail_text_util_get_text (priv->textutil, 3474 eel_editable_label_get_layout (label), 3475 GAIL_AT_OFFSET, 3476 boundary_type, offset, 3477 start_offset, end_offset); 3478 } 3479 3480 static gchar* 3481 eel_editable_label_accessible_get_text_after_offset (AtkText *text, 3482 gint offset, 3483 AtkTextBoundary boundary_type, 3484 gint *start_offset, 3485 gint *end_offset) 3486 { 3487 GtkWidget *widget; 3488 EelEditableLabel *label; 3489 EelEditableLabelAccessiblePrivate *priv; 3490 3491 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3492 if (widget == NULL) 3493 /* State is defunct */ 3494 return NULL; 3495 3496 label = EEL_EDITABLE_LABEL (widget); 3497 priv = g_object_get_data (G_OBJECT (text), eel_editable_label_accessible_data); 3498 return gail_text_util_get_text (priv->textutil, 3499 eel_editable_label_get_layout (label), 3500 GAIL_AFTER_OFFSET, 3501 boundary_type, offset, 3502 start_offset, end_offset); 3503 } 3504 3505 static gint 3506 eel_editable_label_accessible_get_caret_offset (AtkText *text) 3507 { 3508 GtkWidget *widget; 3509 3510 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3511 if (widget == NULL) 3512 /* State is defunct */ 3513 return 0; 3514 3515 return gtk_editable_get_position (GTK_EDITABLE (widget)); 3516 } 3517 3518 static gboolean 3519 eel_editable_label_accessible_set_caret_offset (AtkText *text, gint offset) 3520 { 3521 GtkWidget *widget; 3522 3523 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3524 if (widget == NULL) 3525 /* State is defunct */ 3526 return FALSE; 3527 3528 gtk_editable_set_position (GTK_EDITABLE (widget), offset); 3529 return TRUE; 3530 } 3531 3532 static gint 3533 eel_editable_label_accessible_get_character_count (AtkText *text) 3534 { 3535 GtkWidget *widget; 3536 EelEditableLabel *label; 3537 3538 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3539 if (widget == NULL) 3540 /* State is defunct */ 3541 return 0; 3542 3543 label = EEL_EDITABLE_LABEL (widget); 3544 return g_utf8_strlen (eel_editable_label_get_text (label), -1); 3545 } 3546 3547 static gint 3548 eel_editable_label_accessible_get_n_selections (AtkText *text) 3549 { 3550 GtkWidget *widget; 3551 EelEditableLabel *label; 3552 gint select_start, select_end; 3553 3554 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3555 if (widget == NULL) 3556 /* State is defunct */ 3557 return -1; 3558 3559 label = EEL_EDITABLE_LABEL (widget); 3560 gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, 3561 &select_end); 3562 3563 if (select_start != select_end) 3564 return 1; 3565 else 3566 return 0; 3567 } 3568 3569 static gchar* 3570 eel_editable_label_accessible_get_selection (AtkText *text, 3571 gint selection_num, 3572 gint *start_pos, 3573 gint *end_pos) 3574 { 3575 GtkWidget *widget; 3576 EelEditableLabel *label; 3577 3578 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3579 if (widget == NULL) 3580 /* State is defunct */ 3581 return NULL; 3582 3583 /* Only let the user get the selection if one is set, and if the 3584 * selection_num is 0. 3585 */ 3586 if (selection_num != 0) 3587 return NULL; 3588 3589 label = EEL_EDITABLE_LABEL (widget); 3590 gtk_editable_get_selection_bounds (GTK_EDITABLE (label), start_pos, end_pos); 3591 3592 if (*start_pos != *end_pos) 3593 return gtk_editable_get_chars (GTK_EDITABLE (label), *start_pos, *end_pos); 3594 else 3595 return NULL; 3596 } 3597 3598 static gboolean 3599 eel_editable_label_accessible_add_selection (AtkText *text, 3600 gint start_pos, 3601 gint end_pos) 3602 { 3603 GtkWidget *widget; 3604 EelEditableLabel *label; 3605 gint select_start, select_end; 3606 3607 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3608 if (widget == NULL) 3609 /* State is defunct */ 3610 return FALSE; 3611 3612 label = EEL_EDITABLE_LABEL (widget); 3613 gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, 3614 &select_end); 3615 3616 /* If there is already a selection, then don't allow another to be added, 3617 * since EelEditableLabel only supports one selected region. 3618 */ 3619 if (select_start == select_end) 3620 { 3621 gtk_editable_select_region (GTK_EDITABLE (label), start_pos, end_pos); 3622 return TRUE; 3623 } 3624 else 3625 return FALSE; 3626 } 3627 3628 static gboolean 3629 eel_editable_label_accessible_remove_selection (AtkText *text, 3630 gint selection_num) 3631 { 3632 GtkWidget *widget; 3633 EelEditableLabel *label; 3634 gint select_start, select_end, caret_pos; 3635 3636 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3637 if (widget == NULL) 3638 /* State is defunct */ 3639 return FALSE; 3640 3641 if (selection_num != 0) 3642 return FALSE; 3643 3644 label = EEL_EDITABLE_LABEL (widget); 3645 gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, 3646 &select_end); 3647 3648 if (select_start != select_end) 3649 { 3650 /* Setting the start & end of the selected region to the caret position 3651 * turns off the selection. 3652 */ 3653 caret_pos = gtk_editable_get_position (GTK_EDITABLE (label)); 3654 gtk_editable_select_region (GTK_EDITABLE (label), caret_pos, caret_pos); 3655 return TRUE; 3656 } 3657 else 3658 return FALSE; 3659 } 3660 3661 static gboolean 3662 eel_editable_label_accessible_set_selection (AtkText *text, 3663 gint selection_num, 3664 gint start_pos, 3665 gint end_pos) 3666 { 3667 GtkWidget *widget; 3668 EelEditableLabel *label; 3669 gint select_start, select_end; 3670 3671 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3672 if (widget == NULL) 3673 /* State is defunct */ 3674 return FALSE; 3675 3676 /* Only let the user move the selection if one is set, and if the 3677 * selection_num is 0 3678 */ 3679 if (selection_num != 0) 3680 return FALSE; 3681 3682 label = EEL_EDITABLE_LABEL (widget); 3683 gtk_editable_get_selection_bounds (GTK_EDITABLE (label), &select_start, 3684 &select_end); 3685 3686 if (select_start != select_end) 3687 { 3688 gtk_editable_select_region (GTK_EDITABLE (label), start_pos, end_pos); 3689 return TRUE; 3690 } 3691 else 3692 return FALSE; 3693 } 3694 3695 static AtkAttributeSet* 3696 eel_editable_label_accessible_get_run_attributes (AtkText *text, 3697 gint offset, 3698 gint *start_offset, 3699 gint *end_offset) 3700 { 3701 GtkWidget *widget; 3702 EelEditableLabel *label; 3703 AtkAttributeSet *at_set = NULL; 3704 GtkTextDirection dir; 3705 3706 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3707 if (widget == NULL) 3708 /* State is defunct */ 3709 return NULL; 3710 3711 label = EEL_EDITABLE_LABEL (widget); 3712 3713 dir = gtk_widget_get_direction (widget); 3714 if (dir == GTK_TEXT_DIR_RTL) 3715 { 3716 at_set = gail_misc_add_attribute (at_set, 3717 ATK_TEXT_ATTR_DIRECTION, 3718 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir))); 3719 } 3720 3721 at_set = gail_misc_layout_get_run_attributes (at_set, 3722 eel_editable_label_get_layout (label), 3723 label->text, 3724 offset, 3725 start_offset, 3726 end_offset); 3727 return at_set; 3728 } 3729 3730 static AtkAttributeSet* 3731 eel_editable_label_accessible_get_default_attributes (AtkText *text) 3732 { 3733 GtkWidget *widget; 3734 EelEditableLabel *label; 3735 AtkAttributeSet *at_set = NULL; 3736 3737 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3738 if (widget == NULL) 3739 /* State is defunct */ 3740 return NULL; 3741 3742 label = EEL_EDITABLE_LABEL (widget); 3743 3744 at_set = gail_misc_get_default_attributes (at_set, 3745 eel_editable_label_get_layout (label), 3746 widget); 3747 return at_set; 3748 } 3749 3750 static void 3751 eel_editable_label_accessible_get_character_extents (AtkText *text, 3752 gint offset, 3753 gint *x, 3754 gint *y, 3755 gint *width, 3756 gint *height, 3757 AtkCoordType coords) 3758 { 3759 GtkWidget *widget; 3760 EelEditableLabel *label; 3761 PangoRectangle char_rect; 3762 gint index, cursor_index, x_layout, y_layout; 3763 3764 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3765 if (widget == NULL) 3766 /* State is defunct */ 3767 return; 3768 3769 label = EEL_EDITABLE_LABEL (widget); 3770 eel_editable_label_get_layout_offsets (label, &x_layout, &y_layout); 3771 index = g_utf8_offset_to_pointer (label->text, offset) - label->text; 3772 cursor_index = label->selection_anchor; 3773 if (index > cursor_index) 3774 index += label->preedit_length; 3775 pango_layout_index_to_pos (eel_editable_label_get_layout(label), index, &char_rect); 3776 3777 gail_misc_get_extents_from_pango_rectangle (widget, &char_rect,
Function call argument is an uninitialized value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

3778 x_layout, y_layout, x, y, width, height, coords); 3779 } 3780 3781 static gint 3782 eel_editable_label_accessible_get_offset_at_point (AtkText *text, 3783 gint x, 3784 gint y, 3785 AtkCoordType coords) 3786 { 3787 GtkWidget *widget; 3788 EelEditableLabel *label; 3789 gint index, cursor_index, x_layout, y_layout; 3790 3791 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3792 if (widget == NULL) 3793 /* State is defunct */ 3794 return -1; 3795 3796 label = EEL_EDITABLE_LABEL (widget); 3797 3798 eel_editable_label_get_layout_offsets (label, &x_layout, &y_layout); 3799 3800 index = gail_misc_get_index_at_point_in_layout (widget,
Function call argument is an uninitialized value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

3801 eel_editable_label_get_layout(label), x_layout, y_layout, x, y, coords); 3802 if (index == -1) 3803 { 3804 if (coords == ATK_XY_SCREEN || coords == ATK_XY_WINDOW) 3805 return g_utf8_strlen (label->text, -1); 3806 3807 return index; 3808 } 3809 else 3810 { 3811 cursor_index = label->selection_anchor; 3812 if (index >= cursor_index && label->preedit_length) 3813 { 3814 if (index >= cursor_index + label->preedit_length) 3815 index -= label->preedit_length; 3816 else 3817 index = cursor_index; 3818 } 3819 return g_utf8_pointer_to_offset (label->text, label->text + index); 3820 } 3821 } 3822 3823 static void 3824 atk_text_interface_init (AtkTextIface *iface) 3825 { 3826 g_assert (iface != NULL); 3827 3828 iface->get_text = eel_editable_label_accessible_get_text; 3829 iface->get_character_at_offset = eel_editable_label_accessible_get_character_at_offset; 3830 iface->get_text_before_offset = eel_editable_label_accessible_get_text_before_offset; 3831 iface->get_text_at_offset = eel_editable_label_accessible_get_text_at_offset; 3832 iface->get_text_after_offset = eel_editable_label_accessible_get_text_after_offset; 3833 iface->get_caret_offset = eel_editable_label_accessible_get_caret_offset; 3834 iface->set_caret_offset = eel_editable_label_accessible_set_caret_offset; 3835 iface->get_character_count = eel_editable_label_accessible_get_character_count; 3836 iface->get_n_selections = eel_editable_label_accessible_get_n_selections; 3837 iface->get_selection = eel_editable_label_accessible_get_selection; 3838 iface->add_selection = eel_editable_label_accessible_add_selection; 3839 iface->remove_selection = eel_editable_label_accessible_remove_selection; 3840 iface->set_selection = eel_editable_label_accessible_set_selection; 3841 iface->get_run_attributes = eel_editable_label_accessible_get_run_attributes; 3842 iface->get_default_attributes = eel_editable_label_accessible_get_default_attributes; 3843 iface->get_character_extents = eel_editable_label_accessible_get_character_extents; 3844 iface->get_offset_at_point = eel_editable_label_accessible_get_offset_at_point; 3845 } 3846 3847 static void 3848 eel_editable_label_accessible_set_text_contents (AtkEditableText *text, 3849 const gchar *string) 3850 { 3851 GtkWidget *widget; 3852 EelEditableLabel *label; 3853 3854 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3855 if (widget == NULL) 3856 /* State is defunct */ 3857 return; 3858 3859 label = EEL_EDITABLE_LABEL (widget); 3860 3861 eel_editable_label_set_text (label, string); 3862 } 3863 3864 static void 3865 eel_editable_label_accessible_insert_text (AtkEditableText *text, 3866 const gchar *string, 3867 gint length, 3868 gint *position) 3869 { 3870 GtkWidget *widget; 3871 EelEditableLabel *label; 3872 GtkEditable *editable; 3873 3874 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3875 if (widget == NULL) 3876 /* State is defunct */ 3877 return; 3878 3879 label = EEL_EDITABLE_LABEL (widget); 3880 editable = GTK_EDITABLE (label); 3881 3882 gtk_editable_insert_text (editable, string, length, position); 3883 } 3884 3885 static void 3886 eel_editable_label_accessible_copy_text (AtkEditableText *text, 3887 gint start_pos, 3888 gint end_pos) 3889 { 3890 GtkWidget *widget; 3891 EelEditableLabel *label; 3892 GtkEditable *editable; 3893 gchar *str; 3894 3895 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3896 if (widget == NULL) 3897 /* State is defunct */ 3898 return; 3899 3900 label = EEL_EDITABLE_LABEL (widget); 3901 editable = GTK_EDITABLE (label); 3902 str = gtk_editable_get_chars (editable, start_pos, end_pos); 3903 gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); 3904 } 3905 3906 static void 3907 eel_editable_label_accessible_cut_text (AtkEditableText *text, 3908 gint start_pos, 3909 gint end_pos) 3910 { 3911 GtkWidget *widget; 3912 EelEditableLabel *label; 3913 GtkEditable *editable; 3914 gchar *str; 3915 3916 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3917 if (widget == NULL) 3918 /* State is defunct */ 3919 return; 3920 3921 label = EEL_EDITABLE_LABEL (widget); 3922 editable = GTK_EDITABLE (label); 3923 str = gtk_editable_get_chars (editable, start_pos, end_pos); 3924 gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); 3925 gtk_editable_delete_text (editable, start_pos, end_pos); 3926 } 3927 3928 static void 3929 eel_editable_label_accessible_delete_text (AtkEditableText *text, 3930 gint start_pos, 3931 gint end_pos) 3932 { 3933 GtkWidget *widget; 3934 EelEditableLabel *label; 3935 GtkEditable *editable; 3936 3937 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3938 if (widget == NULL) 3939 /* State is defunct */ 3940 return; 3941 3942 label = EEL_EDITABLE_LABEL (widget); 3943 editable = GTK_EDITABLE (label); 3944 3945 gtk_editable_delete_text (editable, start_pos, end_pos); 3946 } 3947 3948 static void 3949 eel_editable_label_accessible_paste_received (GtkClipboard *clipboard, 3950 const gchar *text, 3951 gpointer data) 3952 { 3953 EelEditableLabelAccessiblePaste* paste_struct = (EelEditableLabelAccessiblePaste *)data; 3954 3955 if (text) 3956 gtk_editable_insert_text (GTK_EDITABLE (paste_struct->label), text, -1, 3957 &(paste_struct->position)); 3958 3959 g_object_unref (paste_struct->label); 3960 } 3961 3962 static void 3963 eel_editable_label_accessible_paste_text (AtkEditableText *text, 3964 gint position) 3965 { 3966 GtkWidget *widget; 3967 GtkEditable *editable; 3968 EelEditableLabelAccessiblePaste paste_struct; 3969 3970 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); 3971 if (widget == NULL) 3972 /* State is defunct */ 3973 return; 3974 3975 editable = GTK_EDITABLE (widget); 3976 if (!gtk_editable_get_editable (editable)) 3977 return; 3978 paste_struct.label = EEL_EDITABLE_LABEL (widget); 3979 paste_struct.position = position; 3980 3981 g_object_ref (paste_struct.label); 3982 gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE), 3983 eel_editable_label_accessible_paste_received, &paste_struct); 3984 } 3985 3986 static void 3987 atk_editable_text_interface_init (AtkEditableTextIface *iface) 3988 { 3989 g_assert (iface != NULL); 3990 3991 iface->set_text_contents = eel_editable_label_accessible_set_text_contents; 3992 iface->insert_text = eel_editable_label_accessible_insert_text; 3993 iface->copy_text = eel_editable_label_accessible_copy_text; 3994 iface->cut_text = eel_editable_label_accessible_cut_text; 3995 iface->delete_text = eel_editable_label_accessible_delete_text; 3996 iface->paste_text = eel_editable_label_accessible_paste_text; 3997 } 3998 3999 static void 4000 eel_editable_label_accessible_notify_insert (AtkObject *accessible) 4001 { 4002 EelEditableLabelAccessiblePrivate *priv; 4003 4004 priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); 4005 if (priv->signal_name) 4006 { 4007 g_signal_emit_by_name (accessible, 4008 priv->signal_name, 4009 priv->position, 4010 priv->length); 4011 priv->signal_name = NULL; 4012 } 4013 } 4014 4015 static gboolean 4016 eel_editable_label_accessible_idle_notify_insert (gpointer data) 4017 { 4018 eel_editable_label_accessible_notify_insert (data); 4019 return FALSE; 4020 } 4021 4022 /* Note arg1 returns the character at the start of the insert. 4023 * arg2 returns the number of characters inserted. 4024 */ 4025 static void 4026 eel_editable_label_accessible_insert_text_cb (EelEditableLabel *label, 4027 gchar *arg1, 4028 gint arg2, 4029 gpointer arg3) 4030 { 4031 AtkObject *accessible; 4032 EelEditableLabelAccessiblePrivate *priv; 4033 gint *position = (gint *) arg3; 4034 4035 accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); 4036 priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); 4037 if (!priv->signal_name) 4038 { 4039 priv->signal_name = "text_changed::insert"; 4040 priv->position = *position; 4041 priv->length = arg2; 4042 } 4043 /* 4044 * The signal will be emitted when the cursor position is updated. 4045 * or in an idle handler if it not updated. 4046 */ 4047 g_idle_add (eel_editable_label_accessible_idle_notify_insert, accessible); 4048 } 4049 4050 /* Note arg1 returns the start of the delete range, arg2 returns the 4051 * end of the delete range if multiple characters are deleted. 4052 */ 4053 static void 4054 eel_editable_label_accessible_delete_text_cb (EelEditableLabel *label, 4055 gint arg1, 4056 gint arg2) 4057 { 4058 AtkObject *accessible; 4059 4060 accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); 4061 4062 /* 4063 * Zero length text deleted so ignore 4064 */ 4065 if (arg2 - arg1 == 0) 4066 return; 4067 4068 g_signal_emit_by_name (accessible, "text_changed::delete", arg1, arg2 - arg1); 4069 } 4070 4071 static void 4072 eel_editable_label_accessible_changed_cb (EelEditableLabel *label) 4073 { 4074 AtkObject *accessible; 4075 EelEditableLabelAccessiblePrivate *priv; 4076 4077 accessible = gtk_widget_get_accessible (GTK_WIDGET (label)); 4078 priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); 4079 gail_text_util_text_setup (priv->textutil, eel_editable_label_get_text (label)); 4080 } 4081 4082 static gboolean 4083 check_for_selection_change (AtkObject *accessible, 4084 GtkWidget *widget) 4085 { 4086 EelEditableLabelAccessiblePrivate *priv; 4087 EelEditableLabel *label; 4088 gboolean ret_val = FALSE; 4089 4090 priv = g_object_get_data (G_OBJECT (accessible), eel_editable_label_accessible_data); 4091 label = EEL_EDITABLE_LABEL (widget); 4092 4093 if (label->selection_anchor != label->selection_end) 4094 { 4095 if (label->selection_anchor != priv->selection_anchor || 4096 label->selection_end != priv->selection_end) 4097 /* 4098 * This check is here as this function can be called 4099 * for notification of selection_end and selection_anchor. 4100 * The values of selection_anchor and selection_end may be the same 4101 * for both notifications and we only want to generate one 4102 * text_selection_changed signal. 4103 */ 4104 ret_val = TRUE; 4105 } 4106 else 4107 { 4108 /* We had a selection */ 4109 ret_val = (priv->selection_anchor != priv->selection_end); 4110 } 4111 priv->selection_anchor = label->selection_anchor; 4112 priv->selection_end = label->selection_end; 4113 4114 return ret_val; 4115 } 4116 4117 static void 4118 eel_editable_label_accessible_notify_gtk (GObject *obj, 4119 GParamSpec *pspec) 4120 { 4121 GtkWidget *widget; 4122 AtkObject *accessible; 4123 EelEditableLabel *label; 4124 4125 widget = GTK_WIDGET (obj); 4126 label = EEL_EDITABLE_LABEL (widget); 4127 accessible = gtk_widget_get_accessible (widget); 4128 4129 if (strcmp (pspec->name, "cursor-position") == 0) 4130 { 4131 eel_editable_label_accessible_notify_insert (accessible); 4132 if (check_for_selection_change (accessible, widget)) 4133 g_signal_emit_by_name (accessible, "text_selection_changed"); 4134 /* 4135 * The label cursor position has moved so generate the signal. 4136 */ 4137 g_signal_emit_by_name (accessible, "text_caret_moved", 4138 g_utf8_pointer_to_offset (label->text, 4139 label->text + label->selection_anchor)); 4140 } 4141 else if (strcmp (pspec->name, "selection-bound") == 0) 4142 { 4143 eel_editable_label_accessible_notify_insert (accessible); 4144 4145 if (check_for_selection_change (accessible, widget)) 4146 g_signal_emit_by_name (accessible, "text_selection_changed"); 4147 } 4148 } 4149 4150 static void 4151 eel_editable_label_accessible_initialize (AtkObject *accessible, 4152 gpointer widget) 4153 { 4154 EelEditableLabelAccessiblePrivate *priv; 4155 EelEditableLabel *label; 4156 4157 a11y_parent_class->initialize (accessible, widget); 4158 4159 label = EEL_EDITABLE_LABEL (widget); 4160 priv = g_new0 (EelEditableLabelAccessiblePrivate, 1); 4161 priv->textutil = gail_text_util_new (); 4162 gail_text_util_text_setup (priv->textutil, eel_editable_label_get_text (EEL_EDITABLE_LABEL (widget))); 4163 priv->selection_anchor = label->selection_anchor; 4164 priv->selection_end = label->selection_end; 4165 g_object_set_data (G_OBJECT (accessible), eel_editable_label_accessible_data, priv); 4166 g_signal_connect (widget, "insert-text", 4167 G_CALLBACK (eel_editable_label_accessible_insert_text_cb), NULL); 4168 g_signal_connect (widget, "delete-text", 4169 G_CALLBACK (eel_editable_label_accessible_delete_text_cb), NULL); 4170 g_signal_connect (widget, "changed", 4171 G_CALLBACK (eel_editable_label_accessible_changed_cb), NULL); 4172 4173 g_signal_connect (widget, 4174 "notify", 4175 G_CALLBACK (eel_editable_label_accessible_notify_gtk), 4176 NULL); 4177 atk_object_set_role (accessible, ATK_ROLE_TEXT); 4178 } 4179 4180 static const gchar* 4181 eel_editable_label_accessible_get_name (AtkObject *accessible) 4182 { 4183 if (accessible->name != NULL) 4184 return accessible->name; 4185 else 4186 { 4187 GtkWidget *widget; 4188 4189 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); 4190 if (widget == NULL) 4191 /* State is defunct */ 4192 return NULL; 4193 4194 g_assert (EEL_IS_EDITABLE_LABEL (widget)); 4195 return eel_editable_label_get_text (EEL_EDITABLE_LABEL (widget)); 4196 } 4197 } 4198 4199 static AtkStateSet* 4200 eel_editable_label_accessible_ref_state_set (AtkObject *accessible) 4201 { 4202 AtkStateSet *state_set; 4203 GtkWidget *widget; 4204 4205 state_set = a11y_parent_class->ref_state_set (accessible); 4206 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); 4207 4208 if (widget == NULL) 4209 return state_set; 4210 4211 atk_state_set_add_state (state_set, ATK_STATE_EDITABLE); 4212 atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE); 4213 return state_set; 4214 } 4215 4216 static void 4217 eel_editable_label_accessible_finalize (GObject *object) 4218 { 4219 EelEditableLabelAccessiblePrivate *priv; 4220 4221 priv = g_object_get_data (object, eel_editable_label_accessible_data); 4222 g_object_unref (priv->textutil); 4223 g_free (priv); 4224 G_OBJECT_CLASS (a11y_parent_class)->finalize (object); 4225 } 4226 4227 static void 4228 eel_editable_label_accessible_class_init (AtkObjectClass *klass) 4229 { 4230 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 4231 4232 a11y_parent_class = g_type_class_peek_parent (klass); 4233 4234 klass->initialize = eel_editable_label_accessible_initialize; 4235 klass->get_name = eel_editable_label_accessible_get_name; 4236 klass->ref_state_set = eel_editable_label_accessible_ref_state_set; 4237 gobject_class->finalize = eel_editable_label_accessible_finalize; 4238 } 4239 4240 static AtkObject * 4241 eel_editable_label_get_accessible (GtkWidget *widget) 4242 { 4243 static GType type = 0; 4244 AtkObject *accessible; 4245 4246 if ((accessible = eel_accessibility_get_atk_object (widget))) 4247 return accessible; 4248 4249 if (!type) 4250 { 4251 const GInterfaceInfo atk_editable_text_info = 4252 { 4253 (GInterfaceInitFunc) atk_editable_text_interface_init, 4254 (GInterfaceFinalizeFunc) NULL, 4255 NULL 4256 }; 4257 const GInterfaceInfo atk_text_info = 4258 { 4259 (GInterfaceInitFunc) atk_text_interface_init, 4260 (GInterfaceFinalizeFunc) NULL, 4261 NULL 4262 }; 4263 4264 type = eel_accessibility_create_accessible_gtype 4265 ("EelEditableLabelAccessible", 4266 widget, 4267 (GClassInitFunc) eel_editable_label_accessible_class_init); 4268 4269 if (!type) 4270 return NULL; 4271 4272 g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info); 4273 g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info); 4274 } 4275 4276 accessible = g_object_new (type, "widget", widget, NULL); 4277 4278 return eel_accessibility_set_atk_object_return (widget, accessible); 4279 }