1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
21 #include "gdk/gdkkeysyms.h"
26 #include "gtkselection.h"
27 #include "gtksignal.h"
29 #include "line-wrap.xbm"
30 #include "line-arrow.xbm"
33 #define INITIAL_BUFFER_SIZE 1024
34 #define INITIAL_LINE_CACHE_SIZE 256
35 #define MIN_GAP_SIZE 256
36 #define LINE_DELIM '\n'
37 #define MIN_TEXT_WIDTH_LINES 20
38 #define MIN_TEXT_HEIGHT_LINES 10
39 #define TEXT_BORDER_ROOM 1
40 #define LINE_WRAP_ROOM 8 /* The bitmaps are 6 wide. */
41 #define DEFAULT_TAB_STOP_WIDTH 4
42 #define SCROLL_PIXELS 5
43 #define KEY_SCROLL_PIXELS 10
44 #define SCROLL_TIME 100
45 #define FREEZE_LENGTH 1024
46 /* Freeze text when inserting or deleting more than this many characters */
48 #define SET_PROPERTY_MARK(m, p, o) do { \
49 (m)->property = (p); \
52 #define MARK_CURRENT_PROPERTY(mark) ((TextProperty*)(mark)->property->data)
53 #define MARK_NEXT_PROPERTY(mark) ((TextProperty*)(mark)->property->next->data)
54 #define MARK_PREV_PROPERTY(mark) ((TextProperty*)((mark)->property->prev ? \
55 (mark)->property->prev->data \
57 #define MARK_PREV_LIST_PTR(mark) ((mark)->property->prev)
58 #define MARK_LIST_PTR(mark) ((mark)->property)
59 #define MARK_NEXT_LIST_PTR(mark) ((mark)->property->next)
60 #define MARK_OFFSET(mark) ((mark)->offset)
61 #define MARK_PROPERTY_LENGTH(mark) (MARK_CURRENT_PROPERTY(mark)->length)
64 #define MARK_CURRENT_FONT(text, mark) \
65 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
66 MARK_CURRENT_PROPERTY(mark)->font->gdk_font : \
67 GTK_WIDGET (text)->style->font)
68 #define MARK_CURRENT_FORE(text, mark) \
69 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FOREGROUND) ? \
70 &MARK_CURRENT_PROPERTY(mark)->fore_color : \
71 &((GtkWidget *)text)->style->text[((GtkWidget *)text)->state])
72 #define MARK_CURRENT_BACK(text, mark) \
73 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_BACKGROUND) ? \
74 &MARK_CURRENT_PROPERTY(mark)->back_color : \
75 &((GtkWidget *)text)->style->base[((GtkWidget *)text)->state])
76 #define MARK_CURRENT_TEXT_FONT(text, mark) \
77 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
78 MARK_CURRENT_PROPERTY(mark)->font : \
81 #define TEXT_LENGTH(t) ((t)->text_end - (t)->gap_size)
82 #define FONT_HEIGHT(f) ((f)->ascent + (f)->descent)
83 #define LINE_HEIGHT(l) ((l).font_ascent + (l).font_descent)
84 #define LINE_CONTAINS(l, i) ((l).start.index <= (i) && (l).end.index >= (i))
85 #define LINE_STARTS_AT(l, i) ((l).start.index == (i))
86 #define LINE_START_PIXEL(l) ((l).tab_cont.pixel_offset)
87 #define LAST_INDEX(t, m) ((m).index == TEXT_LENGTH(t))
88 #define CACHE_DATA(c) (*(LineParams*)(c)->data)
90 typedef struct _TextProperty TextProperty;
91 typedef struct _TabStopMark TabStopMark;
92 typedef struct _PrevTabCont PrevTabCont;
93 typedef struct _FetchLinesData FetchLinesData;
94 typedef struct _LineParams LineParams;
95 typedef struct _SetVerticalScrollData SetVerticalScrollData;
97 typedef gint (*LineIteratorFunction) (GtkText* text, LineParams* lp, void* data);
105 struct _SetVerticalScrollData {
107 gint last_didnt_wrap;
108 gint last_line_start;
109 GtkPropertyMark mark;
114 /* The actual font. */
118 gint16 char_widths[256];
122 PROPERTY_FONT = 1 << 0,
123 PROPERTY_FOREGROUND = 1 << 1,
124 PROPERTY_BACKGROUND = 1 << 2
132 /* Background Color. */
135 /* Foreground Color. */
138 /* Show which properties are set */
139 TextPropertyFlags flags;
141 /* Length of this property. */
147 GList* tab_stops; /* Index into list containing the next tab position. If
148 * NULL, using default widths. */
155 TabStopMark tab_start;
158 struct _FetchLinesData
171 guint displayable_chars;
174 PrevTabCont tab_cont;
175 PrevTabCont tab_cont_next;
177 GtkPropertyMark start;
182 static void gtk_text_class_init (GtkTextClass *klass);
183 static void gtk_text_init (GtkText *text);
184 static void gtk_text_destroy (GtkObject *object);
185 static void gtk_text_finalize (GtkObject *object);
186 static void gtk_text_realize (GtkWidget *widget);
187 static void gtk_text_unrealize (GtkWidget *widget);
188 static void gtk_text_style_set (GtkWidget *widget,
189 GtkStyle *previous_style);
190 static void gtk_text_draw_focus (GtkWidget *widget);
191 static void gtk_text_size_request (GtkWidget *widget,
192 GtkRequisition *requisition);
193 static void gtk_text_size_allocate (GtkWidget *widget,
194 GtkAllocation *allocation);
195 static void gtk_text_adjustment (GtkAdjustment *adjustment,
197 static void gtk_text_disconnect (GtkAdjustment *adjustment,
200 static void gtk_text_insert_text (GtkEditable *editable,
201 const gchar *new_text,
202 gint new_text_length,
204 static void gtk_text_delete_text (GtkEditable *editable,
207 static void gtk_text_update_text (GtkEditable *editable,
210 static gchar *gtk_text_get_chars (GtkEditable *editable,
213 static void gtk_text_set_selection (GtkEditable *editable,
216 static void gtk_text_real_set_editable (GtkEditable *editable,
217 gboolean is_editable);
220 static void gtk_text_draw (GtkWidget *widget,
222 static gint gtk_text_expose (GtkWidget *widget,
223 GdkEventExpose *event);
224 static gint gtk_text_button_press (GtkWidget *widget,
225 GdkEventButton *event);
226 static gint gtk_text_button_release (GtkWidget *widget,
227 GdkEventButton *event);
228 static gint gtk_text_motion_notify (GtkWidget *widget,
229 GdkEventMotion *event);
230 static gint gtk_text_key_press (GtkWidget *widget,
232 static gint gtk_text_focus_in (GtkWidget *widget,
233 GdkEventFocus *event);
234 static gint gtk_text_focus_out (GtkWidget *widget,
235 GdkEventFocus *event);
237 static void move_gap_to_point (GtkText* text);
238 static void make_forward_space (GtkText* text, guint len);
240 /* Property management */
241 static GtkTextFont* get_text_font (GdkFont* gfont);
242 static void text_font_unref (GtkTextFont *text_font);
244 static void insert_text_property (GtkText* text, GdkFont* font,
245 GdkColor *fore, GdkColor* back, guint len);
246 static TextProperty* new_text_property (GtkText *text, GdkFont* font,
247 GdkColor* fore, GdkColor* back, guint length);
248 static void destroy_text_property (TextProperty *prop);
249 static void init_properties (GtkText *text);
250 static void realize_property (GtkText *text, TextProperty *prop);
251 static void realize_properties (GtkText *text);
252 static void unrealize_property (GtkText *text, TextProperty *prop);
253 static void unrealize_properties (GtkText *text);
255 static void delete_text_property (GtkText* text, guint len);
257 static guint pixel_height_of (GtkText* text, GList* cache_line);
259 /* Property Movement and Size Computations */
260 static void advance_mark (GtkPropertyMark* mark);
261 static void decrement_mark (GtkPropertyMark* mark);
262 static void advance_mark_n (GtkPropertyMark* mark, gint n);
263 static void decrement_mark_n (GtkPropertyMark* mark, gint n);
264 static void move_mark_n (GtkPropertyMark* mark, gint n);
265 static GtkPropertyMark find_mark (GtkText* text, guint mark_position);
266 static GtkPropertyMark find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near);
267 static void find_line_containing_point (GtkText* text, guint point,
271 static void compute_lines_pixels (GtkText* text, guint char_count,
272 guint *lines, guint *pixels);
274 static gint total_line_height (GtkText* text,
277 static LineParams find_line_params (GtkText* text,
278 const GtkPropertyMark *mark,
279 const PrevTabCont *tab_cont,
280 PrevTabCont *next_cont);
281 static void recompute_geometry (GtkText* text);
282 static void insert_expose (GtkText* text, guint old_pixels, gint nchars, guint new_line_count);
283 static void delete_expose (GtkText* text,
287 static void clear_area (GtkText *text, GdkRectangle *area);
288 static void draw_line (GtkText* text,
291 static void draw_line_wrap (GtkText* text,
293 static void draw_cursor (GtkText* text, gint absolute);
294 static void undraw_cursor (GtkText* text, gint absolute);
295 static gint drawn_cursor_min (GtkText* text);
296 static gint drawn_cursor_max (GtkText* text);
297 static void expose_text (GtkText* text, GdkRectangle *area, gboolean cursor);
299 /* Search and Placement. */
300 static void find_cursor (GtkText* text,
302 static void find_cursor_at_line (GtkText* text,
303 const LineParams* start_line,
305 static void find_mouse_cursor (GtkText* text, gint x, gint y);
308 static void adjust_adj (GtkText* text, GtkAdjustment* adj);
309 static void scroll_up (GtkText* text, gint diff);
310 static void scroll_down (GtkText* text, gint diff);
311 static void scroll_int (GtkText* text, gint diff);
313 static void process_exposes (GtkText *text);
315 /* Cache Management. */
316 static void free_cache (GtkText* text);
317 static GList* remove_cache_line (GtkText* text, GList* list);
320 static void move_cursor_buffer_ver (GtkText *text, int dir);
321 static void move_cursor_page_ver (GtkText *text, int dir);
322 static void move_cursor_ver (GtkText *text, int count);
323 static void move_cursor_hor (GtkText *text, int count);
325 /* Binding actions */
326 static void gtk_text_move_cursor (GtkEditable *editable,
329 static void gtk_text_move_word (GtkEditable *editable,
331 static void gtk_text_move_page (GtkEditable *editable,
334 static void gtk_text_move_to_row (GtkEditable *editable,
336 static void gtk_text_move_to_column (GtkEditable *editable,
338 static void gtk_text_kill_char (GtkEditable *editable,
340 static void gtk_text_kill_word (GtkEditable *editable,
342 static void gtk_text_kill_line (GtkEditable *editable,
346 static void gtk_text_move_forward_character (GtkText *text);
347 static void gtk_text_move_backward_character (GtkText *text);
348 static void gtk_text_move_forward_word (GtkText *text);
349 static void gtk_text_move_backward_word (GtkText *text);
350 static void gtk_text_move_beginning_of_line (GtkText *text);
351 static void gtk_text_move_end_of_line (GtkText *text);
352 static void gtk_text_move_next_line (GtkText *text);
353 static void gtk_text_move_previous_line (GtkText *text);
355 static void gtk_text_delete_forward_character (GtkText *text);
356 static void gtk_text_delete_backward_character (GtkText *text);
357 static void gtk_text_delete_forward_word (GtkText *text);
358 static void gtk_text_delete_backward_word (GtkText *text);
359 static void gtk_text_delete_line (GtkText *text);
360 static void gtk_text_delete_to_line_end (GtkText *text);
361 static void gtk_text_select_word (GtkText *text,
363 static void gtk_text_select_line (GtkText *text,
366 static void gtk_text_set_position (GtkEditable *editable,
369 /* #define DEBUG_GTK_TEXT */
371 #if defined(DEBUG_GTK_TEXT) && defined(__GNUC__)
372 /* Debugging utilities. */
373 static void gtk_text_assert_mark (GtkText *text,
374 GtkPropertyMark *mark,
375 GtkPropertyMark *before,
376 GtkPropertyMark *after,
381 static void gtk_text_assert (GtkText *text,
384 static void gtk_text_show_cache_line (GtkText *text, GList *cache,
385 const char* what, const char* func, gint line);
386 static void gtk_text_show_cache (GtkText *text, const char* func, gint line);
387 static void gtk_text_show_adj (GtkText *text,
392 static void gtk_text_show_props (GtkText* test,
396 #define TDEBUG(args) g_message args
397 #define TEXT_ASSERT(text) gtk_text_assert (text,__PRETTY_FUNCTION__,__LINE__)
398 #define TEXT_ASSERT_MARK(text,mark,msg) gtk_text_assert_mark (text,mark, \
399 __PRETTY_FUNCTION__,msg,__LINE__)
400 #define TEXT_SHOW(text) gtk_text_show_cache (text, __PRETTY_FUNCTION__,__LINE__)
401 #define TEXT_SHOW_LINE(text,line,msg) gtk_text_show_cache_line (text,line,msg,\
402 __PRETTY_FUNCTION__,__LINE__)
403 #define TEXT_SHOW_ADJ(text,adj,msg) gtk_text_show_adj (text,adj,msg, \
404 __PRETTY_FUNCTION__,__LINE__)
407 #define TEXT_ASSERT(text)
408 #define TEXT_ASSERT_MARK(text,mark,msg)
409 #define TEXT_SHOW(text)
410 #define TEXT_SHOW_LINE(text,line,msg)
411 #define TEXT_SHOW_ADJ(text,adj,msg)
414 /* Memory Management. */
415 static GMemChunk *params_mem_chunk = NULL;
416 static GMemChunk *text_property_chunk = NULL;
418 static GtkWidgetClass *parent_class = NULL;
421 static GtkTextFunction control_keys[26] =
423 (GtkTextFunction)gtk_text_move_beginning_of_line, /* a */
424 (GtkTextFunction)gtk_text_move_backward_character, /* b */
425 (GtkTextFunction)gtk_editable_copy_clipboard, /* c */
426 (GtkTextFunction)gtk_text_delete_forward_character, /* d */
427 (GtkTextFunction)gtk_text_move_end_of_line, /* e */
428 (GtkTextFunction)gtk_text_move_forward_character, /* f */
430 (GtkTextFunction)gtk_text_delete_backward_character, /* h */
433 (GtkTextFunction)gtk_text_delete_to_line_end, /* k */
436 (GtkTextFunction)gtk_text_move_next_line, /* n */
438 (GtkTextFunction)gtk_text_move_previous_line, /* p */
443 (GtkTextFunction)gtk_text_delete_line, /* u */
444 (GtkTextFunction)gtk_editable_paste_clipboard, /* v */
445 (GtkTextFunction)gtk_text_delete_backward_word, /* w */
446 (GtkTextFunction)gtk_editable_cut_clipboard, /* x */
451 static GtkTextFunction alt_keys[26] =
454 (GtkTextFunction)gtk_text_move_backward_word, /* b */
456 (GtkTextFunction)gtk_text_delete_forward_word, /* d */
458 (GtkTextFunction)gtk_text_move_forward_word, /* f */
482 /**********************************************************************/
484 /**********************************************************************/
487 gtk_text_get_type (void)
489 static GtkType text_type = 0;
493 GtkTypeInfo text_info =
497 sizeof (GtkTextClass),
498 (GtkClassInitFunc) gtk_text_class_init,
499 (GtkObjectInitFunc) gtk_text_init,
500 /* reserved_1 */ NULL,
501 /* reserved_2 */ NULL,
502 (GtkClassInitFunc) NULL,
505 text_type = gtk_type_unique (GTK_TYPE_EDITABLE, &text_info);
512 gtk_text_class_init (GtkTextClass *class)
514 GtkObjectClass *object_class;
515 GtkWidgetClass *widget_class;
516 GtkEditableClass *editable_class;
518 object_class = (GtkObjectClass*) class;
519 widget_class = (GtkWidgetClass*) class;
520 editable_class = (GtkEditableClass*) class;
522 parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
524 object_class->destroy = gtk_text_destroy;
525 object_class->finalize = gtk_text_finalize;
527 widget_class->realize = gtk_text_realize;
528 widget_class->unrealize = gtk_text_unrealize;
529 widget_class->style_set = gtk_text_style_set;
530 widget_class->draw_focus = gtk_text_draw_focus;
531 widget_class->size_request = gtk_text_size_request;
532 widget_class->size_allocate = gtk_text_size_allocate;
533 widget_class->draw = gtk_text_draw;
534 widget_class->expose_event = gtk_text_expose;
535 widget_class->button_press_event = gtk_text_button_press;
536 widget_class->button_release_event = gtk_text_button_release;
537 widget_class->motion_notify_event = gtk_text_motion_notify;
538 widget_class->key_press_event = gtk_text_key_press;
539 widget_class->focus_in_event = gtk_text_focus_in;
540 widget_class->focus_out_event = gtk_text_focus_out;
542 editable_class->set_editable = gtk_text_real_set_editable;
543 editable_class->insert_text = gtk_text_insert_text;
544 editable_class->delete_text = gtk_text_delete_text;
546 editable_class->move_cursor = gtk_text_move_cursor;
547 editable_class->move_word = gtk_text_move_word;
548 editable_class->move_page = gtk_text_move_page;
549 editable_class->move_to_row = gtk_text_move_to_row;
550 editable_class->move_to_column = gtk_text_move_to_column;
552 editable_class->kill_char = gtk_text_kill_char;
553 editable_class->kill_word = gtk_text_kill_word;
554 editable_class->kill_line = gtk_text_kill_line;
556 editable_class->update_text = gtk_text_update_text;
557 editable_class->get_chars = gtk_text_get_chars;
558 editable_class->set_selection = gtk_text_set_selection;
559 editable_class->set_position = gtk_text_set_position;
563 gtk_text_init (GtkText *text)
565 GTK_WIDGET_SET_FLAGS (text, GTK_CAN_FOCUS);
567 text->text = g_new (guchar, INITIAL_BUFFER_SIZE);
568 text->text_len = INITIAL_BUFFER_SIZE;
570 if (!params_mem_chunk)
571 params_mem_chunk = g_mem_chunk_new ("LineParams",
573 256 * sizeof (LineParams),
576 text->default_tab_width = 4;
577 text->tab_stops = NULL;
579 text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);
580 text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);
582 text->line_start_cache = NULL;
583 text->first_cut_pixels = 0;
585 text->line_wrap = TRUE;
586 text->word_wrap = FALSE;
591 text->current_font = NULL;
593 init_properties (text);
595 GTK_EDITABLE(text)->editable = FALSE;
599 gtk_text_new (GtkAdjustment *hadj,
604 text = gtk_type_new (GTK_TYPE_TEXT);
606 gtk_text_set_adjustments (text, hadj, vadj);
607 gtk_editable_set_position (GTK_EDITABLE (text), 0);
609 return GTK_WIDGET (text);
613 gtk_text_set_word_wrap (GtkText *text,
616 g_return_if_fail (text != NULL);
617 g_return_if_fail (GTK_IS_TEXT (text));
619 text->word_wrap = (word_wrap != FALSE);
621 if (GTK_WIDGET_REALIZED (text))
623 recompute_geometry (text);
624 gtk_widget_queue_draw (GTK_WIDGET (text));
629 gtk_text_set_line_wrap (GtkText *text,
632 g_return_if_fail (text != NULL);
633 g_return_if_fail (GTK_IS_TEXT (text));
635 text->line_wrap = (line_wrap != FALSE);
637 if (GTK_WIDGET_REALIZED (text))
639 recompute_geometry (text);
640 gtk_widget_queue_draw (GTK_WIDGET (text));
645 gtk_text_set_editable (GtkText *text,
646 gboolean is_editable)
648 g_return_if_fail (text != NULL);
649 g_return_if_fail (GTK_IS_TEXT (text));
651 gtk_editable_set_editable (GTK_EDITABLE (text), is_editable);
655 gtk_text_real_set_editable (GtkEditable *editable,
656 gboolean is_editable)
660 g_return_if_fail (editable != NULL);
661 g_return_if_fail (GTK_IS_TEXT (editable));
663 text = GTK_TEXT (editable);
665 editable->editable = (is_editable != FALSE);
668 draw_cursor (text, TRUE);
670 undraw_cursor (text, TRUE);
674 gtk_text_set_adjustments (GtkText *text,
678 g_return_if_fail (text != NULL);
679 g_return_if_fail (GTK_IS_TEXT (text));
681 if (text->hadj && (text->hadj != hadj))
683 gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text);
684 gtk_object_unref (GTK_OBJECT (text->hadj));
687 if (text->vadj && (text->vadj != vadj))
689 gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text);
690 gtk_object_unref (GTK_OBJECT (text->vadj));
694 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
697 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
699 if (text->hadj != hadj)
702 gtk_object_ref (GTK_OBJECT (text->hadj));
703 gtk_object_sink (GTK_OBJECT (text->hadj));
705 gtk_signal_connect (GTK_OBJECT (text->hadj), "changed",
706 (GtkSignalFunc) gtk_text_adjustment,
708 gtk_signal_connect (GTK_OBJECT (text->hadj), "value_changed",
709 (GtkSignalFunc) gtk_text_adjustment,
711 gtk_signal_connect (GTK_OBJECT (text->hadj), "disconnect",
712 (GtkSignalFunc) gtk_text_disconnect,
716 if (text->vadj != vadj)
719 gtk_object_ref (GTK_OBJECT (text->vadj));
720 gtk_object_sink (GTK_OBJECT (text->vadj));
722 gtk_signal_connect (GTK_OBJECT (text->vadj), "changed",
723 (GtkSignalFunc) gtk_text_adjustment,
725 gtk_signal_connect (GTK_OBJECT (text->vadj), "value_changed",
726 (GtkSignalFunc) gtk_text_adjustment,
728 gtk_signal_connect (GTK_OBJECT (text->vadj), "disconnect",
729 (GtkSignalFunc) gtk_text_disconnect,
735 gtk_text_set_point (GtkText *text,
738 g_return_if_fail (text != NULL);
739 g_return_if_fail (GTK_IS_TEXT (text));
740 g_return_if_fail (index <= TEXT_LENGTH (text));
742 text->point = find_mark (text, index);
746 gtk_text_get_point (GtkText *text)
748 g_return_val_if_fail (text != NULL, 0);
749 g_return_val_if_fail (GTK_IS_TEXT (text), 0);
751 return text->point.index;
755 gtk_text_get_length (GtkText *text)
757 g_return_val_if_fail (text != NULL, 0);
758 g_return_val_if_fail (GTK_IS_TEXT (text), 0);
760 return TEXT_LENGTH (text);
764 gtk_text_freeze (GtkText *text)
766 g_return_if_fail (text != NULL);
767 g_return_if_fail (GTK_IS_TEXT (text));
773 gtk_text_thaw (GtkText *text)
775 g_return_if_fail (text != NULL);
776 g_return_if_fail (GTK_IS_TEXT (text));
778 text->freeze = FALSE;
780 if (GTK_WIDGET_REALIZED (text))
782 recompute_geometry (text);
783 gtk_widget_queue_draw (GTK_WIDGET (text));
788 gtk_text_insert (GtkText *text,
795 GtkEditable *editable = GTK_EDITABLE (text);
796 gboolean frozen = FALSE;
798 gint new_line_count = 1;
799 guint old_height = 0;
803 g_return_if_fail (text != NULL);
804 g_return_if_fail (GTK_IS_TEXT (text));
807 length = strlen (chars);
814 if (!text->freeze && (length > FREEZE_LENGTH))
816 gtk_text_freeze (text);
820 if (!text->freeze && (text->line_start_cache != NULL))
822 find_line_containing_point (text, text->point.index, TRUE);
823 old_height = total_line_height (text, text->current_line, 1);
824 for (i=0; i<length; i++)
825 if (chars[i] == '\n')
829 if (text->point.index < text->first_line_start_index)
830 text->first_line_start_index += length;
832 if (text->point.index < editable->selection_start_pos)
833 editable->selection_start_pos += length;
834 if (text->point.index < editable->selection_end_pos)
835 editable->selection_end_pos += length;
836 /* We'll reset the cursor later anyways if we aren't frozen */
837 if (text->point.index < text->cursor_mark.index)
838 text->cursor_mark.index += length;
840 move_gap_to_point (text);
842 make_forward_space (text, length);
843 memcpy (text->text + text->gap_position, chars, length);
845 insert_text_property (text, font, fore, back, length);
847 text->gap_size -= length;
848 text->gap_position += length;
850 advance_mark_n (&text->point, length);
852 if (!text->freeze && (text->line_start_cache != NULL))
853 insert_expose (text, old_height, length, new_line_count);
856 gtk_text_thaw (text);
860 gtk_text_backward_delete (GtkText *text,
863 g_return_val_if_fail (text != NULL, 0);
864 g_return_val_if_fail (GTK_IS_TEXT (text), 0);
866 if (nchars > text->point.index || nchars <= 0)
869 gtk_text_set_point (text, text->point.index - nchars);
871 return gtk_text_forward_delete (text, nchars);
875 gtk_text_forward_delete (GtkText *text,
878 guint old_lines, old_height;
879 GtkEditable *editable = GTK_EDITABLE (text);
880 gboolean frozen = FALSE;
882 g_return_val_if_fail (text != NULL, 0);
883 g_return_val_if_fail (GTK_IS_TEXT (text), 0);
885 if (text->point.index + nchars > TEXT_LENGTH (text) || nchars <= 0)
888 if (!text->freeze && (nchars > FREEZE_LENGTH))
890 gtk_text_freeze (text);
894 if (!text->freeze && (text->line_start_cache != NULL))
896 /* We need to undraw the cursor here, since we may later
897 * delete the cursor's property
899 undraw_cursor (text, FALSE);
900 find_line_containing_point (text, text->point.index, TRUE);
901 compute_lines_pixels (text, nchars, &old_lines, &old_height);
904 /* FIXME, or resizing after deleting will be odd */
905 if (text->point.index < text->first_line_start_index)
907 if (text->point.index + nchars >= text->first_line_start_index)
909 text->first_line_start_index = text->point.index;
910 while ((text->first_line_start_index > 0) &&
911 (GTK_TEXT_INDEX (text, text->first_line_start_index - 1) != LINE_DELIM))
912 text->first_line_start_index -= 1;
916 text->first_line_start_index -= nchars;
919 if (text->point.index < editable->selection_start_pos)
920 editable->selection_start_pos -=
921 MIN(nchars, editable->selection_start_pos - text->point.index);
922 if (text->point.index < editable->selection_end_pos)
923 editable->selection_end_pos -=
924 MIN(nchars, editable->selection_end_pos - text->point.index);
925 /* We'll reset the cursor later anyways if we aren't frozen */
926 if (text->point.index < text->cursor_mark.index)
927 move_mark_n (&text->cursor_mark,
928 -MIN(nchars, text->cursor_mark.index - text->point.index));
930 move_gap_to_point (text);
932 text->gap_size += nchars;
934 delete_text_property (text, nchars);
936 if (!text->freeze && (text->line_start_cache != NULL))
938 delete_expose (text, nchars, old_lines, old_height);
939 draw_cursor (text, FALSE);
943 gtk_text_thaw (text);
949 gtk_text_set_position (GtkEditable *editable,
952 GtkText *text = (GtkText *) editable;
954 undraw_cursor (text, FALSE);
955 text->cursor_mark = find_mark (text, position);
956 find_cursor (text, TRUE);
957 draw_cursor (text, FALSE);
958 gtk_editable_select_region (editable, 0, 0);
962 gtk_text_get_chars (GtkEditable *editable,
972 g_return_val_if_fail (editable != NULL, NULL);
973 g_return_val_if_fail (GTK_IS_TEXT (editable), NULL);
974 text = GTK_TEXT (editable);
977 end_pos = TEXT_LENGTH (text);
979 if ((start_pos < 0) ||
980 (end_pos > TEXT_LENGTH (text)) ||
981 (end_pos < start_pos))
984 nchars = end_pos - start_pos;
986 retval = g_new (gchar, nchars+1);
989 if (start_pos < text->gap_position)
991 n = MIN (text->gap_position - start_pos, nchars);
992 memcpy (p, &text->text[start_pos], n);
998 if (start_pos+nchars >= text->gap_position)
1001 text->text + MAX (text->gap_position + text->gap_size,
1002 start_pos + text->gap_size),
1014 gtk_text_destroy (GtkObject *object)
1018 g_return_if_fail (object != NULL);
1019 g_return_if_fail (GTK_IS_TEXT (object));
1021 text = (GtkText *)object;
1024 gtk_object_unref (GTK_OBJECT (text->hadj));
1029 gtk_object_unref (GTK_OBJECT (text->vadj));
1034 gtk_timeout_remove (text->timer);
1038 GTK_OBJECT_CLASS(parent_class)->destroy (object);
1042 gtk_text_finalize (GtkObject *object)
1047 g_return_if_fail (object != NULL);
1048 g_return_if_fail (GTK_IS_TEXT (object));
1050 text = (GtkText *)object;
1052 /* Clean up the internal structures */
1053 g_free (text->text);
1056 tmp_list = text->text_properties;
1059 destroy_text_property (tmp_list->data);
1060 tmp_list = tmp_list->next;
1063 text_font_unref (text->current_font);
1065 g_list_free (text->text_properties);
1067 if (text->scratch_buffer)
1068 g_free (text->scratch_buffer);
1070 g_list_free (text->tab_stops);
1072 GTK_OBJECT_CLASS(parent_class)->finalize (object);
1076 gtk_text_realize (GtkWidget *widget)
1079 GtkEditable *editable;
1080 GdkWindowAttr attributes;
1081 gint attributes_mask;
1083 g_return_if_fail (widget != NULL);
1084 g_return_if_fail (GTK_IS_TEXT (widget));
1086 text = GTK_TEXT (widget);
1087 editable = GTK_EDITABLE (widget);
1088 GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED);
1090 attributes.window_type = GDK_WINDOW_CHILD;
1091 attributes.x = widget->allocation.x;
1092 attributes.y = widget->allocation.y;
1093 attributes.width = widget->allocation.width;
1094 attributes.height = widget->allocation.height;
1095 attributes.wclass = GDK_INPUT_OUTPUT;
1096 attributes.visual = gtk_widget_get_visual (widget);
1097 attributes.colormap = gtk_widget_get_colormap (widget);
1098 attributes.event_mask = gtk_widget_get_events (widget);
1099 attributes.event_mask |= (GDK_EXPOSURE_MASK |
1100 GDK_BUTTON_PRESS_MASK |
1101 GDK_BUTTON_RELEASE_MASK |
1102 GDK_BUTTON_MOTION_MASK |
1103 GDK_ENTER_NOTIFY_MASK |
1104 GDK_LEAVE_NOTIFY_MASK |
1105 GDK_KEY_PRESS_MASK);
1106 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1108 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
1109 gdk_window_set_user_data (widget->window, text);
1111 attributes.x = (widget->style->klass->xthickness + TEXT_BORDER_ROOM);
1112 attributes.y = (widget->style->klass->ythickness + TEXT_BORDER_ROOM);
1113 attributes.width = MAX (1, (gint)widget->allocation.width - (gint)attributes.x * 2);
1114 attributes.height = MAX (1, (gint)widget->allocation.height - (gint)attributes.y * 2);
1116 text->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
1117 gdk_window_set_user_data (text->text_area, text);
1119 widget->style = gtk_style_attach (widget->style, widget->window);
1121 /* Can't call gtk_style_set_background here because it's handled specially */
1122 gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]);
1123 gdk_window_set_background (text->text_area, &widget->style->base[GTK_STATE_NORMAL]);
1125 text->line_wrap_bitmap = gdk_bitmap_create_from_data (text->text_area,
1126 (gchar*) line_wrap_bits,
1130 text->line_arrow_bitmap = gdk_bitmap_create_from_data (text->text_area,
1131 (gchar*) line_arrow_bits,
1135 text->gc = gdk_gc_new (text->text_area);
1136 gdk_gc_set_exposures (text->gc, TRUE);
1137 gdk_gc_set_foreground (text->gc, &widget->style->text[GTK_STATE_NORMAL]);
1140 if (gdk_im_ready ())
1147 GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE |
1148 GDK_IM_PREEDIT_NOTHING |
1149 GDK_IM_PREEDIT_POSITION |
1150 GDK_IM_STATUS_NONE |
1151 GDK_IM_STATUS_NOTHING;
1153 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1154 supported_style &= ~GDK_IM_PREEDIT_POSITION;
1156 style = gdk_im_decide_style (supported_style);
1157 switch (style & GDK_IM_PREEDIT_MASK)
1159 case GDK_IM_PREEDIT_POSITION:
1160 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1162 g_warning ("over-the-spot style requires fontset");
1165 gdk_window_get_size (text->text_area, &width, &height);
1169 rect.height = height;
1173 editable->ic = gdk_ic_new (text->text_area, text->text_area,
1175 "spotLocation", &spot,
1177 "fontSet", GDK_FONT_XFONT (widget->style->font),
1181 editable->ic = gdk_ic_new (text->text_area, text->text_area,
1185 if (editable->ic == NULL)
1186 g_warning ("Can't create input context.");
1189 GdkColormap *colormap;
1191 mask = gdk_window_get_events (text->text_area);
1192 mask |= gdk_ic_get_events (editable->ic);
1193 gdk_window_set_events (text->text_area, mask);
1195 if ((colormap = gtk_widget_get_colormap (widget)) !=
1196 gtk_widget_get_default_colormap ())
1198 gdk_ic_set_attr (editable->ic, "preeditAttributes",
1199 "colorMap", GDK_COLORMAP_XCOLORMAP (colormap),
1206 realize_properties (text);
1207 gdk_window_show (text->text_area);
1208 init_properties (text);
1210 if (editable->selection_start_pos != editable->selection_end_pos)
1211 gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
1213 recompute_geometry (text);
1217 gtk_text_style_set (GtkWidget *widget,
1218 GtkStyle *previous_style)
1222 g_return_if_fail (widget != NULL);
1223 g_return_if_fail (GTK_IS_TEXT (widget));
1225 text = GTK_TEXT (widget);
1226 if (GTK_WIDGET_REALIZED (widget))
1228 gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]);
1229 gdk_window_set_background (text->text_area, &widget->style->base[GTK_STATE_NORMAL]);
1231 recompute_geometry (text);
1234 if (text->current_font)
1235 text_font_unref (text->current_font);
1236 text->current_font = get_text_font (widget->style->font);
1238 if (GTK_WIDGET_DRAWABLE (widget))
1239 gdk_window_clear (widget->window);
1243 gtk_text_unrealize (GtkWidget *widget)
1247 g_return_if_fail (widget != NULL);
1248 g_return_if_fail (GTK_IS_TEXT (widget));
1250 text = GTK_TEXT (widget);
1252 gdk_window_set_user_data (text->text_area, NULL);
1253 gdk_window_destroy (text->text_area);
1254 text->text_area = NULL;
1256 gdk_gc_destroy (text->gc);
1259 gdk_pixmap_unref (text->line_wrap_bitmap);
1260 gdk_pixmap_unref (text->line_arrow_bitmap);
1262 unrealize_properties (text);
1264 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1265 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1269 clear_focus_area (GtkText *text, gint area_x, gint area_y, gint area_width, gint area_height)
1271 GtkWidget *widget = GTK_WIDGET (text);
1273 gint ythick = TEXT_BORDER_ROOM + widget->style->klass->ythickness;
1274 gint xthick = TEXT_BORDER_ROOM + widget->style->klass->xthickness;
1280 gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height);
1282 yorig = - text->first_onscreen_ver_pixel + ythick;
1283 xorig = - text->first_onscreen_hor_pixel + xthick;
1291 for (y = area_y; y < area_y + area_height; )
1293 gint yoff = (y - yorig) % height;
1294 gint yw = MIN(height - yoff, (area_y + area_height) - y);
1296 for (x = area_x; x < area_x + area_width; )
1298 gint xoff = (x - xorig) % width;
1299 gint xw = MIN(width - xoff, (area_x + area_width) - x);
1301 gdk_draw_pixmap (widget->window,
1303 widget->style->bg_pixmap[GTK_STATE_NORMAL],
1320 gtk_text_draw_focus (GtkWidget *widget)
1326 g_return_if_fail (widget != NULL);
1327 g_return_if_fail (GTK_IS_TEXT (widget));
1329 text = GTK_TEXT (widget);
1331 if (GTK_WIDGET_DRAWABLE (widget))
1333 gint ythick = widget->style->klass->ythickness;
1334 gint xthick = widget->style->klass->xthickness;
1335 gint xextra = TEXT_BORDER_ROOM;
1336 gint yextra = TEXT_BORDER_ROOM;
1338 TDEBUG (("in gtk_text_draw_focus\n"));
1342 width = widget->allocation.width;
1343 height = widget->allocation.height;
1345 if (GTK_WIDGET_HAS_FOCUS (widget))
1354 gtk_paint_focus (widget->style, widget->window,
1355 NULL, widget, "text",
1357 widget->allocation.width - 1,
1358 widget->allocation.height - 1);
1361 gtk_paint_shadow (widget->style, widget->window,
1362 GTK_STATE_NORMAL, GTK_SHADOW_IN,
1363 NULL, widget, "text",
1364 x, y, width, height);
1368 width -= 2 * xthick;
1369 height -= 2 * ythick;
1371 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
1374 clear_focus_area (text, x, y, width, yextra);
1376 clear_focus_area (text, x, y + yextra,
1377 xextra, y + height - 2 * yextra);
1379 clear_focus_area (text, x + width - xextra, y + yextra,
1380 xextra, height - 2 * ythick);
1382 clear_focus_area (text, x, x + height - yextra, width, yextra);
1387 TDEBUG (("in gtk_text_draw_focus (undrawable !!!)\n"));
1392 gtk_text_size_request (GtkWidget *widget,
1393 GtkRequisition *requisition)
1400 g_return_if_fail (widget != NULL);
1401 g_return_if_fail (GTK_IS_TEXT (widget));
1402 g_return_if_fail (requisition != NULL);
1404 xthickness = widget->style->klass->xthickness + TEXT_BORDER_ROOM;
1405 ythickness = widget->style->klass->ythickness + TEXT_BORDER_ROOM;
1407 char_height = MIN_TEXT_HEIGHT_LINES * (widget->style->font->ascent +
1408 widget->style->font->descent);
1410 char_width = MIN_TEXT_WIDTH_LINES * (gdk_text_width (widget->style->font,
1411 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
1415 requisition->width = char_width + xthickness * 2;
1416 requisition->height = char_height + ythickness * 2;
1420 gtk_text_size_allocate (GtkWidget *widget,
1421 GtkAllocation *allocation)
1424 GtkEditable *editable;
1426 g_return_if_fail (widget != NULL);
1427 g_return_if_fail (GTK_IS_TEXT (widget));
1428 g_return_if_fail (allocation != NULL);
1430 text = GTK_TEXT (widget);
1431 editable = GTK_EDITABLE (widget);
1433 widget->allocation = *allocation;
1434 if (GTK_WIDGET_REALIZED (widget))
1436 gdk_window_move_resize (widget->window,
1437 allocation->x, allocation->y,
1438 allocation->width, allocation->height);
1440 gdk_window_move_resize (text->text_area,
1441 widget->style->klass->xthickness + TEXT_BORDER_ROOM,
1442 widget->style->klass->ythickness + TEXT_BORDER_ROOM,
1443 MAX (1, (gint)widget->allocation.width - (gint)(widget->style->klass->xthickness +
1444 (gint)TEXT_BORDER_ROOM) * 2),
1445 MAX (1, (gint)widget->allocation.height - (gint)(widget->style->klass->ythickness +
1446 (gint)TEXT_BORDER_ROOM) * 2));
1449 if (editable->ic && (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
1454 gdk_window_get_size (text->text_area, &width, &height);
1458 rect.height = height;
1459 gdk_ic_set_attr (editable->ic, "preeditAttributes", "area", &rect, NULL);
1463 recompute_geometry (text);
1468 gtk_text_draw (GtkWidget *widget,
1471 g_return_if_fail (widget != NULL);
1472 g_return_if_fail (GTK_IS_TEXT (widget));
1473 g_return_if_fail (area != NULL);
1475 if (GTK_WIDGET_DRAWABLE (widget))
1477 expose_text (GTK_TEXT (widget), area, TRUE);
1478 gtk_widget_draw_focus (widget);
1483 gtk_text_expose (GtkWidget *widget,
1484 GdkEventExpose *event)
1486 g_return_val_if_fail (widget != NULL, FALSE);
1487 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
1488 g_return_val_if_fail (event != NULL, FALSE);
1490 if (event->window == GTK_TEXT (widget)->text_area)
1492 TDEBUG (("in gtk_text_expose (expose)\n"));
1493 expose_text (GTK_TEXT (widget), &event->area, TRUE);
1495 else if (event->count == 0)
1497 TDEBUG (("in gtk_text_expose (focus)\n"));
1498 gtk_widget_draw_focus (widget);
1505 gtk_text_scroll_timeout (gpointer data)
1508 GdkEventMotion event;
1511 GdkModifierType mask;
1513 g_return_val_if_fail (GTK_IS_TEXT (data), FALSE);
1515 text = GTK_TEXT (data);
1518 gdk_window_get_pointer (text->text_area, &x, &y, &mask);
1520 if (!(mask & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)))
1528 gtk_text_motion_notify (GTK_WIDGET (text), &event);
1534 gtk_text_button_press (GtkWidget *widget,
1535 GdkEventButton *event)
1538 GtkEditable *editable;
1539 static GdkAtom ctext_atom = GDK_NONE;
1541 g_return_val_if_fail (widget != NULL, FALSE);
1542 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
1543 g_return_val_if_fail (event != NULL, FALSE);
1545 if (ctext_atom == GDK_NONE)
1546 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
1548 text = GTK_TEXT (widget);
1549 editable = GTK_EDITABLE (widget);
1551 if (text->button && (event->button != text->button))
1554 text->button = event->button;
1556 if (!GTK_WIDGET_HAS_FOCUS (widget))
1557 gtk_widget_grab_focus (widget);
1559 if (event->button == 1)
1561 switch (event->type)
1563 case GDK_BUTTON_PRESS:
1564 gtk_grab_add (widget);
1566 undraw_cursor (text, FALSE);
1567 find_mouse_cursor (text, (gint)event->x, (gint)event->y);
1568 draw_cursor (text, FALSE);
1570 /* Set it now, so we display things right. We'll unset it
1571 * later if things don't work out */
1572 editable->has_selection = TRUE;
1573 gtk_text_set_selection (GTK_EDITABLE(text),
1574 text->cursor_mark.index,
1575 text->cursor_mark.index);
1579 case GDK_2BUTTON_PRESS:
1580 gtk_text_select_word (text, event->time);
1583 case GDK_3BUTTON_PRESS:
1584 gtk_text_select_line (text, event->time);
1591 else if (event->type == GDK_BUTTON_PRESS)
1593 if ((event->button == 2) && editable->editable)
1595 if (editable->selection_start_pos == editable->selection_end_pos ||
1596 editable->has_selection)
1598 undraw_cursor (text, FALSE);
1599 find_mouse_cursor (text, (gint)event->x, (gint)event->y);
1600 draw_cursor (text, FALSE);
1604 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
1605 ctext_atom, event->time);
1609 gtk_grab_add (widget);
1611 undraw_cursor (text, FALSE);
1612 find_mouse_cursor (text, event->x, event->y);
1613 draw_cursor (text, FALSE);
1615 gtk_text_set_selection (GTK_EDITABLE(text),
1616 text->cursor_mark.index,
1617 text->cursor_mark.index);
1619 editable->has_selection = FALSE;
1620 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
1621 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
1629 gtk_text_button_release (GtkWidget *widget,
1630 GdkEventButton *event)
1633 GtkEditable *editable;
1634 g_return_val_if_fail (widget != NULL, FALSE);
1635 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
1636 g_return_val_if_fail (event != NULL, FALSE);
1638 text = GTK_TEXT (widget);
1640 gtk_grab_remove (widget);
1642 if (text->button != event->button)
1649 gtk_timeout_remove (text->timer);
1653 if (event->button == 1)
1655 text = GTK_TEXT (widget);
1656 editable = GTK_EDITABLE (widget);
1658 gtk_grab_remove (widget);
1660 editable->has_selection = FALSE;
1661 if (editable->selection_start_pos != editable->selection_end_pos)
1663 if (gtk_selection_owner_set (widget,
1664 GDK_SELECTION_PRIMARY,
1666 editable->has_selection = TRUE;
1668 gtk_text_update_text (editable, editable->selection_start_pos,
1669 editable->selection_end_pos);
1673 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
1674 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
1677 else if (event->button == 3)
1679 gtk_grab_remove (widget);
1682 undraw_cursor (text, FALSE);
1683 find_cursor (text, TRUE);
1684 draw_cursor (text, FALSE);
1690 gtk_text_motion_notify (GtkWidget *widget,
1691 GdkEventMotion *event)
1696 GdkModifierType mask;
1698 g_return_val_if_fail (widget != NULL, FALSE);
1699 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
1700 g_return_val_if_fail (event != NULL, FALSE);
1702 text = GTK_TEXT (widget);
1706 mask = event->state;
1707 if (event->is_hint || (text->text_area != event->window))
1709 gdk_window_get_pointer (text->text_area, &x, &y, &mask);
1712 if ((text->button == 0) ||
1713 !(mask & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)))
1716 gdk_window_get_size (text->text_area, NULL, &height);
1718 if ((y < 0) || (y > height))
1720 if (text->timer == 0)
1722 text->timer = gtk_timeout_add (SCROLL_TIME,
1723 gtk_text_scroll_timeout,
1727 scroll_int (text, y/2);
1729 scroll_int (text, (y - height)/2);
1735 undraw_cursor (GTK_TEXT (widget), FALSE);
1736 find_mouse_cursor (GTK_TEXT (widget), x, y);
1737 draw_cursor (GTK_TEXT (widget), FALSE);
1739 gtk_text_set_selection (GTK_EDITABLE(text),
1740 GTK_EDITABLE(text)->selection_start_pos,
1741 text->cursor_mark.index);
1747 gtk_text_insert_text (GtkEditable *editable,
1748 const gchar *new_text,
1749 gint new_text_length,
1752 GtkText *text = GTK_TEXT (editable);
1754 GdkColor *fore, *back;
1756 TextProperty *property;
1758 gtk_text_set_point (text, *position);
1760 property = MARK_CURRENT_PROPERTY (&text->point);
1761 font = property->flags & PROPERTY_FONT ? property->font->gdk_font : NULL;
1762 fore = property->flags & PROPERTY_FOREGROUND ? &property->fore_color : NULL;
1763 back = property->flags & PROPERTY_BACKGROUND ? &property->back_color : NULL;
1765 gtk_text_insert (text, font, fore, back, new_text, new_text_length);
1767 *position = text->point.index;
1771 gtk_text_delete_text (GtkEditable *editable,
1777 g_return_if_fail (start_pos >= 0);
1779 text = GTK_TEXT (editable);
1781 gtk_text_set_point (text, start_pos);
1783 end_pos = TEXT_LENGTH (text);
1785 if (end_pos > start_pos)
1786 gtk_text_forward_delete (text, end_pos - start_pos);
1790 gtk_text_key_press (GtkWidget *widget,
1794 GtkEditable *editable;
1799 g_return_val_if_fail (widget != NULL, FALSE);
1800 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
1801 g_return_val_if_fail (event != NULL, FALSE);
1805 text = GTK_TEXT (widget);
1806 editable = GTK_EDITABLE (widget);
1808 key = event->keyval;
1811 if ((GTK_EDITABLE(text)->editable == FALSE))
1813 switch (event->keyval)
1816 if (event->state & GDK_CONTROL_MASK)
1817 scroll_int (text, -text->vadj->value);
1820 if (event->state & GDK_CONTROL_MASK)
1821 scroll_int (text, +text->vadj->upper);
1823 case GDK_Page_Up: scroll_int (text, -text->vadj->page_increment); break;
1824 case GDK_Page_Down: scroll_int (text, +text->vadj->page_increment); break;
1825 case GDK_Up: scroll_int (text, -KEY_SCROLL_PIXELS); break;
1826 case GDK_Down: scroll_int (text, +KEY_SCROLL_PIXELS); break;
1828 if (event->state & GDK_CONTROL_MASK)
1829 gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
1838 gint extend_selection;
1840 guint initial_pos = editable->current_pos;
1842 text->point = find_mark (text, text->cursor_mark.index);
1844 extend_selection = event->state & GDK_SHIFT_MASK;
1845 extend_start = FALSE;
1847 if (extend_selection)
1849 editable->has_selection = TRUE;
1851 if (editable->selection_start_pos == editable->selection_end_pos)
1853 editable->selection_start_pos = text->point.index;
1854 editable->selection_end_pos = text->point.index;
1857 extend_start = (text->point.index == editable->selection_start_pos);
1860 switch (event->keyval)
1863 if (event->state & GDK_CONTROL_MASK)
1864 move_cursor_buffer_ver (text, -1);
1866 gtk_text_move_beginning_of_line (text);
1869 if (event->state & GDK_CONTROL_MASK)
1870 move_cursor_buffer_ver (text, +1);
1872 gtk_text_move_end_of_line (text);
1874 case GDK_Page_Up: move_cursor_page_ver (text, -1); break;
1875 case GDK_Page_Down: move_cursor_page_ver (text, +1); break;
1876 /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
1877 case GDK_Up: move_cursor_ver (text, -1); break;
1878 case GDK_Down: move_cursor_ver (text, +1); break;
1880 if (event->state & GDK_CONTROL_MASK)
1881 gtk_text_move_backward_word (text);
1883 move_cursor_hor (text, -1);
1886 if (event->state & GDK_CONTROL_MASK)
1887 gtk_text_move_forward_word (text);
1889 move_cursor_hor (text, +1);
1893 if (event->state & GDK_CONTROL_MASK)
1894 gtk_text_delete_backward_word (text);
1896 gtk_text_delete_backward_character (text);
1899 gtk_text_delete_line (text);
1902 if (event->state & GDK_SHIFT_MASK)
1904 extend_selection = FALSE;
1905 gtk_editable_paste_clipboard (editable);
1907 else if (event->state & GDK_CONTROL_MASK)
1909 gtk_editable_copy_clipboard (editable);
1913 /* gtk_toggle_insert(text) -- IMPLEMENT */
1917 if (event->state & GDK_CONTROL_MASK)
1918 gtk_text_delete_forward_word (text);
1919 else if (event->state & GDK_SHIFT_MASK)
1921 extend_selection = FALSE;
1922 gtk_editable_cut_clipboard (editable);
1925 gtk_text_delete_forward_character (text);
1928 position = text->point.index;
1929 gtk_editable_insert_text (editable, "\t", 1, &position);
1932 if (event->state & GDK_CONTROL_MASK)
1933 gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
1936 position = text->point.index;
1937 gtk_editable_insert_text (editable, "\n", 1, &position);
1941 /* Don't insert literally */
1948 if (event->state & GDK_CONTROL_MASK)
1950 if ((key >= 'A') && (key <= 'Z'))
1953 if ((key >= 'a') && (key <= 'z') && control_keys[(int) (key - 'a')])
1955 (* control_keys[(int) (key - 'a')]) (editable, event->time);
1961 else if (event->state & GDK_MOD1_MASK)
1963 if ((key >= 'A') && (key <= 'Z'))
1966 if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')])
1968 (* alt_keys[(int) (key - 'a')]) (editable, event->time);
1974 else if (event->length > 0)
1976 extend_selection = FALSE;
1978 if (event->length == 1)
1980 gtk_editable_delete_selection (editable);
1981 position = text->point.index;
1982 gtk_editable_insert_text (editable, &(event->string[0]), 1, &position);
1991 if (return_val && (editable->current_pos != initial_pos))
1993 if (extend_selection)
1995 if (editable->current_pos < editable->selection_start_pos)
1996 gtk_text_set_selection (editable, editable->current_pos,
1997 editable->selection_end_pos);
1998 else if (editable->current_pos > editable->selection_end_pos)
1999 gtk_text_set_selection (editable, editable->selection_start_pos,
2000 editable->current_pos);
2004 gtk_text_set_selection (editable, editable->current_pos,
2005 editable->selection_end_pos);
2007 gtk_text_set_selection (editable, editable->selection_start_pos,
2008 editable->current_pos);
2012 gtk_text_set_selection (editable, 0, 0);
2014 gtk_editable_claim_selection (editable,
2015 editable->selection_start_pos != editable->selection_end_pos,
2024 gtk_text_focus_in (GtkWidget *widget,
2025 GdkEventFocus *event)
2027 g_return_val_if_fail (widget != NULL, FALSE);
2028 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
2029 g_return_val_if_fail (event != NULL, FALSE);
2031 TDEBUG (("in gtk_text_focus_in\n"));
2033 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2034 gtk_widget_draw_focus (widget);
2037 if (GTK_EDITABLE(widget)->ic)
2038 gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_TEXT(widget)->text_area);
2041 draw_cursor (GTK_TEXT(widget), TRUE);
2047 gtk_text_focus_out (GtkWidget *widget,
2048 GdkEventFocus *event)
2050 g_return_val_if_fail (widget != NULL, FALSE);
2051 g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
2052 g_return_val_if_fail (event != NULL, FALSE);
2054 TDEBUG (("in gtk_text_focus_out\n"));
2056 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2057 gtk_widget_draw_focus (widget);
2059 undraw_cursor (GTK_TEXT(widget), TRUE);
2069 gtk_text_adjustment (GtkAdjustment *adjustment,
2072 g_return_if_fail (adjustment != NULL);
2073 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2074 g_return_if_fail (text != NULL);
2075 g_return_if_fail (GTK_IS_TEXT (text));
2077 /* Just ignore it if we haven't been size-allocated and realized yet */
2078 if (text->line_start_cache == NULL)
2081 if (adjustment == text->hadj)
2083 g_warning ("horizontal scrolling not implemented");
2087 gint diff = ((gint)adjustment->value) - text->last_ver_value;
2091 undraw_cursor (text, FALSE);
2094 scroll_down (text, diff);
2095 else /* if (diff < 0) */
2096 scroll_up (text, diff);
2098 draw_cursor (text, FALSE);
2100 text->last_ver_value = adjustment->value;
2106 gtk_text_disconnect (GtkAdjustment *adjustment,
2109 g_return_if_fail (adjustment != NULL);
2110 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2111 g_return_if_fail (text != NULL);
2112 g_return_if_fail (GTK_IS_TEXT (text));
2114 if (adjustment == text->hadj)
2116 if (adjustment == text->vadj)
2121 static GtkPropertyMark
2122 find_this_line_start_mark (GtkText* text, guint point_position, const GtkPropertyMark* near)
2124 GtkPropertyMark mark;
2126 mark = find_mark_near (text, point_position, near);
2128 while (mark.index > 0 &&
2129 GTK_TEXT_INDEX (text, mark.index - 1) != LINE_DELIM)
2130 decrement_mark (&mark);
2136 init_tab_cont (GtkText* text, PrevTabCont* tab_cont)
2138 tab_cont->pixel_offset = 0;
2139 tab_cont->tab_start.tab_stops = text->tab_stops;
2140 tab_cont->tab_start.to_next_tab = (gulong) text->tab_stops->data;
2142 if (!tab_cont->tab_start.to_next_tab)
2143 tab_cont->tab_start.to_next_tab = text->default_tab_width;
2147 line_params_iterate (GtkText* text,
2148 const GtkPropertyMark* mark0,
2149 const PrevTabCont* tab_mark0,
2152 LineIteratorFunction iter)
2153 /* mark0 MUST be a real line start. if ALLOC, allocate line params
2154 * from a mem chunk. DATA is passed to ITER_CALL, which is called
2155 * for each line following MARK, iteration continues unless ITER_CALL
2158 GtkPropertyMark mark = *mark0;
2159 PrevTabCont tab_conts[2];
2160 LineParams *lp, lpbuf;
2161 gint tab_cont_index = 0;
2164 tab_conts[0] = *tab_mark0;
2166 init_tab_cont (text, tab_conts);
2171 lp = g_chunk_new (LineParams, params_mem_chunk);
2175 *lp = find_line_params (text, &mark, tab_conts + tab_cont_index,
2176 tab_conts + (tab_cont_index + 1) % 2);
2178 if ((*iter) (text, lp, data))
2181 if (LAST_INDEX (text, lp->end))
2185 advance_mark (&mark);
2186 tab_cont_index = (tab_cont_index + 1) % 2;
2191 fetch_lines_iterator (GtkText* text, LineParams* lp, void* data)
2193 FetchLinesData *fldata = (FetchLinesData*) data;
2195 fldata->new_lines = g_list_prepend (fldata->new_lines, lp);
2197 switch (fldata->fl_type)
2199 case FetchLinesCount:
2200 if (!text->line_wrap || !lp->wraps)
2203 if (fldata->data >= fldata->data_max)
2207 case FetchLinesPixels:
2209 fldata->data += LINE_HEIGHT(*lp);
2211 if (fldata->data >= fldata->data_max)
2221 fetch_lines (GtkText* text,
2222 const GtkPropertyMark* mark0,
2223 const PrevTabCont* tab_cont0,
2227 FetchLinesData fl_data;
2229 fl_data.new_lines = NULL;
2231 fl_data.data_max = data;
2232 fl_data.fl_type = fl_type;
2234 line_params_iterate (text, mark0, tab_cont0, TRUE, &fl_data, fetch_lines_iterator);
2236 return g_list_reverse (fl_data.new_lines);
2240 fetch_lines_backward (GtkText* text)
2242 GList* new_lines = NULL, *new_line_start;
2243 GtkPropertyMark mark;
2245 if (CACHE_DATA(text->line_start_cache).start.index == 0)
2248 mark = find_this_line_start_mark (text,
2249 CACHE_DATA(text->line_start_cache).start.index - 1,
2250 &CACHE_DATA(text->line_start_cache).start);
2252 new_line_start = new_lines = fetch_lines (text, &mark, NULL, FetchLinesCount, 1);
2254 while (new_line_start->next)
2255 new_line_start = new_line_start->next;
2257 new_line_start->next = text->line_start_cache;
2258 text->line_start_cache->prev = new_line_start;
2262 fetch_lines_forward (GtkText* text, gint line_count)
2264 GtkPropertyMark mark;
2265 GList* line = text->line_start_cache;
2270 mark = CACHE_DATA(line).end;
2272 if (LAST_INDEX (text, mark))
2275 advance_mark(&mark);
2277 line->next = fetch_lines (text, &mark, &CACHE_DATA(line).tab_cont_next, FetchLinesCount, line_count);
2280 line->next->prev = line;
2283 /* Compute the number of lines, and vertical pixels for n characters
2284 * starting from the point
2287 compute_lines_pixels (GtkText* text, guint char_count,
2288 guint *lines, guint *pixels)
2290 GList *line = text->current_line;
2291 gint chars_left = char_count;
2296 /* If chars_left == 0, that means we're joining two lines in a
2297 * deletion, so add in the values for the next line as well
2299 for (; line && chars_left >= 0; line = line->next)
2301 *pixels += LINE_HEIGHT(CACHE_DATA(line));
2303 if (line == text->current_line)
2304 chars_left -= CACHE_DATA(line).end.index - text->point.index + 1;
2306 chars_left -= CACHE_DATA(line).end.index - CACHE_DATA(line).start.index + 1;
2308 if (!text->line_wrap || !CACHE_DATA(line).wraps)
2312 chars_left = 0; /* force another loop */
2315 fetch_lines_forward (text, 1);
2320 total_line_height (GtkText* text, GList* line, gint line_count)
2324 for (; line && line_count > 0; line = line->next)
2326 height += LINE_HEIGHT(CACHE_DATA(line));
2328 if (!text->line_wrap || !CACHE_DATA(line).wraps)
2332 fetch_lines_forward (text, line_count);
2339 swap_lines (GtkText* text, GList* old, GList* new, guint old_line_count)
2341 if (old == text->line_start_cache)
2345 for (; old_line_count > 0; old_line_count -= 1)
2347 while (text->line_start_cache &&
2349 CACHE_DATA(text->line_start_cache).wraps)
2350 remove_cache_line(text, text->line_start_cache);
2352 remove_cache_line(text, text->line_start_cache);
2355 last = g_list_last (new);
2357 last->next = text->line_start_cache;
2359 if (text->line_start_cache)
2360 text->line_start_cache->prev = last;
2362 text->line_start_cache = new;
2368 g_assert (old->prev);
2372 for (; old_line_count > 0; old_line_count -= 1)
2374 while (old && text->line_wrap && CACHE_DATA(old).wraps)
2375 old = remove_cache_line (text, old);
2377 old = remove_cache_line (text, old);
2383 last = g_list_last (new);
2393 correct_cache_delete (GtkText* text, gint nchars, gint lines)
2395 GList* cache = text->current_line;
2398 for (i = 0; cache && i < lines; i += 1, cache = cache->next)
2401 for (; cache; cache = cache->next)
2403 GtkPropertyMark *start = &CACHE_DATA(cache).start;
2404 GtkPropertyMark *end = &CACHE_DATA(cache).end;
2406 start->index -= nchars;
2407 end->index -= nchars;
2409 if (LAST_INDEX (text, text->point) &&
2410 start->index == text->point.index)
2411 *start = text->point;
2412 else if (start->property == text->point.property)
2413 start->offset = start->index - (text->point.index - text->point.offset);
2415 if (LAST_INDEX (text, text->point) &&
2416 end->index == text->point.index)
2418 if (end->property == text->point.property)
2419 end->offset = end->index - (text->point.index - text->point.offset);
2421 /*TEXT_ASSERT_MARK(text, start, "start");*/
2422 /*TEXT_ASSERT_MARK(text, end, "end");*/
2427 delete_expose (GtkText* text, guint nchars, guint old_lines, guint old_pixels)
2429 GtkWidget *widget = GTK_WIDGET (text);
2432 guint new_pixels = 0;
2434 GList* new_line = NULL;
2437 text->cursor_virtual_x = 0;
2439 correct_cache_delete (text, nchars, old_lines);
2441 pixel_height = pixel_height_of(text, text->current_line) -
2442 LINE_HEIGHT(CACHE_DATA(text->current_line));
2444 if (CACHE_DATA(text->current_line).start.index == text->point.index)
2445 CACHE_DATA(text->current_line).start = text->point;
2447 new_line = fetch_lines (text,
2448 &CACHE_DATA(text->current_line).start,
2449 &CACHE_DATA(text->current_line).tab_cont,
2453 swap_lines (text, text->current_line, new_line, old_lines);
2455 text->current_line = new_line;
2457 new_pixels = total_line_height (text, new_line, 1);
2459 gdk_window_get_size (text->text_area, &width, &height);
2461 if (old_pixels != new_pixels)
2463 if (!widget->style->bg_pixmap[GTK_STATE_NORMAL])
2465 gdk_draw_pixmap (text->text_area,
2469 pixel_height + old_pixels,
2471 pixel_height + new_pixels,
2475 text->vadj->upper += new_pixels;
2476 text->vadj->upper -= old_pixels;
2477 adjust_adj (text, text->vadj);
2481 rect.y = pixel_height;
2483 rect.height = new_pixels;
2485 expose_text (text, &rect, FALSE);
2486 gtk_text_draw_focus ( (GtkWidget *) text);
2488 text->cursor_mark = text->point;
2490 find_cursor (text, TRUE);
2492 if (old_pixels != new_pixels)
2494 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
2497 rect.y = pixel_height + new_pixels;
2499 rect.height = height - rect.y;
2501 expose_text (text, &rect, FALSE);
2504 process_exposes (text);
2511 /* note, the point has already been moved forward */
2513 correct_cache_insert (GtkText* text, gint nchars)
2516 GtkPropertyMark *start;
2517 GtkPropertyMark *end;
2518 gboolean was_split = FALSE;
2520 /* We need to distinguish whether the property was split in the
2521 * insert or not, so we check if the point (which points after
2522 * the insertion here), points to the same character as the
2523 * point before. Ugh.
2527 GtkPropertyMark tmp_mark = text->point;
2528 move_mark_n (&tmp_mark, -1);
2530 if (tmp_mark.property != text->point.property)
2534 /* If we inserted a property exactly at the beginning of the
2535 * line, we have to correct here, or fetch_lines will
2538 start = &CACHE_DATA(text->current_line).start;
2540 /* Check if if we split exactly at the beginning of the line:
2541 * (was_split won't be set if we are inserting at the end of the text,
2542 * so we don't check)
2544 if (start->offset == MARK_CURRENT_PROPERTY (start)->length)
2545 SET_PROPERTY_MARK (start, start->property->next, 0);
2546 /* Check if we inserted a property at the beginning of the text: */
2547 else if (was_split &&
2548 (start->property == text->point.property) &&
2549 (start->index == text->point.index - nchars))
2550 SET_PROPERTY_MARK (start, start->property->prev, 0);
2552 /* Now correct the offsets, and check for start or end marks that
2553 * are after the point, yet point to a property before the point's
2554 * property. This indicates that they are meant to point to the
2555 * second half of a property we split in insert_text_property(), so
2556 * we fix them up that way.
2558 cache = text->current_line->next;
2560 for (; cache; cache = cache->next)
2562 start = &CACHE_DATA(cache).start;
2563 end = &CACHE_DATA(cache).end;
2565 if (LAST_INDEX (text, text->point) &&
2566 start->index == text->point.index)
2567 *start = text->point;
2568 else if (start->index >= text->point.index - nchars)
2570 if (!was_split && start->property == text->point.property)
2571 move_mark_n(start, nchars);
2574 if (start->property->next &&
2575 (start->property->next->next == text->point.property))
2577 g_assert (start->offset >= MARK_CURRENT_PROPERTY (start)->length);
2578 start->offset -= MARK_CURRENT_PROPERTY (start)->length;
2579 start->property = text->point.property;
2581 start->index += nchars;
2585 if (LAST_INDEX (text, text->point) &&
2586 end->index == text->point.index)
2588 if (end->index >= text->point.index - nchars)
2590 if (!was_split && end->property == text->point.property)
2591 move_mark_n(end, nchars);
2594 if (end->property->next &&
2595 (end->property->next->next == text->point.property))
2597 g_assert (end->offset >= MARK_CURRENT_PROPERTY (end)->length);
2598 end->offset -= MARK_CURRENT_PROPERTY (end)->length;
2599 end->property = text->point.property;
2601 end->index += nchars;
2605 /*TEXT_ASSERT_MARK(text, start, "start");*/
2606 /*TEXT_ASSERT_MARK(text, end, "end");*/
2612 insert_expose (GtkText* text, guint old_pixels, gint nchars,
2613 guint new_line_count)
2615 GtkWidget *widget = GTK_WIDGET (text);
2618 guint new_pixels = 0;
2620 GList* new_lines = NULL;
2623 text->cursor_virtual_x = 0;
2625 undraw_cursor (text, FALSE);
2627 correct_cache_insert (text, nchars);
2629 TEXT_SHOW_ADJ (text, text->vadj, "vadj");
2631 pixel_height = pixel_height_of(text, text->current_line) -
2632 LINE_HEIGHT(CACHE_DATA(text->current_line));
2634 new_lines = fetch_lines (text,
2635 &CACHE_DATA(text->current_line).start,
2636 &CACHE_DATA(text->current_line).tab_cont,
2640 swap_lines (text, text->current_line, new_lines, 1);
2642 text->current_line = new_lines;
2644 new_pixels = total_line_height (text, new_lines, new_line_count);
2646 gdk_window_get_size (text->text_area, &width, &height);
2648 if (old_pixels != new_pixels)
2650 if (!widget->style->bg_pixmap[GTK_STATE_NORMAL])
2652 gdk_draw_pixmap (text->text_area,
2656 pixel_height + old_pixels,
2658 pixel_height + new_pixels,
2660 height + (old_pixels - new_pixels) - pixel_height);
2663 text->vadj->upper += new_pixels;
2664 text->vadj->upper -= old_pixels;
2665 adjust_adj (text, text->vadj);
2669 rect.y = pixel_height;
2671 rect.height = new_pixels;
2673 expose_text (text, &rect, FALSE);
2674 gtk_text_draw_focus ( (GtkWidget *) text);
2676 text->cursor_mark = text->point;
2678 find_cursor (text, TRUE);
2680 draw_cursor (text, FALSE);
2682 if (old_pixels != new_pixels)
2684 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
2687 rect.y = pixel_height + new_pixels;
2689 rect.height = height - rect.y;
2691 expose_text (text, &rect, FALSE);
2694 process_exposes (text);
2697 TEXT_SHOW_ADJ (text, text->vadj, "vadj");
2702 /* Text property functions */
2705 font_hash (gconstpointer font)
2707 return gdk_font_id ((const GdkFont*) font);
2710 static GHashTable *font_cache_table = NULL;
2713 get_text_font (GdkFont* gfont)
2718 if (!font_cache_table)
2719 font_cache_table = g_hash_table_new (font_hash, (GCompareFunc) gdk_font_equal);
2721 tf = g_hash_table_lookup (font_cache_table, gfont);
2729 tf = g_new (GtkTextFont, 1);
2732 tf->gdk_font = gfont;
2733 gdk_font_ref (gfont);
2735 for(i = 0; i < 256; i += 1)
2736 tf->char_widths[i] = gdk_char_width (gfont, (char)i);
2738 g_hash_table_insert (font_cache_table, gfont, tf);
2744 text_font_unref (GtkTextFont *text_font)
2746 text_font->ref_count--;
2747 if (text_font->ref_count == 0)
2749 g_hash_table_remove (font_cache_table, text_font->gdk_font);
2750 gdk_font_unref (text_font->gdk_font);
2756 text_properties_equal (TextProperty* prop, GdkFont* font, GdkColor *fore, GdkColor *back)
2758 if (prop->flags & PROPERTY_FONT)
2761 GtkTextFont *text_font;
2766 text_font = get_text_font (font);
2768 retval = (prop->font == text_font);
2769 text_font_unref (text_font);
2778 if (prop->flags & PROPERTY_FOREGROUND)
2780 if (!fore || !gdk_color_equal (&prop->fore_color, fore))
2787 if (prop->flags & PROPERTY_BACKGROUND)
2789 if (!back || !gdk_color_equal (&prop->fore_color, fore))
2800 realize_property (GtkText *text, TextProperty *prop)
2802 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (text));
2804 if (prop->flags & PROPERTY_FOREGROUND)
2805 gdk_colormap_alloc_color (colormap, &prop->fore_color, FALSE, FALSE);
2807 if (prop->flags & PROPERTY_BACKGROUND)
2808 gdk_colormap_alloc_color (colormap, &prop->back_color, FALSE, FALSE);
2812 realize_properties (GtkText *text)
2814 GList *tmp_list = text->text_properties;
2818 realize_property (text, tmp_list->data);
2820 tmp_list = tmp_list->next;
2825 unrealize_property (GtkText *text, TextProperty *prop)
2827 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (text));
2829 if (prop->flags & PROPERTY_FOREGROUND)
2830 gdk_colormap_free_colors (colormap, &prop->fore_color, 1);
2832 if (prop->flags & PROPERTY_BACKGROUND)
2833 gdk_colormap_free_colors (colormap, &prop->back_color, 1);
2837 unrealize_properties (GtkText *text)
2839 GList *tmp_list = text->text_properties;
2843 unrealize_property (text, tmp_list->data);
2845 tmp_list = tmp_list->next;
2849 static TextProperty*
2850 new_text_property (GtkText *text, GdkFont *font, GdkColor* fore,
2851 GdkColor* back, guint length)
2855 if (text_property_chunk == NULL)
2857 text_property_chunk = g_mem_chunk_new ("text property mem chunk",
2858 sizeof(TextProperty),
2859 1024*sizeof(TextProperty),
2863 prop = g_chunk_new(TextProperty, text_property_chunk);
2868 prop->flags |= PROPERTY_FONT;
2869 prop->font = get_text_font (font);
2876 prop->flags |= PROPERTY_FOREGROUND;
2877 prop->fore_color = *fore;
2882 prop->flags |= PROPERTY_BACKGROUND;
2883 prop->back_color = *back;
2886 prop->length = length;
2888 if (GTK_WIDGET_REALIZED (text))
2889 realize_property (text, prop);
2895 destroy_text_property (TextProperty *prop)
2898 text_font_unref (prop->font);
2900 g_mem_chunk_free (text_property_chunk, prop);
2903 /* Flop the memory between the point and the gap around like a
2906 move_gap_to_point (GtkText* text)
2908 if (text->gap_position < text->point.index)
2910 gint diff = text->point.index - text->gap_position;
2912 g_memmove (text->text + text->gap_position,
2913 text->text + text->gap_position + text->gap_size,
2916 text->gap_position = text->point.index;
2918 else if (text->gap_position > text->point.index)
2920 gint diff = text->gap_position - text->point.index;
2922 g_memmove (text->text + text->point.index + text->gap_size,
2923 text->text + text->point.index,
2926 text->gap_position = text->point.index;
2930 /* Increase the gap size. */
2932 make_forward_space (GtkText* text, guint len)
2934 if (text->gap_size < len)
2936 guint sum = MAX(2*len, MIN_GAP_SIZE) + text->text_end;
2938 if (sum >= text->text_len)
2942 while (i <= sum) i <<= 1;
2944 text->text = (guchar*)g_realloc(text->text, i);
2947 g_memmove (text->text + text->gap_position + text->gap_size + 2*len,
2948 text->text + text->gap_position + text->gap_size,
2949 text->text_end - (text->gap_position + text->gap_size));
2951 text->text_end += len*2;
2952 text->gap_size += len*2;
2956 /* Inserts into the text property list a list element that guarantees
2957 * that for len characters following the point, text has the correct
2958 * property. does not move point. adjusts text_properties_point and
2959 * text_properties_point_offset relative to the current value of
2962 insert_text_property (GtkText* text, GdkFont* font,
2963 GdkColor *fore, GdkColor* back, guint len)
2965 GtkPropertyMark *mark = &text->point;
2966 TextProperty* forward_prop = MARK_CURRENT_PROPERTY(mark);
2967 TextProperty* backward_prop = MARK_PREV_PROPERTY(mark);
2969 if (MARK_OFFSET(mark) == 0)
2971 /* Point is on the boundary of two properties.
2972 * If it is the same as either, grow, else insert
2975 if (text_properties_equal(forward_prop, font, fore, back))
2977 /* Grow the property in front of us. */
2979 MARK_PROPERTY_LENGTH(mark) += len;
2981 else if (backward_prop &&
2982 text_properties_equal(backward_prop, font, fore, back))
2984 /* Grow property behind us, point property and offset
2987 SET_PROPERTY_MARK (&text->point,
2988 MARK_PREV_LIST_PTR (mark),
2989 backward_prop->length);
2991 backward_prop->length += len;
2993 else if ((MARK_NEXT_LIST_PTR(mark) == NULL) &&
2994 (forward_prop->length == 1))
2996 /* Next property just has last position, take it over */
2998 if (GTK_WIDGET_REALIZED (text))
2999 unrealize_property (text, forward_prop);
3001 forward_prop->flags = 0;
3004 forward_prop->flags |= PROPERTY_FONT;
3005 forward_prop->font = get_text_font (font);
3008 forward_prop->font = NULL;
3012 forward_prop->flags |= PROPERTY_FOREGROUND;
3013 forward_prop->fore_color = *fore;
3017 forward_prop->flags |= PROPERTY_BACKGROUND;
3018 forward_prop->back_color = *back;
3020 forward_prop->length += len;
3022 if (GTK_WIDGET_REALIZED (text))
3023 realize_property (text, forward_prop);
3027 /* Splice a new property into the list. */
3029 GList* new_prop = g_list_alloc();
3031 new_prop->next = MARK_LIST_PTR(mark);
3032 new_prop->prev = MARK_PREV_LIST_PTR(mark);
3033 new_prop->next->prev = new_prop;
3036 new_prop->prev->next = new_prop;
3038 new_prop->data = new_text_property (text, font, fore, back, len);
3040 SET_PROPERTY_MARK (mark, new_prop, 0);
3045 /* The following will screw up the line_start cache,
3046 * we'll fix it up in correct_cache_insert
3049 /* In the middle of forward_prop, if properties are equal,
3050 * just add to its length, else split it into two and splice
3052 if (text_properties_equal (forward_prop, font, fore, back))
3054 forward_prop->length += len;
3056 else if ((MARK_NEXT_LIST_PTR(mark) == NULL) &&
3057 (MARK_OFFSET(mark) + 1 == forward_prop->length))
3059 /* Inserting before only the last position in the text */
3062 forward_prop->length -= 1;
3064 new_prop = g_list_alloc();
3065 new_prop->data = new_text_property (text, font, fore, back, len+1);
3066 new_prop->prev = MARK_LIST_PTR(mark);
3067 new_prop->next = NULL;
3068 MARK_NEXT_LIST_PTR(mark) = new_prop;
3070 SET_PROPERTY_MARK (mark, new_prop, 0);
3074 GList* new_prop = g_list_alloc();
3075 GList* new_prop_forward = g_list_alloc();
3076 gint old_length = forward_prop->length;
3077 GList* next = MARK_NEXT_LIST_PTR(mark);
3079 /* Set the new lengths according to where they are split. Construct
3080 * two new properties. */
3081 forward_prop->length = MARK_OFFSET(mark);
3083 new_prop_forward->data =
3084 new_text_property(text,
3085 forward_prop->flags & PROPERTY_FONT ?
3086 forward_prop->font->gdk_font : NULL,
3087 forward_prop->flags & PROPERTY_FOREGROUND ?
3088 &forward_prop->fore_color : NULL,
3089 forward_prop->flags & PROPERTY_BACKGROUND ?
3090 &forward_prop->back_color : NULL,
3091 old_length - forward_prop->length);
3093 new_prop->data = new_text_property(text, font, fore, back, len);
3095 /* Now splice things in. */
3096 MARK_NEXT_LIST_PTR(mark) = new_prop;
3097 new_prop->prev = MARK_LIST_PTR(mark);
3099 new_prop->next = new_prop_forward;
3100 new_prop_forward->prev = new_prop;
3102 new_prop_forward->next = next;
3105 next->prev = new_prop_forward;
3107 SET_PROPERTY_MARK (mark, new_prop, 0);
3111 while (text->text_properties_end->next)
3112 text->text_properties_end = text->text_properties_end->next;
3114 while (text->text_properties->prev)
3115 text->text_properties = text->text_properties->prev;
3119 delete_text_property (GtkText* text, guint nchars)
3121 /* Delete nchars forward from point. */
3123 /* Deleting text properties is problematical, because we
3124 * might be storing around marks pointing to a property.
3126 * The marks in question and how we handle them are:
3128 * point: We know the new value, since it will be at the
3129 * end of the deleted text, and we move it there
3131 * cursor: We just remove the mark and set it equal to the
3132 * point after the operation.
3133 * line-start cache: We replace most affected lines.
3134 * The current line gets used to fetch the new
3135 * lines so, if necessary, (delete at the beginning
3136 * of a line) we fix it up by setting it equal to the
3144 for(; nchars; nchars -= 1)
3146 prop = MARK_CURRENT_PROPERTY(&text->point);
3150 if (prop->length == 0)
3152 tmp = MARK_LIST_PTR (&text->point);
3154 is_first = tmp == text->text_properties;
3156 MARK_LIST_PTR (&text->point) = g_list_remove_link (tmp, tmp);
3157 text->point.offset = 0;
3159 if (GTK_WIDGET_REALIZED (text))
3160 unrealize_property (text, prop);
3162 destroy_text_property (prop);
3163 g_list_free_1 (tmp);
3165 prop = MARK_CURRENT_PROPERTY (&text->point);
3168 text->text_properties = MARK_LIST_PTR (&text->point);
3170 g_assert (prop->length != 0);
3172 else if (prop->length == text->point.offset)
3174 MARK_LIST_PTR (&text->point) = MARK_NEXT_LIST_PTR (&text->point);
3175 text->point.offset = 0;
3179 /* Check to see if we have just the single final position remaining
3180 * along in a property; if so, combine it with the previous property
3182 if (LAST_INDEX (text, text->point) &&
3183 (MARK_OFFSET (&text->point) == 0) &&
3184 (MARK_PREV_LIST_PTR(&text->point) != NULL))
3186 tmp = MARK_LIST_PTR (&text->point);
3187 prop = MARK_CURRENT_PROPERTY(&text->point);
3189 MARK_LIST_PTR (&text->point) = MARK_PREV_LIST_PTR (&text->point);
3190 MARK_CURRENT_PROPERTY(&text->point)->length += 1;
3191 MARK_NEXT_LIST_PTR(&text->point) = NULL;
3193 text->point.offset = MARK_CURRENT_PROPERTY(&text->point)->length - 1;
3195 if (GTK_WIDGET_REALIZED (text))
3196 unrealize_property (text, prop);
3198 destroy_text_property (prop);
3199 g_list_free_1 (tmp);
3204 init_properties (GtkText *text)
3206 if (!text->text_properties)
3208 text->text_properties = g_list_alloc();
3209 text->text_properties->next = NULL;
3210 text->text_properties->prev = NULL;
3211 text->text_properties->data = new_text_property (text, NULL, NULL, NULL, 1);
3212 text->text_properties_end = text->text_properties;
3214 SET_PROPERTY_MARK (&text->point, text->text_properties, 0);
3216 text->point.index = 0;
3221 /**********************************************************************/
3222 /* Property Movement */
3223 /**********************************************************************/
3226 move_mark_n (GtkPropertyMark* mark, gint n)
3229 advance_mark_n(mark, n);
3231 decrement_mark_n(mark, -n);
3235 advance_mark_n (GtkPropertyMark* mark, gint n)
3241 for (i = 0; i < n; i += 1)
3242 advance_mark (mark);
3246 advance_mark (GtkPropertyMark* mark)
3248 TextProperty* prop = MARK_CURRENT_PROPERTY (mark);
3252 if (prop->length > mark->offset + 1)
3256 mark->property = MARK_NEXT_LIST_PTR (mark);
3262 decrement_mark (GtkPropertyMark* mark)
3266 if (mark->offset > 0)
3270 mark->property = MARK_PREV_LIST_PTR (mark);
3271 mark->offset = MARK_CURRENT_PROPERTY (mark)->length - 1;
3276 decrement_mark_n (GtkPropertyMark* mark, gint n)
3282 for (i = 0; i < n; i += 1)
3283 decrement_mark (mark);
3286 static GtkPropertyMark
3287 find_mark (GtkText* text, guint mark_position)
3289 return find_mark_near (text, mark_position, &text->point);
3292 /* This can be optimized in two ways.
3293 * First, advances can be made in units of the current TextProperty
3294 * length, when possible. This will reduce computation and function
3297 * You can also start from the end, what a drag.
3299 static GtkPropertyMark
3300 find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near)
3305 GtkPropertyMark mark;
3308 diffa = mark_position + 1;
3310 diffa = mark_position - near->index;
3312 diffb = mark_position;
3324 mark.property = text->text_properties;
3328 if (mark.index > mark_position)
3330 while (mark.index > mark_position)
3331 decrement_mark (&mark);
3335 while (mark_position > mark.index)
3336 advance_mark (&mark);
3342 /* This routine must be called with scroll == FALSE, only when
3343 * point is at least partially on screen
3347 find_line_containing_point (GtkText* text, guint point,
3353 text->current_line = NULL;
3355 if (!text->line_start_cache->next)
3357 /* @@@ Its visible, right? */
3358 text->current_line = text->line_start_cache;
3362 while ( ( scroll && (text->first_cut_pixels != 0) &&
3363 (CACHE_DATA(text->line_start_cache->next).start.index > point) ) ||
3364 ( (text->first_cut_pixels == 0) &&
3365 (CACHE_DATA(text->line_start_cache).start.index > point) ) )
3367 scroll_int (text, - SCROLL_PIXELS);
3368 g_assert (text->line_start_cache->next);
3372 gdk_window_get_size (text->text_area, NULL, &height);
3374 for (cache = text->line_start_cache; cache; cache = cache->next)
3378 if (CACHE_DATA(cache).end.index >= point ||
3379 LAST_INDEX(text, CACHE_DATA(cache).end))
3381 text->current_line = cache; /* LOOK HERE, this proc has an
3382 * important side effect. */
3386 TEXT_SHOW_LINE (text, cache, "cache");
3388 if (cache->next == NULL)
3389 fetch_lines_forward (text, 1);
3393 lph = pixel_height_of (text, cache->next);
3395 /* Scroll the bottom of the line is on screen, or until
3396 * the line is the first onscreen line.
3398 while (cache->next != text->line_start_cache && lph > height)
3400 TEXT_SHOW_LINE (text, cache, "cache");
3401 TEXT_SHOW_LINE (text, cache->next, "cache->next");
3402 scroll_int (text, LINE_HEIGHT(CACHE_DATA(cache->next)));
3403 lph = pixel_height_of (text, cache->next);
3408 g_assert_not_reached (); /* Must set text->current_line here */
3412 pixel_height_of (GtkText* text, GList* cache_line)
3414 gint pixels = - text->first_cut_pixels;
3415 GList *cache = text->line_start_cache;
3418 pixels += LINE_HEIGHT (CACHE_DATA(cache));
3420 if (cache->data == cache_line->data)
3423 cache = cache->next;
3429 /**********************************************************************/
3430 /* Search and Placement */
3431 /**********************************************************************/
3434 find_char_width (GtkText* text, const GtkPropertyMark *mark, const TabStopMark *tab_mark)
3437 gint16* char_widths;
3439 if (LAST_INDEX (text, *mark))
3442 ch = GTK_TEXT_INDEX (text, mark->index);
3443 char_widths = MARK_CURRENT_TEXT_FONT (text, mark)->char_widths;
3447 return tab_mark->to_next_tab * char_widths[' '];
3451 return char_widths[ch & 0xff];
3456 advance_tab_mark (GtkText* text, TabStopMark* tab_mark, gchar ch)
3458 if (tab_mark->to_next_tab == 1 || ch == '\t')
3460 if (tab_mark->tab_stops->next)
3462 tab_mark->tab_stops = tab_mark->tab_stops->next;
3463 tab_mark->to_next_tab = (gulong) tab_mark->tab_stops->data;
3467 tab_mark->to_next_tab = text->default_tab_width;
3472 tab_mark->to_next_tab -= 1;
3477 advance_tab_mark_n (GtkText* text, TabStopMark* tab_mark, gint n)
3481 advance_tab_mark (text, tab_mark, 0);
3485 find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height)
3488 GtkEditable *editable = (GtkEditable *)text;
3490 GtkPropertyMark mark = start_line->start;
3491 TabStopMark tab_mark = start_line->tab_cont.tab_start;
3492 gint pixel_width = LINE_START_PIXEL (*start_line);
3494 while (mark.index < text->cursor_mark.index)
3496 pixel_width += find_char_width (text, &mark, &tab_mark);
3498 advance_tab_mark (text, &tab_mark, GTK_TEXT_INDEX(text, mark.index));
3499 advance_mark (&mark);
3502 text->cursor_pos_x = pixel_width;
3503 text->cursor_pos_y = pixel_height;
3504 text->cursor_char_offset = start_line->font_descent;
3505 text->cursor_mark = mark;
3507 ch = LAST_INDEX (text, mark) ?
3508 LINE_DELIM : GTK_TEXT_INDEX (text, mark.index);
3511 text->cursor_char = ch;
3513 text->cursor_char = 0;
3516 if (gdk_im_ready() && editable->ic &&
3517 gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION)
3521 spot.x = text->cursor_pos_x;
3522 spot.y = text->cursor_pos_y - text->cursor_char_offset;
3523 if (MARK_CURRENT_FONT (text, &mark)->type == GDK_FONT_FONTSET)
3524 gdk_ic_set_attr (editable->ic, "preeditAttributes",
3525 "fontSet", GDK_FONT_XFONT (MARK_CURRENT_FONT (text, &mark)),
3528 gdk_ic_set_attr (editable->ic, "preeditAttributes",
3529 "spotLocation", &spot,
3530 "lineSpace", LINE_HEIGHT (*start_line),
3531 "foreground", MARK_CURRENT_FORE (text, &mark)->pixel,
3532 "background", MARK_CURRENT_BACK (text, &mark)->pixel,
3539 find_cursor (GtkText* text, gboolean scroll)
3541 if (GTK_WIDGET_REALIZED (text))
3543 find_line_containing_point (text, text->cursor_mark.index, scroll);
3545 if (text->current_line)
3546 find_cursor_at_line (text,
3547 &CACHE_DATA(text->current_line),
3548 pixel_height_of(text, text->current_line));
3551 GTK_EDITABLE (text)->current_pos = text->cursor_mark.index;
3555 find_mouse_cursor_at_line (GtkText *text, const LineParams* lp,
3556 guint line_pixel_height,
3559 GtkPropertyMark mark = lp->start;
3560 TabStopMark tab_mark = lp->tab_cont.tab_start;
3562 gint char_width = find_char_width(text, &mark, &tab_mark);
3563 gint pixel_width = LINE_START_PIXEL (*lp) + (char_width+1)/2;
3565 text->cursor_pos_y = line_pixel_height;
3569 gchar ch = LAST_INDEX (text, mark) ?
3570 LINE_DELIM : GTK_TEXT_INDEX (text, mark.index);
3572 if (button_x < pixel_width || mark.index == lp->end.index)
3574 text->cursor_pos_x = pixel_width - (char_width+1)/2;
3575 text->cursor_mark = mark;
3576 text->cursor_char_offset = lp->font_descent;
3579 text->cursor_char = ch;
3581 text->cursor_char = 0;
3586 advance_tab_mark (text, &tab_mark, ch);
3587 advance_mark (&mark);
3589 pixel_width += char_width/2;
3591 char_width = find_char_width (text, &mark, &tab_mark);
3593 pixel_width += (char_width+1)/2;
3598 find_mouse_cursor (GtkText* text, gint x, gint y)
3601 GList* cache = text->line_start_cache;
3605 pixel_height = - text->first_cut_pixels;
3607 for (; cache; cache = cache->next)
3609 pixel_height += LINE_HEIGHT(CACHE_DATA(cache));
3611 if (y < pixel_height || !cache->next)
3613 find_mouse_cursor_at_line (text, &CACHE_DATA(cache), pixel_height, x);
3615 find_cursor (text, FALSE);
3622 /**********************************************************************/
3624 /**********************************************************************/
3627 free_cache (GtkText* text)
3629 GList* cache = text->line_start_cache;
3634 cache = cache->prev;
3636 text->line_start_cache = cache;
3639 for (; cache; cache = cache->next)
3640 g_mem_chunk_free (params_mem_chunk, cache->data);
3642 g_list_free (text->line_start_cache);
3644 text->line_start_cache = NULL;
3648 remove_cache_line (GtkText* text, GList* member)
3655 if (member == text->line_start_cache)
3656 text->line_start_cache = text->line_start_cache->next;
3659 member->prev->next = member->next;
3662 member->next->prev = member->prev;
3664 list = member->next;
3666 g_mem_chunk_free (params_mem_chunk, member->data);
3667 g_list_free_1 (member);
3672 /**********************************************************************/
3674 /**********************************************************************/
3677 move_cursor_buffer_ver (GtkText *text, int dir)
3679 undraw_cursor (text, FALSE);
3683 scroll_int (text, text->vadj->upper);
3684 text->cursor_mark = find_this_line_start_mark (text,
3686 &text->cursor_mark);
3690 scroll_int (text, - text->vadj->value);
3691 text->cursor_mark = find_this_line_start_mark (text,
3693 &text->cursor_mark);
3696 find_cursor (text, TRUE);
3697 draw_cursor (text, FALSE);
3701 move_cursor_page_ver (GtkText *text, int dir)
3703 scroll_int (text, dir * text->vadj->page_increment);
3707 move_cursor_ver (GtkText *text, int count)
3710 GtkPropertyMark mark;
3713 mark = find_this_line_start_mark (text, text->cursor_mark.index, &text->cursor_mark);
3714 offset = text->cursor_mark.index - mark.index;
3716 if (offset > text->cursor_virtual_x)
3717 text->cursor_virtual_x = offset;
3721 if (mark.index == 0)
3724 decrement_mark (&mark);
3725 mark = find_this_line_start_mark (text, mark.index, &mark);
3729 mark = text->cursor_mark;
3731 while (!LAST_INDEX(text, mark) && GTK_TEXT_INDEX(text, mark.index) != LINE_DELIM)
3732 advance_mark (&mark);
3734 if (LAST_INDEX(text, mark))
3737 advance_mark (&mark);
3740 for (i=0; i < text->cursor_virtual_x; i += 1, advance_mark(&mark))
3741 if (LAST_INDEX(text, mark) || GTK_TEXT_INDEX(text, mark.index) == LINE_DELIM)
3744 undraw_cursor (text, FALSE);
3746 text->cursor_mark = mark;
3748 find_cursor (text, TRUE);
3750 draw_cursor (text, FALSE);
3754 move_cursor_hor (GtkText *text, int count)
3756 /* count should be +-1. */
3757 if ( (count > 0 && text->cursor_mark.index + count > TEXT_LENGTH(text)) ||
3758 (count < 0 && text->cursor_mark.index < (- count)) ||
3762 text->cursor_virtual_x = 0;
3764 undraw_cursor (text, FALSE);
3766 move_mark_n (&text->cursor_mark, count);
3768 find_cursor (text, TRUE);
3770 draw_cursor (text, FALSE);
3774 gtk_text_move_cursor (GtkEditable *editable,
3781 move_cursor_hor (GTK_TEXT (editable), 1);
3786 move_cursor_hor (GTK_TEXT (editable), -1);
3792 move_cursor_ver (GTK_TEXT (editable), 1);
3797 move_cursor_ver (GTK_TEXT (editable), -1);
3802 gtk_text_move_forward_character (GtkText *text)
3804 move_cursor_hor (text, 1);
3808 gtk_text_move_backward_character (GtkText *text)
3810 move_cursor_hor (text, -1);
3814 gtk_text_move_next_line (GtkText *text)
3816 move_cursor_ver (text, 1);
3820 gtk_text_move_previous_line (GtkText *text)
3822 move_cursor_ver (text, -1);
3826 gtk_text_move_word (GtkEditable *editable,
3832 gtk_text_move_forward_word (GTK_TEXT (editable));
3837 gtk_text_move_backward_word (GTK_TEXT (editable));
3842 gtk_text_move_forward_word (GtkText *text)
3844 text->cursor_virtual_x = 0;
3846 undraw_cursor (text, FALSE);
3848 while (!LAST_INDEX (text, text->cursor_mark) &&
3849 !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
3850 advance_mark (&text->cursor_mark);
3852 while (!LAST_INDEX (text, text->cursor_mark) &&
3853 isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
3854 advance_mark (&text->cursor_mark);
3856 find_cursor (text, TRUE);
3857 draw_cursor (text, FALSE);
3861 gtk_text_move_backward_word (GtkText *text)
3863 text->cursor_virtual_x = 0;
3865 undraw_cursor (text, FALSE);
3867 while ((text->cursor_mark.index > 0) &&
3868 !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
3869 decrement_mark (&text->cursor_mark);
3871 while ((text->cursor_mark.index > 0) &&
3872 isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
3873 decrement_mark (&text->cursor_mark);
3875 find_cursor (text, TRUE);
3876 draw_cursor (text, FALSE);
3880 gtk_text_move_page (GtkEditable *editable,
3885 scroll_int (GTK_TEXT (editable),
3886 y * GTK_TEXT(editable)->vadj->page_increment);
3890 gtk_text_move_to_row (GtkEditable *editable,
3896 gtk_text_move_to_column (GtkEditable *editable,
3901 text = GTK_TEXT (editable);
3903 text->cursor_virtual_x = 0; /* FIXME */
3905 undraw_cursor (text, FALSE);
3907 /* Move to the beginning of the line */
3908 while ((text->cursor_mark.index > 0) &&
3909 (GTK_TEXT_INDEX (text, text->cursor_mark.index - 1) != LINE_DELIM))
3910 decrement_mark (&text->cursor_mark);
3912 while (!LAST_INDEX (text, text->cursor_mark) &&
3913 (GTK_TEXT_INDEX (text, text->cursor_mark.index) != LINE_DELIM))
3917 else if (column == 0)
3920 advance_mark (&text->cursor_mark);
3923 find_cursor (text, TRUE);
3924 draw_cursor (text, FALSE);
3928 gtk_text_move_beginning_of_line (GtkText *text)
3930 gtk_text_move_to_column (GTK_EDITABLE (text), 0);
3935 gtk_text_move_end_of_line (GtkText *text)
3937 gtk_text_move_to_column (GTK_EDITABLE (text), -1);
3941 gtk_text_kill_char (GtkEditable *editable,
3946 text = GTK_TEXT (editable);
3948 if (editable->selection_start_pos != editable->selection_end_pos)
3949 gtk_editable_delete_selection (editable);
3954 if (text->point.index + 1 <= TEXT_LENGTH (text))
3955 gtk_editable_delete_text (editable, text->point.index, text->point.index + 1);
3959 if (text->point.index > 0)
3960 gtk_editable_delete_text (editable, text->point.index - 1, text->point.index);
3966 gtk_text_delete_forward_character (GtkText *text)
3968 gtk_text_kill_char (GTK_EDITABLE (text), 1);
3972 gtk_text_delete_backward_character (GtkText *text)
3974 gtk_text_kill_char (GTK_EDITABLE (text), -1);
3978 gtk_text_kill_word (GtkEditable *editable,
3981 if (editable->selection_start_pos != editable->selection_end_pos)
3982 gtk_editable_delete_selection (editable);
3985 gint old_pos = editable->current_pos;
3988 gtk_text_move_word (editable, 1);
3989 gtk_editable_delete_text (editable, old_pos, editable->current_pos);
3993 gtk_text_move_word (editable, -1);
3994 gtk_editable_delete_text (editable, editable->current_pos, old_pos);
4000 gtk_text_delete_forward_word (GtkText *text)
4002 gtk_text_kill_word (GTK_EDITABLE (text), 1);
4006 gtk_text_delete_backward_word (GtkText *text)
4008 gtk_text_kill_word (GTK_EDITABLE (text), -1);
4012 gtk_text_kill_line (GtkEditable *editable,
4015 gint old_pos = editable->current_pos;
4018 gtk_text_move_to_column (editable, -1);
4019 gtk_editable_delete_text (editable, old_pos, editable->current_pos);
4023 gtk_text_move_to_column (editable, 0);
4024 gtk_editable_delete_text (editable, editable->current_pos, old_pos);
4029 gtk_text_delete_line (GtkText *text)
4031 gtk_text_move_to_column (GTK_EDITABLE (text), 0);
4032 gtk_text_kill_line (GTK_EDITABLE (text), 1);
4036 gtk_text_delete_to_line_end (GtkText *text)
4038 gtk_text_kill_line (GTK_EDITABLE (text), 1);
4042 gtk_text_select_word (GtkText *text, guint32 time)
4047 GtkEditable *editable;
4048 editable = GTK_EDITABLE (text);
4050 gtk_text_move_backward_word (text);
4051 start_pos = text->cursor_mark.index;
4053 gtk_text_move_forward_word (text);
4054 end_pos = text->cursor_mark.index;
4056 editable->has_selection = TRUE;
4057 gtk_text_set_selection (editable, start_pos, end_pos);
4058 gtk_editable_claim_selection (editable, start_pos != end_pos, time);
4062 gtk_text_select_line (GtkText *text, guint32 time)
4067 GtkEditable *editable;
4068 editable = GTK_EDITABLE (text);
4070 gtk_text_move_beginning_of_line (text);
4071 start_pos = text->cursor_mark.index;
4073 gtk_text_move_end_of_line (text);
4074 gtk_text_move_forward_character (text);
4075 end_pos = text->cursor_mark.index;
4077 editable->has_selection = TRUE;
4078 gtk_text_set_selection (editable, start_pos, end_pos);
4079 gtk_editable_claim_selection (editable, start_pos != end_pos, time);
4082 /**********************************************************************/
4084 /**********************************************************************/
4087 adjust_adj (GtkText* text, GtkAdjustment* adj)
4091 gdk_window_get_size (text->text_area, NULL, &height);
4093 adj->step_increment = MIN (adj->upper, (float) SCROLL_PIXELS);
4094 adj->page_increment = MIN (adj->upper, height - (float) KEY_SCROLL_PIXELS);
4095 adj->page_size = MIN (adj->upper, height);
4096 adj->value = MIN (adj->value, adj->upper - adj->page_size);
4097 adj->value = MAX (adj->value, 0.0);
4099 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
4103 set_vertical_scroll_iterator (GtkText* text, LineParams* lp, void* data)
4105 SetVerticalScrollData *svdata = (SetVerticalScrollData *) data;
4107 if ((text->first_line_start_index >= lp->start.index) &&
4108 (text->first_line_start_index <= lp->end.index))
4110 svdata->mark = lp->start;
4112 if (text->first_line_start_index == lp->start.index)
4114 text->first_onscreen_ver_pixel = svdata->pixel_height + text->first_cut_pixels;
4118 text->first_onscreen_ver_pixel = svdata->pixel_height;
4119 text->first_cut_pixels = 0;
4122 text->vadj->value = (float) text->first_onscreen_ver_pixel;
4125 svdata->pixel_height += LINE_HEIGHT (*lp);
4131 set_vertical_scroll_find_iterator (GtkText* text, LineParams* lp, void* data)
4133 SetVerticalScrollData *svdata = (SetVerticalScrollData *) data;
4136 if (svdata->pixel_height <= (gint) text->vadj->value &&
4137 svdata->pixel_height + LINE_HEIGHT(*lp) > (gint) text->vadj->value)
4139 svdata->mark = lp->start;
4141 text->first_cut_pixels = (gint)text->vadj->value - svdata->pixel_height;
4142 text->first_onscreen_ver_pixel = svdata->pixel_height;
4143 text->first_line_start_index = lp->start.index;
4149 svdata->pixel_height += LINE_HEIGHT (*lp);
4157 static GtkPropertyMark
4158 set_vertical_scroll (GtkText* text)
4160 GtkPropertyMark mark = find_mark (text, 0);
4161 SetVerticalScrollData data;
4165 data.pixel_height = 0;
4166 line_params_iterate (text, &mark, NULL, FALSE, &data, set_vertical_scroll_iterator);
4168 text->vadj->upper = (float) data.pixel_height;
4169 orig_value = (gint) text->vadj->value;
4171 gdk_window_get_size (text->text_area, NULL, &height);
4173 text->vadj->step_increment = MIN (text->vadj->upper, (float) SCROLL_PIXELS);
4174 text->vadj->page_increment = MIN (text->vadj->upper, height - (float) KEY_SCROLL_PIXELS);
4175 text->vadj->page_size = MIN (text->vadj->upper, height);
4176 text->vadj->value = MIN (text->vadj->value, text->vadj->upper - text->vadj->page_size);
4177 text->vadj->value = MAX (text->vadj->value, 0.0);
4179 text->last_ver_value = (gint)text->vadj->value;
4181 gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "changed");
4183 if (text->vadj->value != orig_value)
4185 /* We got clipped, and don't really know which line to put first. */
4186 data.pixel_height = 0;
4187 data.last_didnt_wrap = TRUE;
4189 line_params_iterate (text, &mark, NULL,
4191 set_vertical_scroll_find_iterator);
4198 scroll_int (GtkText* text, gint diff)
4202 text->vadj->value += diff;
4204 upper = text->vadj->upper - text->vadj->page_size;
4205 text->vadj->value = MIN (text->vadj->value, upper);
4206 text->vadj->value = MAX (text->vadj->value, 0.0);
4208 gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "value_changed");
4212 process_exposes (GtkText *text)
4216 /* Make sure graphics expose events are processed before scrolling
4219 while ((event = gdk_event_get_graphics_expose (text->text_area)) != NULL)
4221 gtk_widget_event (GTK_WIDGET (text), event);
4222 if (event->expose.count == 0)
4224 gdk_event_free (event);
4227 gdk_event_free (event);
4231 static gint last_visible_line_height (GtkText* text)
4233 GList *cache = text->line_start_cache;
4236 gdk_window_get_size (text->text_area, NULL, &height);
4238 for (; cache->next; cache = cache->next)
4239 if (pixel_height_of(text, cache->next) > height)
4243 return pixel_height_of(text, cache) - 1;
4248 static gint first_visible_line_height (GtkText* text)
4250 if (text->first_cut_pixels)
4251 return pixel_height_of(text, text->line_start_cache) + 1;
4257 scroll_down (GtkText* text, gint diff0)
4263 text->first_onscreen_ver_pixel += diff0;
4267 g_assert (text->line_start_cache);
4269 if (text->first_cut_pixels < LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1)
4271 text->first_cut_pixels += 1;
4275 text->first_cut_pixels = 0;
4277 text->line_start_cache = text->line_start_cache->next;
4279 text->first_line_start_index =
4280 CACHE_DATA(text->line_start_cache).start.index;
4282 if (!text->line_start_cache->next)
4283 fetch_lines_forward (text, 1);
4289 gdk_window_get_size (text->text_area, &width, &height);
4290 if (height > real_diff)
4291 gdk_draw_pixmap (text->text_area,
4299 height - real_diff);
4302 rect.y = MAX (0, height - real_diff);
4304 rect.height = MIN (height, real_diff);
4306 expose_text (text, &rect, FALSE);
4307 gtk_text_draw_focus ( (GtkWidget *) text);
4309 if (text->current_line)
4313 text->cursor_pos_y -= real_diff;
4314 cursor_min = drawn_cursor_min(text);
4317 find_mouse_cursor (text, text->cursor_pos_x,
4318 first_visible_line_height (text));
4321 if (height > real_diff)
4322 process_exposes (text);
4326 scroll_up (GtkText* text, gint diff0)
4332 text->first_onscreen_ver_pixel += diff0;
4336 g_assert (text->line_start_cache);
4338 if (text->first_cut_pixels > 0)
4340 text->first_cut_pixels -= 1;
4344 if (!text->line_start_cache->prev)
4345 fetch_lines_backward (text);
4347 text->line_start_cache = text->line_start_cache->prev;
4349 text->first_line_start_index =
4350 CACHE_DATA(text->line_start_cache).start.index;
4352 text->first_cut_pixels = LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1;
4358 gdk_window_get_size (text->text_area, &width, &height);
4359 if (height > real_diff)
4360 gdk_draw_pixmap (text->text_area,
4368 height - real_diff);
4373 rect.height = MIN (height, real_diff);
4375 expose_text (text, &rect, FALSE);
4376 gtk_text_draw_focus ( (GtkWidget *) text);
4378 if (text->current_line)
4383 text->cursor_pos_y += real_diff;
4384 cursor_max = drawn_cursor_max(text);
4385 gdk_window_get_size (text->text_area, NULL, &height);
4387 if (cursor_max >= height)
4388 find_mouse_cursor (text, text->cursor_pos_x,
4389 last_visible_line_height (text));
4392 if (height > real_diff)
4393 process_exposes (text);
4396 /**********************************************************************/
4398 /**********************************************************************/
4400 /* Assumes mark starts a line. Calculates the height, width, and
4401 * displayable character count of a single DISPLAYABLE line. That
4402 * means that in line-wrap mode, this does may not compute the
4403 * properties of an entire line. */
4405 find_line_params (GtkText* text,
4406 const GtkPropertyMark* mark,
4407 const PrevTabCont *tab_cont,
4408 PrevTabCont *next_cont)
4411 TabStopMark tab_mark = tab_cont->tab_start;
4412 guint max_display_pixels;
4417 gdk_window_get_size (text->text_area, (gint*) &max_display_pixels, NULL);
4418 max_display_pixels -= LINE_WRAP_ROOM;
4421 lp.tab_cont = *tab_cont;
4424 lp.pixel_width = tab_cont->pixel_offset;
4425 lp.displayable_chars = 0;
4427 lp.font_descent = 0;
4429 init_tab_cont (text, next_cont);
4431 while (!LAST_INDEX(text, lp.end))
4433 g_assert (lp.end.property);
4435 ch = GTK_TEXT_INDEX (text, lp.end.index);
4436 font = MARK_CURRENT_FONT (text, &lp.end);
4438 if (ch == LINE_DELIM)
4440 /* Newline doesn't count in computation of line height, even
4441 * if its in a bigger font than the rest of the line. Unless,
4442 * of course, there are no other characters. */
4444 if (!lp.font_ascent && !lp.font_descent)
4446 lp.font_ascent = font->ascent;
4447 lp.font_descent = font->descent;
4450 lp.tab_cont_next = *next_cont;
4455 ch_width = find_char_width (text, &lp.end, &tab_mark);
4457 if ((ch_width + lp.pixel_width > max_display_pixels) &&
4458 (lp.end.index > lp.start.index))
4462 if (text->line_wrap)
4464 next_cont->tab_start = tab_mark;
4465 next_cont->pixel_offset = 0;
4469 /* Here's the tough case, a tab is wrapping. */
4470 gint pixels_avail = max_display_pixels - lp.pixel_width;
4471 gint space_width = MARK_CURRENT_TEXT_FONT(text, &lp.end)->char_widths[' '];
4472 gint spaces_avail = pixels_avail / space_width;
4474 if (spaces_avail == 0)
4476 decrement_mark (&lp.end);
4480 advance_tab_mark (text, &next_cont->tab_start, '\t');
4481 next_cont->pixel_offset = space_width * (tab_mark.to_next_tab -
4483 lp.displayable_chars += 1;
4488 if (text->word_wrap)
4490 GtkPropertyMark saved_mark = lp.end;
4491 guint saved_characters = lp.displayable_chars;
4493 lp.displayable_chars += 1;
4495 while (!isspace (GTK_TEXT_INDEX (text, lp.end.index)) &&
4496 (lp.end.index > lp.start.index))
4498 decrement_mark (&lp.end);
4499 lp.displayable_chars -= 1;
4502 /* If whole line is one word, revert to char wrapping */
4503 if (lp.end.index == lp.start.index)
4505 lp.end = saved_mark;
4506 lp.displayable_chars = saved_characters;
4507 decrement_mark (&lp.end);
4512 /* Don't include this character, it will wrap. */
4513 decrement_mark (&lp.end);
4517 lp.tab_cont_next = *next_cont;
4524 lp.displayable_chars += 1;
4527 lp.font_ascent = MAX (font->ascent, lp.font_ascent);
4528 lp.font_descent = MAX (font->descent, lp.font_descent);
4529 lp.pixel_width += ch_width;
4531 advance_mark(&lp.end);
4532 advance_tab_mark (text, &tab_mark, ch);
4535 if (LAST_INDEX(text, lp.start))
4537 /* Special case, empty last line. */
4538 font = MARK_CURRENT_FONT (text, &lp.end);
4540 lp.font_ascent = font->ascent;
4541 lp.font_descent = font->descent;
4544 lp.tab_cont_next = *next_cont;
4550 expand_scratch_buffer (GtkText* text, guint len)
4552 if (len >= text->scratch_buffer_len)
4556 while (i <= len && i < MIN_GAP_SIZE) i <<= 1;
4558 if (text->scratch_buffer)
4559 text->scratch_buffer = g_new (guchar, i);
4561 text->scratch_buffer = g_realloc (text->scratch_buffer, i);
4563 text->scratch_buffer_len = i;
4567 /* Side effect: modifies text->gc
4571 draw_bg_rect (GtkText* text, GtkPropertyMark *mark,
4572 gint x, gint y, gint width, gint height,
4573 gboolean already_cleared)
4575 GtkEditable *editable = GTK_EDITABLE(text);
4577 if ((mark->index >= MIN(editable->selection_start_pos, editable->selection_end_pos) &&
4578 mark->index < MAX(editable->selection_start_pos, editable->selection_end_pos)))
4580 gtk_paint_flat_box(GTK_WIDGET(text)->style, text->text_area,
4581 editable->has_selection ?
4582 GTK_STATE_SELECTED : GTK_STATE_ACTIVE,
4584 NULL, GTK_WIDGET(text), "text",
4585 x, y, width, height);
4587 else if (!gdk_color_equal(MARK_CURRENT_BACK (text, mark),
4588 >K_WIDGET(text)->style->base[GTK_STATE_NORMAL]))
4590 gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (text, mark));
4592 gdk_draw_rectangle (text->text_area,
4594 TRUE, x, y, width, height);
4596 else if (GTK_WIDGET (text)->style->bg_pixmap[GTK_STATE_NORMAL])
4603 rect.height = height;
4605 clear_area (text, &rect);
4607 else if (!already_cleared)
4608 gdk_window_clear_area (text->text_area, x, y, width, height);
4612 draw_line (GtkText* text,
4613 gint pixel_start_height,
4616 GdkGCValues gc_values;
4619 guint running_offset = lp->tab_cont.pixel_offset;
4623 GtkEditable *editable = GTK_EDITABLE(text);
4625 guint selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
4626 guint selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
4628 GtkPropertyMark mark = lp->start;
4629 TabStopMark tab_mark = lp->tab_cont.tab_start;
4630 gint pixel_height = pixel_start_height + lp->font_ascent;
4631 guint chars = lp->displayable_chars;
4633 /* First provide a contiguous segment of memory. This makes reading
4634 * the code below *much* easier, and only incurs the cost of copying
4635 * when the line being displayed spans the gap. */
4636 if (mark.index <= text->gap_position &&
4637 mark.index + chars > text->gap_position)
4639 expand_scratch_buffer (text, chars);
4641 for (i = 0; i < chars; i += 1)
4642 text->scratch_buffer[i] = GTK_TEXT_INDEX(text, mark.index + i);
4644 buffer = text->scratch_buffer;
4648 if (mark.index >= text->gap_position)
4649 buffer = text->text + mark.index + text->gap_size;
4651 buffer = text->text + mark.index;
4655 if (running_offset > 0)
4657 draw_bg_rect (text, &mark, 0, pixel_start_height, running_offset,
4658 LINE_HEIGHT (*lp), TRUE);
4661 for (; chars > 0; chars -= len, buffer += len, len = 0)
4663 if (buffer[0] != '\t')
4665 guchar* next_tab = memchr (buffer, '\t', chars);
4669 len = MIN (MARK_CURRENT_PROPERTY (&mark)->length - mark.offset, chars);
4672 len = MIN (len, next_tab - buffer);
4674 if (mark.index < selection_start_pos)
4675 len = MIN (len, selection_start_pos - mark.index);
4676 else if (mark.index < selection_end_pos)
4677 len = MIN (len, selection_end_pos - mark.index);
4679 font = MARK_CURRENT_FONT (text, &mark);
4680 if (font->type == GDK_FONT_FONT)
4682 gdk_gc_set_font (text->gc, font);
4683 gdk_gc_get_values (text->gc, &gc_values);
4684 pixel_width = gdk_text_width (gc_values.font,
4685 (gchar*) buffer, len);
4688 pixel_width = gdk_text_width (font, (gchar*) buffer, len);
4690 draw_bg_rect (text, &mark, running_offset, pixel_start_height,
4691 pixel_width, LINE_HEIGHT (*lp), TRUE);
4693 if ((mark.index >= selection_start_pos) &&
4694 (mark.index < selection_end_pos))
4696 if (editable->has_selection)
4697 fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_SELECTED];
4699 fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_ACTIVE];
4703 gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (text, &mark));
4707 gdk_draw_text (text->text_area, MARK_CURRENT_FONT (text, &mark),
4714 running_offset += pixel_width;
4716 advance_tab_mark_n (text, &tab_mark, len);
4720 gint pixels_remaining;
4726 gdk_window_get_size (text->text_area, &pixels_remaining, NULL);
4727 pixels_remaining -= (LINE_WRAP_ROOM + running_offset);
4729 space_width = MARK_CURRENT_TEXT_FONT(text, &mark)->char_widths[' '];
4731 spaces_avail = pixels_remaining / space_width;
4732 spaces_avail = MIN (spaces_avail, tab_mark.to_next_tab);
4734 draw_bg_rect (text, &mark, running_offset, pixel_start_height,
4735 spaces_avail * space_width, LINE_HEIGHT (*lp), TRUE);
4737 running_offset += tab_mark.to_next_tab *
4738 MARK_CURRENT_TEXT_FONT(text, &mark)->char_widths[' '];
4740 advance_tab_mark (text, &tab_mark, '\t');
4743 advance_mark_n (&mark, len);
4748 draw_line_wrap (GtkText* text, guint height /* baseline height */)
4755 if (text->line_wrap)
4757 bitmap = text->line_wrap_bitmap;
4758 bitmap_width = line_wrap_width;
4759 bitmap_height = line_wrap_height;
4763 bitmap = text->line_arrow_bitmap;
4764 bitmap_width = line_arrow_width;
4765 bitmap_height = line_arrow_height;
4768 gdk_window_get_size (text->text_area, &width, NULL);
4769 width -= LINE_WRAP_ROOM;
4771 gdk_gc_set_stipple (text->gc,
4774 gdk_gc_set_fill (text->gc, GDK_STIPPLED);
4776 gdk_gc_set_foreground (text->gc, >K_WIDGET (text)->style->text[GTK_STATE_NORMAL]);
4778 gdk_gc_set_ts_origin (text->gc,
4780 height - bitmap_height - 1);
4782 gdk_draw_rectangle (text->text_area,
4786 height - bitmap_height - 1 /* one pixel above the baseline. */,
4790 gdk_gc_set_ts_origin (text->gc, 0, 0);
4792 gdk_gc_set_fill (text->gc, GDK_SOLID);
4796 undraw_cursor (GtkText* text, gint absolute)
4798 GtkEditable *editable = (GtkEditable *)text;
4800 TDEBUG (("in undraw_cursor\n"));
4803 text->cursor_drawn_level = 0;
4805 if ((text->cursor_drawn_level ++ == 0) &&
4806 (editable->selection_start_pos == editable->selection_end_pos) &&
4807 GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
4811 g_assert(text->cursor_mark.property);
4813 font = MARK_CURRENT_FONT(text, &text->cursor_mark);
4815 draw_bg_rect (text, &text->cursor_mark,
4817 text->cursor_pos_y - text->cursor_char_offset - font->ascent,
4818 1, font->ascent + 1, FALSE);
4820 if (text->cursor_char)
4822 if (font->type == GDK_FONT_FONT)
4823 gdk_gc_set_font (text->gc, font);
4825 gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (text, &text->cursor_mark));
4827 gdk_draw_text (text->text_area, font,
4830 text->cursor_pos_y - text->cursor_char_offset,
4838 drawn_cursor_min (GtkText* text)
4842 g_assert(text->cursor_mark.property);
4844 font = MARK_CURRENT_FONT(text, &text->cursor_mark);
4846 return text->cursor_pos_y - text->cursor_char_offset - font->ascent;
4850 drawn_cursor_max (GtkText* text)
4854 g_assert(text->cursor_mark.property);
4856 font = MARK_CURRENT_FONT(text, &text->cursor_mark);
4858 return text->cursor_pos_y - text->cursor_char_offset;
4862 draw_cursor (GtkText* text, gint absolute)
4864 GtkEditable *editable = (GtkEditable *)text;
4866 TDEBUG (("in draw_cursor\n"));
4869 text->cursor_drawn_level = 1;
4871 if ((--text->cursor_drawn_level == 0) &&
4872 editable->editable &&
4873 (editable->selection_start_pos == editable->selection_end_pos) &&
4874 GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
4878 g_assert (text->cursor_mark.property);
4880 font = MARK_CURRENT_FONT (text, &text->cursor_mark);
4882 gdk_gc_set_foreground (text->gc, >K_WIDGET (text)->style->text[GTK_STATE_NORMAL]);
4884 gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x,
4885 text->cursor_pos_y - text->cursor_char_offset,
4887 text->cursor_pos_y - text->cursor_char_offset - font->ascent);
4892 clear_area (GtkText *text, GdkRectangle *area)
4894 GtkWidget *widget = GTK_WIDGET (text);
4896 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
4899 gint x = area->x, y = area->y;
4902 gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height);
4904 yorig = - text->first_onscreen_ver_pixel;
4905 xorig = - text->first_onscreen_hor_pixel;
4907 for (y = area->y; y < area->y + area->height; )
4909 gint yoff = (y - yorig) % height;
4910 gint yw = MIN(height - yoff, (area->y + area->height) - y);
4912 for (x = area->x; x < area->x + area->width; )
4914 gint xoff = (x - xorig) % width;
4915 gint xw = MIN(width - xoff, (area->x + area->width) - x);
4917 gdk_draw_pixmap (text->text_area,
4919 widget->style->bg_pixmap[GTK_STATE_NORMAL],
4933 gdk_window_clear_area (text->text_area, area->x, area->y, area->width, area->height);
4937 expose_text (GtkText* text, GdkRectangle *area, gboolean cursor)
4939 GList *cache = text->line_start_cache;
4940 gint pixels = - text->first_cut_pixels;
4941 gint min_y = MAX (0, area->y);
4942 gint max_y = MAX (0, area->y + area->height);
4945 gdk_window_get_size (text->text_area, NULL, &height);
4946 max_y = MIN (max_y, height);
4948 TDEBUG (("in expose x=%d y=%d w=%d h=%d\n", area->x, area->y, area->width, area->height));
4950 clear_area (text, area);
4952 for (; pixels < height; cache = cache->next)
4954 if (pixels < max_y && (pixels + (gint)LINE_HEIGHT(CACHE_DATA(cache))) >= min_y)
4956 draw_line (text, pixels, &CACHE_DATA(cache));
4958 if (CACHE_DATA(cache).wraps)
4959 draw_line_wrap (text, pixels + CACHE_DATA(cache).font_ascent);
4962 if (cursor && GTK_WIDGET_HAS_FOCUS (text))
4964 if (CACHE_DATA(cache).start.index <= text->cursor_mark.index &&
4965 CACHE_DATA(cache).end.index >= text->cursor_mark.index)
4967 /* We undraw and draw the cursor here to get the drawn
4968 * level right ... FIXME - maybe the second parameter
4969 * of draw_cursor should work differently
4971 undraw_cursor (text, FALSE);
4972 draw_cursor (text, FALSE);
4976 pixels += LINE_HEIGHT(CACHE_DATA(cache));
4980 fetch_lines_forward (text, 1);
4989 gtk_text_update_text (GtkEditable *editable,
4993 GtkText *text = GTK_TEXT (editable);
4995 GList *cache = text->line_start_cache;
4996 gint pixels = - text->first_cut_pixels;
5002 end_pos = TEXT_LENGTH (text);
5004 if (end_pos < start_pos)
5007 gdk_window_get_size (text->text_area, &width, &height);
5013 TDEBUG (("in expose span start=%d stop=%d\n", start_pos, end_pos));
5015 for (; pixels < height; cache = cache->next)
5017 if (CACHE_DATA(cache).start.index < end_pos)
5019 if (CACHE_DATA(cache).end.index >= start_pos)
5022 area.y = MAX(0,pixels);
5023 area.height = pixels + LINE_HEIGHT(CACHE_DATA(cache)) - area.y;
5029 pixels += LINE_HEIGHT(CACHE_DATA(cache));
5033 fetch_lines_forward (text, 1);
5041 expose_text (text, &area, TRUE);
5045 recompute_geometry (GtkText* text)
5047 GtkPropertyMark mark, start_mark;
5054 mark = start_mark = set_vertical_scroll (text);
5056 /* We need a real start of a line when calling fetch_lines().
5057 * not the start of a wrapped line.
5059 while (mark.index > 0 &&
5060 GTK_TEXT_INDEX (text, mark.index - 1) != LINE_DELIM)
5061 decrement_mark (&mark);
5063 gdk_window_get_size (text->text_area, &width, &height);
5065 /* Fetch an entire line, to make sure that we get all the text
5066 * we backed over above, in addition to enough text to fill up
5067 * the space vertically
5070 new_lines = fetch_lines (text,
5076 mark = CACHE_DATA (g_list_last (new_lines)).end;
5077 if (!LAST_INDEX (text, mark))
5079 advance_mark (&mark);
5081 new_lines = g_list_concat (new_lines,
5086 height + text->first_cut_pixels));
5089 /* Now work forward to the actual first onscreen line */
5091 while (CACHE_DATA (new_lines).start.index < start_mark.index)
5092 new_lines = new_lines->next;
5094 text->line_start_cache = new_lines;
5096 find_cursor (text, TRUE);
5099 /**********************************************************************/
5101 /**********************************************************************/
5104 gtk_text_set_selection (GtkEditable *editable,
5108 GtkText *text = GTK_TEXT (editable);
5110 guint start1, end1, start2, end2;
5113 end = TEXT_LENGTH (text);
5115 start1 = MIN(start,end);
5116 end1 = MAX(start,end);
5117 start2 = MIN(editable->selection_start_pos, editable->selection_end_pos);
5118 end2 = MAX(editable->selection_start_pos, editable->selection_end_pos);
5120 if (start2 < start1)
5124 tmp = start1; start1 = start2; start2 = tmp;
5125 tmp = end1; end1 = end2; end2 = tmp;
5128 undraw_cursor (text, FALSE);
5129 editable->selection_start_pos = start;
5130 editable->selection_end_pos = end;
5131 draw_cursor (text, FALSE);
5133 /* Expose only what changed */
5135 if (start1 < start2)
5136 gtk_text_update_text (editable, start1, MIN(end1, start2));
5139 gtk_text_update_text (editable, MAX(end1, start2), end2);
5140 else if (end2 < end1)
5141 gtk_text_update_text (editable, end2, end1);
5145 /**********************************************************************/
5147 /**********************************************************************/
5149 #ifdef DEBUG_GTK_TEXT
5151 gtk_text_show_cache_line (GtkText *text, GList *cache,
5152 const char* what, const char* func, gint line)
5154 LineParams *lp = &CACHE_DATA(cache);
5157 if (cache == text->line_start_cache)
5158 g_message ("Line Start Cache: ");
5160 if (cache == text->current_line)
5161 g_message("Current Line: ");
5163 g_message ("%s:%d: cache line %s s=%d,e=%d,lh=%d (",
5171 for (i = lp->start.index; i < (lp->end.index + lp->wraps); i += 1)
5172 g_message ("%c", GTK_TEXT_INDEX (text, i));
5178 gtk_text_show_cache (GtkText *text, const char* func, gint line)
5180 GList *l = text->line_start_cache;
5186 /* back up to the absolute beginning of the line cache */
5190 g_message ("*** line cache ***\n");
5191 for (; l; l = l->next)
5192 gtk_text_show_cache_line (text, l, "all", func, line);
5196 gtk_text_assert_mark (GtkText *text,
5197 GtkPropertyMark *mark,
5198 GtkPropertyMark *before,
5199 GtkPropertyMark *after,
5204 GtkPropertyMark correct_mark = find_mark (text, mark->index);
5206 if (mark->offset != correct_mark.offset ||
5207 mark->property != correct_mark.property)
5208 g_warning ("incorrect %s text property marker in %s:%d, index %d -- bad!", where, msg, line, mark->index);
5212 gtk_text_assert (GtkText *text,
5216 GList* cache = text->line_start_cache;
5217 GtkPropertyMark* before_mark = NULL;
5218 GtkPropertyMark* after_mark = NULL;
5220 gtk_text_show_props (text, msg, line);
5222 for (; cache->prev; cache = cache->prev)
5225 g_message ("*** line markers ***\n");
5227 for (; cache; cache = cache->next)
5229 after_mark = &CACHE_DATA(cache).end;
5230 gtk_text_assert_mark (text, &CACHE_DATA(cache).start, before_mark, after_mark, msg, "start", line);
5231 before_mark = &CACHE_DATA(cache).start;
5234 after_mark = &CACHE_DATA(cache->next).start;
5238 gtk_text_assert_mark (text, &CACHE_DATA(cache).end, before_mark, after_mark, msg, "end", line);
5239 before_mark = &CACHE_DATA(cache).end;
5244 gtk_text_show_adj (GtkText *text,
5250 g_message ("*** adjustment ***\n");
5252 g_message ("%s:%d: %s adjustment l=%.1f u=%.1f v=%.1f si=%.1f pi=%.1f ps=%.1f\n",
5259 adj->step_increment,
5260 adj->page_increment,
5265 gtk_text_show_props (GtkText *text,
5269 GList* props = text->text_properties;
5272 g_message ("%s:%d: ", msg, line);
5274 for (; props; props = props->next)
5276 TextProperty *p = (TextProperty*)props->data;
5278 proplen += p->length;
5280 g_message ("[%d,%p,", p->length, p);
5281 if (p->flags & PROPERTY_FONT)
5282 g_message ("%p,", p->font);
5285 if (p->flags & PROPERTY_FOREGROUND)
5286 g_message ("%ld, ", p->fore_color.pixel);
5289 if (p->flags & PROPERTY_BACKGROUND)
5290 g_message ("%ld] ", p->back_color.pixel);
5297 if (proplen - 1 != TEXT_LENGTH(text))
5298 g_warning ("incorrect property list length in %s:%d -- bad!", msg, line);