Changes to make word motion work again.

Cut/copy/paste via the X clipboard.
Generalized extending selection using <Shift> to work with all types
  of motion, not just arrow keys.
Don't change length of GtkEntry structure because of USE_XIM

                                        -owt
This commit is contained in:
Owen Taylor 1997-12-07 16:25:48 +00:00
parent 37f6b421f2
commit 56aae058fc
2 changed files with 246 additions and 203 deletions

View File

@ -27,15 +27,10 @@
#include "gtkselection.h"
#include "gtksignal.h"
#ifdef USE_XIM
#include "gdk/gdkx.h"
#endif
#define MIN_ENTRY_WIDTH 150
#define DRAW_TIMEOUT 20
#define INNER_BORDER 2
enum {
INSERT_TEXT,
DELETE_TEXT,
@ -46,7 +41,7 @@ enum {
};
typedef void (*GtkTextFunction) (GtkEntry *entry);
typedef void (*GtkTextFunction) (GtkEntry *entry, GdkEventKey *event);
typedef void (*GtkEntrySignal1) (GtkObject *object,
gpointer arg1,
gint arg2,
@ -142,71 +137,77 @@ static void gtk_select_line (GtkEntry *entry);
static void gtk_select_region (GtkEntry *entry,
gint start,
gint end);
static void gtk_entry_cut_clipboard (GtkEntry *entry,
GdkEventKey *event);
static void gtk_entry_copy_clipboard (GtkEntry *entry,
GdkEventKey *event);
static void gtk_entry_paste_clipboard (GtkEntry *entry,
GdkEventKey *event);
static GtkWidgetClass *parent_class = NULL;
static gint entry_signals[LAST_SIGNAL] = { 0 };
static GdkAtom ctext_atom = GDK_NONE;
static GdkAtom text_atom = GDK_NONE;
static GdkAtom clipboard_atom = GDK_NONE;
static GtkTextFunction control_keys[26] =
{
gtk_move_beginning_of_line, /* a */
gtk_move_backward_character, /* b */
NULL, /* c */
gtk_delete_forward_character, /* d */
gtk_move_end_of_line, /* e */
gtk_move_forward_character, /* f */
NULL, /* g */
gtk_delete_backward_character, /* h */
NULL, /* i */
NULL, /* j */
gtk_delete_to_line_end, /* k */
NULL, /* l */
NULL, /* m */
NULL, /* n */
NULL, /* o */
NULL, /* p */
NULL, /* q */
NULL, /* r */
NULL, /* s */
NULL, /* t */
gtk_delete_line, /* u */
NULL, /* v */
gtk_delete_backward_word, /* w */
NULL, /* x */
NULL, /* y */
NULL, /* z */
(GtkTextFunction)gtk_move_beginning_of_line, /* a */
(GtkTextFunction)gtk_move_backward_character, /* b */
gtk_entry_copy_clipboard, /* c */
(GtkTextFunction)gtk_delete_forward_character, /* d */
(GtkTextFunction)gtk_move_end_of_line, /* e */
(GtkTextFunction)gtk_move_forward_character, /* f */
NULL, /* g */
(GtkTextFunction)gtk_delete_backward_character, /* h */
NULL, /* i */
NULL, /* j */
(GtkTextFunction)gtk_delete_to_line_end, /* k */
NULL, /* l */
NULL, /* m */
NULL, /* n */
NULL, /* o */
NULL, /* p */
NULL, /* q */
NULL, /* r */
NULL, /* s */
NULL, /* t */
(GtkTextFunction)gtk_delete_line, /* u */
gtk_entry_paste_clipboard, /* v */
(GtkTextFunction)gtk_delete_backward_word, /* w */
gtk_entry_cut_clipboard, /* x */
NULL, /* y */
NULL, /* z */
};
static GtkTextFunction alt_keys[26] =
{
NULL, /* a */
gtk_move_backward_word, /* b */
NULL, /* c */
gtk_delete_forward_word, /* d */
NULL, /* e */
gtk_move_forward_word, /* f */
NULL, /* g */
NULL, /* h */
NULL, /* i */
NULL, /* j */
NULL, /* k */
NULL, /* l */
NULL, /* m */
NULL, /* n */
NULL, /* o */
NULL, /* p */
NULL, /* q */
NULL, /* r */
NULL, /* s */
NULL, /* t */
NULL, /* u */
NULL, /* v */
NULL, /* w */
NULL, /* x */
NULL, /* y */
NULL, /* z */
NULL, /* a */
(GtkTextFunction)gtk_move_backward_word, /* b */
NULL, /* c */
(GtkTextFunction)gtk_delete_forward_word, /* d */
NULL, /* e */
(GtkTextFunction)gtk_move_forward_word, /* f */
NULL, /* g */
NULL, /* h */
NULL, /* i */
NULL, /* j */
NULL, /* k */
NULL, /* l */
NULL, /* m */
NULL, /* n */
NULL, /* o */
NULL, /* p */
NULL, /* q */
NULL, /* r */
NULL, /* s */
NULL, /* t */
NULL, /* u */
NULL, /* v */
NULL, /* w */
NULL, /* x */
NULL, /* y */
NULL, /* z */
};
@ -326,14 +327,21 @@ gtk_entry_init (GtkEntry *entry)
entry->have_selection = FALSE;
entry->timer = 0;
entry->visible = 1;
entry->clipboard_text = NULL;
#ifdef USE_XIM
entry->ic = NULL;
#endif
if (!clipboard_atom)
clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY,
GDK_TARGET_STRING, gtk_entry_selection_handler,
NULL, NULL);
gtk_selection_add_handler (GTK_WIDGET(entry), clipboard_atom,
GDK_TARGET_STRING, gtk_entry_selection_handler,
NULL, NULL);
if (!text_atom)
text_atom = gdk_atom_intern ("TEXT", FALSE);
@ -342,6 +350,10 @@ gtk_entry_init (GtkEntry *entry)
text_atom,
gtk_entry_selection_handler,
NULL, NULL);
gtk_selection_add_handler (GTK_WIDGET(entry), clipboard_atom,
text_atom,
gtk_entry_selection_handler,
NULL, NULL);
if (!ctext_atom)
ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
@ -350,6 +362,10 @@ gtk_entry_init (GtkEntry *entry)
ctext_atom,
gtk_entry_selection_handler,
NULL, NULL);
gtk_selection_add_handler (GTK_WIDGET(entry), clipboard_atom,
ctext_atom,
gtk_entry_selection_handler,
NULL, NULL);
}
GtkWidget*
@ -937,9 +953,8 @@ gtk_entry_key_press (GtkWidget *widget,
gint return_val;
gint key;
gint tmp_pos;
gchar tmp;
gint extend_selection;
gint selection_pos;
gint extend_start;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
@ -947,14 +962,20 @@ gtk_entry_key_press (GtkWidget *widget,
entry = GTK_ENTRY (widget);
return_val = FALSE;
extend_selection = FALSE;
if (entry->selection_start_pos == entry->selection_end_pos)
selection_pos = entry->current_pos;
else if (entry->selection_start_pos == entry->current_pos)
selection_pos = entry->selection_end_pos;
else
selection_pos = entry->selection_start_pos;
extend_selection = event->state & GDK_SHIFT_MASK;
extend_start = FALSE;
if (extend_selection)
{
if (entry->selection_start_pos == entry->selection_end_pos)
{
entry->selection_start_pos = entry->current_pos;
entry->selection_end_pos = entry->current_pos;
}
extend_start = (entry->current_pos == entry->selection_start_pos);
}
switch (event->keyval)
{
@ -975,11 +996,12 @@ gtk_entry_key_press (GtkWidget *widget,
return_val = TRUE;
if (event->state & GDK_SHIFT_MASK)
{
/* gtk_paste_clipboard(entry) -- NEEDS CLIPBOARD */
extend_selection = FALSE;
gtk_entry_paste_clipboard (entry, event);
}
else if (event->state & GDK_CONTROL_MASK)
{
/* gtk_copy_clipboard(entry) -- NEEDS CLIPBOARD */
gtk_entry_copy_clipboard (entry, event);
}
else
{
@ -995,56 +1017,26 @@ gtk_entry_key_press (GtkWidget *widget,
if (event->state & GDK_CONTROL_MASK)
gtk_delete_line (entry);
else if (event->state & GDK_SHIFT_MASK)
/* gtk_cut_clipboard(entry) -- NEEDS CLIPBOARD */ ;
gtk_entry_cut_clipboard (entry, event);
else
gtk_delete_forward_character (entry);
}
break;
case GDK_Home:
return_val = TRUE;
if (event->state & GDK_SHIFT_MASK)
{
if (entry->selection_start_pos == entry->selection_end_pos)
entry->selection_start_pos = entry->current_pos;
entry->current_pos = entry->selection_end_pos = 0;
}
else
gtk_move_beginning_of_line (entry);
gtk_move_beginning_of_line (entry);
break;
case GDK_End:
return_val = TRUE;
if (event->state & GDK_SHIFT_MASK)
{
if (entry->selection_start_pos == entry->selection_end_pos)
entry->selection_start_pos = entry->current_pos;
entry->current_pos = entry->selection_end_pos = entry->text_length;
}
else
gtk_move_end_of_line (entry);
break;
return_val = TRUE;
gtk_move_end_of_line (entry);
break;
case GDK_Left:
return_val = TRUE;
if (event->state & GDK_SHIFT_MASK)
{
if (entry->selection_start_pos == entry->selection_end_pos)
entry->selection_start_pos = entry->selection_end_pos = entry->current_pos;
if (entry->selection_end_pos > 0)
entry->current_pos = --entry->selection_end_pos;
}
else
gtk_move_backward_character (entry);
break;
return_val = TRUE;
gtk_move_backward_character (entry);
break;
case GDK_Right:
return_val = TRUE;
if (event->state & GDK_SHIFT_MASK)
{
if (entry->selection_start_pos == entry->selection_end_pos)
entry->selection_start_pos = entry->selection_end_pos = entry->current_pos;
if (entry->selection_end_pos < entry->text_length)
entry->current_pos = ++entry->selection_end_pos;
}
else
gtk_move_forward_character (entry);
gtk_move_forward_character (entry);
break;
case GDK_Return:
return_val = TRUE;
@ -1066,7 +1058,7 @@ gtk_entry_key_press (GtkWidget *widget,
if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a'])
{
(* control_keys[key - 'a']) (entry);
(* control_keys[key - 'a']) (entry, event);
return_val = TRUE;
}
break;
@ -1078,7 +1070,7 @@ gtk_entry_key_press (GtkWidget *widget,
if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a'])
{
(* alt_keys[key - 'a']) (entry);
(* alt_keys[key - 'a']) (entry, event);
return_val = TRUE;
}
break;
@ -1086,6 +1078,7 @@ gtk_entry_key_press (GtkWidget *widget,
}
if (event->length > 0)
{
extend_selection = FALSE;
gtk_delete_selection (entry);
tmp_pos = entry->current_pos;
@ -1097,24 +1090,39 @@ gtk_entry_key_press (GtkWidget *widget,
break;
}
/* alex stuff */
if (entry->selection_start_pos != entry->selection_end_pos)
{
if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time))
{
entry->have_selection = TRUE;
gtk_entry_queue_draw (entry);
}
}
else
{
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
}
/* end of alex stuff */
if (return_val)
{
if (extend_selection)
{
if (entry->current_pos < entry->selection_start_pos)
entry->selection_start_pos = entry->current_pos;
else if (entry->current_pos > entry->selection_end_pos)
entry->selection_end_pos = entry->current_pos;
else
{
if (extend_start)
entry->selection_start_pos = entry->current_pos;
else
entry->selection_end_pos = entry->current_pos;
}
}
/* alex stuff */
if (entry->selection_start_pos != entry->selection_end_pos)
{
if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time))
{
entry->have_selection = TRUE;
gtk_entry_queue_draw (entry);
}
}
else
{
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
}
/* end of alex stuff */
gtk_entry_adjust_scroll (entry);
gtk_entry_queue_draw (entry);
}
@ -1175,10 +1183,18 @@ gtk_entry_selection_clear (GtkWidget *widget,
entry = GTK_ENTRY (widget);
if (entry->have_selection)
if (event->selection == GDK_SELECTION_PRIMARY)
{
entry->have_selection = FALSE;
gtk_entry_queue_draw (entry);
if (entry->have_selection)
{
entry->have_selection = FALSE;
gtk_entry_queue_draw (entry);
}
}
else if (event->selection == clipboard_atom)
{
g_free (entry->clipboard_text);
entry->clipboard_text = NULL;
}
return FALSE;
@ -1193,40 +1209,51 @@ gtk_entry_selection_handler (GtkWidget *widget,
gint selection_start_pos;
gint selection_end_pos;
guchar *str;
gint length;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_ENTRY (widget));
entry = GTK_ENTRY (widget);
selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos);
selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos);
if (selection_data->selection == GDK_SELECTION_PRIMARY)
{
selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos);
selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos);
str = &entry->text[selection_start_pos];
length = selection_end_pos - selection_start_pos;
}
else /* CLIPBOARD */
{
if (!entry->clipboard_text)
return; /* Refuse */
str = entry->clipboard_text;
length = strlen (entry->clipboard_text);
}
if (selection_data->target == GDK_SELECTION_TYPE_STRING)
{
gtk_selection_data_set (selection_data,
GDK_SELECTION_TYPE_STRING,
8*sizeof(gchar),
&entry->text[selection_start_pos],
selection_end_pos - selection_start_pos);
8*sizeof(gchar), str, length);
}
else if (selection_data->target == text_atom ||
selection_data->target == ctext_atom)
{
gchar *str;
gint length;
guchar *text;
gchar c;
GdkAtom encoding;
gint format;
guchar *text;
gint new_length;
length = selection_end_pos - selection_start_pos;
c = entry->text[selection_end_pos];
entry->text[selection_end_pos] = '\0';
str = entry->text + selection_start_pos;
gdk_string_to_compound_text (str, &encoding, &format, &text, &length);
gtk_selection_data_set (selection_data, encoding, format, text, length);
c = str[length];
str[length] = '\0';
gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length);
gtk_selection_data_set (selection_data, encoding, format, text, new_length);
gdk_free_compound_text (text);
entry->text[selection_end_pos] = c;
str[length] = c;
}
}
@ -1256,17 +1283,29 @@ gtk_entry_selection_received (GtkWidget *widget,
{
/* avoid infinite loop */
if (selection_data->target != GDK_TARGET_STRING)
gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
gtk_selection_convert (widget, selection_data->selection,
GDK_TARGET_STRING, GDK_CURRENT_TIME);
return;
}
reselect = FALSE;
if ((entry->selection_start_pos != entry->selection_end_pos) &&
!entry->have_selection)
(!entry->have_selection ||
(selection_data->selection == clipboard_atom)))
{
reselect = TRUE;
gtk_delete_selection (entry);
/* Don't want to call gtk_delete_selection here if we are going
* to reclaim the selection to avoid extra server traffic */
if (entry->have_selection)
{
gtk_entry_delete_text (entry,
MIN (entry->selection_start_pos, entry->selection_end_pos),
MAX (entry->selection_start_pos, entry->selection_end_pos));
}
else
gtk_delete_selection (entry);
}
tmp_pos = old_pos = entry->current_pos;
@ -1299,13 +1338,12 @@ gtk_entry_selection_received (GtkWidget *widget,
gdk_free_text_list (list);
}
break;
case INVALID: /* quiet compiler */
break;
}
if (reselect)
{
gtk_select_region (entry, old_pos, entry->current_pos);
entry->have_selection = FALSE;
}
gtk_select_region (entry, old_pos, entry->current_pos);
gtk_entry_queue_draw (entry);
}
@ -1678,9 +1716,6 @@ gtk_move_forward_character (GtkEntry *entry)
}
if (entry->current_pos > entry->text_length)
entry->current_pos = entry->text_length;
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static gint
@ -1703,8 +1738,6 @@ move_backward_character (gchar *str, gint index)
static void
gtk_move_backward_character (GtkEntry *entry)
{
gint i;
gint diff = 0;
/* this routine is correct only if string is state-independent-encoded */
if (0 < entry->current_pos)
@ -1714,9 +1747,6 @@ gtk_move_backward_character (GtkEntry *entry)
if (entry->current_pos < 0)
entry->current_pos = 0;
}
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1733,18 +1763,18 @@ gtk_move_forward_word (GtkEntry *entry)
i = entry->current_pos;
len = mbtowc (&c, text+i, MB_CUR_MAX);
if (!(!isascii(c) || c == '_' || iswalnum (c)))
if (!iswalnum(c))
for (; i < entry->text_length; i+=len)
{
len = mbtowc (&c, text+i, MB_CUR_MAX);
if (len < 1 || !isascii(c) || c == '_' || iswalnum (c))
if (len < 1 || iswalnum(c))
break;
}
for (; i < entry->text_length; i+=len)
{
len = mbtowc (&c, text+i, MB_CUR_MAX);
if (len < 1 || !(!isascii(c) || c == '_' || iswalnum (c)))
if (len < 1 || !iswalnum(c))
break;
}
@ -1752,9 +1782,6 @@ gtk_move_forward_word (GtkEntry *entry)
if (entry->current_pos > entry->text_length)
entry->current_pos = entry->text_length;
}
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1768,7 +1795,7 @@ gtk_move_backward_word (GtkEntry *entry)
if (entry->text)
{
text = entry->text;
i = entry->current_pos - 1;
i=move_backward_character(text, entry->current_pos);
if (i < 0) /* Per */
{
entry->selection_start_pos = 0;
@ -1777,50 +1804,41 @@ gtk_move_backward_word (GtkEntry *entry)
}
len = mbtowc (&c, text+i, MB_CUR_MAX);
if (!(!isascii(c) || (c == '_') || iswalnum (c)))
if (!iswalnum(c))
for (; i >= 0; i=move_backward_character(text, i))
{
len = mbtowc (&c, text+i, MB_CUR_MAX);
if (!isascii(c) || (c == '_') || iswalnum (c))
if (iswalnum(c))
break;
}
for (; i >= 0; i=move_backward_character(text, i))
{
len = mbtowc (&c, text+i, MB_CUR_MAX);
if (!(!isascii(c) || (c == '_') || iswalnum (c)))
if (!iswalnum(c))
{
i += len;
break;
}
}
if (i < 0)
i = 0;
entry->current_pos = i;
if (entry->current_pos < 0)
entry->current_pos = 0;
if (text[entry->current_pos] == ' ')
entry->current_pos += 1;
}
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
gtk_move_beginning_of_line (GtkEntry *entry)
{
entry->current_pos = 0;
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
gtk_move_end_of_line (GtkEntry *entry)
{
entry->current_pos = entry->text_length;
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1831,9 +1849,6 @@ gtk_delete_forward_character (GtkEntry *entry)
old_pos = entry->current_pos;
gtk_move_forward_character (entry);
gtk_entry_delete_text (entry, old_pos, entry->current_pos);
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1844,9 +1859,6 @@ gtk_delete_backward_character (GtkEntry *entry)
old_pos = entry->current_pos;
gtk_move_backward_character (entry);
gtk_entry_delete_text (entry, entry->current_pos, old_pos);
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1857,9 +1869,6 @@ gtk_delete_forward_word (GtkEntry *entry)
old_pos = entry->current_pos;
gtk_move_forward_word (entry);
gtk_entry_delete_text (entry, old_pos, entry->current_pos);
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1870,27 +1879,18 @@ gtk_delete_backward_word (GtkEntry *entry)
old_pos = entry->current_pos;
gtk_move_backward_word (entry);
gtk_entry_delete_text (entry, entry->current_pos, old_pos);
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
gtk_delete_line (GtkEntry *entry)
{
gtk_entry_delete_text (entry, 0, entry->text_length);
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
gtk_delete_to_line_end (GtkEntry *entry)
{
gtk_entry_delete_text (entry, entry->current_pos, entry->text_length);
entry->selection_start_pos = 0;
entry->selection_end_pos = 0;
}
static void
@ -1907,7 +1907,8 @@ gtk_delete_selection (GtkEntry *entry)
if (entry->have_selection)
{
entry->have_selection = FALSE;
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (entry)->window)
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
}
}
@ -1919,6 +1920,7 @@ gtk_select_word (GtkEntry *entry)
gtk_move_backward_word (entry);
start_pos = entry->current_pos;
end_pos = entry->current_pos;
gtk_move_forward_word (entry);
end_pos = entry->current_pos;
@ -1942,3 +1944,44 @@ gtk_select_region (GtkEntry *entry,
entry->selection_start_pos = start;
entry->selection_end_pos = end;
}
static void
gtk_entry_cut_clipboard (GtkEntry *entry, GdkEventKey *event)
{
gtk_entry_copy_clipboard (entry, event);
gtk_delete_selection (entry);
gtk_entry_queue_draw (entry);
}
static void
gtk_entry_copy_clipboard (GtkEntry *entry, GdkEventKey *event)
{
gint selection_start_pos;
gint selection_end_pos;
selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos);
selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos);
if (selection_start_pos != selection_end_pos)
{
if (gtk_selection_owner_set (GTK_WIDGET (entry),
clipboard_atom,
event->time))
{
char c;
c = entry->text[selection_end_pos];
entry->text[selection_end_pos] = 0;
entry->clipboard_text = g_strdup (entry->text + selection_start_pos);
entry->text[selection_end_pos] = c;
}
}
}
static void
gtk_entry_paste_clipboard (GtkEntry *entry, GdkEventKey *event)
{
gtk_selection_convert (GTK_WIDGET(entry),
clipboard_atom, ctext_atom, event->time);
}

View File

@ -52,9 +52,9 @@ struct _GtkEntry
guint have_selection : 1;
guint visible : 1;
guint32 timer;
#ifdef USE_XIM
GdkIC ic;
#endif
gchar *clipboard_text;
};
struct _GtkEntryClass