Yattm - unified GTK instant-messaging client logo
   [Generated for version 0.2-17 - Mon Jan 6 19:01:23 GMT+1 2003]

Home - Main Page - Data Structures - File List - Data Fields - Globals

extgtktext.c

Go to the documentation of this file.
00001 /* GTK - The GIMP Toolkit
00002  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 /*
00021  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
00022  * file for a list of people on the GTK+ Team.  See the ChangeLog
00023  * files for a list of changes.  These files are distributed with
00024  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
00025  */
00026 
00027 /* 
00028  * Modified by the AOL Instant Messenger (SM) Development Team in August 2001. 
00029  * Besides adding support for images and action-requiring 
00030  * (eg. hyperlinked) text, the following was also applied: 
00031  * Underline Patch (#2) for GtkText by Patrick Earl 
00032  * (located at http://www.informatik.fh-hamburg.de/pub/linux/gtk/patches/). 
00033  * In accordance with LGPL, the files that were modified 
00034  * for use in the Linux AIM software are provided free of charge 
00035  * with this distribution and on the AOL Linux AIM website. 
00036  * The modifications were localized to gtktext widget. 
00037  */
00038 
00039 /*
00040  * Modified by Torrey Searle for use with Yattm
00041  * added support for Horizontal Divider rendering
00042  * Fixed some rendering glitches with the image rendering
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 /* Freeze text when inserting or deleting more than this many characters */
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   /* The actual font. */
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   /* Font. */
00204   ExtGtkTextFont* font;
00205 
00206   /* Background Color. */
00207   GdkColor back_color;
00208   
00209   /* Foreground Color. */
00210   GdkColor fore_color;
00211 
00212   /*  Image */
00213   GdkDrawable *image;
00214   GdkBitmap *mask;
00215 
00216   /* Show which properties are set */
00217   TextPropertyFlags flags;
00218 
00219   /* user data */
00220   gpointer user_data;
00221   guint user_data_length;
00222   DataFunc *user_data_func;
00223 
00224   /* Length of this property. */
00225   guint length;
00226 };
00227 
00228 struct _TabStopMark
00229 {
00230   GList* tab_stops; /* Index into list containing the next tab position.  If
00231              * NULL, using default widths. */
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 /* Event handlers */
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 /* Property management */
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 /* Property Movement and Size Computations */
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 /* Display */
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 /* Search and Placement. */
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 /* Scrolling. */
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 /* Cache Management. */
00415 static void   free_cache        (ExtGtkText* text);
00416 static GList* remove_cache_line (ExtGtkText* text, GList* list);
00417 
00418 /* Key Motion. */
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 /* Binding actions */
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 /* To be removed */
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 /* #define DEBUG_EXT_GTK_TEXT */
00469 
00470 #if defined(DEBUG_EXT_GTK_TEXT) && defined(__GNUC__)
00471 /* Debugging utilities. */
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 /* Memory Management. */
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,    /* a */
00526   (GtkTextFunction)gtk_text_move_backward_character,   /* b */
00527   (GtkTextFunction)gtk_editable_copy_clipboard,        /* c */
00528   (GtkTextFunction)gtk_text_delete_forward_character,  /* d */
00529   (GtkTextFunction)gtk_text_move_end_of_line,          /* e */
00530   (GtkTextFunction)gtk_text_move_forward_character,    /* f */
00531   NULL,                                                /* g */
00532   (GtkTextFunction)gtk_text_delete_backward_character, /* h */
00533   NULL,                                                /* i */
00534   NULL,                                                /* j */
00535   (GtkTextFunction)gtk_text_delete_to_line_end,        /* k */
00536   NULL,                                                /* l */
00537   NULL,                                                /* m */
00538   (GtkTextFunction)gtk_text_move_next_line,            /* n */
00539   NULL,                                                /* o */
00540   (GtkTextFunction)gtk_text_move_previous_line,        /* p */
00541   NULL,                                                /* q */
00542   NULL,                                                /* r */
00543   NULL,                                                /* s */
00544   NULL,                                                /* t */
00545   (GtkTextFunction)gtk_text_delete_line,               /* u */
00546   (GtkTextFunction)gtk_editable_paste_clipboard,       /* v */
00547   (GtkTextFunction)gtk_text_delete_backward_word,      /* w */
00548   (GtkTextFunction)gtk_editable_cut_clipboard,         /* x */
00549   NULL,                                                /* y */
00550   NULL,                                                /* z */
00551 };
00552 
00553 static const GtkTextFunction alt_keys[26] =
00554 {
00555   NULL,                                                /* a */
00556   (GtkTextFunction)gtk_text_move_backward_word,        /* b */
00557   NULL,                                                /* c */
00558   (GtkTextFunction)gtk_text_delete_forward_word,       /* d */
00559   NULL,                                           /* e */
00560   (GtkTextFunction)gtk_text_move_forward_word,         /* f */
00561   NULL,                                           /* g */
00562   NULL,                                           /* h */
00563   NULL,                                           /* i */
00564   NULL,                                           /* j */
00565   NULL,                                           /* k */
00566   NULL,                                           /* l */
00567   NULL,                                           /* m */
00568   NULL,                                           /* n */
00569   NULL,                                           /* o */
00570   NULL,                                           /* p */
00571   NULL,                                           /* q */
00572   NULL,                                           /* r */
00573   NULL,                                           /* s */
00574   NULL,                                           /* t */
00575   NULL,                                           /* u */
00576   NULL,                                           /* v */
00577   NULL,                                           /* w */
00578   NULL,                                           /* x */
00579   NULL,                                           /* y */
00580   NULL,                                           /* z */
00581 };
00582 
00583 /**********************************************************************/
00584 /*                  Widget Crap                           */
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     //XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid);
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     /* reserved_1 */ NULL,
00655         /* reserved_2 */ 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) /*  this is where rejection happened, changed next */
01173     {
01174 /*      insert_text_property (text, font, fore, back, numwcs); */
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       /* We'll reset the cursor later anyways if we aren't frozen */
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       /* We need to undraw the cursor here, since we may later
01316        * delete the cursor's property
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   /* FIXME, or resizing after deleting will be odd */
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   /* We'll reset the cursor later anyways if we aren't frozen */
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   /* Clean up the internal structures */
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   /* Can't call gtk_style_set_background here because it's handled specially */
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       /* top rect */
01794       clear_focus_area (text, x, y, width, yextra);
01795       /* left rect */
01796       clear_focus_area (text, x, y + yextra, 
01797                 xextra, y + height - 2 * yextra);
01798       /* right rect */
01799       clear_focus_area (text, x + width - xextra, y + yextra, 
01800                 xextra, height - 2 * ythick);
01801       /* bottom rect */
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       /* Set it now, so we display things right. We'll unset it
02002        * later if things don't work out */
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       /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
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           /* gtk_toggle_insert(text) -- IMPLEMENT */
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       /* Don't insert literally */
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   /* Clamp the value here, because we'll get really confused
02529    * if someone tries to move the adjusment outside of the
02530    * allowed bounds
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   /* Just ignore it if we haven't been size-allocated and realized yet */
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 /* if (diff < 0) */
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      /* mark0 MUST be a real line start.  if ALLOC, allocate line params
02625       * from a mem chunk.  DATA is passed to ITER_CALL, which is called
02626       * for each line following MARK, iteration continues unless ITER_CALL
02627       * returns TRUE. */
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 /* Compute the number of lines, and vertical pixels for n characters
02755  * starting from the point 
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   /* If chars_left == 0, that means we're joining two lines in a
02768    * deletion, so add in the values for the next line as well 
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;   /* force another loop */
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     /* nothing */;
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       /*TEXT_ASSERT_MARK(text, start, "start");*/
02892       /*TEXT_ASSERT_MARK(text, end, "end");*/
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 /* note, the point has already been moved forward */
02982 static void
02983 correct_cache_insert (ExtGtkText* text, gint nchars)
02984 {
02985   GList *cache;
02986   ExtGtkPropertyMark *start;
02987   ExtGtkPropertyMark *end;
02988   
02989   /* If we inserted a property exactly at the beginning of the
02990    * line, we have to correct here, or fetch_lines will
02991    * fetch junk.
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   /* Now correct the offsets, and check for start or end marks that
03001    * are after the point, yet point to a property before the point's
03002    * property. This indicates that they are meant to point to the
03003    * second half of a property we split in insert_text_property(), so
03004    * we fix them up that way.  
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           /* We split the property, and this is the second half */
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           /* We split the property, and this is the second half */
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       /*TEXT_ASSERT_MARK(text, start, "start");*/
03058       /*TEXT_ASSERT_MARK(text, end, "end");*/
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 /* Text property functions */
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 /* Flop the memory between the point and the gap around like a
03476  * dead fish. */
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 /* Increase the gap size. */
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 /* Inserts into the text property list a list element that guarantees
03550  * that for len characters following the point, text has the correct
03551  * property.  does not move point.  adjusts text_properties_point and
03552  * text_properties_point_offset relative to the current value of
03553  * point. */
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       /* Point is on the boundary of two properties.
03570        * If it is the same as either, grow, else insert
03571        * a new one. */
03572       
03573       if (text_properties_equal(forward_prop, font, fore, back, underlined, divider, image, user_data, user_data_length, user_data_func)) 
03574     {
03575       /* Grow the property in front of us. */
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       /* Grow property behind us, point property and offset
03583        * change. */
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       /* Next property just has last position, take it over */
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       /* Splice a new property into the list. */
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       /* The following will screw up the line_start cache,
03672        * we'll fix it up in correct_cache_insert
03673        */
03674       
03675       /* In the middle of forward_prop, if properties are equal,
03676        * just add to its length, else split it into two and splice
03677        * in a new one. */
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       /* Inserting before only the last position in the text */
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       /* Set the new lengths according to where they are split.  Construct
03706        * two new properties. */
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       /* Now splice things in. */
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   /* Delete nchars forward from point. */
03761   
03762   /* Deleting text properties is problematical, because we
03763    * might be storing around marks pointing to a property.
03764    *
03765    * The marks in question and how we handle them are:
03766    *
03767    *  point: We know the new value, since it will be at the
03768    *         end of the deleted text, and we move it there
03769    *         first.
03770    *  cursor: We just remove the mark and set it equal to the
03771    *         point after the operation.
03772    *  line-start cache: We replace most affected lines.
03773    *         The current line gets used to fetch the new
03774    *         lines so, if necessary, (delete at the beginning
03775    *         of a line) we fix it up by setting it equal to the
03776    *         point.
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   /* Check to see if we have just the single final position remaining
03819    * along in a property; if so, combine it with the previous property
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 /*             Property Movement                          */
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;            /* otherwise it migth not be init. */
03898   prop = MARK_CURRENT_PROPERTY(mark);
03899 
03900   if ((prop->length - mark->offset - 1) < n) { /* if we need to change prop. */
03901     /* to make it easier */
03902     n += (mark->offset);
03903     mark->index -= mark->offset;
03904     mark->offset = 0;
03905     /* first we take seven-mile-leaps to get to the right text
03906      * property. */
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   /* and then the rest */
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     /* jump to end of prev */
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   /* and the rest */
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  * You can also start from the end, what a drag.
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 /* This routine must be called with scroll == FALSE, only when
03998  * point is at least partially on screen
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   /* Scroll backwards until the point is on screen
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   /* Now additionally try to make sure that the point is fully on screen
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; /* LOOK HERE, this proc has an
04037                        * important side effect. */
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       /* Scroll the bottom of the line is on screen, or until
04051        * the line is the first onscreen line.
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 (); /* Must set text->current_line here */
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 /*          Search and Placement                          */
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      /* No tabs! */
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 /*              Cache Manager                             */
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 /*               Key Motion                               */
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   /* count should be +-1. */
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;   /* FIXME */
04605   
04606   undraw_cursor (text, FALSE);
04607   
04608   /* Move to the beginning of the line */
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 /*                Scrolling                               */
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       /* We got clipped, and don't really know which line to put first. */
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   /* Make sure graphics expose events are processed before scrolling
04918    * again */
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 /*                Display Code                            */
05098 /**********************************************************************/
05099 
05100 /* Assumes mark starts a line.  Calculates the height, width, and
05101  * displayable character count of a single DISPLAYABLE line.  That
05102  * means that in line-wrap mode, this does may not compute the
05103  * properties of an entire line. */
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       /* Newline doesn't count in computation of line height, even
05141        * if its in a bigger font than the rest of the line.  Unless,
05142        * of course, there are no other characters. */
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            * if it is an image that is overflowing,
05168            * always wrap it
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           /* Here's the tough case, a tab is wrapping. */
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               /* If whole line is one word, revert to char wrapping */
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               /* Don't include this character, it will wrap. */
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       /* Special case, empty last line. */
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 /* Side effect: modifies text->gc
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                 &GTK_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   /* First provide a contiguous segment of memory.  This makes reading
05384    * the code below *much* easier, and only incurs the cost of copying
05385    * when the line being displayed spans the gap. */
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 = &GTK_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 = &GTK_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           /* Note that the underline starts drawing at running_offset+1 which
05571              technically isn't the beginning of the the line, but it "looked
05572              better" when testing it. */
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                           // pixel_start_height+1,
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, &GTK_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           /* We undraw and draw the cursor here to get the drawn
05827            * level right ... FIXME - maybe the second parameter
05828            * of draw_cursor should work differently
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   /* We need a real start of a line when calling fetch_lines().
05916    * not the start of a wrapped line.
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   /* Fetch an entire line, to make sure that we get all the text
05925    * we backed over above, in addition to enough text to fill up
05926    * the space vertically
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   /* Now work forward to the actual first onscreen line */
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 /*                            Selection                               */
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   /* Expose only what changed */
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 /*                              Debug                                 */
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   /* back up to the absolute beginning of the line cache */
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     /* nothing */;
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

Contact: Andy Maloney     [Documentation generated by doxygen]