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 Library 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 | * Library General Public License for more details. |
---|
13 | * |
---|
14 | * You should have received a copy of the GNU Library General Public |
---|
15 | * License along with this library; if not, write to the |
---|
16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
17 | * Boston, MA 02111-1307, USA. |
---|
18 | */ |
---|
19 | |
---|
20 | /* |
---|
21 | * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS |
---|
22 | * file for a list of people on the GTK+ Team. See the ChangeLog |
---|
23 | * files for a list of changes. These files are distributed with |
---|
24 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
---|
25 | */ |
---|
26 | |
---|
27 | #include <ctype.h> |
---|
28 | #include <string.h> |
---|
29 | #include "gdk/gdkkeysyms.h" |
---|
30 | #include "gdk/gdki18n.h" |
---|
31 | #include "gtkentry.h" |
---|
32 | #include "gtkmain.h" |
---|
33 | #include "gtkselection.h" |
---|
34 | #include "gtksignal.h" |
---|
35 | #include "gtkstyle.h" |
---|
36 | |
---|
37 | #define MIN_ENTRY_WIDTH 150 |
---|
38 | #define DRAW_TIMEOUT 20 |
---|
39 | |
---|
40 | /* If you are going to change this, see the note in entry_adjust_scroll */ |
---|
41 | #define INNER_BORDER 2 |
---|
42 | |
---|
43 | enum { |
---|
44 | ARG_0, |
---|
45 | ARG_MAX_LENGTH, |
---|
46 | ARG_VISIBILITY |
---|
47 | }; |
---|
48 | |
---|
49 | |
---|
50 | static void gtk_entry_class_init (GtkEntryClass *klass); |
---|
51 | static void gtk_entry_init (GtkEntry *entry); |
---|
52 | static void gtk_entry_set_arg (GtkObject *object, |
---|
53 | GtkArg *arg, |
---|
54 | guint arg_id); |
---|
55 | static void gtk_entry_get_arg (GtkObject *object, |
---|
56 | GtkArg *arg, |
---|
57 | guint arg_id); |
---|
58 | static void gtk_entry_finalize (GtkObject *object); |
---|
59 | static void gtk_entry_realize (GtkWidget *widget); |
---|
60 | static void gtk_entry_unrealize (GtkWidget *widget); |
---|
61 | static void gtk_entry_draw_focus (GtkWidget *widget); |
---|
62 | static void gtk_entry_size_request (GtkWidget *widget, |
---|
63 | GtkRequisition *requisition); |
---|
64 | static void gtk_entry_size_allocate (GtkWidget *widget, |
---|
65 | GtkAllocation *allocation); |
---|
66 | static void gtk_entry_make_backing_pixmap (GtkEntry *entry, |
---|
67 | gint width, gint height); |
---|
68 | static void gtk_entry_draw (GtkWidget *widget, |
---|
69 | GdkRectangle *area); |
---|
70 | static gint gtk_entry_expose (GtkWidget *widget, |
---|
71 | GdkEventExpose *event); |
---|
72 | static gint gtk_entry_button_press (GtkWidget *widget, |
---|
73 | GdkEventButton *event); |
---|
74 | static gint gtk_entry_button_release (GtkWidget *widget, |
---|
75 | GdkEventButton *event); |
---|
76 | static gint gtk_entry_motion_notify (GtkWidget *widget, |
---|
77 | GdkEventMotion *event); |
---|
78 | static gint gtk_entry_key_press (GtkWidget *widget, |
---|
79 | GdkEventKey *event); |
---|
80 | static gint gtk_entry_focus_in (GtkWidget *widget, |
---|
81 | GdkEventFocus *event); |
---|
82 | static gint gtk_entry_focus_out (GtkWidget *widget, |
---|
83 | GdkEventFocus *event); |
---|
84 | static void gtk_entry_draw_text (GtkEntry *entry); |
---|
85 | static void gtk_entry_draw_cursor (GtkEntry *entry); |
---|
86 | static void gtk_entry_draw_cursor_on_drawable |
---|
87 | (GtkEntry *entry, |
---|
88 | GdkDrawable *drawable); |
---|
89 | static void gtk_entry_style_set (GtkWidget *widget, |
---|
90 | GtkStyle *previous_style); |
---|
91 | static void gtk_entry_state_changed (GtkWidget *widget, |
---|
92 | GtkStateType previous_state); |
---|
93 | #ifdef USE_XIM |
---|
94 | static void gtk_entry_update_ic_attr (GtkWidget *widget); |
---|
95 | #endif |
---|
96 | static void gtk_entry_queue_draw (GtkEntry *entry); |
---|
97 | static gint gtk_entry_timer (gpointer data); |
---|
98 | static gint gtk_entry_position (GtkEntry *entry, |
---|
99 | gint x); |
---|
100 | static void entry_adjust_scroll (GtkEntry *entry); |
---|
101 | static void gtk_entry_grow_text (GtkEntry *entry); |
---|
102 | static void gtk_entry_insert_text (GtkEditable *editable, |
---|
103 | const gchar *new_text, |
---|
104 | gint new_text_length, |
---|
105 | gint *position); |
---|
106 | static void gtk_entry_delete_text (GtkEditable *editable, |
---|
107 | gint start_pos, |
---|
108 | gint end_pos); |
---|
109 | static void gtk_entry_update_text (GtkEditable *editable, |
---|
110 | gint start_pos, |
---|
111 | gint end_pos); |
---|
112 | static gchar *gtk_entry_get_chars (GtkEditable *editable, |
---|
113 | gint start_pos, |
---|
114 | gint end_pos); |
---|
115 | |
---|
116 | /* Binding actions */ |
---|
117 | static void gtk_entry_move_cursor (GtkEditable *editable, |
---|
118 | gint x, |
---|
119 | gint y); |
---|
120 | static void gtk_entry_move_word (GtkEditable *editable, |
---|
121 | gint n); |
---|
122 | static void gtk_entry_move_to_column (GtkEditable *editable, |
---|
123 | gint row); |
---|
124 | static void gtk_entry_kill_char (GtkEditable *editable, |
---|
125 | gint direction); |
---|
126 | static void gtk_entry_kill_word (GtkEditable *editable, |
---|
127 | gint direction); |
---|
128 | static void gtk_entry_kill_line (GtkEditable *editable, |
---|
129 | gint direction); |
---|
130 | |
---|
131 | /* To be removed */ |
---|
132 | static void gtk_move_forward_character (GtkEntry *entry); |
---|
133 | static void gtk_move_backward_character (GtkEntry *entry); |
---|
134 | static void gtk_move_forward_word (GtkEntry *entry); |
---|
135 | static void gtk_move_backward_word (GtkEntry *entry); |
---|
136 | static void gtk_move_beginning_of_line (GtkEntry *entry); |
---|
137 | static void gtk_move_end_of_line (GtkEntry *entry); |
---|
138 | static void gtk_delete_forward_character (GtkEntry *entry); |
---|
139 | static void gtk_delete_backward_character (GtkEntry *entry); |
---|
140 | static void gtk_delete_forward_word (GtkEntry *entry); |
---|
141 | static void gtk_delete_backward_word (GtkEntry *entry); |
---|
142 | static void gtk_delete_line (GtkEntry *entry); |
---|
143 | static void gtk_delete_to_line_end (GtkEntry *entry); |
---|
144 | static void gtk_select_word (GtkEntry *entry, |
---|
145 | guint32 time); |
---|
146 | static void gtk_select_line (GtkEntry *entry, |
---|
147 | guint32 time); |
---|
148 | |
---|
149 | |
---|
150 | static void gtk_entry_set_selection (GtkEditable *editable, |
---|
151 | gint start, |
---|
152 | gint end); |
---|
153 | |
---|
154 | static void gtk_entry_recompute_offsets (GtkEntry *entry); |
---|
155 | static gint gtk_entry_find_position (GtkEntry *entry, |
---|
156 | gint position); |
---|
157 | static void gtk_entry_set_position_from_editable (GtkEditable *editable, |
---|
158 | gint position); |
---|
159 | |
---|
160 | static GtkWidgetClass *parent_class = NULL; |
---|
161 | static GdkAtom ctext_atom = GDK_NONE; |
---|
162 | |
---|
163 | static const GtkTextFunction control_keys[26] = |
---|
164 | { |
---|
165 | (GtkTextFunction)gtk_move_beginning_of_line, /* a */ |
---|
166 | (GtkTextFunction)gtk_move_backward_character, /* b */ |
---|
167 | (GtkTextFunction)gtk_editable_copy_clipboard, /* c */ |
---|
168 | (GtkTextFunction)gtk_delete_forward_character, /* d */ |
---|
169 | (GtkTextFunction)gtk_move_end_of_line, /* e */ |
---|
170 | (GtkTextFunction)gtk_move_forward_character, /* f */ |
---|
171 | NULL, /* g */ |
---|
172 | (GtkTextFunction)gtk_delete_backward_character, /* h */ |
---|
173 | NULL, /* i */ |
---|
174 | NULL, /* j */ |
---|
175 | (GtkTextFunction)gtk_delete_to_line_end, /* k */ |
---|
176 | NULL, /* l */ |
---|
177 | NULL, /* m */ |
---|
178 | NULL, /* n */ |
---|
179 | NULL, /* o */ |
---|
180 | NULL, /* p */ |
---|
181 | NULL, /* q */ |
---|
182 | NULL, /* r */ |
---|
183 | NULL, /* s */ |
---|
184 | NULL, /* t */ |
---|
185 | (GtkTextFunction)gtk_delete_line, /* u */ |
---|
186 | (GtkTextFunction)gtk_editable_paste_clipboard, /* v */ |
---|
187 | (GtkTextFunction)gtk_delete_backward_word, /* w */ |
---|
188 | (GtkTextFunction)gtk_editable_cut_clipboard, /* x */ |
---|
189 | NULL, /* y */ |
---|
190 | NULL, /* z */ |
---|
191 | }; |
---|
192 | |
---|
193 | static const GtkTextFunction alt_keys[26] = |
---|
194 | { |
---|
195 | NULL, /* a */ |
---|
196 | (GtkTextFunction)gtk_move_backward_word, /* b */ |
---|
197 | NULL, /* c */ |
---|
198 | (GtkTextFunction)gtk_delete_forward_word, /* d */ |
---|
199 | NULL, /* e */ |
---|
200 | (GtkTextFunction)gtk_move_forward_word, /* f */ |
---|
201 | NULL, /* g */ |
---|
202 | NULL, /* h */ |
---|
203 | NULL, /* i */ |
---|
204 | NULL, /* j */ |
---|
205 | NULL, /* k */ |
---|
206 | NULL, /* l */ |
---|
207 | NULL, /* m */ |
---|
208 | NULL, /* n */ |
---|
209 | NULL, /* o */ |
---|
210 | NULL, /* p */ |
---|
211 | NULL, /* q */ |
---|
212 | NULL, /* r */ |
---|
213 | NULL, /* s */ |
---|
214 | NULL, /* t */ |
---|
215 | NULL, /* u */ |
---|
216 | NULL, /* v */ |
---|
217 | NULL, /* w */ |
---|
218 | NULL, /* x */ |
---|
219 | NULL, /* y */ |
---|
220 | NULL, /* z */ |
---|
221 | }; |
---|
222 | |
---|
223 | |
---|
224 | GtkType |
---|
225 | gtk_entry_get_type (void) |
---|
226 | { |
---|
227 | static GtkType entry_type = 0; |
---|
228 | |
---|
229 | if (!entry_type) |
---|
230 | { |
---|
231 | static const GtkTypeInfo entry_info = |
---|
232 | { |
---|
233 | "GtkEntry", |
---|
234 | sizeof (GtkEntry), |
---|
235 | sizeof (GtkEntryClass), |
---|
236 | (GtkClassInitFunc) gtk_entry_class_init, |
---|
237 | (GtkObjectInitFunc) gtk_entry_init, |
---|
238 | /* reserved_1 */ NULL, |
---|
239 | /* reserved_2 */ NULL, |
---|
240 | (GtkClassInitFunc) NULL, |
---|
241 | }; |
---|
242 | |
---|
243 | entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info); |
---|
244 | } |
---|
245 | |
---|
246 | return entry_type; |
---|
247 | } |
---|
248 | |
---|
249 | static void |
---|
250 | gtk_entry_class_init (GtkEntryClass *class) |
---|
251 | { |
---|
252 | GtkObjectClass *object_class; |
---|
253 | GtkWidgetClass *widget_class; |
---|
254 | GtkEditableClass *editable_class; |
---|
255 | |
---|
256 | object_class = (GtkObjectClass*) class; |
---|
257 | widget_class = (GtkWidgetClass*) class; |
---|
258 | editable_class = (GtkEditableClass*) class; |
---|
259 | parent_class = gtk_type_class (GTK_TYPE_EDITABLE); |
---|
260 | |
---|
261 | gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH); |
---|
262 | gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY); |
---|
263 | |
---|
264 | object_class->set_arg = gtk_entry_set_arg; |
---|
265 | object_class->get_arg = gtk_entry_get_arg; |
---|
266 | object_class->finalize = gtk_entry_finalize; |
---|
267 | |
---|
268 | widget_class->realize = gtk_entry_realize; |
---|
269 | widget_class->unrealize = gtk_entry_unrealize; |
---|
270 | widget_class->draw_focus = gtk_entry_draw_focus; |
---|
271 | widget_class->size_request = gtk_entry_size_request; |
---|
272 | widget_class->size_allocate = gtk_entry_size_allocate; |
---|
273 | widget_class->draw = gtk_entry_draw; |
---|
274 | widget_class->expose_event = gtk_entry_expose; |
---|
275 | widget_class->button_press_event = gtk_entry_button_press; |
---|
276 | widget_class->button_release_event = gtk_entry_button_release; |
---|
277 | widget_class->motion_notify_event = gtk_entry_motion_notify; |
---|
278 | widget_class->key_press_event = gtk_entry_key_press; |
---|
279 | widget_class->focus_in_event = gtk_entry_focus_in; |
---|
280 | widget_class->focus_out_event = gtk_entry_focus_out; |
---|
281 | widget_class->style_set = gtk_entry_style_set; |
---|
282 | widget_class->state_changed = gtk_entry_state_changed; |
---|
283 | |
---|
284 | editable_class->insert_text = gtk_entry_insert_text; |
---|
285 | editable_class->delete_text = gtk_entry_delete_text; |
---|
286 | editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll; |
---|
287 | |
---|
288 | editable_class->move_cursor = gtk_entry_move_cursor; |
---|
289 | editable_class->move_word = gtk_entry_move_word; |
---|
290 | editable_class->move_to_column = gtk_entry_move_to_column; |
---|
291 | |
---|
292 | editable_class->kill_char = gtk_entry_kill_char; |
---|
293 | editable_class->kill_word = gtk_entry_kill_word; |
---|
294 | editable_class->kill_line = gtk_entry_kill_line; |
---|
295 | |
---|
296 | editable_class->update_text = gtk_entry_update_text; |
---|
297 | editable_class->get_chars = gtk_entry_get_chars; |
---|
298 | editable_class->set_selection = gtk_entry_set_selection; |
---|
299 | editable_class->set_position = gtk_entry_set_position_from_editable; |
---|
300 | } |
---|
301 | |
---|
302 | static void |
---|
303 | gtk_entry_set_arg (GtkObject *object, |
---|
304 | GtkArg *arg, |
---|
305 | guint arg_id) |
---|
306 | { |
---|
307 | GtkEntry *entry; |
---|
308 | |
---|
309 | entry = GTK_ENTRY (object); |
---|
310 | |
---|
311 | switch (arg_id) |
---|
312 | { |
---|
313 | case ARG_MAX_LENGTH: |
---|
314 | gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg)); |
---|
315 | break; |
---|
316 | case ARG_VISIBILITY: |
---|
317 | gtk_entry_set_visibility (entry, GTK_VALUE_BOOL (*arg)); |
---|
318 | break; |
---|
319 | default: |
---|
320 | break; |
---|
321 | } |
---|
322 | } |
---|
323 | |
---|
324 | static void |
---|
325 | gtk_entry_get_arg (GtkObject *object, |
---|
326 | GtkArg *arg, |
---|
327 | guint arg_id) |
---|
328 | { |
---|
329 | GtkEntry *entry; |
---|
330 | |
---|
331 | entry = GTK_ENTRY (object); |
---|
332 | |
---|
333 | switch (arg_id) |
---|
334 | { |
---|
335 | case ARG_MAX_LENGTH: |
---|
336 | GTK_VALUE_UINT (*arg) = entry->text_max_length; |
---|
337 | break; |
---|
338 | case ARG_VISIBILITY: |
---|
339 | GTK_VALUE_BOOL (*arg) = GTK_EDITABLE (entry)->visible; |
---|
340 | break; |
---|
341 | default: |
---|
342 | arg->type = GTK_TYPE_INVALID; |
---|
343 | break; |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | static void |
---|
348 | gtk_entry_init (GtkEntry *entry) |
---|
349 | { |
---|
350 | GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS); |
---|
351 | |
---|
352 | entry->text_area = NULL; |
---|
353 | entry->backing_pixmap = NULL; |
---|
354 | entry->text = NULL; |
---|
355 | entry->text_size = 0; |
---|
356 | entry->text_length = 0; |
---|
357 | entry->text_max_length = 0; |
---|
358 | entry->scroll_offset = 0; |
---|
359 | entry->timer = 0; |
---|
360 | entry->button = 0; |
---|
361 | entry->visible = 1; |
---|
362 | |
---|
363 | entry->char_offset = NULL; |
---|
364 | entry->text_mb = NULL; |
---|
365 | entry->text_mb_dirty = TRUE; |
---|
366 | entry->use_wchar = FALSE; |
---|
367 | |
---|
368 | gtk_entry_grow_text (entry); |
---|
369 | } |
---|
370 | |
---|
371 | GtkWidget* |
---|
372 | gtk_entry_new (void) |
---|
373 | { |
---|
374 | return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY)); |
---|
375 | } |
---|
376 | |
---|
377 | static GdkWChar |
---|
378 | gtk_entry_get_invisible_char (GtkEntry *entry) |
---|
379 | { |
---|
380 | GdkWChar ch = 0; |
---|
381 | |
---|
382 | if (entry->use_wchar) |
---|
383 | gdk_mbstowcs (&ch, "*", 1); |
---|
384 | else |
---|
385 | ch = '*'; |
---|
386 | |
---|
387 | return ch; |
---|
388 | } |
---|
389 | |
---|
390 | /* |
---|
391 | * Draws the string, noting that if entry->use_wchar is false, then |
---|
392 | * the text is not really wide characters, but narrow characters |
---|
393 | * stored as wide characters. |
---|
394 | */ |
---|
395 | static void |
---|
396 | gtk_entry_draw_wchars (GtkEntry *entry, |
---|
397 | GdkDrawable *drawable, |
---|
398 | GdkFont *font, |
---|
399 | GdkGC *gc, |
---|
400 | gint x, |
---|
401 | gint y, |
---|
402 | const GdkWChar *text, |
---|
403 | gint text_length) |
---|
404 | { |
---|
405 | if (entry->use_wchar) |
---|
406 | gdk_draw_text_wc (drawable, font, gc, x, y, text, text_length); |
---|
407 | else |
---|
408 | { |
---|
409 | gint i; |
---|
410 | gchar *mbstr = g_new (gchar, text_length); |
---|
411 | |
---|
412 | for (i = 0; i < text_length; i++) |
---|
413 | mbstr[i] = text[i]; |
---|
414 | gdk_draw_text (drawable, font, gc, x, y, mbstr, text_length); |
---|
415 | g_free(mbstr); |
---|
416 | } |
---|
417 | } |
---|
418 | |
---|
419 | GtkWidget* |
---|
420 | gtk_entry_new_with_max_length (guint16 max) |
---|
421 | { |
---|
422 | GtkEntry *entry; |
---|
423 | |
---|
424 | entry = gtk_type_new (GTK_TYPE_ENTRY); |
---|
425 | entry->text_max_length = max; |
---|
426 | |
---|
427 | return GTK_WIDGET (entry); |
---|
428 | } |
---|
429 | |
---|
430 | void |
---|
431 | gtk_entry_set_text (GtkEntry *entry, |
---|
432 | const gchar *text) |
---|
433 | { |
---|
434 | gint tmp_pos; |
---|
435 | |
---|
436 | GtkEditable *editable; |
---|
437 | |
---|
438 | g_return_if_fail (entry != NULL); |
---|
439 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
440 | g_return_if_fail (text != NULL); |
---|
441 | |
---|
442 | editable = GTK_EDITABLE (entry); |
---|
443 | |
---|
444 | gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length); |
---|
445 | |
---|
446 | tmp_pos = 0; |
---|
447 | gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos); |
---|
448 | editable->current_pos = tmp_pos; |
---|
449 | |
---|
450 | editable->selection_start_pos = 0; |
---|
451 | editable->selection_end_pos = 0; |
---|
452 | |
---|
453 | if (GTK_WIDGET_DRAWABLE (entry)) |
---|
454 | gtk_entry_draw_text (entry); |
---|
455 | } |
---|
456 | |
---|
457 | void |
---|
458 | gtk_entry_append_text (GtkEntry *entry, |
---|
459 | const gchar *text) |
---|
460 | { |
---|
461 | gint tmp_pos; |
---|
462 | |
---|
463 | g_return_if_fail (entry != NULL); |
---|
464 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
465 | g_return_if_fail (text != NULL); |
---|
466 | |
---|
467 | tmp_pos = entry->text_length; |
---|
468 | gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos); |
---|
469 | GTK_EDITABLE(entry)->current_pos = tmp_pos; |
---|
470 | } |
---|
471 | |
---|
472 | void |
---|
473 | gtk_entry_prepend_text (GtkEntry *entry, |
---|
474 | const gchar *text) |
---|
475 | { |
---|
476 | gint tmp_pos; |
---|
477 | |
---|
478 | g_return_if_fail (entry != NULL); |
---|
479 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
480 | g_return_if_fail (text != NULL); |
---|
481 | |
---|
482 | tmp_pos = 0; |
---|
483 | gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos); |
---|
484 | GTK_EDITABLE(entry)->current_pos = tmp_pos; |
---|
485 | } |
---|
486 | |
---|
487 | void |
---|
488 | gtk_entry_set_position (GtkEntry *entry, |
---|
489 | gint position) |
---|
490 | { |
---|
491 | g_return_if_fail (entry != NULL); |
---|
492 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
493 | |
---|
494 | if ((position == -1) || (position > entry->text_length)) |
---|
495 | GTK_EDITABLE(entry)->current_pos = entry->text_length; |
---|
496 | else |
---|
497 | GTK_EDITABLE(entry)->current_pos = position; |
---|
498 | entry_adjust_scroll (entry); |
---|
499 | } |
---|
500 | |
---|
501 | static void |
---|
502 | gtk_entry_set_position_from_editable (GtkEditable *editable, |
---|
503 | gint position) |
---|
504 | { |
---|
505 | gtk_entry_set_position (GTK_ENTRY (editable), position); |
---|
506 | } |
---|
507 | |
---|
508 | void |
---|
509 | gtk_entry_set_visibility (GtkEntry *entry, |
---|
510 | gboolean visible) |
---|
511 | { |
---|
512 | g_return_if_fail (entry != NULL); |
---|
513 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
514 | |
---|
515 | entry->visible = visible ? TRUE : FALSE; |
---|
516 | GTK_EDITABLE (entry)->visible = visible ? TRUE : FALSE; |
---|
517 | gtk_entry_recompute_offsets (entry); |
---|
518 | gtk_widget_queue_draw (GTK_WIDGET (entry)); |
---|
519 | } |
---|
520 | |
---|
521 | void |
---|
522 | gtk_entry_set_editable(GtkEntry *entry, |
---|
523 | gboolean editable) |
---|
524 | { |
---|
525 | g_return_if_fail (entry != NULL); |
---|
526 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
527 | |
---|
528 | gtk_editable_set_editable (GTK_EDITABLE (entry), editable); |
---|
529 | } |
---|
530 | |
---|
531 | gchar* |
---|
532 | gtk_entry_get_text (GtkEntry *entry) |
---|
533 | { |
---|
534 | g_return_val_if_fail (entry != NULL, NULL); |
---|
535 | g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); |
---|
536 | |
---|
537 | if (!entry->text_mb_dirty) |
---|
538 | return entry->text_mb; |
---|
539 | |
---|
540 | if (entry->text_mb) |
---|
541 | g_free(entry->text_mb); |
---|
542 | |
---|
543 | if (!entry->text) |
---|
544 | { |
---|
545 | entry->text_mb = g_new(gchar, 1); |
---|
546 | entry->text_mb[0] = 0; |
---|
547 | } |
---|
548 | else |
---|
549 | { |
---|
550 | entry->text_mb = gtk_entry_get_chars(GTK_EDITABLE(entry), 0, -1); |
---|
551 | } |
---|
552 | entry->text_mb_dirty = 0; |
---|
553 | |
---|
554 | return entry->text_mb; |
---|
555 | } |
---|
556 | |
---|
557 | static void |
---|
558 | gtk_entry_finalize (GtkObject *object) |
---|
559 | { |
---|
560 | GtkEntry *entry; |
---|
561 | |
---|
562 | g_return_if_fail (object != NULL); |
---|
563 | g_return_if_fail (GTK_IS_ENTRY (object)); |
---|
564 | |
---|
565 | entry = GTK_ENTRY (object); |
---|
566 | |
---|
567 | if (entry->timer) |
---|
568 | gtk_timeout_remove (entry->timer); |
---|
569 | |
---|
570 | entry->text_size = 0; |
---|
571 | |
---|
572 | if (entry->text) |
---|
573 | g_free (entry->text); |
---|
574 | if (entry->char_offset) |
---|
575 | g_free (entry->char_offset); |
---|
576 | entry->text = NULL; |
---|
577 | |
---|
578 | if (entry->text_mb) |
---|
579 | g_free (entry->text_mb); |
---|
580 | entry->text_mb = NULL; |
---|
581 | |
---|
582 | if (entry->backing_pixmap) |
---|
583 | gdk_pixmap_unref (entry->backing_pixmap); |
---|
584 | |
---|
585 | (* GTK_OBJECT_CLASS (parent_class)->finalize) (object); |
---|
586 | } |
---|
587 | |
---|
588 | static void |
---|
589 | gtk_entry_realize (GtkWidget *widget) |
---|
590 | { |
---|
591 | GtkEntry *entry; |
---|
592 | GtkEditable *editable; |
---|
593 | GtkRequisition requisition; |
---|
594 | GdkWindowAttr attributes; |
---|
595 | gint attributes_mask; |
---|
596 | |
---|
597 | g_return_if_fail (widget != NULL); |
---|
598 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
599 | |
---|
600 | GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); |
---|
601 | entry = GTK_ENTRY (widget); |
---|
602 | editable = GTK_EDITABLE (widget); |
---|
603 | |
---|
604 | gtk_widget_get_child_requisition (widget, &requisition); |
---|
605 | |
---|
606 | attributes.window_type = GDK_WINDOW_CHILD; |
---|
607 | attributes.x = widget->allocation.x; |
---|
608 | attributes.y = widget->allocation.y + (widget->allocation.height - |
---|
609 | requisition.height) / 2; |
---|
610 | attributes.width = widget->allocation.width; |
---|
611 | attributes.height = requisition.height; |
---|
612 | attributes.wclass = GDK_INPUT_OUTPUT; |
---|
613 | attributes.visual = gtk_widget_get_visual (widget); |
---|
614 | attributes.colormap = gtk_widget_get_colormap (widget); |
---|
615 | attributes.event_mask = gtk_widget_get_events (widget); |
---|
616 | attributes.event_mask |= (GDK_EXPOSURE_MASK | |
---|
617 | GDK_BUTTON_PRESS_MASK | |
---|
618 | GDK_BUTTON_RELEASE_MASK | |
---|
619 | GDK_BUTTON1_MOTION_MASK | |
---|
620 | GDK_BUTTON3_MOTION_MASK | |
---|
621 | GDK_POINTER_MOTION_HINT_MASK | |
---|
622 | GDK_ENTER_NOTIFY_MASK | |
---|
623 | GDK_LEAVE_NOTIFY_MASK | |
---|
624 | GDK_KEY_PRESS_MASK); |
---|
625 | attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; |
---|
626 | |
---|
627 | widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); |
---|
628 | gdk_window_set_user_data (widget->window, entry); |
---|
629 | |
---|
630 | attributes.x = widget->style->klass->xthickness; |
---|
631 | attributes.y = widget->style->klass->ythickness; |
---|
632 | attributes.width = widget->allocation.width - attributes.x * 2; |
---|
633 | attributes.height = requisition.height - attributes.y * 2; |
---|
634 | attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM); |
---|
635 | attributes_mask |= GDK_WA_CURSOR; |
---|
636 | |
---|
637 | entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); |
---|
638 | gdk_window_set_user_data (entry->text_area, entry); |
---|
639 | |
---|
640 | widget->style = gtk_style_attach (widget->style, widget->window); |
---|
641 | |
---|
642 | gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); |
---|
643 | gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); |
---|
644 | |
---|
645 | #ifdef USE_XIM |
---|
646 | if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL) |
---|
647 | { |
---|
648 | gint width, height; |
---|
649 | GdkEventMask mask; |
---|
650 | GdkColormap *colormap; |
---|
651 | GdkICAttr *attr = editable->ic_attr; |
---|
652 | GdkICAttributesType attrmask = GDK_IC_ALL_REQ; |
---|
653 | GdkIMStyle style; |
---|
654 | GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE | |
---|
655 | GDK_IM_PREEDIT_NOTHING | |
---|
656 | GDK_IM_PREEDIT_POSITION | |
---|
657 | GDK_IM_STATUS_NONE | |
---|
658 | GDK_IM_STATUS_NOTHING; |
---|
659 | |
---|
660 | if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) |
---|
661 | supported_style &= ~GDK_IM_PREEDIT_POSITION; |
---|
662 | |
---|
663 | attr->style = style = gdk_im_decide_style (supported_style); |
---|
664 | attr->client_window = entry->text_area; |
---|
665 | |
---|
666 | if ((colormap = gtk_widget_get_colormap (widget)) != |
---|
667 | gtk_widget_get_default_colormap ()) |
---|
668 | { |
---|
669 | attrmask |= GDK_IC_PREEDIT_COLORMAP; |
---|
670 | attr->preedit_colormap = colormap; |
---|
671 | } |
---|
672 | attrmask |= GDK_IC_PREEDIT_FOREGROUND; |
---|
673 | attrmask |= GDK_IC_PREEDIT_BACKGROUND; |
---|
674 | attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL]; |
---|
675 | attr->preedit_background = widget->style->base[GTK_STATE_NORMAL]; |
---|
676 | |
---|
677 | switch (style & GDK_IM_PREEDIT_MASK) |
---|
678 | { |
---|
679 | case GDK_IM_PREEDIT_POSITION: |
---|
680 | if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) |
---|
681 | { |
---|
682 | g_warning ("over-the-spot style requires fontset"); |
---|
683 | break; |
---|
684 | } |
---|
685 | |
---|
686 | gdk_window_get_size (entry->text_area, &width, &height); |
---|
687 | |
---|
688 | attrmask |= GDK_IC_PREEDIT_POSITION_REQ; |
---|
689 | attr->spot_location.x = 0; |
---|
690 | attr->spot_location.y = height; |
---|
691 | attr->preedit_area.x = 0; |
---|
692 | attr->preedit_area.y = 0; |
---|
693 | attr->preedit_area.width = width; |
---|
694 | attr->preedit_area.height = height; |
---|
695 | attr->preedit_fontset = widget->style->font; |
---|
696 | |
---|
697 | break; |
---|
698 | } |
---|
699 | editable->ic = gdk_ic_new (attr, attrmask); |
---|
700 | |
---|
701 | if (editable->ic == NULL) |
---|
702 | g_warning ("Can't create input context."); |
---|
703 | else |
---|
704 | { |
---|
705 | mask = gdk_window_get_events (entry->text_area); |
---|
706 | mask |= gdk_ic_get_events (editable->ic); |
---|
707 | gdk_window_set_events (entry->text_area, mask); |
---|
708 | |
---|
709 | if (GTK_WIDGET_HAS_FOCUS(widget)) |
---|
710 | gdk_im_begin (editable->ic, entry->text_area); |
---|
711 | } |
---|
712 | } |
---|
713 | #endif |
---|
714 | |
---|
715 | gdk_window_show (entry->text_area); |
---|
716 | |
---|
717 | if (editable->selection_start_pos != editable->selection_end_pos) |
---|
718 | gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME); |
---|
719 | |
---|
720 | gtk_entry_recompute_offsets (entry); |
---|
721 | } |
---|
722 | |
---|
723 | static void |
---|
724 | gtk_entry_unrealize (GtkWidget *widget) |
---|
725 | { |
---|
726 | GtkEntry *entry; |
---|
727 | |
---|
728 | g_return_if_fail (widget != NULL); |
---|
729 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
730 | |
---|
731 | entry = GTK_ENTRY (widget); |
---|
732 | |
---|
733 | #ifdef USE_XIM |
---|
734 | if (GTK_EDITABLE (widget)->ic) |
---|
735 | { |
---|
736 | gdk_ic_destroy (GTK_EDITABLE (widget)->ic); |
---|
737 | GTK_EDITABLE (widget)->ic = NULL; |
---|
738 | } |
---|
739 | if (GTK_EDITABLE (widget)->ic_attr) |
---|
740 | { |
---|
741 | gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr); |
---|
742 | GTK_EDITABLE (widget)->ic_attr = NULL; |
---|
743 | } |
---|
744 | #endif |
---|
745 | |
---|
746 | if (entry->text_area) |
---|
747 | { |
---|
748 | gdk_window_set_user_data (entry->text_area, NULL); |
---|
749 | gdk_window_destroy (entry->text_area); |
---|
750 | entry->text_area = NULL; |
---|
751 | gdk_cursor_destroy (entry->cursor); |
---|
752 | entry->cursor = NULL; |
---|
753 | } |
---|
754 | |
---|
755 | if (GTK_WIDGET_CLASS (parent_class)->unrealize) |
---|
756 | (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); |
---|
757 | } |
---|
758 | |
---|
759 | static void |
---|
760 | gtk_entry_draw_focus (GtkWidget *widget) |
---|
761 | { |
---|
762 | gint width, height; |
---|
763 | gint x, y; |
---|
764 | |
---|
765 | g_return_if_fail (widget != NULL); |
---|
766 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
767 | |
---|
768 | if (GTK_WIDGET_DRAWABLE (widget)) |
---|
769 | { |
---|
770 | x = 0; |
---|
771 | y = 0; |
---|
772 | gdk_window_get_size (widget->window, &width, &height); |
---|
773 | |
---|
774 | if (GTK_WIDGET_HAS_FOCUS (widget)) |
---|
775 | { |
---|
776 | x += 1; |
---|
777 | y += 1; |
---|
778 | width -= 2; |
---|
779 | height -= 2; |
---|
780 | } |
---|
781 | |
---|
782 | gtk_paint_shadow (widget->style, widget->window, |
---|
783 | GTK_STATE_NORMAL, GTK_SHADOW_IN, |
---|
784 | NULL, widget, "entry", |
---|
785 | x, y, width, height); |
---|
786 | |
---|
787 | if (GTK_WIDGET_HAS_FOCUS (widget)) |
---|
788 | { |
---|
789 | gdk_window_get_size (widget->window, &width, &height); |
---|
790 | gtk_paint_focus (widget->style, widget->window, |
---|
791 | NULL, widget, "entry", |
---|
792 | 0, 0, width - 1, height - 1); |
---|
793 | } |
---|
794 | |
---|
795 | if (GTK_EDITABLE (widget)->editable) |
---|
796 | gtk_entry_draw_cursor (GTK_ENTRY (widget)); |
---|
797 | } |
---|
798 | } |
---|
799 | |
---|
800 | static void |
---|
801 | gtk_entry_size_request (GtkWidget *widget, |
---|
802 | GtkRequisition *requisition) |
---|
803 | { |
---|
804 | g_return_if_fail (widget != NULL); |
---|
805 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
806 | g_return_if_fail (requisition != NULL); |
---|
807 | |
---|
808 | requisition->width = MIN_ENTRY_WIDTH + (widget->style->klass->xthickness + INNER_BORDER) * 2; |
---|
809 | requisition->height = (widget->style->font->ascent + |
---|
810 | widget->style->font->descent + |
---|
811 | (widget->style->klass->ythickness + INNER_BORDER) * 2); |
---|
812 | } |
---|
813 | |
---|
814 | static void |
---|
815 | gtk_entry_size_allocate (GtkWidget *widget, |
---|
816 | GtkAllocation *allocation) |
---|
817 | { |
---|
818 | GtkEntry *entry; |
---|
819 | GtkEditable *editable; |
---|
820 | |
---|
821 | g_return_if_fail (widget != NULL); |
---|
822 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
823 | g_return_if_fail (allocation != NULL); |
---|
824 | |
---|
825 | widget->allocation = *allocation; |
---|
826 | entry = GTK_ENTRY (widget); |
---|
827 | editable = GTK_EDITABLE (widget); |
---|
828 | |
---|
829 | if (GTK_WIDGET_REALIZED (widget)) |
---|
830 | { |
---|
831 | /* We call gtk_widget_get_child_requisition, since we want (for |
---|
832 | * backwards compatibility reasons) the realization here to |
---|
833 | * be affected by the usize of the entry, if set |
---|
834 | */ |
---|
835 | GtkRequisition requisition; |
---|
836 | gtk_widget_get_child_requisition (widget, &requisition); |
---|
837 | |
---|
838 | gdk_window_move_resize (widget->window, |
---|
839 | allocation->x, |
---|
840 | allocation->y + (allocation->height - requisition.height) / 2, |
---|
841 | allocation->width, requisition.height); |
---|
842 | gdk_window_move_resize (entry->text_area, |
---|
843 | widget->style->klass->xthickness, |
---|
844 | widget->style->klass->ythickness, |
---|
845 | allocation->width - widget->style->klass->xthickness * 2, |
---|
846 | requisition.height - widget->style->klass->ythickness * 2); |
---|
847 | |
---|
848 | /* And make sure the cursor is on screen */ |
---|
849 | entry_adjust_scroll (entry); |
---|
850 | |
---|
851 | #ifdef USE_XIM |
---|
852 | if (editable->ic && |
---|
853 | (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION)) |
---|
854 | { |
---|
855 | gint width, height; |
---|
856 | |
---|
857 | gdk_window_get_size (entry->text_area, &width, &height); |
---|
858 | editable->ic_attr->preedit_area.width = width; |
---|
859 | editable->ic_attr->preedit_area.height = height; |
---|
860 | gdk_ic_set_attr (editable->ic, editable->ic_attr, |
---|
861 | GDK_IC_PREEDIT_AREA); |
---|
862 | } |
---|
863 | #endif |
---|
864 | } |
---|
865 | } |
---|
866 | |
---|
867 | static void |
---|
868 | gtk_entry_draw (GtkWidget *widget, |
---|
869 | GdkRectangle *area) |
---|
870 | { |
---|
871 | g_return_if_fail (widget != NULL); |
---|
872 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
873 | g_return_if_fail (area != NULL); |
---|
874 | |
---|
875 | if (GTK_WIDGET_DRAWABLE (widget)) |
---|
876 | { |
---|
877 | gtk_widget_draw_focus (widget); |
---|
878 | gtk_entry_draw_text (GTK_ENTRY (widget)); |
---|
879 | } |
---|
880 | } |
---|
881 | |
---|
882 | static gint |
---|
883 | gtk_entry_expose (GtkWidget *widget, |
---|
884 | GdkEventExpose *event) |
---|
885 | { |
---|
886 | GtkEntry *entry; |
---|
887 | |
---|
888 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
889 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
890 | g_return_val_if_fail (event != NULL, FALSE); |
---|
891 | |
---|
892 | entry = GTK_ENTRY (widget); |
---|
893 | |
---|
894 | if (widget->window == event->window) |
---|
895 | gtk_widget_draw_focus (widget); |
---|
896 | else if (entry->text_area == event->window) |
---|
897 | gtk_entry_draw_text (GTK_ENTRY (widget)); |
---|
898 | |
---|
899 | return FALSE; |
---|
900 | } |
---|
901 | |
---|
902 | static gint |
---|
903 | gtk_entry_button_press (GtkWidget *widget, |
---|
904 | GdkEventButton *event) |
---|
905 | { |
---|
906 | GtkEntry *entry; |
---|
907 | GtkEditable *editable; |
---|
908 | gint tmp_pos; |
---|
909 | |
---|
910 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
911 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
912 | g_return_val_if_fail (event != NULL, FALSE); |
---|
913 | |
---|
914 | if (ctext_atom == GDK_NONE) |
---|
915 | ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); |
---|
916 | |
---|
917 | entry = GTK_ENTRY (widget); |
---|
918 | editable = GTK_EDITABLE (widget); |
---|
919 | |
---|
920 | if (entry->button && (event->button != entry->button)) |
---|
921 | return FALSE; |
---|
922 | |
---|
923 | entry->button = event->button; |
---|
924 | |
---|
925 | if (!GTK_WIDGET_HAS_FOCUS (widget)) |
---|
926 | gtk_widget_grab_focus (widget); |
---|
927 | |
---|
928 | if (event->button == 1) |
---|
929 | { |
---|
930 | switch (event->type) |
---|
931 | { |
---|
932 | case GDK_BUTTON_PRESS: |
---|
933 | gtk_grab_add (widget); |
---|
934 | |
---|
935 | tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); |
---|
936 | /* Set it now, so we display things right. We'll unset it |
---|
937 | * later if things don't work out */ |
---|
938 | editable->has_selection = TRUE; |
---|
939 | gtk_entry_set_selection (editable, tmp_pos, tmp_pos); |
---|
940 | editable->current_pos = editable->selection_start_pos; |
---|
941 | break; |
---|
942 | |
---|
943 | case GDK_2BUTTON_PRESS: |
---|
944 | gtk_select_word (entry, event->time); |
---|
945 | break; |
---|
946 | |
---|
947 | case GDK_3BUTTON_PRESS: |
---|
948 | gtk_select_line (entry, event->time); |
---|
949 | break; |
---|
950 | |
---|
951 | default: |
---|
952 | break; |
---|
953 | } |
---|
954 | |
---|
955 | return TRUE; |
---|
956 | } |
---|
957 | else if (event->type == GDK_BUTTON_PRESS) |
---|
958 | { |
---|
959 | if ((event->button == 2) && editable->editable) |
---|
960 | { |
---|
961 | if (editable->selection_start_pos == editable->selection_end_pos || |
---|
962 | editable->has_selection) |
---|
963 | editable->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); |
---|
964 | gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, |
---|
965 | ctext_atom, event->time); |
---|
966 | } |
---|
967 | else |
---|
968 | { |
---|
969 | gtk_grab_add (widget); |
---|
970 | |
---|
971 | tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); |
---|
972 | gtk_entry_set_selection (editable, tmp_pos, tmp_pos); |
---|
973 | editable->has_selection = FALSE; |
---|
974 | editable->current_pos = editable->selection_start_pos; |
---|
975 | |
---|
976 | if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) |
---|
977 | gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); |
---|
978 | } |
---|
979 | |
---|
980 | return TRUE; |
---|
981 | } |
---|
982 | |
---|
983 | return FALSE; |
---|
984 | } |
---|
985 | |
---|
986 | static gint |
---|
987 | gtk_entry_button_release (GtkWidget *widget, |
---|
988 | GdkEventButton *event) |
---|
989 | { |
---|
990 | GtkEntry *entry; |
---|
991 | GtkEditable *editable; |
---|
992 | |
---|
993 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
994 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
995 | g_return_val_if_fail (event != NULL, FALSE); |
---|
996 | |
---|
997 | entry = GTK_ENTRY (widget); |
---|
998 | editable = GTK_EDITABLE (widget); |
---|
999 | |
---|
1000 | if (entry->button != event->button) |
---|
1001 | return FALSE; |
---|
1002 | |
---|
1003 | entry->button = 0; |
---|
1004 | |
---|
1005 | if (event->button == 1) |
---|
1006 | { |
---|
1007 | gtk_grab_remove (widget); |
---|
1008 | |
---|
1009 | editable->has_selection = FALSE; |
---|
1010 | if (editable->selection_start_pos != editable->selection_end_pos) |
---|
1011 | { |
---|
1012 | if (gtk_selection_owner_set (widget, |
---|
1013 | GDK_SELECTION_PRIMARY, |
---|
1014 | event->time)) |
---|
1015 | editable->has_selection = TRUE; |
---|
1016 | else |
---|
1017 | gtk_entry_queue_draw (entry); |
---|
1018 | } |
---|
1019 | else |
---|
1020 | { |
---|
1021 | if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) |
---|
1022 | gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); |
---|
1023 | } |
---|
1024 | |
---|
1025 | return TRUE; |
---|
1026 | } |
---|
1027 | else if (event->button == 3) |
---|
1028 | { |
---|
1029 | gtk_grab_remove (widget); |
---|
1030 | |
---|
1031 | return TRUE; |
---|
1032 | } |
---|
1033 | |
---|
1034 | return FALSE; |
---|
1035 | } |
---|
1036 | |
---|
1037 | static gint |
---|
1038 | gtk_entry_motion_notify (GtkWidget *widget, |
---|
1039 | GdkEventMotion *event) |
---|
1040 | { |
---|
1041 | GtkEntry *entry; |
---|
1042 | gint x; |
---|
1043 | |
---|
1044 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
1045 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
1046 | g_return_val_if_fail (event != NULL, FALSE); |
---|
1047 | |
---|
1048 | entry = GTK_ENTRY (widget); |
---|
1049 | |
---|
1050 | if (entry->button == 0) |
---|
1051 | return FALSE; |
---|
1052 | |
---|
1053 | x = event->x; |
---|
1054 | if (event->is_hint || (entry->text_area != event->window)) |
---|
1055 | gdk_window_get_pointer (entry->text_area, &x, NULL, NULL); |
---|
1056 | |
---|
1057 | GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_position (entry, x + entry->scroll_offset); |
---|
1058 | GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos; |
---|
1059 | entry_adjust_scroll (entry); |
---|
1060 | gtk_entry_queue_draw (entry); |
---|
1061 | |
---|
1062 | return TRUE; |
---|
1063 | } |
---|
1064 | |
---|
1065 | static gint |
---|
1066 | gtk_entry_key_press (GtkWidget *widget, |
---|
1067 | GdkEventKey *event) |
---|
1068 | { |
---|
1069 | GtkEntry *entry; |
---|
1070 | GtkEditable *editable; |
---|
1071 | |
---|
1072 | gint return_val; |
---|
1073 | gint key; |
---|
1074 | guint initial_pos; |
---|
1075 | gint extend_selection; |
---|
1076 | gint extend_start; |
---|
1077 | |
---|
1078 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
1079 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
1080 | g_return_val_if_fail (event != NULL, FALSE); |
---|
1081 | |
---|
1082 | entry = GTK_ENTRY (widget); |
---|
1083 | editable = GTK_EDITABLE (widget); |
---|
1084 | return_val = FALSE; |
---|
1085 | |
---|
1086 | if(editable->editable == FALSE) |
---|
1087 | return FALSE; |
---|
1088 | |
---|
1089 | initial_pos = editable->current_pos; |
---|
1090 | |
---|
1091 | extend_selection = event->state & GDK_SHIFT_MASK; |
---|
1092 | extend_start = FALSE; |
---|
1093 | |
---|
1094 | if (extend_selection) |
---|
1095 | { |
---|
1096 | if (editable->selection_start_pos == editable->selection_end_pos) |
---|
1097 | { |
---|
1098 | editable->selection_start_pos = editable->current_pos; |
---|
1099 | editable->selection_end_pos = editable->current_pos; |
---|
1100 | } |
---|
1101 | |
---|
1102 | extend_start = (editable->current_pos == editable->selection_start_pos); |
---|
1103 | } |
---|
1104 | |
---|
1105 | switch (event->keyval) |
---|
1106 | { |
---|
1107 | case GDK_BackSpace: |
---|
1108 | return_val = TRUE; |
---|
1109 | if (event->state & GDK_CONTROL_MASK) |
---|
1110 | gtk_delete_backward_word (entry); |
---|
1111 | else |
---|
1112 | gtk_delete_backward_character (entry); |
---|
1113 | break; |
---|
1114 | case GDK_Clear: |
---|
1115 | return_val = TRUE; |
---|
1116 | gtk_delete_line (entry); |
---|
1117 | break; |
---|
1118 | case GDK_Insert: |
---|
1119 | return_val = TRUE; |
---|
1120 | if (event->state & GDK_SHIFT_MASK) |
---|
1121 | { |
---|
1122 | extend_selection = FALSE; |
---|
1123 | gtk_editable_paste_clipboard (editable); |
---|
1124 | } |
---|
1125 | else if (event->state & GDK_CONTROL_MASK) |
---|
1126 | { |
---|
1127 | gtk_editable_copy_clipboard (editable); |
---|
1128 | } |
---|
1129 | else |
---|
1130 | { |
---|
1131 | /* gtk_toggle_insert(entry) -- IMPLEMENT */ |
---|
1132 | } |
---|
1133 | break; |
---|
1134 | case GDK_Delete: |
---|
1135 | return_val = TRUE; |
---|
1136 | if (event->state & GDK_CONTROL_MASK) |
---|
1137 | gtk_delete_forward_word (entry); |
---|
1138 | else if (event->state & GDK_SHIFT_MASK) |
---|
1139 | { |
---|
1140 | extend_selection = FALSE; |
---|
1141 | gtk_editable_cut_clipboard (editable); |
---|
1142 | } |
---|
1143 | else |
---|
1144 | gtk_delete_forward_character (entry); |
---|
1145 | break; |
---|
1146 | case GDK_Home: |
---|
1147 | return_val = TRUE; |
---|
1148 | gtk_move_beginning_of_line (entry); |
---|
1149 | break; |
---|
1150 | case GDK_End: |
---|
1151 | return_val = TRUE; |
---|
1152 | gtk_move_end_of_line (entry); |
---|
1153 | break; |
---|
1154 | case GDK_Left: |
---|
1155 | return_val = TRUE; |
---|
1156 | if (!extend_selection && |
---|
1157 | editable->selection_start_pos != editable->selection_end_pos) |
---|
1158 | { |
---|
1159 | editable->current_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); |
---|
1160 | initial_pos = (guint)-1; /* Force redraw below */ |
---|
1161 | } |
---|
1162 | else |
---|
1163 | { |
---|
1164 | if (event->state & GDK_CONTROL_MASK) |
---|
1165 | gtk_move_backward_word (entry); |
---|
1166 | else |
---|
1167 | gtk_move_backward_character (entry); |
---|
1168 | } |
---|
1169 | break; |
---|
1170 | case GDK_Right: |
---|
1171 | return_val = TRUE; |
---|
1172 | if (!extend_selection && |
---|
1173 | editable->selection_start_pos != editable->selection_end_pos) |
---|
1174 | { |
---|
1175 | editable->current_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); |
---|
1176 | initial_pos = (guint)-1; /* Force redraw below */ |
---|
1177 | } |
---|
1178 | else |
---|
1179 | { |
---|
1180 | if (event->state & GDK_CONTROL_MASK) |
---|
1181 | gtk_move_forward_word (entry); |
---|
1182 | else |
---|
1183 | gtk_move_forward_character (entry); |
---|
1184 | } |
---|
1185 | break; |
---|
1186 | case GDK_Return: |
---|
1187 | return_val = TRUE; |
---|
1188 | gtk_widget_activate (widget); |
---|
1189 | break; |
---|
1190 | /* The next two keys should not be inserted literally. Any others ??? */ |
---|
1191 | case GDK_Tab: |
---|
1192 | case GDK_Escape: |
---|
1193 | break; |
---|
1194 | default: |
---|
1195 | if ((event->keyval >= 0x20) && (event->keyval <= 0xFF)) |
---|
1196 | { |
---|
1197 | key = event->keyval; |
---|
1198 | |
---|
1199 | if (event->state & GDK_CONTROL_MASK) |
---|
1200 | { |
---|
1201 | if ((key >= 'A') && (key <= 'Z')) |
---|
1202 | key -= 'A' - 'a'; |
---|
1203 | |
---|
1204 | if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a']) |
---|
1205 | { |
---|
1206 | (* control_keys[key - 'a']) (editable, event->time); |
---|
1207 | return_val = TRUE; |
---|
1208 | } |
---|
1209 | break; |
---|
1210 | } |
---|
1211 | else if (event->state & GDK_MOD1_MASK) |
---|
1212 | { |
---|
1213 | if ((key >= 'A') && (key <= 'Z')) |
---|
1214 | key -= 'A' - 'a'; |
---|
1215 | |
---|
1216 | if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a']) |
---|
1217 | { |
---|
1218 | (* alt_keys[key - 'a']) (editable, event->time); |
---|
1219 | return_val = TRUE; |
---|
1220 | } |
---|
1221 | break; |
---|
1222 | } |
---|
1223 | } |
---|
1224 | if (event->length > 0) |
---|
1225 | { |
---|
1226 | gint tmp_pos; |
---|
1227 | |
---|
1228 | extend_selection = FALSE; |
---|
1229 | gtk_editable_delete_selection (editable); |
---|
1230 | |
---|
1231 | tmp_pos = editable->current_pos; |
---|
1232 | gtk_editable_insert_text (editable, event->string, event->length, &tmp_pos); |
---|
1233 | editable->current_pos = tmp_pos; |
---|
1234 | |
---|
1235 | return_val = TRUE; |
---|
1236 | } |
---|
1237 | break; |
---|
1238 | } |
---|
1239 | |
---|
1240 | /* since we emit signals from within the above code, |
---|
1241 | * the widget might already be destroyed or at least |
---|
1242 | * unrealized. |
---|
1243 | */ |
---|
1244 | if (GTK_WIDGET_REALIZED (editable) && |
---|
1245 | return_val && (editable->current_pos != initial_pos)) |
---|
1246 | { |
---|
1247 | if (extend_selection) |
---|
1248 | { |
---|
1249 | if (editable->current_pos < editable->selection_start_pos) |
---|
1250 | editable->selection_start_pos = editable->current_pos; |
---|
1251 | else if (editable->current_pos > editable->selection_end_pos) |
---|
1252 | editable->selection_end_pos = editable->current_pos; |
---|
1253 | else |
---|
1254 | { |
---|
1255 | if (extend_start) |
---|
1256 | editable->selection_start_pos = editable->current_pos; |
---|
1257 | else |
---|
1258 | editable->selection_end_pos = editable->current_pos; |
---|
1259 | } |
---|
1260 | } |
---|
1261 | else |
---|
1262 | { |
---|
1263 | editable->selection_start_pos = 0; |
---|
1264 | editable->selection_end_pos = 0; |
---|
1265 | } |
---|
1266 | |
---|
1267 | gtk_editable_claim_selection (editable, |
---|
1268 | editable->selection_start_pos != editable->selection_end_pos, |
---|
1269 | event->time); |
---|
1270 | |
---|
1271 | entry_adjust_scroll (entry); |
---|
1272 | gtk_entry_queue_draw (entry); |
---|
1273 | } |
---|
1274 | |
---|
1275 | return return_val; |
---|
1276 | } |
---|
1277 | |
---|
1278 | static gint |
---|
1279 | gtk_entry_focus_in (GtkWidget *widget, |
---|
1280 | GdkEventFocus *event) |
---|
1281 | { |
---|
1282 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
1283 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
1284 | g_return_val_if_fail (event != NULL, FALSE); |
---|
1285 | |
---|
1286 | GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); |
---|
1287 | gtk_widget_draw_focus (widget); |
---|
1288 | |
---|
1289 | #ifdef USE_XIM |
---|
1290 | if (GTK_EDITABLE(widget)->ic) |
---|
1291 | gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_ENTRY(widget)->text_area); |
---|
1292 | #endif |
---|
1293 | |
---|
1294 | return FALSE; |
---|
1295 | } |
---|
1296 | |
---|
1297 | static gint |
---|
1298 | gtk_entry_focus_out (GtkWidget *widget, |
---|
1299 | GdkEventFocus *event) |
---|
1300 | { |
---|
1301 | g_return_val_if_fail (widget != NULL, FALSE); |
---|
1302 | g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); |
---|
1303 | g_return_val_if_fail (event != NULL, FALSE); |
---|
1304 | |
---|
1305 | GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); |
---|
1306 | gtk_widget_draw_focus (widget); |
---|
1307 | |
---|
1308 | #ifdef USE_XIM |
---|
1309 | gdk_im_end (); |
---|
1310 | #endif |
---|
1311 | |
---|
1312 | return FALSE; |
---|
1313 | } |
---|
1314 | |
---|
1315 | static void |
---|
1316 | gtk_entry_make_backing_pixmap (GtkEntry *entry, gint width, gint height) |
---|
1317 | { |
---|
1318 | gint pixmap_width, pixmap_height; |
---|
1319 | |
---|
1320 | if (!entry->backing_pixmap) |
---|
1321 | { |
---|
1322 | /* allocate */ |
---|
1323 | entry->backing_pixmap = gdk_pixmap_new (entry->text_area, |
---|
1324 | width, height, |
---|
1325 | -1); |
---|
1326 | } |
---|
1327 | else |
---|
1328 | { |
---|
1329 | /* reallocate if sizes don't match */ |
---|
1330 | gdk_window_get_size (entry->backing_pixmap, |
---|
1331 | &pixmap_width, &pixmap_height); |
---|
1332 | if ((pixmap_width != width) || (pixmap_height != height)) |
---|
1333 | { |
---|
1334 | gdk_pixmap_unref (entry->backing_pixmap); |
---|
1335 | entry->backing_pixmap = gdk_pixmap_new (entry->text_area, |
---|
1336 | width, height, |
---|
1337 | -1); |
---|
1338 | } |
---|
1339 | } |
---|
1340 | } |
---|
1341 | |
---|
1342 | static void |
---|
1343 | gtk_entry_draw_text (GtkEntry *entry) |
---|
1344 | { |
---|
1345 | GtkWidget *widget; |
---|
1346 | GtkEditable *editable; |
---|
1347 | GtkStateType selected_state; |
---|
1348 | gint start_pos; |
---|
1349 | gint end_pos; |
---|
1350 | gint start_xoffset; |
---|
1351 | gint selection_start_pos; |
---|
1352 | gint selection_end_pos; |
---|
1353 | gint selection_start_xoffset; |
---|
1354 | gint selection_end_xoffset; |
---|
1355 | gint width, height; |
---|
1356 | gint y; |
---|
1357 | GdkDrawable *drawable; |
---|
1358 | gint use_backing_pixmap; |
---|
1359 | GdkWChar *stars; |
---|
1360 | GdkWChar *toprint; |
---|
1361 | |
---|
1362 | g_return_if_fail (entry != NULL); |
---|
1363 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
1364 | |
---|
1365 | if (entry->timer) |
---|
1366 | { |
---|
1367 | gtk_timeout_remove (entry->timer); |
---|
1368 | entry->timer = 0; |
---|
1369 | } |
---|
1370 | |
---|
1371 | if (GTK_WIDGET_DRAWABLE (entry)) |
---|
1372 | { |
---|
1373 | widget = GTK_WIDGET (entry); |
---|
1374 | editable = GTK_EDITABLE (entry); |
---|
1375 | |
---|
1376 | if (!entry->text) |
---|
1377 | { |
---|
1378 | gtk_paint_flat_box (widget->style, entry->text_area, |
---|
1379 | GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, |
---|
1380 | NULL, widget, "entry_bg", |
---|
1381 | 0, 0, -1, -1); |
---|
1382 | |
---|
1383 | if (editable->editable) |
---|
1384 | gtk_entry_draw_cursor (entry); |
---|
1385 | return; |
---|
1386 | } |
---|
1387 | |
---|
1388 | gdk_window_get_size (entry->text_area, &width, &height); |
---|
1389 | |
---|
1390 | /* |
---|
1391 | If the widget has focus, draw on a backing pixmap to avoid flickering |
---|
1392 | and copy it to the text_area. |
---|
1393 | Otherwise draw to text_area directly for better speed. |
---|
1394 | */ |
---|
1395 | use_backing_pixmap = GTK_WIDGET_HAS_FOCUS (widget) && (entry->text != NULL); |
---|
1396 | if (use_backing_pixmap) |
---|
1397 | { |
---|
1398 | gtk_entry_make_backing_pixmap (entry, width, height); |
---|
1399 | drawable = entry->backing_pixmap; |
---|
1400 | } |
---|
1401 | else |
---|
1402 | { |
---|
1403 | drawable = entry->text_area; |
---|
1404 | } |
---|
1405 | gtk_paint_flat_box (widget->style, drawable, |
---|
1406 | GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, |
---|
1407 | NULL, widget, "entry_bg", |
---|
1408 | 0, 0, width, height); |
---|
1409 | |
---|
1410 | y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2; |
---|
1411 | y += widget->style->font->ascent; |
---|
1412 | |
---|
1413 | start_pos = gtk_entry_find_position (entry, entry->scroll_offset); |
---|
1414 | start_xoffset = entry->char_offset[start_pos] - entry->scroll_offset; |
---|
1415 | |
---|
1416 | end_pos = gtk_entry_find_position (entry, entry->scroll_offset + width); |
---|
1417 | if (end_pos < entry->text_length) |
---|
1418 | end_pos += 1; |
---|
1419 | |
---|
1420 | selected_state = GTK_STATE_SELECTED; |
---|
1421 | if (!editable->has_selection) |
---|
1422 | selected_state = GTK_STATE_ACTIVE; |
---|
1423 | |
---|
1424 | selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos); |
---|
1425 | selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos); |
---|
1426 | |
---|
1427 | selection_start_pos = CLAMP (selection_start_pos, start_pos, end_pos); |
---|
1428 | selection_end_pos = CLAMP (selection_end_pos, start_pos, end_pos); |
---|
1429 | |
---|
1430 | selection_start_xoffset = |
---|
1431 | entry->char_offset[selection_start_pos] - entry->scroll_offset; |
---|
1432 | selection_end_xoffset = |
---|
1433 | entry->char_offset[selection_end_pos] -entry->scroll_offset; |
---|
1434 | |
---|
1435 | /* if editable->visible, print a bunch of stars. If not, print the standard text. */ |
---|
1436 | if (editable->visible) |
---|
1437 | { |
---|
1438 | toprint = entry->text + start_pos; |
---|
1439 | } |
---|
1440 | else |
---|
1441 | { |
---|
1442 | gint i; |
---|
1443 | GdkWChar invisible_char = gtk_entry_get_invisible_char (entry); |
---|
1444 | |
---|
1445 | stars = g_new (GdkWChar, end_pos - start_pos); |
---|
1446 | for (i = 0; i < end_pos - start_pos; i++) |
---|
1447 | stars[i] = invisible_char; |
---|
1448 | toprint = stars; |
---|
1449 | } |
---|
1450 | |
---|
1451 | if (selection_start_pos > start_pos) |
---|
1452 | gtk_entry_draw_wchars (entry, drawable, widget->style->font, |
---|
1453 | widget->style->fg_gc[GTK_WIDGET_STATE (widget)], |
---|
1454 | INNER_BORDER + start_xoffset, y, |
---|
1455 | toprint, |
---|
1456 | selection_start_pos - start_pos); |
---|
1457 | |
---|
1458 | if ((selection_end_pos >= start_pos) && |
---|
1459 | (selection_start_pos < end_pos) && |
---|
1460 | (selection_start_pos != selection_end_pos)) |
---|
1461 | { |
---|
1462 | gtk_paint_flat_box (widget->style, drawable, |
---|
1463 | selected_state, GTK_SHADOW_NONE, |
---|
1464 | NULL, widget, "text", |
---|
1465 | INNER_BORDER + selection_start_xoffset, |
---|
1466 | INNER_BORDER, |
---|
1467 | selection_end_xoffset - selection_start_xoffset, |
---|
1468 | height - 2*INNER_BORDER); |
---|
1469 | gtk_entry_draw_wchars (entry, drawable, widget->style->font, |
---|
1470 | widget->style->fg_gc[selected_state], |
---|
1471 | INNER_BORDER + selection_start_xoffset, y, |
---|
1472 | toprint + selection_start_pos - start_pos, |
---|
1473 | selection_end_pos - selection_start_pos); |
---|
1474 | } |
---|
1475 | |
---|
1476 | if (selection_end_pos < end_pos) |
---|
1477 | gtk_entry_draw_wchars (entry, drawable, widget->style->font, |
---|
1478 | widget->style->fg_gc[GTK_WIDGET_STATE (widget)], |
---|
1479 | INNER_BORDER + selection_end_xoffset, y, |
---|
1480 | toprint + selection_end_pos - start_pos, |
---|
1481 | end_pos - selection_end_pos); |
---|
1482 | /* free the space allocated for the stars if it's neccessary. */ |
---|
1483 | if (!editable->visible) |
---|
1484 | g_free (toprint); |
---|
1485 | |
---|
1486 | if (editable->editable) |
---|
1487 | gtk_entry_draw_cursor_on_drawable (entry, drawable); |
---|
1488 | |
---|
1489 | if (use_backing_pixmap) |
---|
1490 | gdk_draw_pixmap(entry->text_area, |
---|
1491 | widget->style->fg_gc[GTK_STATE_NORMAL], |
---|
1492 | entry->backing_pixmap, |
---|
1493 | 0, 0, 0, 0, width, height); |
---|
1494 | } |
---|
1495 | } |
---|
1496 | |
---|
1497 | static void |
---|
1498 | gtk_entry_draw_cursor (GtkEntry *entry) |
---|
1499 | { |
---|
1500 | g_return_if_fail (entry != NULL); |
---|
1501 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
1502 | |
---|
1503 | gtk_entry_draw_cursor_on_drawable (entry, entry->text_area); |
---|
1504 | } |
---|
1505 | |
---|
1506 | static void |
---|
1507 | gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable) |
---|
1508 | { |
---|
1509 | GtkWidget *widget; |
---|
1510 | GtkEditable *editable; |
---|
1511 | gint xoffset; |
---|
1512 | gint text_area_height; |
---|
1513 | |
---|
1514 | g_return_if_fail (entry != NULL); |
---|
1515 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
1516 | |
---|
1517 | if (GTK_WIDGET_DRAWABLE (entry)) |
---|
1518 | { |
---|
1519 | widget = GTK_WIDGET (entry); |
---|
1520 | editable = GTK_EDITABLE (entry); |
---|
1521 | |
---|
1522 | xoffset = INNER_BORDER + entry->char_offset[editable->current_pos]; |
---|
1523 | xoffset -= entry->scroll_offset; |
---|
1524 | |
---|
1525 | gdk_window_get_size (entry->text_area, NULL, &text_area_height); |
---|
1526 | |
---|
1527 | if (GTK_WIDGET_HAS_FOCUS (widget) && |
---|
1528 | (editable->selection_start_pos == editable->selection_end_pos)) |
---|
1529 | { |
---|
1530 | gdk_draw_line (drawable, widget->style->fg_gc[GTK_STATE_NORMAL], |
---|
1531 | xoffset, INNER_BORDER, |
---|
1532 | xoffset, text_area_height - INNER_BORDER); |
---|
1533 | } |
---|
1534 | else |
---|
1535 | { |
---|
1536 | gint yoffset = |
---|
1537 | (text_area_height - |
---|
1538 | (widget->style->font->ascent + widget->style->font->descent)) / 2 |
---|
1539 | + widget->style->font->ascent; |
---|
1540 | |
---|
1541 | gtk_paint_flat_box (widget->style, drawable, |
---|
1542 | GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE, |
---|
1543 | NULL, widget, "entry_bg", |
---|
1544 | xoffset, INNER_BORDER, |
---|
1545 | 1, text_area_height - INNER_BORDER); |
---|
1546 | |
---|
1547 | /* Draw the character under the cursor again |
---|
1548 | */ |
---|
1549 | if ((editable->current_pos < entry->text_length) && |
---|
1550 | (editable->selection_start_pos == editable->selection_end_pos)) |
---|
1551 | { |
---|
1552 | GdkWChar c = editable->visible ? |
---|
1553 | *(entry->text + editable->current_pos) : |
---|
1554 | '*'; |
---|
1555 | |
---|
1556 | gtk_entry_draw_wchars (entry, drawable, widget->style->font, |
---|
1557 | widget->style->fg_gc[GTK_WIDGET_STATE (widget)], |
---|
1558 | xoffset, yoffset, &c, 1); |
---|
1559 | } |
---|
1560 | } |
---|
1561 | |
---|
1562 | |
---|
1563 | #ifdef USE_XIM |
---|
1564 | if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && editable->ic && |
---|
1565 | (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION)) |
---|
1566 | { |
---|
1567 | editable->ic_attr->spot_location.x = xoffset; |
---|
1568 | editable->ic_attr->spot_location.y = |
---|
1569 | (text_area_height + (widget->style->font->ascent |
---|
1570 | - widget->style->font->descent) + 1) / 2; |
---|
1571 | |
---|
1572 | gdk_ic_set_attr (editable->ic, |
---|
1573 | editable->ic_attr, GDK_IC_SPOT_LOCATION); |
---|
1574 | } |
---|
1575 | #endif |
---|
1576 | } |
---|
1577 | } |
---|
1578 | |
---|
1579 | static void |
---|
1580 | gtk_entry_queue_draw (GtkEntry *entry) |
---|
1581 | { |
---|
1582 | g_return_if_fail (entry != NULL); |
---|
1583 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
1584 | |
---|
1585 | if (!entry->timer) |
---|
1586 | entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_entry_timer, entry); |
---|
1587 | } |
---|
1588 | |
---|
1589 | static gint |
---|
1590 | gtk_entry_timer (gpointer data) |
---|
1591 | { |
---|
1592 | GtkEntry *entry; |
---|
1593 | |
---|
1594 | GDK_THREADS_ENTER (); |
---|
1595 | |
---|
1596 | entry = GTK_ENTRY (data); |
---|
1597 | entry->timer = 0; |
---|
1598 | gtk_entry_draw_text (entry); |
---|
1599 | |
---|
1600 | GDK_THREADS_LEAVE (); |
---|
1601 | |
---|
1602 | return FALSE; |
---|
1603 | } |
---|
1604 | |
---|
1605 | static gint |
---|
1606 | gtk_entry_find_position (GtkEntry *entry, |
---|
1607 | gint x) |
---|
1608 | { |
---|
1609 | gint start = 0; |
---|
1610 | gint end = entry->text_length; |
---|
1611 | gint half; |
---|
1612 | |
---|
1613 | if (x <= 0) |
---|
1614 | return 0; |
---|
1615 | if (x >= entry->char_offset[end]) |
---|
1616 | return end; |
---|
1617 | |
---|
1618 | /* invariant - char_offset[start] <= x < char_offset[end] */ |
---|
1619 | |
---|
1620 | while (start != end) |
---|
1621 | { |
---|
1622 | half = (start+end)/2; |
---|
1623 | if (half == start) |
---|
1624 | return half; |
---|
1625 | else if (entry->char_offset[half] <= x) |
---|
1626 | start = half; |
---|
1627 | else |
---|
1628 | end = half; |
---|
1629 | } |
---|
1630 | |
---|
1631 | return start; |
---|
1632 | } |
---|
1633 | |
---|
1634 | static gint |
---|
1635 | gtk_entry_position (GtkEntry *entry, |
---|
1636 | gint x) |
---|
1637 | { |
---|
1638 | return gtk_entry_find_position(entry, x); |
---|
1639 | } |
---|
1640 | |
---|
1641 | static void |
---|
1642 | entry_adjust_scroll (GtkEntry *entry) |
---|
1643 | { |
---|
1644 | gint xoffset, max_offset; |
---|
1645 | gint text_area_width; |
---|
1646 | |
---|
1647 | g_return_if_fail (entry != NULL); |
---|
1648 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
1649 | |
---|
1650 | if (!entry->text_area) |
---|
1651 | return; |
---|
1652 | |
---|
1653 | gdk_window_get_size (entry->text_area, &text_area_width, NULL); |
---|
1654 | text_area_width -= 2 * INNER_BORDER; |
---|
1655 | |
---|
1656 | /* Display as much text as we can */ |
---|
1657 | max_offset = MAX(0, entry->char_offset[entry->text_length] - text_area_width); |
---|
1658 | |
---|
1659 | if (entry->scroll_offset > max_offset) |
---|
1660 | entry->scroll_offset = max_offset; |
---|
1661 | |
---|
1662 | /* And make sure cursor is on screen. Note that the cursor is |
---|
1663 | * actually drawn one pixel into the INNER_BORDER space on |
---|
1664 | * the right, when the scroll is at the utmost right. This |
---|
1665 | * looks better to to me than confining the cursor inside the |
---|
1666 | * border entirely, though it means that the cursor gets one |
---|
1667 | * pixel closer to the the edge of the widget on the right than |
---|
1668 | * on the left. This might need changing if one changed |
---|
1669 | * INNER_BORDER from 2 to 1, as one would do on a |
---|
1670 | * small-screen-real-estate display. |
---|
1671 | */ |
---|
1672 | xoffset = entry->char_offset[GTK_EDITABLE(entry)->current_pos]; |
---|
1673 | xoffset -= entry->scroll_offset; |
---|
1674 | |
---|
1675 | if (xoffset < 0) |
---|
1676 | entry->scroll_offset += xoffset; |
---|
1677 | else if (xoffset > text_area_width) |
---|
1678 | entry->scroll_offset += xoffset - text_area_width; |
---|
1679 | |
---|
1680 | gtk_widget_queue_draw (GTK_WIDGET (entry)); |
---|
1681 | } |
---|
1682 | |
---|
1683 | static void |
---|
1684 | gtk_entry_grow_text (GtkEntry *entry) |
---|
1685 | { |
---|
1686 | gint previous_size; |
---|
1687 | gint i; |
---|
1688 | |
---|
1689 | g_return_if_fail (entry != NULL); |
---|
1690 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
1691 | |
---|
1692 | previous_size = entry->text_size; |
---|
1693 | if (!entry->text_size) |
---|
1694 | entry->text_size = 128; |
---|
1695 | else |
---|
1696 | entry->text_size *= 2; |
---|
1697 | entry->text = g_realloc (entry->text, entry->text_size * sizeof(GdkWChar)); |
---|
1698 | entry->char_offset = g_realloc (entry->char_offset, |
---|
1699 | entry->text_size * sizeof(guint)); |
---|
1700 | |
---|
1701 | if (entry->text_length == 0) /* initial allocation */ |
---|
1702 | { |
---|
1703 | entry->char_offset[0] = 0; |
---|
1704 | } |
---|
1705 | |
---|
1706 | for (i = previous_size; i < entry->text_size; i++) |
---|
1707 | entry->text[i] = '\0'; |
---|
1708 | } |
---|
1709 | |
---|
1710 | static void |
---|
1711 | gtk_entry_insert_text (GtkEditable *editable, |
---|
1712 | const gchar *new_text, |
---|
1713 | gint new_text_length, |
---|
1714 | gint *position) |
---|
1715 | { |
---|
1716 | GdkWChar *text; |
---|
1717 | gint start_pos; |
---|
1718 | gint end_pos; |
---|
1719 | gint last_pos; |
---|
1720 | gint max_length; |
---|
1721 | gint i; |
---|
1722 | |
---|
1723 | guchar *new_text_nt; |
---|
1724 | gint insertion_length; |
---|
1725 | GdkWChar *insertion_text; |
---|
1726 | |
---|
1727 | GtkEntry *entry; |
---|
1728 | GtkWidget *widget; |
---|
1729 | |
---|
1730 | g_return_if_fail (editable != NULL); |
---|
1731 | g_return_if_fail (GTK_IS_ENTRY (editable)); |
---|
1732 | |
---|
1733 | entry = GTK_ENTRY (editable); |
---|
1734 | widget = GTK_WIDGET (editable); |
---|
1735 | |
---|
1736 | if ((entry->text_length == 0) && (entry->use_wchar == FALSE)) |
---|
1737 | { |
---|
1738 | if (!GTK_WIDGET_REALIZED (widget)) |
---|
1739 | gtk_widget_ensure_style (widget); |
---|
1740 | if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET)) |
---|
1741 | entry->use_wchar = TRUE; |
---|
1742 | } |
---|
1743 | |
---|
1744 | if (new_text_length < 0) |
---|
1745 | { |
---|
1746 | new_text_nt = (gchar *)new_text; |
---|
1747 | new_text_length = strlen (new_text); |
---|
1748 | if (new_text_length <= 0) return; |
---|
1749 | } |
---|
1750 | else if (new_text_length == 0) |
---|
1751 | { |
---|
1752 | return; |
---|
1753 | } |
---|
1754 | else |
---|
1755 | { |
---|
1756 | /* make a null-terminated copy of new_text */ |
---|
1757 | new_text_nt = g_new (gchar, new_text_length + 1); |
---|
1758 | memcpy (new_text_nt, new_text, new_text_length); |
---|
1759 | new_text_nt[new_text_length] = 0; |
---|
1760 | } |
---|
1761 | |
---|
1762 | /* The algorithms here will work as long as, the text size (a |
---|
1763 | * multiple of 2), fits into a guint16 but we specify a shorter |
---|
1764 | * maximum length so that if the user pastes a very long text, there |
---|
1765 | * is not a long hang from the slow X_LOCALE functions. */ |
---|
1766 | |
---|
1767 | if (entry->text_max_length == 0) |
---|
1768 | max_length = 2047; |
---|
1769 | else |
---|
1770 | max_length = MIN (2047, entry->text_max_length); |
---|
1771 | |
---|
1772 | /* Convert to wide characters */ |
---|
1773 | insertion_text = g_new (GdkWChar, new_text_length); |
---|
1774 | if (entry->use_wchar) |
---|
1775 | insertion_length = gdk_mbstowcs (insertion_text, new_text_nt, |
---|
1776 | new_text_length); |
---|
1777 | else |
---|
1778 | for (insertion_length=0; new_text_nt[insertion_length]; insertion_length++) |
---|
1779 | insertion_text[insertion_length] = new_text_nt[insertion_length]; |
---|
1780 | if (new_text_nt != (guchar *)new_text) |
---|
1781 | g_free (new_text_nt); |
---|
1782 | |
---|
1783 | /* Make sure we do not exceed the maximum size of the entry. */ |
---|
1784 | if (insertion_length + entry->text_length > max_length) |
---|
1785 | insertion_length = max_length - entry->text_length; |
---|
1786 | |
---|
1787 | /* Don't insert anything, if there was nothing to insert. */ |
---|
1788 | if (insertion_length <= 0) |
---|
1789 | { |
---|
1790 | g_free(insertion_text); |
---|
1791 | return; |
---|
1792 | } |
---|
1793 | |
---|
1794 | /* Make sure we are inserting at integral character position */ |
---|
1795 | start_pos = *position; |
---|
1796 | if (start_pos < 0) |
---|
1797 | start_pos = 0; |
---|
1798 | else if (start_pos > entry->text_length) |
---|
1799 | start_pos = entry->text_length; |
---|
1800 | |
---|
1801 | end_pos = start_pos + insertion_length; |
---|
1802 | last_pos = insertion_length + entry->text_length; |
---|
1803 | |
---|
1804 | if (editable->selection_start_pos >= *position) |
---|
1805 | editable->selection_start_pos += insertion_length; |
---|
1806 | if (editable->selection_end_pos >= *position) |
---|
1807 | editable->selection_end_pos += insertion_length; |
---|
1808 | |
---|
1809 | while (last_pos >= entry->text_size) |
---|
1810 | gtk_entry_grow_text (entry); |
---|
1811 | |
---|
1812 | text = entry->text; |
---|
1813 | for (i = last_pos - 1; i >= end_pos; i--) |
---|
1814 | text[i] = text[i- (end_pos - start_pos)]; |
---|
1815 | for (i = start_pos; i < end_pos; i++) |
---|
1816 | text[i] = insertion_text[i - start_pos]; |
---|
1817 | g_free (insertion_text); |
---|
1818 | |
---|
1819 | /* Fix up the the character offsets */ |
---|
1820 | |
---|
1821 | if (GTK_WIDGET_REALIZED (entry)) |
---|
1822 | { |
---|
1823 | gint offset = 0; |
---|
1824 | |
---|
1825 | for (i = last_pos; i >= end_pos; i--) |
---|
1826 | entry->char_offset[i] = entry->char_offset[i - insertion_length]; |
---|
1827 | |
---|
1828 | for (i=start_pos; i<end_pos; i++) |
---|
1829 | { |
---|
1830 | GdkWChar ch; |
---|
1831 | |
---|
1832 | entry->char_offset[i] = entry->char_offset[start_pos] + offset; |
---|
1833 | |
---|
1834 | if (editable->visible) |
---|
1835 | ch = entry->text[i]; |
---|
1836 | else |
---|
1837 | ch = gtk_entry_get_invisible_char (entry); |
---|
1838 | |
---|
1839 | if (entry->use_wchar) |
---|
1840 | offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font, ch); |
---|
1841 | else |
---|
1842 | offset += gdk_char_width (GTK_WIDGET (entry)->style->font, ch); |
---|
1843 | } |
---|
1844 | for (i = end_pos; i <= last_pos; i++) |
---|
1845 | entry->char_offset[i] += offset; |
---|
1846 | } |
---|
1847 | |
---|
1848 | entry->text_length += insertion_length; |
---|
1849 | *position = end_pos; |
---|
1850 | |
---|
1851 | entry->text_mb_dirty = 1; |
---|
1852 | gtk_entry_queue_draw (entry); |
---|
1853 | } |
---|
1854 | |
---|
1855 | /* Recompute the x offsets of all characters in the buffer */ |
---|
1856 | static void |
---|
1857 | gtk_entry_recompute_offsets (GtkEntry *entry) |
---|
1858 | { |
---|
1859 | gint i; |
---|
1860 | gint offset = 0; |
---|
1861 | GtkEditable *editable = GTK_EDITABLE (entry); |
---|
1862 | |
---|
1863 | for (i=0; i<entry->text_length; i++) |
---|
1864 | { |
---|
1865 | GdkWChar ch; |
---|
1866 | |
---|
1867 | entry->char_offset[i] = offset; |
---|
1868 | |
---|
1869 | if (editable->visible) |
---|
1870 | ch = entry->text[i]; |
---|
1871 | else |
---|
1872 | ch = gtk_entry_get_invisible_char (entry); |
---|
1873 | |
---|
1874 | if (entry->use_wchar) |
---|
1875 | offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font, ch); |
---|
1876 | else |
---|
1877 | offset += gdk_char_width (GTK_WIDGET (entry)->style->font, ch); |
---|
1878 | } |
---|
1879 | |
---|
1880 | entry->char_offset[i] = offset; |
---|
1881 | } |
---|
1882 | |
---|
1883 | static void |
---|
1884 | gtk_entry_delete_text (GtkEditable *editable, |
---|
1885 | gint start_pos, |
---|
1886 | gint end_pos) |
---|
1887 | { |
---|
1888 | GdkWChar *text; |
---|
1889 | gint deletion_length; |
---|
1890 | gint i; |
---|
1891 | |
---|
1892 | GtkEntry *entry; |
---|
1893 | |
---|
1894 | g_return_if_fail (editable != NULL); |
---|
1895 | g_return_if_fail (GTK_IS_ENTRY (editable)); |
---|
1896 | |
---|
1897 | entry = GTK_ENTRY (editable); |
---|
1898 | |
---|
1899 | if (end_pos < 0) |
---|
1900 | end_pos = entry->text_length; |
---|
1901 | |
---|
1902 | if (editable->selection_start_pos > start_pos) |
---|
1903 | editable->selection_start_pos -= MIN(end_pos, editable->selection_start_pos) - start_pos; |
---|
1904 | if (editable->selection_end_pos > start_pos) |
---|
1905 | editable->selection_end_pos -= MIN(end_pos, editable->selection_end_pos) - start_pos; |
---|
1906 | |
---|
1907 | if ((start_pos < end_pos) && |
---|
1908 | (start_pos >= 0) && |
---|
1909 | (end_pos <= entry->text_length)) |
---|
1910 | { |
---|
1911 | text = entry->text; |
---|
1912 | deletion_length = end_pos - start_pos; |
---|
1913 | |
---|
1914 | /* Fix up the character offsets */ |
---|
1915 | if (GTK_WIDGET_REALIZED (entry)) |
---|
1916 | { |
---|
1917 | gint deletion_width = |
---|
1918 | entry->char_offset[end_pos] - entry->char_offset[start_pos]; |
---|
1919 | |
---|
1920 | for (i = 0 ; i <= entry->text_length - end_pos; i++) |
---|
1921 | entry->char_offset[start_pos+i] = entry->char_offset[end_pos+i] - deletion_width; |
---|
1922 | } |
---|
1923 | |
---|
1924 | for (i = end_pos; i < entry->text_length; i++) |
---|
1925 | text[i - deletion_length] = text[i]; |
---|
1926 | |
---|
1927 | for (i = entry->text_length - deletion_length; i < entry->text_length; i++) |
---|
1928 | text[i] = '\0'; |
---|
1929 | |
---|
1930 | entry->text_length -= deletion_length; |
---|
1931 | editable->current_pos = start_pos; |
---|
1932 | } |
---|
1933 | |
---|
1934 | entry->text_mb_dirty = 1; |
---|
1935 | gtk_entry_queue_draw (entry); |
---|
1936 | } |
---|
1937 | |
---|
1938 | static void |
---|
1939 | gtk_entry_update_text (GtkEditable *editable, |
---|
1940 | gint start_pos, |
---|
1941 | gint end_pos) |
---|
1942 | { |
---|
1943 | gtk_entry_queue_draw (GTK_ENTRY(editable)); |
---|
1944 | } |
---|
1945 | |
---|
1946 | static gchar * |
---|
1947 | gtk_entry_get_chars (GtkEditable *editable, |
---|
1948 | gint start_pos, |
---|
1949 | gint end_pos) |
---|
1950 | { |
---|
1951 | GtkEntry *entry; |
---|
1952 | |
---|
1953 | g_return_val_if_fail (editable != NULL, NULL); |
---|
1954 | g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL); |
---|
1955 | |
---|
1956 | entry = GTK_ENTRY (editable); |
---|
1957 | |
---|
1958 | if (end_pos < 0) |
---|
1959 | end_pos = entry->text_length; |
---|
1960 | |
---|
1961 | start_pos = MIN(entry->text_length, start_pos); |
---|
1962 | end_pos = MIN(entry->text_length, end_pos); |
---|
1963 | |
---|
1964 | if (start_pos <= end_pos) |
---|
1965 | { |
---|
1966 | guchar *mbstr; |
---|
1967 | if (entry->use_wchar) |
---|
1968 | { |
---|
1969 | GdkWChar ch; |
---|
1970 | if (end_pos >= entry->text_size) |
---|
1971 | gtk_entry_grow_text(entry); |
---|
1972 | ch = entry->text[end_pos]; |
---|
1973 | entry->text[end_pos] = 0; |
---|
1974 | mbstr = gdk_wcstombs (entry->text + start_pos); |
---|
1975 | entry->text[end_pos] = ch; |
---|
1976 | return (gchar *)mbstr; |
---|
1977 | } |
---|
1978 | else |
---|
1979 | { |
---|
1980 | gint i; |
---|
1981 | mbstr = g_new (gchar, end_pos - start_pos + 1); |
---|
1982 | for (i=0; i<end_pos-start_pos; i++) |
---|
1983 | mbstr[i] = entry->text[start_pos + i]; |
---|
1984 | mbstr[i] = 0; |
---|
1985 | return (gchar *)mbstr; |
---|
1986 | } |
---|
1987 | } |
---|
1988 | else |
---|
1989 | return NULL; |
---|
1990 | } |
---|
1991 | |
---|
1992 | static void |
---|
1993 | gtk_entry_move_cursor (GtkEditable *editable, |
---|
1994 | gint x, |
---|
1995 | gint y) |
---|
1996 | { |
---|
1997 | GtkEntry *entry; |
---|
1998 | entry = GTK_ENTRY (editable); |
---|
1999 | |
---|
2000 | /* Horizontal motion */ |
---|
2001 | if ((gint)editable->current_pos < -x) |
---|
2002 | editable->current_pos = 0; |
---|
2003 | else if (editable->current_pos + x > entry->text_length) |
---|
2004 | editable->current_pos = entry->text_length; |
---|
2005 | else |
---|
2006 | editable->current_pos += x; |
---|
2007 | |
---|
2008 | /* Ignore vertical motion */ |
---|
2009 | } |
---|
2010 | |
---|
2011 | static void |
---|
2012 | gtk_move_forward_character (GtkEntry *entry) |
---|
2013 | { |
---|
2014 | gtk_entry_move_cursor (GTK_EDITABLE (entry), 1, 0); |
---|
2015 | } |
---|
2016 | |
---|
2017 | static void |
---|
2018 | gtk_move_backward_character (GtkEntry *entry) |
---|
2019 | { |
---|
2020 | gtk_entry_move_cursor (GTK_EDITABLE (entry), -1, 0); |
---|
2021 | } |
---|
2022 | |
---|
2023 | static void |
---|
2024 | gtk_entry_move_word (GtkEditable *editable, |
---|
2025 | gint n) |
---|
2026 | { |
---|
2027 | while (n > 0) |
---|
2028 | { |
---|
2029 | gtk_move_forward_word (GTK_ENTRY (editable)); |
---|
2030 | n--; |
---|
2031 | } |
---|
2032 | while (n < 0) |
---|
2033 | { |
---|
2034 | gtk_move_backward_word (GTK_ENTRY (editable)); |
---|
2035 | n++; |
---|
2036 | } |
---|
2037 | } |
---|
2038 | |
---|
2039 | static void |
---|
2040 | gtk_move_forward_word (GtkEntry *entry) |
---|
2041 | { |
---|
2042 | GtkEditable *editable; |
---|
2043 | GdkWChar *text; |
---|
2044 | gint i; |
---|
2045 | |
---|
2046 | editable = GTK_EDITABLE (entry); |
---|
2047 | |
---|
2048 | /* Prevent any leak of information */ |
---|
2049 | if (!editable->visible) |
---|
2050 | { |
---|
2051 | editable->current_pos = entry->text_length; |
---|
2052 | return; |
---|
2053 | } |
---|
2054 | |
---|
2055 | if (entry->text && (editable->current_pos < entry->text_length)) |
---|
2056 | { |
---|
2057 | text = entry->text; |
---|
2058 | i = editable->current_pos; |
---|
2059 | |
---|
2060 | if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i]))) |
---|
2061 | for (; i < entry->text_length; i++) |
---|
2062 | { |
---|
2063 | if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i])) |
---|
2064 | break; |
---|
2065 | } |
---|
2066 | |
---|
2067 | for (; i < entry->text_length; i++) |
---|
2068 | { |
---|
2069 | if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i]))) |
---|
2070 | break; |
---|
2071 | } |
---|
2072 | |
---|
2073 | editable->current_pos = i; |
---|
2074 | } |
---|
2075 | } |
---|
2076 | |
---|
2077 | static void |
---|
2078 | gtk_move_backward_word (GtkEntry *entry) |
---|
2079 | { |
---|
2080 | GtkEditable *editable; |
---|
2081 | GdkWChar *text; |
---|
2082 | gint i; |
---|
2083 | |
---|
2084 | editable = GTK_EDITABLE (entry); |
---|
2085 | |
---|
2086 | /* Prevent any leak of information */ |
---|
2087 | if (!editable->visible) |
---|
2088 | { |
---|
2089 | editable->current_pos = 0; |
---|
2090 | return; |
---|
2091 | } |
---|
2092 | |
---|
2093 | if (entry->text && editable->current_pos > 0) |
---|
2094 | { |
---|
2095 | text = entry->text; |
---|
2096 | i = editable->current_pos - 1; |
---|
2097 | if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i]))) |
---|
2098 | for (; i >= 0; i--) |
---|
2099 | { |
---|
2100 | if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i])) |
---|
2101 | break; |
---|
2102 | } |
---|
2103 | for (; i >= 0; i--) |
---|
2104 | { |
---|
2105 | if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i]))) |
---|
2106 | { |
---|
2107 | i++; |
---|
2108 | break; |
---|
2109 | } |
---|
2110 | } |
---|
2111 | |
---|
2112 | if (i < 0) |
---|
2113 | i = 0; |
---|
2114 | |
---|
2115 | editable->current_pos = i; |
---|
2116 | } |
---|
2117 | } |
---|
2118 | |
---|
2119 | static void |
---|
2120 | gtk_entry_move_to_column (GtkEditable *editable, gint column) |
---|
2121 | { |
---|
2122 | GtkEntry *entry; |
---|
2123 | |
---|
2124 | entry = GTK_ENTRY (editable); |
---|
2125 | |
---|
2126 | if (column < 0 || column > entry->text_length) |
---|
2127 | editable->current_pos = entry->text_length; |
---|
2128 | else |
---|
2129 | editable->current_pos = column; |
---|
2130 | } |
---|
2131 | |
---|
2132 | static void |
---|
2133 | gtk_move_beginning_of_line (GtkEntry *entry) |
---|
2134 | { |
---|
2135 | gtk_entry_move_to_column (GTK_EDITABLE (entry), 0); |
---|
2136 | } |
---|
2137 | |
---|
2138 | static void |
---|
2139 | gtk_move_end_of_line (GtkEntry *entry) |
---|
2140 | { |
---|
2141 | gtk_entry_move_to_column (GTK_EDITABLE (entry), -1); |
---|
2142 | } |
---|
2143 | |
---|
2144 | static void |
---|
2145 | gtk_entry_kill_char (GtkEditable *editable, |
---|
2146 | gint direction) |
---|
2147 | { |
---|
2148 | if (editable->selection_start_pos != editable->selection_end_pos) |
---|
2149 | gtk_editable_delete_selection (editable); |
---|
2150 | else |
---|
2151 | { |
---|
2152 | gint old_pos = editable->current_pos; |
---|
2153 | if (direction >= 0) |
---|
2154 | { |
---|
2155 | gtk_entry_move_cursor (editable, 1, 0); |
---|
2156 | gtk_editable_delete_text (editable, old_pos, editable->current_pos); |
---|
2157 | } |
---|
2158 | else |
---|
2159 | { |
---|
2160 | gtk_entry_move_cursor (editable, -1, 0); |
---|
2161 | gtk_editable_delete_text (editable, editable->current_pos, old_pos); |
---|
2162 | } |
---|
2163 | } |
---|
2164 | } |
---|
2165 | |
---|
2166 | static void |
---|
2167 | gtk_delete_forward_character (GtkEntry *entry) |
---|
2168 | { |
---|
2169 | gtk_entry_kill_char (GTK_EDITABLE (entry), 1); |
---|
2170 | } |
---|
2171 | |
---|
2172 | static void |
---|
2173 | gtk_delete_backward_character (GtkEntry *entry) |
---|
2174 | { |
---|
2175 | gtk_entry_kill_char (GTK_EDITABLE (entry), -1); |
---|
2176 | } |
---|
2177 | |
---|
2178 | static void |
---|
2179 | gtk_entry_kill_word (GtkEditable *editable, |
---|
2180 | gint direction) |
---|
2181 | { |
---|
2182 | if (editable->selection_start_pos != editable->selection_end_pos) |
---|
2183 | gtk_editable_delete_selection (editable); |
---|
2184 | else |
---|
2185 | { |
---|
2186 | gint old_pos = editable->current_pos; |
---|
2187 | if (direction >= 0) |
---|
2188 | { |
---|
2189 | gtk_entry_move_word (editable, 1); |
---|
2190 | gtk_editable_delete_text (editable, old_pos, editable->current_pos); |
---|
2191 | } |
---|
2192 | else |
---|
2193 | { |
---|
2194 | gtk_entry_move_word (editable, -1); |
---|
2195 | gtk_editable_delete_text (editable, editable->current_pos, old_pos); |
---|
2196 | } |
---|
2197 | } |
---|
2198 | } |
---|
2199 | |
---|
2200 | static void |
---|
2201 | gtk_delete_forward_word (GtkEntry *entry) |
---|
2202 | { |
---|
2203 | gtk_entry_kill_word (GTK_EDITABLE (entry), 1); |
---|
2204 | } |
---|
2205 | |
---|
2206 | static void |
---|
2207 | gtk_delete_backward_word (GtkEntry *entry) |
---|
2208 | { |
---|
2209 | gtk_entry_kill_word (GTK_EDITABLE (entry), -1); |
---|
2210 | } |
---|
2211 | |
---|
2212 | static void |
---|
2213 | gtk_entry_kill_line (GtkEditable *editable, |
---|
2214 | gint direction) |
---|
2215 | { |
---|
2216 | gint old_pos = editable->current_pos; |
---|
2217 | if (direction >= 0) |
---|
2218 | { |
---|
2219 | gtk_entry_move_to_column (editable, -1); |
---|
2220 | gtk_editable_delete_text (editable, old_pos, editable->current_pos); |
---|
2221 | } |
---|
2222 | else |
---|
2223 | { |
---|
2224 | gtk_entry_move_to_column (editable, 0); |
---|
2225 | gtk_editable_delete_text (editable, editable->current_pos, old_pos); |
---|
2226 | } |
---|
2227 | } |
---|
2228 | |
---|
2229 | static void |
---|
2230 | gtk_delete_line (GtkEntry *entry) |
---|
2231 | { |
---|
2232 | gtk_entry_move_to_column (GTK_EDITABLE (entry), 0); |
---|
2233 | gtk_entry_kill_line (GTK_EDITABLE (entry), 1); |
---|
2234 | } |
---|
2235 | |
---|
2236 | static void |
---|
2237 | gtk_delete_to_line_end (GtkEntry *entry) |
---|
2238 | { |
---|
2239 | gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length); |
---|
2240 | } |
---|
2241 | |
---|
2242 | static void |
---|
2243 | gtk_select_word (GtkEntry *entry, |
---|
2244 | guint32 time) |
---|
2245 | { |
---|
2246 | GtkEditable *editable; |
---|
2247 | gint start_pos; |
---|
2248 | gint end_pos; |
---|
2249 | |
---|
2250 | editable = GTK_EDITABLE (entry); |
---|
2251 | |
---|
2252 | gtk_move_backward_word (entry); |
---|
2253 | start_pos = editable->current_pos; |
---|
2254 | |
---|
2255 | gtk_move_forward_word (entry); |
---|
2256 | end_pos = editable->current_pos; |
---|
2257 | |
---|
2258 | editable->has_selection = TRUE; |
---|
2259 | gtk_entry_set_selection (editable, start_pos, end_pos); |
---|
2260 | gtk_editable_claim_selection (editable, start_pos != end_pos, time); |
---|
2261 | } |
---|
2262 | |
---|
2263 | static void |
---|
2264 | gtk_select_line (GtkEntry *entry, |
---|
2265 | guint32 time) |
---|
2266 | { |
---|
2267 | GtkEditable *editable; |
---|
2268 | |
---|
2269 | editable = GTK_EDITABLE (entry); |
---|
2270 | |
---|
2271 | editable->has_selection = TRUE; |
---|
2272 | gtk_entry_set_selection (editable, 0, entry->text_length); |
---|
2273 | gtk_editable_claim_selection (editable, entry->text_length != 0, time); |
---|
2274 | |
---|
2275 | editable->current_pos = editable->selection_end_pos; |
---|
2276 | } |
---|
2277 | |
---|
2278 | static void |
---|
2279 | gtk_entry_set_selection (GtkEditable *editable, |
---|
2280 | gint start, |
---|
2281 | gint end) |
---|
2282 | { |
---|
2283 | gint length = GTK_ENTRY (editable)->text_length; |
---|
2284 | |
---|
2285 | g_return_if_fail (editable != NULL); |
---|
2286 | g_return_if_fail (GTK_IS_ENTRY (editable)); |
---|
2287 | |
---|
2288 | if (end < 0) |
---|
2289 | end = length; |
---|
2290 | |
---|
2291 | editable->selection_start_pos = CLAMP (start, 0, length); |
---|
2292 | editable->selection_end_pos = MIN (end, length); |
---|
2293 | |
---|
2294 | gtk_entry_queue_draw (GTK_ENTRY (editable)); |
---|
2295 | } |
---|
2296 | |
---|
2297 | void |
---|
2298 | gtk_entry_select_region (GtkEntry *entry, |
---|
2299 | gint start, |
---|
2300 | gint end) |
---|
2301 | { |
---|
2302 | gtk_editable_select_region (GTK_EDITABLE (entry), start, end); |
---|
2303 | } |
---|
2304 | |
---|
2305 | void |
---|
2306 | gtk_entry_set_max_length (GtkEntry *entry, |
---|
2307 | guint16 max) |
---|
2308 | { |
---|
2309 | g_return_if_fail (entry != NULL); |
---|
2310 | g_return_if_fail (GTK_IS_ENTRY (entry)); |
---|
2311 | |
---|
2312 | if (max && entry->text_length > max) |
---|
2313 | gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1); |
---|
2314 | entry->text_max_length = max; |
---|
2315 | } |
---|
2316 | |
---|
2317 | #ifdef USE_XIM |
---|
2318 | static void |
---|
2319 | gtk_entry_update_ic_attr (GtkWidget *widget) |
---|
2320 | { |
---|
2321 | GtkEditable *editable = (GtkEditable *) widget; |
---|
2322 | GdkICAttributesType mask = 0; |
---|
2323 | |
---|
2324 | if (editable->ic == NULL) |
---|
2325 | return; |
---|
2326 | |
---|
2327 | gdk_ic_get_attr (editable->ic, editable->ic_attr, |
---|
2328 | GDK_IC_PREEDIT_FOREGROUND | |
---|
2329 | GDK_IC_PREEDIT_BACKGROUND | |
---|
2330 | GDK_IC_PREEDIT_FONTSET); |
---|
2331 | |
---|
2332 | if (editable->ic_attr->preedit_foreground.pixel != |
---|
2333 | widget->style->fg[GTK_STATE_NORMAL].pixel) |
---|
2334 | { |
---|
2335 | mask |= GDK_IC_PREEDIT_FOREGROUND; |
---|
2336 | editable->ic_attr->preedit_foreground |
---|
2337 | = widget->style->fg[GTK_STATE_NORMAL]; |
---|
2338 | } |
---|
2339 | if (editable->ic_attr->preedit_background.pixel != |
---|
2340 | widget->style->base[GTK_STATE_NORMAL].pixel) |
---|
2341 | { |
---|
2342 | mask |= GDK_IC_PREEDIT_BACKGROUND; |
---|
2343 | editable->ic_attr->preedit_background |
---|
2344 | = widget->style->base[GTK_STATE_NORMAL]; |
---|
2345 | } |
---|
2346 | if ((gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION) && |
---|
2347 | widget->style->font != NULL && |
---|
2348 | widget->style->font->type == GDK_FONT_FONTSET && |
---|
2349 | !gdk_font_equal (editable->ic_attr->preedit_fontset, |
---|
2350 | widget->style->font)) |
---|
2351 | { |
---|
2352 | mask |= GDK_IC_PREEDIT_FONTSET; |
---|
2353 | editable->ic_attr->preedit_fontset = widget->style->font; |
---|
2354 | } |
---|
2355 | |
---|
2356 | if (mask) |
---|
2357 | gdk_ic_set_attr (editable->ic, editable->ic_attr, mask); |
---|
2358 | } |
---|
2359 | #endif /* USE_XIM */ |
---|
2360 | |
---|
2361 | static void |
---|
2362 | gtk_entry_style_set (GtkWidget *widget, |
---|
2363 | GtkStyle *previous_style) |
---|
2364 | { |
---|
2365 | GtkEntry *entry; |
---|
2366 | gint scroll_char; |
---|
2367 | |
---|
2368 | g_return_if_fail (widget != NULL); |
---|
2369 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
2370 | |
---|
2371 | if (previous_style && GTK_WIDGET_REALIZED (widget)) |
---|
2372 | { |
---|
2373 | entry = GTK_ENTRY (widget); |
---|
2374 | |
---|
2375 | scroll_char = gtk_entry_find_position (entry, entry->scroll_offset); |
---|
2376 | gtk_entry_recompute_offsets (GTK_ENTRY (widget)); |
---|
2377 | entry->scroll_offset = entry->char_offset[scroll_char]; |
---|
2378 | entry_adjust_scroll (entry); |
---|
2379 | |
---|
2380 | gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); |
---|
2381 | gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); |
---|
2382 | |
---|
2383 | #ifdef USE_XIM |
---|
2384 | gtk_entry_update_ic_attr (widget); |
---|
2385 | #endif |
---|
2386 | } |
---|
2387 | } |
---|
2388 | |
---|
2389 | static void |
---|
2390 | gtk_entry_state_changed (GtkWidget *widget, |
---|
2391 | GtkStateType previous_state) |
---|
2392 | { |
---|
2393 | g_return_if_fail (widget != NULL); |
---|
2394 | g_return_if_fail (GTK_IS_ENTRY (widget)); |
---|
2395 | |
---|
2396 | if (GTK_WIDGET_REALIZED (widget)) |
---|
2397 | { |
---|
2398 | gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]); |
---|
2399 | gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]); |
---|
2400 | |
---|
2401 | #ifdef USE_XIM |
---|
2402 | gtk_entry_update_ic_attr (widget); |
---|
2403 | #endif |
---|
2404 | } |
---|
2405 | |
---|
2406 | if (GTK_WIDGET_DRAWABLE (widget)) |
---|
2407 | gtk_widget_queue_clear(widget); |
---|
2408 | } |
---|