00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #ifdef HAVE_CONFIG_H
00047 # include <config.h>
00048 #endif
00049
00050 #include "intl.h"
00051 #include <ctype.h>
00052 #include <string.h>
00053 #include <gdk/gdkkeysyms.h>
00054 #include <gdk/gdki18n.h>
00055 #include <gtk/gtkmain.h>
00056 #include <gtk/gtkselection.h>
00057 #include <gtk/gtksignal.h>
00058 #include <gdk/gdkprivate.h>
00059 #include "extgtktext.h"
00060 #include "globals.h"
00061 #ifdef HAVE_LIBXFT
00062 #include <X11/Xft/Xft.h>
00063 #endif
00064
00065
00066 #define INITIAL_BUFFER_SIZE 1024
00067 #define INITIAL_LINE_CACHE_SIZE 256
00068 #define MIN_GAP_SIZE 256
00069 #define LINE_DELIM '\n'
00070 #define MIN_TEXT_WIDTH_LINES 20
00071 #define MIN_TEXT_HEIGHT_LINES 10
00072 #define TEXT_BORDER_ROOM 1
00073 #define DEFAULT_TAB_STOP_WIDTH 4
00074 #define SCROLL_PIXELS 5
00075 #define KEY_SCROLL_PIXELS 10
00076 #define SCROLL_TIME 100
00077 #define FREEZE_LENGTH 1024
00078
00079
00080 #define SET_PROPERTY_MARK(m, p, o) do { \
00081 (m)->property = (p); \
00082 (m)->offset = (o); \
00083 } while (0)
00084 #define MARK_CURRENT_PROPERTY(mark) ((TextProperty*)(mark)->property->data)
00085 #define MARK_NEXT_PROPERTY(mark) ((TextProperty*)(mark)->property->next->data)
00086 #define MARK_PREV_PROPERTY(mark) ((TextProperty*)((mark)->property->prev ? \
00087 (mark)->property->prev->data \
00088 : NULL))
00089 #define MARK_PREV_LIST_PTR(mark) ((mark)->property->prev)
00090 #define MARK_LIST_PTR(mark) ((mark)->property)
00091 #define MARK_NEXT_LIST_PTR(mark) ((mark)->property->next)
00092 #define MARK_OFFSET(mark) ((mark)->offset)
00093 #define MARK_PROPERTY_LENGTH(mark) (MARK_CURRENT_PROPERTY(mark)->length)
00094
00095
00096 #ifndef HAVE_LIBXFT
00097 #define MARK_CURRENT_FONT(text, mark) \
00098 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
00099 MARK_CURRENT_PROPERTY(mark)->font->gdk_font : \
00100 GTK_WIDGET (text)->style->font)
00101 #else
00102 #define MARK_CURRENT_FONT(text, mark) \
00103 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
00104 MARK_CURRENT_PROPERTY(mark)->font->gdk_font : \
00105 default_font)
00106 #endif
00107
00108 #define MARK_CURRENT_FORE(text, mark) \
00109 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FOREGROUND) ? \
00110 &MARK_CURRENT_PROPERTY(mark)->fore_color : \
00111 &((GtkWidget *)text)->style->text[((GtkWidget *)text)->state])
00112 #define MARK_CURRENT_BACK(text, mark) \
00113 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_BACKGROUND) ? \
00114 &MARK_CURRENT_PROPERTY(mark)->back_color : \
00115 &((GtkWidget *)text)->style->base[((GtkWidget *)text)->state])
00116 #define MARK_CURRENT_UNDERLINED(text, mark) \
00117 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_UNDERLINED) ? \
00118 TRUE : \
00119 FALSE)
00120 #define MARK_CURRENT_DIVIDER(text, mark) \
00121 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_DIVIDER) ? \
00122 TRUE : \
00123 FALSE)
00124 #define MARK_CURRENT_MASK(text, mark) \
00125 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_IMAGE) ? \
00126 MARK_CURRENT_PROPERTY(mark)->mask: \
00127 NULL)
00128 #define MARK_CURRENT_IMAGE(text, mark) \
00129 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_IMAGE) ? \
00130 MARK_CURRENT_PROPERTY(mark)->image : \
00131 NULL)
00132 #define MARK_CURRENT_TEXT_FONT(text, mark) \
00133 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_FONT) ? \
00134 MARK_CURRENT_PROPERTY(mark)->font : \
00135 text->current_font)
00136 #define MARK_CURRENT_DATA(text,mark) \
00137 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_DATA) ? \
00138 MARK_CURRENT_PROPERTY(mark)->user_data:NULL)
00139 #define MARK_CURRENT_DATA_FUNC(text,mark) \
00140 ((MARK_CURRENT_PROPERTY(mark)->flags & PROPERTY_DATA) ? \
00141 MARK_CURRENT_PROPERTY(mark)->user_data_func:NULL)
00142
00143 #define TEXT_LENGTH(t) ((t)->text_end - (t)->gap_size)
00144 #define FONT_HEIGHT(f) ((f)->ascent + (f)->descent)
00145 #define LINE_HEIGHT(l) ((l).font_ascent + (l).font_descent)
00146 #define LINE_CONTAINS(l, i) ((l).start.index <= (i) && (l).end.index >= (i))
00147 #define LINE_STARTS_AT(l, i) ((l).start.index == (i))
00148 #define LINE_START_PIXEL(l) ((l).tab_cont.pixel_offset)
00149 #define LAST_INDEX(t, m) ((m).index == TEXT_LENGTH(t))
00150 #define CACHE_DATA(c) (*(LineParams*)(c)->data)
00151
00152 enum {
00153 ARG_0,
00154 ARG_HADJUSTMENT,
00155 ARG_VADJUSTMENT,
00156 ARG_LINE_WRAP,
00157 ARG_WORD_WRAP
00158 };
00159
00160 typedef struct _TextProperty TextProperty;
00161 typedef struct _TabStopMark TabStopMark;
00162 typedef struct _PrevTabCont PrevTabCont;
00163 typedef struct _FetchLinesData FetchLinesData;
00164 typedef struct _LineParams LineParams;
00165 typedef struct _SetVerticalScrollData SetVerticalScrollData;
00166
00167 typedef gint (*LineIteratorFunction) (ExtGtkText* text, LineParams* lp, void* data);
00168
00169 typedef enum
00170 {
00171 FetchLinesPixels,
00172 FetchLinesCount
00173 } FLType;
00174
00175 struct _SetVerticalScrollData {
00176 gint pixel_height;
00177 gint last_didnt_wrap;
00178 gint last_line_start;
00179 ExtGtkPropertyMark mark;
00180 };
00181
00182 struct _ExtGtkTextFont
00183 {
00184
00185 VFont *gdk_font;
00186 guint ref_count;
00187
00188 gint16 char_widths[256];
00189 };
00190 typedef enum {
00191 PROPERTY_FONT = 1 << 0,
00192 PROPERTY_FOREGROUND = 1 << 1,
00193 PROPERTY_BACKGROUND = 1 << 2,
00194 PROPERTY_UNDERLINED = 1 << 3,
00195 PROPERTY_IMAGE = 1 << 4,
00196 PROPERTY_DATA = 1 << 5,
00197 PROPERTY_DIVIDER = 1 << 6
00198 } TextPropertyFlags;
00199
00200
00201 struct _TextProperty
00202 {
00203
00204 ExtGtkTextFont* font;
00205
00206
00207 GdkColor back_color;
00208
00209
00210 GdkColor fore_color;
00211
00212
00213 GdkDrawable *image;
00214 GdkBitmap *mask;
00215
00216
00217 TextPropertyFlags flags;
00218
00219
00220 gpointer user_data;
00221 guint user_data_length;
00222 DataFunc *user_data_func;
00223
00224
00225 guint length;
00226 };
00227
00228 struct _TabStopMark
00229 {
00230 GList* tab_stops;
00231
00232 gint to_next_tab;
00233 };
00234
00235 struct _PrevTabCont
00236 {
00237 guint pixel_offset;
00238 TabStopMark tab_start;
00239 };
00240
00241 struct _FetchLinesData
00242 {
00243 GList* new_lines;
00244 FLType fl_type;
00245 gint data;
00246 gint data_max;
00247 };
00248
00249 struct _LineParams
00250 {
00251 guint font_ascent;
00252 guint font_descent;
00253 guint pixel_width;
00254 guint displayable_chars;
00255 guint wraps : 1;
00256
00257 PrevTabCont tab_cont;
00258 PrevTabCont tab_cont_next;
00259
00260 ExtGtkPropertyMark start;
00261 ExtGtkPropertyMark end;
00262 };
00263
00264
00265 static void gtk_text_class_init (ExtGtkTextClass *klass);
00266 static void gtk_text_set_arg (GtkObject *object,
00267 GtkArg *arg,
00268 guint arg_id);
00269 static void gtk_text_get_arg (GtkObject *object,
00270 GtkArg *arg,
00271 guint arg_id);
00272 static void gtk_text_init (ExtGtkText *text);
00273 static void gtk_text_destroy (GtkObject *object);
00274 static void gtk_text_finalize (GtkObject *object);
00275 static void gtk_text_realize (GtkWidget *widget);
00276 static void gtk_text_unrealize (GtkWidget *widget);
00277 static void gtk_text_style_set (GtkWidget *widget,
00278 GtkStyle *previous_style);
00279 static void gtk_text_state_changed (GtkWidget *widget,
00280 GtkStateType previous_state);
00281 static void gtk_text_draw_focus (GtkWidget *widget);
00282 static void gtk_text_size_request (GtkWidget *widget,
00283 GtkRequisition *requisition);
00284 static void gtk_text_size_allocate (GtkWidget *widget,
00285 GtkAllocation *allocation);
00286 static void gtk_text_adjustment (GtkAdjustment *adjustment,
00287 ExtGtkText *text);
00288 static void gtk_text_disconnect (GtkAdjustment *adjustment,
00289 ExtGtkText *text);
00290
00291 static void ext_gtk_text_insert_text (GtkEditable *editable,
00292 const gchar *new_text,
00293 gint new_text_length,
00294 gint *position);
00295 static void gtk_text_delete_text (GtkEditable *editable,
00296 gint start_pos,
00297 gint end_pos);
00298 static void gtk_text_update_text (GtkEditable *editable,
00299 gint start_pos,
00300 gint end_pos);
00301 static gchar *gtk_text_get_chars (GtkEditable *editable,
00302 gint start,
00303 gint end);
00304 static void gtk_text_set_selection (GtkEditable *editable,
00305 gint start,
00306 gint end);
00307 static void gtk_text_real_set_editable (GtkEditable *editable,
00308 gboolean is_editable);
00309
00310
00311 static void gtk_text_draw (GtkWidget *widget,
00312 GdkRectangle *area);
00313 static gint gtk_text_expose (GtkWidget *widget,
00314 GdkEventExpose *event);
00315 static gint gtk_text_button_press (GtkWidget *widget,
00316 GdkEventButton *event);
00317 static gint gtk_text_button_release (GtkWidget *widget,
00318 GdkEventButton *event);
00319 static gint gtk_text_motion_notify (GtkWidget *widget,
00320 GdkEventMotion *event);
00321 static gint gtk_text_key_press (GtkWidget *widget,
00322 GdkEventKey *event);
00323 static gint gtk_text_focus_in (GtkWidget *widget,
00324 GdkEventFocus *event);
00325 static gint gtk_text_focus_out (GtkWidget *widget,
00326 GdkEventFocus *event);
00327
00328 static void move_gap (ExtGtkText* text, guint index);
00329 static void make_forward_space (ExtGtkText* text, guint len);
00330
00331
00332 static ExtGtkTextFont* get_text_font (VFont* gfont);
00333 static void text_font_unref (ExtGtkTextFont *text_font);
00334 static void insert_text_property (ExtGtkText* text, VFont* font,
00335 GdkColor *fore, GdkColor* back,
00336 gboolean underlined, gboolean divider,
00337 GdkDrawable *image, GdkBitmap *mask,
00338 gpointer user_data, guint user_data_length,
00339 DataFunc *user_data_func,
00340 guint len);
00341 static TextProperty* new_text_property (ExtGtkText *text, VFont* font,
00342 GdkColor* fore, GdkColor* back,
00343 gboolean underlined, gboolean divider, GdkDrawable *image,
00344 GdkBitmap *mask,
00345 gpointer user_data, guint user_data_length,
00346 DataFunc *user_data_func,
00347 guint length);
00348 static void destroy_text_property (TextProperty *prop);
00349 static void init_properties (ExtGtkText *text);
00350 static void realize_property (ExtGtkText *text, TextProperty *prop);
00351 static void realize_properties (ExtGtkText *text);
00352 static void unrealize_property (ExtGtkText *text, TextProperty *prop);
00353 static void unrealize_properties (ExtGtkText *text);
00354
00355 static void delete_text_property (ExtGtkText* text, guint len);
00356
00357 static guint pixel_height_of (ExtGtkText* text, GList* cache_line);
00358
00359
00360 static void advance_mark (ExtGtkPropertyMark* mark);
00361 static void decrement_mark (ExtGtkPropertyMark* mark);
00362 static void advance_mark_n (ExtGtkPropertyMark* mark, gint n);
00363 static void decrement_mark_n (ExtGtkPropertyMark* mark, gint n);
00364 static void move_mark_n (ExtGtkPropertyMark* mark, gint n);
00365 static ExtGtkPropertyMark find_mark (ExtGtkText* text, guint mark_position);
00366 static ExtGtkPropertyMark find_mark_near (ExtGtkText* text, guint mark_position, const ExtGtkPropertyMark* near);
00367 static void find_line_containing_point (ExtGtkText* text, guint point,
00368 gboolean scroll);
00369
00370
00371 static void compute_lines_pixels (ExtGtkText* text, guint char_count,
00372 guint *lines, guint *pixels);
00373
00374 static gint total_line_height (ExtGtkText* text,
00375 GList* line,
00376 gint line_count);
00377 static LineParams find_line_params (ExtGtkText* text,
00378 const ExtGtkPropertyMark *mark,
00379 const PrevTabCont *tab_cont,
00380 PrevTabCont *next_cont);
00381 static void recompute_geometry (ExtGtkText* text);
00382 static void insert_expose (ExtGtkText* text, guint old_pixels, gint nchars, guint new_line_count);
00383 static void delete_expose (ExtGtkText* text,
00384 guint nchars,
00385 guint old_lines,
00386 guint old_pixels);
00387 static GdkGC *create_bg_gc (ExtGtkText *text);
00388 static void clear_area (ExtGtkText *text, GdkRectangle *area);
00389 static void draw_line (ExtGtkText* text,
00390 gint pixel_height,
00391 LineParams* lp);
00392 static void draw_cursor (ExtGtkText* text, gint absolute);
00393 static void undraw_cursor (ExtGtkText* text, gint absolute);
00394 static gint drawn_cursor_min (ExtGtkText* text);
00395 static gint drawn_cursor_max (ExtGtkText* text);
00396 static void expose_text (ExtGtkText* text, GdkRectangle *area, gboolean cursor);
00397
00398
00399 static void find_cursor (ExtGtkText* text,
00400 gboolean scroll);
00401 static void find_cursor_at_line (ExtGtkText* text,
00402 const LineParams* start_line,
00403 gint pixel_height);
00404 static void find_mouse_cursor (ExtGtkText* text, gint x, gint y);
00405
00406
00407 static void adjust_adj (ExtGtkText* text, GtkAdjustment* adj);
00408 static void scroll_up (ExtGtkText* text, gint diff);
00409 static void scroll_down (ExtGtkText* text, gint diff);
00410 static void scroll_int (ExtGtkText* text, gint diff);
00411
00412 static void process_exposes (ExtGtkText *text);
00413
00414
00415 static void free_cache (ExtGtkText* text);
00416 static GList* remove_cache_line (ExtGtkText* text, GList* list);
00417
00418
00419 static void move_cursor_buffer_ver (ExtGtkText *text, int dir);
00420 static void move_cursor_page_ver (ExtGtkText *text, int dir);
00421 static void move_cursor_ver (ExtGtkText *text, int count);
00422 static void move_cursor_hor (ExtGtkText *text, int count);
00423
00424
00425 static void gtk_text_move_cursor (GtkEditable *editable,
00426 gint x,
00427 gint y);
00428 static void gtk_text_move_word (GtkEditable *editable,
00429 gint n);
00430 static void gtk_text_move_page (GtkEditable *editable,
00431 gint x,
00432 gint y);
00433 static void gtk_text_move_to_row (GtkEditable *editable,
00434 gint row);
00435 static void gtk_text_move_to_column (GtkEditable *editable,
00436 gint row);
00437 static void gtk_text_kill_char (GtkEditable *editable,
00438 gint direction);
00439 static void gtk_text_kill_word (GtkEditable *editable,
00440 gint direction);
00441 static void gtk_text_kill_line (GtkEditable *editable,
00442 gint direction);
00443
00444
00445 static void gtk_text_move_forward_character (ExtGtkText *text);
00446 static void gtk_text_move_backward_character (ExtGtkText *text);
00447 static void gtk_text_move_forward_word (ExtGtkText *text);
00448 static void gtk_text_move_backward_word (ExtGtkText *text);
00449 static void gtk_text_move_beginning_of_line (ExtGtkText *text);
00450 static void gtk_text_move_end_of_line (ExtGtkText *text);
00451 static void gtk_text_move_next_line (ExtGtkText *text);
00452 static void gtk_text_move_previous_line (ExtGtkText *text);
00453
00454 static void gtk_text_delete_forward_character (ExtGtkText *text);
00455 static void gtk_text_delete_backward_character (ExtGtkText *text);
00456 static void gtk_text_delete_forward_word (ExtGtkText *text);
00457 static void gtk_text_delete_backward_word (ExtGtkText *text);
00458 static void gtk_text_delete_line (ExtGtkText *text);
00459 static void gtk_text_delete_to_line_end (ExtGtkText *text);
00460 static void gtk_text_select_word (ExtGtkText *text,
00461 guint32 time);
00462 static void gtk_text_select_line (ExtGtkText *text,
00463 guint32 time);
00464
00465 static void gtk_text_set_position (GtkEditable *editable,
00466 gint position);
00467
00468
00469
00470 #if defined(DEBUG_EXT_GTK_TEXT) && defined(__GNUC__)
00471
00472 static void gtk_text_assert_mark (ExtGtkText *text,
00473 ExtGtkPropertyMark *mark,
00474 ExtGtkPropertyMark *before,
00475 ExtGtkPropertyMark *after,
00476 const gchar *msg,
00477 const gchar *where,
00478 gint line);
00479
00480 static void gtk_text_assert (ExtGtkText *text,
00481 const gchar *msg,
00482 gint line);
00483 static void gtk_text_show_cache_line (ExtGtkText *text, GList *cache,
00484 const char* what, const char* func, gint line);
00485 static void gtk_text_show_cache (ExtGtkText *text, const char* func, gint line);
00486 static void gtk_text_show_adj (ExtGtkText *text,
00487 GtkAdjustment *adj,
00488 const char* what,
00489 const char* func,
00490 gint line);
00491 static void gtk_text_show_props (ExtGtkText* test,
00492 const char* func,
00493 int line);
00494
00495 #define TDEBUG(args) g_message args
00496 #define TEXT_ASSERT(text) gtk_text_assert (text,__PRETTY_FUNCTION__,__LINE__)
00497 #define TEXT_ASSERT_MARK(text,mark,msg) gtk_text_assert_mark (text,mark, \
00498 __PRETTY_FUNCTION__,msg,__LINE__)
00499 #define TEXT_SHOW(text) gtk_text_show_cache (text, __PRETTY_FUNCTION__,__LINE__)
00500 #define TEXT_SHOW_LINE(text,line,msg) gtk_text_show_cache_line (text,line,msg,\
00501 __PRETTY_FUNCTION__,__LINE__)
00502 #define TEXT_SHOW_ADJ(text,adj,msg) gtk_text_show_adj (text,adj,msg, \
00503 __PRETTY_FUNCTION__,__LINE__)
00504 #else
00505 #define TDEBUG(args)
00506 #define TEXT_ASSERT(text)
00507 #define TEXT_ASSERT_MARK(text,mark,msg)
00508 #define TEXT_SHOW(text)
00509 #define TEXT_SHOW_LINE(text,line,msg)
00510 #define TEXT_SHOW_ADJ(text,adj,msg)
00511 #endif
00512
00513
00514 static GMemChunk *params_mem_chunk = NULL;
00515 static GMemChunk *text_property_chunk = NULL;
00516
00517 static GtkWidgetClass *parent_class = NULL;
00518
00519 #ifdef HAVE_LIBXFT
00520 static XftFont * default_font = NULL;
00521 #endif
00522
00523 static const GtkTextFunction control_keys[26] =
00524 {
00525 (GtkTextFunction)gtk_text_move_beginning_of_line,
00526 (GtkTextFunction)gtk_text_move_backward_character,
00527 (GtkTextFunction)gtk_editable_copy_clipboard,
00528 (GtkTextFunction)gtk_text_delete_forward_character,
00529 (GtkTextFunction)gtk_text_move_end_of_line,
00530 (GtkTextFunction)gtk_text_move_forward_character,
00531 NULL,
00532 (GtkTextFunction)gtk_text_delete_backward_character,
00533 NULL,
00534 NULL,
00535 (GtkTextFunction)gtk_text_delete_to_line_end,
00536 NULL,
00537 NULL,
00538 (GtkTextFunction)gtk_text_move_next_line,
00539 NULL,
00540 (GtkTextFunction)gtk_text_move_previous_line,
00541 NULL,
00542 NULL,
00543 NULL,
00544 NULL,
00545 (GtkTextFunction)gtk_text_delete_line,
00546 (GtkTextFunction)gtk_editable_paste_clipboard,
00547 (GtkTextFunction)gtk_text_delete_backward_word,
00548 (GtkTextFunction)gtk_editable_cut_clipboard,
00549 NULL,
00550 NULL,
00551 };
00552
00553 static const GtkTextFunction alt_keys[26] =
00554 {
00555 NULL,
00556 (GtkTextFunction)gtk_text_move_backward_word,
00557 NULL,
00558 (GtkTextFunction)gtk_text_delete_forward_word,
00559 NULL,
00560 (GtkTextFunction)gtk_text_move_forward_word,
00561 NULL,
00562 NULL,
00563 NULL,
00564 NULL,
00565 NULL,
00566 NULL,
00567 NULL,
00568 NULL,
00569 NULL,
00570 NULL,
00571 NULL,
00572 NULL,
00573 NULL,
00574 NULL,
00575 NULL,
00576 NULL,
00577 NULL,
00578 NULL,
00579 NULL,
00580 NULL,
00581 };
00582
00583
00584
00585
00586
00587 #ifdef HAVE_LIBXFT
00588 void xft_draw_text (GdkDrawable *drawable,
00589 XftFont *font,
00590 GdkGC *gc,
00591 GdkColor *color,
00592 gint x,
00593 gint y,
00594 const gchar *text,
00595 char use_wchar,
00596 gint text_length)
00597 {
00598 GdkWindowPrivate *drawable_private;
00599 GdkGCPrivate *gc_private;
00600 XftDraw *xftdraw;
00601 XftColor xftcolor;
00602
00603 g_return_if_fail(drawable!=NULL);
00604 g_return_if_fail(font!=NULL);
00605 g_return_if_fail(gc!=NULL);
00606 g_return_if_fail( text!=NULL);
00607
00608 drawable_private = (GdkWindowPrivate *) drawable;
00609 if(drawable_private->destroyed) return;
00610 gc_private = (GdkGCPrivate *) gc;
00611
00612 xftdraw = XftDrawCreate( gc_private->xdisplay,
00613 (Drawable) drawable_private->xwindow,
00614 DefaultVisual(gc_private->xdisplay,
00615 DefaultScreen(gc_private->xdisplay)),
00616 DefaultColormap(gc_private->xdisplay,
00617 DefaultScreen(gc_private->xdisplay))
00618 );
00619
00620
00621
00622 xftcolor.color.red = color->red;
00623 xftcolor.color.green = color->green;
00624 xftcolor.color.blue = color->blue;
00625 xftcolor.color.alpha = 0xffff;
00626 xftcolor.pixel = color->pixel;
00627
00628 if(!use_wchar)
00629 {
00630 XftDrawString8(xftdraw, &xftcolor, font, x, y, (unsigned char *) text,text_length);
00631 }
00632 else
00633 {
00634 XftDrawString32(xftdraw, &xftcolor, font, x, y, (unsigned char *) text,text_length);
00635 }
00636 XftDrawDestroy(xftdraw);
00637 }
00638 #endif
00639
00640 GtkType
00641 ext_gtk_text_get_type (void)
00642 {
00643 static GtkType text_type = 0;
00644
00645 if (!text_type)
00646 {
00647 static const GtkTypeInfo text_info =
00648 {
00649 "ExtGtkText",
00650 sizeof (ExtGtkText),
00651 sizeof (ExtGtkTextClass),
00652 (GtkClassInitFunc) gtk_text_class_init,
00653 (GtkObjectInitFunc) gtk_text_init,
00654 NULL,
00655 NULL,
00656 (GtkClassInitFunc) NULL,
00657 };
00658
00659 text_type = gtk_type_unique (GTK_TYPE_EDITABLE, &text_info);
00660 }
00661
00662 return text_type;
00663 }
00664
00665 static void
00666 gtk_text_class_init (ExtGtkTextClass *class)
00667 {
00668 GtkObjectClass *object_class;
00669 GtkWidgetClass *widget_class;
00670 GtkEditableClass *editable_class;
00671
00672 object_class = (GtkObjectClass*) class;
00673 widget_class = (GtkWidgetClass*) class;
00674 editable_class = (GtkEditableClass*) class;
00675 parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
00676
00677 gtk_object_add_arg_type ("ExtGtkText::hadjustment",
00678 GTK_TYPE_ADJUSTMENT,
00679 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
00680 ARG_HADJUSTMENT);
00681 gtk_object_add_arg_type ("ExtGtkText::vadjustment",
00682 GTK_TYPE_ADJUSTMENT,
00683 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
00684 ARG_VADJUSTMENT);
00685 gtk_object_add_arg_type ("ExtGtkText::line_wrap",
00686 GTK_TYPE_BOOL,
00687 GTK_ARG_READWRITE,
00688 ARG_LINE_WRAP);
00689 gtk_object_add_arg_type ("ExtGtkText::word_wrap",
00690 GTK_TYPE_BOOL,
00691 GTK_ARG_READWRITE,
00692 ARG_WORD_WRAP);
00693
00694 object_class->set_arg = gtk_text_set_arg;
00695 object_class->get_arg = gtk_text_get_arg;
00696 object_class->destroy = gtk_text_destroy;
00697 object_class->finalize = gtk_text_finalize;
00698
00699 widget_class->realize = gtk_text_realize;
00700 widget_class->unrealize = gtk_text_unrealize;
00701 widget_class->style_set = gtk_text_style_set;
00702 widget_class->state_changed = gtk_text_state_changed;
00703 widget_class->draw_focus = gtk_text_draw_focus;
00704 widget_class->size_request = gtk_text_size_request;
00705 widget_class->size_allocate = gtk_text_size_allocate;
00706 widget_class->draw = gtk_text_draw;
00707 widget_class->expose_event = gtk_text_expose;
00708 widget_class->button_press_event = gtk_text_button_press;
00709 widget_class->button_release_event = gtk_text_button_release;
00710 widget_class->motion_notify_event = gtk_text_motion_notify;
00711 widget_class->key_press_event = gtk_text_key_press;
00712 widget_class->focus_in_event = gtk_text_focus_in;
00713 widget_class->focus_out_event = gtk_text_focus_out;
00714
00715 widget_class->set_scroll_adjustments_signal =
00716 gtk_signal_new ("set_scroll_adjustments",
00717 GTK_RUN_LAST,
00718 object_class->type,
00719 GTK_SIGNAL_OFFSET (ExtGtkTextClass, set_scroll_adjustments),
00720 gtk_marshal_NONE__POINTER_POINTER,
00721 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
00722
00723 editable_class->set_editable = gtk_text_real_set_editable;
00724 editable_class->insert_text = ext_gtk_text_insert_text;
00725 editable_class->delete_text = gtk_text_delete_text;
00726
00727 editable_class->move_cursor = gtk_text_move_cursor;
00728 editable_class->move_word = gtk_text_move_word;
00729 editable_class->move_page = gtk_text_move_page;
00730 editable_class->move_to_row = gtk_text_move_to_row;
00731 editable_class->move_to_column = gtk_text_move_to_column;
00732
00733 editable_class->kill_char = gtk_text_kill_char;
00734 editable_class->kill_word = gtk_text_kill_word;
00735 editable_class->kill_line = gtk_text_kill_line;
00736
00737 editable_class->update_text = gtk_text_update_text;
00738 editable_class->get_chars = gtk_text_get_chars;
00739 editable_class->set_selection = gtk_text_set_selection;
00740 editable_class->set_position = gtk_text_set_position;
00741
00742 class->set_scroll_adjustments = ext_gtk_text_set_adjustments;
00743 }
00744
00745 static void
00746 gtk_text_set_arg (GtkObject *object,
00747 GtkArg *arg,
00748 guint arg_id)
00749 {
00750 ExtGtkText *text;
00751
00752 text = EXT_GTK_TEXT (object);
00753
00754 switch (arg_id)
00755 {
00756 case ARG_HADJUSTMENT:
00757 ext_gtk_text_set_adjustments (text,
00758 GTK_VALUE_POINTER (*arg),
00759 text->vadj);
00760 break;
00761 case ARG_VADJUSTMENT:
00762 ext_gtk_text_set_adjustments (text,
00763 text->hadj,
00764 GTK_VALUE_POINTER (*arg));
00765 break;
00766 case ARG_LINE_WRAP:
00767 ext_gtk_text_set_line_wrap (text, GTK_VALUE_BOOL (*arg));
00768 break;
00769 case ARG_WORD_WRAP:
00770 ext_gtk_text_set_word_wrap (text, GTK_VALUE_BOOL (*arg));
00771 break;
00772 default:
00773 break;
00774 }
00775 }
00776
00777 static void
00778 gtk_text_get_arg (GtkObject *object,
00779 GtkArg *arg,
00780 guint arg_id)
00781 {
00782 ExtGtkText *text;
00783
00784 text = EXT_GTK_TEXT (object);
00785
00786 switch (arg_id)
00787 {
00788 case ARG_HADJUSTMENT:
00789 GTK_VALUE_POINTER (*arg) = text->hadj;
00790 break;
00791 case ARG_VADJUSTMENT:
00792 GTK_VALUE_POINTER (*arg) = text->vadj;
00793 break;
00794 case ARG_LINE_WRAP:
00795 GTK_VALUE_BOOL (*arg) = text->line_wrap;
00796 break;
00797 case ARG_WORD_WRAP:
00798 GTK_VALUE_BOOL (*arg) = text->word_wrap;
00799 break;
00800 default:
00801 arg->type = GTK_TYPE_INVALID;
00802 break;
00803 }
00804 }
00805
00806 static void
00807 gtk_text_init (ExtGtkText *text)
00808 {
00809 GTK_WIDGET_SET_FLAGS (text, GTK_CAN_FOCUS);
00810
00811 text->text_area = NULL;
00812 text->hadj = NULL;
00813 text->vadj = NULL;
00814 text->gc = NULL;
00815 text->bg_gc = NULL;
00816
00817 text->use_wchar = FALSE;
00818 text->text.ch = g_new (guchar, INITIAL_BUFFER_SIZE);
00819 text->text_len = INITIAL_BUFFER_SIZE;
00820
00821 text->scratch_buffer.ch = NULL;
00822 text->scratch_buffer_len = 0;
00823
00824 text->freeze_count = 0;
00825
00826 if (!params_mem_chunk)
00827 params_mem_chunk = g_mem_chunk_new ("LineParams",
00828 sizeof (LineParams),
00829 256 * sizeof (LineParams),
00830 G_ALLOC_AND_FREE);
00831
00832 text->default_tab_width = 4;
00833 text->tab_stops = NULL;
00834
00835 text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);
00836 text->tab_stops = g_list_prepend (text->tab_stops, (void*)8);
00837
00838 text->line_start_cache = NULL;
00839 text->first_cut_pixels = 0;
00840
00841 text->line_wrap = TRUE;
00842 text->word_wrap = FALSE;
00843
00844
00845 text->timer = 0;
00846 text->button = 0;
00847
00848 text->current_font = NULL;
00849
00850 init_properties (text);
00851
00852 GTK_EDITABLE (text)->editable = FALSE;
00853
00854 gtk_editable_set_position (GTK_EDITABLE (text), 0);
00855 }
00856
00857 GtkWidget*
00858 ext_gtk_text_new (GtkAdjustment *hadj,
00859 GtkAdjustment *vadj)
00860 {
00861 GtkWidget *text;
00862 #ifdef HAVE_LIBXFT
00863 if(!default_font)
00864 {
00865 default_font = XftFontOpen(gdk_display, DefaultScreen(gdk_display),XFT_FAMILY, XftTypeString,
00866 "Helvetica",XFT_FAMILY, XftTypeString,
00867 "Arial",XFT_SIZE, XftTypeInteger, 10,0);
00868 }
00869 #endif
00870
00871 if (hadj)
00872 g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadj), NULL);
00873 if (vadj)
00874 g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadj), NULL);
00875
00876 text = gtk_widget_new (EXT_GTK_TYPE_TEXT,
00877 "hadjustment", hadj,
00878 "vadjustment", vadj,
00879 NULL);
00880
00881 return text;
00882 }
00883
00884 void
00885 ext_gtk_text_set_word_wrap (ExtGtkText *text,
00886 gint word_wrap)
00887 {
00888 g_return_if_fail (text != NULL);
00889 g_return_if_fail (EXT_GTK_IS_TEXT (text));
00890
00891 text->word_wrap = (word_wrap != FALSE);
00892
00893 if (GTK_WIDGET_REALIZED (text))
00894 {
00895 recompute_geometry (text);
00896 gtk_widget_queue_draw (GTK_WIDGET (text));
00897 }
00898 }
00899
00900 void
00901 ext_gtk_text_set_line_wrap (ExtGtkText *text,
00902 gint line_wrap)
00903 {
00904 g_return_if_fail (text != NULL);
00905 g_return_if_fail (EXT_GTK_IS_TEXT (text));
00906
00907 text->line_wrap = (line_wrap != FALSE);
00908
00909 if (GTK_WIDGET_REALIZED (text))
00910 {
00911 recompute_geometry (text);
00912 gtk_widget_queue_draw (GTK_WIDGET (text));
00913 }
00914 }
00915
00916 void
00917 ext_gtk_text_set_editable (ExtGtkText *text,
00918 gboolean is_editable)
00919 {
00920 g_return_if_fail (text != NULL);
00921 g_return_if_fail (EXT_GTK_IS_TEXT (text));
00922
00923 gtk_editable_set_editable (GTK_EDITABLE (text), is_editable);
00924 }
00925
00926 static void
00927 gtk_text_real_set_editable (GtkEditable *editable,
00928 gboolean is_editable)
00929 {
00930 ExtGtkText *text;
00931
00932 g_return_if_fail (editable != NULL);
00933 g_return_if_fail (EXT_GTK_IS_TEXT (editable));
00934
00935 text = EXT_GTK_TEXT (editable);
00936
00937 editable->editable = (is_editable != FALSE);
00938
00939 if (GTK_WIDGET_REALIZED (text))
00940 {
00941 recompute_geometry (text);
00942 gtk_widget_queue_draw (GTK_WIDGET (text));
00943 }
00944 }
00945
00946 void
00947 ext_gtk_text_set_adjustments (ExtGtkText *text,
00948 GtkAdjustment *hadj,
00949 GtkAdjustment *vadj)
00950 {
00951 g_return_if_fail (text != NULL);
00952 g_return_if_fail (EXT_GTK_IS_TEXT (text));
00953 if (hadj)
00954 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
00955 else
00956 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
00957 if (vadj)
00958 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
00959 else
00960 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
00961
00962 if (text->hadj && (text->hadj != hadj))
00963 {
00964 gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text);
00965 gtk_object_unref (GTK_OBJECT (text->hadj));
00966 }
00967
00968 if (text->vadj && (text->vadj != vadj))
00969 {
00970 gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text);
00971 gtk_object_unref (GTK_OBJECT (text->vadj));
00972 }
00973
00974 if (text->hadj != hadj)
00975 {
00976 text->hadj = hadj;
00977 gtk_object_ref (GTK_OBJECT (text->hadj));
00978 gtk_object_sink (GTK_OBJECT (text->hadj));
00979
00980 gtk_signal_connect (GTK_OBJECT (text->hadj), "changed",
00981 (GtkSignalFunc) gtk_text_adjustment,
00982 text);
00983 gtk_signal_connect (GTK_OBJECT (text->hadj), "value_changed",
00984 (GtkSignalFunc) gtk_text_adjustment,
00985 text);
00986 gtk_signal_connect (GTK_OBJECT (text->hadj), "disconnect",
00987 (GtkSignalFunc) gtk_text_disconnect,
00988 text);
00989 gtk_text_adjustment (hadj, text);
00990 }
00991
00992 if (text->vadj != vadj)
00993 {
00994 text->vadj = vadj;
00995 gtk_object_ref (GTK_OBJECT (text->vadj));
00996 gtk_object_sink (GTK_OBJECT (text->vadj));
00997
00998 gtk_signal_connect (GTK_OBJECT (text->vadj), "changed",
00999 (GtkSignalFunc) gtk_text_adjustment,
01000 text);
01001 gtk_signal_connect (GTK_OBJECT (text->vadj), "value_changed",
01002 (GtkSignalFunc) gtk_text_adjustment,
01003 text);
01004 gtk_signal_connect (GTK_OBJECT (text->vadj), "disconnect",
01005 (GtkSignalFunc) gtk_text_disconnect,
01006 text);
01007 gtk_text_adjustment (vadj, text);
01008 }
01009 }
01010
01011 void
01012 ext_gtk_text_set_point (ExtGtkText *text,
01013 guint index)
01014 {
01015 g_return_if_fail (text != NULL);
01016 g_return_if_fail (EXT_GTK_IS_TEXT (text));
01017 g_return_if_fail (index <= TEXT_LENGTH (text));
01018
01019 text->point = find_mark (text, index);
01020 }
01021
01022 guint
01023 ext_gtk_text_get_point (ExtGtkText *text)
01024 {
01025 g_return_val_if_fail (text != NULL, 0);
01026 g_return_val_if_fail (EXT_GTK_IS_TEXT (text), 0);
01027
01028 return text->point.index;
01029 }
01030
01031 guint
01032 ext_gtk_text_get_length (ExtGtkText *text)
01033 {
01034 g_return_val_if_fail (text != NULL, 0);
01035 g_return_val_if_fail (EXT_GTK_IS_TEXT (text), 0);
01036
01037 return TEXT_LENGTH (text);
01038 }
01039
01040 void
01041 ext_gtk_text_freeze (ExtGtkText *text)
01042 {
01043 g_return_if_fail (text != NULL);
01044 g_return_if_fail (EXT_GTK_IS_TEXT (text));
01045
01046 text->freeze_count++;
01047 undraw_cursor (text, FALSE);
01048 }
01049
01050 void
01051 ext_gtk_text_thaw (ExtGtkText *text)
01052 {
01053 g_return_if_fail (text != NULL);
01054 g_return_if_fail (EXT_GTK_IS_TEXT (text));
01055
01056 if (text->freeze_count)
01057 if (!(--text->freeze_count) && GTK_WIDGET_REALIZED (text))
01058 {
01059 recompute_geometry (text);
01060 gtk_widget_queue_draw (GTK_WIDGET (text));
01061 }
01062 draw_cursor (text, FALSE);
01063 }
01064
01065 void
01066 ext_gtk_text_insert_alltypes (ExtGtkText *text,
01067 VFont *font,
01068 GdkColor *fore,
01069 GdkColor *back,
01070 gboolean underlined,
01071 gboolean divider,
01072 GdkDrawable *image,
01073 GdkBitmap *mask,
01074 gpointer user_data,
01075 guint user_data_length,
01076 DataFunc *user_data_func,
01077 const char *chars,
01078 gint nchars)
01079 {
01080 GtkEditable *editable = GTK_EDITABLE (text);
01081 gboolean frozen = FALSE;
01082
01083 gint new_line_count = 1;
01084 guint old_height = 0;
01085 guint length;
01086 gint i;
01087 gint numwcs;
01088
01089 g_return_if_fail (text != NULL);
01090 g_return_if_fail (EXT_GTK_IS_TEXT (text));
01091 if (nchars > 0)
01092 g_return_if_fail (chars != NULL);
01093 else
01094 {
01095 if (!nchars || !chars)
01096 return;
01097 nchars = strlen (chars);
01098 }
01099 length = nchars;
01100
01101 if (!text->freeze_count && (length > FREEZE_LENGTH))
01102 {
01103 ext_gtk_text_freeze (text);
01104 frozen = TRUE;
01105 }
01106
01107 if (!text->freeze_count && (text->line_start_cache != NULL))
01108 {
01109 find_line_containing_point (text, text->point.index, TRUE);
01110 old_height = total_line_height (text, text->current_line, 1);
01111 }
01112
01113 if ((TEXT_LENGTH (text) == 0) && (text->use_wchar == FALSE))
01114 {
01115 GtkWidget *widget;
01116 widget = GTK_WIDGET (text);
01117 gtk_widget_ensure_style (widget);
01118 if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET))
01119 {
01120 text->use_wchar = TRUE;
01121 g_free (text->text.ch);
01122 text->text.wc = g_new (GdkWChar, INITIAL_BUFFER_SIZE);
01123 text->text_len = INITIAL_BUFFER_SIZE;
01124 if (text->scratch_buffer.ch)
01125 g_free (text->scratch_buffer.ch);
01126 text->scratch_buffer.wc = NULL;
01127 text->scratch_buffer_len = 0;
01128 }
01129 }
01130
01131 move_gap (text, text->point.index);
01132 make_forward_space (text, length);
01133
01134 if (text->use_wchar)
01135 {
01136 char *chars_nt = (char *)chars;
01137 if (nchars > 0)
01138 {
01139 chars_nt = g_new (char, length+1);
01140 memcpy (chars_nt, chars, length);
01141 chars_nt[length] = 0;
01142 }
01143 numwcs = gdk_mbstowcs (text->text.wc + text->gap_position, chars_nt,
01144 length);
01145 if (chars_nt != chars)
01146 g_free(chars_nt);
01147 if (numwcs < 0)
01148 numwcs = 0;
01149 }
01150 else
01151 {
01152 numwcs = length;
01153 memcpy(text->text.ch + text->gap_position, chars, strlen(chars));
01154 }
01155
01156 if (!text->freeze_count && (text->line_start_cache != NULL))
01157 {
01158 if (text->use_wchar)
01159 {
01160 for (i=0; i<numwcs; i++)
01161 if (text->text.wc[text->gap_position + i] == '\n')
01162 new_line_count++;
01163 }
01164 else
01165 {
01166 for (i=0; i<numwcs; i++)
01167 if (text->text.ch[text->gap_position + i] == '\n')
01168 new_line_count++;
01169 }
01170 }
01171
01172 if (numwcs > 0)
01173 {
01174
01175 insert_text_property (text, font, fore, back, underlined, divider, image, mask, user_data, user_data_length, user_data_func, numwcs);
01176
01177 text->gap_size -= numwcs;
01178 text->gap_position += numwcs;
01179
01180 if (text->point.index < text->first_line_start_index)
01181 text->first_line_start_index += numwcs;
01182 if (text->point.index < editable->selection_start_pos)
01183 editable->selection_start_pos += numwcs;
01184 if (text->point.index < editable->selection_end_pos)
01185 editable->selection_end_pos += numwcs;
01186
01187 if (text->point.index < text->cursor_mark.index)
01188 text->cursor_mark.index += numwcs;
01189
01190 advance_mark_n (&text->point, numwcs);
01191
01192 if (!text->freeze_count && (text->line_start_cache != NULL))
01193 insert_expose (text, old_height, numwcs, new_line_count);
01194 }
01195
01196 if (frozen)
01197 ext_gtk_text_thaw (text);
01198 }
01199
01200 void
01201 ext_gtk_text_insert (ExtGtkText *text,
01202 VFont*font,
01203 GdkColor *fore,
01204 GdkColor *back,
01205 const char *chars,
01206 gint nchars)
01207 {
01208 ext_gtk_text_insert_alltypes(text, font, fore, back, FALSE, FALSE, NULL, NULL, NULL,0,NULL, chars, nchars);
01209 }
01210
01211 void
01212 ext_gtk_text_insert_underlined (ExtGtkText *text,
01213 VFont*font,
01214 GdkColor *fore,
01215 GdkColor *back,
01216 const char *chars,
01217 gint nchars)
01218 {
01219 ext_gtk_text_insert_alltypes(text, font, fore, back, TRUE, FALSE, NULL, NULL, NULL,0, NULL, chars, nchars);
01220 }
01221
01222 void
01223 ext_gtk_text_insert_divider(ExtGtkText *text,
01224 VFont *font,
01225 GdkColor *fore,
01226 GdkColor *back,
01227 const char *chars,
01228 gint nchars)
01229 {
01230 ext_gtk_text_insert_alltypes(text, font, fore, back, FALSE, TRUE, NULL, NULL, NULL,0, NULL, " \n", 2);
01231 }
01232
01233 void
01234 ext_gtk_text_insert_pixmap (ExtGtkText *text,
01235 VFont*font,
01236 GdkColor *fore,
01237 GdkColor *back,
01238 GdkDrawable *image,
01239 GdkBitmap *mask,
01240 const char *chars,
01241 gint nchars)
01242 {
01243 ext_gtk_text_insert_alltypes(text, font, fore, back, FALSE, FALSE, image, mask, NULL,0,NULL, " ", 1);
01244 }
01245
01246 void
01247 ext_gtk_text_insert_data_underlined (ExtGtkText *text,
01248 VFont*font,
01249 GdkColor *fore,
01250 GdkColor *back,
01251 gpointer user_data_n,
01252 guint user_data_length,
01253 DataFunc *user_data_func,
01254 const char *chars,
01255 gint nchars)
01256 {
01257 gpointer user_data=g_malloc(user_data_length);
01258 memcpy(user_data,user_data_n, user_data_length);
01259 ext_gtk_text_insert_alltypes(text, font, fore, back, TRUE, FALSE, NULL, NULL, user_data, user_data_length, user_data_func, chars, nchars);
01260 }
01261
01262 void
01263 ext_gtk_text_insert_data (ExtGtkText *text,
01264 VFont*font,
01265 GdkColor *fore,
01266 GdkColor *back,
01267 gpointer user_data_n,
01268 guint user_data_length,
01269 DataFunc *user_data_func,
01270 const char *chars,
01271 gint nchars)
01272 {
01273 gpointer user_data=g_malloc(user_data_length);
01274 memcpy(user_data,user_data_n, user_data_length);
01275 ext_gtk_text_insert_alltypes(text, font, fore, back, FALSE, FALSE, NULL, NULL, user_data, user_data_length, user_data_func, chars, nchars);
01276 }
01277
01278 gint
01279 ext_gtk_text_backward_delete (ExtGtkText *text,
01280 guint nchars)
01281 {
01282 g_return_val_if_fail (text != NULL, 0);
01283 g_return_val_if_fail (EXT_GTK_IS_TEXT (text), 0);
01284
01285 if (nchars > text->point.index || nchars <= 0)
01286 return FALSE;
01287
01288 ext_gtk_text_set_point (text, text->point.index - nchars);
01289
01290 return ext_gtk_text_forward_delete (text, nchars);
01291 }
01292
01293 gint
01294 ext_gtk_text_forward_delete (ExtGtkText *text,
01295 guint nchars)
01296 {
01297 guint old_lines, old_height;
01298 GtkEditable *editable = GTK_EDITABLE (text);
01299 gboolean frozen = FALSE;
01300
01301 g_return_val_if_fail (text != NULL, 0);
01302 g_return_val_if_fail (EXT_GTK_IS_TEXT (text), 0);
01303
01304 if (text->point.index + nchars > TEXT_LENGTH (text) || nchars <= 0)
01305 return FALSE;
01306
01307 if (!text->freeze_count && nchars > FREEZE_LENGTH)
01308 {
01309 ext_gtk_text_freeze (text);
01310 frozen = TRUE;
01311 }
01312
01313 if (!text->freeze_count && text->line_start_cache != NULL)
01314 {
01315
01316
01317
01318 undraw_cursor (text, FALSE);
01319 find_line_containing_point (text, text->point.index, TRUE);
01320 compute_lines_pixels (text, nchars, &old_lines, &old_height);
01321 }
01322
01323
01324 if (text->point.index < text->first_line_start_index)
01325 {
01326 if (text->point.index + nchars >= text->first_line_start_index)
01327 {
01328 text->first_line_start_index = text->point.index;
01329 while ((text->first_line_start_index > 0) &&
01330 (EXT_GTK_TEXT_INDEX (text, text->first_line_start_index - 1)
01331 != LINE_DELIM))
01332 text->first_line_start_index -= 1;
01333
01334 }
01335 else
01336 text->first_line_start_index -= nchars;
01337 }
01338
01339 if (text->point.index < editable->selection_start_pos)
01340 editable->selection_start_pos -=
01341 MIN(nchars, editable->selection_start_pos - text->point.index);
01342 if (text->point.index < editable->selection_end_pos)
01343 editable->selection_end_pos -=
01344 MIN(nchars, editable->selection_end_pos - text->point.index);
01345
01346 if (text->point.index < text->cursor_mark.index)
01347 move_mark_n (&text->cursor_mark,
01348 -MIN(nchars, text->cursor_mark.index - text->point.index));
01349
01350 move_gap (text, text->point.index);
01351
01352 text->gap_size += nchars;
01353
01354 delete_text_property (text, nchars);
01355
01356 if (!text->freeze_count && (text->line_start_cache != NULL))
01357 {
01358 delete_expose (text, nchars, old_lines, old_height);
01359 draw_cursor (text, FALSE);
01360 }
01361
01362 if (frozen)
01363 ext_gtk_text_thaw (text);
01364
01365 return TRUE;
01366 }
01367
01368 static void
01369 gtk_text_set_position (GtkEditable *editable,
01370 gint position)
01371 {
01372 ExtGtkText *text = (ExtGtkText *) editable;
01373
01374 undraw_cursor (text, FALSE);
01375 text->cursor_mark = find_mark (text, position);
01376 find_cursor (text, TRUE);
01377 draw_cursor (text, FALSE);
01378 gtk_editable_select_region (editable, 0, 0);
01379 }
01380
01381 static gchar *
01382 gtk_text_get_chars (GtkEditable *editable,
01383 gint start_pos,
01384 gint end_pos)
01385 {
01386 ExtGtkText *text;
01387
01388 gchar *retval;
01389
01390 g_return_val_if_fail (editable != NULL, NULL);
01391 g_return_val_if_fail (EXT_GTK_IS_TEXT (editable), NULL);
01392 text = EXT_GTK_TEXT (editable);
01393
01394 if (end_pos < 0)
01395 end_pos = TEXT_LENGTH (text);
01396
01397 if ((start_pos < 0) ||
01398 (end_pos > TEXT_LENGTH (text)) ||
01399 (end_pos < start_pos))
01400 return NULL;
01401
01402 move_gap (text, TEXT_LENGTH (text));
01403 make_forward_space (text, 1);
01404
01405 if (text->use_wchar)
01406 {
01407 GdkWChar ch;
01408 ch = text->text.wc[end_pos];
01409 text->text.wc[end_pos] = 0;
01410 retval = gdk_wcstombs (text->text.wc + start_pos);
01411 text->text.wc[end_pos] = ch;
01412 }
01413 else
01414 {
01415 guchar ch;
01416 ch = text->text.ch[end_pos];
01417 text->text.ch[end_pos] = 0;
01418 retval = g_strdup (text->text.ch + start_pos);
01419 text->text.ch[end_pos] = ch;
01420 }
01421
01422 return retval;
01423 }
01424
01425
01426 static void
01427 gtk_text_destroy (GtkObject *object)
01428 {
01429 ExtGtkText *text;
01430 g_return_if_fail (object != NULL);
01431 g_return_if_fail (EXT_GTK_IS_TEXT (object));
01432
01433 text = (ExtGtkText*) object;
01434
01435 gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text);
01436 gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text);
01437
01438 if (text->timer)
01439 {
01440 gtk_timeout_remove (text->timer);
01441 text->timer = 0;
01442 }
01443
01444 GTK_OBJECT_CLASS(parent_class)->destroy (object);
01445 }
01446
01447 static void
01448 gtk_text_finalize (GtkObject *object)
01449 {
01450 ExtGtkText *text;
01451 GList *tmp_list;
01452
01453 g_return_if_fail (object != NULL);
01454 g_return_if_fail (EXT_GTK_IS_TEXT (object));
01455
01456 text = (ExtGtkText *)object;
01457
01458 gtk_object_unref (GTK_OBJECT (text->hadj));
01459 gtk_object_unref (GTK_OBJECT (text->vadj));
01460
01461
01462 if (text->use_wchar)
01463 g_free (text->text.wc);
01464 else
01465 g_free (text->text.ch);
01466
01467 tmp_list = text->text_properties;
01468 while (tmp_list)
01469 {
01470 destroy_text_property (tmp_list->data);
01471 tmp_list = tmp_list->next;
01472 }
01473
01474 if (text->current_font)
01475 text_font_unref (text->current_font);
01476
01477 g_list_free (text->text_properties);
01478
01479 if (text->use_wchar)
01480 {
01481 if (text->scratch_buffer.wc)
01482 g_free (text->scratch_buffer.wc);
01483 }
01484 else
01485 {
01486 if (text->scratch_buffer.ch)
01487 g_free (text->scratch_buffer.ch);
01488 }
01489
01490 g_list_free (text->tab_stops);
01491
01492 GTK_OBJECT_CLASS(parent_class)->finalize (object);
01493 }
01494
01495 static void
01496 gtk_text_realize (GtkWidget *widget)
01497 {
01498 ExtGtkText *text;
01499 GtkEditable *editable;
01500 GdkWindowAttr attributes;
01501 gint attributes_mask;
01502
01503 g_return_if_fail (widget != NULL);
01504 g_return_if_fail (EXT_GTK_IS_TEXT (widget));
01505
01506 text = EXT_GTK_TEXT (widget);
01507 editable = GTK_EDITABLE (widget);
01508 GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED);
01509
01510 attributes.window_type = GDK_WINDOW_CHILD;
01511 attributes.x = widget->allocation.x;
01512 attributes.y = widget->allocation.y;
01513 attributes.width = widget->allocation.width;
01514 attributes.height = widget->allocation.height;
01515 attributes.wclass = GDK_INPUT_OUTPUT;
01516 attributes.visual = gtk_widget_get_visual (widget);
01517 attributes.colormap = gtk_widget_get_colormap (widget);
01518 attributes.event_mask = gtk_widget_get_events (widget);
01519 attributes.event_mask |= (GDK_EXPOSURE_MASK |
01520 GDK_BUTTON_PRESS_MASK |
01521 GDK_BUTTON_RELEASE_MASK |
01522 GDK_BUTTON_MOTION_MASK |
01523 GDK_ENTER_NOTIFY_MASK |
01524 GDK_LEAVE_NOTIFY_MASK |
01525 GDK_KEY_PRESS_MASK);
01526 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
01527
01528 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
01529 gdk_window_set_user_data (widget->window, text);
01530
01531 attributes.x = (widget->style->klass->xthickness + TEXT_BORDER_ROOM);
01532 attributes.y = (widget->style->klass->ythickness + TEXT_BORDER_ROOM);
01533 attributes.width = MAX (1, (gint)widget->allocation.width - (gint)attributes.x * 2);
01534 attributes.height = MAX (1, (gint)widget->allocation.height - (gint)attributes.y * 2);
01535
01536 text->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
01537 gdk_window_set_user_data (text->text_area, text);
01538
01539 widget->style = gtk_style_attach (widget->style, widget->window);
01540
01541
01542 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
01543 gdk_window_set_background (text->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
01544
01545 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
01546 text->bg_gc = create_bg_gc (text);
01547
01548
01549 text->gc = gdk_gc_new (text->text_area);
01550 gdk_gc_set_exposures (text->gc, TRUE);
01551 gdk_gc_set_foreground (text->gc, &widget->style->text[GTK_STATE_NORMAL]);
01552
01553 #ifdef USE_XIM
01554 if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL)
01555 {
01556 gint width, height;
01557 GdkColormap *colormap;
01558 GdkEventMask mask;
01559 GdkICAttr *attr = editable->ic_attr;
01560 GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
01561 GdkIMStyle style;
01562 GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE |
01563 GDK_IM_PREEDIT_NOTHING |
01564 GDK_IM_PREEDIT_POSITION |
01565 GDK_IM_STATUS_NONE |
01566 GDK_IM_STATUS_NOTHING;
01567
01568 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
01569 supported_style &= ~GDK_IM_PREEDIT_POSITION;
01570
01571 attr->style = style = gdk_im_decide_style (supported_style);
01572 attr->client_window = text->text_area;
01573
01574 if ((colormap = gtk_widget_get_colormap (widget)) !=
01575 gtk_widget_get_default_colormap ())
01576 {
01577 attrmask |= GDK_IC_PREEDIT_COLORMAP;
01578 attr->preedit_colormap = colormap;
01579 }
01580
01581 switch (style & GDK_IM_PREEDIT_MASK)
01582 {
01583 case GDK_IM_PREEDIT_POSITION:
01584 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
01585 {
01586 g_warning ("over-the-spot style requires fontset");
01587 break;
01588 }
01589
01590 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
01591 gdk_window_get_size (text->text_area, &width, &height);
01592 attr->spot_location.x = 0;
01593 attr->spot_location.y = height;
01594 attr->preedit_area.x = 0;
01595 attr->preedit_area.y = 0;
01596 attr->preedit_area.width = width;
01597 attr->preedit_area.height = height;
01598 attr->preedit_fontset = widget->style->font;
01599
01600 break;
01601 }
01602 editable->ic = gdk_ic_new (attr, attrmask);
01603
01604 if (editable->ic == NULL)
01605 g_warning ("Can't create input context.");
01606 else
01607 {
01608 mask = gdk_window_get_events (text->text_area);
01609 mask |= gdk_ic_get_events (editable->ic);
01610 gdk_window_set_events (text->text_area, mask);
01611
01612 if (GTK_WIDGET_HAS_FOCUS (widget))
01613 gdk_im_begin (editable->ic, text->text_area);
01614 }
01615 }
01616 #endif
01617
01618 realize_properties (text);
01619 gdk_window_show (text->text_area);
01620 init_properties (text);
01621
01622 if (editable->selection_start_pos != editable->selection_end_pos)
01623 gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
01624
01625 recompute_geometry (text);
01626 }
01627
01628 static void
01629 gtk_text_style_set (GtkWidget *widget,
01630 GtkStyle *previous_style)
01631 {
01632 ExtGtkText *text = EXT_GTK_TEXT (widget);
01633
01634 if (GTK_WIDGET_REALIZED (widget))
01635 {
01636 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
01637 gdk_window_set_background (text->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
01638
01639 if (text->bg_gc)
01640 {
01641 gdk_gc_destroy (text->bg_gc);
01642 text->bg_gc = NULL;
01643 }
01644
01645 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
01646 text->bg_gc = create_bg_gc (text);
01647
01648 recompute_geometry (text);
01649 }
01650
01651 if (text->current_font)
01652 text_font_unref (text->current_font);
01653 #ifndef HAVE_LIBXFT
01654 text->current_font = get_text_font (widget->style->font);
01655 #else
01656 text->current_font = get_text_font(default_font);
01657 #endif
01658 }
01659
01660 static void
01661 gtk_text_state_changed (GtkWidget *widget,
01662 GtkStateType previous_state)
01663 {
01664 ExtGtkText *text = EXT_GTK_TEXT (widget);
01665
01666 if (GTK_WIDGET_REALIZED (widget))
01667 {
01668 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
01669 gdk_window_set_background (text->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
01670 }
01671 }
01672
01673 static void
01674 gtk_text_unrealize (GtkWidget *widget)
01675 {
01676 ExtGtkText *text;
01677
01678 g_return_if_fail (widget != NULL);
01679 g_return_if_fail (EXT_GTK_IS_TEXT (widget));
01680
01681 text = EXT_GTK_TEXT (widget);
01682
01683 #ifdef USE_XIM
01684 if (GTK_EDITABLE (widget)->ic)
01685 {
01686 gdk_ic_destroy (GTK_EDITABLE (widget)->ic);
01687 GTK_EDITABLE (widget)->ic = NULL;
01688 }
01689 if (GTK_EDITABLE (widget)->ic_attr)
01690 {
01691 gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr);
01692 GTK_EDITABLE (widget)->ic_attr = NULL;
01693 }
01694 #endif
01695
01696 gdk_window_set_user_data (text->text_area, NULL);
01697 gdk_window_destroy (text->text_area);
01698 text->text_area = NULL;
01699
01700 gdk_gc_destroy (text->gc);
01701 text->gc = NULL;
01702
01703 if (text->bg_gc)
01704 {
01705 gdk_gc_destroy (text->bg_gc);
01706 text->bg_gc = NULL;
01707 }
01708
01709
01710 unrealize_properties (text);
01711
01712 free_cache (text);
01713
01714 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
01715 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
01716 }
01717
01718 static void
01719 clear_focus_area (ExtGtkText *text, gint area_x, gint area_y, gint area_width, gint area_height)
01720 {
01721 GtkWidget *widget = GTK_WIDGET (text);
01722
01723 gint ythick = TEXT_BORDER_ROOM + widget->style->klass->ythickness;
01724 gint xthick = TEXT_BORDER_ROOM + widget->style->klass->xthickness;
01725
01726 gint width, height;
01727
01728 gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height);
01729
01730 gdk_gc_set_ts_origin (text->bg_gc,
01731 (- (gint)text->first_onscreen_hor_pixel + xthick) % width,
01732 (- (gint)text->first_onscreen_ver_pixel + ythick) % height);
01733
01734
01735 gdk_draw_rectangle (GTK_WIDGET (text)->window, text->bg_gc, TRUE,
01736 area_x, area_y, area_width, area_height);
01737 }
01738
01739 static void
01740 gtk_text_draw_focus (GtkWidget *widget)
01741 {
01742 ExtGtkText *text;
01743 gint width, height;
01744 gint x, y;
01745
01746 g_return_if_fail (widget != NULL);
01747 g_return_if_fail (EXT_GTK_IS_TEXT (widget));
01748
01749 text = EXT_GTK_TEXT (widget);
01750
01751 if (GTK_WIDGET_DRAWABLE (widget))
01752 {
01753 gint ythick = widget->style->klass->ythickness;
01754 gint xthick = widget->style->klass->xthickness;
01755 gint xextra = TEXT_BORDER_ROOM;
01756 gint yextra = TEXT_BORDER_ROOM;
01757
01758 TDEBUG (("in gtk_text_draw_focus\n"));
01759
01760 x = 0;
01761 y = 0;
01762 width = widget->allocation.width;
01763 height = widget->allocation.height;
01764
01765 if (GTK_WIDGET_HAS_FOCUS (widget))
01766 {
01767 x += 1;
01768 y += 1;
01769 width -= 2;
01770 height -= 2;
01771 xextra -= 1;
01772 yextra -= 1;
01773
01774 gtk_paint_focus (widget->style, widget->window,
01775 NULL, widget, "text",
01776 0, 0,
01777 widget->allocation.width - 1,
01778 widget->allocation.height - 1);
01779 }
01780
01781 gtk_paint_shadow (widget->style, widget->window,
01782 GTK_STATE_NORMAL, GTK_SHADOW_IN,
01783 NULL, widget, "text",
01784 x, y, width, height);
01785
01786 x += xthick;
01787 y += ythick;
01788 width -= 2 * xthick;
01789 height -= 2 * ythick;
01790
01791 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
01792 {
01793
01794 clear_focus_area (text, x, y, width, yextra);
01795
01796 clear_focus_area (text, x, y + yextra,
01797 xextra, y + height - 2 * yextra);
01798
01799 clear_focus_area (text, x + width - xextra, y + yextra,
01800 xextra, height - 2 * ythick);
01801
01802 clear_focus_area (text, x, x + height - yextra, width, yextra);
01803 }
01804 }
01805 else
01806 {
01807 TDEBUG (("in gtk_text_draw_focus (undrawable !!!)\n"));
01808 }
01809 }
01810
01811 static void
01812 gtk_text_size_request (GtkWidget *widget,
01813 GtkRequisition *requisition)
01814 {
01815 gint xthickness;
01816 gint ythickness;
01817 gint char_height;
01818 gint char_width;
01819
01820 g_return_if_fail (widget != NULL);
01821 g_return_if_fail (EXT_GTK_IS_TEXT (widget));
01822 g_return_if_fail (requisition != NULL);
01823
01824 xthickness = widget->style->klass->xthickness + TEXT_BORDER_ROOM;
01825 ythickness = widget->style->klass->ythickness + TEXT_BORDER_ROOM;
01826
01827 char_height = MIN_TEXT_HEIGHT_LINES * (widget->style->font->ascent +
01828 widget->style->font->descent);
01829
01830 char_width = MIN_TEXT_WIDTH_LINES * (gdk_text_width (widget->style->font,
01831 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
01832 26)
01833 / 26);
01834
01835 requisition->width = char_width + xthickness * 2;
01836 requisition->height = char_height + ythickness * 2;
01837 }
01838
01839 static void
01840 gtk_text_size_allocate (GtkWidget *widget,
01841 GtkAllocation *allocation)
01842 {
01843 ExtGtkText *text;
01844 GtkEditable *editable;
01845
01846 g_return_if_fail (widget != NULL);
01847 g_return_if_fail (EXT_GTK_IS_TEXT (widget));
01848 g_return_if_fail (allocation != NULL);
01849
01850 text = EXT_GTK_TEXT (widget);
01851 editable = GTK_EDITABLE (widget);
01852
01853 widget->allocation = *allocation;
01854 if (GTK_WIDGET_REALIZED (widget))
01855 {
01856 gdk_window_move_resize (widget->window,
01857 allocation->x, allocation->y,
01858 allocation->width, allocation->height);
01859
01860 gdk_window_move_resize (text->text_area,
01861 widget->style->klass->xthickness + TEXT_BORDER_ROOM,
01862 widget->style->klass->ythickness + TEXT_BORDER_ROOM,
01863 MAX (1, (gint)widget->allocation.width - (gint)(widget->style->klass->xthickness +
01864 (gint)TEXT_BORDER_ROOM) * 2),
01865 MAX (1, (gint)widget->allocation.height - (gint)(widget->style->klass->ythickness +
01866 (gint)TEXT_BORDER_ROOM) * 2));
01867
01868 #ifdef USE_XIM
01869 if (editable->ic && (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
01870 {
01871 gint width, height;
01872
01873 gdk_window_get_size (text->text_area, &width, &height);
01874 editable->ic_attr->preedit_area.width = width;
01875 editable->ic_attr->preedit_area.height = height;
01876
01877 gdk_ic_set_attr (editable->ic,
01878 editable->ic_attr, GDK_IC_PREEDIT_AREA);
01879 }
01880 #endif
01881
01882 recompute_geometry (text);
01883 }
01884 }
01885
01886 static void
01887 gtk_text_draw (GtkWidget *widget,
01888 GdkRectangle *area)
01889 {
01890 g_return_if_fail (widget != NULL);
01891 g_return_if_fail (EXT_GTK_IS_TEXT (widget));
01892 g_return_if_fail (area != NULL);
01893
01894 if (GTK_WIDGET_DRAWABLE (widget))
01895 {
01896 expose_text (EXT_GTK_TEXT (widget), area, TRUE);
01897 gtk_widget_draw_focus (widget);
01898 }
01899 }
01900
01901 static gint
01902 gtk_text_expose (GtkWidget *widget,
01903 GdkEventExpose *event)
01904 {
01905 g_return_val_if_fail (widget != NULL, FALSE);
01906 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
01907 g_return_val_if_fail (event != NULL, FALSE);
01908
01909 if (event->window == EXT_GTK_TEXT (widget)->text_area)
01910 {
01911 TDEBUG (("in gtk_text_expose (expose)\n"));
01912 expose_text (EXT_GTK_TEXT (widget), &event->area, TRUE);
01913 }
01914 else if (event->count == 0)
01915 {
01916 TDEBUG (("in gtk_text_expose (focus)\n"));
01917 gtk_widget_draw_focus (widget);
01918 }
01919
01920 return FALSE;
01921 }
01922
01923 static gint
01924 gtk_text_scroll_timeout (gpointer data)
01925 {
01926 ExtGtkText *text;
01927 GdkEventMotion event;
01928 gint x, y;
01929 GdkModifierType mask;
01930
01931 GDK_THREADS_ENTER ();
01932
01933 text = EXT_GTK_TEXT (data);
01934
01935 text->timer = 0;
01936 gdk_window_get_pointer (text->text_area, &x, &y, &mask);
01937
01938 if (mask & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK))
01939 {
01940 event.is_hint = 0;
01941 event.x = x;
01942 event.y = y;
01943 event.state = mask;
01944
01945 gtk_text_motion_notify (GTK_WIDGET (text), &event);
01946 }
01947
01948 GDK_THREADS_LEAVE ();
01949
01950 return FALSE;
01951 }
01952
01953 static gint
01954 gtk_text_button_press (GtkWidget *widget,
01955 GdkEventButton *event)
01956 {
01957 ExtGtkText *text;
01958 ExtGtkPropertyMark mark;
01959 GtkEditable *editable;
01960 static GdkAtom ctext_atom = GDK_NONE;
01961 DataFunc *func;
01962
01963 g_return_val_if_fail (widget != NULL, FALSE);
01964 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
01965 g_return_val_if_fail (event != NULL, FALSE);
01966
01967 if (ctext_atom == GDK_NONE)
01968 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
01969
01970 text = EXT_GTK_TEXT (widget);
01971 editable = GTK_EDITABLE (widget);
01972
01973 if (text->button && (event->button != text->button))
01974 return FALSE;
01975
01976 text->button = event->button;
01977
01978 if (!GTK_WIDGET_HAS_FOCUS (widget))
01979 gtk_widget_grab_focus (widget);
01980
01981 if (event->button == 1)
01982 {
01983 switch (event->type)
01984 {
01985 case GDK_BUTTON_PRESS:
01986 gtk_grab_add (widget);
01987
01988 undraw_cursor (text, FALSE);
01989 find_mouse_cursor (text, (gint)event->x, (gint)event->y);
01990 draw_cursor (text, FALSE);
01991
01992 mark=find_mark(text, text->cursor_mark.index);
01993 if (MARK_CURRENT_DATA(text,&mark))
01994 {
01995 func=MARK_CURRENT_DATA_FUNC(text, &mark);
01996 if (func)
01997 func(text->text_area, MARK_CURRENT_DATA(text,&mark));
01998
01999 }
02000
02001
02002
02003 editable->has_selection = TRUE;
02004 gtk_text_set_selection (GTK_EDITABLE(text),
02005 text->cursor_mark.index,
02006 text->cursor_mark.index);
02007
02008 break;
02009
02010 case GDK_2BUTTON_PRESS:
02011 gtk_text_select_word (text, event->time);
02012 break;
02013
02014 case GDK_3BUTTON_PRESS:
02015 gtk_text_select_line (text, event->time);
02016 break;
02017
02018 default:
02019 break;
02020 }
02021 }
02022 else if (event->type == GDK_BUTTON_PRESS)
02023 {
02024 if ((event->button == 2) && editable->editable)
02025 {
02026 if (editable->selection_start_pos == editable->selection_end_pos ||
02027 editable->has_selection)
02028 {
02029 undraw_cursor (text, FALSE);
02030 find_mouse_cursor (text, (gint)event->x, (gint)event->y);
02031 draw_cursor (text, FALSE);
02032
02033 }
02034
02035 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
02036 ctext_atom, event->time);
02037 }
02038 else
02039 {
02040 gtk_grab_add (widget);
02041
02042 undraw_cursor (text, FALSE);
02043 find_mouse_cursor (text, event->x, event->y);
02044 draw_cursor (text, FALSE);
02045
02046 gtk_text_set_selection (GTK_EDITABLE(text),
02047 text->cursor_mark.index,
02048 text->cursor_mark.index);
02049
02050 editable->has_selection = FALSE;
02051 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
02052 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
02053 }
02054 }
02055
02056 return FALSE;
02057 }
02058
02059 static gint
02060 gtk_text_button_release (GtkWidget *widget,
02061 GdkEventButton *event)
02062 {
02063 ExtGtkText *text;
02064 GtkEditable *editable;
02065 g_return_val_if_fail (widget != NULL, FALSE);
02066 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
02067 g_return_val_if_fail (event != NULL, FALSE);
02068
02069 text = EXT_GTK_TEXT (widget);
02070
02071 gtk_grab_remove (widget);
02072
02073 if (text->button != event->button)
02074 return FALSE;
02075
02076 text->button = 0;
02077
02078 if (text->timer)
02079 {
02080 gtk_timeout_remove (text->timer);
02081 text->timer = 0;
02082 }
02083
02084 if (event->button == 1)
02085 {
02086 text = EXT_GTK_TEXT (widget);
02087 editable = GTK_EDITABLE (widget);
02088
02089 gtk_grab_remove (widget);
02090
02091 editable->has_selection = FALSE;
02092 if (editable->selection_start_pos != editable->selection_end_pos)
02093 {
02094 if (gtk_selection_owner_set (widget,
02095 GDK_SELECTION_PRIMARY,
02096 event->time))
02097 editable->has_selection = TRUE;
02098 else
02099 gtk_text_update_text (editable, editable->selection_start_pos,
02100 editable->selection_end_pos);
02101 }
02102 else
02103 {
02104 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
02105 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
02106 }
02107 }
02108 else if (event->button == 3)
02109 {
02110 gtk_grab_remove (widget);
02111 }
02112
02113 undraw_cursor (text, FALSE);
02114 find_cursor (text, TRUE);
02115 draw_cursor (text, FALSE);
02116
02117 return FALSE;
02118 }
02119
02120 static gint
02121 gtk_text_motion_notify (GtkWidget *widget,
02122 GdkEventMotion *event)
02123 {
02124 ExtGtkText *text;
02125 gint x, y;
02126 gint height;
02127 GdkModifierType mask;
02128
02129 g_return_val_if_fail (widget != NULL, FALSE);
02130 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
02131 g_return_val_if_fail (event != NULL, FALSE);
02132
02133 text = EXT_GTK_TEXT (widget);
02134
02135 x = event->x;
02136 y = event->y;
02137 mask = event->state;
02138 if (event->is_hint || (text->text_area != event->window))
02139 {
02140 gdk_window_get_pointer (text->text_area, &x, &y, &mask);
02141 }
02142
02143 if ((text->button == 0) ||
02144 !(mask & (GDK_BUTTON1_MASK | GDK_BUTTON3_MASK)))
02145 return FALSE;
02146
02147 gdk_window_get_size (text->text_area, NULL, &height);
02148
02149 if ((y < 0) || (y > height))
02150 {
02151 if (text->timer == 0)
02152 {
02153 text->timer = gtk_timeout_add (SCROLL_TIME,
02154 gtk_text_scroll_timeout,
02155 text);
02156
02157 if (y < 0)
02158 scroll_int (text, y/2);
02159 else
02160 scroll_int (text, (y - height)/2);
02161 }
02162 else
02163 return FALSE;
02164 }
02165
02166 undraw_cursor (EXT_GTK_TEXT (widget), FALSE);
02167 find_mouse_cursor (EXT_GTK_TEXT (widget), x, y);
02168 draw_cursor (EXT_GTK_TEXT (widget), FALSE);
02169
02170 gtk_text_set_selection (GTK_EDITABLE(text),
02171 GTK_EDITABLE(text)->selection_start_pos,
02172 text->cursor_mark.index);
02173
02174 return FALSE;
02175 }
02176
02177 static void
02178 ext_gtk_text_insert_text (GtkEditable *editable,
02179 const gchar *new_text,
02180 gint new_text_length,
02181 gint *position)
02182 {
02183 ExtGtkText *text = EXT_GTK_TEXT (editable);
02184 VFont*font;
02185 GdkColor *fore, *back;
02186 gboolean underlined;
02187 GdkDrawable *image;
02188 GdkBitmap *mask;
02189 gpointer user_data=NULL;
02190 guint user_data_length=0;
02191 DataFunc *user_data_func=NULL;
02192 TextProperty *property;
02193
02194 ext_gtk_text_set_point (text, *position);
02195
02196 property = MARK_CURRENT_PROPERTY (&text->point);
02197 font = property->flags & PROPERTY_FONT ? property->font->gdk_font : NULL;
02198 fore = property->flags & PROPERTY_FOREGROUND ? &property->fore_color : NULL;
02199 back = property->flags & PROPERTY_BACKGROUND ? &property->back_color : NULL;
02200 underlined = property->flags & PROPERTY_UNDERLINED ? TRUE : FALSE;
02201 image = property->flags & PROPERTY_IMAGE ? property->image : NULL;
02202 mask = property->flags & PROPERTY_IMAGE ? property->mask: NULL;
02203 if (property->flags & PROPERTY_DATA)
02204 {
02205
02206 user_data_length=property->user_data_length;
02207 user_data = g_malloc(user_data_length);
02208 memcpy(user_data, property->user_data, user_data_length);
02209 user_data_func=property->user_data_func;
02210 }
02211 ext_gtk_text_insert_alltypes (text, font, fore, back, underlined, FALSE, image, mask, user_data, user_data_length, user_data_func, new_text, new_text_length);
02212
02213 *position = text->point.index;
02214 }
02215
02216 static void
02217 gtk_text_delete_text (GtkEditable *editable,
02218 gint start_pos,
02219 gint end_pos)
02220 {
02221 ExtGtkText *text;
02222
02223 g_return_if_fail (start_pos >= 0);
02224
02225 text = EXT_GTK_TEXT (editable);
02226
02227 ext_gtk_text_set_point (text, start_pos);
02228 if (end_pos < 0)
02229 end_pos = TEXT_LENGTH (text);
02230
02231 if (end_pos > start_pos)
02232 ext_gtk_text_forward_delete (text, end_pos - start_pos);
02233 }
02234
02235 static gint
02236 gtk_text_key_press (GtkWidget *widget,
02237 GdkEventKey *event)
02238 {
02239 ExtGtkText *text;
02240 GtkEditable *editable;
02241 gchar key;
02242 gint return_val;
02243 gint position;
02244
02245 g_return_val_if_fail (widget != NULL, FALSE);
02246 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
02247 g_return_val_if_fail (event != NULL, FALSE);
02248
02249 return_val = FALSE;
02250
02251 text = EXT_GTK_TEXT (widget);
02252 editable = GTK_EDITABLE (widget);
02253
02254 key = event->keyval;
02255 return_val = TRUE;
02256
02257 if ((GTK_EDITABLE(text)->editable == FALSE))
02258 {
02259 switch (event->keyval)
02260 {
02261 case GDK_Home:
02262 if (event->state & GDK_CONTROL_MASK)
02263 scroll_int (text, -text->vadj->value);
02264 else
02265 return_val = FALSE;
02266 break;
02267 case GDK_End:
02268 if (event->state & GDK_CONTROL_MASK)
02269 scroll_int (text, +text->vadj->upper);
02270 else
02271 return_val = FALSE;
02272 break;
02273 case GDK_Page_Up: scroll_int (text, -text->vadj->page_increment); break;
02274 case GDK_Page_Down: scroll_int (text, +text->vadj->page_increment); break;
02275 case GDK_Up: scroll_int (text, -KEY_SCROLL_PIXELS); break;
02276 case GDK_Down: scroll_int (text, +KEY_SCROLL_PIXELS); break;
02277 case GDK_Return:
02278 if (event->state & GDK_CONTROL_MASK)
02279 gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
02280 else
02281 return_val = FALSE;
02282 break;
02283 default:
02284 return_val = FALSE;
02285 break;
02286 }
02287 }
02288 else
02289 {
02290 gint extend_selection;
02291 gint extend_start;
02292 guint initial_pos = editable->current_pos;
02293
02294 text->point = find_mark (text, text->cursor_mark.index);
02295
02296 extend_selection = event->state & GDK_SHIFT_MASK;
02297 extend_start = FALSE;
02298
02299 if (extend_selection)
02300 {
02301 editable->has_selection = TRUE;
02302
02303 if (editable->selection_start_pos == editable->selection_end_pos)
02304 {
02305 editable->selection_start_pos = text->point.index;
02306 editable->selection_end_pos = text->point.index;
02307 }
02308
02309 extend_start = (text->point.index == editable->selection_start_pos);
02310 }
02311
02312 switch (event->keyval)
02313 {
02314 case GDK_Home:
02315 if (event->state & GDK_CONTROL_MASK)
02316 move_cursor_buffer_ver (text, -1);
02317 else
02318 gtk_text_move_beginning_of_line (text);
02319 break;
02320 case GDK_End:
02321 if (event->state & GDK_CONTROL_MASK)
02322 move_cursor_buffer_ver (text, +1);
02323 else
02324 gtk_text_move_end_of_line (text);
02325 break;
02326 case GDK_Page_Up: move_cursor_page_ver (text, -1); break;
02327 case GDK_Page_Down: move_cursor_page_ver (text, +1); break;
02328
02329 case GDK_Up: move_cursor_ver (text, -1); break;
02330 case GDK_Down: move_cursor_ver (text, +1); break;
02331 case GDK_Left:
02332 if (event->state & GDK_CONTROL_MASK)
02333 gtk_text_move_backward_word (text);
02334 else
02335 move_cursor_hor (text, -1);
02336 break;
02337 case GDK_Right:
02338 if (event->state & GDK_CONTROL_MASK)
02339 gtk_text_move_forward_word (text);
02340 else
02341 move_cursor_hor (text, +1);
02342 break;
02343
02344 case GDK_BackSpace:
02345 if (event->state & GDK_CONTROL_MASK)
02346 gtk_text_delete_backward_word (text);
02347 else
02348 gtk_text_delete_backward_character (text);
02349 break;
02350 case GDK_Clear:
02351 gtk_text_delete_line (text);
02352 break;
02353 case GDK_Insert:
02354 if (event->state & GDK_SHIFT_MASK)
02355 {
02356 extend_selection = FALSE;
02357 gtk_editable_paste_clipboard (editable);
02358 }
02359 else if (event->state & GDK_CONTROL_MASK)
02360 {
02361 gtk_editable_copy_clipboard (editable);
02362 }
02363 else
02364 {
02365
02366 }
02367 break;
02368 case GDK_Delete:
02369 if (event->state & GDK_CONTROL_MASK)
02370 gtk_text_delete_forward_word (text);
02371 else if (event->state & GDK_SHIFT_MASK)
02372 {
02373 extend_selection = FALSE;
02374 gtk_editable_cut_clipboard (editable);
02375 }
02376 else
02377 gtk_text_delete_forward_character (text);
02378 break;
02379 case GDK_Tab:
02380 position = text->point.index;
02381 gtk_editable_insert_text (editable, "\t", 1, &position);
02382 break;
02383 case GDK_Return:
02384 if (event->state & GDK_CONTROL_MASK)
02385 gtk_signal_emit_by_name (GTK_OBJECT (text), "activate");
02386 else
02387 {
02388 position = text->point.index;
02389 gtk_editable_insert_text (editable, "\n", 1, &position);
02390 }
02391 break;
02392 case GDK_Escape:
02393
02394 return_val = FALSE;
02395 break;
02396
02397 default:
02398 return_val = FALSE;
02399
02400 if (event->state & GDK_CONTROL_MASK)
02401 {
02402 if ((key >= 'A') && (key <= 'Z'))
02403 key -= 'A' - 'a';
02404
02405 if ((key >= 'a') && (key <= 'z') && control_keys[(int) (key - 'a')])
02406 {
02407 (* control_keys[(int) (key - 'a')]) (editable, event->time);
02408 return_val = TRUE;
02409 }
02410
02411 break;
02412 }
02413 else if (event->state & GDK_MOD1_MASK)
02414 {
02415 if ((key >= 'A') && (key <= 'Z'))
02416 key -= 'A' - 'a';
02417
02418 if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')])
02419 {
02420 (* alt_keys[(int) (key - 'a')]) (editable, event->time);
02421 return_val = TRUE;
02422 }
02423
02424 break;
02425 }
02426 else if (event->length > 0)
02427 {
02428 extend_selection = FALSE;
02429
02430 gtk_editable_delete_selection (editable);
02431 position = text->point.index;
02432 gtk_editable_insert_text (editable, event->string, event->length, &position);
02433
02434 return_val = TRUE;
02435 }
02436 else
02437 return_val = FALSE;
02438 }
02439
02440 if (return_val && (editable->current_pos != initial_pos))
02441 {
02442 if (extend_selection)
02443 {
02444 if (editable->current_pos < editable->selection_start_pos)
02445 gtk_text_set_selection (editable, editable->current_pos,
02446 editable->selection_end_pos);
02447 else if (editable->current_pos > editable->selection_end_pos)
02448 gtk_text_set_selection (editable, editable->selection_start_pos,
02449 editable->current_pos);
02450 else
02451 {
02452 if (extend_start)
02453 gtk_text_set_selection (editable, editable->current_pos,
02454 editable->selection_end_pos);
02455 else
02456 gtk_text_set_selection (editable, editable->selection_start_pos,
02457 editable->current_pos);
02458 }
02459 }
02460 else
02461 gtk_text_set_selection (editable, 0, 0);
02462
02463 gtk_editable_claim_selection (editable,
02464 editable->selection_start_pos != editable->selection_end_pos,
02465 event->time);
02466 }
02467 }
02468
02469 return return_val;
02470 }
02471
02472 static gint
02473 gtk_text_focus_in (GtkWidget *widget,
02474 GdkEventFocus *event)
02475 {
02476 g_return_val_if_fail (widget != NULL, FALSE);
02477 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
02478 g_return_val_if_fail (event != NULL, FALSE);
02479
02480 TDEBUG (("in gtk_text_focus_in\n"));
02481
02482 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
02483 gtk_widget_draw_focus (widget);
02484
02485 #ifdef USE_XIM
02486 if (GTK_EDITABLE(widget)->ic)
02487 gdk_im_begin (GTK_EDITABLE(widget)->ic, EXT_GTK_TEXT(widget)->text_area);
02488 #endif
02489
02490 draw_cursor (EXT_GTK_TEXT(widget), TRUE);
02491
02492 return FALSE;
02493 }
02494
02495 static gint
02496 gtk_text_focus_out (GtkWidget *widget,
02497 GdkEventFocus *event)
02498 {
02499 g_return_val_if_fail (widget != NULL, FALSE);
02500 g_return_val_if_fail (EXT_GTK_IS_TEXT (widget), FALSE);
02501 g_return_val_if_fail (event != NULL, FALSE);
02502
02503 TDEBUG (("in gtk_text_focus_out\n"));
02504
02505 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
02506 gtk_widget_draw_focus (widget);
02507
02508 undraw_cursor (EXT_GTK_TEXT(widget), TRUE);
02509
02510 #ifdef USE_XIM
02511 gdk_im_end ();
02512 #endif
02513
02514 return FALSE;
02515 }
02516
02517 static void
02518 gtk_text_adjustment (GtkAdjustment *adjustment,
02519 ExtGtkText *text)
02520 {
02521 gfloat old_val;
02522
02523 g_return_if_fail (adjustment != NULL);
02524 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
02525 g_return_if_fail (text != NULL);
02526 g_return_if_fail (EXT_GTK_IS_TEXT (text));
02527
02528
02529
02530
02531
02532 old_val = adjustment->value;
02533
02534 adjustment->value = MIN (adjustment->value, adjustment->upper - adjustment->page_size);
02535 adjustment->value = MAX (adjustment->value, 0.0);
02536
02537 if (adjustment->value != old_val)
02538 {
02539 gtk_signal_handler_block_by_func (GTK_OBJECT (adjustment),
02540 GTK_SIGNAL_FUNC (gtk_text_adjustment),
02541 text);
02542 gtk_adjustment_changed (adjustment);
02543 gtk_signal_handler_unblock_by_func (GTK_OBJECT (adjustment),
02544 GTK_SIGNAL_FUNC (gtk_text_adjustment),
02545 text);
02546 }
02547
02548
02549 if (text->line_start_cache == NULL)
02550 return;
02551
02552 if (adjustment == text->hadj)
02553 {
02554 eb_debug (DBG_CORE, "extgtktext: horizontal scrolling not implemented");
02555 }
02556 else
02557 {
02558 gint diff = ((gint)adjustment->value) - text->last_ver_value;
02559
02560 if (diff != 0)
02561 {
02562 undraw_cursor (text, FALSE);
02563
02564 if (diff > 0)
02565 scroll_down (text, diff);
02566 else
02567 scroll_up (text, diff);
02568
02569 draw_cursor (text, FALSE);
02570
02571 text->last_ver_value = adjustment->value;
02572 }
02573 }
02574 }
02575
02576 static void
02577 gtk_text_disconnect (GtkAdjustment *adjustment,
02578 ExtGtkText *text)
02579 {
02580 g_return_if_fail (adjustment != NULL);
02581 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
02582 g_return_if_fail (text != NULL);
02583 g_return_if_fail (EXT_GTK_IS_TEXT (text));
02584
02585 if (adjustment == text->hadj)
02586 ext_gtk_text_set_adjustments (text, NULL, text->vadj);
02587 if (adjustment == text->vadj)
02588 ext_gtk_text_set_adjustments (text, text->hadj, NULL);
02589 }
02590
02591
02592 static ExtGtkPropertyMark
02593 find_this_line_start_mark (ExtGtkText* text, guint point_position, const ExtGtkPropertyMark* near)
02594 {
02595 ExtGtkPropertyMark mark;
02596
02597 mark = find_mark_near (text, point_position, near);
02598
02599 while (mark.index > 0 &&
02600 EXT_GTK_TEXT_INDEX (text, mark.index - 1) != LINE_DELIM)
02601 decrement_mark (&mark);
02602
02603 return mark;
02604 }
02605
02606 static void
02607 init_tab_cont (ExtGtkText* text, PrevTabCont* tab_cont)
02608 {
02609 tab_cont->pixel_offset = 0;
02610 tab_cont->tab_start.tab_stops = text->tab_stops;
02611 tab_cont->tab_start.to_next_tab = (gulong) text->tab_stops->data;
02612
02613 if (!tab_cont->tab_start.to_next_tab)
02614 tab_cont->tab_start.to_next_tab = text->default_tab_width;
02615 }
02616
02617 static void
02618 line_params_iterate (ExtGtkText* text,
02619 const ExtGtkPropertyMark* mark0,
02620 const PrevTabCont* tab_mark0,
02621 gint8 alloc,
02622 void* data,
02623 LineIteratorFunction iter)
02624
02625
02626
02627
02628 {
02629 ExtGtkPropertyMark mark = *mark0;
02630 PrevTabCont tab_conts[2];
02631 LineParams *lp, lpbuf;
02632 gint tab_cont_index = 0;
02633
02634 if (tab_mark0)
02635 tab_conts[0] = *tab_mark0;
02636 else
02637 init_tab_cont (text, tab_conts);
02638
02639 for (;;)
02640 {
02641 if (alloc)
02642 lp = g_chunk_new (LineParams, params_mem_chunk);
02643 else
02644 lp = &lpbuf;
02645
02646 *lp = find_line_params (text, &mark, tab_conts + tab_cont_index,
02647 tab_conts + (tab_cont_index + 1) % 2);
02648
02649 if ((*iter) (text, lp, data))
02650 return;
02651
02652 if (LAST_INDEX (text, lp->end))
02653 break;
02654
02655 mark = lp->end;
02656 advance_mark (&mark);
02657 tab_cont_index = (tab_cont_index + 1) % 2;
02658 }
02659 }
02660
02661 static gint
02662 fetch_lines_iterator (ExtGtkText* text, LineParams* lp, void* data)
02663 {
02664 FetchLinesData *fldata = (FetchLinesData*) data;
02665
02666 fldata->new_lines = g_list_prepend (fldata->new_lines, lp);
02667
02668 switch (fldata->fl_type)
02669 {
02670 case FetchLinesCount:
02671 if (!text->line_wrap || !lp->wraps)
02672 fldata->data += 1;
02673
02674 if (fldata->data >= fldata->data_max)
02675 return TRUE;
02676
02677 break;
02678 case FetchLinesPixels:
02679
02680 fldata->data += LINE_HEIGHT(*lp);
02681
02682 if (fldata->data >= fldata->data_max)
02683 return TRUE;
02684
02685 break;
02686 }
02687
02688 return FALSE;
02689 }
02690
02691 static GList*
02692 fetch_lines (ExtGtkText* text,
02693 const ExtGtkPropertyMark* mark0,
02694 const PrevTabCont* tab_cont0,
02695 FLType fl_type,
02696 gint data)
02697 {
02698 FetchLinesData fl_data;
02699
02700 fl_data.new_lines = NULL;
02701 fl_data.data = 0;
02702 fl_data.data_max = data;
02703 fl_data.fl_type = fl_type;
02704
02705 line_params_iterate (text, mark0, tab_cont0, TRUE, &fl_data, fetch_lines_iterator);
02706
02707 return g_list_reverse (fl_data.new_lines);
02708 }
02709
02710 static void
02711 fetch_lines_backward (ExtGtkText* text)
02712 {
02713 GList* new_lines = NULL, *new_line_start;
02714 ExtGtkPropertyMark mark;
02715
02716 if (CACHE_DATA(text->line_start_cache).start.index == 0)
02717 return;
02718
02719 mark = find_this_line_start_mark (text,
02720 CACHE_DATA(text->line_start_cache).start.index - 1,
02721 &CACHE_DATA(text->line_start_cache).start);
02722
02723 new_line_start = new_lines = fetch_lines (text, &mark, NULL, FetchLinesCount, 1);
02724
02725 while (new_line_start->next)
02726 new_line_start = new_line_start->next;
02727
02728 new_line_start->next = text->line_start_cache;
02729 text->line_start_cache->prev = new_line_start;
02730 }
02731
02732 static void
02733 fetch_lines_forward (ExtGtkText* text, gint line_count)
02734 {
02735 ExtGtkPropertyMark mark;
02736 GList* line = text->line_start_cache;
02737
02738 while(line->next)
02739 line = line->next;
02740
02741 mark = CACHE_DATA(line).end;
02742
02743 if (LAST_INDEX (text, mark))
02744 return;
02745
02746 advance_mark(&mark);
02747
02748 line->next = fetch_lines (text, &mark, &CACHE_DATA(line).tab_cont_next, FetchLinesCount, line_count);
02749
02750 if (line->next)
02751 line->next->prev = line;
02752 }
02753
02754
02755
02756
02757 static void
02758 compute_lines_pixels (ExtGtkText* text, guint char_count,
02759 guint *lines, guint *pixels)
02760 {
02761 GList *line = text->current_line;
02762 gint chars_left = char_count;
02763
02764 *lines = 0;
02765 *pixels = 0;
02766
02767
02768
02769
02770 for (; line && chars_left >= 0; line = line->next)
02771 {
02772 *pixels += LINE_HEIGHT(CACHE_DATA(line));
02773
02774 if (line == text->current_line)
02775 chars_left -= CACHE_DATA(line).end.index - text->point.index + 1;
02776 else
02777 chars_left -= CACHE_DATA(line).end.index - CACHE_DATA(line).start.index + 1;
02778
02779 if (!text->line_wrap || !CACHE_DATA(line).wraps)
02780 *lines += 1;
02781 else
02782 if (chars_left < 0)
02783 chars_left = 0;
02784
02785 if (!line->next)
02786 fetch_lines_forward (text, 1);
02787 }
02788 }
02789 static gint
02790 total_line_height (ExtGtkText* text, GList* line, gint line_count)
02791 {
02792 gint height = 0;
02793
02794 for (; line && line_count > 0; line = line->next)
02795 {
02796 height += LINE_HEIGHT(CACHE_DATA(line));
02797
02798 if (!text->line_wrap || !CACHE_DATA(line).wraps)
02799 line_count -= 1;
02800
02801 if (!line->next)
02802 fetch_lines_forward (text, line_count);
02803 }
02804
02805 return height;
02806 }
02807
02808 static void
02809 swap_lines (ExtGtkText* text, GList* old, GList* new, guint old_line_count)
02810 {
02811 if (old == text->line_start_cache)
02812 {
02813 GList* last;
02814
02815 for (; old_line_count > 0; old_line_count -= 1)
02816 {
02817 while (text->line_start_cache &&
02818 text->line_wrap &&
02819 CACHE_DATA(text->line_start_cache).wraps)
02820 remove_cache_line(text, text->line_start_cache);
02821
02822 remove_cache_line(text, text->line_start_cache);
02823 }
02824
02825 last = g_list_last (new);
02826
02827 last->next = text->line_start_cache;
02828
02829 if (text->line_start_cache)
02830 text->line_start_cache->prev = last;
02831
02832 text->line_start_cache = new;
02833 }
02834 else
02835 {
02836 GList *last;
02837
02838 g_assert (old->prev);
02839
02840 last = old->prev;
02841
02842 for (; old_line_count > 0; old_line_count -= 1)
02843 {
02844 while (old && text->line_wrap && CACHE_DATA(old).wraps)
02845 old = remove_cache_line (text, old);
02846
02847 old = remove_cache_line (text, old);
02848 }
02849
02850 last->next = new;
02851 new->prev = last;
02852
02853 last = g_list_last (new);
02854
02855 last->next = old;
02856
02857 if (old)
02858 old->prev = last;
02859 }
02860 }
02861
02862 static void
02863 correct_cache_delete (ExtGtkText* text, gint nchars, gint lines)
02864 {
02865 GList* cache = text->current_line;
02866 gint i;
02867
02868 for (i = 0; cache && i < lines; i += 1, cache = cache->next)
02869 ;
02870
02871 for (; cache; cache = cache->next)
02872 {
02873 ExtGtkPropertyMark *start = &CACHE_DATA(cache).start;
02874 ExtGtkPropertyMark *end = &CACHE_DATA(cache).end;
02875
02876 start->index -= nchars;
02877 end->index -= nchars;
02878
02879 if (LAST_INDEX (text, text->point) &&
02880 start->index == text->point.index)
02881 *start = text->point;
02882 else if (start->property == text->point.property)
02883 start->offset = start->index - (text->point.index - text->point.offset);
02884
02885 if (LAST_INDEX (text, text->point) &&
02886 end->index == text->point.index)
02887 *end = text->point;
02888 if (end->property == text->point.property)
02889 end->offset = end->index - (text->point.index - text->point.offset);
02890
02891
02892
02893 }
02894 }
02895
02896 static void
02897 delete_expose (ExtGtkText* text, guint nchars, guint old_lines, guint old_pixels)
02898 {
02899 GtkWidget *widget = GTK_WIDGET (text);
02900
02901 gint pixel_height;
02902 guint new_pixels = 0;
02903 GdkRectangle rect;
02904 GList* new_line = NULL;
02905 gint width, height;
02906
02907 text->cursor_virtual_x = 0;
02908
02909 correct_cache_delete (text, nchars, old_lines);
02910
02911 pixel_height = pixel_height_of(text, text->current_line) -
02912 LINE_HEIGHT(CACHE_DATA(text->current_line));
02913
02914 if (CACHE_DATA(text->current_line).start.index == text->point.index)
02915 CACHE_DATA(text->current_line).start = text->point;
02916
02917 new_line = fetch_lines (text,
02918 &CACHE_DATA(text->current_line).start,
02919 &CACHE_DATA(text->current_line).tab_cont,
02920 FetchLinesCount,
02921 1);
02922
02923 swap_lines (text, text->current_line, new_line, old_lines);
02924
02925 text->current_line = new_line;
02926
02927 new_pixels = total_line_height (text, new_line, 1);
02928
02929 gdk_window_get_size (text->text_area, &width, &height);
02930
02931 if (old_pixels != new_pixels)
02932 {
02933 if (!widget->style->bg_pixmap[GTK_STATE_NORMAL])
02934 {
02935 gdk_draw_pixmap (text->text_area,
02936 text->gc,
02937 text->text_area,
02938 0,
02939 pixel_height + old_pixels,
02940 0,
02941 pixel_height + new_pixels,
02942 width,
02943 height);
02944 }
02945 text->vadj->upper += new_pixels;
02946 text->vadj->upper -= old_pixels;
02947 adjust_adj (text, text->vadj);
02948 }
02949
02950 rect.x = 0;
02951 rect.y = pixel_height;
02952 rect.width = width;
02953 rect.height = new_pixels;
02954
02955 expose_text (text, &rect, FALSE);
02956 gtk_text_draw_focus ( (GtkWidget *) text);
02957
02958 text->cursor_mark = text->point;
02959
02960 find_cursor (text, TRUE);
02961
02962 if (old_pixels != new_pixels)
02963 {
02964 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
02965 {
02966 rect.x = 0;
02967 rect.y = pixel_height + new_pixels;
02968 rect.width = width;
02969 rect.height = height - rect.y;
02970
02971 expose_text (text, &rect, FALSE);
02972 }
02973 else
02974 process_exposes (text);
02975 }
02976
02977 TEXT_ASSERT (text);
02978 TEXT_SHOW(text);
02979 }
02980
02981
02982 static void
02983 correct_cache_insert (ExtGtkText* text, gint nchars)
02984 {
02985 GList *cache;
02986 ExtGtkPropertyMark *start;
02987 ExtGtkPropertyMark *end;
02988
02989
02990
02991
02992
02993 start = &CACHE_DATA(text->current_line).start;
02994 if (start->index == text->point.index - nchars)
02995 {
02996 *start = text->point;
02997 move_mark_n (start, -nchars);
02998 }
02999
03000
03001
03002
03003
03004
03005
03006 cache = text->current_line->next;
03007
03008 for (; cache; cache = cache->next)
03009 {
03010 start = &CACHE_DATA(cache).start;
03011 end = &CACHE_DATA(cache).end;
03012
03013 if (LAST_INDEX (text, text->point) &&
03014 start->index == text->point.index)
03015 *start = text->point;
03016 else
03017 {
03018 if (start->property == text->point.property)
03019 {
03020 start->offset += nchars;
03021 start->index += nchars;
03022 }
03023 else if (start->property->next &&
03024 (start->property->next->next == text->point.property))
03025 {
03026
03027 start->offset -= MARK_CURRENT_PROPERTY (start)->length;
03028 start->index += nchars;
03029 start->property = text->point.property;
03030 }
03031 else
03032 start->index += nchars;
03033 }
03034
03035 if (LAST_INDEX (text, text->point) &&
03036 end->index == text->point.index)
03037 *end = text->point;
03038 else
03039 {
03040 if (end->property == text->point.property)
03041 {
03042 end->offset += nchars;
03043 end->index += nchars;
03044 }
03045 else if (end->property->next &&
03046 (end->property->next->next == text->point.property))
03047 {
03048
03049 end->offset -= MARK_CURRENT_PROPERTY (end)->length;
03050 end->index += nchars;
03051 end->property = text->point.property;
03052 }
03053 else
03054 end->index += nchars;
03055 }
03056
03057
03058
03059 }
03060 }
03061
03062
03063 static void
03064 insert_expose (ExtGtkText* text, guint old_pixels, gint nchars,
03065 guint new_line_count)
03066 {
03067 GtkWidget *widget = GTK_WIDGET (text);
03068
03069 gint pixel_height;
03070 guint new_pixels = 0;
03071 GdkRectangle rect;
03072 GList* new_lines = NULL;
03073 gint width, height;
03074
03075 text->cursor_virtual_x = 0;
03076
03077 undraw_cursor (text, FALSE);
03078
03079 correct_cache_insert (text, nchars);
03080
03081 TEXT_SHOW_ADJ (text, text->vadj, "vadj");
03082
03083 pixel_height = pixel_height_of(text, text->current_line) -
03084 LINE_HEIGHT(CACHE_DATA(text->current_line));
03085
03086 new_lines = fetch_lines (text,
03087 &CACHE_DATA(text->current_line).start,
03088 &CACHE_DATA(text->current_line).tab_cont,
03089 FetchLinesCount,
03090 new_line_count);
03091
03092 swap_lines (text, text->current_line, new_lines, 1);
03093
03094 text->current_line = new_lines;
03095
03096 new_pixels = total_line_height (text, new_lines, new_line_count);
03097
03098 gdk_window_get_size (text->text_area, &width, &height);
03099
03100 if (old_pixels != new_pixels)
03101 {
03102 if (!widget->style->bg_pixmap[GTK_STATE_NORMAL])
03103 {
03104 gdk_draw_pixmap (text->text_area,
03105 text->gc,
03106 text->text_area,
03107 0,
03108 pixel_height + old_pixels,
03109 0,
03110 pixel_height + new_pixels,
03111 width,
03112 height + (old_pixels - new_pixels) - pixel_height);
03113
03114 }
03115 text->vadj->upper += new_pixels;
03116 text->vadj->upper -= old_pixels;
03117 adjust_adj (text, text->vadj);
03118 }
03119
03120 rect.x = 0;
03121 rect.y = pixel_height;
03122 rect.width = width;
03123 rect.height = new_pixels;
03124
03125 expose_text (text, &rect, FALSE);
03126 gtk_text_draw_focus ( (GtkWidget *) text);
03127
03128 text->cursor_mark = text->point;
03129
03130 find_cursor (text, TRUE);
03131
03132 draw_cursor (text, FALSE);
03133
03134 if (old_pixels != new_pixels)
03135 {
03136 if (widget->style->bg_pixmap[GTK_STATE_NORMAL])
03137 {
03138 rect.x = 0;
03139 rect.y = pixel_height + new_pixels;
03140 rect.width = width;
03141 rect.height = height - rect.y;
03142
03143 expose_text (text, &rect, FALSE);
03144 }
03145 else
03146 process_exposes (text);
03147 }
03148
03149 TEXT_SHOW_ADJ (text, text->vadj, "vadj");
03150 TEXT_ASSERT (text);
03151 TEXT_SHOW(text);
03152 }
03153
03154
03155
03156 static guint
03157 font_hash (gconstpointer font)
03158 {
03159 #ifndef HAVE_LIBXFT
03160 return gdk_font_id ((const VFont*) font);
03161 #else
03162 return (guint)font;
03163 #endif
03164 }
03165
03166 static GHashTable *font_cache_table = NULL;
03167
03168 #ifdef HAVE_LIBXFT
03169
03170 gboolean xft_font_equal(XftFont * fonta, XftFont * fontb)
03171 {
03172 if(fonta->ascent != fontb->ascent)
03173 {
03174 return FALSE;
03175 }
03176 if(fonta->descent != fontb->descent)
03177 {
03178 return FALSE;
03179 }
03180 if(fonta->height != fontb->height)
03181 {
03182 return FALSE;
03183 }
03184 if(fonta->max_advance_width != fontb->max_advance_width)
03185 {
03186 return FALSE;
03187 }
03188 return TRUE;
03189 }
03190
03191 #endif
03192
03193 static ExtGtkTextFont*
03194 get_text_font (VFont* gfont)
03195 {
03196 ExtGtkTextFont* tf=NULL;
03197 gint i;
03198
03199 #ifndef HAVE_LIBXFT
03200 if (!font_cache_table)
03201 font_cache_table = g_hash_table_new (font_hash, (GCompareFunc) gdk_font_equal);
03202 #else
03203 if (!font_cache_table)
03204 font_cache_table = g_hash_table_new (font_hash, (GCompareFunc) xft_font_equal);
03205 #endif
03206
03207 tf = g_hash_table_lookup (font_cache_table, gfont);
03208
03209 if (tf)
03210 {
03211 tf->ref_count++;
03212 return tf;
03213 }
03214
03215 tf = g_new (ExtGtkTextFont, 1);
03216 tf->ref_count = 1;
03217
03218 tf->gdk_font = gfont;
03219 #ifndef HAVE_LIBXFT
03220 gdk_font_ref (gfont);
03221 #endif
03222
03223 for(i = 0; i < 256; i += 1)
03224 #ifndef HAVE_LIBXFT
03225 tf->char_widths[i] = gdk_char_width (gfont, (char)i);
03226 #else
03227 {
03228 XGlyphInfo extents;
03229 char string[] = {(char)i, '\0'};
03230 XftTextExtents8(gdk_display, gfont, string, 1, &extents);
03231 tf->char_widths[i] = extents.xOff;
03232 }
03233 #endif
03234
03235 g_hash_table_insert (font_cache_table, gfont, tf);
03236
03237 return tf;
03238 }
03239 static void
03240 text_font_unref (ExtGtkTextFont *text_font)
03241 {
03242 text_font->ref_count--;
03243 if (text_font->ref_count == 0)
03244 {
03245 g_hash_table_remove (font_cache_table, text_font->gdk_font);
03246 #ifndef HAVE_LIBXFT
03247 gdk_font_unref (text_font->gdk_font);
03248 #endif
03249 g_free (text_font);
03250 }
03251 }
03252
03253 static gint
03254 text_properties_equal (TextProperty* prop, VFont* font, GdkColor *fore,
03255 GdkColor *back, gboolean underlined,gboolean divider,
03256 GdkDrawable *image,
03257 gpointer user_data, guint user_data_length,
03258 DataFunc *user_data_func)
03259 {
03260 if (prop->flags & PROPERTY_FONT)
03261 {
03262 gboolean retval;
03263 ExtGtkTextFont *text_font;
03264
03265 if (!font)
03266 return FALSE;
03267
03268 text_font = get_text_font (font);
03269
03270 retval = (prop->font == text_font);
03271 text_font_unref (text_font);
03272
03273 if (!retval)
03274 return FALSE;
03275 }
03276 else
03277 if (font != NULL)
03278 return FALSE;
03279
03280 if (prop->flags & PROPERTY_FOREGROUND)
03281 {
03282 if (!fore || !gdk_color_equal (&prop->fore_color, fore))
03283 return FALSE;
03284 }
03285 else
03286 if (fore != NULL)
03287 return FALSE;
03288
03289 if (prop->flags & PROPERTY_BACKGROUND)
03290 {
03291 if (!back || !gdk_color_equal (&prop->back_color, back))
03292 return FALSE;
03293 }
03294 else
03295 if (back != NULL)
03296 return FALSE;
03297
03298 if (((prop->flags & PROPERTY_UNDERLINED)?TRUE:FALSE)!=underlined)
03299 return FALSE;
03300
03301 if (((prop->flags & PROPERTY_DIVIDER)?TRUE:FALSE)!=divider)
03302 return FALSE;
03303
03304 if (prop->flags & PROPERTY_IMAGE)
03305 {
03306 if (image != prop->image)
03307 return FALSE;
03308 }
03309 else
03310 if (image !=NULL)
03311 return FALSE;
03312
03313 if (prop->flags & PROPERTY_DATA)
03314 {
03315 if (memcmp(prop->user_data, user_data,user_data_length)!=0)
03316 return FALSE;
03317 }
03318 else
03319 if (user_data!=NULL)
03320 return FALSE;
03321
03322 return TRUE;
03323 }
03324
03325 static void
03326 realize_property (ExtGtkText *text, TextProperty *prop)
03327 {
03328 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (text));
03329
03330 if (prop->flags & PROPERTY_FOREGROUND)
03331 gdk_colormap_alloc_color (colormap, &prop->fore_color, FALSE, FALSE);
03332
03333 if (prop->flags & PROPERTY_BACKGROUND)
03334 gdk_colormap_alloc_color (colormap, &prop->back_color, FALSE, FALSE);
03335 }
03336
03337 static void
03338 realize_properties (ExtGtkText *text)
03339 {
03340 GList *tmp_list = text->text_properties;
03341
03342 while (tmp_list)
03343 {
03344 realize_property (text, tmp_list->data);
03345
03346 tmp_list = tmp_list->next;
03347 }
03348 }
03349
03350 static void
03351 unrealize_property (ExtGtkText *text, TextProperty *prop)
03352 {
03353 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (text));
03354
03355 if (prop->flags & PROPERTY_FOREGROUND)
03356 gdk_colormap_free_colors (colormap, &prop->fore_color, 1);
03357
03358 if (prop->flags & PROPERTY_BACKGROUND)
03359 gdk_colormap_free_colors (colormap, &prop->back_color, 1);
03360 }
03361
03362 static void
03363 unrealize_properties (ExtGtkText *text)
03364 {
03365 GList *tmp_list = text->text_properties;
03366
03367 while (tmp_list)
03368 {
03369 unrealize_property (text, tmp_list->data);
03370
03371 tmp_list = tmp_list->next;
03372 }
03373 }
03374
03375 static TextProperty*
03376 new_text_property (ExtGtkText *text, VFont*font, GdkColor* fore,
03377 GdkColor* back, gboolean underlined, gboolean divider, GdkDrawable *image,
03378 GdkBitmap *mask, gpointer user_data, guint user_data_length,
03379 DataFunc *user_data_func, guint length)
03380 {
03381 TextProperty *prop;
03382
03383 if (text_property_chunk == NULL)
03384 {
03385 text_property_chunk = g_mem_chunk_new ("text property mem chunk",
03386 sizeof(TextProperty),
03387 1024*sizeof(TextProperty),
03388 G_ALLOC_AND_FREE);
03389 }
03390
03391 prop = g_chunk_new(TextProperty, text_property_chunk);
03392
03393 prop->flags = 0;
03394 prop->user_data=NULL;
03395 prop->user_data_func=NULL;
03396 if (font)
03397 {
03398 prop->flags |= PROPERTY_FONT;
03399 prop->font = get_text_font (font);
03400 }
03401 else
03402 prop->font = NULL;
03403
03404 if (fore)
03405 {
03406 prop->flags |= PROPERTY_FOREGROUND;
03407 prop->fore_color = *fore;
03408 }
03409
03410 if (back)
03411 {
03412 prop->flags |= PROPERTY_BACKGROUND;
03413 prop->back_color = *back;
03414 }
03415
03416 if (underlined)
03417 {
03418 prop->flags |= PROPERTY_UNDERLINED;
03419 }
03420
03421 if (divider)
03422 {
03423 prop->flags |= PROPERTY_DIVIDER;
03424 }
03425
03426 if (image)
03427 {
03428 prop->flags |= PROPERTY_IMAGE;
03429 prop->image = image;
03430 prop->mask = mask;
03431 }
03432 else
03433 {
03434 prop->image=NULL;
03435 prop->mask =NULL;
03436 }
03437 if (user_data)
03438 {
03439 prop->flags |= PROPERTY_DATA;
03440 prop->user_data_length=user_data_length;
03441 prop->user_data=g_malloc(user_data_length);
03442 prop->user_data_func=user_data_func;
03443 memcpy(prop->user_data, user_data, user_data_length);
03444 }
03445 else
03446 {
03447 prop->user_data=NULL;
03448 prop->user_data_length=0;
03449 prop->user_data_func=NULL;
03450 }
03451
03452 prop->length = length;
03453
03454 if (GTK_WIDGET_REALIZED (text))
03455 realize_property (text, prop);
03456
03457 return prop;
03458 }
03459
03460 static void
03461 destroy_text_property (TextProperty *prop)
03462 {
03463 if (prop->font)
03464 text_font_unref (prop->font);
03465 if (prop->user_data)
03466 g_free(prop->user_data);
03467 if (prop->image)
03468 gdk_pixmap_unref(prop->image);
03469 if (prop->mask)
03470 gdk_pixmap_unref(prop->mask);
03471
03472 g_mem_chunk_free (text_property_chunk, prop);
03473 }
03474
03475
03476
03477 static void
03478 move_gap (ExtGtkText* text, guint index)
03479 {
03480 if (text->gap_position < index)
03481 {
03482 gint diff = index - text->gap_position;
03483
03484 if (text->use_wchar)
03485 g_memmove (text->text.wc + text->gap_position,
03486 text->text.wc + text->gap_position + text->gap_size,
03487 diff*sizeof (GdkWChar));
03488 else
03489 g_memmove (text->text.ch + text->gap_position,
03490 text->text.ch + text->gap_position + text->gap_size,
03491 diff);
03492
03493 text->gap_position = index;
03494 }
03495 else if (text->gap_position > index)
03496 {
03497 gint diff = text->gap_position - index;
03498
03499 if (text->use_wchar)
03500 g_memmove (text->text.wc + index + text->gap_size,
03501 text->text.wc + index,
03502 diff*sizeof (GdkWChar));
03503 else
03504 g_memmove (text->text.ch + index + text->gap_size,
03505 text->text.ch + index,
03506 diff);
03507
03508 text->gap_position = index;
03509 }
03510 }
03511
03512
03513 static void
03514 make_forward_space (ExtGtkText* text, guint len)
03515 {
03516 if (text->gap_size < len)
03517 {
03518 guint sum = MAX(2*len, MIN_GAP_SIZE) + text->text_end;
03519
03520 if (sum >= text->text_len)
03521 {
03522 guint i = 1;
03523
03524 while (i <= sum) i <<= 1;
03525
03526 if (text->use_wchar)
03527 text->text.wc = (GdkWChar *)g_realloc(text->text.wc,
03528 i*sizeof(GdkWChar));
03529 else
03530 text->text.ch = (guchar *)g_realloc(text->text.ch, i);
03531 text->text_len = i;
03532 }
03533
03534 if (text->use_wchar)
03535 g_memmove (text->text.wc + text->gap_position + text->gap_size + 2*len,
03536 text->text.wc + text->gap_position + text->gap_size,
03537 (text->text_end - (text->gap_position + text->gap_size))
03538 *sizeof(GdkWChar));
03539 else
03540 g_memmove (text->text.ch + text->gap_position + text->gap_size + 2*len,
03541 text->text.ch + text->gap_position + text->gap_size,
03542 text->text_end - (text->gap_position + text->gap_size));
03543
03544 text->text_end += len*2;
03545 text->gap_size += len*2;
03546 }
03547 }
03548
03549
03550
03551
03552
03553
03554 static void
03555 insert_text_property (ExtGtkText* text, VFont* font,
03556 GdkColor *fore, GdkColor* back,
03557 gboolean underlined, gboolean divider,
03558 GdkDrawable* image, GdkBitmap *mask,
03559 gpointer user_data, guint user_data_length,
03560 DataFunc *user_data_func,
03561 guint len)
03562 {
03563 ExtGtkPropertyMark *mark = &text->point;
03564 TextProperty* forward_prop = MARK_CURRENT_PROPERTY(mark);
03565 TextProperty* backward_prop = MARK_PREV_PROPERTY(mark);
03566
03567 if (MARK_OFFSET(mark) == 0)
03568 {
03569
03570
03571
03572
03573 if (text_properties_equal(forward_prop, font, fore, back, underlined, divider, image, user_data, user_data_length, user_data_func))
03574 {
03575
03576
03577 MARK_PROPERTY_LENGTH(mark) += len;
03578 }
03579 else if (backward_prop &&
03580 text_properties_equal(backward_prop, font, fore, back, underlined, divider, image, user_data, user_data_length, user_data_func))
03581 {
03582
03583
03584
03585 SET_PROPERTY_MARK (&text->point,
03586 MARK_PREV_LIST_PTR (mark),
03587 backward_prop->length);
03588
03589 backward_prop->length += len;
03590 }
03591 else if ((MARK_NEXT_LIST_PTR(mark) == NULL) &&
03592 (forward_prop->length == 1))
03593 {
03594
03595
03596 if (GTK_WIDGET_REALIZED (text))
03597 unrealize_property (text, forward_prop);
03598
03599 forward_prop->flags = 0;
03600 if (font)
03601 {
03602 forward_prop->flags |= PROPERTY_FONT;
03603 forward_prop->font = get_text_font (font);
03604 }
03605 else
03606 forward_prop->font = NULL;
03607
03608 if (fore)
03609 {
03610 forward_prop->flags |= PROPERTY_FOREGROUND;
03611 forward_prop->fore_color = *fore;
03612 }
03613 if (back)
03614 {
03615 forward_prop->flags |= PROPERTY_BACKGROUND;
03616 forward_prop->back_color = *back;
03617 }
03618 if (underlined)
03619 {
03620 forward_prop->flags |= PROPERTY_UNDERLINED;
03621 }
03622 if (image)
03623 {
03624 forward_prop->flags |= PROPERTY_IMAGE;
03625 forward_prop->image = image;
03626 forward_prop->mask = mask;
03627 }
03628 if(divider)
03629 {
03630 forward_prop->flags |= PROPERTY_DIVIDER;
03631 }
03632 if (user_data!=NULL)
03633 {
03634 forward_prop->flags |= PROPERTY_DATA;
03635 forward_prop->user_data_length=user_data_length;
03636 forward_prop->user_data = g_malloc(user_data_length);
03637 memcpy(forward_prop->user_data , user_data, user_data_length);
03638 forward_prop->user_data_func=user_data_func;
03639 }
03640 else
03641 {
03642 forward_prop->user_data=NULL;
03643 forward_prop->user_data_length=0;
03644 forward_prop->user_data_func=NULL;
03645 }
03646 forward_prop->length += len;
03647
03648 if (GTK_WIDGET_REALIZED (text))
03649 realize_property (text, forward_prop);
03650 }
03651 else
03652 {
03653
03654
03655 GList* new_prop = g_list_alloc();
03656
03657 new_prop->next = MARK_LIST_PTR(mark);
03658 new_prop->prev = MARK_PREV_LIST_PTR(mark);
03659 new_prop->next->prev = new_prop;
03660
03661 if (new_prop->prev)
03662 new_prop->prev->next = new_prop;
03663
03664 new_prop->data = new_text_property (text, font, fore, back, underlined, divider, image,mask,user_data, user_data_length, user_data_func,len);
03665
03666 SET_PROPERTY_MARK (mark, new_prop, 0);
03667 }
03668 }
03669 else
03670 {
03671
03672
03673
03674
03675
03676
03677
03678 if (text_properties_equal (forward_prop, font, fore, back, underlined, divider, image, user_data, user_data_length, user_data_func))
03679 {
03680 forward_prop->length += len;
03681 }
03682 else if ((MARK_NEXT_LIST_PTR(mark) == NULL) &&
03683 (MARK_OFFSET(mark) + 1 == forward_prop->length))
03684 {
03685
03686
03687 GList* new_prop;
03688 forward_prop->length -= 1;
03689
03690 new_prop = g_list_alloc();
03691 new_prop->data = new_text_property (text, font, fore, back, underlined, divider, image, mask, user_data,user_data_length, user_data_func, len+1);
03692 new_prop->prev = MARK_LIST_PTR(mark);
03693 new_prop->next = NULL;
03694 MARK_NEXT_LIST_PTR(mark) = new_prop;
03695
03696 SET_PROPERTY_MARK (mark, new_prop, 0);
03697 }
03698 else
03699 {
03700 GList* new_prop = g_list_alloc();
03701 GList* new_prop_forward = g_list_alloc();
03702 gint old_length = forward_prop->length;
03703 GList* next = MARK_NEXT_LIST_PTR(mark);
03704
03705
03706
03707 forward_prop->length = MARK_OFFSET(mark);
03708
03709 new_prop_forward->data =
03710 new_text_property(text,
03711 forward_prop->flags & PROPERTY_FONT ?
03712 forward_prop->font->gdk_font : NULL,
03713 forward_prop->flags & PROPERTY_FOREGROUND ?
03714 &forward_prop->fore_color : NULL,
03715 forward_prop->flags & PROPERTY_BACKGROUND ?
03716 &forward_prop->back_color : NULL,
03717 forward_prop->flags & PROPERTY_UNDERLINED ?
03718 TRUE : FALSE,
03719 forward_prop->flags & PROPERTY_DIVIDER?
03720 TRUE : FALSE,
03721 forward_prop->flags & PROPERTY_IMAGE ?
03722 forward_prop->image: NULL,
03723 forward_prop->flags & PROPERTY_IMAGE ?
03724 forward_prop->mask: NULL,
03725 (forward_prop->flags & PROPERTY_DATA) ?
03726 forward_prop->user_data: NULL,
03727 (forward_prop->flags & PROPERTY_DATA) ?
03728 forward_prop->user_data_length:0,
03729 (forward_prop->flags & PROPERTY_DATA) ?
03730 forward_prop->user_data_func:NULL,
03731 old_length - forward_prop->length);
03732
03733 new_prop->data = new_text_property(text, font, fore, back, underlined, divider, image, mask, user_data,user_data_length, user_data_func, len);
03734
03735 MARK_NEXT_LIST_PTR(mark) = new_prop;
03736 new_prop->prev = MARK_LIST_PTR(mark);
03737
03738 new_prop->next = new_prop_forward;
03739 new_prop_forward->prev = new_prop;
03740
03741 new_prop_forward->next = next;
03742
03743 if (next)
03744 next->prev = new_prop_forward;
03745
03746 SET_PROPERTY_MARK (mark, new_prop, 0);
03747 }
03748 }
03749
03750 while (text->text_properties_end->next)
03751 text->text_properties_end = text->text_properties_end->next;
03752
03753 while (text->text_properties->prev)
03754 text->text_properties = text->text_properties->prev;
03755 }
03756
03757 static void
03758 delete_text_property (ExtGtkText* text, guint nchars)
03759 {
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779 TextProperty *prop;
03780 GList *tmp;
03781 gint is_first;
03782
03783 for(; nchars; nchars -= 1)
03784 {
03785 prop = MARK_CURRENT_PROPERTY(&text->point);
03786
03787 prop->length -= 1;
03788
03789 if (prop->length == 0)
03790 {
03791 tmp = MARK_LIST_PTR (&text->point);
03792
03793 is_first = tmp == text->text_properties;
03794
03795 MARK_LIST_PTR (&text->point) = g_list_remove_link (tmp, tmp);
03796 text->point.offset = 0;
03797
03798 if (GTK_WIDGET_REALIZED (text))
03799 unrealize_property (text, prop);
03800
03801 destroy_text_property (prop);
03802 g_list_free_1 (tmp);
03803
03804 prop = MARK_CURRENT_PROPERTY (&text->point);
03805
03806 if (is_first)
03807 text->text_properties = MARK_LIST_PTR (&text->point);
03808
03809 g_assert (prop->length != 0);
03810 }
03811 else if (prop->length == text->point.offset)
03812 {
03813 MARK_LIST_PTR (&text->point) = MARK_NEXT_LIST_PTR (&text->point);
03814 text->point.offset = 0;
03815 }
03816 }
03817
03818
03819
03820
03821 if (LAST_INDEX (text, text->point) &&
03822 (MARK_OFFSET (&text->point) == 0) &&
03823 (MARK_PREV_LIST_PTR(&text->point) != NULL))
03824 {
03825 tmp = MARK_LIST_PTR (&text->point);
03826 prop = MARK_CURRENT_PROPERTY(&text->point);
03827
03828 MARK_LIST_PTR (&text->point) = MARK_PREV_LIST_PTR (&text->point);
03829 MARK_CURRENT_PROPERTY(&text->point)->length += 1;
03830 MARK_NEXT_LIST_PTR(&text->point) = NULL;
03831
03832 text->point.offset = MARK_CURRENT_PROPERTY(&text->point)->length - 1;
03833
03834 if (GTK_WIDGET_REALIZED (text))
03835 unrealize_property (text, prop);
03836
03837 destroy_text_property (prop);
03838 g_list_free_1 (tmp);
03839 }
03840 }
03841
03842 static void
03843 init_properties (ExtGtkText *text)
03844 {
03845 if (!text->text_properties)
03846 {
03847 text->text_properties = g_list_alloc();
03848 text->text_properties->next = NULL;
03849 text->text_properties->prev = NULL;
03850 text->text_properties->data = new_text_property (text, NULL, NULL, NULL, FALSE, FALSE, NULL, NULL, NULL,0,NULL, 1);
03851 text->text_properties_end = text->text_properties;
03852
03853 SET_PROPERTY_MARK (&text->point, text->text_properties, 0);
03854
03855 text->point.index = 0;
03856 }
03857 }
03858
03859
03860
03861
03862
03863
03864 static void
03865 move_mark_n (ExtGtkPropertyMark* mark, gint n)
03866 {
03867 if (n > 0)
03868 advance_mark_n(mark, n);
03869 else if (n < 0)
03870 decrement_mark_n(mark, -n);
03871 }
03872
03873 static void
03874 advance_mark (ExtGtkPropertyMark* mark)
03875 {
03876 TextProperty* prop = MARK_CURRENT_PROPERTY (mark);
03877
03878 mark->index += 1;
03879
03880 if (prop->length > mark->offset + 1)
03881 mark->offset += 1;
03882 else
03883 {
03884 mark->property = MARK_NEXT_LIST_PTR (mark);
03885 mark->offset = 0;
03886 }
03887 }
03888
03889 static void
03890 advance_mark_n (ExtGtkPropertyMark* mark, gint n)
03891 {
03892 gint i;
03893 TextProperty* prop;
03894
03895 g_assert (n > 0);
03896
03897 i = 0;
03898 prop = MARK_CURRENT_PROPERTY(mark);
03899
03900 if ((prop->length - mark->offset - 1) < n) {
03901
03902 n += (mark->offset);
03903 mark->index -= mark->offset;
03904 mark->offset = 0;
03905
03906
03907 while ((n-i) > prop->length - 1) {
03908 i += prop->length;
03909 mark->index += prop->length;
03910 mark->property = MARK_NEXT_LIST_PTR (mark);
03911 if (mark->property == NULL)
03912 break;
03913 prop = MARK_CURRENT_PROPERTY (mark);
03914 }
03915 }
03916
03917
03918 mark->index += n - i;
03919 mark->offset += n - i;
03920 }
03921
03922 static void
03923 decrement_mark (ExtGtkPropertyMark* mark)
03924 {
03925 mark->index -= 1;
03926
03927 if (mark->offset > 0)
03928 mark->offset -= 1;
03929 else
03930 {
03931 mark->property = MARK_PREV_LIST_PTR (mark);
03932 mark->offset = MARK_CURRENT_PROPERTY (mark)->length - 1;
03933 }
03934 }
03935
03936 static void
03937 decrement_mark_n (ExtGtkPropertyMark* mark, gint n)
03938 {
03939 g_assert (n > 0);
03940
03941 while (mark->offset < n) {
03942
03943 n -= mark->offset + 1;
03944 mark->index -= mark->offset + 1;
03945 mark->property = MARK_PREV_LIST_PTR (mark);
03946 mark->offset = MARK_CURRENT_PROPERTY (mark)->length - 1;
03947 }
03948
03949
03950 mark->index -= n;
03951 mark->offset -= n;
03952 }
03953
03954 static ExtGtkPropertyMark
03955 find_mark (ExtGtkText* text, guint mark_position)
03956 {
03957 return find_mark_near (text, mark_position, &text->point);
03958 }
03959
03960
03961
03962
03963 static ExtGtkPropertyMark
03964 find_mark_near (ExtGtkText* text, guint mark_position, const ExtGtkPropertyMark* near)
03965 {
03966 gint diffa;
03967 gint diffb;
03968
03969 ExtGtkPropertyMark mark;
03970
03971 if (!near)
03972 diffa = mark_position + 1;
03973 else
03974 diffa = mark_position - near->index;
03975
03976 diffb = mark_position;
03977
03978 if (diffa < 0)
03979 diffa = -diffa;
03980
03981 if (diffa <= diffb)
03982 {
03983 mark = *near;
03984 }
03985 else
03986 {
03987 mark.index = 0;
03988 mark.property = text->text_properties;
03989 mark.offset = 0;
03990 }
03991
03992 move_mark_n (&mark, mark_position - mark.index);
03993
03994 return mark;
03995 }
03996
03997
03998
03999
04000
04001 static void
04002 find_line_containing_point (ExtGtkText* text, guint point,
04003 gboolean scroll)
04004 {
04005 GList* cache;
04006 gint height;
04007
04008 text->current_line = NULL;
04009
04010 TEXT_SHOW (text);
04011
04012
04013
04014 while (CACHE_DATA(text->line_start_cache).start.index > point)
04015 scroll_int (text, - LINE_HEIGHT(CACHE_DATA(text->line_start_cache)));
04016
04017
04018
04019 if (scroll)
04020 {
04021 while (text->first_cut_pixels != 0 &&
04022 text->line_start_cache->next &&
04023 CACHE_DATA(text->line_start_cache->next).start.index > point)
04024 scroll_int (text, - LINE_HEIGHT(CACHE_DATA(text->line_start_cache->next)));
04025 }
04026
04027 gdk_window_get_size (text->text_area, NULL, &height);
04028
04029 for (cache = text->line_start_cache; cache; cache = cache->next)
04030 {
04031 guint lph;
04032
04033 if (CACHE_DATA(cache).end.index >= point ||
04034 LAST_INDEX(text, CACHE_DATA(cache).end))
04035 {
04036 text->current_line = cache;
04037
04038 return;
04039 }
04040
04041 TEXT_SHOW_LINE (text, cache, "cache");
04042
04043 if (cache->next == NULL)
04044 fetch_lines_forward (text, 1);
04045
04046 if (scroll)
04047 {
04048 lph = pixel_height_of (text, cache->next);
04049
04050
04051
04052
04053 while (cache->next != text->line_start_cache && lph > height)
04054 {
04055 TEXT_SHOW_LINE (text, cache, "cache");
04056 TEXT_SHOW_LINE (text, cache->next, "cache->next");
04057 scroll_int (text, LINE_HEIGHT(CACHE_DATA(cache->next)));
04058 lph = pixel_height_of (text, cache->next);
04059 }
04060 }
04061 }
04062
04063 g_assert_not_reached ();
04064 }
04065
04066 static guint
04067 pixel_height_of (ExtGtkText* text, GList* cache_line)
04068 {
04069 gint pixels = - text->first_cut_pixels;
04070 GList *cache = text->line_start_cache;
04071
04072 while (TRUE) {
04073 pixels += LINE_HEIGHT (CACHE_DATA(cache));
04074
04075 if (cache->data == cache_line->data)
04076 break;
04077
04078 cache = cache->next;
04079 }
04080
04081 return pixels;
04082 }
04083
04084
04085
04086
04087
04088 static gint
04089 find_char_width (ExtGtkText* text, const ExtGtkPropertyMark *mark, const TabStopMark *tab_mark)
04090 {
04091 GdkWChar ch;
04092 gint16* char_widths;
04093 GdkDrawable* image;
04094
04095 if (LAST_INDEX (text, *mark))
04096 return 0;
04097
04098 ch = EXT_GTK_TEXT_INDEX (text, mark->index);
04099 char_widths = MARK_CURRENT_TEXT_FONT (text, mark)->char_widths;
04100 if((image=MARK_CURRENT_IMAGE(text, mark)))
04101 {
04102 #ifdef __MINGW32__
04103 return ((GdkDrawablePrivate*) image) ->width + 2;
04104 #else
04105 return ((GdkWindowPrivate*) image) ->width + 2;
04106 #endif
04107 }
04108
04109 if (ch == '\t')
04110 {
04111 return tab_mark->to_next_tab * char_widths[' '];
04112 }
04113 else if (ch < 256)
04114 {
04115 return char_widths[ch];
04116 }
04117 else
04118 {
04119 return gdk_char_width_wc(MARK_CURRENT_TEXT_FONT(text, mark)->gdk_font, ch);
04120 }
04121 }
04122
04123 static void
04124 advance_tab_mark (ExtGtkText* text, TabStopMark* tab_mark, GdkWChar ch)
04125 {
04126 if (tab_mark->to_next_tab == 1 || ch == '\t')
04127 {
04128 if (tab_mark->tab_stops->next)
04129 {
04130 tab_mark->tab_stops = tab_mark->tab_stops->next;
04131 tab_mark->to_next_tab = (gulong) tab_mark->tab_stops->data;
04132 }
04133 else
04134 {
04135 tab_mark->to_next_tab = text->default_tab_width;
04136 }
04137 }
04138 else
04139 {
04140 tab_mark->to_next_tab -= 1;
04141 }
04142 }
04143
04144 static void
04145 advance_tab_mark_n (ExtGtkText* text, TabStopMark* tab_mark, gint n)
04146
04147 {
04148 while (n--)
04149 advance_tab_mark (text, tab_mark, 0);
04150 }
04151
04152 static void
04153 find_cursor_at_line (ExtGtkText* text, const LineParams* start_line, gint pixel_height)
04154 {
04155 GdkWChar ch;
04156 #ifdef USE_XIM
04157 GtkEditable *editable = (GtkEditable *)text;
04158 #endif
04159
04160 ExtGtkPropertyMark mark = start_line->start;
04161 TabStopMark tab_mark = start_line->tab_cont.tab_start;
04162 gint pixel_width = LINE_START_PIXEL (*start_line);
04163
04164 while (mark.index < text->cursor_mark.index)
04165 {
04166 pixel_width += find_char_width (text, &mark, &tab_mark);
04167
04168 advance_tab_mark (text, &tab_mark, EXT_GTK_TEXT_INDEX(text, mark.index));
04169 advance_mark (&mark);
04170 }
04171
04172 text->cursor_pos_x = pixel_width;
04173 text->cursor_pos_y = pixel_height;
04174 text->cursor_char_offset = start_line->font_descent;
04175 text->cursor_mark = mark;
04176
04177 ch = LAST_INDEX (text, mark) ?
04178 LINE_DELIM : EXT_GTK_TEXT_INDEX (text, mark.index);
04179
04180 if ((text->use_wchar) ? gdk_iswspace (ch) : isspace (ch))
04181 text->cursor_char = 0;
04182 else
04183 text->cursor_char = ch;
04184
04185 #ifdef USE_XIM
04186 if (GTK_WIDGET_HAS_FOCUS(text) && gdk_im_ready() && editable->ic &&
04187 (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
04188 {
04189 GdkICAttributesType mask = GDK_IC_SPOT_LOCATION |
04190 GDK_IC_PREEDIT_FOREGROUND |
04191 GDK_IC_PREEDIT_BACKGROUND;
04192
04193 editable->ic_attr->spot_location.x = text->cursor_pos_x;
04194 editable->ic_attr->spot_location.y
04195 = text->cursor_pos_y - text->cursor_char_offset;
04196 editable->ic_attr->preedit_foreground = *MARK_CURRENT_FORE (text, &mark);
04197 editable->ic_attr->preedit_background = *MARK_CURRENT_BACK (text, &mark);
04198
04199 #ifndef HAVE_LIBXFT
04200 if (MARK_CURRENT_FONT (text, &mark)->type == GDK_FONT_FONTSET)
04201 {
04202 mask |= GDK_IC_PREEDIT_FONTSET;
04203 editable->ic_attr->preedit_fontset = MARK_CURRENT_FONT (text, &mark);
04204 }
04205 #endif
04206
04207 gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
04208 }
04209 #endif
04210 }
04211
04212 static void
04213 find_cursor (ExtGtkText* text, gboolean scroll)
04214 {
04215 if (GTK_WIDGET_REALIZED (text))
04216 {
04217 find_line_containing_point (text, text->cursor_mark.index, scroll);
04218
04219 if (text->current_line)
04220 find_cursor_at_line (text,
04221 &CACHE_DATA(text->current_line),
04222 pixel_height_of(text, text->current_line));
04223 }
04224
04225 GTK_EDITABLE (text)->current_pos = text->cursor_mark.index;
04226 }
04227
04228 static void
04229 find_mouse_cursor_at_line (ExtGtkText *text, const LineParams* lp,
04230 guint line_pixel_height,
04231 gint button_x)
04232 {
04233 ExtGtkPropertyMark mark = lp->start;
04234 TabStopMark tab_mark = lp->tab_cont.tab_start;
04235
04236 gint char_width = find_char_width(text, &mark, &tab_mark);
04237 gint pixel_width = LINE_START_PIXEL (*lp) + (char_width+1)/2;
04238
04239 text->cursor_pos_y = line_pixel_height;
04240
04241 for (;;)
04242 {
04243 GdkWChar ch = LAST_INDEX (text, mark) ?
04244 LINE_DELIM : EXT_GTK_TEXT_INDEX (text, mark.index);
04245
04246 if (button_x < pixel_width || mark.index == lp->end.index)
04247 {
04248 text->cursor_pos_x = pixel_width - (char_width+1)/2;
04249 text->cursor_mark = mark;
04250 text->cursor_char_offset = lp->font_descent;
04251
04252 if ((text->use_wchar) ? gdk_iswspace (ch) : isspace (ch))
04253 text->cursor_char = 0;
04254 else
04255 text->cursor_char = ch;
04256
04257 break;
04258 }
04259
04260 advance_tab_mark (text, &tab_mark, ch);
04261 advance_mark (&mark);
04262
04263 pixel_width += char_width/2;
04264
04265 char_width = find_char_width (text, &mark, &tab_mark);
04266
04267 pixel_width += (char_width+1)/2;
04268 }
04269 }
04270
04271 static void
04272 find_mouse_cursor (ExtGtkText* text, gint x, gint y)
04273 {
04274 gint pixel_height;
04275 GList* cache = text->line_start_cache;
04276
04277 g_assert (cache);
04278
04279 pixel_height = - text->first_cut_pixels;
04280
04281 for (; cache; cache = cache->next)
04282 {
04283 pixel_height += LINE_HEIGHT(CACHE_DATA(cache));
04284
04285 if (y < pixel_height || !cache->next)
04286 {
04287 find_mouse_cursor_at_line (text, &CACHE_DATA(cache), pixel_height, x);
04288
04289 find_cursor (text, FALSE);
04290
04291 return;
04292 }
04293 }
04294 }
04295
04296
04297
04298
04299
04300 static void
04301 free_cache (ExtGtkText* text)
04302 {
04303 GList* cache = text->line_start_cache;
04304
04305 if (cache)
04306 {
04307 while (cache->prev)
04308 cache = cache->prev;
04309
04310 text->line_start_cache = cache;
04311 }
04312
04313 for (; cache; cache = cache->next)
04314 g_mem_chunk_free (params_mem_chunk, cache->data);
04315
04316 g_list_free (text->line_start_cache);
04317
04318 text->line_start_cache = NULL;
04319 }
04320
04321 static GList*
04322 remove_cache_line (ExtGtkText* text, GList* member)
04323 {
04324 GList *list;
04325
04326 if (member == NULL)
04327 return NULL;
04328
04329 if (member == text->line_start_cache)
04330 text->line_start_cache = text->line_start_cache->next;
04331
04332 if (member->prev)
04333 member->prev->next = member->next;
04334
04335 if (member->next)
04336 member->next->prev = member->prev;
04337
04338 list = member->next;
04339
04340 g_mem_chunk_free (params_mem_chunk, member->data);
04341 g_list_free_1 (member);
04342
04343 return list;
04344 }
04345
04346
04347
04348
04349
04350 static void
04351 move_cursor_buffer_ver (ExtGtkText *text, int dir)
04352 {
04353 undraw_cursor (text, FALSE);
04354
04355 if (dir > 0)
04356 {
04357 scroll_int (text, text->vadj->upper);
04358 text->cursor_mark = find_this_line_start_mark (text,
04359 TEXT_LENGTH (text),
04360 &text->cursor_mark);
04361 }
04362 else
04363 {
04364 scroll_int (text, - text->vadj->value);
04365 text->cursor_mark = find_this_line_start_mark (text,
04366 0,
04367 &text->cursor_mark);
04368 }
04369
04370 find_cursor (text, TRUE);
04371 draw_cursor (text, FALSE);
04372 }
04373
04374 static void
04375 move_cursor_page_ver (ExtGtkText *text, int dir)
04376 {
04377 scroll_int (text, dir * text->vadj->page_increment);
04378 }
04379
04380 static void
04381 move_cursor_ver (ExtGtkText *text, int count)
04382 {
04383 gint i;
04384 ExtGtkPropertyMark mark;
04385 gint offset;
04386
04387 mark = find_this_line_start_mark (text, text->cursor_mark.index, &text->cursor_mark);
04388 offset = text->cursor_mark.index - mark.index;
04389
04390 if (offset > text->cursor_virtual_x)
04391 text->cursor_virtual_x = offset;
04392
04393 if (count < 0)
04394 {
04395 if (mark.index == 0)
04396 return;
04397
04398 decrement_mark (&mark);
04399 mark = find_this_line_start_mark (text, mark.index, &mark);
04400 }
04401 else
04402 {
04403 mark = text->cursor_mark;
04404
04405 while (!LAST_INDEX(text, mark) && EXT_GTK_TEXT_INDEX(text, mark.index) != LINE_DELIM)
04406 advance_mark (&mark);
04407
04408 if (LAST_INDEX(text, mark))
04409 return;
04410
04411 advance_mark (&mark);
04412 }
04413
04414 for (i=0; i < text->cursor_virtual_x; i += 1, advance_mark(&mark))
04415 if (LAST_INDEX(text, mark) ||
04416 EXT_GTK_TEXT_INDEX(text, mark.index) == LINE_DELIM)
04417 break;
04418
04419 undraw_cursor (text, FALSE);
04420
04421 text->cursor_mark = mark;
04422
04423 find_cursor (text, TRUE);
04424
04425 draw_cursor (text, FALSE);
04426 }
04427
04428 static void
04429 move_cursor_hor (ExtGtkText *text, int count)
04430 {
04431
04432 if ( (count > 0 && text->cursor_mark.index + count > TEXT_LENGTH(text)) ||
04433 (count < 0 && text->cursor_mark.index < (- count)) ||
04434 (count == 0) )
04435 return;
04436
04437 text->cursor_virtual_x = 0;
04438
04439 undraw_cursor (text, FALSE);
04440
04441 move_mark_n (&text->cursor_mark, count);
04442
04443 find_cursor (text, TRUE);
04444
04445 draw_cursor (text, FALSE);
04446 }
04447
04448 static void
04449 gtk_text_move_cursor (GtkEditable *editable,
04450 gint x,
04451 gint y)
04452 {
04453 if (x > 0)
04454 {
04455 while (x-- != 0)
04456 move_cursor_hor (EXT_GTK_TEXT (editable), 1);
04457 }
04458 else if (x < 0)
04459 {
04460 while (x++ != 0)
04461 move_cursor_hor (EXT_GTK_TEXT (editable), -1);
04462 }
04463
04464 if (y > 0)
04465 {
04466 while (y-- != 0)
04467 move_cursor_ver (EXT_GTK_TEXT (editable), 1);
04468 }
04469 else if (y < 0)
04470 {
04471 while (y++ != 0)
04472 move_cursor_ver (EXT_GTK_TEXT (editable), -1);
04473 }
04474 }
04475
04476 static void
04477 gtk_text_move_forward_character (ExtGtkText *text)
04478 {
04479 move_cursor_hor (text, 1);
04480 }
04481
04482 static void
04483 gtk_text_move_backward_character (ExtGtkText *text)
04484 {
04485 move_cursor_hor (text, -1);
04486 }
04487
04488 static void
04489 gtk_text_move_next_line (ExtGtkText *text)
04490 {
04491 move_cursor_ver (text, 1);
04492 }
04493
04494 static void
04495 gtk_text_move_previous_line (ExtGtkText *text)
04496 {
04497 move_cursor_ver (text, -1);
04498 }
04499
04500 static void
04501 gtk_text_move_word (GtkEditable *editable,
04502 gint n)
04503 {
04504 if (n > 0)
04505 {
04506 while (n-- != 0)
04507 gtk_text_move_forward_word (EXT_GTK_TEXT (editable));
04508 }
04509 else if (n < 0)
04510 {
04511 while (n++ != 0)
04512 gtk_text_move_backward_word (EXT_GTK_TEXT (editable));
04513 }
04514 }
04515
04516 static void
04517 gtk_text_move_forward_word (ExtGtkText *text)
04518 {
04519 text->cursor_virtual_x = 0;
04520
04521 undraw_cursor (text, FALSE);
04522
04523 if (text->use_wchar)
04524 {
04525 while (!LAST_INDEX (text, text->cursor_mark) &&
04526 !gdk_iswalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index)))
04527 advance_mark (&text->cursor_mark);
04528
04529 while (!LAST_INDEX (text, text->cursor_mark) &&
04530 gdk_iswalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index)))
04531 advance_mark (&text->cursor_mark);
04532 }
04533 else
04534 {
04535 while (!LAST_INDEX (text, text->cursor_mark) &&
04536 !isalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index)))
04537 advance_mark (&text->cursor_mark);
04538
04539 while (!LAST_INDEX (text, text->cursor_mark) &&
04540 isalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index)))
04541 advance_mark (&text->cursor_mark);
04542 }
04543
04544 find_cursor (text, TRUE);
04545 draw_cursor (text, FALSE);
04546 }
04547
04548 static void
04549 gtk_text_move_backward_word (ExtGtkText *text)
04550 {
04551 text->cursor_virtual_x = 0;
04552
04553 undraw_cursor (text, FALSE);
04554
04555 if (text->use_wchar)
04556 {
04557 while ((text->cursor_mark.index > 0) &&
04558 !gdk_iswalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
04559 decrement_mark (&text->cursor_mark);
04560
04561 while ((text->cursor_mark.index > 0) &&
04562 gdk_iswalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
04563 decrement_mark (&text->cursor_mark);
04564 }
04565 else
04566 {
04567 while ((text->cursor_mark.index > 0) &&
04568 !isalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
04569 decrement_mark (&text->cursor_mark);
04570
04571 while ((text->cursor_mark.index > 0) &&
04572 isalnum (EXT_GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
04573 decrement_mark (&text->cursor_mark);
04574 }
04575
04576 find_cursor (text, TRUE);
04577 draw_cursor (text, FALSE);
04578 }
04579
04580 static void
04581 gtk_text_move_page (GtkEditable *editable,
04582 gint x,
04583 gint y)
04584 {
04585 if (y != 0)
04586 scroll_int (EXT_GTK_TEXT (editable),
04587 y * EXT_GTK_TEXT(editable)->vadj->page_increment);
04588 }
04589
04590 static void
04591 gtk_text_move_to_row (GtkEditable *editable,
04592 gint row)
04593 {
04594 }
04595
04596 static void
04597 gtk_text_move_to_column (GtkEditable *editable,
04598 gint column)
04599 {
04600 ExtGtkText *text;
04601
04602 text = EXT_GTK_TEXT (editable);
04603
04604 text->cursor_virtual_x = 0;
04605
04606 undraw_cursor (text, FALSE);
04607
04608
04609 while ((text->cursor_mark.index > 0) &&
04610 (EXT_GTK_TEXT_INDEX (text, text->cursor_mark.index - 1) != LINE_DELIM))
04611 decrement_mark (&text->cursor_mark);
04612
04613 while (!LAST_INDEX (text, text->cursor_mark) &&
04614 (EXT_GTK_TEXT_INDEX (text, text->cursor_mark.index) != LINE_DELIM))
04615 {
04616 if (column > 0)
04617 column--;
04618 else if (column == 0)
04619 break;
04620
04621 advance_mark (&text->cursor_mark);
04622 }
04623
04624 find_cursor (text, TRUE);
04625 draw_cursor (text, FALSE);
04626 }
04627
04628 static void
04629 gtk_text_move_beginning_of_line (ExtGtkText *text)
04630 {
04631 gtk_text_move_to_column (GTK_EDITABLE (text), 0);
04632
04633 }
04634
04635 static void
04636 gtk_text_move_end_of_line (ExtGtkText *text)
04637 {
04638 gtk_text_move_to_column (GTK_EDITABLE (text), -1);
04639 }
04640
04641 static void
04642 gtk_text_kill_char (GtkEditable *editable,
04643 gint direction)
04644 {
04645 ExtGtkText *text;
04646
04647 text = EXT_GTK_TEXT (editable);
04648
04649 if (editable->selection_start_pos != editable->selection_end_pos)
04650 gtk_editable_delete_selection (editable);
04651 else
04652 {
04653 if (direction >= 0)
04654 {
04655 if (text->point.index + 1 <= TEXT_LENGTH (text))
04656 gtk_editable_delete_text (editable, text->point.index, text->point.index + 1);
04657 }
04658 else
04659 {
04660 if (text->point.index > 0)
04661 gtk_editable_delete_text (editable, text->point.index - 1, text->point.index);
04662 }
04663 }
04664 }
04665
04666 static void
04667 gtk_text_delete_forward_character (ExtGtkText *text)
04668 {
04669 gtk_text_kill_char (GTK_EDITABLE (text), 1);
04670 }
04671
04672 static void
04673 gtk_text_delete_backward_character (ExtGtkText *text)
04674 {
04675 gtk_text_kill_char (GTK_EDITABLE (text), -1);
04676 }
04677
04678 static void
04679 gtk_text_kill_word (GtkEditable *editable,
04680 gint direction)
04681 {
04682 if (editable->selection_start_pos != editable->selection_end_pos)
04683 gtk_editable_delete_selection (editable);
04684 else
04685 {
04686 gint old_pos = editable->current_pos;
04687 if (direction >= 0)
04688 {
04689 gtk_text_move_word (editable, 1);
04690 gtk_editable_delete_text (editable, old_pos, editable->current_pos);
04691 }
04692 else
04693 {
04694 gtk_text_move_word (editable, -1);
04695 gtk_editable_delete_text (editable, editable->current_pos, old_pos);
04696 }
04697 }
04698 }
04699
04700 static void
04701 gtk_text_delete_forward_word (ExtGtkText *text)
04702 {
04703 gtk_text_kill_word (GTK_EDITABLE (text), 1);
04704 }
04705
04706 static void
04707 gtk_text_delete_backward_word (ExtGtkText *text)
04708 {
04709 gtk_text_kill_word (GTK_EDITABLE (text), -1);
04710 }
04711
04712 static void
04713 gtk_text_kill_line (GtkEditable *editable,
04714 gint direction)
04715 {
04716 gint old_pos = editable->current_pos;
04717 if (direction >= 0)
04718 {
04719 gtk_text_move_to_column (editable, -1);
04720 gtk_editable_delete_text (editable, old_pos, editable->current_pos);
04721 }
04722 else
04723 {
04724 gtk_text_move_to_column (editable, 0);
04725 gtk_editable_delete_text (editable, editable->current_pos, old_pos);
04726 }
04727 }
04728
04729 static void
04730 gtk_text_delete_line (ExtGtkText *text)
04731 {
04732 gtk_text_move_to_column (GTK_EDITABLE (text), 0);
04733 gtk_text_kill_line (GTK_EDITABLE (text), 1);
04734 }
04735
04736 static void
04737 gtk_text_delete_to_line_end (ExtGtkText *text)
04738 {
04739 gtk_text_kill_line (GTK_EDITABLE (text), 1);
04740 }
04741
04742 static void
04743 gtk_text_select_word (ExtGtkText *text, guint32 time)
04744 {
04745 gint start_pos;
04746 gint end_pos;
04747
04748 GtkEditable *editable;
04749 editable = GTK_EDITABLE (text);
04750
04751 gtk_text_move_backward_word (text);
04752 start_pos = text->cursor_mark.index;
04753
04754 gtk_text_move_forward_word (text);
04755 end_pos = text->cursor_mark.index;
04756
04757 editable->has_selection = TRUE;
04758 gtk_text_set_selection (editable, start_pos, end_pos);
04759 gtk_editable_claim_selection (editable, start_pos != end_pos, time);
04760 }
04761
04762 static void
04763 gtk_text_select_line (ExtGtkText *text, guint32 time)
04764 {
04765 gint start_pos;
04766 gint end_pos;
04767
04768 GtkEditable *editable;
04769 editable = GTK_EDITABLE (text);
04770
04771 gtk_text_move_beginning_of_line (text);
04772 start_pos = text->cursor_mark.index;
04773
04774 gtk_text_move_end_of_line (text);
04775 gtk_text_move_forward_character (text);
04776 end_pos = text->cursor_mark.index;
04777
04778 editable->has_selection = TRUE;
04779 gtk_text_set_selection (editable, start_pos, end_pos);
04780 gtk_editable_claim_selection (editable, start_pos != end_pos, time);
04781 }
04782
04783
04784
04785
04786
04787 static void
04788 adjust_adj (ExtGtkText* text, GtkAdjustment* adj)
04789 {
04790 gint height;
04791
04792 gdk_window_get_size (text->text_area, NULL, &height);
04793
04794 adj->step_increment = MIN (adj->upper, (float) SCROLL_PIXELS);
04795 adj->page_increment = MIN (adj->upper, height - (float) KEY_SCROLL_PIXELS);
04796 adj->page_size = MIN (adj->upper, height);
04797 adj->value = MIN (adj->value, adj->upper - adj->page_size);
04798 adj->value = MAX (adj->value, 0.0);
04799
04800 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
04801 }
04802
04803 static gint
04804 set_vertical_scroll_iterator (ExtGtkText* text, LineParams* lp, void* data)
04805 {
04806 SetVerticalScrollData *svdata = (SetVerticalScrollData *) data;
04807
04808 if ((text->first_line_start_index >= lp->start.index) &&
04809 (text->first_line_start_index <= lp->end.index))
04810 {
04811 svdata->mark = lp->start;
04812
04813 if (text->first_line_start_index == lp->start.index)
04814 {
04815 text->first_onscreen_ver_pixel = svdata->pixel_height + text->first_cut_pixels;
04816 }
04817 else
04818 {
04819 text->first_onscreen_ver_pixel = svdata->pixel_height;
04820 text->first_cut_pixels = 0;
04821 }
04822
04823 text->vadj->value = (float) text->first_onscreen_ver_pixel;
04824 }
04825
04826 svdata->pixel_height += LINE_HEIGHT (*lp);
04827
04828 return FALSE;
04829 }
04830
04831 static gint
04832 set_vertical_scroll_find_iterator (ExtGtkText* text, LineParams* lp, void* data)
04833 {
04834 SetVerticalScrollData *svdata = (SetVerticalScrollData *) data;
04835 gint return_val;
04836
04837 if (svdata->pixel_height <= (gint) text->vadj->value &&
04838 svdata->pixel_height + LINE_HEIGHT(*lp) > (gint) text->vadj->value)
04839 {
04840 svdata->mark = lp->start;
04841
04842 text->first_cut_pixels = (gint)text->vadj->value - svdata->pixel_height;
04843 text->first_onscreen_ver_pixel = svdata->pixel_height;
04844 text->first_line_start_index = lp->start.index;
04845
04846 return_val = TRUE;
04847 }
04848 else
04849 {
04850 svdata->pixel_height += LINE_HEIGHT (*lp);
04851
04852 return_val = FALSE;
04853 }
04854
04855 return return_val;
04856 }
04857
04858 static ExtGtkPropertyMark
04859 set_vertical_scroll (ExtGtkText* text)
04860 {
04861 ExtGtkPropertyMark mark = find_mark (text, 0);
04862 SetVerticalScrollData data;
04863 gint height;
04864 gint orig_value;
04865
04866 data.pixel_height = 0;
04867 line_params_iterate (text, &mark, NULL, FALSE, &data, set_vertical_scroll_iterator);
04868
04869 text->vadj->upper = (float) data.pixel_height;
04870 orig_value = (gint) text->vadj->value;
04871
04872 gdk_window_get_size (text->text_area, NULL, &height);
04873
04874 text->vadj->step_increment = MIN (text->vadj->upper, (float) SCROLL_PIXELS);
04875 text->vadj->page_increment = MIN (text->vadj->upper, height - (float) KEY_SCROLL_PIXELS);
04876 text->vadj->page_size = MIN (text->vadj->upper, height);
04877 text->vadj->value = MIN (text->vadj->value, text->vadj->upper - text->vadj->page_size);
04878 text->vadj->value = MAX (text->vadj->value, 0.0);
04879
04880 text->last_ver_value = (gint)text->vadj->value;
04881
04882 gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "changed");
04883
04884 if (text->vadj->value != orig_value)
04885 {
04886
04887 data.pixel_height = 0;
04888 data.last_didnt_wrap = TRUE;
04889
04890 line_params_iterate (text, &mark, NULL,
04891 FALSE, &data,
04892 set_vertical_scroll_find_iterator);
04893 }
04894
04895 return data.mark;
04896 }
04897
04898 static void
04899 scroll_int (ExtGtkText* text, gint diff)
04900 {
04901 gfloat upper;
04902
04903 text->vadj->value += diff;
04904
04905 upper = text->vadj->upper - text->vadj->page_size;
04906 text->vadj->value = MIN (text->vadj->value, upper);
04907 text->vadj->value = MAX (text->vadj->value, 0.0);
04908
04909 gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "value_changed");
04910 }
04911
04912 static void
04913 process_exposes (ExtGtkText *text)
04914 {
04915 GdkEvent *event;
04916
04917
04918
04919
04920 while ((event = gdk_event_get_graphics_expose (text->text_area)) != NULL)
04921 {
04922 gtk_widget_event (GTK_WIDGET (text), event);
04923 if (event->expose.count == 0)
04924 {
04925 gdk_event_free (event);
04926 break;
04927 }
04928 gdk_event_free (event);
04929 }
04930 }
04931
04932 static gint last_visible_line_height (ExtGtkText* text)
04933 {
04934 GList *cache = text->line_start_cache;
04935 gint height;
04936
04937 gdk_window_get_size (text->text_area, NULL, &height);
04938
04939 for (; cache->next; cache = cache->next)
04940 if (pixel_height_of(text, cache->next) > height)
04941 break;
04942
04943 if (cache)
04944 return pixel_height_of(text, cache) - 1;
04945 else
04946 return 0;
04947 }
04948
04949 static gint first_visible_line_height (ExtGtkText* text)
04950 {
04951 if (text->first_cut_pixels)
04952 return pixel_height_of(text, text->line_start_cache) + 1;
04953 else
04954 return 1;
04955 }
04956
04957 static void
04958 scroll_down (ExtGtkText* text, gint diff0)
04959 {
04960 GdkRectangle rect;
04961 gint real_diff = 0;
04962 gint width, height;
04963
04964 text->first_onscreen_ver_pixel += diff0;
04965
04966 while (diff0-- > 0)
04967 {
04968 if (text->first_cut_pixels < LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1)
04969 {
04970 text->first_cut_pixels += 1;
04971 }
04972 else
04973 {
04974 text->first_cut_pixels = 0;
04975
04976 text->line_start_cache = text->line_start_cache->next;
04977 g_assert (text->line_start_cache);
04978
04979 text->first_line_start_index =
04980 CACHE_DATA(text->line_start_cache).start.index;
04981
04982 if (!text->line_start_cache->next)
04983 fetch_lines_forward (text, 1);
04984 }
04985
04986 real_diff += 1;
04987 }
04988
04989 gdk_window_get_size (text->text_area, &width, &height);
04990 if (height > real_diff)
04991 gdk_draw_pixmap (text->text_area,
04992 text->gc,
04993 text->text_area,
04994 0,
04995 real_diff,
04996 0,
04997 0,
04998 width,
04999 height - real_diff);
05000
05001 rect.x = 0;
05002 rect.y = MAX (0, height - real_diff);
05003 rect.width = width;
05004 rect.height = MIN (height, real_diff);
05005
05006 expose_text (text, &rect, FALSE);
05007 gtk_text_draw_focus ( (GtkWidget *) text);
05008
05009 if (text->current_line)
05010 {
05011 gint cursor_min;
05012
05013 text->cursor_pos_y -= real_diff;
05014 cursor_min = drawn_cursor_min(text);
05015
05016 if (cursor_min < 0)
05017 find_mouse_cursor (text, text->cursor_pos_x,
05018 first_visible_line_height (text));
05019 }
05020
05021 if (height > real_diff)
05022 process_exposes (text);
05023 }
05024
05025 static void
05026 scroll_up (ExtGtkText* text, gint diff0)
05027 {
05028 gint real_diff = 0;
05029 GdkRectangle rect;
05030 gint width, height;
05031
05032 text->first_onscreen_ver_pixel += diff0;
05033
05034 while (diff0++ < 0)
05035 {
05036 g_assert (text->line_start_cache);
05037
05038 if (text->first_cut_pixels > 0)
05039 {
05040 text->first_cut_pixels -= 1;
05041 }
05042 else
05043 {
05044 if (!text->line_start_cache->prev)
05045 fetch_lines_backward (text);
05046
05047 text->line_start_cache = text->line_start_cache->prev;
05048
05049 text->first_line_start_index =
05050 CACHE_DATA(text->line_start_cache).start.index;
05051
05052 text->first_cut_pixels = LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1;
05053 }
05054
05055 real_diff += 1;
05056 }
05057
05058 gdk_window_get_size (text->text_area, &width, &height);
05059 if (height > real_diff)
05060 gdk_draw_pixmap (text->text_area,
05061 text->gc,
05062 text->text_area,
05063 0,
05064 0,
05065 0,
05066 real_diff,
05067 width,
05068 height - real_diff);
05069
05070 rect.x = 0;
05071 rect.y = 0;
05072 rect.width = width;
05073 rect.height = MIN (height, real_diff);
05074
05075 expose_text (text, &rect, FALSE);
05076 gtk_text_draw_focus ( (GtkWidget *) text);
05077
05078 if (text->current_line)
05079 {
05080 gint cursor_max;
05081 gint height;
05082
05083 text->cursor_pos_y += real_diff;
05084 cursor_max = drawn_cursor_max(text);
05085 gdk_window_get_size (text->text_area, NULL, &height);
05086
05087 if (cursor_max >= height)
05088 find_mouse_cursor (text, text->cursor_pos_x,
05089 last_visible_line_height (text));
05090 }
05091
05092 if (height > real_diff)
05093 process_exposes (text);
05094 }
05095
05096
05097
05098
05099
05100
05101
05102
05103
05104 static LineParams
05105 find_line_params (ExtGtkText* text,
05106 const ExtGtkPropertyMark* mark,
05107 const PrevTabCont *tab_cont,
05108 PrevTabCont *next_cont)
05109 {
05110 LineParams lp;
05111 TabStopMark tab_mark = tab_cont->tab_start;
05112 guint max_display_pixels;
05113 GdkWChar ch;
05114 gint ch_width;
05115 VFont* font;
05116 GdkDrawable * image;
05117
05118 gdk_window_get_size (text->text_area, (gint*) &max_display_pixels, NULL);
05119
05120 lp.wraps = 0;
05121 lp.tab_cont = *tab_cont;
05122 lp.start = *mark;
05123 lp.end = *mark;
05124 lp.pixel_width = tab_cont->pixel_offset;
05125 lp.displayable_chars = 0;
05126 lp.font_ascent = 0;
05127 lp.font_descent = 0;
05128
05129 init_tab_cont (text, next_cont);
05130
05131 while (!LAST_INDEX(text, lp.end))
05132 {
05133 g_assert (lp.end.property);
05134
05135 ch = EXT_GTK_TEXT_INDEX (text, lp.end.index);
05136 font = MARK_CURRENT_FONT (text, &lp.end);
05137
05138 if (ch == LINE_DELIM)
05139 {
05140
05141
05142
05143 if (!lp.font_ascent && !lp.font_descent)
05144 {
05145 lp.font_ascent = font->ascent+1;
05146 lp.font_descent = font->descent+1;
05147 }
05148
05149 lp.tab_cont_next = *next_cont;
05150
05151 return lp;
05152 }
05153
05154 ch_width = find_char_width (text, &lp.end, &tab_mark);
05155
05156 if ((ch_width + lp.pixel_width > max_display_pixels) &&
05157 (lp.end.index > lp.start.index))
05158 {
05159 lp.wraps = 1;
05160
05161 if (text->line_wrap)
05162 {
05163 next_cont->tab_start = tab_mark;
05164 next_cont->pixel_offset = 0;
05165
05166
05167
05168
05169
05170
05171 if(MARK_CURRENT_IMAGE(text, &lp.end))
05172 {
05173 decrement_mark (&lp.end);
05174 lp.displayable_chars -= 1;
05175 }
05176
05177 else if (ch == '\t')
05178 {
05179
05180 gint pixels_avail = max_display_pixels - lp.pixel_width;
05181 gint space_width = MARK_CURRENT_TEXT_FONT(text, &lp.end)->char_widths[' '];
05182 gint spaces_avail = pixels_avail / space_width;
05183
05184 if (spaces_avail == 0)
05185 {
05186 decrement_mark (&lp.end);
05187 }
05188 else
05189 {
05190 advance_tab_mark (text, &next_cont->tab_start, '\t');
05191 next_cont->pixel_offset = space_width * (tab_mark.to_next_tab -
05192 spaces_avail);
05193 lp.displayable_chars += 1;
05194 }
05195 }
05196 else
05197 {
05198 if (text->word_wrap)
05199 {
05200 ExtGtkPropertyMark saved_mark = lp.end;
05201 guint saved_characters = lp.displayable_chars;
05202
05203 lp.displayable_chars += 1;
05204
05205 if (text->use_wchar)
05206 {
05207 while (!gdk_iswspace (EXT_GTK_TEXT_INDEX (text, lp.end.index)) &&
05208 (lp.end.index > lp.start.index))
05209 {
05210 decrement_mark (&lp.end);
05211 lp.displayable_chars -= 1;
05212 }
05213 }
05214 else
05215 {
05216 while (!isspace(EXT_GTK_TEXT_INDEX (text, lp.end.index)) &&
05217 (lp.end.index > lp.start.index))
05218 {
05219 decrement_mark (&lp.end);
05220 lp.displayable_chars -= 1;
05221 }
05222 }
05223
05224
05225 if (lp.end.index == lp.start.index)
05226 {
05227 lp.end = saved_mark;
05228 lp.displayable_chars = saved_characters;
05229 decrement_mark (&lp.end);
05230 }
05231 }
05232 else
05233 {
05234
05235 decrement_mark (&lp.end);
05236 }
05237 }
05238
05239 lp.tab_cont_next = *next_cont;
05240
05241 return lp;
05242 }
05243 }
05244 else
05245 {
05246 lp.displayable_chars += 1;
05247 }
05248 if((image=MARK_CURRENT_IMAGE(text, &lp.end)))
05249 {
05250 #ifdef __MINGW32__
05251 int height=((GdkDrawablePrivate*) image) ->height;
05252 int pixel_width =((GdkDrawablePrivate*) image) ->width+2;
05253 #else
05254 int height=((GdkWindowPrivate*) image) ->height;
05255 int pixel_width =((GdkWindowPrivate*) image) ->width+2;
05256 #endif
05257 lp.pixel_width += pixel_width;
05258 lp.font_ascent = MAX(((height*3)/4)+1, lp.font_ascent);
05259 lp.font_descent = MAX((height/4)+1, lp.font_descent);
05260 }
05261 else
05262 {
05263 lp.font_ascent = MAX (font->ascent+1, lp.font_ascent);
05264 lp.font_descent = MAX (font->descent+1, lp.font_descent);
05265 lp.pixel_width += ch_width;
05266 }
05267
05268 advance_mark(&lp.end);
05269 advance_tab_mark (text, &tab_mark, ch);
05270 }
05271
05272 if (LAST_INDEX(text, lp.start))
05273 {
05274
05275 font = MARK_CURRENT_FONT (text, &lp.end);
05276 lp.font_ascent = font->ascent+1;
05277 lp.font_descent = font->descent+1;
05278 }
05279
05280 lp.tab_cont_next = *next_cont;
05281
05282 return lp;
05283 }
05284
05285 static void
05286 expand_scratch_buffer (ExtGtkText* text, guint len)
05287 {
05288 if (len >= text->scratch_buffer_len)
05289 {
05290 guint i = 1;
05291
05292 while (i <= len && i < MIN_GAP_SIZE) i <<= 1;
05293
05294 if (text->use_wchar)
05295 {
05296 if (!text->scratch_buffer.wc)
05297 text->scratch_buffer.wc = g_new (GdkWChar, i);
05298 else
05299 text->scratch_buffer.wc = g_realloc (text->scratch_buffer.wc,
05300 i * sizeof (GdkWChar));
05301 }
05302 else
05303 {
05304 if (!text->scratch_buffer.ch)
05305 text->scratch_buffer.ch = g_new (guchar, i);
05306 else
05307 text->scratch_buffer.ch = g_realloc (text->scratch_buffer.ch, i);
05308 }
05309
05310 text->scratch_buffer_len = i;
05311 }
05312 }
05313
05314
05315
05316
05317 static void
05318 draw_bg_rect (ExtGtkText* text, ExtGtkPropertyMark *mark,
05319 gint x, gint y, gint width, gint height,
05320 gboolean already_cleared)
05321 {
05322 GtkEditable *editable = GTK_EDITABLE(text);
05323
05324 if ((mark->index >= MIN(editable->selection_start_pos, editable->selection_end_pos) &&
05325 mark->index < MAX(editable->selection_start_pos, editable->selection_end_pos)))
05326 {
05327 gtk_paint_flat_box(GTK_WIDGET(text)->style, text->text_area,
05328 editable->has_selection ?
05329 GTK_STATE_SELECTED : GTK_STATE_ACTIVE,
05330 GTK_SHADOW_NONE,
05331 NULL, GTK_WIDGET(text), "text",
05332 x, y, width, height);
05333 }
05334 else if (!gdk_color_equal(MARK_CURRENT_BACK (text, mark),
05335 >K_WIDGET(text)->style->base[GTK_WIDGET_STATE (text)]))
05336 {
05337 gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (text, mark));
05338
05339 gdk_draw_rectangle (text->text_area,
05340 text->gc,
05341 TRUE, x, y, width, height);
05342 }
05343 else if (GTK_WIDGET (text)->style->bg_pixmap[GTK_STATE_NORMAL])
05344 {
05345 GdkRectangle rect;
05346
05347 rect.x = x;
05348 rect.y = y;
05349 rect.width = width;
05350 rect.height = height;
05351
05352 clear_area (text, &rect);
05353 }
05354 else if (!already_cleared)
05355 gdk_window_clear_area (text->text_area, x, y, width, height);
05356 }
05357
05358 static void
05359 draw_line (ExtGtkText* text,
05360 gint pixel_start_height,
05361 LineParams* lp)
05362 {
05363 GdkGCValues gc_values;
05364 gint i;
05365 gint len = 0;
05366 guint running_offset = lp->tab_cont.pixel_offset;
05367 union { GdkWChar *wc; guchar *ch; } buffer;
05368 GdkGC *fg_gc, *temp_gc;
05369 GdkColor * fg_color;
05370 GdkDrawable *image;
05371 int height;
05372
05373 GtkEditable *editable = GTK_EDITABLE(text);
05374
05375 guint selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
05376 guint selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
05377
05378 ExtGtkPropertyMark mark = lp->start;
05379 TabStopMark tab_mark = lp->tab_cont.tab_start;
05380 gint pixel_height = pixel_start_height + lp->font_ascent;
05381 guint chars = lp->displayable_chars;
05382
05383
05384
05385
05386 if (mark.index <= text->gap_position &&
05387 mark.index + chars > text->gap_position)
05388 {
05389 expand_scratch_buffer (text, chars);
05390
05391 if (text->use_wchar)
05392 {
05393 for (i = 0; i < chars; i += 1)
05394 text->scratch_buffer.wc[i] = EXT_GTK_TEXT_INDEX(text, mark.index + i);
05395 buffer.wc = text->scratch_buffer.wc;
05396 }
05397 else
05398 {
05399 for (i = 0; i < chars; i += 1)
05400 text->scratch_buffer.ch[i] = EXT_GTK_TEXT_INDEX(text, mark.index + i);
05401 buffer.ch = text->scratch_buffer.ch;
05402 }
05403 }
05404 else
05405 {
05406 if (text->use_wchar)
05407 {
05408 if (mark.index >= text->gap_position)
05409 buffer.wc = text->text.wc + mark.index + text->gap_size;
05410 else
05411 buffer.wc = text->text.wc + mark.index;
05412 }
05413 else
05414 {
05415 if (mark.index >= text->gap_position)
05416 buffer.ch = text->text.ch + mark.index + text->gap_size;
05417 else
05418 buffer.ch = text->text.ch + mark.index;
05419 }
05420 }
05421
05422
05423 if (running_offset > 0)
05424 {
05425 draw_bg_rect (text, &mark, 0, pixel_start_height, running_offset,
05426 LINE_HEIGHT (*lp), TRUE);
05427 }
05428
05429 while (chars > 0)
05430 {
05431 len = 0;
05432 if ((text->use_wchar && buffer.wc[0] != '\t') ||
05433 (!text->use_wchar && buffer.ch[0] != '\t'))
05434 {
05435 union { GdkWChar *wc; guchar *ch; } next_tab;
05436 gint pixel_width;
05437 VFont* font;
05438
05439 next_tab.wc = NULL;
05440 if (text->use_wchar)
05441 for (i=0; i<chars; i++)
05442 {
05443 if (buffer.wc[i] == '\t')
05444 {
05445 next_tab.wc = buffer.wc + i;
05446 break;
05447 }
05448 }
05449 else
05450 next_tab.ch = memchr (buffer.ch, '\t', chars);
05451
05452 len = MIN (MARK_CURRENT_PROPERTY (&mark)->length - mark.offset, chars);
05453
05454 if (text->use_wchar)
05455 {
05456 if (next_tab.wc)
05457 len = MIN (len, next_tab.wc - buffer.wc);
05458 }
05459 else
05460 {
05461 if (next_tab.ch)
05462 len = MIN (len, next_tab.ch - buffer.ch);
05463 }
05464
05465 if (mark.index < selection_start_pos)
05466 len = MIN (len, selection_start_pos - mark.index);
05467 else if (mark.index < selection_end_pos)
05468 len = MIN (len, selection_end_pos - mark.index);
05469
05470 font = MARK_CURRENT_FONT (text, &mark);
05471 #ifndef HAVE_LIBXFT
05472 if (font->type == GDK_FONT_FONT)
05473 {
05474 gdk_gc_set_font (text->gc, font);
05475 gdk_gc_get_values (text->gc, &gc_values);
05476 if (text->use_wchar)
05477 pixel_width = gdk_text_width_wc (gc_values.font,
05478 buffer.wc, len);
05479 else
05480 pixel_width = gdk_text_width (gc_values.font,
05481 buffer.ch, len);
05482 }
05483 else
05484 #endif
05485 {
05486 #ifndef HAVE_LIBXFT
05487 if (text->use_wchar)
05488 pixel_width = gdk_text_width_wc (font, buffer.wc, len);
05489 else
05490 pixel_width = gdk_text_width (font, buffer.ch, len);
05491 #else
05492 XGlyphInfo glyph;
05493 if(text->use_wchar)
05494 XftTextExtents32(gdk_display, font, buffer.ch, len, &glyph);
05495 else
05496 XftTextExtents8(gdk_display, font, buffer.ch, len, &glyph);
05497 pixel_width = glyph.xOff;
05498 #endif
05499 }
05500 if((image=MARK_CURRENT_IMAGE(text, &mark)))
05501 {
05502 #ifdef __MINGW32__
05503 pixel_width =((GdkDrawablePrivate*) image) ->width +2;
05504 #else
05505 pixel_width =((GdkWindowPrivate*) image) ->width +2;
05506 #endif
05507 }
05508 if(MARK_CURRENT_DIVIDER(text, &mark))
05509 {
05510 int width;
05511 gdk_window_get_size(text->text_area, &width, NULL);
05512 pixel_width = width;
05513 }
05514
05515 draw_bg_rect (text, &mark, running_offset, pixel_start_height,
05516 pixel_width, LINE_HEIGHT (*lp), TRUE);
05517
05518 if ((mark.index >= selection_start_pos) &&
05519 (mark.index < selection_end_pos))
05520 {
05521 if (editable->has_selection)
05522 {
05523 fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_SELECTED];
05524 fg_color = >K_WIDGET(text)->style->fg[GTK_STATE_SELECTED];
05525 }
05526 else
05527 {
05528 fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_ACTIVE];
05529 fg_color = >K_WIDGET(text)->style->fg[GTK_STATE_ACTIVE];
05530 }
05531 }
05532 else
05533 {
05534 gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (text, &mark));
05535 fg_color = MARK_CURRENT_FORE(text, &mark);
05536 fg_gc = text->gc;
05537 }
05538
05539 #ifndef HAVE_LIBXFT
05540 if (text->use_wchar)
05541 gdk_draw_text_wc (text->text_area, MARK_CURRENT_FONT (text, &mark),
05542 fg_gc,
05543 running_offset,
05544 pixel_height,
05545 buffer.wc,
05546 len);
05547 else
05548 #endif
05549 {
05550 #ifdef HAVE_LIBXFT
05551 draw_bg_rect (text, &mark, running_offset, pixel_start_height, pixel_width,
05552 LINE_HEIGHT (*lp), FALSE);
05553 xft_draw_text (text->text_area, MARK_CURRENT_FONT (text, &mark),
05554 fg_gc,
05555 fg_color,
05556 running_offset,
05557 pixel_height,
05558 buffer.ch,
05559 text->use_wchar,
05560 len);
05561 #else
05562 gdk_draw_text (text->text_area, MARK_CURRENT_FONT (text, &mark),
05563 fg_gc,
05564 running_offset,
05565 pixel_height,
05566 buffer.ch,
05567 len);
05568 #endif
05569 }
05570
05571
05572
05573 if(MARK_CURRENT_UNDERLINED(text, &mark)) {
05574 gdk_draw_line (text->text_area,
05575 fg_gc,
05576 running_offset+1,
05577 pixel_height+1,
05578 running_offset+pixel_width-1,
05579 pixel_height+1);
05580 }
05581 if(MARK_CURRENT_DIVIDER(text, &mark))
05582 {
05583 int width;
05584 gdk_window_get_size(text->text_area, &width, NULL);
05585
05586 gdk_draw_line (text->text_area,
05587 fg_gc,
05588 1,
05589 pixel_height-(lp->font_ascent/2),
05590 width-2,
05591 pixel_height-(lp->font_ascent/2));
05592 }
05593 if((image=MARK_CURRENT_IMAGE(text, &mark)))
05594 {
05595 GdkBitmap * mask = MARK_CURRENT_MASK(text, &mark);
05596 temp_gc = gdk_gc_new(text->text_area);
05597 gdk_gc_copy(temp_gc, fg_gc);
05598 #ifdef __MINGW32__
05599 height=((GdkDrawablePrivate*) image) ->height;
05600 pixel_width =((GdkDrawablePrivate*) image) ->width+2;
05601 #else
05602 height=((GdkWindowPrivate*) image) ->height;
05603 pixel_width =((GdkWindowPrivate*) image) ->width+2;
05604 #endif
05605 height=(pixel_height-height)<pixel_start_height?
05606 pixel_height-pixel_start_height:height;
05607
05608 if(mask)
05609 {
05610 gdk_gc_set_clip_origin(temp_gc, running_offset+1, pixel_height-height);
05611 gdk_gc_set_clip_mask(temp_gc, mask);
05612 }
05613 gdk_draw_pixmap(text->text_area,
05614 temp_gc,
05615 image,
05616 0,
05617 0,
05618 running_offset+1,
05619
05620 pixel_height-height,
05621 -1, -1);
05622 gdk_gc_destroy(temp_gc);
05623
05624 }
05625
05626 running_offset += pixel_width;
05627
05628 advance_tab_mark_n (text, &tab_mark, len);
05629 }
05630 else
05631 {
05632 gint pixels_remaining;
05633 gint space_width;
05634 gint spaces_avail;
05635
05636 len = 1;
05637
05638 gdk_window_get_size (text->text_area, &pixels_remaining, NULL);
05639 pixels_remaining -= running_offset;
05640
05641 space_width = MARK_CURRENT_TEXT_FONT(text, &mark)->char_widths[' '];
05642
05643 spaces_avail = pixels_remaining / space_width;
05644 spaces_avail = MIN (spaces_avail, tab_mark.to_next_tab);
05645
05646 draw_bg_rect (text, &mark, running_offset, pixel_start_height,
05647 spaces_avail * space_width, LINE_HEIGHT (*lp), TRUE);
05648
05649 running_offset += tab_mark.to_next_tab *
05650 MARK_CURRENT_TEXT_FONT(text, &mark)->char_widths[' '];
05651
05652 advance_tab_mark (text, &tab_mark, '\t');
05653 }
05654
05655 advance_mark_n (&mark, len);
05656 if (text->use_wchar)
05657 buffer.wc += len;
05658 else
05659 buffer.ch += len;
05660 chars -= len;
05661 }
05662 }
05663
05664 static void
05665 undraw_cursor (ExtGtkText* text, gint absolute)
05666 {
05667 GtkEditable *editable = (GtkEditable *)text;
05668
05669 TDEBUG (("in undraw_cursor\n"));
05670
05671 if (absolute)
05672 text->cursor_drawn_level = 0;
05673
05674 if ((text->cursor_drawn_level ++ == 0) &&
05675 (editable->selection_start_pos == editable->selection_end_pos) &&
05676 GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
05677 {
05678 VFont* font;
05679
05680 g_assert(text->cursor_mark.property);
05681
05682 font = MARK_CURRENT_FONT(text, &text->cursor_mark);
05683
05684 draw_bg_rect (text, &text->cursor_mark,
05685 text->cursor_pos_x,
05686 text->cursor_pos_y - text->cursor_char_offset - font->ascent,
05687 1, font->ascent + 1, FALSE);
05688
05689 if (text->cursor_char)
05690 {
05691 #ifndef HAVE_LIBXFT
05692 if (font->type == GDK_FONT_FONT)
05693 gdk_gc_set_font (text->gc, font);
05694
05695 gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (text, &text->cursor_mark));
05696
05697 gdk_draw_text_wc (text->text_area, font,
05698 text->gc,
05699 text->cursor_pos_x,
05700 text->cursor_pos_y - text->cursor_char_offset,
05701 &text->cursor_char,
05702 1);
05703 #endif
05704 }
05705 }
05706 }
05707
05708 static gint
05709 drawn_cursor_min (ExtGtkText* text)
05710 {
05711 VFont* font;
05712
05713 g_assert(text->cursor_mark.property);
05714
05715 font = MARK_CURRENT_FONT(text, &text->cursor_mark);
05716
05717 return text->cursor_pos_y - text->cursor_char_offset - font->ascent;
05718 }
05719
05720 static gint
05721 drawn_cursor_max (ExtGtkText* text)
05722 {
05723 VFont* font;
05724
05725 g_assert(text->cursor_mark.property);
05726
05727 font = MARK_CURRENT_FONT(text, &text->cursor_mark);
05728
05729 return text->cursor_pos_y - text->cursor_char_offset;
05730 }
05731
05732 static void
05733 draw_cursor (ExtGtkText* text, gint absolute)
05734 {
05735 GtkEditable *editable = (GtkEditable *)text;
05736
05737 TDEBUG (("in draw_cursor\n"));
05738
05739 if (absolute)
05740 text->cursor_drawn_level = 1;
05741
05742 if ((--text->cursor_drawn_level == 0) &&
05743 editable->editable &&
05744 (editable->selection_start_pos == editable->selection_end_pos) &&
05745 GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
05746 {
05747
05748 VFont* font;
05749
05750 g_assert (text->cursor_mark.property);
05751
05752 font = MARK_CURRENT_FONT (text, &text->cursor_mark);
05753
05754 gdk_gc_set_foreground (text->gc, >K_WIDGET (text)->style->text[GTK_STATE_NORMAL]);
05755
05756 gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x,
05757 text->cursor_pos_y - text->cursor_char_offset,
05758 text->cursor_pos_x,
05759 text->cursor_pos_y - text->cursor_char_offset - font->ascent);
05760 }
05761 }
05762
05763 static GdkGC *
05764 create_bg_gc (ExtGtkText *text)
05765 {
05766 GdkGCValues values;
05767
05768 values.tile = GTK_WIDGET (text)->style->bg_pixmap[GTK_STATE_NORMAL];
05769 values.fill = GDK_TILED;
05770
05771 return gdk_gc_new_with_values (text->text_area, &values,
05772 GDK_GC_FILL | GDK_GC_TILE);
05773 }
05774
05775 static void
05776 clear_area (ExtGtkText *text, GdkRectangle *area)
05777 {
05778 GtkWidget *widget = GTK_WIDGET (text);
05779
05780 if (text->bg_gc)
05781 {
05782 gint width, height;
05783
05784 gdk_window_get_size (widget->style->bg_pixmap[GTK_STATE_NORMAL], &width, &height);
05785
05786 gdk_gc_set_ts_origin (text->bg_gc,
05787 (- (gint)text->first_onscreen_hor_pixel) % width,
05788 (- (gint)text->first_onscreen_ver_pixel) % height);
05789
05790 gdk_draw_rectangle (text->text_area, text->bg_gc, TRUE,
05791 area->x, area->y, area->width, area->height);
05792 }
05793 else
05794 gdk_window_clear_area (text->text_area, area->x, area->y, area->width, area->height);
05795 }
05796
05797 static void
05798 expose_text (ExtGtkText* text, GdkRectangle *area, gboolean cursor)
05799 {
05800 GList *cache = text->line_start_cache;
05801 gint pixels = - text->first_cut_pixels;
05802 gint min_y = MAX (0, area->y);
05803 gint max_y = MAX (0, area->y + area->height);
05804 gint height;
05805
05806 gdk_window_get_size (text->text_area, NULL, &height);
05807 max_y = MIN (max_y, height);
05808
05809 TDEBUG (("in expose x=%d y=%d w=%d h=%d\n", area->x, area->y, area->width, area->height));
05810
05811 clear_area (text, area);
05812
05813 for (; pixels < height; cache = cache->next)
05814 {
05815 if (pixels < max_y && (pixels + (gint)LINE_HEIGHT(CACHE_DATA(cache))) >= min_y)
05816 {
05817 draw_line (text, pixels, &CACHE_DATA(cache));
05818
05819 }
05820
05821 if (cursor && GTK_WIDGET_HAS_FOCUS (text))
05822 {
05823 if (CACHE_DATA(cache).start.index <= text->cursor_mark.index &&
05824 CACHE_DATA(cache).end.index >= text->cursor_mark.index)
05825 {
05826
05827
05828
05829
05830 undraw_cursor (text, FALSE);
05831 draw_cursor (text, FALSE);
05832 }
05833 }
05834
05835 pixels += LINE_HEIGHT(CACHE_DATA(cache));
05836
05837 if (!cache->next)
05838 {
05839 fetch_lines_forward (text, 1);
05840
05841 if (!cache->next)
05842 break;
05843 }
05844 }
05845 }
05846
05847 static void
05848 gtk_text_update_text (GtkEditable *editable,
05849 gint start_pos,
05850 gint end_pos)
05851 {
05852 ExtGtkText *text = EXT_GTK_TEXT (editable);
05853
05854 GList *cache = text->line_start_cache;
05855 gint pixels = - text->first_cut_pixels;
05856 GdkRectangle area;
05857 gint width;
05858 gint height;
05859
05860 if (end_pos < 0)
05861 end_pos = TEXT_LENGTH (text);
05862
05863 if (end_pos < start_pos)
05864 return;
05865
05866 gdk_window_get_size (text->text_area, &width, &height);
05867 area.x = 0;
05868 area.y = -1;
05869 area.width = width;
05870 area.height = 0;
05871
05872 TDEBUG (("in expose span start=%d stop=%d\n", start_pos, end_pos));
05873
05874 for (; pixels < height; cache = cache->next)
05875 {
05876 if (CACHE_DATA(cache).start.index < end_pos)
05877 {
05878 if (CACHE_DATA(cache).end.index >= start_pos)
05879 {
05880 if (area.y < 0)
05881 area.y = MAX(0,pixels);
05882 area.height = pixels + LINE_HEIGHT(CACHE_DATA(cache)) - area.y;
05883 }
05884 }
05885 else
05886 break;
05887
05888 pixels += LINE_HEIGHT(CACHE_DATA(cache));
05889
05890 if (!cache->next)
05891 {
05892 fetch_lines_forward (text, 1);
05893
05894 if (!cache->next)
05895 break;
05896 }
05897 }
05898
05899 if (area.y >= 0)
05900 expose_text (text, &area, TRUE);
05901 }
05902
05903 static void
05904 recompute_geometry (ExtGtkText* text)
05905 {
05906 ExtGtkPropertyMark mark, start_mark;
05907 GList *new_lines;
05908 gint height;
05909 gint width;
05910
05911 free_cache (text);
05912
05913 mark = start_mark = set_vertical_scroll (text);
05914
05915
05916
05917
05918 while (mark.index > 0 &&
05919 EXT_GTK_TEXT_INDEX (text, mark.index - 1) != LINE_DELIM)
05920 decrement_mark (&mark);
05921
05922 gdk_window_get_size (text->text_area, &width, &height);
05923
05924
05925
05926
05927
05928
05929 new_lines = fetch_lines (text,
05930 &mark,
05931 NULL,
05932 FetchLinesCount,
05933 1);
05934
05935 mark = CACHE_DATA (g_list_last (new_lines)).end;
05936 if (!LAST_INDEX (text, mark))
05937 {
05938 advance_mark (&mark);
05939
05940 new_lines = g_list_concat (new_lines,
05941 fetch_lines (text,
05942 &mark,
05943 NULL,
05944 FetchLinesPixels,
05945 height + text->first_cut_pixels));
05946 }
05947
05948
05949
05950 while (CACHE_DATA (new_lines).start.index < start_mark.index)
05951 new_lines = new_lines->next;
05952
05953 text->line_start_cache = new_lines;
05954
05955 find_cursor (text, TRUE);
05956 }
05957
05958
05959
05960
05961
05962 static void
05963 gtk_text_set_selection (GtkEditable *editable,
05964 gint start,
05965 gint end)
05966 {
05967 ExtGtkText *text = EXT_GTK_TEXT (editable);
05968
05969 guint start1, end1, start2, end2;
05970
05971 if (end < 0)
05972 end = TEXT_LENGTH (text);
05973
05974 start1 = MIN(start,end);
05975 end1 = MAX(start,end);
05976 start2 = MIN(editable->selection_start_pos, editable->selection_end_pos);
05977 end2 = MAX(editable->selection_start_pos, editable->selection_end_pos);
05978
05979 if (start2 < start1)
05980 {
05981 guint tmp;
05982
05983 tmp = start1; start1 = start2; start2 = tmp;
05984 tmp = end1; end1 = end2; end2 = tmp;
05985 }
05986
05987 undraw_cursor (text, FALSE);
05988 editable->selection_start_pos = start;
05989 editable->selection_end_pos = end;
05990 draw_cursor (text, FALSE);
05991
05992
05993
05994 if (start1 < start2)
05995 gtk_text_update_text (editable, start1, MIN(end1, start2));
05996
05997 if (end2 > end1)
05998 gtk_text_update_text (editable, MAX(end1, start2), end2);
05999 else if (end2 < end1)
06000 gtk_text_update_text (editable, end2, end1);
06001 }
06002
06003
06004
06005
06006
06007
06008 #ifdef DEBUG_EXT_GTK_TEXT
06009 static void
06010 gtk_text_show_cache_line (ExtGtkText *text, GList *cache,
06011 const char* what, const char* func, gint line)
06012 {
06013 LineParams *lp = &CACHE_DATA(cache);
06014 gint i;
06015
06016 if (cache == text->line_start_cache)
06017 g_message ("Line Start Cache: ");
06018
06019 if (cache == text->current_line)
06020 g_message("Current Line: ");
06021
06022 g_message ("%s:%d: cache line %s s=%d,e=%d,lh=%d (",
06023 func,
06024 line,
06025 what,
06026 lp->start.index,
06027 lp->end.index,
06028 LINE_HEIGHT(*lp));
06029
06030 for (i = lp->start.index; i < (lp->end.index + lp->wraps); i += 1)
06031 g_message ("%c", EXT_GTK_TEXT_INDEX (text, i));
06032
06033 g_message (")\n");
06034 }
06035
06036 static void
06037 gtk_text_show_cache (ExtGtkText *text, const char* func, gint line)
06038 {
06039 GList *l = text->line_start_cache;
06040
06041 if (!l) {
06042 return;
06043 }
06044
06045
06046 while (l->prev)
06047 l = l->prev;
06048
06049 g_message ("*** line cache ***\n");
06050 for (; l; l = l->next)
06051 gtk_text_show_cache_line (text, l, "all", func, line);
06052 }
06053
06054 static void
06055 gtk_text_assert_mark (ExtGtkText *text,
06056 ExtGtkPropertyMark *mark,
06057 ExtGtkPropertyMark *before,
06058 ExtGtkPropertyMark *after,
06059 const gchar *msg,
06060 const gchar *where,
06061 gint line)
06062 {
06063 ExtGtkPropertyMark correct_mark = find_mark (text, mark->index);
06064
06065 if (mark->offset != correct_mark.offset ||
06066 mark->property != correct_mark.property)
06067 g_warning ("incorrect %s text property marker in %s:%d, index %d -- bad!", where, msg, line, mark->index);
06068 }
06069
06070 static void
06071 gtk_text_assert (ExtGtkText *text,
06072 const gchar *msg,
06073 gint line)
06074 {
06075 GList* cache = text->line_start_cache;
06076 ExtGtkPropertyMark* before_mark = NULL;
06077 ExtGtkPropertyMark* after_mark = NULL;
06078
06079 gtk_text_show_props (text, msg, line);
06080
06081 for (; cache->prev; cache = cache->prev)
06082 ;
06083
06084 g_message ("*** line markers ***\n");
06085
06086 for (; cache; cache = cache->next)
06087 {
06088 after_mark = &CACHE_DATA(cache).end;
06089 gtk_text_assert_mark (text, &CACHE_DATA(cache).start, before_mark, after_mark, msg, "start", line);
06090 before_mark = &CACHE_DATA(cache).start;
06091
06092 if (cache->next)
06093 after_mark = &CACHE_DATA(cache->next).start;
06094 else
06095 after_mark = NULL;
06096
06097 gtk_text_assert_mark (text, &CACHE_DATA(cache).end, before_mark, after_mark, msg, "end", line);
06098 before_mark = &CACHE_DATA(cache).end;
06099 }
06100 }
06101
06102 static void
06103 gtk_text_show_adj (ExtGtkText *text,
06104 GtkAdjustment *adj,
06105 const char* what,
06106 const char* func,
06107 gint line)
06108 {
06109 g_message ("*** adjustment ***\n");
06110
06111 g_message ("%s:%d: %s adjustment l=%.1f u=%.1f v=%.1f si=%.1f pi=%.1f ps=%.1f\n",
06112 func,
06113 line,
06114 what,
06115 adj->lower,
06116 adj->upper,
06117 adj->value,
06118 adj->step_increment,
06119 adj->page_increment,
06120 adj->page_size);
06121 }
06122
06123 static void
06124 gtk_text_show_props (ExtGtkText *text,
06125 const char* msg,
06126 int line)
06127 {
06128 GList* props = text->text_properties;
06129 int proplen = 0;
06130
06131 g_message ("%s:%d: ", msg, line);
06132
06133 for (; props; props = props->next)
06134 {
06135 TextProperty *p = (TextProperty*)props->data;
06136
06137 proplen += p->length;
06138
06139 g_message ("[%d,%p,", p->length, p);
06140 if (p->flags & PROPERTY_FONT)
06141 g_message ("%p,", p->font);
06142 else
06143 g_message ("-,");
06144 if (p->flags & PROPERTY_FOREGROUND)
06145 g_message ("%ld, ", p->fore_color.pixel);
06146 else
06147 g_message ("-,");
06148 if (p->flags & PROPERTY_BACKGROUND)
06149 g_message ("%ld] ", p->back_color.pixel);
06150 else
06151 g_message ("-] ");
06152 }
06153
06154 g_message ("\n");
06155
06156 if (proplen - 1 != TEXT_LENGTH(text))
06157 g_warning ("incorrect property list length in %s:%d -- bad!", msg, line);
06158 }
06159 #endif