gtkoldeditable.c 23 KB
Newer Older
Owen Taylor's avatar
Owen Taylor committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

27 28
#undef GTK_DISABLE_DEPRECATED

29
#include <config.h>
Owen Taylor's avatar
Owen Taylor committed
30 31 32 33 34 35
#include <string.h>
#include "gdk/gdkkeysyms.h"
#include "gdk/gdki18n.h"
#include "gtkclipboard.h"
#include "gtkoldeditable.h"
#include "gtkmain.h"
36
#include "gtkmarshalers.h"
Owen Taylor's avatar
Owen Taylor committed
37 38
#include "gtkselection.h"
#include "gtksignal.h"
Matthias Clasen's avatar
Matthias Clasen committed
39
#include "gtkintl.h"
40
#include "gtkalias.h"
Owen Taylor's avatar
Owen Taylor committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

#define MIN_EDITABLE_WIDTH  150
#define DRAW_TIMEOUT     20
#define INNER_BORDER     2

enum {
  /* Binding actions */
  ACTIVATE,
  SET_EDITABLE,
  MOVE_CURSOR,
  MOVE_WORD,
  MOVE_PAGE,
  MOVE_TO_ROW,
  MOVE_TO_COLUMN,
  KILL_CHAR,
  KILL_WORD,
  KILL_LINE,
  CUT_CLIPBOARD,
  COPY_CLIPBOARD,
  PASTE_CLIPBOARD,
  LAST_SIGNAL
};

enum {
  ARG_0,
  ARG_TEXT_POSITION,
  ARG_EDITABLE
};

/* values for selection info */

enum {
  TARGET_STRING,
  TARGET_TEXT,
  TARGET_COMPOUND_TEXT
};

static void  gtk_old_editable_editable_init        (GtkEditableClass    *iface);
static void  gtk_old_editable_set_arg              (GtkObject           *object,
						    GtkArg              *arg,
						    guint                arg_id);
static void  gtk_old_editable_get_arg              (GtkObject           *object,
						    GtkArg              *arg,
						    guint                arg_id);
static void *gtk_old_editable_get_public_chars     (GtkOldEditable      *old_editable,
						    gint                 start,
						    gint                 end);

static gint gtk_old_editable_selection_clear    (GtkWidget         *widget,
						 GdkEventSelection *event);
static void gtk_old_editable_selection_get      (GtkWidget         *widget,
						 GtkSelectionData  *selection_data,
						 guint              info,
						 guint              time);
static void gtk_old_editable_selection_received (GtkWidget         *widget,
						 GtkSelectionData  *selection_data,
						 guint              time);

static void  gtk_old_editable_set_selection        (GtkOldEditable      *old_editable,
						    gint                 start,
						    gint                 end);

static void gtk_old_editable_real_set_editable    (GtkOldEditable *old_editable,
						   gboolean        is_editable);
static void gtk_old_editable_real_cut_clipboard   (GtkOldEditable *old_editable);
static void gtk_old_editable_real_copy_clipboard  (GtkOldEditable *old_editable);
static void gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable);

static void     gtk_old_editable_insert_text         (GtkEditable *editable,
						      const gchar *new_text,
						      gint         new_text_length,
						      gint        *position);
static void     gtk_old_editable_delete_text         (GtkEditable *editable,
						      gint         start_pos,
						      gint         end_pos);
static gchar *  gtk_old_editable_get_chars           (GtkEditable *editable,
						      gint         start,
						      gint         end);
static void     gtk_old_editable_set_selection_bounds (GtkEditable *editable,
						       gint         start,
						       gint         end);
static gboolean gtk_old_editable_get_selection_bounds (GtkEditable *editable,
						       gint        *start,
						       gint        *end);
static void     gtk_old_editable_set_position        (GtkEditable *editable,
						      gint         position);
static gint     gtk_old_editable_get_position        (GtkEditable *editable);

static guint editable_signals[LAST_SIGNAL] = { 0 };

Matthias Clasen's avatar
Matthias Clasen committed
131 132 133
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkOldEditable, gtk_old_editable, GTK_TYPE_WIDGET,
				  G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
							 gtk_old_editable_editable_init));
Owen Taylor's avatar
Owen Taylor committed
134 135 136 137 138 139 140 141 142 143

static void
gtk_old_editable_class_init (GtkOldEditableClass *class)
{
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;

  object_class = (GtkObjectClass*) class;
  widget_class = (GtkWidgetClass*) class;

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
  object_class->set_arg = gtk_old_editable_set_arg;
  object_class->get_arg = gtk_old_editable_get_arg;

  widget_class->selection_clear_event = gtk_old_editable_selection_clear;
  widget_class->selection_received = gtk_old_editable_selection_received;
  widget_class->selection_get = gtk_old_editable_selection_get;

  class->activate = NULL;
  class->set_editable = gtk_old_editable_real_set_editable;

  class->move_cursor = NULL;
  class->move_word = NULL;
  class->move_page = NULL;
  class->move_to_row = NULL;
  class->move_to_column = NULL;

  class->kill_char = NULL;
  class->kill_word = NULL;
  class->kill_line = NULL;

  class->cut_clipboard = gtk_old_editable_real_cut_clipboard;
  class->copy_clipboard = gtk_old_editable_real_copy_clipboard;
  class->paste_clipboard = gtk_old_editable_real_paste_clipboard;

  class->update_text = NULL;
  class->get_chars = NULL;
  class->set_selection = NULL;
  class->set_position = NULL;
Owen Taylor's avatar
Owen Taylor committed
172 173

  editable_signals[ACTIVATE] =
Matthias Clasen's avatar
Matthias Clasen committed
174
    gtk_signal_new (I_("activate"),
Owen Taylor's avatar
Owen Taylor committed
175 176 177
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, activate),
178
		    _gtk_marshal_NONE__NONE,
Owen Taylor's avatar
Owen Taylor committed
179 180 181 182
		    GTK_TYPE_NONE, 0);
  widget_class->activate_signal = editable_signals[ACTIVATE];

  editable_signals[SET_EDITABLE] =
Matthias Clasen's avatar
Matthias Clasen committed
183
    gtk_signal_new (I_("set-editable"),
Owen Taylor's avatar
Owen Taylor committed
184 185 186
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, set_editable),
187
		    _gtk_marshal_NONE__BOOLEAN,
Owen Taylor's avatar
Owen Taylor committed
188 189 190 191
		    GTK_TYPE_NONE, 1,
		    GTK_TYPE_BOOL);

  editable_signals[MOVE_CURSOR] =
Matthias Clasen's avatar
Matthias Clasen committed
192
    gtk_signal_new (I_("move_cursor"),
Owen Taylor's avatar
Owen Taylor committed
193 194 195
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_cursor),
196
		    _gtk_marshal_NONE__INT_INT,
Owen Taylor's avatar
Owen Taylor committed
197 198 199 200 201
		    GTK_TYPE_NONE, 2, 
		    GTK_TYPE_INT, 
		    GTK_TYPE_INT);

  editable_signals[MOVE_WORD] =
Matthias Clasen's avatar
Matthias Clasen committed
202
    gtk_signal_new (I_("move_word"),
Owen Taylor's avatar
Owen Taylor committed
203 204 205
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_word),
206
		    _gtk_marshal_NONE__INT,
Owen Taylor's avatar
Owen Taylor committed
207 208 209 210
		    GTK_TYPE_NONE, 1, 
		    GTK_TYPE_INT);

  editable_signals[MOVE_PAGE] =
Matthias Clasen's avatar
Matthias Clasen committed
211
    gtk_signal_new (I_("move_page"),
Owen Taylor's avatar
Owen Taylor committed
212 213 214
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_page),
215
		    _gtk_marshal_NONE__INT_INT,
Owen Taylor's avatar
Owen Taylor committed
216 217 218 219 220
		    GTK_TYPE_NONE, 2, 
		    GTK_TYPE_INT, 
		    GTK_TYPE_INT);

  editable_signals[MOVE_TO_ROW] =
Matthias Clasen's avatar
Matthias Clasen committed
221
    gtk_signal_new (I_("move_to_row"),
Owen Taylor's avatar
Owen Taylor committed
222 223 224
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_row),
225
		    _gtk_marshal_NONE__INT,
Owen Taylor's avatar
Owen Taylor committed
226 227 228 229
		    GTK_TYPE_NONE, 1, 
		    GTK_TYPE_INT);

  editable_signals[MOVE_TO_COLUMN] =
Matthias Clasen's avatar
Matthias Clasen committed
230
    gtk_signal_new (I_("move_to_column"),
Owen Taylor's avatar
Owen Taylor committed
231 232 233
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_column),
234
		    _gtk_marshal_NONE__INT,
Owen Taylor's avatar
Owen Taylor committed
235 236 237 238
		    GTK_TYPE_NONE, 1, 
		    GTK_TYPE_INT);

  editable_signals[KILL_CHAR] =
Matthias Clasen's avatar
Matthias Clasen committed
239
    gtk_signal_new (I_("kill_char"),
Owen Taylor's avatar
Owen Taylor committed
240 241 242
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_char),
243
		    _gtk_marshal_NONE__INT,
Owen Taylor's avatar
Owen Taylor committed
244 245 246 247
		    GTK_TYPE_NONE, 1, 
		    GTK_TYPE_INT);

  editable_signals[KILL_WORD] =
Matthias Clasen's avatar
Matthias Clasen committed
248
    gtk_signal_new (I_("kill_word"),
Owen Taylor's avatar
Owen Taylor committed
249 250 251
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_word),
252
		    _gtk_marshal_NONE__INT,
Owen Taylor's avatar
Owen Taylor committed
253 254 255 256
		    GTK_TYPE_NONE, 1, 
		    GTK_TYPE_INT);

  editable_signals[KILL_LINE] =
Matthias Clasen's avatar
Matthias Clasen committed
257
    gtk_signal_new (I_("kill_line"),
Owen Taylor's avatar
Owen Taylor committed
258 259 260
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_line),
261
		    _gtk_marshal_NONE__INT,
Owen Taylor's avatar
Owen Taylor committed
262 263 264 265
		    GTK_TYPE_NONE, 1, 
		    GTK_TYPE_INT);

  editable_signals[CUT_CLIPBOARD] =
Matthias Clasen's avatar
Matthias Clasen committed
266
    gtk_signal_new (I_("cut_clipboard"),
Owen Taylor's avatar
Owen Taylor committed
267 268 269
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, cut_clipboard),
270
		    _gtk_marshal_NONE__NONE,
Owen Taylor's avatar
Owen Taylor committed
271 272 273
		    GTK_TYPE_NONE, 0);

  editable_signals[COPY_CLIPBOARD] =
Matthias Clasen's avatar
Matthias Clasen committed
274
    gtk_signal_new (I_("copy_clipboard"),
Owen Taylor's avatar
Owen Taylor committed
275 276 277
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, copy_clipboard),
278
		    _gtk_marshal_NONE__NONE,
Owen Taylor's avatar
Owen Taylor committed
279 280 281
		    GTK_TYPE_NONE, 0);

  editable_signals[PASTE_CLIPBOARD] =
Matthias Clasen's avatar
Matthias Clasen committed
282
    gtk_signal_new (I_("paste_clipboard"),
Owen Taylor's avatar
Owen Taylor committed
283 284 285
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkOldEditableClass, paste_clipboard),
286
		    _gtk_marshal_NONE__NONE,
Owen Taylor's avatar
Owen Taylor committed
287 288
		    GTK_TYPE_NONE, 0);

289 290
  gtk_object_add_arg_type ("GtkOldEditable::text-position", GTK_TYPE_INT, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_TEXT_POSITION);
  gtk_object_add_arg_type ("GtkOldEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_EDITABLE);
Owen Taylor's avatar
Owen Taylor committed
291 292 293 294 295
}

static void
gtk_old_editable_editable_init (GtkEditableClass *iface)
{
296 297
  iface->do_insert_text = gtk_old_editable_insert_text;
  iface->do_delete_text = gtk_old_editable_delete_text;
Owen Taylor's avatar
Owen Taylor committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
  iface->get_chars = gtk_old_editable_get_chars;
  iface->set_selection_bounds = gtk_old_editable_set_selection_bounds;
  iface->get_selection_bounds = gtk_old_editable_get_selection_bounds;
  iface->set_position = gtk_old_editable_set_position;
  iface->get_position = gtk_old_editable_get_position;
}

static void
gtk_old_editable_set_arg (GtkObject *object,
			  GtkArg    *arg,
			  guint      arg_id)
{
  GtkEditable *editable = GTK_EDITABLE (object);

  switch (arg_id)
    {
    case ARG_TEXT_POSITION:
      gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
      break;
    case ARG_EDITABLE:
      gtk_signal_emit (object, editable_signals[SET_EDITABLE],
		       GTK_VALUE_BOOL (*arg) != FALSE);
      break;
    default:
      break;
    }
}

static void
gtk_old_editable_get_arg (GtkObject *object,
			  GtkArg    *arg,
			  guint      arg_id)
{
  GtkOldEditable *old_editable;

  old_editable = GTK_OLD_EDITABLE (object);

  switch (arg_id)
    {
    case ARG_TEXT_POSITION:
      GTK_VALUE_INT (*arg) = old_editable->current_pos;
      break;
    case ARG_EDITABLE:
      GTK_VALUE_BOOL (*arg) = old_editable->editable;
      break;
    default:
      arg->type = GTK_TYPE_INVALID;
      break;
    }
}

static void
gtk_old_editable_init (GtkOldEditable *old_editable)
{
  static const GtkTargetEntry targets[] = {
    { "UTF8_STRING", 0, 0 },
    { "STRING", 0, 0 },
    { "TEXT",   0, 0 }, 
    { "COMPOUND_TEXT", 0, 0 }
  };

  GTK_WIDGET_SET_FLAGS (old_editable, GTK_CAN_FOCUS);

  old_editable->selection_start_pos = 0;
  old_editable->selection_end_pos = 0;
  old_editable->has_selection = FALSE;
  old_editable->editable = 1;
  old_editable->visible = 1;
  old_editable->clipboard_text = NULL;

  gtk_selection_add_targets (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY,
			     targets, G_N_ELEMENTS (targets));
}

static void
gtk_old_editable_insert_text (GtkEditable *editable,
			      const gchar *new_text,
			      gint         new_text_length,
			      gint        *position)
{
  gchar buf[64];
  gchar *text;

  gtk_widget_ref (GTK_WIDGET (editable));

  if (new_text_length <= 63)
    text = buf;
  else
    text = g_new (gchar, new_text_length + 1);

  text[new_text_length] = '\0';
  strncpy (text, new_text, new_text_length);
390 391 392 393 394
  
  g_signal_emit_by_name (editable, "insert_text", text, new_text_length,
			 position);
  g_signal_emit_by_name (editable, "changed");
  
Owen Taylor's avatar
Owen Taylor committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
  if (new_text_length > 63)
    g_free (text);

  gtk_widget_unref (GTK_WIDGET (editable));
}

static void
gtk_old_editable_delete_text (GtkEditable *editable,
			      gint         start_pos,
			      gint         end_pos)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);

  gtk_widget_ref (GTK_WIDGET (old_editable));

410 411
  g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos);
  g_signal_emit_by_name (editable, "changed");
Owen Taylor's avatar
Owen Taylor committed
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

  if (old_editable->selection_start_pos == old_editable->selection_end_pos &&
      old_editable->has_selection)
    gtk_old_editable_claim_selection (old_editable, FALSE, GDK_CURRENT_TIME);
  
  gtk_widget_unref (GTK_WIDGET (old_editable));
}

static void
gtk_old_editable_update_text (GtkOldEditable *old_editable,
			      gint            start_pos,
			      gint            end_pos)
{
  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
  klass->update_text (GTK_OLD_EDITABLE (old_editable), start_pos, end_pos);
}

static gchar *    
gtk_old_editable_get_chars  (GtkEditable      *editable,
			     gint              start,
			     gint              end)
{
  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
  return klass->get_chars (GTK_OLD_EDITABLE (editable), start, end);
}

/*
 * Like gtk_editable_get_chars, but if the editable is not
 * visible, return asterisks; also convert result to UTF-8.
 */
static void *    
gtk_old_editable_get_public_chars (GtkOldEditable   *old_editable,
				   gint              start,
				   gint              end)
{
  gchar *str = NULL;
Owen Taylor's avatar
Owen Taylor committed
448
  const gchar *charset;
Owen Taylor's avatar
Owen Taylor committed
449 450 451 452
  gboolean need_conversion = !g_get_charset (&charset);

  if (old_editable->visible)
    {
453
      GError *error = NULL;
Owen Taylor's avatar
Owen Taylor committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
      gchar *tmp = gtk_editable_get_chars (GTK_EDITABLE (old_editable), start, end);

      if (need_conversion)
	{
	  str = g_convert (tmp, -1,
			   "UTF-8", charset,
			   NULL, NULL, &error);
	  
	  if (!str)
	    {
	      g_warning ("Cannot convert text from charset to UTF-8 %s: %s", charset, error->message);
	      g_error_free (error);
	    }

	  g_free (tmp);
	}
      else
	str = tmp;
    }
  else
    {
      gint i;
      gint nchars = end - start;
       
      if (nchars < 0)
	nchars = -nchars;

      str = g_new (gchar, nchars + 1);
      for (i = 0; i<nchars; i++)
	str[i] = '*';
      str[i] = '\0';
    }

  return str;
}

static void
gtk_old_editable_set_selection (GtkOldEditable *old_editable,
				gint            start_pos,
				gint            end_pos)
{
  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
  klass->set_selection (old_editable, start_pos, end_pos);
}

static void
gtk_old_editable_set_position (GtkEditable *editable,
			       gint            position)
{
  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);

  klass->set_position (GTK_OLD_EDITABLE (editable), position);
}

static gint
gtk_old_editable_get_position (GtkEditable *editable)
{
  return GTK_OLD_EDITABLE (editable)->current_pos;
}

static gint
gtk_old_editable_selection_clear (GtkWidget         *widget,
				  GdkEventSelection *event)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
  
  /* Let the selection handling code know that the selection
   * has been changed, since we've overriden the default handler */
Matthias Clasen's avatar
Matthias Clasen committed
522
  if (!GTK_WIDGET_CLASS (gtk_old_editable_parent_class)->selection_clear_event (widget, event))
Owen Taylor's avatar
Owen Taylor committed
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    return FALSE;
  
  if (old_editable->has_selection)
    {
      old_editable->has_selection = FALSE;
      gtk_old_editable_update_text (old_editable, old_editable->selection_start_pos,
				    old_editable->selection_end_pos);
    }
  
  return TRUE;
}

static void
gtk_old_editable_selection_get (GtkWidget        *widget,
				GtkSelectionData *selection_data,
				guint             info,
				guint             time)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
  gint selection_start_pos;
  gint selection_end_pos;

  gchar *str;

  selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
  selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);

  str = gtk_old_editable_get_public_chars (old_editable, 
					   selection_start_pos, 
					   selection_end_pos);

  if (str)
    {
556
      gtk_selection_data_set_text (selection_data, str, -1);
Owen Taylor's avatar
Owen Taylor committed
557 558 559 560 561 562 563 564 565 566
      g_free (str);
    }
}

static void
gtk_old_editable_paste_received (GtkOldEditable *old_editable,
				 const gchar    *text,
				 gboolean        is_clipboard)
{
  const gchar *str = NULL;
Owen Taylor's avatar
Owen Taylor committed
567
  const gchar *charset;
Owen Taylor's avatar
Owen Taylor committed
568 569 570 571
  gboolean need_conversion = FALSE;

  if (text)
    {
572
      GError *error = NULL;
Owen Taylor's avatar
Owen Taylor committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
      
      need_conversion = !g_get_charset (&charset);

      if (need_conversion)
	{
	  str = g_convert_with_fallback (text, -1,
					 charset, "UTF-8", NULL,
					 NULL, NULL, &error);
	  if (!str)
	    {
	      g_warning ("Cannot convert text from UTF-8 to %s: %s",
			 charset, error->message);
	      g_error_free (error);
	      return;
	    }
	}
      else
	str = text;
    }

  if (str)
    {
      gboolean reselect;
      gint old_pos;
      gint tmp_pos;
  
      reselect = FALSE;

      if ((old_editable->selection_start_pos != old_editable->selection_end_pos) && 
	  (!old_editable->has_selection || is_clipboard))
	{
	  reselect = TRUE;
	  
	  /* Don't want to call gtk_editable_delete_selection here if we are going
	   * to reclaim the selection to avoid extra server traffic */
	  if (old_editable->has_selection)
	    {
	      gtk_editable_delete_text (GTK_EDITABLE (old_editable),
					MIN (old_editable->selection_start_pos, old_editable->selection_end_pos),
					MAX (old_editable->selection_start_pos, old_editable->selection_end_pos));
	    }
	  else
	    gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
	}
      
      tmp_pos = old_pos = old_editable->current_pos;
      
      gtk_editable_insert_text (GTK_EDITABLE (old_editable), str, -1, &tmp_pos);

      if (reselect)
	gtk_old_editable_set_selection (old_editable, old_pos, old_editable->current_pos);

      if (str && str != text)
	g_free ((gchar *) str);
    }
}

static void
gtk_old_editable_selection_received  (GtkWidget         *widget,
				      GtkSelectionData  *selection_data,
				      guint              time)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);

  gchar *text = gtk_selection_data_get_text (selection_data);

  if (!text)
    {
      /* If we asked for UTF8 and didn't get it, try text; if we asked
       * for text and didn't get it, try string.  If we asked for
       * anything else and didn't get it, give up.
       */
645
      if (selection_data->target == gdk_atom_intern_static_string ("UTF8_STRING"))
Owen Taylor's avatar
Owen Taylor committed
646 647
	{
	  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
648
				 gdk_atom_intern_static_string ("TEXT"),
Owen Taylor's avatar
Owen Taylor committed
649 650 651
				 time);
	  return;
	}
652
      else if (selection_data->target == gdk_atom_intern_static_string ("TEXT"))
Owen Taylor's avatar
Owen Taylor committed
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
	{
	  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
				 GDK_TARGET_STRING,
				 time);
	  return;
	}
    }

  if (text)
    {
      gtk_old_editable_paste_received (old_editable, text, FALSE);
      g_free (text);
    }
}

static void
old_editable_text_received_cb (GtkClipboard *clipboard,
			       const gchar  *text,
			       gpointer      data)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (data);

  gtk_old_editable_paste_received (old_editable, text, TRUE);
  g_object_unref (G_OBJECT (old_editable));
}

Matthias Clasen's avatar
Matthias Clasen committed
679 680 681 682 683
/**
 * gtk_old_editable_claim_selection:
 * @old_editable: a #GtkOldEditable
 * @claim: if %TRUE, claim ownership of the selection, if %FALSE, give
 *   up ownership
684
 * @time_: timestamp for this operation
Matthias Clasen's avatar
Matthias Clasen committed
685 686 687
 * 
 * Claims or gives up ownership of the selection.
 */
Owen Taylor's avatar
Owen Taylor committed
688 689 690 691 692
void
gtk_old_editable_claim_selection (GtkOldEditable *old_editable, 
				  gboolean        claim, 
				  guint32         time)
{
693 694 695
  GtkWidget *widget = GTK_WIDGET (old_editable);
  GdkDisplay *display = gtk_widget_get_display (widget);
  
Owen Taylor's avatar
Owen Taylor committed
696 697 698 699 700 701 702
  g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
  g_return_if_fail (GTK_WIDGET_REALIZED (old_editable));

  old_editable->has_selection = FALSE;
  
  if (claim)
    {
703 704
      if (gtk_selection_owner_set_for_display (display, widget,
					       GDK_SELECTION_PRIMARY, time))
Owen Taylor's avatar
Owen Taylor committed
705 706 707 708
	old_editable->has_selection = TRUE;
    }
  else
    {
709 710 711 712
      if (gdk_selection_owner_get_for_display (display, GDK_SELECTION_PRIMARY) == widget->window)
	gtk_selection_owner_set_for_display (display,
					     NULL,
					     GDK_SELECTION_PRIMARY, time);
Owen Taylor's avatar
Owen Taylor committed
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
    }
}

static void
gtk_old_editable_set_selection_bounds (GtkEditable *editable,
				       gint         start,
				       gint         end)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
  
  if (GTK_WIDGET_REALIZED (editable))
    gtk_old_editable_claim_selection (old_editable, start != end, GDK_CURRENT_TIME);
  
  gtk_old_editable_set_selection (old_editable, start, end);
}

static gboolean
gtk_old_editable_get_selection_bounds (GtkEditable *editable,
				       gint        *start,
				       gint        *end)
{
  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);

  *start = old_editable->selection_start_pos;
  *end = old_editable->selection_end_pos;

  return (old_editable->selection_start_pos != old_editable->selection_end_pos);
}

static void
gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
				    gboolean        is_editable)
{
  is_editable = is_editable != FALSE;

  if (old_editable->editable != is_editable)
    {
      old_editable->editable = is_editable;
      gtk_widget_queue_draw (GTK_WIDGET (old_editable));
    }
}

static void
gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable)
{
  gtk_old_editable_real_copy_clipboard (old_editable);
  gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
}

static void
gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable)
{
  gint selection_start_pos; 
  gint selection_end_pos;

  selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
  selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);

  if (selection_start_pos != selection_end_pos)
    {
      gchar *text = gtk_old_editable_get_public_chars (old_editable,
						       selection_start_pos,
						       selection_end_pos);

      if (text)
	{
779 780 781 782
	  GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (old_editable),
							      GDK_SELECTION_CLIPBOARD);
	  
	  gtk_clipboard_set_text (clipboard, text, -1);
Owen Taylor's avatar
Owen Taylor committed
783 784 785 786 787 788 789 790
	  g_free (text);
	}
    }
}

static void
gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable)
{
791 792 793
  GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (old_editable), 
						      GDK_SELECTION_CLIPBOARD);

Owen Taylor's avatar
Owen Taylor committed
794
  g_object_ref (G_OBJECT (old_editable));
795
  gtk_clipboard_request_text (clipboard, old_editable_text_received_cb, old_editable);
Owen Taylor's avatar
Owen Taylor committed
796 797
}

Matthias Clasen's avatar
Matthias Clasen committed
798 799 800 801 802 803
/**
 * gtk_old_editable_changed:
 * @old_editable: a #GtkOldEditable
 *
 * Emits the ::changed signal on @old_editable.
 */
Owen Taylor's avatar
Owen Taylor committed
804 805 806 807 808
void
gtk_old_editable_changed (GtkOldEditable *old_editable)
{
  g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
  
809
  g_signal_emit_by_name (old_editable, "changed");
Owen Taylor's avatar
Owen Taylor committed
810
}
811 812 813

#define __GTK_OLD_EDITABLE_C__
#include "gtkaliasdef.c"