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 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 * Modified by the Sylpheed Team and others 2001. Interesting
29 * parts are marked using comment block following this one.
30 * This modification is based on the GtkSText of GTK 1.2.8
43 #include <gdk/gdkkeysyms.h>
44 #include <gdk/gdki18n.h>
45 #include <gtk/gtkmain.h>
46 #include <gtk/gtkselection.h>
47 #include <gtk/gtksignal.h>
51 * compile time settings
53 #define INITIAL_BUFFER_SIZE 1024
54 #define INITIAL_LINE_CACHE_SIZE 256
55 #define MIN_GAP_SIZE 256
58 * intending to introduce a paragraph delimiter '\r' because
59 * '\r' are being stripped by sylpheed
61 #define LINE_DELIM '\n'
62 #define MIN_TEXT_WIDTH_LINES 20
63 #define MIN_TEXT_HEIGHT_LINES 10
64 #define TEXT_BORDER_ROOM 1
65 #define LINE_WRAP_ROOM 8 /* The bitmaps are 6 wide. */
66 #define DEFAULT_TAB_STOP_WIDTH 4
67 #define SCROLL_PIXELS 5
68 #define KEY_SCROLL_PIXELS 10
69 #define SCROLL_TIME 100
70 #define FREEZE_LENGTH 1024
73 /* Freeze text when inserting or deleting more than this many characters */
76 * could also mark paragraphs using marks, but don't know anything yet
77 * about consistency when characters are removed
79 #define SET_PROPERTY_MARK(m, p, o) do { \
80 (m)->property = (p); \
83 #define MARK_CURRENT_PROPERTY(mark) ((TextProperty*)(mark)->property->data)
84 #define MARK_NEXT_PROPERTY(mark) ((TextProperty*)(mark)->property->next->data)
85 #define MARK_PREV_PROPERTY(mark) ((TextProperty*)((mark)->property->prev ? \
86 (mark)->property->prev->data \
88 #define MARK_PREV_LIST_PTR(mark) ((mark)->property->prev)
89 #define MARK_LIST_PTR(mark) ((mark)->property)
90 #define MARK_NEXT_LIST_PTR(mark) ((mark)->property->next)
91 #define MARK_OFFSET(mark) ((mark)->offset)
92 #define MARK_PROPERTY_LENGTH(mark) (MARK_CURRENT_PROPERTY(mark)->length)
95 #define MARK_CURRENT_FONT(text, mark) \
96 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
97 MARK_CURRENT_PROPERTY(mark)->font->gdk_font : \
98 GTK_WIDGET (text)->style->font)
99 #define MARK_CURRENT_FORE(text, mark) \
100 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FOREGROUND) ? \
101 &MARK_CURRENT_PROPERTY(mark)->fore_color : \
102 &((GtkWidget *)text)->style->text[((GtkWidget *)text)->state])
103 #define MARK_CURRENT_BACK(text, mark) \
104 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_BACKGROUND) ? \
105 &MARK_CURRENT_PROPERTY(mark)->back_color : \
106 &((GtkWidget *)text)->style->base[((GtkWidget *)text)->state])
107 #define MARK_CURRENT_TEXT_FONT(text, mark) \
108 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
109 MARK_CURRENT_PROPERTY(mark)->font : \
112 #define TEXT_LENGTH(t) ((t)->text_end - (t)->gap_size)
113 #define FONT_HEIGHT(f) ((f)->ascent + (f)->descent)
114 #define LINE_HEIGHT(l) ((l).font_ascent + (l).font_descent)
115 #define LINE_CONTAINS(l, i) ((l).start.index <= (i) && (l).end.index >= (i))
116 #define LINE_STARTS_AT(l, i) ((l).start.index == (i))
117 #define LINE_START_PIXEL(l) ((l).tab_cont.pixel_offset)
118 #define LAST_INDEX(t, m) ((m).index == TEXT_LENGTH(t))
119 #define CACHE_DATA(c) (*(LineParams*)(c)->data)
129 typedef struct _TextProperty TextProperty
;
130 typedef struct _TabStopMark TabStopMark
;
131 typedef struct _PrevTabCont PrevTabCont
;
132 typedef struct _FetchLinesData FetchLinesData
;
133 typedef struct _LineParams LineParams
;
134 typedef struct _SetVerticalScrollData SetVerticalScrollData
;
139 typedef gint (*LineIteratorFunction
) (GtkSText
* text
, LineParams
* lp
, void* data
);
147 struct _SetVerticalScrollData
{
149 gint last_didnt_wrap
;
150 gint last_line_start
;
151 GtkSPropertyMark mark
;
156 /* The actual font. */
160 gint16 char_widths
[256];
164 PROPERTY_FONT
= 1 << 0,
165 PROPERTY_FOREGROUND
= 1 << 1,
166 PROPERTY_BACKGROUND
= 1 << 2
174 /* Background Color. */
177 /* Foreground Color. */
180 /* Show which properties are set */
181 TextPropertyFlags flags
;
183 /* Length of this property. */
189 GList
* tab_stops
; /* Index into list containing the next tab position. If
190 * NULL, using default widths. */
197 TabStopMark tab_start
;
200 struct _FetchLinesData
213 guint displayable_chars
;
216 PrevTabCont tab_cont
;
217 PrevTabCont tab_cont_next
;
219 GtkSPropertyMark start
;
220 GtkSPropertyMark end
;
224 static void gtk_stext_class_init (GtkSTextClass
*klass
);
225 static void gtk_stext_set_arg (GtkObject
*object
,
228 static void gtk_stext_get_arg (GtkObject
*object
,
231 static void gtk_stext_init (GtkSText
*text
);
232 static void gtk_stext_destroy (GtkObject
*object
);
233 static void gtk_stext_finalize (GtkObject
*object
);
234 static void gtk_stext_realize (GtkWidget
*widget
);
235 static void gtk_stext_unrealize (GtkWidget
*widget
);
236 static void gtk_stext_style_set (GtkWidget
*widget
,
237 GtkStyle
*previous_style
);
238 static void gtk_stext_state_changed (GtkWidget
*widget
,
239 GtkStateType previous_state
);
240 static void gtk_stext_draw_focus (GtkWidget
*widget
);
241 static void gtk_stext_size_request (GtkWidget
*widget
,
242 GtkRequisition
*requisition
);
243 static void gtk_stext_size_allocate (GtkWidget
*widget
,
244 GtkAllocation
*allocation
);
245 static void gtk_stext_adjustment (GtkAdjustment
*adjustment
,
247 static void gtk_stext_disconnect (GtkAdjustment
*adjustment
,
250 static void gtk_stext_insert_text (GtkEditable
*editable
,
251 const gchar
*new_text
,
252 gint new_text_length
,
254 static void gtk_stext_delete_text (GtkEditable
*editable
,
257 static void gtk_stext_update_text (GtkEditable
*editable
,
260 static gchar
*gtk_stext_get_chars (GtkEditable
*editable
,
263 static void gtk_stext_set_selection (GtkEditable
*editable
,
266 static void gtk_stext_real_set_editable (GtkEditable
*editable
,
267 gboolean is_editable
);
270 static void gtk_stext_draw (GtkWidget
*widget
,
272 static gint
gtk_stext_expose (GtkWidget
*widget
,
273 GdkEventExpose
*event
);
274 static gint
gtk_stext_button_press (GtkWidget
*widget
,
275 GdkEventButton
*event
);
276 static gint
gtk_stext_button_release (GtkWidget
*widget
,
277 GdkEventButton
*event
);
278 static gint
gtk_stext_motion_notify (GtkWidget
*widget
,
279 GdkEventMotion
*event
);
280 static gint
gtk_stext_key_press (GtkWidget
*widget
,
282 static gint
gtk_stext_focus_in (GtkWidget
*widget
,
283 GdkEventFocus
*event
);
284 static gint
gtk_stext_focus_out (GtkWidget
*widget
,
285 GdkEventFocus
*event
);
287 static void move_gap (GtkSText
* text
, guint index
);
288 static void make_forward_space (GtkSText
* text
, guint len
);
290 /* Property management */
291 static GtkSTextFont
* get_text_font (GdkFont
* gfont
);
292 static void text_font_unref (GtkSTextFont
*text_font
);
294 static void insert_text_property (GtkSText
* text
, GdkFont
* font
,
295 GdkColor
*fore
, GdkColor
* back
, guint len
);
296 static TextProperty
* new_text_property (GtkSText
*text
, GdkFont
* font
,
297 GdkColor
* fore
, GdkColor
* back
, guint length
);
298 static void destroy_text_property (TextProperty
*prop
);
299 static void init_properties (GtkSText
*text
);
300 static void realize_property (GtkSText
*text
, TextProperty
*prop
);
301 static void realize_properties (GtkSText
*text
);
302 static void unrealize_property (GtkSText
*text
, TextProperty
*prop
);
303 static void unrealize_properties (GtkSText
*text
);
305 static void delete_text_property (GtkSText
* text
, guint len
);
307 static guint
pixel_height_of (GtkSText
* text
, GList
* cache_line
);
309 /* Property Movement and Size Computations */
310 static void advance_mark (GtkSPropertyMark
* mark
);
311 static void decrement_mark (GtkSPropertyMark
* mark
);
312 static void advance_mark_n (GtkSPropertyMark
* mark
, gint n
);
313 static void decrement_mark_n (GtkSPropertyMark
* mark
, gint n
);
314 static void move_mark_n (GtkSPropertyMark
* mark
, gint n
);
315 static GtkSPropertyMark
find_mark (GtkSText
* text
, guint mark_position
);
316 static GtkSPropertyMark
find_mark_near (GtkSText
* text
, guint mark_position
, const GtkSPropertyMark
* near
);
317 static void find_line_containing_point (GtkSText
* text
, guint point
,
321 static void compute_lines_pixels (GtkSText
* text
, guint char_count
,
322 guint
*lines
, guint
*pixels
);
324 static gint
total_line_height (GtkSText
* text
,
327 static LineParams
find_line_params (GtkSText
* text
,
328 const GtkSPropertyMark
*mark
,
329 const PrevTabCont
*tab_cont
,
330 PrevTabCont
*next_cont
);
331 static void recompute_geometry (GtkSText
* text
);
332 static void insert_expose (GtkSText
* text
, guint old_pixels
, gint nchars
, guint new_line_count
);
333 static void delete_expose (GtkSText
* text
,
337 static GdkGC
*create_bg_gc (GtkSText
*text
);
338 static void clear_area (GtkSText
*text
, GdkRectangle
*area
);
339 static void draw_line (GtkSText
* text
,
342 static void draw_line_wrap (GtkSText
* text
,
344 static void draw_cursor (GtkSText
* text
, gint absolute
);
345 static void undraw_cursor (GtkSText
* text
, gint absolute
);
346 static gint
drawn_cursor_min (GtkSText
* text
);
347 static gint
drawn_cursor_max (GtkSText
* text
);
348 static void expose_text (GtkSText
* text
, GdkRectangle
*area
, gboolean cursor
);
350 /* Search and Placement. */
351 static void find_cursor (GtkSText
* text
,
353 static void find_cursor_at_line (GtkSText
* text
,
354 const LineParams
* start_line
,
356 static void find_mouse_cursor (GtkSText
* text
, gint x
, gint y
);
359 static void adjust_adj (GtkSText
* text
, GtkAdjustment
* adj
);
360 static void scroll_up (GtkSText
* text
, gint diff
);
361 static void scroll_down (GtkSText
* text
, gint diff
);
362 static void scroll_int (GtkSText
* text
, gint diff
);
364 static void process_exposes (GtkSText
*text
);
366 /* Cache Management. */
367 static void free_cache (GtkSText
* text
);
368 static GList
* remove_cache_line (GtkSText
* text
, GList
* list
);
371 static void move_cursor_buffer_ver (GtkSText
*text
, int dir
);
372 static void move_cursor_page_ver (GtkSText
*text
, int dir
);
373 static void move_cursor_ver (GtkSText
*text
, int count
);
374 static void move_cursor_hor (GtkSText
*text
, int count
);
378 static void move_cursor_to_display_row_end (GtkSText
*text
);
379 static void move_cursor_to_display_row_start (GtkSText
*text
);
380 static void move_cursor_to_display_row_up (GtkSText
*text
);
381 static void move_cursor_to_display_row_down (GtkSText
*text
);
382 static void reset_persist_col_pos (GtkSText
*text
);
384 /* Binding actions */
385 static void gtk_stext_move_cursor (GtkEditable
*editable
,
388 static void gtk_stext_move_word (GtkEditable
*editable
,
390 static void gtk_stext_move_page (GtkEditable
*editable
,
393 static void gtk_stext_move_to_row (GtkEditable
*editable
,
395 static void gtk_stext_move_to_column (GtkEditable
*editable
,
397 static void gtk_stext_kill_char (GtkEditable
*editable
,
399 static void gtk_stext_kill_word (GtkEditable
*editable
,
401 static void gtk_stext_kill_line (GtkEditable
*editable
,
405 static void gtk_stext_move_forward_character (GtkSText
*text
);
406 static void gtk_stext_move_backward_character (GtkSText
*text
);
407 static void gtk_stext_move_forward_word (GtkSText
*text
);
408 static void gtk_stext_move_backward_word (GtkSText
*text
);
409 static void gtk_stext_move_beginning_of_line (GtkSText
*text
);
410 static void gtk_stext_move_end_of_line (GtkSText
*text
);
411 static void gtk_stext_move_next_line (GtkSText
*text
);
412 static void gtk_stext_move_previous_line (GtkSText
*text
);
414 static void gtk_stext_delete_forward_character (GtkSText
*text
);
415 static void gtk_stext_delete_backward_character (GtkSText
*text
);
416 static void gtk_stext_delete_forward_word (GtkSText
*text
);
417 static void gtk_stext_delete_backward_word (GtkSText
*text
);
418 static void gtk_stext_delete_line (GtkSText
*text
);
419 static void gtk_stext_delete_to_line_end (GtkSText
*text
);
420 static void gtk_stext_select_word (GtkSText
*text
,
422 static void gtk_stext_select_line (GtkSText
*text
,
425 static void gtk_stext_set_position (GtkEditable
*editable
,
432 static void gtk_stext_enable_blink (GtkSText
*text
);
433 static void gtk_stext_disable_blink (GtkSText
*text
);
435 /* #define DEBUG_GTK_STEXT */
437 #if defined(DEBUG_GTK_STEXT) && defined(__GNUC__)
438 /* Debugging utilities. */
439 static void gtk_stext_assert_mark (GtkSText
*text
,
440 GtkSPropertyMark
*mark
,
441 GtkSPropertyMark
*before
,
442 GtkSPropertyMark
*after
,
447 static void gtk_stext_assert (GtkSText
*text
,
450 static void gtk_stext_show_cache_line (GtkSText
*text
, GList
*cache
,
451 const char* what
, const char* func
, gint line
);
452 static void gtk_stext_show_cache (GtkSText
*text
, const char* func
, gint line
);
453 static void gtk_stext_show_adj (GtkSText
*text
,
458 static void gtk_stext_show_props (GtkSText
* test
,
462 #define TDEBUG(args) g_message args
463 #define TEXT_ASSERT(text) gtk_stext_assert (text,__PRETTY_FUNCTION__,__LINE__)
464 #define TEXT_ASSERT_MARK(text,mark,msg) gtk_stext_assert_mark (text,mark, \
465 __PRETTY_FUNCTION__,msg,__LINE__)
466 #define TEXT_SHOW(text) gtk_stext_show_cache (text, __PRETTY_FUNCTION__,__LINE__)
467 #define TEXT_SHOW_LINE(text,line,msg) gtk_stext_show_cache_line (text,line,msg,\
468 __PRETTY_FUNCTION__,__LINE__)
469 #define TEXT_SHOW_ADJ(text,adj,msg) gtk_stext_show_adj (text,adj,msg, \
470 __PRETTY_FUNCTION__,__LINE__)
473 #define TEXT_ASSERT(text)
474 #define TEXT_ASSERT_MARK(text,mark,msg)
475 #define TEXT_SHOW(text)
476 #define TEXT_SHOW_LINE(text,line,msg)
477 #define TEXT_SHOW_ADJ(text,adj,msg)
481 #if defined(AHX_DEBUG)
482 # define XDEBUG(args) g_message args
484 # define XDEBUG(args)
485 #endif /* AHX_DEBUG */
487 /* Memory Management. */
488 static GMemChunk
*params_mem_chunk
= NULL
;
489 static GMemChunk
*text_property_chunk
= NULL
;
491 static GtkWidgetClass
*parent_class
= NULL
;
494 static const GtkTextFunction control_keys
[26] =
496 (GtkTextFunction
)gtk_stext_move_beginning_of_line
, /* a */
497 (GtkTextFunction
)gtk_stext_move_backward_character
, /* b */
498 (GtkTextFunction
)gtk_editable_copy_clipboard
, /* c */
499 (GtkTextFunction
)gtk_stext_delete_forward_character
, /* d */
500 (GtkTextFunction
)gtk_stext_move_end_of_line
, /* e */
501 (GtkTextFunction
)gtk_stext_move_forward_character
, /* f */
503 (GtkTextFunction
)gtk_stext_delete_backward_character
, /* h */
506 (GtkTextFunction
)gtk_stext_delete_to_line_end
, /* k */
509 (GtkTextFunction
)gtk_stext_move_next_line
, /* n */
511 (GtkTextFunction
)gtk_stext_move_previous_line
, /* p */
516 (GtkTextFunction
)gtk_stext_delete_line
, /* u */
517 (GtkTextFunction
)gtk_editable_paste_clipboard
, /* v */
518 (GtkTextFunction
)gtk_stext_delete_backward_word
, /* w */
519 (GtkTextFunction
)gtk_editable_cut_clipboard
, /* x */
524 static const GtkTextFunction alt_keys
[26] =
527 (GtkTextFunction
)gtk_stext_move_backward_word
, /* b */
529 (GtkTextFunction
)gtk_stext_delete_forward_word
, /* d */
531 (GtkTextFunction
)gtk_stext_move_forward_word
, /* f */
556 #define line_arrow_width 6
557 #define line_arrow_height 9
558 static unsigned char line_arrow_bits
[] = {
559 0x00, 0x00, 0x04, 0x0c, 0x18, 0x3f, 0x18, 0x0c, 0x04};
562 #define line_wrap_width 6
563 #define line_wrap_height 9
564 static unsigned char line_wrap_bits
[] = {
565 0x1e, 0x3e, 0x30, 0x30, 0x39, 0x1f, 0x0f, 0x0f, 0x1f, };
567 /**********************************************************************/
569 /**********************************************************************/
572 gtk_stext_get_type (void)
574 static GtkType text_type
= 0;
578 static const GtkTypeInfo text_info
=
582 sizeof (GtkSTextClass
),
583 (GtkClassInitFunc
) gtk_stext_class_init
,
584 (GtkObjectInitFunc
) gtk_stext_init
,
585 /* reserved_1 */ NULL
,
586 /* reserved_2 */ NULL
,
587 (GtkClassInitFunc
) NULL
,
590 text_type
= gtk_type_unique (GTK_TYPE_EDITABLE
, &text_info
);
597 gtk_stext_class_init (GtkSTextClass
*class)
599 GtkObjectClass
*object_class
;
600 GtkWidgetClass
*widget_class
;
601 GtkEditableClass
*editable_class
;
603 object_class
= (GtkObjectClass
*) class;
604 widget_class
= (GtkWidgetClass
*) class;
605 editable_class
= (GtkEditableClass
*) class;
606 parent_class
= gtk_type_class (GTK_TYPE_EDITABLE
);
608 gtk_object_add_arg_type ("GtkSText::hadjustment",
610 GTK_ARG_READWRITE
| GTK_ARG_CONSTRUCT
,
612 gtk_object_add_arg_type ("GtkSText::vadjustment",
614 GTK_ARG_READWRITE
| GTK_ARG_CONSTRUCT
,
616 gtk_object_add_arg_type ("GtkSText::line_wrap",
620 gtk_object_add_arg_type ("GtkSText::word_wrap",
625 object_class
->set_arg
= gtk_stext_set_arg
;
626 object_class
->get_arg
= gtk_stext_get_arg
;
627 object_class
->destroy
= gtk_stext_destroy
;
628 object_class
->finalize
= gtk_stext_finalize
;
630 widget_class
->realize
= gtk_stext_realize
;
631 widget_class
->unrealize
= gtk_stext_unrealize
;
632 widget_class
->style_set
= gtk_stext_style_set
;
633 widget_class
->state_changed
= gtk_stext_state_changed
;
634 widget_class
->draw_focus
= gtk_stext_draw_focus
;
635 widget_class
->size_request
= gtk_stext_size_request
;
636 widget_class
->size_allocate
= gtk_stext_size_allocate
;
637 widget_class
->draw
= gtk_stext_draw
;
638 widget_class
->expose_event
= gtk_stext_expose
;
639 widget_class
->button_press_event
= gtk_stext_button_press
;
640 widget_class
->button_release_event
= gtk_stext_button_release
;
641 widget_class
->motion_notify_event
= gtk_stext_motion_notify
;
642 widget_class
->key_press_event
= gtk_stext_key_press
;
643 widget_class
->focus_in_event
= gtk_stext_focus_in
;
644 widget_class
->focus_out_event
= gtk_stext_focus_out
;
646 widget_class
->set_scroll_adjustments_signal
=
647 gtk_signal_new ("set_scroll_adjustments",
650 GTK_SIGNAL_OFFSET (GtkSTextClass
, set_scroll_adjustments
),
651 gtk_marshal_NONE__POINTER_POINTER
,
652 GTK_TYPE_NONE
, 2, GTK_TYPE_ADJUSTMENT
, GTK_TYPE_ADJUSTMENT
);
654 editable_class
->set_editable
= gtk_stext_real_set_editable
;
655 editable_class
->insert_text
= gtk_stext_insert_text
;
656 editable_class
->delete_text
= gtk_stext_delete_text
;
658 editable_class
->move_cursor
= gtk_stext_move_cursor
;
659 editable_class
->move_word
= gtk_stext_move_word
;
660 editable_class
->move_page
= gtk_stext_move_page
;
661 editable_class
->move_to_row
= gtk_stext_move_to_row
;
662 editable_class
->move_to_column
= gtk_stext_move_to_column
;
664 editable_class
->kill_char
= gtk_stext_kill_char
;
665 editable_class
->kill_word
= gtk_stext_kill_word
;
666 editable_class
->kill_line
= gtk_stext_kill_line
;
668 editable_class
->update_text
= gtk_stext_update_text
;
669 editable_class
->get_chars
= gtk_stext_get_chars
;
670 editable_class
->set_selection
= gtk_stext_set_selection
;
671 editable_class
->set_position
= gtk_stext_set_position
;
673 class->set_scroll_adjustments
= gtk_stext_set_adjustments
;
677 gtk_stext_set_arg (GtkObject
*object
,
683 text
= GTK_STEXT (object
);
687 case ARG_HADJUSTMENT
:
688 gtk_stext_set_adjustments (text
,
689 GTK_VALUE_POINTER (*arg
),
692 case ARG_VADJUSTMENT
:
693 gtk_stext_set_adjustments (text
,
695 GTK_VALUE_POINTER (*arg
));
698 gtk_stext_set_line_wrap (text
, GTK_VALUE_BOOL (*arg
));
701 gtk_stext_set_word_wrap (text
, GTK_VALUE_BOOL (*arg
));
709 gtk_stext_get_arg (GtkObject
*object
,
715 text
= GTK_STEXT (object
);
719 case ARG_HADJUSTMENT
:
720 GTK_VALUE_POINTER (*arg
) = text
->hadj
;
722 case ARG_VADJUSTMENT
:
723 GTK_VALUE_POINTER (*arg
) = text
->vadj
;
726 GTK_VALUE_BOOL (*arg
) = text
->line_wrap
;
729 GTK_VALUE_BOOL (*arg
) = text
->word_wrap
;
732 arg
->type
= GTK_TYPE_INVALID
;
738 gtk_stext_init (GtkSText
*text
)
740 GTK_WIDGET_SET_FLAGS (text
, GTK_CAN_FOCUS
);
742 text
->text_area
= NULL
;
747 text
->line_wrap_bitmap
= NULL
;
748 text
->line_arrow_bitmap
= NULL
;
750 text
->use_wchar
= FALSE
;
751 text
->text
.ch
= g_new (guchar
, INITIAL_BUFFER_SIZE
);
752 text
->text_len
= INITIAL_BUFFER_SIZE
;
754 text
->scratch_buffer
.ch
= NULL
;
755 text
->scratch_buffer_len
= 0;
757 text
->freeze_count
= 0;
759 if (!params_mem_chunk
)
760 params_mem_chunk
= g_mem_chunk_new ("LineParams",
762 256 * sizeof (LineParams
),
765 text
->default_tab_width
= 4;
766 text
->tab_stops
= NULL
;
768 text
->tab_stops
= g_list_prepend (text
->tab_stops
, (void*)8);
769 text
->tab_stops
= g_list_prepend (text
->tab_stops
, (void*)8);
771 text
->line_start_cache
= NULL
;
772 text
->first_cut_pixels
= 0;
774 text
->line_wrap
= TRUE
;
775 text
->word_wrap
= FALSE
;
780 text
->current_font
= NULL
;
783 * timer for blinking cursor
785 text
->cursor_visible
= FALSE
; /* don't know whether gtktext stores this somewhere */
786 text
->cursor_timer_on
= TRUE
;
787 text
->cursor_off_ms
= 500;
788 text
->cursor_on_ms
= 500;
789 text
->cursor_timer_id
= 0;
790 text
->cursor_idle_time_timer_id
= 0;
791 text
->wrap_rmargin
= 0;
792 text
->cursor_type
= STEXT_CURSOR_LINE
;
793 text
->persist_column
= 0;
795 init_properties (text
);
797 GTK_EDITABLE (text
)->editable
= FALSE
;
799 gtk_editable_set_position (GTK_EDITABLE (text
), 0);
803 gtk_stext_new (GtkAdjustment
*hadj
,
809 g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadj
), NULL
);
811 g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadj
), NULL
);
813 text
= gtk_widget_new (GTK_TYPE_STEXT
,
822 gtk_stext_set_word_wrap (GtkSText
*text
,
825 g_return_if_fail (text
!= NULL
);
826 g_return_if_fail (GTK_IS_STEXT (text
));
828 text
->word_wrap
= (word_wrap
!= FALSE
);
830 if (GTK_WIDGET_REALIZED (text
))
832 recompute_geometry (text
);
833 gtk_widget_queue_draw (GTK_WIDGET (text
));
838 gtk_stext_set_line_wrap (GtkSText
*text
,
841 g_return_if_fail (text
!= NULL
);
842 g_return_if_fail (GTK_IS_STEXT (text
));
844 text
->line_wrap
= (line_wrap
!= FALSE
);
846 if (GTK_WIDGET_REALIZED (text
))
848 recompute_geometry (text
);
849 gtk_widget_queue_draw (GTK_WIDGET (text
));
854 gtk_stext_set_editable (GtkSText
*text
,
855 gboolean is_editable
)
857 g_return_if_fail (text
!= NULL
);
858 g_return_if_fail (GTK_IS_STEXT (text
));
860 gtk_editable_set_editable (GTK_EDITABLE (text
), is_editable
);
864 gtk_stext_real_set_editable (GtkEditable
*editable
,
865 gboolean is_editable
)
869 g_return_if_fail (editable
!= NULL
);
870 g_return_if_fail (GTK_IS_STEXT (editable
));
872 text
= GTK_STEXT (editable
);
874 editable
->editable
= (is_editable
!= FALSE
);
876 if (GTK_WIDGET_REALIZED (text
))
878 recompute_geometry (text
);
879 gtk_widget_queue_draw (GTK_WIDGET (text
));
884 gtk_stext_set_adjustments (GtkSText
*text
,
888 g_return_if_fail (text
!= NULL
);
889 g_return_if_fail (GTK_IS_STEXT (text
));
891 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj
));
893 hadj
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
895 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj
));
897 vadj
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
899 if (text
->hadj
&& (text
->hadj
!= hadj
))
901 gtk_signal_disconnect_by_data (GTK_OBJECT (text
->hadj
), text
);
902 gtk_object_unref (GTK_OBJECT (text
->hadj
));
905 if (text
->vadj
&& (text
->vadj
!= vadj
))
907 gtk_signal_disconnect_by_data (GTK_OBJECT (text
->vadj
), text
);
908 gtk_object_unref (GTK_OBJECT (text
->vadj
));
911 if (text
->hadj
!= hadj
)
914 gtk_object_ref (GTK_OBJECT (text
->hadj
));
915 gtk_object_sink (GTK_OBJECT (text
->hadj
));
917 gtk_signal_connect (GTK_OBJECT (text
->hadj
), "changed",
918 (GtkSignalFunc
) gtk_stext_adjustment
,
920 gtk_signal_connect (GTK_OBJECT (text
->hadj
), "value_changed",
921 (GtkSignalFunc
) gtk_stext_adjustment
,
923 gtk_signal_connect (GTK_OBJECT (text
->hadj
), "disconnect",
924 (GtkSignalFunc
) gtk_stext_disconnect
,
926 gtk_stext_adjustment (hadj
, text
);
929 if (text
->vadj
!= vadj
)
932 gtk_object_ref (GTK_OBJECT (text
->vadj
));
933 gtk_object_sink (GTK_OBJECT (text
->vadj
));
935 gtk_signal_connect (GTK_OBJECT (text
->vadj
), "changed",
936 (GtkSignalFunc
) gtk_stext_adjustment
,
938 gtk_signal_connect (GTK_OBJECT (text
->vadj
), "value_changed",
939 (GtkSignalFunc
) gtk_stext_adjustment
,
941 gtk_signal_connect (GTK_OBJECT (text
->vadj
), "disconnect",
942 (GtkSignalFunc
) gtk_stext_disconnect
,
944 gtk_stext_adjustment (vadj
, text
);
949 gtk_stext_set_point (GtkSText
*text
,
952 g_return_if_fail (text
!= NULL
);
953 g_return_if_fail (GTK_IS_STEXT (text
));
954 g_return_if_fail (index
<= TEXT_LENGTH (text
));
956 text
->point
= find_mark (text
, index
);
960 gtk_stext_get_point (GtkSText
*text
)
962 g_return_val_if_fail (text
!= NULL
, 0);
963 g_return_val_if_fail (GTK_IS_STEXT (text
), 0);
965 return text
->point
.index
;
969 gtk_stext_get_length (GtkSText
*text
)
971 g_return_val_if_fail (text
!= NULL
, 0);
972 g_return_val_if_fail (GTK_IS_STEXT (text
), 0);
974 return TEXT_LENGTH (text
);
978 gtk_stext_freeze (GtkSText
*text
)
980 g_return_if_fail (text
!= NULL
);
981 g_return_if_fail (GTK_IS_STEXT (text
));
983 text
->freeze_count
++;
984 undraw_cursor (text
, FALSE
);
988 gtk_stext_thaw (GtkSText
*text
)
990 g_return_if_fail (text
!= NULL
);
991 g_return_if_fail (GTK_IS_STEXT (text
));
993 if (text
->freeze_count
)
994 if (!(--text
->freeze_count
) && GTK_WIDGET_REALIZED (text
))
996 recompute_geometry (text
);
997 gtk_widget_queue_draw (GTK_WIDGET (text
));
999 draw_cursor (text
, FALSE
);
1003 gtk_stext_insert (GtkSText
*text
,
1010 GtkEditable
*editable
= GTK_EDITABLE (text
);
1011 gboolean frozen
= FALSE
;
1013 gint new_line_count
= 1;
1014 guint old_height
= 0;
1019 g_return_if_fail (text
!= NULL
);
1020 g_return_if_fail (GTK_IS_STEXT (text
));
1022 g_return_if_fail (chars
!= NULL
);
1025 if (!nchars
|| !chars
)
1027 nchars
= strlen (chars
);
1031 if (!text
->freeze_count
&& (length
> FREEZE_LENGTH
))
1033 gtk_stext_freeze (text
);
1037 if (!text
->freeze_count
&& (text
->line_start_cache
!= NULL
))
1039 find_line_containing_point (text
, text
->point
.index
, TRUE
);
1040 old_height
= total_line_height (text
, text
->current_line
, 1);
1043 if ((TEXT_LENGTH (text
) == 0) && (text
->use_wchar
== FALSE
))
1046 widget
= GTK_WIDGET (text
);
1047 gtk_widget_ensure_style (widget
);
1048 if ((widget
->style
) && (widget
->style
->font
->type
== GDK_FONT_FONTSET
))
1050 text
->use_wchar
= TRUE
;
1051 g_free (text
->text
.ch
);
1052 text
->text
.wc
= g_new (GdkWChar
, INITIAL_BUFFER_SIZE
);
1053 text
->text_len
= INITIAL_BUFFER_SIZE
;
1054 if (text
->scratch_buffer
.ch
)
1055 g_free (text
->scratch_buffer
.ch
);
1056 text
->scratch_buffer
.wc
= NULL
;
1057 text
->scratch_buffer_len
= 0;
1061 move_gap (text
, text
->point
.index
);
1062 make_forward_space (text
, length
);
1064 if (text
->use_wchar
)
1066 char *chars_nt
= (char *)chars
;
1069 chars_nt
= g_new (char, length
+1);
1070 memcpy (chars_nt
, chars
, length
);
1071 chars_nt
[length
] = 0;
1073 numwcs
= gdk_mbstowcs (text
->text
.wc
+ text
->gap_position
, chars_nt
,
1075 if (chars_nt
!= chars
)
1083 memcpy(text
->text
.ch
+ text
->gap_position
, chars
, length
);
1086 if (!text
->freeze_count
&& (text
->line_start_cache
!= NULL
))
1088 if (text
->use_wchar
)
1090 for (i
=0; i
<numwcs
; i
++)
1091 if (text
->text
.wc
[text
->gap_position
+ i
] == '\n')
1096 for (i
=0; i
<numwcs
; i
++)
1097 if (text
->text
.ch
[text
->gap_position
+ i
] == '\n')
1104 insert_text_property (text
, font
, fore
, back
, numwcs
);
1106 text
->gap_size
-= numwcs
;
1107 text
->gap_position
+= numwcs
;
1109 if (text
->point
.index
< text
->first_line_start_index
)
1110 text
->first_line_start_index
+= numwcs
;
1111 if (text
->point
.index
< editable
->selection_start_pos
)
1112 editable
->selection_start_pos
+= numwcs
;
1113 if (text
->point
.index
< editable
->selection_end_pos
)
1114 editable
->selection_end_pos
+= numwcs
;
1115 /* We'll reset the cursor later anyways if we aren't frozen */
1116 if (text
->point
.index
< text
->cursor_mark
.index
)
1117 text
->cursor_mark
.index
+= numwcs
;
1119 advance_mark_n (&text
->point
, numwcs
);
1121 if (!text
->freeze_count
&& (text
->line_start_cache
!= NULL
))
1122 insert_expose (text
, old_height
, numwcs
, new_line_count
);
1126 gtk_stext_thaw (text
);
1130 gtk_stext_backward_delete (GtkSText
*text
,
1133 g_return_val_if_fail (text
!= NULL
, 0);
1134 g_return_val_if_fail (GTK_IS_STEXT (text
), 0);
1136 if (nchars
> text
->point
.index
|| nchars
<= 0)
1139 gtk_stext_set_point (text
, text
->point
.index
- nchars
);
1141 return gtk_stext_forward_delete (text
, nchars
);
1145 gtk_stext_forward_delete (GtkSText
*text
,
1148 guint old_lines
, old_height
;
1149 GtkEditable
*editable
= GTK_EDITABLE (text
);
1150 gboolean frozen
= FALSE
;
1152 g_return_val_if_fail (text
!= NULL
, 0);
1153 g_return_val_if_fail (GTK_IS_STEXT (text
), 0);
1155 if (text
->point
.index
+ nchars
> TEXT_LENGTH (text
) || nchars
<= 0)
1158 if (!text
->freeze_count
&& nchars
> FREEZE_LENGTH
)
1160 gtk_stext_freeze (text
);
1164 if (!text
->freeze_count
&& text
->line_start_cache
!= NULL
)
1166 /* We need to undraw the cursor here, since we may later
1167 * delete the cursor's property
1169 undraw_cursor (text
, FALSE
);
1170 find_line_containing_point (text
, text
->point
.index
, TRUE
);
1171 compute_lines_pixels (text
, nchars
, &old_lines
, &old_height
);
1174 /* FIXME, or resizing after deleting will be odd */
1175 if (text
->point
.index
< text
->first_line_start_index
)
1177 if (text
->point
.index
+ nchars
>= text
->first_line_start_index
)
1179 text
->first_line_start_index
= text
->point
.index
;
1180 while ((text
->first_line_start_index
> 0) &&
1181 (GTK_STEXT_INDEX (text
, text
->first_line_start_index
- 1)
1183 text
->first_line_start_index
-= 1;
1187 text
->first_line_start_index
-= nchars
;
1190 if (text
->point
.index
< editable
->selection_start_pos
)
1191 editable
->selection_start_pos
-=
1192 MIN(nchars
, editable
->selection_start_pos
- text
->point
.index
);
1193 if (text
->point
.index
< editable
->selection_end_pos
)
1194 editable
->selection_end_pos
-=
1195 MIN(nchars
, editable
->selection_end_pos
- text
->point
.index
);
1196 /* We'll reset the cursor later anyways if we aren't frozen */
1197 if (text
->point
.index
< text
->cursor_mark
.index
)
1198 move_mark_n (&text
->cursor_mark
,
1199 -MIN(nchars
, text
->cursor_mark
.index
- text
->point
.index
));
1201 move_gap (text
, text
->point
.index
);
1203 text
->gap_size
+= nchars
;
1205 delete_text_property (text
, nchars
);
1207 if (!text
->freeze_count
&& (text
->line_start_cache
!= NULL
))
1209 delete_expose (text
, nchars
, old_lines
, old_height
);
1210 draw_cursor (text
, FALSE
);
1214 gtk_stext_thaw (text
);
1220 gtk_stext_set_position (GtkEditable
*editable
,
1223 GtkSText
*text
= (GtkSText
*) editable
;
1225 undraw_cursor (text
, FALSE
);
1226 text
->cursor_mark
= find_mark (text
, position
);
1227 find_cursor (text
, TRUE
);
1228 draw_cursor (text
, FALSE
);
1229 gtk_editable_select_region (editable
, 0, 0);
1232 /* SYLPHEED - set_position used. Need to find out whether there's
1233 * a better way to handle this */
1234 static void gtk_stext_set_position_X (GtkEditable
*editable
,
1237 GtkSText
*text
= (GtkSText
*) editable
;
1239 undraw_cursor (text
, FALSE
);
1240 text
->cursor_mark
= find_mark (text
, position
);
1241 find_cursor (text
, TRUE
);
1242 draw_cursor (text
, FALSE
);
1246 gtk_stext_get_chars (GtkEditable
*editable
,
1254 g_return_val_if_fail (editable
!= NULL
, NULL
);
1255 g_return_val_if_fail (GTK_IS_STEXT (editable
), NULL
);
1256 text
= GTK_STEXT (editable
);
1259 end_pos
= TEXT_LENGTH (text
);
1261 if ((start_pos
< 0) ||
1262 (end_pos
> TEXT_LENGTH (text
)) ||
1263 (end_pos
< start_pos
))
1266 move_gap (text
, TEXT_LENGTH (text
));
1267 make_forward_space (text
, 1);
1269 if (text
->use_wchar
)
1272 ch
= text
->text
.wc
[end_pos
];
1273 text
->text
.wc
[end_pos
] = 0;
1274 retval
= gdk_wcstombs (text
->text
.wc
+ start_pos
);
1275 text
->text
.wc
[end_pos
] = ch
;
1280 ch
= text
->text
.ch
[end_pos
];
1281 text
->text
.ch
[end_pos
] = 0;
1282 retval
= g_strdup (text
->text
.ch
+ start_pos
);
1283 text
->text
.ch
[end_pos
] = ch
;
1291 gtk_stext_destroy (GtkObject
*object
)
1295 g_return_if_fail (object
!= NULL
);
1296 g_return_if_fail (GTK_IS_STEXT (object
));
1298 text
= (GtkSText
*) object
;
1300 gtk_signal_disconnect_by_data (GTK_OBJECT (text
->hadj
), text
);
1301 gtk_signal_disconnect_by_data (GTK_OBJECT (text
->vadj
), text
);
1305 gtk_timeout_remove (text
->timer
);
1312 gtk_stext_disable_blink(text
);
1314 GTK_OBJECT_CLASS(parent_class
)->destroy (object
);
1318 gtk_stext_finalize (GtkObject
*object
)
1323 g_return_if_fail (object
!= NULL
);
1324 g_return_if_fail (GTK_IS_STEXT (object
));
1326 text
= (GtkSText
*)object
;
1328 gtk_object_unref (GTK_OBJECT (text
->hadj
));
1329 gtk_object_unref (GTK_OBJECT (text
->vadj
));
1331 /* Clean up the internal structures */
1332 if (text
->use_wchar
)
1333 g_free (text
->text
.wc
);
1335 g_free (text
->text
.ch
);
1337 tmp_list
= text
->text_properties
;
1340 destroy_text_property (tmp_list
->data
);
1341 tmp_list
= tmp_list
->next
;
1344 if (text
->current_font
)
1345 text_font_unref (text
->current_font
);
1347 g_list_free (text
->text_properties
);
1349 if (text
->use_wchar
)
1351 if (text
->scratch_buffer
.wc
)
1352 g_free (text
->scratch_buffer
.wc
);
1356 if (text
->scratch_buffer
.ch
)
1357 g_free (text
->scratch_buffer
.ch
);
1360 g_list_free (text
->tab_stops
);
1362 GTK_OBJECT_CLASS(parent_class
)->finalize (object
);
1366 gtk_stext_realize (GtkWidget
*widget
)
1369 GtkEditable
*editable
;
1370 GdkWindowAttr attributes
;
1371 gint attributes_mask
;
1373 g_return_if_fail (widget
!= NULL
);
1374 g_return_if_fail (GTK_IS_STEXT (widget
));
1376 text
= GTK_STEXT (widget
);
1377 editable
= GTK_EDITABLE (widget
);
1378 GTK_WIDGET_SET_FLAGS (text
, GTK_REALIZED
);
1380 attributes
.window_type
= GDK_WINDOW_CHILD
;
1381 attributes
.x
= widget
->allocation
.x
;
1382 attributes
.y
= widget
->allocation
.y
;
1383 attributes
.width
= widget
->allocation
.width
;
1384 attributes
.height
= widget
->allocation
.height
;
1385 attributes
.wclass
= GDK_INPUT_OUTPUT
;
1386 attributes
.visual
= gtk_widget_get_visual (widget
);
1387 attributes
.colormap
= gtk_widget_get_colormap (widget
);
1388 attributes
.event_mask
= gtk_widget_get_events (widget
);
1389 attributes
.event_mask
|= (GDK_EXPOSURE_MASK
|
1390 GDK_BUTTON_PRESS_MASK
|
1391 GDK_BUTTON_RELEASE_MASK
|
1392 GDK_BUTTON_MOTION_MASK
|
1393 GDK_ENTER_NOTIFY_MASK
|
1394 GDK_LEAVE_NOTIFY_MASK
|
1395 GDK_KEY_PRESS_MASK
);
1396 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
1398 widget
->window
= gdk_window_new (gtk_widget_get_parent_window (widget
), &attributes
, attributes_mask
);
1399 gdk_window_set_user_data (widget
->window
, text
);
1401 attributes
.x
= (widget
->style
->klass
->xthickness
+ TEXT_BORDER_ROOM
);
1402 attributes
.y
= (widget
->style
->klass
->ythickness
+ TEXT_BORDER_ROOM
);
1403 attributes
.width
= MAX (1, (gint
)widget
->allocation
.width
- (gint
)attributes
.x
* 2);
1404 attributes
.height
= MAX (1, (gint
)widget
->allocation
.height
- (gint
)attributes
.y
* 2);
1406 attributes
.cursor
= gdk_cursor_new (GDK_XTERM
);
1407 attributes_mask
|= GDK_WA_CURSOR
;
1409 text
->text_area
= gdk_window_new (widget
->window
, &attributes
, attributes_mask
);
1410 gdk_window_set_user_data (text
->text_area
, text
);
1412 gdk_cursor_destroy (attributes
.cursor
); /* The X server will keep it around as long as necessary */
1414 widget
->style
= gtk_style_attach (widget
->style
, widget
->window
);
1416 /* Can't call gtk_style_set_background here because it's handled specially */
1417 gdk_window_set_background (widget
->window
, &widget
->style
->base
[GTK_WIDGET_STATE (widget
)]);
1418 gdk_window_set_background (text
->text_area
, &widget
->style
->base
[GTK_WIDGET_STATE (widget
)]);
1420 if (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
1421 text
->bg_gc
= create_bg_gc (text
);
1423 text
->line_wrap_bitmap
= gdk_bitmap_create_from_data (text
->text_area
,
1424 (gchar
*) line_wrap_bits
,
1428 text
->line_arrow_bitmap
= gdk_bitmap_create_from_data (text
->text_area
,
1429 (gchar
*) line_arrow_bits
,
1433 text
->gc
= gdk_gc_new (text
->text_area
);
1434 gdk_gc_set_exposures (text
->gc
, TRUE
);
1435 gdk_gc_set_foreground (text
->gc
, &widget
->style
->text
[GTK_STATE_NORMAL
]);
1437 #ifdef USE_GTKGDK_XIM
1438 if (gdk_im_ready () && (editable
->ic_attr
= gdk_ic_attr_new ()) != NULL
)
1441 GdkColormap
*colormap
;
1443 GdkICAttr
*attr
= editable
->ic_attr
;
1444 GdkICAttributesType attrmask
= GDK_IC_ALL_REQ
;
1446 GdkIMStyle supported_style
= GDK_IM_PREEDIT_NONE
|
1447 GDK_IM_PREEDIT_NOTHING
|
1448 GDK_IM_PREEDIT_POSITION
|
1449 GDK_IM_STATUS_NONE
|
1450 GDK_IM_STATUS_NOTHING
;
1452 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
1453 supported_style
&= ~GDK_IM_PREEDIT_POSITION
;
1455 attr
->style
= style
= gdk_im_decide_style (supported_style
);
1456 attr
->client_window
= text
->text_area
;
1458 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
1459 gtk_widget_get_default_colormap ())
1461 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
1462 attr
->preedit_colormap
= colormap
;
1465 switch (style
& GDK_IM_PREEDIT_MASK
)
1467 case GDK_IM_PREEDIT_POSITION
:
1468 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
1470 g_warning ("over-the-spot style requires fontset");
1474 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
1475 gdk_window_get_size (text
->text_area
, &width
, &height
);
1476 attr
->spot_location
.x
= 0;
1477 attr
->spot_location
.y
= height
;
1478 attr
->preedit_area
.x
= 0;
1479 attr
->preedit_area
.y
= 0;
1480 attr
->preedit_area
.width
= width
;
1481 attr
->preedit_area
.height
= height
;
1482 attr
->preedit_fontset
= widget
->style
->font
;
1486 editable
->ic
= gdk_ic_new (attr
, attrmask
);
1488 if (editable
->ic
== NULL
)
1489 g_warning ("Can't create input context.");
1492 mask
= gdk_window_get_events (text
->text_area
);
1493 mask
|= gdk_ic_get_events (editable
->ic
);
1494 gdk_window_set_events (text
->text_area
, mask
);
1496 if (GTK_WIDGET_HAS_FOCUS (widget
))
1497 gdk_im_begin (editable
->ic
, text
->text_area
);
1502 realize_properties (text
);
1503 gdk_window_show (text
->text_area
);
1504 init_properties (text
);
1506 if (editable
->selection_start_pos
!= editable
->selection_end_pos
)
1507 gtk_editable_claim_selection (editable
, TRUE
, GDK_CURRENT_TIME
);
1509 recompute_geometry (text
);
1513 gtk_stext_style_set (GtkWidget
*widget
,
1514 GtkStyle
*previous_style
)
1516 GtkSText
*text
= GTK_STEXT (widget
);
1518 if (GTK_WIDGET_REALIZED (widget
))
1520 gdk_window_set_background (widget
->window
, &widget
->style
->base
[GTK_WIDGET_STATE (widget
)]);
1521 gdk_window_set_background (text
->text_area
, &widget
->style
->base
[GTK_WIDGET_STATE (widget
)]);
1525 gdk_gc_destroy (text
->bg_gc
);
1529 if (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
1530 text
->bg_gc
= create_bg_gc (text
);
1532 recompute_geometry (text
);
1535 if (text
->current_font
)
1536 text_font_unref (text
->current_font
);
1537 text
->current_font
= get_text_font (widget
->style
->font
);
1541 gtk_stext_state_changed (GtkWidget
*widget
,
1542 GtkStateType previous_state
)
1544 GtkSText
*text
= GTK_STEXT (widget
);
1546 if (GTK_WIDGET_REALIZED (widget
))
1548 gdk_window_set_background (widget
->window
, &widget
->style
->base
[GTK_WIDGET_STATE (widget
)]);
1549 gdk_window_set_background (text
->text_area
, &widget
->style
->base
[GTK_WIDGET_STATE (widget
)]);
1554 gtk_stext_unrealize (GtkWidget
*widget
)
1558 g_return_if_fail (widget
!= NULL
);
1559 g_return_if_fail (GTK_IS_STEXT (widget
));
1561 text
= GTK_STEXT (widget
);
1563 #ifdef USE_GTKGDK_XIM
1564 if (GTK_EDITABLE (widget
)->ic
)
1566 gdk_ic_destroy (GTK_EDITABLE (widget
)->ic
);
1567 GTK_EDITABLE (widget
)->ic
= NULL
;
1569 if (GTK_EDITABLE (widget
)->ic_attr
)
1571 gdk_ic_attr_destroy (GTK_EDITABLE (widget
)->ic_attr
);
1572 GTK_EDITABLE (widget
)->ic_attr
= NULL
;
1576 gdk_window_set_user_data (text
->text_area
, NULL
);
1577 gdk_window_destroy (text
->text_area
);
1578 text
->text_area
= NULL
;
1580 gdk_gc_destroy (text
->gc
);
1585 gdk_gc_destroy (text
->bg_gc
);
1589 gdk_pixmap_unref (text
->line_wrap_bitmap
);
1590 gdk_pixmap_unref (text
->line_arrow_bitmap
);
1592 unrealize_properties (text
);
1596 if (GTK_WIDGET_CLASS (parent_class
)->unrealize
)
1597 (* GTK_WIDGET_CLASS (parent_class
)->unrealize
) (widget
);
1601 clear_focus_area (GtkSText
*text
, gint area_x
, gint area_y
, gint area_width
, gint area_height
)
1603 GtkWidget
*widget
= GTK_WIDGET (text
);
1606 gint ythick
= TEXT_BORDER_ROOM
+ widget
->style
->klass
->ythickness
;
1607 gint xthick
= TEXT_BORDER_ROOM
+ widget
->style
->klass
->xthickness
;
1611 if (area_width
== 0 || area_height
== 0)
1614 if (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
1616 gdk_window_get_size (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
], &width
, &height
);
1618 gdk_gc_set_ts_origin (text
->bg_gc
,
1619 (- (gint
)text
->first_onscreen_hor_pixel
+ xthick
) % width
,
1620 (- (gint
)text
->first_onscreen_ver_pixel
+ ythick
) % height
);
1625 gc
= widget
->style
->bg_gc
[widget
->state
];
1628 gdk_draw_rectangle (GTK_WIDGET (text
)->window
, gc
, TRUE
,
1629 area_x
, area_y
, area_width
, area_height
);
1633 gtk_stext_draw_focus (GtkWidget
*widget
)
1639 g_return_if_fail (widget
!= NULL
);
1640 g_return_if_fail (GTK_IS_STEXT (widget
));
1642 text
= GTK_STEXT (widget
);
1644 if (GTK_WIDGET_DRAWABLE (widget
))
1646 gint ythick
= widget
->style
->klass
->ythickness
;
1647 gint xthick
= widget
->style
->klass
->xthickness
;
1648 gint xextra
= TEXT_BORDER_ROOM
;
1649 gint yextra
= TEXT_BORDER_ROOM
;
1651 TDEBUG (("in gtk_stext_draw_focus\n"));
1655 width
= widget
->allocation
.width
;
1656 height
= widget
->allocation
.height
;
1658 if (GTK_WIDGET_HAS_FOCUS (widget
))
1667 gtk_paint_focus (widget
->style
, widget
->window
,
1668 NULL
, widget
, "text",
1670 widget
->allocation
.width
- 1,
1671 widget
->allocation
.height
- 1);
1674 gtk_paint_shadow (widget
->style
, widget
->window
,
1675 GTK_STATE_NORMAL
, GTK_SHADOW_IN
,
1676 NULL
, widget
, "text",
1677 x
, y
, width
, height
);
1681 width
-= 2 * xthick
;
1682 height
-= 2 * ythick
;
1685 clear_focus_area (text
, x
, y
, width
, yextra
);
1687 clear_focus_area (text
, x
, y
+ yextra
,
1688 xextra
, y
+ height
- 2 * yextra
);
1690 clear_focus_area (text
, x
+ width
- xextra
, y
+ yextra
,
1691 xextra
, height
- 2 * ythick
);
1693 clear_focus_area (text
, x
, x
+ height
- yextra
, width
, yextra
);
1697 TDEBUG (("in gtk_stext_draw_focus (undrawable !!!)\n"));
1702 gtk_stext_size_request (GtkWidget
*widget
,
1703 GtkRequisition
*requisition
)
1710 g_return_if_fail (widget
!= NULL
);
1711 g_return_if_fail (GTK_IS_STEXT (widget
));
1712 g_return_if_fail (requisition
!= NULL
);
1714 xthickness
= widget
->style
->klass
->xthickness
+ TEXT_BORDER_ROOM
;
1715 ythickness
= widget
->style
->klass
->ythickness
+ TEXT_BORDER_ROOM
;
1717 char_height
= MIN_TEXT_HEIGHT_LINES
* (widget
->style
->font
->ascent
+
1718 widget
->style
->font
->descent
);
1720 char_width
= MIN_TEXT_WIDTH_LINES
* (gdk_text_width (widget
->style
->font
,
1721 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
1725 requisition
->width
= char_width
+ xthickness
* 2;
1726 requisition
->height
= char_height
+ ythickness
* 2;
1730 gtk_stext_size_allocate (GtkWidget
*widget
,
1731 GtkAllocation
*allocation
)
1734 GtkEditable
*editable
;
1736 g_return_if_fail (widget
!= NULL
);
1737 g_return_if_fail (GTK_IS_STEXT (widget
));
1738 g_return_if_fail (allocation
!= NULL
);
1740 text
= GTK_STEXT (widget
);
1741 editable
= GTK_EDITABLE (widget
);
1743 widget
->allocation
= *allocation
;
1744 if (GTK_WIDGET_REALIZED (widget
))
1746 gdk_window_move_resize (widget
->window
,
1747 allocation
->x
, allocation
->y
,
1748 allocation
->width
, allocation
->height
);
1750 gdk_window_move_resize (text
->text_area
,
1751 widget
->style
->klass
->xthickness
+ TEXT_BORDER_ROOM
,
1752 widget
->style
->klass
->ythickness
+ TEXT_BORDER_ROOM
,
1753 MAX (1, (gint
)widget
->allocation
.width
- (gint
)(widget
->style
->klass
->xthickness
+
1754 (gint
)TEXT_BORDER_ROOM
) * 2),
1755 MAX (1, (gint
)widget
->allocation
.height
- (gint
)(widget
->style
->klass
->ythickness
+
1756 (gint
)TEXT_BORDER_ROOM
) * 2));
1758 #ifdef USE_GTKGDK_XIM
1759 if (editable
->ic
&& (gdk_ic_get_style (editable
->ic
) & GDK_IM_PREEDIT_POSITION
))
1763 gdk_window_get_size (text
->text_area
, &width
, &height
);
1764 editable
->ic_attr
->preedit_area
.width
= width
;
1765 editable
->ic_attr
->preedit_area
.height
= height
;
1767 gdk_ic_set_attr (editable
->ic
,
1768 editable
->ic_attr
, GDK_IC_PREEDIT_AREA
);
1772 recompute_geometry (text
);
1777 gtk_stext_draw (GtkWidget
*widget
,
1780 g_return_if_fail (widget
!= NULL
);
1781 g_return_if_fail (GTK_IS_STEXT (widget
));
1782 g_return_if_fail (area
!= NULL
);
1784 if (GTK_WIDGET_DRAWABLE (widget
))
1786 expose_text (GTK_STEXT (widget
), area
, TRUE
);
1787 gtk_widget_draw_focus (widget
);
1792 gtk_stext_expose (GtkWidget
*widget
,
1793 GdkEventExpose
*event
)
1795 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1796 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
1797 g_return_val_if_fail (event
!= NULL
, FALSE
);
1799 if (event
->window
== GTK_STEXT (widget
)->text_area
)
1801 TDEBUG (("in gtk_stext_expose (expose)\n"));
1802 expose_text (GTK_STEXT (widget
), &event
->area
, TRUE
);
1804 else if (event
->count
== 0)
1806 TDEBUG (("in gtk_stext_expose (focus)\n"));
1807 gtk_widget_draw_focus (widget
);
1814 gtk_stext_scroll_timeout (gpointer data
)
1817 GdkEventMotion event
;
1819 GdkModifierType mask
;
1821 GDK_THREADS_ENTER ();
1823 text
= GTK_STEXT (data
);
1826 gdk_window_get_pointer (text
->text_area
, &x
, &y
, &mask
);
1828 if (mask
& (GDK_BUTTON1_MASK
| GDK_BUTTON3_MASK
))
1835 gtk_stext_motion_notify (GTK_WIDGET (text
), &event
);
1838 GDK_THREADS_LEAVE ();
1844 gtk_stext_button_press (GtkWidget
*widget
,
1845 GdkEventButton
*event
)
1848 GtkEditable
*editable
;
1849 static GdkAtom ctext_atom
= GDK_NONE
;
1851 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1852 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
1853 g_return_val_if_fail (event
!= NULL
, FALSE
);
1855 if (ctext_atom
== GDK_NONE
)
1856 ctext_atom
= gdk_atom_intern ("COMPOUND_TEXT", FALSE
);
1858 text
= GTK_STEXT (widget
);
1859 editable
= GTK_EDITABLE (widget
);
1861 if (text
->button
&& (event
->button
!= text
->button
))
1864 text
->button
= event
->button
;
1866 if (!GTK_WIDGET_HAS_FOCUS (widget
))
1867 gtk_widget_grab_focus (widget
);
1869 if (event
->button
== 1)
1871 switch (event
->type
)
1873 case GDK_BUTTON_PRESS
:
1874 gtk_grab_add (widget
);
1876 undraw_cursor (text
, FALSE
);
1877 find_mouse_cursor (text
, (gint
)event
->x
, (gint
)event
->y
);
1878 draw_cursor (text
, FALSE
);
1880 /* Set it now, so we display things right. We'll unset it
1881 * later if things don't work out */
1882 editable
->has_selection
= TRUE
;
1883 gtk_stext_set_selection (GTK_EDITABLE(text
),
1884 text
->cursor_mark
.index
,
1885 text
->cursor_mark
.index
);
1889 case GDK_2BUTTON_PRESS
:
1890 gtk_stext_select_word (text
, event
->time
);
1893 case GDK_3BUTTON_PRESS
:
1894 gtk_stext_select_line (text
, event
->time
);
1901 else if (event
->type
== GDK_BUTTON_PRESS
)
1903 if ((event
->button
== 2) && editable
->editable
)
1905 if (editable
->selection_start_pos
== editable
->selection_end_pos
||
1906 editable
->has_selection
)
1908 undraw_cursor (text
, FALSE
);
1909 find_mouse_cursor (text
, (gint
)event
->x
, (gint
)event
->y
);
1910 draw_cursor (text
, FALSE
);
1914 gtk_selection_convert (widget
, GDK_SELECTION_PRIMARY
,
1915 ctext_atom
, event
->time
);
1919 gtk_grab_add (widget
);
1921 undraw_cursor (text
, FALSE
);
1922 find_mouse_cursor (text
, event
->x
, event
->y
);
1923 draw_cursor (text
, FALSE
);
1925 gtk_stext_set_selection (GTK_EDITABLE(text
),
1926 text
->cursor_mark
.index
,
1927 text
->cursor_mark
.index
);
1929 editable
->has_selection
= FALSE
;
1930 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY
) == widget
->window
)
1931 gtk_selection_owner_set (NULL
, GDK_SELECTION_PRIMARY
, event
->time
);
1939 gtk_stext_button_release (GtkWidget
*widget
,
1940 GdkEventButton
*event
)
1943 GtkEditable
*editable
;
1944 g_return_val_if_fail (widget
!= NULL
, FALSE
);
1945 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
1946 g_return_val_if_fail (event
!= NULL
, FALSE
);
1948 text
= GTK_STEXT (widget
);
1950 gtk_grab_remove (widget
);
1952 if (text
->button
!= event
->button
)
1959 gtk_timeout_remove (text
->timer
);
1963 if (event
->button
== 1)
1965 text
= GTK_STEXT (widget
);
1966 editable
= GTK_EDITABLE (widget
);
1968 gtk_grab_remove (widget
);
1970 editable
->has_selection
= FALSE
;
1971 if (editable
->selection_start_pos
!= editable
->selection_end_pos
)
1973 if (gtk_selection_owner_set (widget
,
1974 GDK_SELECTION_PRIMARY
,
1976 editable
->has_selection
= TRUE
;
1978 gtk_stext_update_text (editable
, editable
->selection_start_pos
,
1979 editable
->selection_end_pos
);
1983 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY
) == widget
->window
)
1984 gtk_selection_owner_set (NULL
, GDK_SELECTION_PRIMARY
, event
->time
);
1987 else if (event
->button
== 3)
1989 gtk_grab_remove (widget
);
1992 undraw_cursor (text
, FALSE
);
1993 find_cursor (text
, TRUE
);
1994 draw_cursor (text
, FALSE
);
2000 gtk_stext_motion_notify (GtkWidget
*widget
,
2001 GdkEventMotion
*event
)
2006 GdkModifierType mask
;
2008 g_return_val_if_fail (widget
!= NULL
, FALSE
);
2009 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
2010 g_return_val_if_fail (event
!= NULL
, FALSE
);
2012 text
= GTK_STEXT (widget
);
2016 mask
= event
->state
;
2017 if (event
->is_hint
|| (text
->text_area
!= event
->window
))
2019 gdk_window_get_pointer (text
->text_area
, &x
, &y
, &mask
);
2022 if ((text
->button
== 0) ||
2023 !(mask
& (GDK_BUTTON1_MASK
| GDK_BUTTON3_MASK
)))
2026 gdk_window_get_size (text
->text_area
, NULL
, &height
);
2028 if ((y
< 0) || (y
> height
))
2030 if (text
->timer
== 0)
2032 text
->timer
= gtk_timeout_add (SCROLL_TIME
,
2033 gtk_stext_scroll_timeout
,
2037 scroll_int (text
, y
/2);
2039 scroll_int (text
, (y
- height
)/2);
2045 undraw_cursor (GTK_STEXT (widget
), FALSE
);
2046 find_mouse_cursor (GTK_STEXT (widget
), x
, y
);
2047 draw_cursor (GTK_STEXT (widget
), FALSE
);
2049 gtk_stext_set_selection (GTK_EDITABLE(text
),
2050 GTK_EDITABLE(text
)->selection_start_pos
,
2051 text
->cursor_mark
.index
);
2057 gtk_stext_insert_text (GtkEditable
*editable
,
2058 const gchar
*new_text
,
2059 gint new_text_length
,
2062 GtkSText
*text
= GTK_STEXT (editable
);
2064 GdkColor
*fore
, *back
;
2066 TextProperty
*property
;
2068 gtk_stext_set_point (text
, *position
);
2070 property
= MARK_CURRENT_PROPERTY (&text
->point
);
2071 font
= property
->flags
& PROPERTY_FONT
? property
->font
->gdk_font
: NULL
;
2072 fore
= property
->flags
& PROPERTY_FOREGROUND
? &property
->fore_color
: NULL
;
2073 back
= property
->flags
& PROPERTY_BACKGROUND
? &property
->back_color
: NULL
;
2075 gtk_stext_insert (text
, font
, fore
, back
, new_text
, new_text_length
);
2077 *position
= text
->point
.index
;
2081 gtk_stext_delete_text (GtkEditable
*editable
,
2087 g_return_if_fail (start_pos
>= 0);
2089 text
= GTK_STEXT (editable
);
2091 gtk_stext_set_point (text
, start_pos
);
2093 end_pos
= TEXT_LENGTH (text
);
2095 if (end_pos
> start_pos
)
2096 gtk_stext_forward_delete (text
, end_pos
- start_pos
);
2100 gtk_stext_key_press (GtkWidget
*widget
,
2104 GtkEditable
*editable
;
2109 g_return_val_if_fail (widget
!= NULL
, FALSE
);
2110 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
2111 g_return_val_if_fail (event
!= NULL
, FALSE
);
2115 text
= GTK_STEXT (widget
);
2116 editable
= GTK_EDITABLE (widget
);
2118 key
= event
->keyval
;
2121 if ((GTK_EDITABLE(text
)->editable
== FALSE
))
2123 switch (event
->keyval
)
2126 if (event
->state
& GDK_CONTROL_MASK
)
2127 scroll_int (text
, -text
->vadj
->value
);
2132 if (event
->state
& GDK_CONTROL_MASK
)
2133 scroll_int (text
, +text
->vadj
->upper
);
2137 case GDK_Page_Up
: scroll_int (text
, -text
->vadj
->page_increment
); break;
2138 case GDK_Page_Down
: scroll_int (text
, +text
->vadj
->page_increment
); break;
2140 scroll_int (text
, -KEY_SCROLL_PIXELS
);
2142 case GDK_Down
: scroll_int (text
, +KEY_SCROLL_PIXELS
); break;
2144 if (event
->state
& GDK_CONTROL_MASK
)
2145 gtk_signal_emit_by_name (GTK_OBJECT (text
), "activate");
2156 gint extend_selection
;
2158 guint initial_pos
= editable
->current_pos
;
2160 text
->point
= find_mark (text
, text
->cursor_mark
.index
);
2162 extend_selection
= event
->state
& GDK_SHIFT_MASK
;
2163 extend_start
= FALSE
;
2165 if (extend_selection
)
2167 editable
->has_selection
= TRUE
;
2169 if (editable
->selection_start_pos
== editable
->selection_end_pos
)
2171 editable
->selection_start_pos
= text
->point
.index
;
2172 editable
->selection_end_pos
= text
->point
.index
;
2175 extend_start
= (text
->point
.index
== editable
->selection_start_pos
);
2176 gtk_stext_disable_blink(text
);
2182 if (!extend_selection
)
2183 gtk_stext_enable_blink(text
);
2185 if (event
->keyval
!= GDK_Up
&& event
->keyval
!= GDK_Down
) {
2186 reset_persist_col_pos(text
);
2189 switch (event
->keyval
)
2192 if (event
->state
& GDK_CONTROL_MASK
) {
2193 if (text
->wrap_rmargin
== 0) {
2194 /* SYLPHEED: old behaviour */
2195 move_cursor_buffer_ver (text
, -1);
2198 /* SYLPHEED: contrived, but "trusty" */
2199 move_cursor_buffer_ver(text
, -1);
2200 move_cursor_to_display_row_start(text
);
2204 if (text
->wrap_rmargin
> 0) {
2205 /* SYLPHEED: line start */
2206 move_cursor_to_display_row_start(text
);
2209 gtk_stext_move_beginning_of_line (text
);
2214 if (event
->state
& GDK_CONTROL_MASK
) {
2215 /* SYLPHEED: a little bit contrived... */
2216 if (text
->wrap_rmargin
== 0) {
2218 move_cursor_buffer_ver (text
, +1);
2221 move_cursor_buffer_ver(text
, +1);
2222 move_cursor_to_display_row_end(text
);
2226 if (text
->wrap_rmargin
> 0) {
2227 /* SYLPHEED: line end */
2228 move_cursor_to_display_row_end(text
);
2231 gtk_stext_move_end_of_line(text
);
2236 move_cursor_page_ver (text
, -1);
2238 case GDK_Page_Down
: move_cursor_page_ver (text
, +1); break;
2239 /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
2241 if (text
->wrap_rmargin
> 0) {
2244 move_cursor_to_display_row_up(text
);
2247 move_cursor_ver (text
, -1);
2251 move_cursor_to_display_row_down(text
);
2252 /* move_cursor_ver (text, +1); */
2255 if (event
->state
& GDK_CONTROL_MASK
)
2256 gtk_stext_move_backward_word (text
);
2258 move_cursor_hor (text
, -1);
2261 if (event
->state
& GDK_CONTROL_MASK
)
2262 gtk_stext_move_forward_word (text
);
2264 move_cursor_hor (text
, +1);
2268 if (event
->state
& GDK_CONTROL_MASK
)
2269 gtk_stext_delete_backward_word (text
);
2271 gtk_stext_delete_backward_character (text
);
2274 gtk_stext_delete_line (text
);
2277 if (event
->state
& GDK_SHIFT_MASK
)
2279 extend_selection
= FALSE
;
2280 gtk_editable_paste_clipboard (editable
);
2282 else if (event
->state
& GDK_CONTROL_MASK
)
2284 gtk_editable_copy_clipboard (editable
);
2288 /* gtk_toggle_insert(text) -- IMPLEMENT */
2293 if (event
->state
& GDK_CONTROL_MASK
) {
2294 gtk_stext_delete_forward_word (text
);
2296 else if (event
->state
& GDK_SHIFT_MASK
)
2298 extend_selection
= FALSE
;
2299 gtk_editable_cut_clipboard (editable
);
2302 gtk_stext_delete_forward_character (text
);
2307 position
= text
->point
.index
;
2308 gtk_editable_insert_text (editable
, "\t", 1, &position
);
2311 if (event
->state
& GDK_CONTROL_MASK
)
2312 gtk_signal_emit_by_name (GTK_OBJECT (text
), "activate");
2315 position
= text
->point
.index
;
2316 gtk_editable_insert_text (editable
, "\n", 1, &position
);
2320 /* Don't insert literally */
2327 if (event
->state
& GDK_CONTROL_MASK
)
2329 if ((key
>= 'A') && (key
<= 'Z'))
2332 if ((key
>= 'a') && (key
<= 'z') && control_keys
[(int) (key
- 'a')])
2334 (* control_keys
[(int) (key
- 'a')]) (editable
, event
->time
);
2340 else if (event
->state
& GDK_MOD1_MASK
)
2342 if ((key
>= 'A') && (key
<= 'Z'))
2345 if ((key
>= 'a') && (key
<= 'z') && alt_keys
[(int) (key
- 'a')])
2347 (* alt_keys
[(int) (key
- 'a')]) (editable
, event
->time
);
2353 else if (event
->length
> 0)
2355 extend_selection
= FALSE
;
2357 gtk_editable_delete_selection (editable
);
2358 position
= text
->point
.index
;
2359 gtk_editable_insert_text (editable
, event
->string
, event
->length
, &position
);
2367 if (return_val
&& (editable
->current_pos
!= initial_pos
))
2369 if (extend_selection
)
2371 if (editable
->current_pos
< editable
->selection_start_pos
)
2372 gtk_stext_set_selection (editable
, editable
->current_pos
,
2373 editable
->selection_end_pos
);
2374 else if (editable
->current_pos
> editable
->selection_end_pos
)
2375 gtk_stext_set_selection (editable
, editable
->selection_start_pos
,
2376 editable
->current_pos
);
2380 gtk_stext_set_selection (editable
, editable
->current_pos
,
2381 editable
->selection_end_pos
);
2383 gtk_stext_set_selection (editable
, editable
->selection_start_pos
,
2384 editable
->current_pos
);
2388 gtk_stext_set_selection (editable
, 0, 0);
2390 gtk_editable_claim_selection (editable
,
2391 editable
->selection_start_pos
!= editable
->selection_end_pos
,
2400 gtk_stext_focus_in (GtkWidget
*widget
,
2401 GdkEventFocus
*event
)
2403 g_return_val_if_fail (widget
!= NULL
, FALSE
);
2404 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
2405 g_return_val_if_fail (event
!= NULL
, FALSE
);
2407 TDEBUG (("in gtk_stext_focus_in\n"));
2409 GTK_WIDGET_SET_FLAGS (widget
, GTK_HAS_FOCUS
);
2410 gtk_widget_draw_focus (widget
);
2412 #ifdef USE_GTKGDK_XIM
2413 if (GTK_EDITABLE(widget
)->ic
)
2414 gdk_im_begin (GTK_EDITABLE(widget
)->ic
, GTK_STEXT(widget
)->text_area
);
2417 draw_cursor (GTK_STEXT(widget
), TRUE
);
2418 GTK_STEXT(widget
)->cursor_visible
= TRUE
;
2419 gtk_stext_enable_blink(GTK_STEXT(widget
));
2425 gtk_stext_focus_out (GtkWidget
*widget
,
2426 GdkEventFocus
*event
)
2428 g_return_val_if_fail (widget
!= NULL
, FALSE
);
2429 g_return_val_if_fail (GTK_IS_STEXT (widget
), FALSE
);
2430 g_return_val_if_fail (event
!= NULL
, FALSE
);
2432 TDEBUG (("in gtk_stext_focus_out\n"));
2434 GTK_WIDGET_UNSET_FLAGS (widget
, GTK_HAS_FOCUS
);
2435 gtk_widget_draw_focus (widget
);
2438 * should disable blink before undrawing the cursor - disabling blink
2439 * redraws the cursor.
2441 gtk_stext_disable_blink(GTK_STEXT(widget
));
2442 undraw_cursor (GTK_STEXT(widget
), TRUE
);
2443 GTK_STEXT(widget
)->cursor_visible
= FALSE
;
2445 #ifdef USE_GTKGDK_XIM
2453 gtk_stext_adjustment (GtkAdjustment
*adjustment
,
2458 g_return_if_fail (adjustment
!= NULL
);
2459 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment
));
2460 g_return_if_fail (text
!= NULL
);
2461 g_return_if_fail (GTK_IS_STEXT (text
));
2463 /* Clamp the value here, because we'll get really confused
2464 * if someone tries to move the adjusment outside of the
2467 old_val
= adjustment
->value
;
2469 adjustment
->value
= MIN (adjustment
->value
, adjustment
->upper
- adjustment
->page_size
);
2470 adjustment
->value
= MAX (adjustment
->value
, 0.0);
2472 if (adjustment
->value
!= old_val
)
2474 gtk_signal_handler_block_by_func (GTK_OBJECT (adjustment
),
2475 GTK_SIGNAL_FUNC (gtk_stext_adjustment
),
2477 gtk_adjustment_changed (adjustment
);
2478 gtk_signal_handler_unblock_by_func (GTK_OBJECT (adjustment
),
2479 GTK_SIGNAL_FUNC (gtk_stext_adjustment
),
2483 /* Just ignore it if we haven't been size-allocated and realized yet */
2484 if (text
->line_start_cache
== NULL
)
2487 if (adjustment
== text
->hadj
)
2489 g_warning ("horizontal scrolling not implemented");
2493 gint diff
= ((gint
)adjustment
->value
) - text
->last_ver_value
;
2497 undraw_cursor (text
, FALSE
);
2500 scroll_down (text
, diff
);
2501 else /* if (diff < 0) */
2502 scroll_up (text
, diff
);
2504 draw_cursor (text
, FALSE
);
2506 text
->last_ver_value
= adjustment
->value
;
2512 gtk_stext_disconnect (GtkAdjustment
*adjustment
,
2515 g_return_if_fail (adjustment
!= NULL
);
2516 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment
));
2517 g_return_if_fail (text
!= NULL
);
2518 g_return_if_fail (GTK_IS_STEXT (text
));
2520 if (adjustment
== text
->hadj
)
2521 gtk_stext_set_adjustments (text
, NULL
, text
->vadj
);
2522 if (adjustment
== text
->vadj
)
2523 gtk_stext_set_adjustments (text
, text
->hadj
, NULL
);
2527 static GtkSPropertyMark
2528 find_this_line_start_mark (GtkSText
* text
, guint point_position
, const GtkSPropertyMark
* near
)
2530 GtkSPropertyMark mark
;
2532 mark
= find_mark_near (text
, point_position
, near
);
2534 while (mark
.index
> 0 &&
2535 GTK_STEXT_INDEX (text
, mark
.index
- 1) != LINE_DELIM
)
2536 decrement_mark (&mark
);
2542 init_tab_cont (GtkSText
* text
, PrevTabCont
* tab_cont
)
2544 tab_cont
->pixel_offset
= 0;
2545 tab_cont
->tab_start
.tab_stops
= text
->tab_stops
;
2546 tab_cont
->tab_start
.to_next_tab
= (gulong
) text
->tab_stops
->data
;
2548 if (!tab_cont
->tab_start
.to_next_tab
)
2549 tab_cont
->tab_start
.to_next_tab
= text
->default_tab_width
;
2553 line_params_iterate (GtkSText
* text
,
2554 const GtkSPropertyMark
* mark0
,
2555 const PrevTabCont
* tab_mark0
,
2558 LineIteratorFunction iter
)
2559 /* mark0 MUST be a real line start. if ALLOC, allocate line params
2560 * from a mem chunk. DATA is passed to ITER_CALL, which is called
2561 * for each line following MARK, iteration continues unless ITER_CALL
2564 GtkSPropertyMark mark
= *mark0
;
2565 PrevTabCont tab_conts
[2];
2566 LineParams
*lp
, lpbuf
;
2567 gint tab_cont_index
= 0;
2570 tab_conts
[0] = *tab_mark0
;
2572 init_tab_cont (text
, tab_conts
);
2577 lp
= g_chunk_new (LineParams
, params_mem_chunk
);
2581 *lp
= find_line_params (text
, &mark
, tab_conts
+ tab_cont_index
,
2582 tab_conts
+ (tab_cont_index
+ 1) % 2);
2584 if ((*iter
) (text
, lp
, data
))
2587 if (LAST_INDEX (text
, lp
->end
))
2591 advance_mark (&mark
);
2592 tab_cont_index
= (tab_cont_index
+ 1) % 2;
2597 fetch_lines_iterator (GtkSText
* text
, LineParams
* lp
, void* data
)
2599 FetchLinesData
*fldata
= (FetchLinesData
*) data
;
2601 fldata
->new_lines
= g_list_prepend (fldata
->new_lines
, lp
);
2603 switch (fldata
->fl_type
)
2605 case FetchLinesCount
:
2606 if (!text
->line_wrap
|| !lp
->wraps
)
2609 if (fldata
->data
>= fldata
->data_max
)
2613 case FetchLinesPixels
:
2615 fldata
->data
+= LINE_HEIGHT(*lp
);
2617 if (fldata
->data
>= fldata
->data_max
)
2627 fetch_lines (GtkSText
* text
,
2628 const GtkSPropertyMark
* mark0
,
2629 const PrevTabCont
* tab_cont0
,
2633 FetchLinesData fl_data
;
2635 fl_data
.new_lines
= NULL
;
2637 fl_data
.data_max
= data
;
2638 fl_data
.fl_type
= fl_type
;
2640 line_params_iterate (text
, mark0
, tab_cont0
, TRUE
, &fl_data
, fetch_lines_iterator
);
2642 return g_list_reverse (fl_data
.new_lines
);
2646 fetch_lines_backward (GtkSText
* text
)
2648 GList
* new_lines
= NULL
, *new_line_start
;
2649 GtkSPropertyMark mark
;
2651 if (CACHE_DATA(text
->line_start_cache
).start
.index
== 0)
2654 mark
= find_this_line_start_mark (text
,
2655 CACHE_DATA(text
->line_start_cache
).start
.index
- 1,
2656 &CACHE_DATA(text
->line_start_cache
).start
);
2658 new_line_start
= new_lines
= fetch_lines (text
, &mark
, NULL
, FetchLinesCount
, 1);
2660 while (new_line_start
->next
)
2661 new_line_start
= new_line_start
->next
;
2663 new_line_start
->next
= text
->line_start_cache
;
2664 text
->line_start_cache
->prev
= new_line_start
;
2668 fetch_lines_forward (GtkSText
* text
, gint line_count
)
2670 GtkSPropertyMark mark
;
2671 GList
* line
= text
->line_start_cache
;
2676 mark
= CACHE_DATA(line
).end
;
2678 if (LAST_INDEX (text
, mark
))
2681 advance_mark(&mark
);
2683 line
->next
= fetch_lines (text
, &mark
, &CACHE_DATA(line
).tab_cont_next
, FetchLinesCount
, line_count
);
2686 line
->next
->prev
= line
;
2689 /* Compute the number of lines, and vertical pixels for n characters
2690 * starting from the point
2693 compute_lines_pixels (GtkSText
* text
, guint char_count
,
2694 guint
*lines
, guint
*pixels
)
2696 GList
*line
= text
->current_line
;
2697 gint chars_left
= char_count
;
2702 /* If chars_left == 0, that means we're joining two lines in a
2703 * deletion, so add in the values for the next line as well
2705 for (; line
&& chars_left
>= 0; line
= line
->next
)
2707 *pixels
+= LINE_HEIGHT(CACHE_DATA(line
));
2709 if (line
== text
->current_line
)
2710 chars_left
-= CACHE_DATA(line
).end
.index
- text
->point
.index
+ 1;
2712 chars_left
-= CACHE_DATA(line
).end
.index
- CACHE_DATA(line
).start
.index
+ 1;
2714 if (!text
->line_wrap
|| !CACHE_DATA(line
).wraps
)
2718 chars_left
= 0; /* force another loop */
2721 fetch_lines_forward (text
, 1);
2726 total_line_height (GtkSText
* text
, GList
* line
, gint line_count
)
2730 for (; line
&& line_count
> 0; line
= line
->next
)
2732 height
+= LINE_HEIGHT(CACHE_DATA(line
));
2734 if (!text
->line_wrap
|| !CACHE_DATA(line
).wraps
)
2738 fetch_lines_forward (text
, line_count
);
2745 swap_lines (GtkSText
* text
, GList
* old
, GList
* new, guint old_line_count
)
2747 if (old
== text
->line_start_cache
)
2751 for (; old_line_count
> 0; old_line_count
-= 1)
2753 while (text
->line_start_cache
&&
2755 CACHE_DATA(text
->line_start_cache
).wraps
)
2756 remove_cache_line(text
, text
->line_start_cache
);
2758 remove_cache_line(text
, text
->line_start_cache
);
2761 last
= g_list_last (new);
2763 last
->next
= text
->line_start_cache
;
2765 if (text
->line_start_cache
)
2766 text
->line_start_cache
->prev
= last
;
2768 text
->line_start_cache
= new;
2774 g_assert (old
->prev
);
2778 for (; old_line_count
> 0; old_line_count
-= 1)
2780 while (old
&& text
->line_wrap
&& CACHE_DATA(old
).wraps
)
2781 old
= remove_cache_line (text
, old
);
2783 old
= remove_cache_line (text
, old
);
2789 last
= g_list_last (new);
2799 correct_cache_delete (GtkSText
* text
, gint nchars
, gint lines
)
2801 GList
* cache
= text
->current_line
;
2804 for (i
= 0; cache
&& i
< lines
; i
+= 1, cache
= cache
->next
)
2807 for (; cache
; cache
= cache
->next
)
2809 GtkSPropertyMark
*start
= &CACHE_DATA(cache
).start
;
2810 GtkSPropertyMark
*end
= &CACHE_DATA(cache
).end
;
2812 start
->index
-= nchars
;
2813 end
->index
-= nchars
;
2815 if (LAST_INDEX (text
, text
->point
) &&
2816 start
->index
== text
->point
.index
)
2817 *start
= text
->point
;
2818 else if (start
->property
== text
->point
.property
)
2819 start
->offset
= start
->index
- (text
->point
.index
- text
->point
.offset
);
2821 if (LAST_INDEX (text
, text
->point
) &&
2822 end
->index
== text
->point
.index
)
2824 if (end
->property
== text
->point
.property
)
2825 end
->offset
= end
->index
- (text
->point
.index
- text
->point
.offset
);
2827 /*TEXT_ASSERT_MARK(text, start, "start");*/
2828 /*TEXT_ASSERT_MARK(text, end, "end");*/
2833 delete_expose (GtkSText
* text
, guint nchars
, guint old_lines
, guint old_pixels
)
2835 GtkWidget
*widget
= GTK_WIDGET (text
);
2838 guint new_pixels
= 0;
2840 GList
* new_line
= NULL
;
2843 text
->cursor_virtual_x
= 0;
2845 correct_cache_delete (text
, nchars
, old_lines
);
2847 pixel_height
= pixel_height_of(text
, text
->current_line
) -
2848 LINE_HEIGHT(CACHE_DATA(text
->current_line
));
2850 if (CACHE_DATA(text
->current_line
).start
.index
== text
->point
.index
)
2851 CACHE_DATA(text
->current_line
).start
= text
->point
;
2853 new_line
= fetch_lines (text
,
2854 &CACHE_DATA(text
->current_line
).start
,
2855 &CACHE_DATA(text
->current_line
).tab_cont
,
2859 swap_lines (text
, text
->current_line
, new_line
, old_lines
);
2861 text
->current_line
= new_line
;
2863 new_pixels
= total_line_height (text
, new_line
, 1);
2865 gdk_window_get_size (text
->text_area
, &width
, &height
);
2867 if (old_pixels
!= new_pixels
)
2869 if (!widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
2871 gdk_draw_pixmap (text
->text_area
,
2875 pixel_height
+ old_pixels
,
2877 pixel_height
+ new_pixels
,
2881 text
->vadj
->upper
+= new_pixels
;
2882 text
->vadj
->upper
-= old_pixels
;
2883 adjust_adj (text
, text
->vadj
);
2887 rect
.y
= pixel_height
;
2889 rect
.height
= new_pixels
;
2891 expose_text (text
, &rect
, FALSE
);
2892 gtk_stext_draw_focus ( (GtkWidget
*) text
);
2894 text
->cursor_mark
= text
->point
;
2896 find_cursor (text
, TRUE
);
2898 if (old_pixels
!= new_pixels
)
2900 if (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
2903 rect
.y
= pixel_height
+ new_pixels
;
2905 rect
.height
= height
- rect
.y
;
2907 expose_text (text
, &rect
, FALSE
);
2910 process_exposes (text
);
2917 /* note, the point has already been moved forward */
2919 correct_cache_insert (GtkSText
* text
, gint nchars
)
2922 GtkSPropertyMark
*start
;
2923 GtkSPropertyMark
*end
;
2925 /* If we inserted a property exactly at the beginning of the
2926 * line, we have to correct here, or fetch_lines will
2929 start
= &CACHE_DATA(text
->current_line
).start
;
2930 if (start
->index
== text
->point
.index
- nchars
)
2932 *start
= text
->point
;
2933 move_mark_n (start
, -nchars
);
2936 /* Now correct the offsets, and check for start or end marks that
2937 * are after the point, yet point to a property before the point's
2938 * property. This indicates that they are meant to point to the
2939 * second half of a property we split in insert_text_property(), so
2940 * we fix them up that way.
2942 cache
= text
->current_line
->next
;
2944 for (; cache
; cache
= cache
->next
)
2946 start
= &CACHE_DATA(cache
).start
;
2947 end
= &CACHE_DATA(cache
).end
;
2949 if (LAST_INDEX (text
, text
->point
) &&
2950 start
->index
== text
->point
.index
)
2951 *start
= text
->point
;
2954 if (start
->property
== text
->point
.property
)
2956 start
->offset
+= nchars
;
2957 start
->index
+= nchars
;
2959 else if (start
->property
->next
&&
2960 (start
->property
->next
->next
== text
->point
.property
))
2962 /* We split the property, and this is the second half */
2963 start
->offset
-= MARK_CURRENT_PROPERTY (start
)->length
;
2964 start
->index
+= nchars
;
2965 start
->property
= text
->point
.property
;
2968 start
->index
+= nchars
;
2971 if (LAST_INDEX (text
, text
->point
) &&
2972 end
->index
== text
->point
.index
)
2976 if (end
->property
== text
->point
.property
)
2978 end
->offset
+= nchars
;
2979 end
->index
+= nchars
;
2981 else if (end
->property
->next
&&
2982 (end
->property
->next
->next
== text
->point
.property
))
2984 /* We split the property, and this is the second half */
2985 end
->offset
-= MARK_CURRENT_PROPERTY (end
)->length
;
2986 end
->index
+= nchars
;
2987 end
->property
= text
->point
.property
;
2990 end
->index
+= nchars
;
2993 /*TEXT_ASSERT_MARK(text, start, "start");*/
2994 /*TEXT_ASSERT_MARK(text, end, "end");*/
3000 insert_expose (GtkSText
* text
, guint old_pixels
, gint nchars
,
3001 guint new_line_count
)
3003 GtkWidget
*widget
= GTK_WIDGET (text
);
3006 guint new_pixels
= 0;
3008 GList
* new_lines
= NULL
;
3011 text
->cursor_virtual_x
= 0;
3013 undraw_cursor (text
, FALSE
);
3015 correct_cache_insert (text
, nchars
);
3017 TEXT_SHOW_ADJ (text
, text
->vadj
, "vadj");
3019 pixel_height
= pixel_height_of(text
, text
->current_line
) -
3020 LINE_HEIGHT(CACHE_DATA(text
->current_line
));
3022 new_lines
= fetch_lines (text
,
3023 &CACHE_DATA(text
->current_line
).start
,
3024 &CACHE_DATA(text
->current_line
).tab_cont
,
3028 swap_lines (text
, text
->current_line
, new_lines
, 1);
3030 text
->current_line
= new_lines
;
3032 new_pixels
= total_line_height (text
, new_lines
, new_line_count
);
3034 gdk_window_get_size (text
->text_area
, &width
, &height
);
3036 if (old_pixels
!= new_pixels
)
3038 if (!widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
3040 gdk_draw_pixmap (text
->text_area
,
3044 pixel_height
+ old_pixels
,
3046 pixel_height
+ new_pixels
,
3048 height
+ (old_pixels
- new_pixels
) - pixel_height
);
3051 text
->vadj
->upper
+= new_pixels
;
3052 text
->vadj
->upper
-= old_pixels
;
3053 adjust_adj (text
, text
->vadj
);
3057 rect
.y
= pixel_height
;
3059 rect
.height
= new_pixels
;
3061 expose_text (text
, &rect
, FALSE
);
3062 gtk_stext_draw_focus ( (GtkWidget
*) text
);
3064 text
->cursor_mark
= text
->point
;
3066 find_cursor (text
, TRUE
);
3068 draw_cursor (text
, FALSE
);
3070 if (old_pixels
!= new_pixels
)
3072 if (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
])
3075 rect
.y
= pixel_height
+ new_pixels
;
3077 rect
.height
= height
- rect
.y
;
3079 expose_text (text
, &rect
, FALSE
);
3082 process_exposes (text
);
3085 TEXT_SHOW_ADJ (text
, text
->vadj
, "vadj");
3090 /* Text property functions */
3093 font_hash (gconstpointer font
)
3095 return gdk_font_id ((const GdkFont
*) font
);
3098 static GHashTable
*font_cache_table
= NULL
;
3100 static GtkSTextFont
*
3101 get_text_font (GdkFont
* gfont
)
3106 if (!font_cache_table
)
3107 font_cache_table
= g_hash_table_new (font_hash
, (GCompareFunc
) gdk_font_equal
);
3109 tf
= g_hash_table_lookup (font_cache_table
, gfont
);
3117 tf
= g_new (GtkSTextFont
, 1);
3120 tf
->gdk_font
= gfont
;
3121 gdk_font_ref (gfont
);
3123 for(i
= 0; i
< 256; i
+= 1)
3124 tf
->char_widths
[i
] = gdk_char_width (gfont
, (char)i
);
3126 g_hash_table_insert (font_cache_table
, gfont
, tf
);
3132 text_font_unref (GtkSTextFont
*text_font
)
3134 text_font
->ref_count
--;
3135 if (text_font
->ref_count
== 0)
3137 g_hash_table_remove (font_cache_table
, text_font
->gdk_font
);
3138 gdk_font_unref (text_font
->gdk_font
);
3144 text_properties_equal (TextProperty
* prop
, GdkFont
* font
, GdkColor
*fore
, GdkColor
*back
)
3146 if (prop
->flags
& PROPERTY_FONT
)
3149 GtkSTextFont
*text_font
;
3154 text_font
= get_text_font (font
);
3156 retval
= (prop
->font
== text_font
);
3157 text_font_unref (text_font
);
3166 if (prop
->flags
& PROPERTY_FOREGROUND
)
3168 if (!fore
|| !gdk_color_equal (&prop
->fore_color
, fore
))
3175 if (prop
->flags
& PROPERTY_BACKGROUND
)
3177 if (!back
|| !gdk_color_equal (&prop
->back_color
, back
))
3188 realize_property (GtkSText
*text
, TextProperty
*prop
)
3190 GdkColormap
*colormap
= gtk_widget_get_colormap (GTK_WIDGET (text
));
3192 if (prop
->flags
& PROPERTY_FOREGROUND
)
3193 gdk_colormap_alloc_color (colormap
, &prop
->fore_color
, FALSE
, FALSE
);
3195 if (prop
->flags
& PROPERTY_BACKGROUND
)
3196 gdk_colormap_alloc_color (colormap
, &prop
->back_color
, FALSE
, FALSE
);
3200 realize_properties (GtkSText
*text
)
3202 GList
*tmp_list
= text
->text_properties
;
3206 realize_property (text
, tmp_list
->data
);
3208 tmp_list
= tmp_list
->next
;
3213 unrealize_property (GtkSText
*text
, TextProperty
*prop
)
3215 GdkColormap
*colormap
= gtk_widget_get_colormap (GTK_WIDGET (text
));
3217 if (prop
->flags
& PROPERTY_FOREGROUND
)
3218 gdk_colormap_free_colors (colormap
, &prop
->fore_color
, 1);
3220 if (prop
->flags
& PROPERTY_BACKGROUND
)
3221 gdk_colormap_free_colors (colormap
, &prop
->back_color
, 1);
3225 unrealize_properties (GtkSText
*text
)
3227 GList
*tmp_list
= text
->text_properties
;
3231 unrealize_property (text
, tmp_list
->data
);
3233 tmp_list
= tmp_list
->next
;
3237 static TextProperty
*
3238 new_text_property (GtkSText
*text
, GdkFont
*font
, GdkColor
* fore
,
3239 GdkColor
* back
, guint length
)
3243 if (text_property_chunk
== NULL
)
3245 text_property_chunk
= g_mem_chunk_new ("text property mem chunk",
3246 sizeof(TextProperty
),
3247 1024*sizeof(TextProperty
),
3251 prop
= g_chunk_new(TextProperty
, text_property_chunk
);
3256 prop
->flags
|= PROPERTY_FONT
;
3257 prop
->font
= get_text_font (font
);
3264 prop
->flags
|= PROPERTY_FOREGROUND
;
3265 prop
->fore_color
= *fore
;
3270 prop
->flags
|= PROPERTY_BACKGROUND
;
3271 prop
->back_color
= *back
;
3274 prop
->length
= length
;
3276 if (GTK_WIDGET_REALIZED (text
))
3277 realize_property (text
, prop
);
3283 destroy_text_property (TextProperty
*prop
)
3286 text_font_unref (prop
->font
);
3288 g_mem_chunk_free (text_property_chunk
, prop
);
3291 /* Flop the memory between the point and the gap around like a
3294 move_gap (GtkSText
* text
, guint index
)
3296 if (text
->gap_position
< index
)
3298 gint diff
= index
- text
->gap_position
;
3300 if (text
->use_wchar
)
3301 g_memmove (text
->text
.wc
+ text
->gap_position
,
3302 text
->text
.wc
+ text
->gap_position
+ text
->gap_size
,
3303 diff
*sizeof (GdkWChar
));
3305 g_memmove (text
->text
.ch
+ text
->gap_position
,
3306 text
->text
.ch
+ text
->gap_position
+ text
->gap_size
,
3309 text
->gap_position
= index
;
3311 else if (text
->gap_position
> index
)
3313 gint diff
= text
->gap_position
- index
;
3315 if (text
->use_wchar
)
3316 g_memmove (text
->text
.wc
+ index
+ text
->gap_size
,
3317 text
->text
.wc
+ index
,
3318 diff
*sizeof (GdkWChar
));
3320 g_memmove (text
->text
.ch
+ index
+ text
->gap_size
,
3321 text
->text
.ch
+ index
,
3324 text
->gap_position
= index
;
3328 /* Increase the gap size. */
3330 make_forward_space (GtkSText
* text
, guint len
)
3332 if (text
->gap_size
< len
)
3334 guint sum
= MAX(2*len
, MIN_GAP_SIZE
) + text
->text_end
;
3336 if (sum
>= text
->text_len
)
3340 while (i
<= sum
) i
<<= 1;
3342 if (text
->use_wchar
)
3343 text
->text
.wc
= (GdkWChar
*)g_realloc(text
->text
.wc
,
3344 i
*sizeof(GdkWChar
));
3346 text
->text
.ch
= (guchar
*)g_realloc(text
->text
.ch
, i
);
3350 if (text
->use_wchar
)
3351 g_memmove (text
->text
.wc
+ text
->gap_position
+ text
->gap_size
+ 2*len
,
3352 text
->text
.wc
+ text
->gap_position
+ text
->gap_size
,
3353 (text
->text_end
- (text
->gap_position
+ text
->gap_size
))
3356 g_memmove (text
->text
.ch
+ text
->gap_position
+ text
->gap_size
+ 2*len
,
3357 text
->text
.ch
+ text
->gap_position
+ text
->gap_size
,
3358 text
->text_end
- (text
->gap_position
+ text
->gap_size
));
3360 text
->text_end
+= len
*2;
3361 text
->gap_size
+= len
*2;
3365 /* Inserts into the text property list a list element that guarantees
3366 * that for len characters following the point, text has the correct
3367 * property. does not move point. adjusts text_properties_point and
3368 * text_properties_point_offset relative to the current value of
3371 insert_text_property (GtkSText
* text
, GdkFont
* font
,
3372 GdkColor
*fore
, GdkColor
* back
, guint len
)
3374 GtkSPropertyMark
*mark
= &text
->point
;
3375 TextProperty
* forward_prop
= MARK_CURRENT_PROPERTY(mark
);
3376 TextProperty
* backward_prop
= MARK_PREV_PROPERTY(mark
);
3378 if (MARK_OFFSET(mark
) == 0)
3380 /* Point is on the boundary of two properties.
3381 * If it is the same as either, grow, else insert
3384 if (text_properties_equal(forward_prop
, font
, fore
, back
))
3386 /* Grow the property in front of us. */
3388 MARK_PROPERTY_LENGTH(mark
) += len
;
3390 else if (backward_prop
&&
3391 text_properties_equal(backward_prop
, font
, fore
, back
))
3393 /* Grow property behind us, point property and offset
3396 SET_PROPERTY_MARK (&text
->point
,
3397 MARK_PREV_LIST_PTR (mark
),
3398 backward_prop
->length
);
3400 backward_prop
->length
+= len
;
3402 else if ((MARK_NEXT_LIST_PTR(mark
) == NULL
) &&
3403 (forward_prop
->length
== 1))
3405 /* Next property just has last position, take it over */
3407 if (GTK_WIDGET_REALIZED (text
))
3408 unrealize_property (text
, forward_prop
);
3410 forward_prop
->flags
= 0;
3413 forward_prop
->flags
|= PROPERTY_FONT
;
3414 forward_prop
->font
= get_text_font (font
);
3417 forward_prop
->font
= NULL
;
3421 forward_prop
->flags
|= PROPERTY_FOREGROUND
;
3422 forward_prop
->fore_color
= *fore
;
3426 forward_prop
->flags
|= PROPERTY_BACKGROUND
;
3427 forward_prop
->back_color
= *back
;
3429 forward_prop
->length
+= len
;
3431 if (GTK_WIDGET_REALIZED (text
))
3432 realize_property (text
, forward_prop
);
3436 /* Splice a new property into the list. */
3438 GList
* new_prop
= g_list_alloc();
3440 new_prop
->next
= MARK_LIST_PTR(mark
);
3441 new_prop
->prev
= MARK_PREV_LIST_PTR(mark
);
3442 new_prop
->next
->prev
= new_prop
;
3445 new_prop
->prev
->next
= new_prop
;
3447 new_prop
->data
= new_text_property (text
, font
, fore
, back
, len
);
3449 SET_PROPERTY_MARK (mark
, new_prop
, 0);
3454 /* The following will screw up the line_start cache,
3455 * we'll fix it up in correct_cache_insert
3458 /* In the middle of forward_prop, if properties are equal,
3459 * just add to its length, else split it into two and splice
3461 if (text_properties_equal (forward_prop
, font
, fore
, back
))
3463 forward_prop
->length
+= len
;
3465 else if ((MARK_NEXT_LIST_PTR(mark
) == NULL
) &&
3466 (MARK_OFFSET(mark
) + 1 == forward_prop
->length
))
3468 /* Inserting before only the last position in the text */
3471 forward_prop
->length
-= 1;
3473 new_prop
= g_list_alloc();
3474 new_prop
->data
= new_text_property (text
, font
, fore
, back
, len
+1);
3475 new_prop
->prev
= MARK_LIST_PTR(mark
);
3476 new_prop
->next
= NULL
;
3477 MARK_NEXT_LIST_PTR(mark
) = new_prop
;
3479 SET_PROPERTY_MARK (mark
, new_prop
, 0);
3483 GList
* new_prop
= g_list_alloc();
3484 GList
* new_prop_forward
= g_list_alloc();
3485 gint old_length
= forward_prop
->length
;
3486 GList
* next
= MARK_NEXT_LIST_PTR(mark
);
3488 /* Set the new lengths according to where they are split. Construct
3489 * two new properties. */
3490 forward_prop
->length
= MARK_OFFSET(mark
);
3492 new_prop_forward
->data
=
3493 new_text_property(text
,
3494 forward_prop
->flags
& PROPERTY_FONT
?
3495 forward_prop
->font
->gdk_font
: NULL
,
3496 forward_prop
->flags
& PROPERTY_FOREGROUND
?
3497 &forward_prop
->fore_color
: NULL
,
3498 forward_prop
->flags
& PROPERTY_BACKGROUND
?
3499 &forward_prop
->back_color
: NULL
,
3500 old_length
- forward_prop
->length
);
3502 new_prop
->data
= new_text_property(text
, font
, fore
, back
, len
);
3504 /* Now splice things in. */
3505 MARK_NEXT_LIST_PTR(mark
) = new_prop
;
3506 new_prop
->prev
= MARK_LIST_PTR(mark
);
3508 new_prop
->next
= new_prop_forward
;
3509 new_prop_forward
->prev
= new_prop
;
3511 new_prop_forward
->next
= next
;
3514 next
->prev
= new_prop_forward
;
3516 SET_PROPERTY_MARK (mark
, new_prop
, 0);
3520 while (text
->text_properties_end
->next
)
3521 text
->text_properties_end
= text
->text_properties_end
->next
;
3523 while (text
->text_properties
->prev
)
3524 text
->text_properties
= text
->text_properties
->prev
;
3528 delete_text_property (GtkSText
* text
, guint nchars
)
3530 /* Delete nchars forward from point. */
3532 /* Deleting text properties is problematical, because we
3533 * might be storing around marks pointing to a property.
3535 * The marks in question and how we handle them are:
3537 * point: We know the new value, since it will be at the
3538 * end of the deleted text, and we move it there
3540 * cursor: We just remove the mark and set it equal to the
3541 * point after the operation.
3542 * line-start cache: We replace most affected lines.
3543 * The current line gets used to fetch the new
3544 * lines so, if necessary, (delete at the beginning
3545 * of a line) we fix it up by setting it equal to the
3553 for(; nchars
; nchars
-= 1)
3555 prop
= MARK_CURRENT_PROPERTY(&text
->point
);
3559 if (prop
->length
== 0)
3561 tmp
= MARK_LIST_PTR (&text
->point
);
3563 is_first
= tmp
== text
->text_properties
;
3565 MARK_LIST_PTR (&text
->point
) = g_list_remove_link (tmp
, tmp
);
3566 text
->point
.offset
= 0;
3568 if (GTK_WIDGET_REALIZED (text
))
3569 unrealize_property (text
, prop
);
3571 destroy_text_property (prop
);
3572 g_list_free_1 (tmp
);
3574 prop
= MARK_CURRENT_PROPERTY (&text
->point
);
3577 text
->text_properties
= MARK_LIST_PTR (&text
->point
);
3579 g_assert (prop
->length
!= 0);
3581 else if (prop
->length
== text
->point
.offset
)
3583 MARK_LIST_PTR (&text
->point
) = MARK_NEXT_LIST_PTR (&text
->point
);
3584 text
->point
.offset
= 0;
3588 /* Check to see if we have just the single final position remaining
3589 * along in a property; if so, combine it with the previous property
3591 if (LAST_INDEX (text
, text
->point
) &&
3592 (MARK_OFFSET (&text
->point
) == 0) &&
3593 (MARK_PREV_LIST_PTR(&text
->point
) != NULL
))
3595 tmp
= MARK_LIST_PTR (&text
->point
);
3596 prop
= MARK_CURRENT_PROPERTY(&text
->point
);
3598 MARK_LIST_PTR (&text
->point
) = MARK_PREV_LIST_PTR (&text
->point
);
3599 MARK_CURRENT_PROPERTY(&text
->point
)->length
+= 1;
3600 MARK_NEXT_LIST_PTR(&text
->point
) = NULL
;
3602 text
->point
.offset
= MARK_CURRENT_PROPERTY(&text
->point
)->length
- 1;
3604 if (GTK_WIDGET_REALIZED (text
))
3605 unrealize_property (text
, prop
);
3607 destroy_text_property (prop
);
3608 g_list_free_1 (tmp
);
3613 init_properties (GtkSText
*text
)
3615 if (!text
->text_properties
)
3617 text
->text_properties
= g_list_alloc();
3618 text
->text_properties
->next
= NULL
;
3619 text
->text_properties
->prev
= NULL
;
3620 text
->text_properties
->data
= new_text_property (text
, NULL
, NULL
, NULL
, 1);
3621 text
->text_properties_end
= text
->text_properties
;
3623 SET_PROPERTY_MARK (&text
->point
, text
->text_properties
, 0);
3625 text
->point
.index
= 0;
3630 /**********************************************************************/
3631 /* Property Movement */
3632 /**********************************************************************/
3635 move_mark_n (GtkSPropertyMark
* mark
, gint n
)
3638 advance_mark_n(mark
, n
);
3640 decrement_mark_n(mark
, -n
);
3644 advance_mark (GtkSPropertyMark
* mark
)
3646 TextProperty
* prop
= MARK_CURRENT_PROPERTY (mark
);
3650 if (prop
->length
> mark
->offset
+ 1)
3654 mark
->property
= MARK_NEXT_LIST_PTR (mark
);
3660 advance_mark_n (GtkSPropertyMark
* mark
, gint n
)
3667 i
= 0; /* otherwise it migth not be init. */
3668 prop
= MARK_CURRENT_PROPERTY(mark
);
3670 if ((prop
->length
- mark
->offset
- 1) < n
) { /* if we need to change prop. */
3671 /* to make it easier */
3672 n
+= (mark
->offset
);
3673 mark
->index
-= mark
->offset
;
3675 /* first we take seven-mile-leaps to get to the right text
3677 while ((n
-i
) > prop
->length
- 1) {
3679 mark
->index
+= prop
->length
;
3680 mark
->property
= MARK_NEXT_LIST_PTR (mark
);
3681 prop
= MARK_CURRENT_PROPERTY (mark
);
3685 /* and then the rest */
3686 mark
->index
+= n
- i
;
3687 mark
->offset
+= n
- i
;
3691 decrement_mark (GtkSPropertyMark
* mark
)
3695 if (mark
->offset
> 0)
3699 mark
->property
= MARK_PREV_LIST_PTR (mark
);
3700 mark
->offset
= MARK_CURRENT_PROPERTY (mark
)->length
- 1;
3705 decrement_mark_n (GtkSPropertyMark
* mark
, gint n
)
3709 while (mark
->offset
< n
) {
3710 /* jump to end of prev */
3711 n
-= mark
->offset
+ 1;
3712 mark
->index
-= mark
->offset
+ 1;
3713 mark
->property
= MARK_PREV_LIST_PTR (mark
);
3714 mark
->offset
= MARK_CURRENT_PROPERTY (mark
)->length
- 1;
3722 static GtkSPropertyMark
3723 find_mark (GtkSText
* text
, guint mark_position
)
3725 return find_mark_near (text
, mark_position
, &text
->point
);
3729 * You can also start from the end, what a drag.
3731 static GtkSPropertyMark
3732 find_mark_near (GtkSText
* text
, guint mark_position
, const GtkSPropertyMark
* near
)
3737 GtkSPropertyMark mark
;
3740 diffa
= mark_position
+ 1;
3742 diffa
= mark_position
- near
->index
;
3744 diffb
= mark_position
;
3756 mark
.property
= text
->text_properties
;
3760 move_mark_n (&mark
, mark_position
- mark
.index
);
3765 /* This routine must be called with scroll == FALSE, only when
3766 * point is at least partially on screen
3770 find_line_containing_point (GtkSText
* text
, guint point
,
3776 text
->current_line
= NULL
;
3780 /* Scroll backwards until the point is on screen
3782 while (CACHE_DATA(text
->line_start_cache
).start
.index
> point
)
3783 scroll_int (text
, - LINE_HEIGHT(CACHE_DATA(text
->line_start_cache
)));
3785 /* Now additionally try to make sure that the point is fully on screen
3789 while (text
->first_cut_pixels
!= 0 &&
3790 text
->line_start_cache
->next
&&
3791 CACHE_DATA(text
->line_start_cache
->next
).start
.index
> point
)
3792 scroll_int (text
, - LINE_HEIGHT(CACHE_DATA(text
->line_start_cache
->next
)));
3795 gdk_window_get_size (text
->text_area
, NULL
, &height
);
3797 for (cache
= text
->line_start_cache
; cache
; cache
= cache
->next
)
3801 if (CACHE_DATA(cache
).end
.index
>= point
||
3802 LAST_INDEX(text
, CACHE_DATA(cache
).end
))
3804 text
->current_line
= cache
; /* LOOK HERE, this proc has an
3805 * important side effect. */
3809 TEXT_SHOW_LINE (text
, cache
, "cache");
3811 if (cache
->next
== NULL
)
3812 fetch_lines_forward (text
, 1);
3816 lph
= pixel_height_of (text
, cache
->next
);
3818 /* Scroll the bottom of the line is on screen, or until
3819 * the line is the first onscreen line.
3821 while (cache
->next
!= text
->line_start_cache
&& lph
> height
)
3823 TEXT_SHOW_LINE (text
, cache
, "cache");
3824 TEXT_SHOW_LINE (text
, cache
->next
, "cache->next");
3825 scroll_int (text
, LINE_HEIGHT(CACHE_DATA(cache
->next
)));
3826 lph
= pixel_height_of (text
, cache
->next
);
3831 g_assert_not_reached (); /* Must set text->current_line here */
3835 pixel_height_of (GtkSText
* text
, GList
* cache_line
)
3837 gint pixels
= - text
->first_cut_pixels
;
3838 GList
*cache
= text
->line_start_cache
;
3841 pixels
+= LINE_HEIGHT (CACHE_DATA(cache
));
3843 if (cache
->data
== cache_line
->data
)
3846 cache
= cache
->next
;
3852 /**********************************************************************/
3853 /* Search and Placement */
3854 /**********************************************************************/
3857 find_char_width (GtkSText
* text
, const GtkSPropertyMark
*mark
, const TabStopMark
*tab_mark
)
3860 gint16
* char_widths
;
3862 if (LAST_INDEX (text
, *mark
))
3865 ch
= GTK_STEXT_INDEX (text
, mark
->index
);
3866 char_widths
= MARK_CURRENT_TEXT_FONT (text
, mark
)->char_widths
;
3870 return tab_mark
->to_next_tab
* char_widths
[' '];
3872 else if (!text
->use_wchar
)
3874 return char_widths
[ch
];
3878 return gdk_char_width_wc(MARK_CURRENT_TEXT_FONT(text
, mark
)->gdk_font
, ch
);
3883 advance_tab_mark (GtkSText
* text
, TabStopMark
* tab_mark
, GdkWChar ch
)
3885 if (tab_mark
->to_next_tab
== 1 || ch
== '\t')
3887 if (tab_mark
->tab_stops
->next
)
3889 tab_mark
->tab_stops
= tab_mark
->tab_stops
->next
;
3890 tab_mark
->to_next_tab
= (gulong
) tab_mark
->tab_stops
->data
;
3894 tab_mark
->to_next_tab
= text
->default_tab_width
;
3899 tab_mark
->to_next_tab
-= 1;
3904 advance_tab_mark_n (GtkSText
* text
, TabStopMark
* tab_mark
, gint n
)
3908 advance_tab_mark (text
, tab_mark
, 0);
3912 find_cursor_at_line (GtkSText
* text
, const LineParams
* start_line
, gint pixel_height
)
3915 GtkEditable
*editable
= (GtkEditable
*)text
;
3917 GtkSPropertyMark mark
= start_line
->start
;
3918 TabStopMark tab_mark
= start_line
->tab_cont
.tab_start
;
3919 gint pixel_width
= LINE_START_PIXEL (*start_line
);
3921 while (mark
.index
< text
->cursor_mark
.index
)
3923 pixel_width
+= find_char_width (text
, &mark
, &tab_mark
);
3925 advance_tab_mark (text
, &tab_mark
, GTK_STEXT_INDEX(text
, mark
.index
));
3926 advance_mark (&mark
);
3929 text
->cursor_pos_x
= pixel_width
;
3930 text
->cursor_pos_y
= pixel_height
;
3931 text
->cursor_char_offset
= start_line
->font_descent
;
3932 text
->cursor_mark
= mark
;
3934 ch
= LAST_INDEX (text
, mark
) ?
3935 LINE_DELIM
: GTK_STEXT_INDEX (text
, mark
.index
);
3937 if ((text
->use_wchar
) ? gdk_iswspace (ch
) : isspace (ch
))
3938 text
->cursor_char
= 0;
3940 text
->cursor_char
= ch
;
3942 #ifdef USE_GTKGDK_XIM
3943 if (GTK_WIDGET_HAS_FOCUS(text
) && gdk_im_ready() && editable
->ic
&&
3944 (gdk_ic_get_style (editable
->ic
) & GDK_IM_PREEDIT_POSITION
))
3946 GdkICAttributesType mask
= GDK_IC_SPOT_LOCATION
|
3947 GDK_IC_PREEDIT_FOREGROUND
|
3948 GDK_IC_PREEDIT_BACKGROUND
;
3950 editable
->ic_attr
->spot_location
.x
= text
->cursor_pos_x
;
3951 editable
->ic_attr
->spot_location
.y
3952 = text
->cursor_pos_y
- text
->cursor_char_offset
;
3953 editable
->ic_attr
->preedit_foreground
= *MARK_CURRENT_FORE (text
, &mark
);
3954 editable
->ic_attr
->preedit_background
= *MARK_CURRENT_BACK (text
, &mark
);
3956 if (MARK_CURRENT_FONT (text
, &mark
)->type
== GDK_FONT_FONTSET
)
3958 mask
|= GDK_IC_PREEDIT_FONTSET
;
3959 editable
->ic_attr
->preedit_fontset
= MARK_CURRENT_FONT (text
, &mark
);
3962 gdk_ic_set_attr (editable
->ic
, editable
->ic_attr
, mask
);
3968 find_cursor (GtkSText
* text
, gboolean scroll
)
3970 if (GTK_WIDGET_REALIZED (text
))
3972 find_line_containing_point (text
, text
->cursor_mark
.index
, scroll
);
3974 if (text
->current_line
)
3975 find_cursor_at_line (text
,
3976 &CACHE_DATA(text
->current_line
),
3977 pixel_height_of(text
, text
->current_line
));
3980 GTK_EDITABLE (text
)->current_pos
= text
->cursor_mark
.index
;
3984 find_mouse_cursor_at_line (GtkSText
*text
, const LineParams
* lp
,
3985 guint line_pixel_height
,
3988 GtkSPropertyMark mark
= lp
->start
;
3989 TabStopMark tab_mark
= lp
->tab_cont
.tab_start
;
3991 gint char_width
= find_char_width(text
, &mark
, &tab_mark
);
3992 gint pixel_width
= LINE_START_PIXEL (*lp
) + (char_width
+1)/2;
3994 text
->cursor_pos_y
= line_pixel_height
;
3998 GdkWChar ch
= LAST_INDEX (text
, mark
) ?
3999 LINE_DELIM
: GTK_STEXT_INDEX (text
, mark
.index
);
4001 if (button_x
< pixel_width
|| mark
.index
== lp
->end
.index
)
4003 text
->cursor_pos_x
= pixel_width
- (char_width
+1)/2;
4004 text
->cursor_mark
= mark
;
4005 text
->cursor_char_offset
= lp
->font_descent
;
4007 if ((text
->use_wchar
) ? gdk_iswspace (ch
) : isspace (ch
))
4008 text
->cursor_char
= 0;
4010 text
->cursor_char
= ch
;
4015 advance_tab_mark (text
, &tab_mark
, ch
);
4016 advance_mark (&mark
);
4018 pixel_width
+= char_width
/2;
4020 char_width
= find_char_width (text
, &mark
, &tab_mark
);
4022 pixel_width
+= (char_width
+1)/2;
4027 find_mouse_cursor (GtkSText
* text
, gint x
, gint y
)
4030 GList
* cache
= text
->line_start_cache
;
4034 pixel_height
= - text
->first_cut_pixels
;
4036 for (; cache
; cache
= cache
->next
)
4038 pixel_height
+= LINE_HEIGHT(CACHE_DATA(cache
));
4040 if (y
< pixel_height
|| !cache
->next
)
4042 find_mouse_cursor_at_line (text
, &CACHE_DATA(cache
), pixel_height
, x
);
4044 find_cursor (text
, FALSE
);
4051 /**********************************************************************/
4053 /**********************************************************************/
4056 free_cache (GtkSText
* text
)
4058 GList
* cache
= text
->line_start_cache
;
4063 cache
= cache
->prev
;
4065 text
->line_start_cache
= cache
;
4068 for (; cache
; cache
= cache
->next
)
4069 g_mem_chunk_free (params_mem_chunk
, cache
->data
);
4071 g_list_free (text
->line_start_cache
);
4073 text
->line_start_cache
= NULL
;
4077 remove_cache_line (GtkSText
* text
, GList
* member
)
4084 if (member
== text
->line_start_cache
)
4085 text
->line_start_cache
= text
->line_start_cache
->next
;
4088 member
->prev
->next
= member
->next
;
4091 member
->next
->prev
= member
->prev
;
4093 list
= member
->next
;
4095 g_mem_chunk_free (params_mem_chunk
, member
->data
);
4096 g_list_free_1 (member
);
4101 /**********************************************************************/
4103 /**********************************************************************/
4106 move_cursor_buffer_ver (GtkSText
*text
, int dir
)
4108 undraw_cursor (text
, FALSE
);
4112 scroll_int (text
, text
->vadj
->upper
);
4113 text
->cursor_mark
= find_this_line_start_mark (text
,
4115 &text
->cursor_mark
);
4119 scroll_int (text
, - text
->vadj
->value
);
4120 text
->cursor_mark
= find_this_line_start_mark (text
,
4122 &text
->cursor_mark
);
4125 find_cursor (text
, TRUE
);
4126 draw_cursor (text
, FALSE
);
4130 move_cursor_page_ver (GtkSText
*text
, int dir
)
4132 scroll_int (text
, dir
* text
->vadj
->page_increment
);
4136 move_cursor_ver (GtkSText
*text
, int count
)
4139 GtkSPropertyMark mark
;
4142 mark
= find_this_line_start_mark (text
, text
->cursor_mark
.index
, &text
->cursor_mark
);
4143 offset
= text
->cursor_mark
.index
- mark
.index
;
4145 if (offset
> text
->cursor_virtual_x
)
4146 text
->cursor_virtual_x
= offset
;
4150 if (mark
.index
== 0)
4153 decrement_mark (&mark
);
4154 mark
= find_this_line_start_mark (text
, mark
.index
, &mark
);
4158 mark
= text
->cursor_mark
;
4160 while (!LAST_INDEX(text
, mark
) && GTK_STEXT_INDEX(text
, mark
.index
) != LINE_DELIM
)
4161 advance_mark (&mark
);
4163 if (LAST_INDEX(text
, mark
))
4166 advance_mark (&mark
);
4169 for (i
=0; i
< text
->cursor_virtual_x
; i
+= 1, advance_mark(&mark
))
4170 if (LAST_INDEX(text
, mark
) ||
4171 GTK_STEXT_INDEX(text
, mark
.index
) == LINE_DELIM
)
4174 undraw_cursor (text
, FALSE
);
4176 text
->cursor_mark
= mark
;
4178 find_cursor (text
, TRUE
);
4180 draw_cursor (text
, FALSE
);
4184 move_cursor_hor (GtkSText
*text
, int count
)
4186 /* count should be +-1. */
4187 if ( (count
> 0 && text
->cursor_mark
.index
+ count
> TEXT_LENGTH(text
)) ||
4188 (count
< 0 && text
->cursor_mark
.index
< (- count
)) ||
4192 text
->cursor_virtual_x
= 0;
4194 undraw_cursor (text
, FALSE
);
4196 move_mark_n (&text
->cursor_mark
, count
);
4198 find_cursor (text
, TRUE
);
4200 draw_cursor (text
, FALSE
);
4203 /* SYLPHEED - the default cursor movement of GtkText is aeons ahead of the
4204 * current technology level of the current generation of programmers and
4205 * end users. so sylpheed has to take a more mundane approach to editing.
4208 * move_cursor_to_display_row_end() (end of display line)
4209 * move_cursor_to_display_row_home() (home of display line)
4210 * move_cursor_to_display_row_up() (line up)
4211 * move_cursor_to_display_row_down() (line down)
4215 * SYLPHEED_TODO: for some reason the line fetcher also returns markers
4216 * of just one character! should investigate this... -- alfons
4219 static void move_cursor_to_display_row_end(GtkSText
*text
)
4221 LineParams lp
= CACHE_DATA(text
->current_line
);
4222 int to_move
= (lp
.end
.index
- text
->cursor_mark
.index
);
4224 /* advance this much */
4226 move_cursor_hor(text
, to_move
);
4230 static void move_cursor_to_display_row_start(GtkSText
*text
)
4232 LineParams lp
= CACHE_DATA(text
->current_line
);
4233 int to_move
= (text
->cursor_mark
.index
- lp
.start
.index
);
4235 move_cursor_hor(text
, -to_move
);
4240 static gboolean
range_intersect(guint x1
, guint x2
, guint y1
, guint y2
)
4243 if (x1
> x2
) { tmp
= x1
; x1
= x2
; x2
= tmp
; }
4244 if (y1
> y2
) { tmp
= y1
; y1
= y2
; y1
= tmp
; }
4245 if (y1
< x1
) { tmp
= x1
; x1
= y1
; y1
= tmp
; tmp
= x2
; x2
= y2
; y2
= tmp
; }
4255 static gint
back_display_row_fetcher(GtkSText
*text
,
4259 if (range_intersect(data
->start
, data
->end
, params
->start
.index
, params
->end
.index
)) {
4260 XDEBUG( ("%s(%d) - FOUND search (%d, %d), current (%d, %d)", __FILE__
, __LINE__
,
4261 data
->start
, data
->end
,
4262 params
->start
.index
, params
->end
.index
) );
4267 XDEBUG( ("%s(%d) - NEXT search (%d, %d), current (%d, %d)", __FILE__
, __LINE__
,
4268 data
->start
, data
->end
,
4269 params
->start
.index
, params
->end
.index
) );
4275 static void move_cursor_to_display_row_up(GtkSText
*text
)
4281 GtkSPropertyMark mark
;
4283 mark
= find_this_line_start_mark(text
, text
->cursor_mark
.index
, &text
->cursor_mark
);
4286 if (mark
.index
== 0) {
4287 XDEBUG ( ("%s(%d) top of buffer", __FILE__
, __LINE__
) );
4290 /* we need previous DISPLAY row not the previous BUFFER line, so we go to start
4291 * of paragraph, and iterate over the lines until we have a LineParams that matches
4293 lp
= CACHE_DATA(text
->current_line
);
4294 col
= (text
->cursor_mark
.index
- lp
.start
.index
);
4295 data
.start
= lp
.start
.index
;
4296 data
.end
= lp
.end
.index
;
4298 /* get the previous line */
4299 if (mark
.index
!= 0) {
4300 decrement_mark(&mark
);
4301 if (mark
.index
!= 0) {
4302 GtkSPropertyMark smark
= mark
;
4303 XDEBUG( ("%s(%d) finding line start mark", __FILE__
, __LINE__
) );
4304 mark
= find_this_line_start_mark(text
, smark
.index
-1, &smark
);
4308 /* let's get the previous display line */
4309 XDEBUG( ("%s(%d) iterating to get display lines", __FILE__
, __LINE__
) );
4310 line_params_iterate(text
, &mark
, NULL
, FALSE
, &data
,
4311 (LineIteratorFunction
)back_display_row_fetcher
);
4312 XDEBUG( ("%s(%d) done iterating. found = %d", __FILE__
, __LINE__
, data
.found
) );
4315 if (col
< text
->persist_column
) col
= text
->persist_column
;
4316 else text
->persist_column
= col
;
4317 new_index
= data
.lp
.start
.index
+ col
;
4318 XDEBUG( ("%s(%d) - new index = %d", __FILE__
, __LINE__
, new_index
) );
4319 if (new_index
> data
.lp
.end
.index
) {
4320 new_index
= data
.lp
.end
.index
;
4322 /* and move the cursor */
4323 XDEBUG( ("%s(%d) - setting index", __FILE__
, __LINE__
) );
4324 gtk_stext_set_position_X(GTK_EDITABLE(text
), new_index
);
4335 #if defined(AHX_DEBUG)
4336 static void print_line(GtkSText
*text
, guint start
, guint end
)
4338 gchar
*buf
= alloca(2048), *walk
= buf
;
4340 memset(buf
, 0, 2048);
4341 for (; start
<= end
; start
++) {
4342 *walk
++ = GTK_STEXT_INDEX(text
, start
);
4344 XDEBUG( ("%s", buf
) );
4348 static gint
forward_display_row_fetcher(GtkSText
*text
,
4353 XDEBUG( ("%s(%d) - FW RETURNS. search (%d, %d), current (%d, %d)",
4354 __FILE__
, __LINE__
, data
->start
, data
->end
, lp
->start
.index
, lp
->end
.index
) );
4356 data
->completed
= TRUE
;
4357 print_line(text
, lp
->start
.index
, lp
->end
.index
);
4360 else if (range_intersect(data
->start
, data
->end
, lp
->start
.index
, lp
->end
.index
)) {
4361 XDEBUG( ("%s(%d) - FW FOUND IT. search (%d, %d), current (%d, %d)",
4362 __FILE__
, __LINE__
, data
->start
, data
->end
, lp
->start
.index
, lp
->end
.index
) );
4371 static void move_cursor_to_display_row_down (GtkSText
*text
)
4376 GtkSPropertyMark mark
;
4377 fdrf data
= { FALSE
, FALSE
};
4379 mark
= find_this_line_start_mark(text
, text
->cursor_mark
.index
, &text
->cursor_mark
);
4380 lp
= CACHE_DATA(text
->current_line
);
4381 col
= (text
->cursor_mark
.index
- lp
.start
.index
);
4383 data
.start
= lp
.start
.index
;
4384 data
.end
= lp
.end
.index
;
4386 /* find the next DISPLAY line */
4387 XDEBUG( ("%s(%d) - FW iterating", __FILE__
, __LINE__
) ) ;
4388 line_params_iterate(text
, &mark
, NULL
, FALSE
, &data
,
4389 (LineIteratorFunction
)forward_display_row_fetcher
);
4390 XDEBUG( ("%s(%d) - FW done iterating", __FILE__
, __LINE__
) );
4392 if (data
.completed
) {
4393 if (col
< text
->persist_column
) col
= text
->persist_column
;
4394 else text
->persist_column
= col
;
4395 new_index
= data
.lp
.start
.index
+ col
;
4396 if (new_index
> data
.lp
.end
.index
) {
4397 new_index
= data
.lp
.end
.index
;
4399 /* and move the cursor */
4400 XDEBUG( ("%s(%d) - FW set pos %d", __FILE__
, __LINE__
, new_index
) );
4401 gtk_stext_set_position_X(GTK_EDITABLE(text
), new_index
);
4405 static void reset_persist_col_pos(GtkSText
*text
)
4407 text
->persist_column
= 0;
4411 gtk_stext_move_cursor (GtkEditable
*editable
,
4418 move_cursor_hor (GTK_STEXT (editable
), 1);
4423 move_cursor_hor (GTK_STEXT (editable
), -1);
4429 move_cursor_ver (GTK_STEXT (editable
), 1);
4434 move_cursor_ver (GTK_STEXT (editable
), -1);
4439 gtk_stext_move_forward_character (GtkSText
*text
)
4441 move_cursor_hor (text
, 1);
4445 gtk_stext_move_backward_character (GtkSText
*text
)
4447 move_cursor_hor (text
, -1);
4451 gtk_stext_move_next_line (GtkSText
*text
)
4453 move_cursor_ver (text
, 1);
4457 gtk_stext_move_previous_line (GtkSText
*text
)
4459 move_cursor_ver (text
, -1);
4463 gtk_stext_move_word (GtkEditable
*editable
,
4469 gtk_stext_move_forward_word (GTK_STEXT (editable
));
4474 gtk_stext_move_backward_word (GTK_STEXT (editable
));
4479 gtk_stext_move_forward_word (GtkSText
*text
)
4481 text
->cursor_virtual_x
= 0;
4483 undraw_cursor (text
, FALSE
);
4485 if (text
->use_wchar
)
4487 while (!LAST_INDEX (text
, text
->cursor_mark
) &&
4488 !gdk_iswalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
)))
4489 advance_mark (&text
->cursor_mark
);
4491 while (!LAST_INDEX (text
, text
->cursor_mark
) &&
4492 gdk_iswalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
)))
4493 advance_mark (&text
->cursor_mark
);
4497 while (!LAST_INDEX (text
, text
->cursor_mark
) &&
4498 !isalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
)))
4499 advance_mark (&text
->cursor_mark
);
4501 while (!LAST_INDEX (text
, text
->cursor_mark
) &&
4502 isalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
)))
4503 advance_mark (&text
->cursor_mark
);
4506 find_cursor (text
, TRUE
);
4507 draw_cursor (text
, FALSE
);
4511 gtk_stext_move_backward_word (GtkSText
*text
)
4513 text
->cursor_virtual_x
= 0;
4515 undraw_cursor (text
, FALSE
);
4517 if (text
->use_wchar
)
4519 while ((text
->cursor_mark
.index
> 0) &&
4520 !gdk_iswalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
-1)))
4521 decrement_mark (&text
->cursor_mark
);
4523 while ((text
->cursor_mark
.index
> 0) &&
4524 gdk_iswalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
-1)))
4525 decrement_mark (&text
->cursor_mark
);
4529 while ((text
->cursor_mark
.index
> 0) &&
4530 !isalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
-1)))
4531 decrement_mark (&text
->cursor_mark
);
4533 while ((text
->cursor_mark
.index
> 0) &&
4534 isalnum (GTK_STEXT_INDEX(text
, text
->cursor_mark
.index
-1)))
4535 decrement_mark (&text
->cursor_mark
);
4538 find_cursor (text
, TRUE
);
4539 draw_cursor (text
, FALSE
);
4543 gtk_stext_move_page (GtkEditable
*editable
,
4548 scroll_int (GTK_STEXT (editable
),
4549 y
* GTK_STEXT(editable
)->vadj
->page_increment
);
4553 gtk_stext_move_to_row (GtkEditable
*editable
,
4559 gtk_stext_move_to_column (GtkEditable
*editable
,
4564 text
= GTK_STEXT (editable
);
4566 text
->cursor_virtual_x
= 0; /* FIXME */
4568 undraw_cursor (text
, FALSE
);
4570 /* Move to the beginning of the line */
4571 while ((text
->cursor_mark
.index
> 0) &&
4572 (GTK_STEXT_INDEX (text
, text
->cursor_mark
.index
- 1) != LINE_DELIM
))
4573 decrement_mark (&text
->cursor_mark
);
4575 while (!LAST_INDEX (text
, text
->cursor_mark
) &&
4576 (GTK_STEXT_INDEX (text
, text
->cursor_mark
.index
) != LINE_DELIM
))
4580 else if (column
== 0)
4583 advance_mark (&text
->cursor_mark
);
4586 find_cursor (text
, TRUE
);
4587 draw_cursor (text
, FALSE
);
4591 gtk_stext_move_beginning_of_line (GtkSText
*text
)
4593 gtk_stext_move_to_column (GTK_EDITABLE (text
), 0);
4598 gtk_stext_move_end_of_line (GtkSText
*text
)
4600 gtk_stext_move_to_column (GTK_EDITABLE (text
), -1);
4604 gtk_stext_kill_char (GtkEditable
*editable
,
4609 text
= GTK_STEXT (editable
);
4611 if (editable
->selection_start_pos
!= editable
->selection_end_pos
)
4612 gtk_editable_delete_selection (editable
);
4617 if (text
->point
.index
+ 1 <= TEXT_LENGTH (text
))
4618 gtk_editable_delete_text (editable
, text
->point
.index
, text
->point
.index
+ 1);
4622 if (text
->point
.index
> 0)
4623 gtk_editable_delete_text (editable
, text
->point
.index
- 1, text
->point
.index
);
4629 gtk_stext_delete_forward_character (GtkSText
*text
)
4631 gtk_stext_kill_char (GTK_EDITABLE (text
), 1);
4635 gtk_stext_delete_backward_character (GtkSText
*text
)
4637 gtk_stext_kill_char (GTK_EDITABLE (text
), -1);
4641 gtk_stext_kill_word (GtkEditable
*editable
,
4644 if (editable
->selection_start_pos
!= editable
->selection_end_pos
) {
4645 gtk_editable_delete_selection (editable
);
4649 gint old_pos
= editable
->current_pos
;
4652 gtk_stext_move_word (editable
, 1);
4653 gtk_editable_delete_text (editable
, old_pos
, editable
->current_pos
);
4657 gtk_stext_move_word (editable
, -1);
4658 gtk_editable_delete_text (editable
, editable
->current_pos
, old_pos
);
4664 gtk_stext_delete_forward_word (GtkSText
*text
)
4666 gtk_stext_kill_word (GTK_EDITABLE (text
), 1);
4670 gtk_stext_delete_backward_word (GtkSText
*text
)
4672 gtk_stext_kill_word (GTK_EDITABLE (text
), -1);
4676 gtk_stext_kill_line (GtkEditable
*editable
,
4679 gint old_pos
= editable
->current_pos
;
4682 gtk_stext_move_to_column (editable
, -1);
4683 gtk_editable_delete_text (editable
, old_pos
, editable
->current_pos
);
4687 gtk_stext_move_to_column (editable
, 0);
4688 gtk_editable_delete_text (editable
, editable
->current_pos
, old_pos
);
4693 gtk_stext_delete_line (GtkSText
*text
)
4695 gtk_stext_move_to_column (GTK_EDITABLE (text
), 0);
4696 gtk_stext_kill_line (GTK_EDITABLE (text
), 1);
4700 gtk_stext_delete_to_line_end (GtkSText
*text
)
4702 gtk_stext_kill_line (GTK_EDITABLE (text
), 1);
4706 gtk_stext_select_word (GtkSText
*text
, guint32 time
)
4711 GtkEditable
*editable
;
4712 editable
= GTK_EDITABLE (text
);
4714 gtk_stext_move_backward_word (text
);
4715 start_pos
= text
->cursor_mark
.index
;
4717 gtk_stext_move_forward_word (text
);
4718 end_pos
= text
->cursor_mark
.index
;
4720 editable
->has_selection
= TRUE
;
4721 gtk_stext_set_selection (editable
, start_pos
, end_pos
);
4722 gtk_editable_claim_selection (editable
, start_pos
!= end_pos
, time
);
4726 gtk_stext_select_line (GtkSText
*text
, guint32 time
)
4731 GtkEditable
*editable
;
4732 editable
= GTK_EDITABLE (text
);
4734 gtk_stext_move_beginning_of_line (text
);
4735 start_pos
= text
->cursor_mark
.index
;
4737 gtk_stext_move_end_of_line (text
);
4738 gtk_stext_move_forward_character (text
);
4739 end_pos
= text
->cursor_mark
.index
;
4741 editable
->has_selection
= TRUE
;
4742 gtk_stext_set_selection (editable
, start_pos
, end_pos
);
4743 gtk_editable_claim_selection (editable
, start_pos
!= end_pos
, time
);
4746 /**********************************************************************/
4748 /**********************************************************************/
4751 adjust_adj (GtkSText
* text
, GtkAdjustment
* adj
)
4755 gdk_window_get_size (text
->text_area
, NULL
, &height
);
4757 adj
->step_increment
= MIN (adj
->upper
, (float) SCROLL_PIXELS
);
4758 adj
->page_increment
= MIN (adj
->upper
, height
- (float) KEY_SCROLL_PIXELS
);
4759 adj
->page_size
= MIN (adj
->upper
, height
);
4760 adj
->value
= MIN (adj
->value
, adj
->upper
- adj
->page_size
);
4761 adj
->value
= MAX (adj
->value
, 0.0);
4763 gtk_signal_emit_by_name (GTK_OBJECT (adj
), "changed");
4767 set_vertical_scroll_iterator (GtkSText
* text
, LineParams
* lp
, void* data
)
4769 SetVerticalScrollData
*svdata
= (SetVerticalScrollData
*) data
;
4771 if ((text
->first_line_start_index
>= lp
->start
.index
) &&
4772 (text
->first_line_start_index
<= lp
->end
.index
))
4774 svdata
->mark
= lp
->start
;
4776 if (text
->first_line_start_index
== lp
->start
.index
)
4778 text
->first_onscreen_ver_pixel
= svdata
->pixel_height
+ text
->first_cut_pixels
;
4782 text
->first_onscreen_ver_pixel
= svdata
->pixel_height
;
4783 text
->first_cut_pixels
= 0;
4786 text
->vadj
->value
= (float) text
->first_onscreen_ver_pixel
;
4789 svdata
->pixel_height
+= LINE_HEIGHT (*lp
);
4795 set_vertical_scroll_find_iterator (GtkSText
* text
, LineParams
* lp
, void* data
)
4797 SetVerticalScrollData
*svdata
= (SetVerticalScrollData
*) data
;
4800 if (svdata
->pixel_height
<= (gint
) text
->vadj
->value
&&
4801 svdata
->pixel_height
+ LINE_HEIGHT(*lp
) > (gint
) text
->vadj
->value
)
4803 svdata
->mark
= lp
->start
;
4805 text
->first_cut_pixels
= (gint
)text
->vadj
->value
- svdata
->pixel_height
;
4806 text
->first_onscreen_ver_pixel
= svdata
->pixel_height
;
4807 text
->first_line_start_index
= lp
->start
.index
;
4813 svdata
->pixel_height
+= LINE_HEIGHT (*lp
);
4821 static GtkSPropertyMark
4822 set_vertical_scroll (GtkSText
* text
)
4824 GtkSPropertyMark mark
= find_mark (text
, 0);
4825 SetVerticalScrollData data
;
4829 data
.pixel_height
= 0;
4830 line_params_iterate (text
, &mark
, NULL
, FALSE
, &data
, set_vertical_scroll_iterator
);
4832 text
->vadj
->upper
= (float) data
.pixel_height
;
4833 orig_value
= (gint
) text
->vadj
->value
;
4835 gdk_window_get_size (text
->text_area
, NULL
, &height
);
4837 text
->vadj
->step_increment
= MIN (text
->vadj
->upper
, (float) SCROLL_PIXELS
);
4838 text
->vadj
->page_increment
= MIN (text
->vadj
->upper
, height
- (float) KEY_SCROLL_PIXELS
);
4839 text
->vadj
->page_size
= MIN (text
->vadj
->upper
, height
);
4840 text
->vadj
->value
= MIN (text
->vadj
->value
, text
->vadj
->upper
- text
->vadj
->page_size
);
4841 text
->vadj
->value
= MAX (text
->vadj
->value
, 0.0);
4843 text
->last_ver_value
= (gint
)text
->vadj
->value
;
4845 gtk_signal_emit_by_name (GTK_OBJECT (text
->vadj
), "changed");
4847 if (text
->vadj
->value
!= orig_value
)
4849 /* We got clipped, and don't really know which line to put first. */
4850 data
.pixel_height
= 0;
4851 data
.last_didnt_wrap
= TRUE
;
4853 line_params_iterate (text
, &mark
, NULL
,
4855 set_vertical_scroll_find_iterator
);
4862 scroll_int (GtkSText
* text
, gint diff
)
4866 text
->vadj
->value
+= diff
;
4868 upper
= text
->vadj
->upper
- text
->vadj
->page_size
;
4869 text
->vadj
->value
= MIN (text
->vadj
->value
, upper
);
4870 text
->vadj
->value
= MAX (text
->vadj
->value
, 0.0);
4872 gtk_signal_emit_by_name (GTK_OBJECT (text
->vadj
), "value_changed");
4876 process_exposes (GtkSText
*text
)
4880 /* Make sure graphics expose events are processed before scrolling
4883 while ((event
= gdk_event_get_graphics_expose (text
->text_area
)) != NULL
)
4885 gtk_widget_event (GTK_WIDGET (text
), event
);
4886 if (event
->expose
.count
== 0)
4888 gdk_event_free (event
);
4891 gdk_event_free (event
);
4895 static gint
last_visible_line_height (GtkSText
* text
)
4897 GList
*cache
= text
->line_start_cache
;
4900 gdk_window_get_size (text
->text_area
, NULL
, &height
);
4902 for (; cache
->next
; cache
= cache
->next
)
4903 if (pixel_height_of(text
, cache
->next
) > height
)
4907 return pixel_height_of(text
, cache
) - 1;
4912 static gint
first_visible_line_height (GtkSText
* text
)
4914 if (text
->first_cut_pixels
)
4915 return pixel_height_of(text
, text
->line_start_cache
) + 1;
4921 scroll_down (GtkSText
* text
, gint diff0
)
4927 text
->first_onscreen_ver_pixel
+= diff0
;
4931 if (text
->first_cut_pixels
< LINE_HEIGHT(CACHE_DATA(text
->line_start_cache
)) - 1)
4933 text
->first_cut_pixels
+= 1;
4937 text
->first_cut_pixels
= 0;
4939 text
->line_start_cache
= text
->line_start_cache
->next
;
4940 g_assert (text
->line_start_cache
);
4942 text
->first_line_start_index
=
4943 CACHE_DATA(text
->line_start_cache
).start
.index
;
4945 if (!text
->line_start_cache
->next
)
4946 fetch_lines_forward (text
, 1);
4952 gdk_window_get_size (text
->text_area
, &width
, &height
);
4953 if (height
> real_diff
)
4954 gdk_draw_pixmap (text
->text_area
,
4962 height
- real_diff
);
4965 rect
.y
= MAX (0, height
- real_diff
);
4967 rect
.height
= MIN (height
, real_diff
);
4969 expose_text (text
, &rect
, FALSE
);
4970 gtk_stext_draw_focus ( (GtkWidget
*) text
);
4972 if (text
->current_line
)
4976 text
->cursor_pos_y
-= real_diff
;
4977 cursor_min
= drawn_cursor_min(text
);
4980 find_mouse_cursor (text
, text
->cursor_pos_x
,
4981 first_visible_line_height (text
));
4984 if (height
> real_diff
)
4985 process_exposes (text
);
4989 scroll_up (GtkSText
* text
, gint diff0
)
4995 text
->first_onscreen_ver_pixel
+= diff0
;
4999 g_assert (text
->line_start_cache
);
5001 if (text
->first_cut_pixels
> 0)
5003 text
->first_cut_pixels
-= 1;
5007 if (!text
->line_start_cache
->prev
)
5008 fetch_lines_backward (text
);
5010 text
->line_start_cache
= text
->line_start_cache
->prev
;
5012 text
->first_line_start_index
=
5013 CACHE_DATA(text
->line_start_cache
).start
.index
;
5015 text
->first_cut_pixels
= LINE_HEIGHT(CACHE_DATA(text
->line_start_cache
)) - 1;
5021 gdk_window_get_size (text
->text_area
, &width
, &height
);
5022 if (height
> real_diff
)
5023 gdk_draw_pixmap (text
->text_area
,
5031 height
- real_diff
);
5036 rect
.height
= MIN (height
, real_diff
);
5038 expose_text (text
, &rect
, FALSE
);
5039 gtk_stext_draw_focus ( (GtkWidget
*) text
);
5041 if (text
->current_line
)
5046 text
->cursor_pos_y
+= real_diff
;
5047 cursor_max
= drawn_cursor_max(text
);
5048 gdk_window_get_size (text
->text_area
, NULL
, &height
);
5050 if (cursor_max
>= height
)
5051 find_mouse_cursor (text
, text
->cursor_pos_x
,
5052 last_visible_line_height (text
));
5055 if (height
> real_diff
)
5056 process_exposes (text
);
5059 /**********************************************************************/
5061 /**********************************************************************/
5063 /* Assumes mark starts a line. Calculates the height, width, and
5064 * displayable character count of a single DISPLAYABLE line. That
5065 * means that in line-wrap mode, this does may not compute the
5066 * properties of an entire line. */
5068 find_line_params (GtkSText
* text
,
5069 const GtkSPropertyMark
* mark
,
5070 const PrevTabCont
*tab_cont
,
5071 PrevTabCont
*next_cont
)
5074 TabStopMark tab_mark
= tab_cont
->tab_start
;
5075 guint max_display_pixels
;
5080 gdk_window_get_size (text
->text_area
, (gint
*) &max_display_pixels
, NULL
);
5082 if (text
->wrap_rmargin
) {
5083 /* SYLPHEED - since sylpheed is a mail program, assume we work with
5084 * fixed fonts. only assume we're using one font! */
5085 font
= MARK_CURRENT_FONT(text
, mark
);
5087 /* SYLPHEED - ok for multi byte charsets to check for ASCII char?
5089 if (text
->use_wchar
)
5090 ch_width
= gdk_char_width_wc(font
, 'W');
5092 ch_width
= gdk_char_width(font
, 'W');
5094 /* SYLPHEED - max_display_chars has the rmargin in pixels
5096 max_display_pixels
= text
->wrap_rmargin
* ch_width
;
5099 if (GTK_EDITABLE (text
)->editable
|| !text
->word_wrap
)
5100 max_display_pixels
-= LINE_WRAP_ROOM
;
5103 lp
.tab_cont
= *tab_cont
;
5106 lp
.pixel_width
= tab_cont
->pixel_offset
;
5107 lp
.displayable_chars
= 0;
5109 lp
.font_descent
= 0;
5111 init_tab_cont (text
, next_cont
);
5113 while (!LAST_INDEX(text
, lp
.end
))
5115 g_assert (lp
.end
.property
);
5117 ch
= GTK_STEXT_INDEX (text
, lp
.end
.index
);
5118 font
= MARK_CURRENT_FONT (text
, &lp
.end
);
5120 if (ch
== LINE_DELIM
)
5122 /* Newline doesn't count in computation of line height, even
5123 * if its in a bigger font than the rest of the line. Unless,
5124 * of course, there are no other characters. */
5126 if (!lp
.font_ascent
&& !lp
.font_descent
)
5128 lp
.font_ascent
= font
->ascent
;
5129 lp
.font_descent
= font
->descent
;
5132 lp
.tab_cont_next
= *next_cont
;
5137 ch_width
= find_char_width (text
, &lp
.end
, &tab_mark
);
5139 if ((ch_width
+ lp
.pixel_width
> max_display_pixels
) &&
5140 (lp
.end
.index
> lp
.start
.index
))
5144 if (text
->line_wrap
)
5146 next_cont
->tab_start
= tab_mark
;
5147 next_cont
->pixel_offset
= 0;
5151 /* Here's the tough case, a tab is wrapping. */
5152 gint pixels_avail
= max_display_pixels
- lp
.pixel_width
;
5153 gint space_width
= MARK_CURRENT_TEXT_FONT(text
, &lp
.end
)->char_widths
[' '];
5154 gint spaces_avail
= pixels_avail
/ space_width
;
5156 if (spaces_avail
== 0)
5158 decrement_mark (&lp
.end
);
5162 advance_tab_mark (text
, &next_cont
->tab_start
, '\t');
5163 next_cont
->pixel_offset
= space_width
* (tab_mark
.to_next_tab
-
5165 lp
.displayable_chars
+= 1;
5170 if (text
->word_wrap
)
5172 GtkSPropertyMark saved_mark
= lp
.end
;
5173 guint saved_characters
= lp
.displayable_chars
;
5175 lp
.displayable_chars
+= 1;
5177 if (text
->use_wchar
)
5179 while (!gdk_iswspace (GTK_STEXT_INDEX (text
, lp
.end
.index
)) &&
5180 (lp
.end
.index
> lp
.start
.index
))
5182 decrement_mark (&lp
.end
);
5183 lp
.displayable_chars
-= 1;
5188 while (!isspace(GTK_STEXT_INDEX (text
, lp
.end
.index
)) &&
5189 (lp
.end
.index
> lp
.start
.index
))
5191 decrement_mark (&lp
.end
);
5192 lp
.displayable_chars
-= 1;
5196 /* If whole line is one word, revert to char wrapping */
5197 if (lp
.end
.index
== lp
.start
.index
)
5199 lp
.end
= saved_mark
;
5200 lp
.displayable_chars
= saved_characters
;
5201 decrement_mark (&lp
.end
);
5206 /* Don't include this character, it will wrap. */
5207 decrement_mark (&lp
.end
);
5211 lp
.tab_cont_next
= *next_cont
;
5218 lp
.displayable_chars
+= 1;
5221 lp
.font_ascent
= MAX (font
->ascent
, lp
.font_ascent
);
5222 lp
.font_descent
= MAX (font
->descent
, lp
.font_descent
);
5223 lp
.pixel_width
+= ch_width
;
5225 advance_mark(&lp
.end
);
5226 advance_tab_mark (text
, &tab_mark
, ch
);
5229 if (LAST_INDEX(text
, lp
.start
))
5231 /* Special case, empty last line. */
5232 font
= MARK_CURRENT_FONT (text
, &lp
.end
);
5234 lp
.font_ascent
= font
->ascent
;
5235 lp
.font_descent
= font
->descent
;
5238 lp
.tab_cont_next
= *next_cont
;
5244 expand_scratch_buffer (GtkSText
* text
, guint len
)
5246 if (len
>= text
->scratch_buffer_len
)
5250 while (i
<= len
&& i
< MIN_GAP_SIZE
) i
<<= 1;
5252 if (text
->use_wchar
)
5254 if (!text
->scratch_buffer
.wc
)
5255 text
->scratch_buffer
.wc
= g_new (GdkWChar
, i
);
5257 text
->scratch_buffer
.wc
= g_realloc (text
->scratch_buffer
.wc
,
5258 i
* sizeof (GdkWChar
));
5262 if (!text
->scratch_buffer
.ch
)
5263 text
->scratch_buffer
.ch
= g_new (guchar
, i
);
5265 text
->scratch_buffer
.ch
= g_realloc (text
->scratch_buffer
.ch
, i
);
5268 text
->scratch_buffer_len
= i
;
5272 /* Side effect: modifies text->gc
5276 draw_bg_rect (GtkSText
* text
, GtkSPropertyMark
*mark
,
5277 gint x
, gint y
, gint width
, gint height
,
5278 gboolean already_cleared
)
5280 GtkEditable
*editable
= GTK_EDITABLE(text
);
5282 if ((mark
->index
>= MIN(editable
->selection_start_pos
, editable
->selection_end_pos
) &&
5283 mark
->index
< MAX(editable
->selection_start_pos
, editable
->selection_end_pos
)))
5285 gtk_paint_flat_box(GTK_WIDGET(text
)->style
, text
->text_area
,
5286 editable
->has_selection
?
5287 GTK_STATE_SELECTED
: GTK_STATE_ACTIVE
,
5289 NULL
, GTK_WIDGET(text
), "text",
5290 x
, y
, width
, height
);
5292 else if (!gdk_color_equal(MARK_CURRENT_BACK (text
, mark
),
5293 >K_WIDGET(text
)->style
->base
[GTK_WIDGET_STATE (text
)]))
5295 gdk_gc_set_foreground (text
->gc
, MARK_CURRENT_BACK (text
, mark
));
5297 gdk_draw_rectangle (text
->text_area
,
5299 TRUE
, x
, y
, width
, height
);
5301 else if (GTK_WIDGET (text
)->style
->bg_pixmap
[GTK_STATE_NORMAL
])
5308 rect
.height
= height
;
5310 clear_area (text
, &rect
);
5312 else if (!already_cleared
)
5313 gdk_window_clear_area (text
->text_area
, x
, y
, width
, height
);
5317 draw_line (GtkSText
* text
,
5318 gint pixel_start_height
,
5321 GdkGCValues gc_values
;
5324 guint running_offset
= lp
->tab_cont
.pixel_offset
;
5325 union { GdkWChar
*wc
; guchar
*ch
; } buffer
;
5328 GtkEditable
*editable
= GTK_EDITABLE(text
);
5330 guint selection_start_pos
= MIN (editable
->selection_start_pos
, editable
->selection_end_pos
);
5331 guint selection_end_pos
= MAX (editable
->selection_start_pos
, editable
->selection_end_pos
);
5333 GtkSPropertyMark mark
= lp
->start
;
5334 TabStopMark tab_mark
= lp
->tab_cont
.tab_start
;
5335 gint pixel_height
= pixel_start_height
+ lp
->font_ascent
;
5336 guint chars
= lp
->displayable_chars
;
5338 /* First provide a contiguous segment of memory. This makes reading
5339 * the code below *much* easier, and only incurs the cost of copying
5340 * when the line being displayed spans the gap. */
5341 if (mark
.index
<= text
->gap_position
&&
5342 mark
.index
+ chars
> text
->gap_position
)
5344 expand_scratch_buffer (text
, chars
);
5346 if (text
->use_wchar
)
5348 for (i
= 0; i
< chars
; i
+= 1)
5349 text
->scratch_buffer
.wc
[i
] = GTK_STEXT_INDEX(text
, mark
.index
+ i
);
5350 buffer
.wc
= text
->scratch_buffer
.wc
;
5354 for (i
= 0; i
< chars
; i
+= 1)
5355 text
->scratch_buffer
.ch
[i
] = GTK_STEXT_INDEX(text
, mark
.index
+ i
);
5356 buffer
.ch
= text
->scratch_buffer
.ch
;
5361 if (text
->use_wchar
)
5363 if (mark
.index
>= text
->gap_position
)
5364 buffer
.wc
= text
->text
.wc
+ mark
.index
+ text
->gap_size
;
5366 buffer
.wc
= text
->text
.wc
+ mark
.index
;
5370 if (mark
.index
>= text
->gap_position
)
5371 buffer
.ch
= text
->text
.ch
+ mark
.index
+ text
->gap_size
;
5373 buffer
.ch
= text
->text
.ch
+ mark
.index
;
5378 if (running_offset
> 0)
5380 draw_bg_rect (text
, &mark
, 0, pixel_start_height
, running_offset
,
5381 LINE_HEIGHT (*lp
), TRUE
);
5387 if ((text
->use_wchar
&& buffer
.wc
[0] != '\t') ||
5388 (!text
->use_wchar
&& buffer
.ch
[0] != '\t'))
5390 union { GdkWChar
*wc
; guchar
*ch
; } next_tab
;
5395 if (text
->use_wchar
)
5396 for (i
=0; i
<chars
; i
++)
5398 if (buffer
.wc
[i
] == '\t')
5400 next_tab
.wc
= buffer
.wc
+ i
;
5405 next_tab
.ch
= memchr (buffer
.ch
, '\t', chars
);
5407 len
= MIN (MARK_CURRENT_PROPERTY (&mark
)->length
- mark
.offset
, chars
);
5409 if (text
->use_wchar
)
5412 len
= MIN (len
, next_tab
.wc
- buffer
.wc
);
5417 len
= MIN (len
, next_tab
.ch
- buffer
.ch
);
5420 if (mark
.index
< selection_start_pos
)
5421 len
= MIN (len
, selection_start_pos
- mark
.index
);
5422 else if (mark
.index
< selection_end_pos
)
5423 len
= MIN (len
, selection_end_pos
- mark
.index
);
5425 font
= MARK_CURRENT_FONT (text
, &mark
);
5426 if (font
->type
== GDK_FONT_FONT
)
5428 gdk_gc_set_font (text
->gc
, font
);
5429 gdk_gc_get_values (text
->gc
, &gc_values
);
5430 if (text
->use_wchar
)
5431 pixel_width
= gdk_text_width_wc (gc_values
.font
,
5434 pixel_width
= gdk_text_width (gc_values
.font
,
5439 if (text
->use_wchar
)
5440 pixel_width
= gdk_text_width_wc (font
, buffer
.wc
, len
);
5442 pixel_width
= gdk_text_width (font
, buffer
.ch
, len
);
5445 draw_bg_rect (text
, &mark
, running_offset
, pixel_start_height
,
5446 pixel_width
, LINE_HEIGHT (*lp
), TRUE
);
5448 if ((mark
.index
>= selection_start_pos
) &&
5449 (mark
.index
< selection_end_pos
))
5451 if (editable
->has_selection
)
5452 fg_gc
= GTK_WIDGET(text
)->style
->fg_gc
[GTK_STATE_SELECTED
];
5454 fg_gc
= GTK_WIDGET(text
)->style
->fg_gc
[GTK_STATE_ACTIVE
];
5458 gdk_gc_set_foreground (text
->gc
, MARK_CURRENT_FORE (text
, &mark
));
5462 if (text
->use_wchar
)
5463 gdk_draw_text_wc (text
->text_area
, MARK_CURRENT_FONT (text
, &mark
),
5470 gdk_draw_text (text
->text_area
, MARK_CURRENT_FONT (text
, &mark
),
5477 running_offset
+= pixel_width
;
5479 advance_tab_mark_n (text
, &tab_mark
, len
);
5483 gint pixels_remaining
;
5489 gdk_window_get_size (text
->text_area
, &pixels_remaining
, NULL
);
5490 if (GTK_EDITABLE (text
)->editable
|| !text
->word_wrap
)
5491 pixels_remaining
-= (LINE_WRAP_ROOM
+ running_offset
);
5493 pixels_remaining
-= running_offset
;
5495 space_width
= MARK_CURRENT_TEXT_FONT(text
, &mark
)->char_widths
[' '];
5497 spaces_avail
= pixels_remaining
/ space_width
;
5498 spaces_avail
= MIN (spaces_avail
, tab_mark
.to_next_tab
);
5500 draw_bg_rect (text
, &mark
, running_offset
, pixel_start_height
,
5501 spaces_avail
* space_width
, LINE_HEIGHT (*lp
), TRUE
);
5503 running_offset
+= tab_mark
.to_next_tab
*
5504 MARK_CURRENT_TEXT_FONT(text
, &mark
)->char_widths
[' '];
5506 advance_tab_mark (text
, &tab_mark
, '\t');
5509 advance_mark_n (&mark
, len
);
5510 if (text
->use_wchar
)
5519 draw_line_wrap (GtkSText
* text
, guint height
/* baseline height */)
5526 if (!GTK_EDITABLE (text
)->editable
&& text
->word_wrap
)
5529 /* SYLPHEED - don't draw ugly word wrapping thing if
5530 * our wrap margin is set */
5531 if (text
->wrap_rmargin
> 0) {
5535 if (text
->line_wrap
)
5537 bitmap
= text
->line_wrap_bitmap
;
5538 bitmap_width
= line_wrap_width
;
5539 bitmap_height
= line_wrap_height
;
5543 bitmap
= text
->line_arrow_bitmap
;
5544 bitmap_width
= line_arrow_width
;
5545 bitmap_height
= line_arrow_height
;
5548 gdk_window_get_size (text
->text_area
, &width
, NULL
);
5549 width
-= LINE_WRAP_ROOM
;
5551 gdk_gc_set_stipple (text
->gc
,
5554 gdk_gc_set_fill (text
->gc
, GDK_STIPPLED
);
5556 gdk_gc_set_foreground (text
->gc
, >K_WIDGET (text
)->style
->text
[GTK_STATE_NORMAL
]);
5558 gdk_gc_set_ts_origin (text
->gc
,
5560 height
- bitmap_height
- 1);
5562 gdk_draw_rectangle (text
->text_area
,
5566 height
- bitmap_height
- 1 /* one pixel above the baseline. */,
5570 gdk_gc_set_ts_origin (text
->gc
, 0, 0);
5572 gdk_gc_set_fill (text
->gc
, GDK_SOLID
);
5576 undraw_cursor (GtkSText
* text
, gint absolute
)
5578 GtkEditable
*editable
= (GtkEditable
*)text
;
5580 TDEBUG (("in undraw_cursor\n"));
5583 text
->cursor_drawn_level
= 0;
5585 if ((text
->cursor_drawn_level
++ == 0) &&
5586 (editable
->selection_start_pos
== editable
->selection_end_pos
) &&
5587 GTK_WIDGET_DRAWABLE (text
) && text
->line_start_cache
)
5590 gint pixel_width
, pixel_height
;
5593 g_assert(text
->cursor_mark
.property
);
5595 gc
= gdk_gc_new(text
->text_area
);
5597 gdk_gc_copy(gc
, text
->gc
);
5599 font
= MARK_CURRENT_FONT(text
, &text
->cursor_mark
);
5602 * changed the cursor to a real block (TM)
5604 if (text
->cursor_type
== STEXT_CURSOR_BLOCK
) {
5605 if (text
->use_wchar
)
5606 pixel_width
= gdk_char_width_wc(font
, text
->cursor_char
);
5608 pixel_width
= gdk_char_width(font
, text
->cursor_char
);
5610 pixel_height
= LINE_HEIGHT(CACHE_DATA(text
->current_line
));
5612 draw_bg_rect (text
, &text
->cursor_mark
,
5614 text
->cursor_pos_y
- (pixel_height
+ 1),
5620 draw_bg_rect (text
, &text
->cursor_mark
,
5621 text
->cursor_pos_x
- 1,
5622 text
->cursor_pos_y
- text
->cursor_char_offset
- font
->ascent
,
5623 2, font
->descent
+ font
->ascent
+ 1, FALSE
);
5627 if (text
->cursor_char
)
5629 if (font
->type
== GDK_FONT_FONT
)
5630 gdk_gc_set_font (text
->gc
, font
);
5632 gdk_gc_set_foreground (text
->gc
, MARK_CURRENT_FORE (text
, &text
->cursor_mark
));
5634 gdk_draw_text_wc (text
->text_area
, font
,
5637 text
->cursor_pos_y
- text
->cursor_char_offset
,
5642 gdk_gc_copy(text
->gc
, gc
);
5648 drawn_cursor_min (GtkSText
* text
)
5652 g_assert(text
->cursor_mark
.property
);
5654 font
= MARK_CURRENT_FONT(text
, &text
->cursor_mark
);
5656 return text
->cursor_pos_y
- text
->cursor_char_offset
- font
->ascent
;
5660 drawn_cursor_max (GtkSText
* text
)
5664 g_assert(text
->cursor_mark
.property
);
5666 font
= MARK_CURRENT_FONT(text
, &text
->cursor_mark
);
5668 return text
->cursor_pos_y
- text
->cursor_char_offset
;
5672 draw_cursor (GtkSText
* text
, gint absolute
)
5674 GtkEditable
*editable
= (GtkEditable
*)text
;
5675 gint pixel_width
, pixel_height
;
5677 TDEBUG (("in draw_cursor\n"));
5680 text
->cursor_drawn_level
= 1;
5682 if ((--text
->cursor_drawn_level
== 0) &&
5683 editable
->editable
&&
5684 (editable
->selection_start_pos
== editable
->selection_end_pos
) &&
5685 GTK_WIDGET_DRAWABLE (text
) && text
->line_start_cache
)
5690 g_assert (text
->cursor_mark
.property
);
5692 gc
= gdk_gc_new(text
->text_area
);
5694 gdk_gc_copy(gc
, text
->gc
);
5695 font
= MARK_CURRENT_FONT (text
, &text
->cursor_mark
);
5696 if (text
->cursor_type
== STEXT_CURSOR_BLOCK
) {
5698 * changed the cursor to a real block (TM)
5700 if (text
->use_wchar
) {
5701 pixel_width
= gdk_char_width_wc(font
, text
->cursor_char
);
5704 pixel_width
= gdk_char_width(font
, text
->cursor_char
);
5708 pixel_height
= LINE_HEIGHT(CACHE_DATA(text
->current_line
));
5709 gdk_gc_set_foreground (text
->gc
, >K_WIDGET (text
)->style
->text
[GTK_STATE_NORMAL
]);
5710 gdk_gc_set_function(text
->gc
, GDK_INVERT
);
5711 gdk_draw_rectangle(text
->text_area
, text
->gc
, TRUE
,
5713 text
->cursor_pos_y
- pixel_height
,
5718 gdk_gc_set_line_attributes(text
->gc
, 2, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_MITER
);
5719 gdk_gc_set_foreground(text
->gc
, >K_WIDGET (text
)->style
->text
[GTK_STATE_NORMAL
]);
5720 gdk_draw_line(text
->text_area
, text
->gc
, text
->cursor_pos_x
,
5721 text
->cursor_pos_y
+ font
->descent
- text
->cursor_char_offset
,
5723 text
->cursor_pos_y
- text
->cursor_char_offset
- font
->ascent
);
5726 gdk_gc_copy(text
->gc
, gc
);
5732 create_bg_gc (GtkSText
*text
)
5736 values
.tile
= GTK_WIDGET (text
)->style
->bg_pixmap
[GTK_STATE_NORMAL
];
5737 values
.fill
= GDK_TILED
;
5739 return gdk_gc_new_with_values (text
->text_area
, &values
,
5740 GDK_GC_FILL
| GDK_GC_TILE
);
5744 clear_area (GtkSText
*text
, GdkRectangle
*area
)
5746 GtkWidget
*widget
= GTK_WIDGET (text
);
5752 gdk_window_get_size (widget
->style
->bg_pixmap
[GTK_STATE_NORMAL
], &width
, &height
);
5754 gdk_gc_set_ts_origin (text
->bg_gc
,
5755 (- (gint
)text
->first_onscreen_hor_pixel
) % width
,
5756 (- (gint
)text
->first_onscreen_ver_pixel
) % height
);
5758 gdk_draw_rectangle (text
->text_area
, text
->bg_gc
, TRUE
,
5759 area
->x
, area
->y
, area
->width
, area
->height
);
5762 gdk_window_clear_area (text
->text_area
, area
->x
, area
->y
, area
->width
, area
->height
);
5766 expose_text (GtkSText
* text
, GdkRectangle
*area
, gboolean cursor
)
5768 GList
*cache
= text
->line_start_cache
;
5769 gint pixels
= - text
->first_cut_pixels
;
5770 gint min_y
= MAX (0, area
->y
);
5771 gint max_y
= MAX (0, area
->y
+ area
->height
);
5774 gdk_window_get_size (text
->text_area
, NULL
, &height
);
5775 max_y
= MIN (max_y
, height
);
5777 TDEBUG (("in expose x=%d y=%d w=%d h=%d\n", area
->x
, area
->y
, area
->width
, area
->height
));
5779 clear_area (text
, area
);
5781 for (; pixels
< height
; cache
= cache
->next
)
5783 if (pixels
< max_y
&& (pixels
+ (gint
)LINE_HEIGHT(CACHE_DATA(cache
))) >= min_y
)
5785 draw_line (text
, pixels
, &CACHE_DATA(cache
));
5787 if (CACHE_DATA(cache
).wraps
)
5788 draw_line_wrap (text
, pixels
+ CACHE_DATA(cache
).font_ascent
);
5791 if (cursor
&& GTK_WIDGET_HAS_FOCUS (text
))
5793 if (CACHE_DATA(cache
).start
.index
<= text
->cursor_mark
.index
&&
5794 CACHE_DATA(cache
).end
.index
>= text
->cursor_mark
.index
)
5796 /* We undraw and draw the cursor here to get the drawn
5797 * level right ... FIXME - maybe the second parameter
5798 * of draw_cursor should work differently
5800 undraw_cursor (text
, FALSE
);
5801 draw_cursor (text
, FALSE
);
5805 pixels
+= LINE_HEIGHT(CACHE_DATA(cache
));
5809 fetch_lines_forward (text
, 1);
5818 gtk_stext_update_text (GtkEditable
*editable
,
5822 GtkSText
*text
= GTK_STEXT (editable
);
5824 GList
*cache
= text
->line_start_cache
;
5825 gint pixels
= - text
->first_cut_pixels
;
5831 end_pos
= TEXT_LENGTH (text
);
5833 if (end_pos
< start_pos
)
5836 gdk_window_get_size (text
->text_area
, &width
, &height
);
5842 TDEBUG (("in expose span start=%d stop=%d\n", start_pos
, end_pos
));
5844 for (; pixels
< height
; cache
= cache
->next
)
5846 if (CACHE_DATA(cache
).start
.index
< end_pos
)
5848 if (CACHE_DATA(cache
).end
.index
>= start_pos
)
5851 area
.y
= MAX(0,pixels
);
5852 area
.height
= pixels
+ LINE_HEIGHT(CACHE_DATA(cache
)) - area
.y
;
5858 pixels
+= LINE_HEIGHT(CACHE_DATA(cache
));
5862 fetch_lines_forward (text
, 1);
5870 expose_text (text
, &area
, TRUE
);
5874 recompute_geometry (GtkSText
* text
)
5876 GtkSPropertyMark mark
, start_mark
;
5883 mark
= start_mark
= set_vertical_scroll (text
);
5885 /* We need a real start of a line when calling fetch_lines().
5886 * not the start of a wrapped line.
5888 while (mark
.index
> 0 &&
5889 GTK_STEXT_INDEX (text
, mark
.index
- 1) != LINE_DELIM
)
5890 decrement_mark (&mark
);
5892 gdk_window_get_size (text
->text_area
, &width
, &height
);
5894 /* Fetch an entire line, to make sure that we get all the text
5895 * we backed over above, in addition to enough text to fill up
5896 * the space vertically
5899 new_lines
= fetch_lines (text
,
5905 mark
= CACHE_DATA (g_list_last (new_lines
)).end
;
5906 if (!LAST_INDEX (text
, mark
))
5908 advance_mark (&mark
);
5910 new_lines
= g_list_concat (new_lines
,
5915 height
+ text
->first_cut_pixels
));
5918 /* Now work forward to the actual first onscreen line */
5920 while (CACHE_DATA (new_lines
).start
.index
< start_mark
.index
)
5921 new_lines
= new_lines
->next
;
5923 text
->line_start_cache
= new_lines
;
5925 find_cursor (text
, TRUE
);
5928 /**********************************************************************/
5930 /**********************************************************************/
5933 gtk_stext_set_selection (GtkEditable
*editable
,
5937 GtkSText
*text
= GTK_STEXT (editable
);
5939 guint start1
, end1
, start2
, end2
;
5942 end
= TEXT_LENGTH (text
);
5944 start1
= MIN(start
,end
);
5945 end1
= MAX(start
,end
);
5946 start2
= MIN(editable
->selection_start_pos
, editable
->selection_end_pos
);
5947 end2
= MAX(editable
->selection_start_pos
, editable
->selection_end_pos
);
5949 if (start2
< start1
)
5953 tmp
= start1
; start1
= start2
; start2
= tmp
;
5954 tmp
= end1
; end1
= end2
; end2
= tmp
;
5957 undraw_cursor (text
, FALSE
);
5958 editable
->selection_start_pos
= start
;
5959 editable
->selection_end_pos
= end
;
5960 draw_cursor (text
, FALSE
);
5962 /* Expose only what changed */
5964 if (start1
< start2
)
5965 gtk_stext_update_text (editable
, start1
, MIN(end1
, start2
));
5968 gtk_stext_update_text (editable
, MAX(end1
, start2
), end2
);
5969 else if (end2
< end1
)
5970 gtk_stext_update_text (editable
, end2
, end1
);
5978 static gint
stext_blink_timer_proc(GtkSText
*text
)
5980 if (text
->cursor_state_on
) {
5981 text
->cursor_state_on
= FALSE
;
5982 undraw_cursor(text
, TRUE
);
5983 /* kill this timer... */
5984 gtk_timeout_remove(text
->cursor_timer_id
);
5985 text
->cursor_timer_id
= gtk_timeout_add(text
->cursor_off_ms
, (GtkFunction
) stext_blink_timer_proc
, (gpointer
) text
);
5988 text
->cursor_state_on
= TRUE
;
5989 draw_cursor(text
, TRUE
);
5990 /* kill this timer... */
5991 gtk_timeout_remove(text
->cursor_timer_id
);
5992 text
->cursor_timer_id
= gtk_timeout_add(text
->cursor_on_ms
, (GtkFunction
) stext_blink_timer_proc
, (gpointer
) text
);
5997 static gint
stext_idle_timer_proc(GtkSText
*text
)
5999 /* make sure the cursor timer is off */
6000 if (text
->cursor_timer_id
) {
6001 gtk_timeout_remove(text
->cursor_timer_id
);
6002 text
->cursor_timer_id
= 0;
6004 /* assuming it's always on when calling this function ... */
6005 text
->cursor_state_on
= TRUE
;
6006 text
->cursor_timer_id
= gtk_timeout_add(text
->cursor_on_ms
, (GtkFunction
) stext_blink_timer_proc
, (gpointer
) text
);
6007 /* make sure we kill the timer (could perhaps make this function return FALSE (not documented in
6008 * the current docs). should check the source. */
6009 gtk_idle_remove( text
->cursor_idle_time_timer_id
);
6010 text
->cursor_idle_time_timer_id
= 0;
6014 static void gtk_stext_enable_blink (GtkSText
*text
)
6016 if (text
->cursor_timer_on
) {
6017 gtk_stext_disable_blink(text
);
6018 text
->cursor_idle_time_timer_id
= gtk_idle_add((GtkFunction
) stext_idle_timer_proc
, (gpointer
) text
);
6022 static void gtk_stext_disable_blink (GtkSText
*text
)
6024 if (text
->cursor_timer_on
) {
6025 if (text
->cursor_idle_time_timer_id
) {
6026 gtk_idle_remove( text
->cursor_idle_time_timer_id
);
6027 text
->cursor_idle_time_timer_id
= 0;
6029 if (text
->cursor_timer_id
) {
6030 gtk_timeout_remove( text
->cursor_timer_id
);
6031 text
->cursor_timer_id
= 0;
6033 draw_cursor(text
, TRUE
);
6037 void gtk_stext_set_blink(GtkSText
*text
, gboolean blinkin_on
)
6039 if (text
->cursor_timer_on
!= blinkin_on
) {
6040 if (text
->cursor_timer_on
) {
6041 /* text widget already created? */
6042 if (text
->cursor_visible
) {
6043 gtk_stext_disable_blink(text
);
6045 text
->cursor_timer_on
= FALSE
;
6048 if (text
->cursor_visible
) {
6049 gtk_stext_enable_blink(text
);
6051 text
->cursor_timer_on
= TRUE
;
6057 void gtk_stext_set_wrap_rmargin (GtkSText
*text
, gint rmargin
)
6059 /* not particularly impressive, but it does the job. */
6060 /* TODO: currently only allowed to set this after a
6061 * gtk_stext_new() */
6062 text
->wrap_rmargin
= rmargin
>= 0 ? rmargin
: 0;
6065 /**********************************************************************/
6067 /**********************************************************************/
6069 #ifdef DEBUG_GTK_STEXT
6071 gtk_stext_show_cache_line (GtkSText
*text
, GList
*cache
,
6072 const char* what
, const char* func
, gint line
)
6074 LineParams
*lp
= &CACHE_DATA(cache
);
6077 if (cache
== text
->line_start_cache
)
6078 g_message ("Line Start Cache: ");
6080 if (cache
== text
->current_line
)
6081 g_message("Current Line: ");
6083 g_message ("%s:%d: cache line %s s=%d,e=%d,lh=%d (",
6091 for (i
= lp
->start
.index
; i
< (lp
->end
.index
+ lp
->wraps
); i
+= 1)
6092 g_message ("%c", GTK_STEXT_INDEX (text
, i
));
6098 gtk_stext_show_cache (GtkSText
*text
, const char* func
, gint line
)
6100 GList
*l
= text
->line_start_cache
;
6106 /* back up to the absolute beginning of the line cache */
6110 g_message ("*** line cache ***\n");
6111 for (; l
; l
= l
->next
)
6112 gtk_stext_show_cache_line (text
, l
, "all", func
, line
);
6116 gtk_stext_assert_mark (GtkSText
*text
,
6117 GtkSPropertyMark
*mark
,
6118 GtkSPropertyMark
*before
,
6119 GtkSPropertyMark
*after
,
6124 GtkSPropertyMark correct_mark
= find_mark (text
, mark
->index
);
6126 if (mark
->offset
!= correct_mark
.offset
||
6127 mark
->property
!= correct_mark
.property
)
6128 g_warning ("incorrect %s text property marker in %s:%d, index %d -- bad!", where
, msg
, line
, mark
->index
);
6132 gtk_stext_assert (GtkSText
*text
,
6136 GList
* cache
= text
->line_start_cache
;
6137 GtkSPropertyMark
* before_mark
= NULL
;
6138 GtkSPropertyMark
* after_mark
= NULL
;
6140 gtk_stext_show_props (text
, msg
, line
);
6142 for (; cache
->prev
; cache
= cache
->prev
)
6145 g_message ("*** line markers ***\n");
6147 for (; cache
; cache
= cache
->next
)
6149 after_mark
= &CACHE_DATA(cache
).end
;
6150 gtk_stext_assert_mark (text
, &CACHE_DATA(cache
).start
, before_mark
, after_mark
, msg
, "start", line
);
6151 before_mark
= &CACHE_DATA(cache
).start
;
6154 after_mark
= &CACHE_DATA(cache
->next
).start
;
6158 gtk_stext_assert_mark (text
, &CACHE_DATA(cache
).end
, before_mark
, after_mark
, msg
, "end", line
);
6159 before_mark
= &CACHE_DATA(cache
).end
;
6164 gtk_stext_show_adj (GtkSText
*text
,
6170 g_message ("*** adjustment ***\n");
6172 g_message ("%s:%d: %s adjustment l=%.1f u=%.1f v=%.1f si=%.1f pi=%.1f ps=%.1f\n",
6179 adj
->step_increment
,
6180 adj
->page_increment
,
6185 gtk_stext_show_props (GtkSText
*text
,
6189 GList
* props
= text
->text_properties
;
6192 g_message ("%s:%d: ", msg
, line
);
6194 for (; props
; props
= props
->next
)
6196 TextProperty
*p
= (TextProperty
*)props
->data
;
6198 proplen
+= p
->length
;
6200 g_message ("[%d,%p,", p
->length
, p
);
6201 if (p
->flags
& PROPERTY_FONT
)
6202 g_message ("%p,", p
->font
);
6205 if (p
->flags
& PROPERTY_FOREGROUND
)
6206 g_message ("%ld, ", p
->fore_color
.pixel
);
6209 if (p
->flags
& PROPERTY_BACKGROUND
)
6210 g_message ("%ld] ", p
->back_color
.pixel
);
6217 if (proplen
- 1 != TEXT_LENGTH(text
))
6218 g_warning ("incorrect property list length in %s:%d -- bad!", msg
, line
);