~canonical-dx-team/ubuntu/maverick/gtk+2.0/menuproxy

« back to all changes in this revision

Viewing changes to tests/testtext.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-05-04 12:24:25 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20070504122425-0m8midgzrp40y8w2
Tags: 2.10.12-1ubuntu1
* Sync with Debian
* New upstream version:
  Fixed bugs:
  - 379414 file chooser warnings when changing path in the entry
  - 418585 GtkFileChooserDefault sizing code is not DPI independent
  - 419568 Crash in search if start with special letter
  - 435062 build dies with icon cache validation
  - 379399 Segfault to call gtk_print_operation_run twice.
  - 387889 cups backend has problems when there are too many printers
  - 418531 invalid read to gtkicontheme.c gtk_icon_theme_lookup_icon...
  - 423916 crash in color scheme code
  - 424042 Segmentation fault while quickly pressing Alt+arrows
  - 415260 Protect against negative indices when setting values in G...
  - 419171 XGetVisualInfo() may not set nxvisuals
  - 128852 Gdk cursors don't look good on win32
  - 344657 Ctrl-H doesn't toggle "Show Hidden Files" setting
  - 345345 PrintOperation::paginate is not emitted for class handler
  - 347567 GtkPrintOperation::end-print is not emitted if it's cance...
  - 369112 gtk_ui_manager_add_ui should accept unnamed separator
  - 392015 Selected menu item invisible on Windows Vista
  - 399253 MS-Windows Theme Bottom Tab placement rendering glitches
  - 399425 gtk_input_dialog_fill_axes() adds child to gtkscrolledwin...
  - 403251 [patch] little memory leak in GtkPrintJob
  - 403267 [patch] memory leak in GtkPageSetupUnixDialog
  - 403470 MS-Windows Theme tab placement other than on top leaks a ...
  - 404506 Windows system fonts that have multi-byte font names cann...
  - 405089 Incorrect window placement for GtkEventBox private window
  - 405515 Minor leak in gtkfilesystemmodel.c
  - 405539 gdk_pixbuf_save() for PNG saver can return FALSE without ...
  - 415681 gdk_window_clear_area includes an extra line and column o...
  - 418219 GtkRecentChooser should apply filter before sorting and c...
  - 418403 Scroll to printer after selecting it from settings
  - 421985 _gtk_print_operation_platform_backend_launch_preview
  - 421990 gtk_print_job_get_surface
  - 421993 gtk_print_operation_init
  - 423064 Conditional jump or move depends on uninitialised value(s...
  - 423722 Fix printing header in gtk-demo
  - 424168 gtk_print_operation_run on async preview
  - 425655 Don't install gtk+-unix-print-2.0.pc on non-UNIX platforms
  - 425786 GDK segfaults if XineramaQueryScreens fails
  - 428665 Lpr Backend gets stuck in infinite loop during gtk_enumer...
  - 429902 GtkPrintOperation leaks cairo contextes
  - 431997 First delay of GdkPixbufAnimationIter is wrong
  - 433242 Inconsistent scroll arrow position calculations
  - 433972 Placing gtk.Expander inside a gtk.TextView() changes gtk....
  - 434261 _gtk_toolbar_elide_underscores incorrectly handles some s...
  - 383354 ctrl-L should make 'Location' entry disappear
  - 418673 gtk_recent_manager_add_item
  - 429732 gtk_accel_group_finalize accesses invalid memory
  - 435028 WM_CLIENT_LEADER is wrong on the leader_window
  - 431067 Background of the header window is not updated
  - 338843 add recent files support inside the ui manager
  - 148535 add drop shadow to menus, tooltips, etc. under Windows XP
* debian/control.in:
  - Conflicts on ubuntulooks (<= 0.9.11-1)
* debian/patches/15_default-fallback-icon-theme.patch:
  - patch from Debian, fallback on gnome icon theme

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* testtext.c
 
2
 * Copyright (C) 2000 Red Hat, Inc
 
3
 * Author: Havoc Pennington
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <stdio.h>
 
23
#include <sys/stat.h>
 
24
#include <errno.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
 
 
28
#undef GTK_DISABLE_DEPRECATED
 
29
 
 
30
#include <gtk/gtk.h>
 
31
#include <gdk/gdkkeysyms.h>
 
32
 
 
33
#include "prop-editor.h"
 
34
 
 
35
typedef struct _Buffer Buffer;
 
36
typedef struct _View View;
 
37
 
 
38
static gint untitled_serial = 1;
 
39
 
 
40
GSList *active_window_stack = NULL;
 
41
 
 
42
struct _Buffer
 
43
{
 
44
  gint refcount;
 
45
  GtkTextBuffer *buffer;
 
46
  char *filename;
 
47
  gint untitled_serial;
 
48
  GtkTextTag *invisible_tag;
 
49
  GtkTextTag *not_editable_tag;
 
50
  GtkTextTag *found_text_tag;
 
51
  GtkTextTag *rise_tag;
 
52
  GtkTextTag *large_tag;
 
53
  GtkTextTag *indent_tag;
 
54
  GtkTextTag *margin_tag;
 
55
  GtkTextTag *custom_tabs_tag;
 
56
  GSList *color_tags;
 
57
  guint color_cycle_timeout;
 
58
  gdouble start_hue;
 
59
};
 
60
 
 
61
struct _View
 
62
{
 
63
  GtkWidget *window;
 
64
  GtkWidget *text_view;
 
65
  GtkAccelGroup *accel_group;
 
66
  GtkItemFactory *item_factory;
 
67
  Buffer *buffer;
 
68
};
 
69
 
 
70
static void push_active_window (GtkWindow *window);
 
71
static void pop_active_window (void);
 
72
static GtkWindow *get_active_window (void);
 
73
 
 
74
static Buffer * create_buffer      (void);
 
75
static gboolean check_buffer_saved (Buffer *buffer);
 
76
static gboolean save_buffer        (Buffer *buffer);
 
77
static gboolean save_as_buffer     (Buffer *buffer);
 
78
static char *   buffer_pretty_name (Buffer *buffer);
 
79
static void     buffer_filename_set (Buffer *buffer);
 
80
static void     buffer_search_forward (Buffer *buffer,
 
81
                                       const char *str,
 
82
                                       View *view);
 
83
static void     buffer_search_backward (Buffer *buffer,
 
84
                                       const char *str,
 
85
                                       View *view);
 
86
static void     buffer_set_colors      (Buffer  *buffer,
 
87
                                        gboolean enabled);
 
88
static void     buffer_cycle_colors    (Buffer  *buffer);
 
89
 
 
90
static View *view_from_widget (GtkWidget *widget);
 
91
 
 
92
static View *create_view      (Buffer *buffer);
 
93
static void  check_close_view (View   *view);
 
94
static void  close_view       (View   *view);
 
95
static void  view_set_title   (View   *view);
 
96
static void  view_init_menus  (View   *view);
 
97
static void  view_add_example_widgets (View *view);
 
98
 
 
99
GSList *buffers = NULL;
 
100
GSList *views = NULL;
 
101
 
 
102
static void
 
103
push_active_window (GtkWindow *window)
 
104
{
 
105
  g_object_ref (window);
 
106
  active_window_stack = g_slist_prepend (active_window_stack, window);
 
107
}
 
108
 
 
109
static void
 
110
pop_active_window (void)
 
111
{
 
112
  g_object_unref (active_window_stack->data);
 
113
  active_window_stack = g_slist_delete_link (active_window_stack, active_window_stack);
 
114
}
 
115
 
 
116
static GtkWindow *
 
117
get_active_window (void)
 
118
{
 
119
  if (active_window_stack)
 
120
    return active_window_stack->data;
 
121
  else
 
122
    return NULL;
 
123
}
 
124
 
 
125
/*
 
126
 * Filesel utility function
 
127
 */
 
128
 
 
129
typedef gboolean (*FileselOKFunc) (const char *filename, gpointer data);
 
130
 
 
131
static void
 
132
filesel_ok_cb (GtkWidget *button, GtkWidget *filesel)
 
133
{
 
134
  FileselOKFunc ok_func = (FileselOKFunc)g_object_get_data (G_OBJECT (filesel), "ok-func");
 
135
  gpointer data = g_object_get_data (G_OBJECT (filesel), "ok-data");
 
136
  gint *result = g_object_get_data (G_OBJECT (filesel), "ok-result");
 
137
  
 
138
  gtk_widget_hide (filesel);
 
139
  
 
140
  if ((*ok_func) (gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), data))
 
141
    {
 
142
      gtk_widget_destroy (filesel);
 
143
      *result = TRUE;
 
144
    }
 
145
  else
 
146
    gtk_widget_show (filesel);
 
147
}
 
148
 
 
149
gboolean
 
150
filesel_run (GtkWindow    *parent, 
 
151
             const char   *title,
 
152
             const char   *start_file,
 
153
             FileselOKFunc func,
 
154
             gpointer      data)
 
155
{
 
156
  GtkWidget *filesel = gtk_file_selection_new (title);
 
157
  gboolean result = FALSE;
 
158
 
 
159
  if (!parent)
 
160
    parent = get_active_window ();
 
161
  
 
162
  if (parent)
 
163
    gtk_window_set_transient_for (GTK_WINDOW (filesel), parent);
 
164
 
 
165
  if (start_file)
 
166
    gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), start_file);
 
167
 
 
168
  
 
169
  g_object_set_data (G_OBJECT (filesel), "ok-func", func);
 
170
  g_object_set_data (G_OBJECT (filesel), "ok-data", data);
 
171
  g_object_set_data (G_OBJECT (filesel), "ok-result", &result);
 
172
 
 
173
  g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button,
 
174
                    "clicked",
 
175
                    G_CALLBACK (filesel_ok_cb), filesel);
 
176
  g_signal_connect_swapped (GTK_FILE_SELECTION (filesel)->cancel_button,
 
177
                            "clicked",
 
178
                            G_CALLBACK (gtk_widget_destroy), filesel);
 
179
 
 
180
  g_signal_connect (filesel, "destroy",
 
181
                    G_CALLBACK (gtk_main_quit), NULL);
 
182
  gtk_window_set_modal (GTK_WINDOW (filesel), TRUE);
 
183
 
 
184
  gtk_widget_show (filesel);
 
185
  gtk_main ();
 
186
 
 
187
  return result;
 
188
}
 
189
 
 
190
/*
 
191
 * MsgBox utility functions
 
192
 */
 
193
 
 
194
static void
 
195
msgbox_yes_cb (GtkWidget *widget, gboolean *result)
 
196
{
 
197
  *result = 0;
 
198
  gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
 
199
}
 
200
 
 
201
static void
 
202
msgbox_no_cb (GtkWidget *widget, gboolean *result)
 
203
{
 
204
  *result = 1;
 
205
  gtk_object_destroy (GTK_OBJECT (gtk_widget_get_toplevel (widget)));
 
206
}
 
207
 
 
208
static gboolean
 
209
msgbox_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
 
210
{
 
211
  if (event->keyval == GDK_Escape)
 
212
    {
 
213
      g_signal_stop_emission_by_name (widget, "key_press_event");
 
214
      gtk_object_destroy (GTK_OBJECT (widget));
 
215
      return TRUE;
 
216
    }
 
217
 
 
218
  return FALSE;
 
219
}
 
220
 
 
221
/* Don't copy this example, it's all crack-smoking - you can just use
 
222
 * GtkMessageDialog now
 
223
 */
 
224
gint
 
225
msgbox_run (GtkWindow  *parent,
 
226
            const char *message,
 
227
            const char *yes_button,
 
228
            const char *no_button,
 
229
            const char *cancel_button,
 
230
            gint default_index)
 
231
{
 
232
  gboolean result = -1;
 
233
  GtkWidget *dialog;
 
234
  GtkWidget *button;
 
235
  GtkWidget *label;
 
236
  GtkWidget *vbox;
 
237
  GtkWidget *button_box;
 
238
  GtkWidget *separator;
 
239
 
 
240
  g_return_val_if_fail (message != NULL, FALSE);
 
241
  g_return_val_if_fail (default_index >= 0 && default_index <= 1, FALSE);
 
242
 
 
243
  if (!parent)
 
244
    parent = get_active_window ();
 
245
  
 
246
  /* Create a dialog
 
247
   */
 
248
  dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
249
  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
250
  if (parent)
 
251
    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
 
252
  gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
 
253
 
 
254
  /* Quit our recursive main loop when the dialog is destroyed.
 
255
   */
 
256
  g_signal_connect (dialog, "destroy",
 
257
                    G_CALLBACK (gtk_main_quit), NULL);
 
258
 
 
259
  /* Catch Escape key presses and have them destroy the dialog
 
260
   */
 
261
  g_signal_connect (dialog, "key_press_event",
 
262
                    G_CALLBACK (msgbox_key_press_cb), NULL);
 
263
 
 
264
  /* Fill in the contents of the widget
 
265
   */
 
266
  vbox = gtk_vbox_new (FALSE, 0);
 
267
  gtk_container_add (GTK_CONTAINER (dialog), vbox);
 
268
  
 
269
  label = gtk_label_new (message);
 
270
  gtk_misc_set_padding (GTK_MISC (label), 12, 12);
 
271
  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
272
  gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
 
273
 
 
274
  separator = gtk_hseparator_new ();
 
275
  gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
 
276
 
 
277
  button_box = gtk_hbutton_box_new ();
 
278
  gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
 
279
  gtk_container_set_border_width (GTK_CONTAINER (button_box), 8);
 
280
  
 
281
 
 
282
  /* When Yes is clicked, call the msgbox_yes_cb
 
283
   * This sets the result variable and destroys the dialog
 
284
   */
 
285
  if (yes_button)
 
286
    {
 
287
      button = gtk_button_new_with_label (yes_button);
 
288
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
289
      gtk_container_add (GTK_CONTAINER (button_box), button);
 
290
 
 
291
      if (default_index == 0)
 
292
        gtk_widget_grab_default (button);
 
293
      
 
294
      g_signal_connect (button, "clicked",
 
295
                        G_CALLBACK (msgbox_yes_cb), &result);
 
296
    }
 
297
 
 
298
  /* When No is clicked, call the msgbox_no_cb
 
299
   * This sets the result variable and destroys the dialog
 
300
   */
 
301
  if (no_button)
 
302
    {
 
303
      button = gtk_button_new_with_label (no_button);
 
304
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
305
      gtk_container_add (GTK_CONTAINER (button_box), button);
 
306
 
 
307
      if (default_index == 0)
 
308
        gtk_widget_grab_default (button);
 
309
      
 
310
      g_signal_connect (button, "clicked",
 
311
                        G_CALLBACK (msgbox_no_cb), &result);
 
312
    }
 
313
 
 
314
  /* When Cancel is clicked, destroy the dialog
 
315
   */
 
316
  if (cancel_button)
 
317
    {
 
318
      button = gtk_button_new_with_label (cancel_button);
 
319
      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
320
      gtk_container_add (GTK_CONTAINER (button_box), button);
 
321
      
 
322
      if (default_index == 1)
 
323
        gtk_widget_grab_default (button);
 
324
      
 
325
      g_signal_connect_swapped (button, "clicked",
 
326
                                G_CALLBACK (gtk_object_destroy), dialog);
 
327
    }
 
328
 
 
329
  gtk_widget_show_all (dialog);
 
330
 
 
331
  /* Run a recursive main loop until a button is clicked
 
332
   * or the user destroys the dialog through the window mananger */
 
333
  gtk_main ();
 
334
 
 
335
  return result;
 
336
}
 
337
 
 
338
#ifdef DO_BLINK
 
339
/*
 
340
 * Example buffer filling code
 
341
 */
 
342
static gint
 
343
blink_timeout (gpointer data)
 
344
{
 
345
  GtkTextTag *tag;
 
346
  static gboolean flip = FALSE;
 
347
  
 
348
  tag = GTK_TEXT_TAG (data);
 
349
 
 
350
  g_object_set (tag,
 
351
                 "foreground", flip ? "blue" : "purple",
 
352
                 NULL);
 
353
 
 
354
  flip = !flip;
 
355
 
 
356
  return TRUE;
 
357
}
 
358
#endif
 
359
 
 
360
static gint
 
361
tag_event_handler (GtkTextTag *tag, GtkWidget *widget, GdkEvent *event,
 
362
                  const GtkTextIter *iter, gpointer user_data)
 
363
{
 
364
  gint char_index;
 
365
 
 
366
  char_index = gtk_text_iter_get_offset (iter);
 
367
  
 
368
  switch (event->type)
 
369
    {
 
370
    case GDK_MOTION_NOTIFY:
 
371
      printf ("Motion event at char %d tag `%s'\n",
 
372
             char_index, tag->name);
 
373
      break;
 
374
        
 
375
    case GDK_BUTTON_PRESS:
 
376
      printf ("Button press at char %d tag `%s'\n",
 
377
             char_index, tag->name);
 
378
      break;
 
379
        
 
380
    case GDK_2BUTTON_PRESS:
 
381
      printf ("Double click at char %d tag `%s'\n",
 
382
             char_index, tag->name);
 
383
      break;
 
384
        
 
385
    case GDK_3BUTTON_PRESS:
 
386
      printf ("Triple click at char %d tag `%s'\n",
 
387
             char_index, tag->name);
 
388
      break;
 
389
        
 
390
    case GDK_BUTTON_RELEASE:
 
391
      printf ("Button release at char %d tag `%s'\n",
 
392
             char_index, tag->name);
 
393
      break;
 
394
        
 
395
    case GDK_KEY_PRESS:
 
396
    case GDK_KEY_RELEASE:
 
397
      printf ("Key event at char %d tag `%s'\n",
 
398
              char_index, tag->name);
 
399
      break;
 
400
      
 
401
    case GDK_ENTER_NOTIFY:
 
402
    case GDK_LEAVE_NOTIFY:
 
403
    case GDK_PROPERTY_NOTIFY:
 
404
    case GDK_SELECTION_CLEAR:
 
405
    case GDK_SELECTION_REQUEST:
 
406
    case GDK_SELECTION_NOTIFY:
 
407
    case GDK_PROXIMITY_IN:
 
408
    case GDK_PROXIMITY_OUT:
 
409
    case GDK_DRAG_ENTER:
 
410
    case GDK_DRAG_LEAVE:
 
411
    case GDK_DRAG_MOTION:
 
412
    case GDK_DRAG_STATUS:
 
413
    case GDK_DROP_START:
 
414
    case GDK_DROP_FINISHED:
 
415
    default:
 
416
      break;
 
417
    }
 
418
 
 
419
  return FALSE;
 
420
}
 
421
 
 
422
static void
 
423
setup_tag (GtkTextTag *tag)
 
424
{
 
425
  g_signal_connect (tag,
 
426
                    "event",
 
427
                    G_CALLBACK (tag_event_handler),
 
428
                    NULL);
 
429
}
 
430
 
 
431
static const char  *book_closed_xpm[] = {
 
432
"16 16 6 1",
 
433
"       c None s None",
 
434
".      c black",
 
435
"X      c red",
 
436
"o      c yellow",
 
437
"O      c #808080",
 
438
"#      c white",
 
439
"                ",
 
440
"       ..       ",
 
441
"     ..XX.      ",
 
442
"   ..XXXXX.     ",
 
443
" ..XXXXXXXX.    ",
 
444
".ooXXXXXXXXX.   ",
 
445
"..ooXXXXXXXXX.  ",
 
446
".X.ooXXXXXXXXX. ",
 
447
".XX.ooXXXXXX..  ",
 
448
" .XX.ooXXX..#O  ",
 
449
"  .XX.oo..##OO. ",
 
450
"   .XX..##OO..  ",
 
451
"    .X.#OO..    ",
 
452
"     ..O..      ",
 
453
"      ..        ",
 
454
"                "};
 
455
 
 
456
void
 
457
fill_example_buffer (GtkTextBuffer *buffer)
 
458
{
 
459
  GtkTextIter iter, iter2;
 
460
  GtkTextTag *tag;
 
461
  GtkTextChildAnchor *anchor;
 
462
  GdkColor color;
 
463
  GdkColor color2;
 
464
  GdkPixbuf *pixbuf;
 
465
  int i;
 
466
  char *str;
 
467
  
 
468
  /* FIXME this is broken if called twice on a buffer, since
 
469
   * we try to create tags a second time.
 
470
   */
 
471
  
 
472
  tag = gtk_text_buffer_create_tag (buffer, "fg_blue", NULL);
 
473
 
 
474
#ifdef DO_BLINK
 
475
  gtk_timeout_add (1000, blink_timeout, tag);
 
476
#endif     
 
477
 
 
478
  setup_tag (tag);
 
479
  
 
480
  color.red = color.green = 0;
 
481
  color.blue = 0xffff;
 
482
  color2.red = 0xfff;
 
483
  color2.blue = 0x0;
 
484
  color2.green = 0;
 
485
  g_object_set (tag,
 
486
                "foreground_gdk", &color,
 
487
                "background_gdk", &color2,
 
488
                "size_points", 24.0,
 
489
                NULL);
 
490
 
 
491
  tag = gtk_text_buffer_create_tag (buffer, "fg_red", NULL);
 
492
 
 
493
  setup_tag (tag);
 
494
      
 
495
  color.blue = color.green = 0;
 
496
  color.red = 0xffff;
 
497
  g_object_set (tag,
 
498
                "rise", -4 * PANGO_SCALE,
 
499
                "foreground_gdk", &color,
 
500
                NULL);
 
501
 
 
502
  tag = gtk_text_buffer_create_tag (buffer, "bg_green", NULL);
 
503
 
 
504
  setup_tag (tag);
 
505
      
 
506
  color.blue = color.red = 0;
 
507
  color.green = 0xffff;
 
508
  g_object_set (tag,
 
509
                "background_gdk", &color,
 
510
                "size_points", 10.0,
 
511
                NULL);
 
512
 
 
513
  tag = gtk_text_buffer_create_tag (buffer, "strikethrough", NULL);
 
514
 
 
515
  setup_tag (tag);
 
516
      
 
517
  g_object_set (tag,
 
518
                "strikethrough", TRUE,
 
519
                NULL);
 
520
 
 
521
 
 
522
  tag = gtk_text_buffer_create_tag (buffer, "underline", NULL);
 
523
 
 
524
  setup_tag (tag);
 
525
      
 
526
  g_object_set (tag,
 
527
                "underline", PANGO_UNDERLINE_SINGLE,
 
528
                NULL);
 
529
 
 
530
  tag = gtk_text_buffer_create_tag (buffer, "underline_error", NULL);
 
531
 
 
532
  setup_tag (tag);
 
533
      
 
534
  g_object_set (tag,
 
535
                "underline", PANGO_UNDERLINE_ERROR,
 
536
                NULL);
 
537
 
 
538
  tag = gtk_text_buffer_create_tag (buffer, "centered", NULL);
 
539
      
 
540
  g_object_set (tag,
 
541
                "justification", GTK_JUSTIFY_CENTER,
 
542
                NULL);
 
543
 
 
544
  tag = gtk_text_buffer_create_tag (buffer, "rtl_quote", NULL);
 
545
      
 
546
  g_object_set (tag,
 
547
                "wrap_mode", GTK_WRAP_WORD,
 
548
                "direction", GTK_TEXT_DIR_RTL,
 
549
                "indent", 30,
 
550
                "left_margin", 20,
 
551
                "right_margin", 20,
 
552
                NULL);
 
553
 
 
554
 
 
555
  tag = gtk_text_buffer_create_tag (buffer, "negative_indent", NULL);
 
556
      
 
557
  g_object_set (tag,
 
558
                "indent", -25,
 
559
                NULL);
 
560
  
 
561
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
 
562
 
 
563
  anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
 
564
 
 
565
  g_object_ref (anchor);
 
566
  
 
567
  g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
 
568
                          (GDestroyNotify) g_object_unref);
 
569
  
 
570
  pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
 
571
  
 
572
  i = 0;
 
573
  while (i < 100)
 
574
    {
 
575
      GtkTextMark * temp_mark;
 
576
      
 
577
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
 
578
          
 
579
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
 
580
          
 
581
      str = g_strdup_printf ("%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n",
 
582
                            i);
 
583
      
 
584
      gtk_text_buffer_insert (buffer, &iter, str, -1);
 
585
 
 
586
      g_free (str);
 
587
      
 
588
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 5);
 
589
          
 
590
      gtk_text_buffer_insert (buffer, &iter,
 
591
                             "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n"
 
592
                             /* This is UTF8 stuff, Emacs doesn't
 
593
                                really know how to display it */
 
594
                             "German (Deutsch S\303\274d) Gr\303\274\303\237 Gott Greek (\316\225\316\273\316\273\316\267\316\275\316\271\316\272\316\254) \316\223\316\265\316\271\316\254 \317\203\316\261\317\202 Hebrew(\327\251\327\234\327\225\327\235) Hebrew punctuation(\xd6\xbf\327\251\xd6\xbb\xd6\xbc\xd6\xbb\xd6\xbf\327\234\xd6\xbc\327\225\xd6\xbc\xd6\xbb\xd6\xbb\xd6\xbf\327\235\xd6\xbc\xd6\xbb\xd6\xbf) Japanese (\346\227\245\346\234\254\350\252\236) Thai (\340\270\252\340\270\247\340\270\261\340\270\252\340\270\224\340\270\265\340\270\204\340\270\243\340\270\261\340\270\232) Thai wrong spelling (\340\270\204\340\270\263\340\270\225\340\271\210\340\270\255\340\271\204\340\270\233\340\270\231\340\270\267\340\271\210\340\270\252\340\270\260\340\270\201\340\270\224\340\270\234\340\270\264\340\270\224 \340\270\236\340\270\261\340\270\261\340\271\211\340\270\261\340\270\261\340\271\210\340\270\207\340\271\202\340\270\201\340\270\260)\n", -1);
 
595
 
 
596
      temp_mark =
 
597
        gtk_text_buffer_create_mark (buffer, "tmp_mark", &iter, TRUE);
 
598
 
 
599
#if 1
 
600
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 6);
 
601
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 13);
 
602
 
 
603
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
 
604
 
 
605
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 10);
 
606
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 16);
 
607
 
 
608
      gtk_text_buffer_apply_tag_by_name (buffer, "underline", &iter, &iter2);
 
609
 
 
610
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 4);
 
611
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 7);
 
612
 
 
613
      gtk_text_buffer_apply_tag_by_name (buffer, "underline_error", &iter, &iter2);
 
614
 
 
615
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 1, 14);
 
616
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 1, 24);
 
617
 
 
618
      gtk_text_buffer_apply_tag_by_name (buffer, "strikethrough", &iter, &iter2);
 
619
          
 
620
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 9);
 
621
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 0, 16);
 
622
 
 
623
      gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
 
624
  
 
625
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 2);
 
626
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 10);
 
627
 
 
628
      gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
 
629
 
 
630
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 4, 8);
 
631
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter2, 4, 15);
 
632
 
 
633
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
 
634
#endif
 
635
 
 
636
      gtk_text_buffer_get_iter_at_mark (buffer, &iter, temp_mark);
 
637
      gtk_text_buffer_insert (buffer, &iter, "Centered text!\n", -1);
 
638
          
 
639
      gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
 
640
      gtk_text_buffer_apply_tag_by_name (buffer, "centered", &iter2, &iter);
 
641
 
 
642
      gtk_text_buffer_move_mark (buffer, temp_mark, &iter);
 
643
      gtk_text_buffer_insert (buffer, &iter, "Word wrapped, Right-to-left Quote\n", -1);
 
644
      gtk_text_buffer_insert (buffer, &iter, "\331\210\331\202\330\257 \330\250\330\257\330\243 \330\253\331\204\330\247\330\253 \331\205\331\206 \330\243\331\203\330\253\330\261 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 \330\252\331\202\330\257\331\205\330\247 \331\201\331\212 \330\264\330\250\331\203\330\251 \330\247\331\203\330\263\331\212\331\210\331\206 \330\250\330\261\330\247\331\205\330\254\331\207\330\247 \331\203\331\205\331\206\330\270\331\205\330\247\330\252 \331\204\330\247 \330\252\330\263\330\271\331\211 \331\204\331\204\330\261\330\250\330\255\330\214 \330\253\331\205 \330\252\330\255\331\210\331\204\330\252 \331\201\331\212 \330\247\331\204\330\263\331\206\331\210\330\247\330\252 \330\247\331\204\330\256\331\205\330\263 \330\247\331\204\331\205\330\247\330\266\331\212\330\251 \330\245\331\204\331\211 \331\205\330\244\330\263\330\263\330\247\330\252 \331\205\330\247\331\204\331\212\330\251 \331\205\331\206\330\270\331\205\330\251\330\214 \331\210\330\250\330\247\330\252\330\252 \330\254\330\262\330\241\330\247 \331\205\331\206 \330\247\331\204\331\206\330\270\330\247\331\205 \330\247\331\204\331\205\330\247\331\204\331\212 \331\201\331\212 \330\250\331\204\330\257\330\247\331\206\331\207\330\247\330\214 \331\210\331\204\331\203\331\206\331\207\330\247 \330\252\330\252\330\256\330\265\330\265 \331\201\331\212 \330\256\330\257\331\205\330\251 \331\202\330\267\330\247\330\271 \330\247\331\204\331\205\330\264\330\261\331\210\330\271\330\247\330\252 \330\247\331\204\330\265\330\272\331\212\330\261\330\251. \331\210\330\243\330\255\330\257 \330\243\331\203\330\253\330\261 \331\207\330\260\331\207 \330\247\331\204\331\205\330\244\330\263\330\263\330\247\330\252 \331\206\330\254\330\247\330\255\330\247 \331\207\331\210 \302\273\330\250\330\247\331\206\331\203\331\210\330\263\331\210\331\204\302\253 \331\201\331\212 \330\250\331\210\331\204\331\212\331\201\331\212\330\247.\n", -1);
 
645
      gtk_text_buffer_get_iter_at_mark (buffer, &iter2, temp_mark);
 
646
      gtk_text_buffer_apply_tag_by_name (buffer, "rtl_quote", &iter2, &iter);
 
647
 
 
648
      gtk_text_buffer_insert_with_tags (buffer, &iter,
 
649
                                        "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
 
650
                                        -1,
 
651
                                        gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer),
 
652
                                                                   "negative_indent"),
 
653
                                        NULL);
 
654
      
 
655
      ++i;
 
656
    }
 
657
 
 
658
  g_object_unref (pixbuf);
 
659
  
 
660
  printf ("%d lines %d chars\n",
 
661
          gtk_text_buffer_get_line_count (buffer),
 
662
          gtk_text_buffer_get_char_count (buffer));
 
663
 
 
664
  /* Move cursor to start */
 
665
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
 
666
  gtk_text_buffer_place_cursor (buffer, &iter);
 
667
  
 
668
  gtk_text_buffer_set_modified (buffer, FALSE);
 
669
}
 
670
 
 
671
gboolean
 
672
fill_file_buffer (GtkTextBuffer *buffer, const char *filename)
 
673
{
 
674
  FILE* f;
 
675
  gchar buf[2048];
 
676
  gint remaining = 0;
 
677
  GtkTextIter iter, end;
 
678
 
 
679
  f = fopen (filename, "r");
 
680
  
 
681
  if (f == NULL)
 
682
    {
 
683
      gchar *err = g_strdup_printf ("Cannot open file '%s': %s",
 
684
                                    filename, g_strerror (errno));
 
685
      msgbox_run (NULL, err, "OK", NULL, NULL, 0);
 
686
      g_free (err);
 
687
      return FALSE;
 
688
    }
 
689
  
 
690
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
 
691
  while (!feof (f))
 
692
    {
 
693
      gint count;
 
694
      const char *leftover;
 
695
      int to_read = 2047  - remaining;
 
696
 
 
697
      count = fread (buf + remaining, 1, to_read, f);
 
698
      buf[count + remaining] = '\0';
 
699
 
 
700
      g_utf8_validate (buf, count + remaining, &leftover);
 
701
      
 
702
      g_assert (g_utf8_validate (buf, leftover - buf, NULL));
 
703
      gtk_text_buffer_insert (buffer, &iter, buf, leftover - buf);
 
704
 
 
705
      remaining = (buf + remaining + count) - leftover;
 
706
      g_memmove (buf, leftover, remaining);
 
707
 
 
708
      if (remaining > 6 || count < to_read)
 
709
          break;
 
710
    }
 
711
 
 
712
  if (remaining)
 
713
    {
 
714
      gchar *err = g_strdup_printf ("Invalid UTF-8 data encountered reading file '%s'", filename);
 
715
      msgbox_run (NULL, err, "OK", NULL, NULL, 0);
 
716
      g_free (err);
 
717
    }
 
718
  
 
719
  /* We had a newline in the buffer to begin with. (The buffer always contains
 
720
   * a newline, so we delete to the end of the buffer to clean up.
 
721
   */
 
722
  gtk_text_buffer_get_end_iter (buffer, &end);
 
723
  gtk_text_buffer_delete (buffer, &iter, &end);
 
724
  
 
725
  gtk_text_buffer_set_modified (buffer, FALSE);
 
726
 
 
727
  return TRUE;
 
728
}
 
729
 
 
730
static gint
 
731
delete_event_cb (GtkWidget *window, GdkEventAny *event, gpointer data)
 
732
{
 
733
  View *view = view_from_widget (window);
 
734
 
 
735
  push_active_window (GTK_WINDOW (window));
 
736
  check_close_view (view);
 
737
  pop_active_window ();
 
738
 
 
739
  return TRUE;
 
740
}
 
741
 
 
742
/*
 
743
 * Menu callbacks
 
744
 */
 
745
 
 
746
static View *
 
747
get_empty_view (View *view)
 
748
{
 
749
  if (!view->buffer->filename &&
 
750
      !gtk_text_buffer_get_modified (view->buffer->buffer))
 
751
    return view;
 
752
  else
 
753
    return create_view (create_buffer ());
 
754
}
 
755
 
 
756
static View *
 
757
view_from_widget (GtkWidget *widget)
 
758
{
 
759
  if (GTK_IS_MENU_ITEM (widget))
 
760
    {
 
761
      GtkItemFactory *item_factory = gtk_item_factory_from_widget (widget);
 
762
      return g_object_get_data (G_OBJECT (item_factory), "view");      
 
763
    }
 
764
  else
 
765
    {
 
766
      GtkWidget *app = gtk_widget_get_toplevel (widget);
 
767
      return g_object_get_data (G_OBJECT (app), "view");
 
768
    }
 
769
}
 
770
 
 
771
static void
 
772
do_new (gpointer             callback_data,
 
773
        guint                callback_action,
 
774
        GtkWidget           *widget)
 
775
{
 
776
  create_view (create_buffer ());
 
777
}
 
778
 
 
779
static void
 
780
do_new_view (gpointer             callback_data,
 
781
             guint                callback_action,
 
782
             GtkWidget           *widget)
 
783
{
 
784
  View *view = view_from_widget (widget);
 
785
  
 
786
  create_view (view->buffer);
 
787
}
 
788
 
 
789
gboolean
 
790
open_ok_func (const char *filename, gpointer data)
 
791
{
 
792
  View *view = data;
 
793
  View *new_view = get_empty_view (view);
 
794
 
 
795
  if (!fill_file_buffer (new_view->buffer->buffer, filename))
 
796
    {
 
797
      if (new_view != view)
 
798
        close_view (new_view);
 
799
      return FALSE;
 
800
    }
 
801
  else
 
802
    {
 
803
      g_free (new_view->buffer->filename);
 
804
      new_view->buffer->filename = g_strdup (filename);
 
805
      buffer_filename_set (new_view->buffer);
 
806
      
 
807
      return TRUE;
 
808
    }
 
809
}
 
810
 
 
811
static void
 
812
do_open (gpointer             callback_data,
 
813
         guint                callback_action,
 
814
         GtkWidget           *widget)
 
815
{
 
816
  View *view = view_from_widget (widget);
 
817
 
 
818
  push_active_window (GTK_WINDOW (view->window));
 
819
  filesel_run (NULL, "Open File", NULL, open_ok_func, view);
 
820
  pop_active_window ();
 
821
}
 
822
 
 
823
static void
 
824
do_save_as (gpointer             callback_data,
 
825
            guint                callback_action,
 
826
            GtkWidget           *widget)
 
827
{
 
828
  View *view = view_from_widget (widget);  
 
829
 
 
830
  push_active_window (GTK_WINDOW (view->window));
 
831
  save_as_buffer (view->buffer);
 
832
  pop_active_window ();
 
833
}
 
834
 
 
835
static void
 
836
do_save (gpointer             callback_data,
 
837
         guint                callback_action,
 
838
         GtkWidget           *widget)
 
839
{
 
840
  View *view = view_from_widget (widget);
 
841
 
 
842
  push_active_window (GTK_WINDOW (view->window));
 
843
  if (!view->buffer->filename)
 
844
    do_save_as (callback_data, callback_action, widget);
 
845
  else
 
846
    save_buffer (view->buffer);
 
847
  pop_active_window ();
 
848
}
 
849
 
 
850
static void
 
851
do_close   (gpointer             callback_data,
 
852
            guint                callback_action,
 
853
            GtkWidget           *widget)
 
854
{
 
855
  View *view = view_from_widget (widget);
 
856
 
 
857
  push_active_window (GTK_WINDOW (view->window));
 
858
  check_close_view (view);
 
859
  pop_active_window ();
 
860
}
 
861
 
 
862
static void
 
863
do_exit    (gpointer             callback_data,
 
864
            guint                callback_action,
 
865
            GtkWidget           *widget)
 
866
{
 
867
  View *view = view_from_widget (widget);
 
868
 
 
869
  GSList *tmp_list = buffers;
 
870
 
 
871
  push_active_window (GTK_WINDOW (view->window));
 
872
  while (tmp_list)
 
873
    {
 
874
      if (!check_buffer_saved (tmp_list->data))
 
875
        return;
 
876
 
 
877
      tmp_list = tmp_list->next;
 
878
    }
 
879
 
 
880
  gtk_main_quit ();
 
881
  pop_active_window ();
 
882
}
 
883
 
 
884
static void
 
885
do_example (gpointer             callback_data,
 
886
            guint                callback_action,
 
887
            GtkWidget           *widget)
 
888
{
 
889
  View *view = view_from_widget (widget);
 
890
  View *new_view;
 
891
 
 
892
  new_view = get_empty_view (view);
 
893
  
 
894
  fill_example_buffer (new_view->buffer->buffer);
 
895
 
 
896
  view_add_example_widgets (new_view);
 
897
}
 
898
 
 
899
 
 
900
static void
 
901
do_insert_and_scroll (gpointer             callback_data,
 
902
                      guint                callback_action,
 
903
                      GtkWidget           *widget)
 
904
{
 
905
  View *view = view_from_widget (widget);
 
906
  GtkTextBuffer *buffer;
 
907
  GtkTextIter start, end;
 
908
  GtkTextMark *mark;
 
909
  
 
910
  buffer = view->buffer->buffer;
 
911
 
 
912
  gtk_text_buffer_get_bounds (buffer, &start, &end);
 
913
  mark = gtk_text_buffer_create_mark (buffer, NULL, &end, /* right grav */ FALSE);
 
914
 
 
915
  gtk_text_buffer_insert (buffer, &end,
 
916
                          "Hello this is multiple lines of text\n"
 
917
                          "Line 1\n"  "Line 2\n"
 
918
                          "Line 3\n"  "Line 4\n"
 
919
                          "Line 5\n",
 
920
                          -1);
 
921
 
 
922
  gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view->text_view), mark,
 
923
                                0, TRUE, 0.0, 1.0);
 
924
  gtk_text_buffer_delete_mark (buffer, mark);
 
925
}
 
926
 
 
927
static void
 
928
do_wrap_changed (gpointer             callback_data,
 
929
                 guint                callback_action,
 
930
                 GtkWidget           *widget)
 
931
{
 
932
  View *view = view_from_widget (widget);
 
933
 
 
934
  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view), callback_action);
 
935
}
 
936
 
 
937
static void
 
938
do_direction_changed (gpointer             callback_data,
 
939
                      guint                callback_action,
 
940
                      GtkWidget           *widget)
 
941
{
 
942
  View *view = view_from_widget (widget);
 
943
  
 
944
  gtk_widget_set_direction (view->text_view, callback_action);
 
945
  gtk_widget_queue_resize (view->text_view);
 
946
}
 
947
 
 
948
 
 
949
static void
 
950
do_spacing_changed (gpointer             callback_data,
 
951
                    guint                callback_action,
 
952
                    GtkWidget           *widget)
 
953
{
 
954
  View *view = view_from_widget (widget);
 
955
 
 
956
  if (callback_action)
 
957
    {
 
958
      gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
 
959
                                            23);
 
960
      gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
 
961
                                            21);
 
962
      gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
 
963
                                            9);
 
964
    }
 
965
  else
 
966
    {
 
967
      gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (view->text_view),
 
968
                                            0);
 
969
      gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (view->text_view),
 
970
                                            0);
 
971
      gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (view->text_view),
 
972
                                            0);
 
973
    }
 
974
}
 
975
 
 
976
static void
 
977
do_editable_changed (gpointer callback_data,
 
978
                     guint callback_action,
 
979
                     GtkWidget *widget)
 
980
{
 
981
  View *view = view_from_widget (widget);
 
982
 
 
983
  gtk_text_view_set_editable (GTK_TEXT_VIEW (view->text_view), callback_action);
 
984
}
 
985
 
 
986
static void
 
987
do_cursor_visible_changed (gpointer callback_data,
 
988
                           guint callback_action,
 
989
                           GtkWidget *widget)
 
990
{
 
991
  View *view = view_from_widget (widget);
 
992
 
 
993
  gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view->text_view), callback_action);
 
994
}
 
995
 
 
996
static void
 
997
do_color_cycle_changed (gpointer callback_data,
 
998
                        guint callback_action,
 
999
                        GtkWidget *widget)
 
1000
{
 
1001
  View *view = view_from_widget (widget);
 
1002
 
 
1003
  buffer_set_colors (view->buffer, callback_action);
 
1004
}
 
1005
 
 
1006
static void
 
1007
do_apply_editable (gpointer callback_data,
 
1008
                   guint callback_action,
 
1009
                   GtkWidget *widget)
 
1010
{
 
1011
  View *view = view_from_widget (widget);
 
1012
  GtkTextIter start;
 
1013
  GtkTextIter end;
 
1014
  
 
1015
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1016
                                            &start, &end))
 
1017
    {
 
1018
      if (callback_action)
 
1019
        {
 
1020
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1021
                                      view->buffer->not_editable_tag,
 
1022
                                      &start, &end);
 
1023
        }
 
1024
      else
 
1025
        {
 
1026
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1027
                                     view->buffer->not_editable_tag,
 
1028
                                     &start, &end);
 
1029
        }
 
1030
    }
 
1031
}
 
1032
 
 
1033
static void
 
1034
do_apply_invisible (gpointer callback_data,
 
1035
                    guint callback_action,
 
1036
                    GtkWidget *widget)
 
1037
{
 
1038
  View *view = view_from_widget (widget);
 
1039
  GtkTextIter start;
 
1040
  GtkTextIter end;
 
1041
  
 
1042
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1043
                                            &start, &end))
 
1044
    {
 
1045
      if (callback_action)
 
1046
        {
 
1047
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1048
                                      view->buffer->invisible_tag,
 
1049
                                      &start, &end);
 
1050
        }
 
1051
      else
 
1052
        {
 
1053
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1054
                                     view->buffer->invisible_tag,
 
1055
                                     &start, &end);
 
1056
        }
 
1057
    }
 
1058
}
 
1059
 
 
1060
static void
 
1061
do_apply_rise (gpointer callback_data,
 
1062
               guint callback_action,
 
1063
               GtkWidget *widget)
 
1064
{
 
1065
  View *view = view_from_widget (widget);
 
1066
  GtkTextIter start;
 
1067
  GtkTextIter end;
 
1068
  
 
1069
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1070
                                            &start, &end))
 
1071
    {
 
1072
      if (callback_action)
 
1073
        {
 
1074
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1075
                                      view->buffer->rise_tag,
 
1076
                                      &start, &end);
 
1077
        }
 
1078
      else
 
1079
        {
 
1080
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1081
                                     view->buffer->rise_tag,
 
1082
                                     &start, &end);
 
1083
        }
 
1084
    }
 
1085
}
 
1086
 
 
1087
static void
 
1088
do_apply_large (gpointer callback_data,
 
1089
                guint callback_action,
 
1090
                GtkWidget *widget)
 
1091
{
 
1092
  View *view = view_from_widget (widget);
 
1093
  GtkTextIter start;
 
1094
  GtkTextIter end;
 
1095
  
 
1096
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1097
                                            &start, &end))
 
1098
    {
 
1099
      if (callback_action)
 
1100
        {
 
1101
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1102
                                      view->buffer->large_tag,
 
1103
                                      &start, &end);
 
1104
        }
 
1105
      else
 
1106
        {
 
1107
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1108
                                     view->buffer->large_tag,
 
1109
                                     &start, &end);
 
1110
        }
 
1111
    }
 
1112
}
 
1113
 
 
1114
static void
 
1115
do_apply_indent (gpointer callback_data,
 
1116
                 guint callback_action,
 
1117
                 GtkWidget *widget)
 
1118
{
 
1119
  View *view = view_from_widget (widget);
 
1120
  GtkTextIter start;
 
1121
  GtkTextIter end;
 
1122
  
 
1123
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1124
                                            &start, &end))
 
1125
    {
 
1126
      if (callback_action)
 
1127
        {
 
1128
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1129
                                      view->buffer->indent_tag,
 
1130
                                      &start, &end);
 
1131
        }
 
1132
      else
 
1133
        {
 
1134
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1135
                                     view->buffer->indent_tag,
 
1136
                                     &start, &end);
 
1137
        }
 
1138
    }
 
1139
}
 
1140
 
 
1141
static void
 
1142
do_apply_margin (gpointer callback_data,
 
1143
                 guint callback_action,
 
1144
                 GtkWidget *widget)
 
1145
{
 
1146
  View *view = view_from_widget (widget);
 
1147
  GtkTextIter start;
 
1148
  GtkTextIter end;
 
1149
  
 
1150
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1151
                                            &start, &end))
 
1152
    {
 
1153
      if (callback_action)
 
1154
        {
 
1155
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1156
                                      view->buffer->margin_tag,
 
1157
                                      &start, &end);
 
1158
        }
 
1159
      else
 
1160
        {
 
1161
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1162
                                     view->buffer->margin_tag,
 
1163
                                     &start, &end);
 
1164
        }
 
1165
    }
 
1166
}
 
1167
 
 
1168
static void
 
1169
do_apply_tabs (gpointer callback_data,
 
1170
               guint callback_action,
 
1171
               GtkWidget *widget)
 
1172
{
 
1173
  View *view = view_from_widget (widget);
 
1174
  GtkTextIter start;
 
1175
  GtkTextIter end;
 
1176
  
 
1177
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1178
                                            &start, &end))
 
1179
    {
 
1180
      if (callback_action)
 
1181
        {
 
1182
          gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1183
                                      view->buffer->custom_tabs_tag,
 
1184
                                      &start, &end);
 
1185
        }
 
1186
      else
 
1187
        {
 
1188
          gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1189
                                     view->buffer->custom_tabs_tag,
 
1190
                                     &start, &end);
 
1191
        }
 
1192
    }
 
1193
}
 
1194
 
 
1195
static void
 
1196
do_apply_colors (gpointer callback_data,
 
1197
                 guint callback_action,
 
1198
                 GtkWidget *widget)
 
1199
{
 
1200
  View *view = view_from_widget (widget);
 
1201
  Buffer *buffer = view->buffer;
 
1202
  GtkTextIter start;
 
1203
  GtkTextIter end;
 
1204
  
 
1205
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1206
                                            &start, &end))
 
1207
    {
 
1208
      if (!callback_action)
 
1209
        {
 
1210
          GSList *tmp;
 
1211
          
 
1212
          tmp = buffer->color_tags;
 
1213
          while (tmp != NULL)
 
1214
            {
 
1215
              gtk_text_buffer_remove_tag (view->buffer->buffer,
 
1216
                                          tmp->data,
 
1217
                                          &start, &end);              
 
1218
              tmp = g_slist_next (tmp);
 
1219
            }
 
1220
        }
 
1221
      else
 
1222
        {
 
1223
          GSList *tmp;
 
1224
          
 
1225
          tmp = buffer->color_tags;
 
1226
          while (TRUE)
 
1227
            {
 
1228
              GtkTextIter next;
 
1229
              gboolean done = FALSE;
 
1230
              
 
1231
              next = start;
 
1232
              gtk_text_iter_forward_char (&next);
 
1233
              gtk_text_iter_forward_char (&next);
 
1234
 
 
1235
              if (gtk_text_iter_compare (&next, &end) >= 0)
 
1236
                {
 
1237
                  next = end;
 
1238
                  done = TRUE;
 
1239
                }
 
1240
              
 
1241
              gtk_text_buffer_apply_tag (view->buffer->buffer,
 
1242
                                         tmp->data,
 
1243
                                         &start, &next);
 
1244
 
 
1245
              start = next;
 
1246
 
 
1247
              if (done)
 
1248
                return;
 
1249
              
 
1250
              tmp = g_slist_next (tmp);
 
1251
              if (tmp == NULL)
 
1252
                tmp = buffer->color_tags;
 
1253
            } 
 
1254
        }
 
1255
    }
 
1256
}
 
1257
 
 
1258
static void
 
1259
do_remove_tags (gpointer callback_data,
 
1260
                guint callback_action,
 
1261
                GtkWidget *widget)
 
1262
{
 
1263
  View *view = view_from_widget (widget);
 
1264
  GtkTextIter start;
 
1265
  GtkTextIter end;
 
1266
  
 
1267
  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
 
1268
                                            &start, &end))
 
1269
    {
 
1270
      gtk_text_buffer_remove_all_tags (view->buffer->buffer,
 
1271
                                       &start, &end);
 
1272
    }
 
1273
}
 
1274
 
 
1275
static void
 
1276
do_properties (gpointer callback_data,
 
1277
                guint callback_action,
 
1278
                GtkWidget *widget)
 
1279
{
 
1280
  View *view = view_from_widget (widget);
 
1281
 
 
1282
  create_prop_editor (G_OBJECT (view->text_view), 0);
 
1283
}
 
1284
 
 
1285
static void
 
1286
rich_text_store_populate (GtkListStore  *store,
 
1287
                          GtkTextBuffer *buffer,
 
1288
                          gboolean       deserialize)
 
1289
{
 
1290
  GdkAtom *formats;
 
1291
  gint     n_formats;
 
1292
  gint     i;
 
1293
 
 
1294
  gtk_list_store_clear (store);
 
1295
 
 
1296
  if (deserialize)
 
1297
    formats = gtk_text_buffer_get_deserialize_formats (buffer, &n_formats);
 
1298
  else
 
1299
    formats = gtk_text_buffer_get_serialize_formats (buffer, &n_formats);
 
1300
 
 
1301
  for (i = 0; i < n_formats; i++)
 
1302
    {
 
1303
      GtkTreeIter  iter;
 
1304
      gchar       *mime_type;
 
1305
      gboolean     can_create_tags = FALSE;
 
1306
 
 
1307
      mime_type = gdk_atom_name (formats[i]);
 
1308
 
 
1309
      if (deserialize)
 
1310
        can_create_tags =
 
1311
          gtk_text_buffer_deserialize_get_can_create_tags (buffer, formats[i]);
 
1312
 
 
1313
      gtk_list_store_append (store, &iter);
 
1314
      gtk_list_store_set (store, &iter,
 
1315
                          0, formats[i],
 
1316
                          1, mime_type,
 
1317
                          2, can_create_tags,
 
1318
                          -1);
 
1319
 
 
1320
      g_free (mime_type);
 
1321
    }
 
1322
 
 
1323
  g_free (formats);
 
1324
}
 
1325
 
 
1326
static void
 
1327
rich_text_paste_target_list_notify (GtkTextBuffer    *buffer,
 
1328
                                    const GParamSpec *pspec,
 
1329
                                    GtkListStore     *store)
 
1330
{
 
1331
  rich_text_store_populate (store, buffer, TRUE);
 
1332
}
 
1333
 
 
1334
static void
 
1335
rich_text_copy_target_list_notify (GtkTextBuffer    *buffer,
 
1336
                                   const GParamSpec *pspec,
 
1337
                                   GtkListStore     *store)
 
1338
{
 
1339
  rich_text_store_populate (store, buffer, FALSE);
 
1340
}
 
1341
 
 
1342
static void
 
1343
rich_text_can_create_tags_toggled (GtkCellRendererToggle *toggle,
 
1344
                                   const gchar           *path,
 
1345
                                   GtkTreeModel          *model)
 
1346
{
 
1347
  GtkTreeIter iter;
 
1348
 
 
1349
  if (gtk_tree_model_get_iter_from_string (model, &iter, path))
 
1350
    {
 
1351
      GtkTextBuffer *buffer;
 
1352
      GdkAtom        format;
 
1353
      gboolean       can_create_tags;
 
1354
 
 
1355
      buffer = g_object_get_data (G_OBJECT (model), "buffer");
 
1356
 
 
1357
      gtk_tree_model_get (model, &iter,
 
1358
                          0, &format,
 
1359
                          2, &can_create_tags,
 
1360
                          -1);
 
1361
 
 
1362
      gtk_text_buffer_deserialize_set_can_create_tags (buffer, format,
 
1363
                                                       !can_create_tags);
 
1364
 
 
1365
      gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
1366
                          2, !can_create_tags,
 
1367
                          -1);
 
1368
    }
 
1369
}
 
1370
 
 
1371
static void
 
1372
rich_text_unregister_clicked (GtkWidget   *button,
 
1373
                              GtkTreeView *tv)
 
1374
{
 
1375
  GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
 
1376
  GtkTreeModel     *model;
 
1377
  GtkTreeIter       iter;
 
1378
 
 
1379
  if (gtk_tree_selection_get_selected (sel, &model, &iter))
 
1380
    {
 
1381
      GtkTextBuffer *buffer;
 
1382
      gboolean       deserialize;
 
1383
      GdkAtom        format;
 
1384
 
 
1385
      buffer = g_object_get_data (G_OBJECT (model), "buffer");
 
1386
      deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
 
1387
                                                        "deserialize"));
 
1388
 
 
1389
      gtk_tree_model_get (model, &iter,
 
1390
                          0, &format,
 
1391
                          -1);
 
1392
 
 
1393
      if (deserialize)
 
1394
        gtk_text_buffer_unregister_deserialize_format (buffer, format);
 
1395
      else
 
1396
        gtk_text_buffer_unregister_serialize_format (buffer, format);
 
1397
    }
 
1398
}
 
1399
 
 
1400
static void
 
1401
rich_text_register_clicked (GtkWidget   *button,
 
1402
                            GtkTreeView *tv)
 
1403
{
 
1404
  GtkWidget *dialog;
 
1405
  GtkWidget *label;
 
1406
  GtkWidget *entry;
 
1407
 
 
1408
  dialog = gtk_dialog_new_with_buttons ("Register new Tagset",
 
1409
                                        GTK_WINDOW (gtk_widget_get_toplevel (button)),
 
1410
                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 
1411
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
1412
                                        GTK_STOCK_OK,     GTK_RESPONSE_OK,
 
1413
                                        NULL);
 
1414
  label = gtk_label_new ("Enter tagset name or leave blank for "
 
1415
                         "unrestricted internal format:");
 
1416
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label,
 
1417
                      FALSE, FALSE, 0);
 
1418
 
 
1419
  entry = gtk_entry_new ();
 
1420
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), entry,
 
1421
                      FALSE, FALSE, 0);
 
1422
 
 
1423
  gtk_widget_show_all (dialog);
 
1424
 
 
1425
  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
 
1426
    {
 
1427
      GtkTreeModel  *model  = gtk_tree_view_get_model (tv);
 
1428
      GtkTextBuffer *buffer = g_object_get_data (G_OBJECT (model), "buffer");
 
1429
      const gchar   *tagset = gtk_entry_get_text (GTK_ENTRY (entry));
 
1430
      gboolean       deserialize;
 
1431
 
 
1432
      deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
 
1433
                                                        "deserialize"));
 
1434
 
 
1435
      if (tagset && ! strlen (tagset))
 
1436
        tagset = NULL;
 
1437
 
 
1438
      if (deserialize)
 
1439
        gtk_text_buffer_register_deserialize_tagset (buffer, tagset);
 
1440
      else
 
1441
        gtk_text_buffer_register_serialize_tagset (buffer, tagset);
 
1442
    }
 
1443
 
 
1444
  gtk_widget_destroy (dialog);
 
1445
}
 
1446
 
 
1447
static void
 
1448
do_rich_text (gpointer callback_data,
 
1449
              guint deserialize,
 
1450
              GtkWidget *widget)
 
1451
{
 
1452
  View *view = view_from_widget (widget);
 
1453
  GtkTextBuffer *buffer;
 
1454
  GtkWidget *dialog;
 
1455
  GtkWidget *tv;
 
1456
  GtkWidget *sw;
 
1457
  GtkWidget *hbox;
 
1458
  GtkWidget *button;
 
1459
  GtkListStore *store;
 
1460
 
 
1461
  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->text_view));
 
1462
 
 
1463
  dialog = gtk_dialog_new_with_buttons (deserialize ?
 
1464
                                        "Rich Text Paste & Drop" :
 
1465
                                        "Rich Text Copy & Drag",
 
1466
                                        GTK_WINDOW (view->window),
 
1467
                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 
1468
                                        GTK_STOCK_CLOSE, 0,
 
1469
                                        NULL);
 
1470
  g_signal_connect (dialog, "response",
 
1471
                    G_CALLBACK (gtk_widget_destroy),
 
1472
                    NULL);
 
1473
 
 
1474
  store = gtk_list_store_new (3,
 
1475
                              G_TYPE_POINTER,
 
1476
                              G_TYPE_STRING,
 
1477
                              G_TYPE_BOOLEAN);
 
1478
 
 
1479
  g_object_set_data (G_OBJECT (store), "buffer", buffer);
 
1480
  g_object_set_data (G_OBJECT (store), "deserialize",
 
1481
                     GUINT_TO_POINTER (deserialize));
 
1482
 
 
1483
  tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
 
1484
  g_object_unref (store);
 
1485
 
 
1486
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
 
1487
                                               0, "Rich Text Format",
 
1488
                                               gtk_cell_renderer_text_new (),
 
1489
                                               "text", 1,
 
1490
                                               NULL);
 
1491
 
 
1492
  if (deserialize)
 
1493
    {
 
1494
      GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new ();
 
1495
 
 
1496
      gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
 
1497
                                                   1, "Can Create Tags",
 
1498
                                                   renderer,
 
1499
                                                   "active", 2,
 
1500
                                                   NULL);
 
1501
 
 
1502
      g_signal_connect (renderer, "toggled",
 
1503
                        G_CALLBACK (rich_text_can_create_tags_toggled),
 
1504
                        store);
 
1505
    }
 
1506
 
 
1507
  sw = gtk_scrolled_window_new (NULL, NULL);
 
1508
  gtk_widget_set_size_request (sw, 300, 100);
 
1509
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), sw);
 
1510
 
 
1511
  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), tv);
 
1512
 
 
1513
  hbox = gtk_hbox_new (FALSE, 6);
 
1514
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
 
1515
                      FALSE, FALSE, 0);
 
1516
 
 
1517
  button = gtk_button_new_with_label ("Unregister Selected Format");
 
1518
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
 
1519
 
 
1520
  g_signal_connect (button, "clicked",
 
1521
                    G_CALLBACK (rich_text_unregister_clicked),
 
1522
                    tv);
 
1523
 
 
1524
  button = gtk_button_new_with_label ("Register New Tagset\n"
 
1525
                                      "for the Internal Format");
 
1526
  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
 
1527
 
 
1528
  g_signal_connect (button, "clicked",
 
1529
                    G_CALLBACK (rich_text_register_clicked),
 
1530
                    tv);
 
1531
 
 
1532
  if (deserialize)
 
1533
    g_signal_connect_object (buffer, "notify::paste-target-list",
 
1534
                             G_CALLBACK (rich_text_paste_target_list_notify),
 
1535
                             G_OBJECT (store), 0);
 
1536
  else
 
1537
    g_signal_connect_object (buffer, "notify::copy-target-list",
 
1538
                             G_CALLBACK (rich_text_copy_target_list_notify),
 
1539
                             G_OBJECT (store), 0);
 
1540
 
 
1541
  rich_text_store_populate (store, buffer, deserialize);
 
1542
 
 
1543
  gtk_widget_show_all (dialog);
 
1544
}
 
1545
 
 
1546
enum
 
1547
{
 
1548
  RESPONSE_FORWARD,
 
1549
  RESPONSE_BACKWARD
 
1550
};
 
1551
 
 
1552
static void
 
1553
dialog_response_callback (GtkWidget *dialog, gint response_id, gpointer data)
 
1554
{
 
1555
  GtkTextBuffer *buffer;
 
1556
  View *view = data;
 
1557
  GtkTextIter start, end;
 
1558
  gchar *search_string;
 
1559
 
 
1560
  if (response_id != RESPONSE_FORWARD &&
 
1561
      response_id != RESPONSE_BACKWARD)
 
1562
    {
 
1563
      gtk_widget_destroy (dialog);
 
1564
      return;
 
1565
    }
 
1566
  
 
1567
  buffer = g_object_get_data (G_OBJECT (dialog), "buffer");
 
1568
 
 
1569
  gtk_text_buffer_get_bounds (buffer, &start, &end);
 
1570
  
 
1571
  search_string = gtk_text_iter_get_text (&start, &end);
 
1572
 
 
1573
  g_print ("Searching for `%s'\n", search_string);
 
1574
 
 
1575
  if (response_id == RESPONSE_FORWARD)
 
1576
    buffer_search_forward (view->buffer, search_string, view);
 
1577
  else if (response_id == RESPONSE_BACKWARD)
 
1578
    buffer_search_backward (view->buffer, search_string, view);
 
1579
    
 
1580
  g_free (search_string);
 
1581
  
 
1582
  gtk_widget_destroy (dialog);
 
1583
}
 
1584
 
 
1585
static void
 
1586
do_copy  (gpointer callback_data,
 
1587
          guint callback_action,
 
1588
          GtkWidget *widget)
 
1589
{
 
1590
  View *view = view_from_widget (widget);
 
1591
  GtkTextBuffer *buffer;
 
1592
 
 
1593
  buffer = view->buffer->buffer;
 
1594
 
 
1595
  gtk_text_buffer_copy_clipboard (buffer,
 
1596
                                  gtk_clipboard_get (GDK_NONE));
 
1597
}
 
1598
 
 
1599
static void
 
1600
do_search (gpointer callback_data,
 
1601
           guint callback_action,
 
1602
           GtkWidget *widget)
 
1603
{
 
1604
  View *view = view_from_widget (widget);
 
1605
  GtkWidget *dialog;
 
1606
  GtkWidget *search_text;
 
1607
  GtkTextBuffer *buffer;
 
1608
 
 
1609
  dialog = gtk_dialog_new_with_buttons ("Search",
 
1610
                                        GTK_WINDOW (view->window),
 
1611
                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 
1612
                                        "Forward", RESPONSE_FORWARD,
 
1613
                                        "Backward", RESPONSE_BACKWARD,
 
1614
                                        GTK_STOCK_CANCEL,
 
1615
                                        GTK_RESPONSE_NONE, NULL);
 
1616
 
 
1617
 
 
1618
  buffer = gtk_text_buffer_new (NULL);
 
1619
 
 
1620
  search_text = gtk_text_view_new_with_buffer (buffer);
 
1621
 
 
1622
  g_object_unref (buffer);
 
1623
  
 
1624
  gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox),
 
1625
                    search_text,
 
1626
                    TRUE, TRUE, 0);
 
1627
 
 
1628
  g_object_set_data (G_OBJECT (dialog), "buffer", buffer);
 
1629
  
 
1630
  g_signal_connect (dialog,
 
1631
                    "response",
 
1632
                    G_CALLBACK (dialog_response_callback),
 
1633
                    view);
 
1634
 
 
1635
  gtk_widget_show (search_text);
 
1636
 
 
1637
  gtk_widget_grab_focus (search_text);
 
1638
  
 
1639
  gtk_widget_show_all (dialog);
 
1640
}
 
1641
 
 
1642
static void
 
1643
do_select_all (gpointer callback_data,
 
1644
               guint callback_action,
 
1645
               GtkWidget *widget)
 
1646
{
 
1647
  View *view = view_from_widget (widget);
 
1648
  GtkTextBuffer *buffer;
 
1649
  GtkTextIter start, end;
 
1650
 
 
1651
  buffer = view->buffer->buffer;
 
1652
 
 
1653
  gtk_text_buffer_get_bounds (buffer, &start, &end);
 
1654
  gtk_text_buffer_select_range (buffer, &start, &end);
 
1655
}
 
1656
 
 
1657
typedef struct
 
1658
{
 
1659
  /* position is in coordinate system of text_view_move_child */
 
1660
  int click_x;
 
1661
  int click_y;
 
1662
  int start_x;
 
1663
  int start_y;
 
1664
  int button;
 
1665
} ChildMoveInfo;
 
1666
 
 
1667
static gboolean
 
1668
movable_child_callback (GtkWidget *child,
 
1669
                        GdkEvent  *event,
 
1670
                        gpointer   data)
 
1671
{
 
1672
  ChildMoveInfo *info;
 
1673
  GtkTextView *text_view;
 
1674
 
 
1675
  text_view = GTK_TEXT_VIEW (data);
 
1676
  
 
1677
  g_return_val_if_fail (GTK_IS_EVENT_BOX (child), FALSE);
 
1678
  g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (text_view), FALSE);  
 
1679
  
 
1680
  info = g_object_get_data (G_OBJECT (child),
 
1681
                            "testtext-move-info");
 
1682
 
 
1683
  if (info == NULL)
 
1684
    {
 
1685
      info = g_new (ChildMoveInfo, 1);      
 
1686
      info->start_x = -1;
 
1687
      info->start_y = -1;
 
1688
      info->button = -1;
 
1689
      g_object_set_data_full (G_OBJECT (child),
 
1690
                              "testtext-move-info",
 
1691
                              info,
 
1692
                              g_free);
 
1693
    }
 
1694
  
 
1695
  switch (event->type)
 
1696
    {
 
1697
    case GDK_BUTTON_PRESS:
 
1698
      if (info->button < 0)
 
1699
        {
 
1700
          if (gdk_pointer_grab (event->button.window,
 
1701
                                FALSE,
 
1702
                                GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
 
1703
                                GDK_BUTTON_RELEASE_MASK,
 
1704
                                NULL,
 
1705
                                NULL,
 
1706
                                event->button.time) != GDK_GRAB_SUCCESS)
 
1707
            return FALSE;
 
1708
          
 
1709
          info->button = event->button.button;
 
1710
          
 
1711
          info->start_x = child->allocation.x;
 
1712
          info->start_y = child->allocation.y;
 
1713
          info->click_x = child->allocation.x + event->button.x;
 
1714
          info->click_y = child->allocation.y + event->button.y;
 
1715
        }
 
1716
      break;
 
1717
 
 
1718
    case GDK_BUTTON_RELEASE:
 
1719
      if (info->button < 0)
 
1720
        return FALSE;
 
1721
 
 
1722
      if (info->button == event->button.button)
 
1723
        {
 
1724
          int x, y;
 
1725
          
 
1726
          gdk_pointer_ungrab (event->button.time);
 
1727
          info->button = -1;
 
1728
 
 
1729
          /* convert to window coords from event box coords */
 
1730
          x = info->start_x + (event->button.x + child->allocation.x - info->click_x);
 
1731
          y = info->start_y + (event->button.y + child->allocation.y - info->click_y);
 
1732
 
 
1733
          gtk_text_view_move_child (text_view,
 
1734
                                    child,
 
1735
                                    x, y);
 
1736
        }
 
1737
      break;
 
1738
 
 
1739
    case GDK_MOTION_NOTIFY:
 
1740
      {
 
1741
        int x, y;
 
1742
        
 
1743
        if (info->button < 0)
 
1744
          return FALSE;
 
1745
        
 
1746
        gdk_window_get_pointer (child->window, &x, &y, NULL); /* ensure more events */
 
1747
 
 
1748
        /* to window coords from event box coords */
 
1749
        x += child->allocation.x;
 
1750
        y += child->allocation.y;
 
1751
        
 
1752
        x = info->start_x + (x - info->click_x);
 
1753
        y = info->start_y + (y - info->click_y);
 
1754
        
 
1755
        gtk_text_view_move_child (text_view,
 
1756
                                  child,
 
1757
                                  x, y);
 
1758
      }
 
1759
      break;
 
1760
 
 
1761
    default:
 
1762
      break;
 
1763
    }
 
1764
 
 
1765
  return FALSE;
 
1766
}
 
1767
 
 
1768
static void
 
1769
add_movable_child (GtkTextView      *text_view,
 
1770
                   GtkTextWindowType window)
 
1771
{
 
1772
  GtkWidget *event_box;
 
1773
  GtkWidget *label;
 
1774
  GdkColor color;
 
1775
  
 
1776
  label = gtk_label_new ("Drag me around");  
 
1777
  
 
1778
  event_box = gtk_event_box_new ();
 
1779
  gtk_widget_add_events (event_box,
 
1780
                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
 
1781
                         GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
 
1782
 
 
1783
  color.red = 0xffff;
 
1784
  color.green = color.blue = 0;
 
1785
  gtk_widget_modify_bg (event_box, GTK_STATE_NORMAL, &color);
 
1786
  
 
1787
  gtk_container_add (GTK_CONTAINER (event_box), label);
 
1788
 
 
1789
  gtk_widget_show_all (event_box);
 
1790
 
 
1791
  g_signal_connect (event_box, "event",
 
1792
                    G_CALLBACK (movable_child_callback),
 
1793
                    text_view);
 
1794
 
 
1795
  gtk_text_view_add_child_in_window (text_view,
 
1796
                                     event_box,
 
1797
                                     window,
 
1798
                                     0, 0);
 
1799
}
 
1800
 
 
1801
static void
 
1802
do_add_children (gpointer callback_data,
 
1803
                 guint callback_action,
 
1804
                 GtkWidget *widget)
 
1805
{
 
1806
  View *view = view_from_widget (widget);
 
1807
 
 
1808
  add_movable_child (GTK_TEXT_VIEW (view->text_view),
 
1809
                     GTK_TEXT_WINDOW_WIDGET);
 
1810
  add_movable_child (GTK_TEXT_VIEW (view->text_view),
 
1811
                     GTK_TEXT_WINDOW_LEFT);
 
1812
  add_movable_child (GTK_TEXT_VIEW (view->text_view),
 
1813
                     GTK_TEXT_WINDOW_RIGHT);
 
1814
}
 
1815
 
 
1816
static void
 
1817
do_add_focus_children (gpointer callback_data,
 
1818
                       guint callback_action,
 
1819
                       GtkWidget *widget)
 
1820
{
 
1821
  View *view = view_from_widget (widget);
 
1822
  GtkWidget *child;
 
1823
  GtkTextChildAnchor *anchor;
 
1824
  GtkTextIter iter;
 
1825
  GtkTextView *text_view;
 
1826
 
 
1827
  text_view = GTK_TEXT_VIEW (view->text_view);
 
1828
  
 
1829
  child = gtk_button_new_with_mnemonic ("Button _A in widget->window");
 
1830
 
 
1831
  gtk_text_view_add_child_in_window (text_view,
 
1832
                                     child,
 
1833
                                     GTK_TEXT_WINDOW_WIDGET,
 
1834
                                     200, 200);
 
1835
 
 
1836
  child = gtk_button_new_with_mnemonic ("Button _B in widget->window");
 
1837
 
 
1838
  gtk_text_view_add_child_in_window (text_view,
 
1839
                                     child,
 
1840
                                     GTK_TEXT_WINDOW_WIDGET,
 
1841
                                     350, 300);
 
1842
 
 
1843
  child = gtk_button_new_with_mnemonic ("Button _C in left window");
 
1844
 
 
1845
  gtk_text_view_add_child_in_window (text_view,
 
1846
                                     child,
 
1847
                                     GTK_TEXT_WINDOW_LEFT,
 
1848
                                     0, 0);
 
1849
 
 
1850
  child = gtk_button_new_with_mnemonic ("Button _D in right window");
 
1851
  
 
1852
  gtk_text_view_add_child_in_window (text_view,
 
1853
                                     child,
 
1854
                                     GTK_TEXT_WINDOW_RIGHT,
 
1855
                                     0, 0);
 
1856
 
 
1857
  gtk_text_buffer_get_start_iter (view->buffer->buffer, &iter);
 
1858
  
 
1859
  anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
 
1860
 
 
1861
  child = gtk_button_new_with_mnemonic ("Button _E in buffer");
 
1862
  
 
1863
  gtk_text_view_add_child_at_anchor (text_view, child, anchor);
 
1864
 
 
1865
  anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
 
1866
 
 
1867
  child = gtk_button_new_with_mnemonic ("Button _F in buffer");
 
1868
  
 
1869
  gtk_text_view_add_child_at_anchor (text_view, child, anchor);
 
1870
 
 
1871
  anchor = gtk_text_buffer_create_child_anchor (view->buffer->buffer, &iter);
 
1872
 
 
1873
  child = gtk_button_new_with_mnemonic ("Button _G in buffer");
 
1874
  
 
1875
  gtk_text_view_add_child_at_anchor (text_view, child, anchor);
 
1876
 
 
1877
  /* show all the buttons */
 
1878
  gtk_widget_show_all (view->text_view);
 
1879
}
 
1880
 
 
1881
static void
 
1882
view_init_menus (View *view)
 
1883
{
 
1884
  GtkTextDirection direction = gtk_widget_get_direction (view->text_view);
 
1885
  GtkWrapMode wrap_mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view->text_view));
 
1886
  GtkWidget *menu_item = NULL;
 
1887
 
 
1888
  switch (direction)
 
1889
    {
 
1890
    case GTK_TEXT_DIR_LTR:
 
1891
      menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Left-to-Right");
 
1892
      break;
 
1893
    case GTK_TEXT_DIR_RTL:
 
1894
      menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Right-to-Left");
 
1895
      break;
 
1896
    default:
 
1897
      break;
 
1898
    }
 
1899
 
 
1900
  if (menu_item)
 
1901
    gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
 
1902
 
 
1903
  switch (wrap_mode)
 
1904
    {
 
1905
    case GTK_WRAP_NONE:
 
1906
      menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Off");
 
1907
      break;
 
1908
    case GTK_WRAP_WORD:
 
1909
      menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Words");
 
1910
      break;
 
1911
    case GTK_WRAP_CHAR:
 
1912
      menu_item = gtk_item_factory_get_widget (view->item_factory, "/Settings/Wrap Chars");
 
1913
      break;
 
1914
    default:
 
1915
      break;
 
1916
    }
 
1917
  
 
1918
  if (menu_item)
 
1919
    gtk_menu_item_activate (GTK_MENU_ITEM (menu_item));
 
1920
}
 
1921
 
 
1922
static GtkItemFactoryEntry menu_items[] =
 
1923
{
 
1924
  { "/_File",            NULL,         NULL,        0, "<Branch>" },
 
1925
  { "/File/_New",        "<control>N", do_new,      0, NULL },
 
1926
  { "/File/New _View",   NULL,         do_new_view, 0, NULL },
 
1927
  { "/File/_Open",       "<control>O", do_open,     0, NULL },
 
1928
  { "/File/_Save",       "<control>S", do_save,     0, NULL },
 
1929
  { "/File/Save _As...", NULL,         do_save_as,  0, NULL },
 
1930
  { "/File/sep1",        NULL,         NULL,        0, "<Separator>" },
 
1931
  { "/File/_Close",     "<control>W" , do_close,    0, NULL },
 
1932
  { "/File/E_xit",      "<control>Q" , do_exit,     0, NULL },
 
1933
 
 
1934
  { "/_Edit", NULL, 0, 0, "<Branch>" },
 
1935
  { "/Edit/Copy", NULL, do_copy, 0, NULL },
 
1936
  { "/Edit/sep1", NULL, NULL, 0, "<Separator>" },
 
1937
  { "/Edit/Find...", NULL, do_search, 0, NULL },
 
1938
  { "/Edit/Select All", "<control>A", do_select_all, 0, NULL }, 
 
1939
 
 
1940
  { "/_Settings",         NULL,         NULL,             0, "<Branch>" },
 
1941
  { "/Settings/Wrap _Off",   NULL,      do_wrap_changed,  GTK_WRAP_NONE, "<RadioItem>" },
 
1942
  { "/Settings/Wrap _Words", NULL,      do_wrap_changed,  GTK_WRAP_WORD, "/Settings/Wrap Off" },
 
1943
  { "/Settings/Wrap _Chars", NULL,      do_wrap_changed,  GTK_WRAP_CHAR, "/Settings/Wrap Off" },
 
1944
  { "/Settings/sep1",        NULL,      NULL,             0, "<Separator>" },
 
1945
  { "/Settings/Editable", NULL,      do_editable_changed,  TRUE, "<RadioItem>" },
 
1946
  { "/Settings/Not editable",    NULL,      do_editable_changed,  FALSE, "/Settings/Editable" },
 
1947
  { "/Settings/sep1",        NULL,      NULL,             0, "<Separator>" },
 
1948
 
 
1949
  { "/Settings/Cursor visible",    NULL,      do_cursor_visible_changed,  TRUE, "<RadioItem>" },
 
1950
  { "/Settings/Cursor not visible", NULL,      do_cursor_visible_changed,  FALSE, "/Settings/Cursor visible" },
 
1951
  { "/Settings/sep1",        NULL,      NULL,          0, "<Separator>" },
 
1952
  
 
1953
  { "/Settings/Left-to-Right", NULL,    do_direction_changed,  GTK_TEXT_DIR_LTR, "<RadioItem>" },
 
1954
  { "/Settings/Right-to-Left", NULL,    do_direction_changed,  GTK_TEXT_DIR_RTL, "/Settings/Left-to-Right" },
 
1955
 
 
1956
  { "/Settings/sep1",        NULL,      NULL,                0, "<Separator>" },
 
1957
  { "/Settings/Sane spacing", NULL,    do_spacing_changed,  FALSE, "<RadioItem>" },
 
1958
  { "/Settings/Funky spacing", NULL,    do_spacing_changed,  TRUE, "/Settings/Sane spacing" },
 
1959
  { "/Settings/sep1",        NULL,      NULL,                0, "<Separator>" },
 
1960
  { "/Settings/Don't cycle color tags", NULL,    do_color_cycle_changed,  FALSE, "<RadioItem>" },
 
1961
  { "/Settings/Cycle colors", NULL,    do_color_cycle_changed,  TRUE, "/Settings/Don't cycle color tags" },
 
1962
  { "/_Attributes",       NULL,         NULL,                0, "<Branch>" },
 
1963
  { "/Attributes/Editable",       NULL,         do_apply_editable, TRUE, NULL },
 
1964
  { "/Attributes/Not editable",           NULL,         do_apply_editable, FALSE, NULL },
 
1965
  { "/Attributes/Invisible",      NULL,         do_apply_invisible, FALSE, NULL },
 
1966
  { "/Attributes/Visible",        NULL,         do_apply_invisible, TRUE, NULL },
 
1967
  { "/Attributes/Rise",           NULL,         do_apply_rise, FALSE, NULL },
 
1968
  { "/Attributes/Large",          NULL,         do_apply_large, FALSE, NULL },
 
1969
  { "/Attributes/Indent",         NULL,         do_apply_indent, FALSE, NULL },
 
1970
  { "/Attributes/Margins",        NULL,         do_apply_margin, FALSE, NULL },
 
1971
  { "/Attributes/Custom tabs",            NULL,         do_apply_tabs, FALSE, NULL },
 
1972
  { "/Attributes/Default tabs",           NULL,         do_apply_tabs, TRUE, NULL },
 
1973
  { "/Attributes/Color cycles",           NULL,         do_apply_colors, TRUE, NULL },
 
1974
  { "/Attributes/No colors",              NULL,         do_apply_colors, FALSE, NULL },
 
1975
  { "/Attributes/Remove all tags",        NULL, do_remove_tags, 0, NULL },
 
1976
  { "/Attributes/Properties",             NULL, do_properties, 0, NULL },
 
1977
  { "/Attributes/Rich Text copy & drag",  NULL, do_rich_text, 0, NULL },
 
1978
  { "/Attributes/Rich Text paste & drop", NULL, do_rich_text, 1, NULL },
 
1979
  { "/_Test",            NULL,         NULL,           0, "<Branch>" },
 
1980
  { "/Test/_Example",    NULL,         do_example,  0, NULL },
 
1981
  { "/Test/_Insert and scroll", NULL,         do_insert_and_scroll,  0, NULL },
 
1982
  { "/Test/_Add fixed children", NULL,         do_add_children,  0, NULL },
 
1983
  { "/Test/A_dd focusable children", NULL,    do_add_focus_children,  0, NULL },
 
1984
};
 
1985
 
 
1986
static gboolean
 
1987
save_buffer (Buffer *buffer)
 
1988
{
 
1989
  GtkTextIter start, end;
 
1990
  gchar *chars;
 
1991
  gboolean result = FALSE;
 
1992
  gboolean have_backup = FALSE;
 
1993
  gchar *bak_filename;
 
1994
  FILE *file;
 
1995
 
 
1996
  g_return_val_if_fail (buffer->filename != NULL, FALSE);
 
1997
 
 
1998
  bak_filename = g_strconcat (buffer->filename, "~", NULL);
 
1999
  
 
2000
  if (rename (buffer->filename, bak_filename) != 0)
 
2001
    {
 
2002
      if (errno != ENOENT)
 
2003
        {
 
2004
          gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
 
2005
                                        buffer->filename, bak_filename, g_strerror (errno));
 
2006
          msgbox_run (NULL, err, "OK", NULL, NULL, 0);
 
2007
          g_free (err);
 
2008
          return FALSE;
 
2009
        }
 
2010
    }
 
2011
  else
 
2012
    have_backup = TRUE;
 
2013
  
 
2014
  file = fopen (buffer->filename, "w");
 
2015
  if (!file)
 
2016
    {
 
2017
      gchar *err = g_strdup_printf ("Cannot back up '%s' to '%s': %s",
 
2018
                                    buffer->filename, bak_filename, g_strerror (errno));
 
2019
      msgbox_run (NULL, err, "OK", NULL, NULL, 0);
 
2020
    }
 
2021
  else
 
2022
    {
 
2023
      gtk_text_buffer_get_iter_at_offset (buffer->buffer, &start, 0);
 
2024
      gtk_text_buffer_get_end_iter (buffer->buffer, &end);
 
2025
  
 
2026
      chars = gtk_text_buffer_get_slice (buffer->buffer, &start, &end, FALSE);
 
2027
 
 
2028
      if (fputs (chars, file) == EOF ||
 
2029
          fclose (file) == EOF)
 
2030
        {
 
2031
          gchar *err = g_strdup_printf ("Error writing to '%s': %s",
 
2032
                                        buffer->filename, g_strerror (errno));
 
2033
          msgbox_run (NULL, err, "OK", NULL, NULL, 0);
 
2034
          g_free (err);
 
2035
        }
 
2036
      else
 
2037
        {
 
2038
          /* Success
 
2039
           */
 
2040
          result = TRUE;
 
2041
          gtk_text_buffer_set_modified (buffer->buffer, FALSE);   
 
2042
        }
 
2043
        
 
2044
      g_free (chars);
 
2045
    }
 
2046
 
 
2047
  if (!result && have_backup)
 
2048
    {
 
2049
      if (rename (bak_filename, buffer->filename) != 0)
 
2050
        {
 
2051
          gchar *err = g_strdup_printf ("Error restoring backup file '%s' to '%s': %s\nBackup left as '%s'",
 
2052
                                        buffer->filename, bak_filename, g_strerror (errno), bak_filename);
 
2053
          msgbox_run (NULL, err, "OK", NULL, NULL, 0);
 
2054
          g_free (err);
 
2055
        }
 
2056
    }
 
2057
 
 
2058
  g_free (bak_filename);
 
2059
  
 
2060
  return result;
 
2061
}
 
2062
 
 
2063
static gboolean
 
2064
save_as_ok_func (const char *filename, gpointer data)
 
2065
{
 
2066
  Buffer *buffer = data;
 
2067
  char *old_filename = buffer->filename;
 
2068
 
 
2069
  if (!buffer->filename || strcmp (filename, buffer->filename) != 0)
 
2070
    {
 
2071
      struct stat statbuf;
 
2072
 
 
2073
      if (stat (filename, &statbuf) == 0)
 
2074
        {
 
2075
          gchar *err = g_strdup_printf ("Ovewrite existing file '%s'?", filename);
 
2076
          gint result = msgbox_run (NULL, err, "Yes", "No", NULL, 1);
 
2077
          g_free (err);
 
2078
 
 
2079
          if (result != 0)
 
2080
            return FALSE;
 
2081
        }
 
2082
    }
 
2083
  
 
2084
  buffer->filename = g_strdup (filename);
 
2085
 
 
2086
  if (save_buffer (buffer))
 
2087
    {
 
2088
      g_free (old_filename);
 
2089
      buffer_filename_set (buffer);
 
2090
      return TRUE;
 
2091
    }
 
2092
  else
 
2093
    {
 
2094
      g_free (buffer->filename);
 
2095
      buffer->filename = old_filename;
 
2096
      return FALSE;
 
2097
    }
 
2098
}
 
2099
 
 
2100
static gboolean
 
2101
save_as_buffer (Buffer *buffer)
 
2102
{
 
2103
  return filesel_run (NULL, "Save File", NULL, save_as_ok_func, buffer);
 
2104
}
 
2105
 
 
2106
static gboolean
 
2107
check_buffer_saved (Buffer *buffer)
 
2108
{
 
2109
  if (gtk_text_buffer_get_modified (buffer->buffer))
 
2110
    {
 
2111
      char *pretty_name = buffer_pretty_name (buffer);
 
2112
      char *msg = g_strdup_printf ("Save changes to '%s'?", pretty_name);
 
2113
      gint result;
 
2114
      
 
2115
      g_free (pretty_name);
 
2116
      
 
2117
      result = msgbox_run (NULL, msg, "Yes", "No", "Cancel", 0);
 
2118
      g_free (msg);
 
2119
  
 
2120
      if (result == 0)
 
2121
        return save_as_buffer (buffer);
 
2122
      else if (result == 1)
 
2123
        return TRUE;
 
2124
      else
 
2125
        return FALSE;
 
2126
    }
 
2127
  else
 
2128
    return TRUE;
 
2129
}
 
2130
 
 
2131
#define N_COLORS 16
 
2132
 
 
2133
static Buffer *
 
2134
create_buffer (void)
 
2135
{
 
2136
  Buffer *buffer;
 
2137
  PangoTabArray *tabs;
 
2138
  gint i;
 
2139
  
 
2140
  buffer = g_new (Buffer, 1);
 
2141
 
 
2142
  buffer->buffer = gtk_text_buffer_new (NULL);
 
2143
  
 
2144
  buffer->refcount = 1;
 
2145
  buffer->filename = NULL;
 
2146
  buffer->untitled_serial = -1;
 
2147
 
 
2148
  buffer->color_tags = NULL;
 
2149
  buffer->color_cycle_timeout = 0;
 
2150
  buffer->start_hue = 0.0;
 
2151
  
 
2152
  i = 0;
 
2153
  while (i < N_COLORS)
 
2154
    {
 
2155
      GtkTextTag *tag;
 
2156
 
 
2157
      tag = gtk_text_buffer_create_tag (buffer->buffer, NULL, NULL);
 
2158
      
 
2159
      buffer->color_tags = g_slist_prepend (buffer->color_tags, tag);
 
2160
      
 
2161
      ++i;
 
2162
    }
 
2163
 
 
2164
#if 1  
 
2165
  buffer->invisible_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2166
                                                      "invisible", TRUE, NULL);
 
2167
#endif  
 
2168
  
 
2169
  buffer->not_editable_tag =
 
2170
    gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2171
                                "editable", FALSE,
 
2172
                                "foreground", "purple", NULL);
 
2173
 
 
2174
  buffer->found_text_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2175
                                                       "foreground", "red", NULL);
 
2176
 
 
2177
  buffer->rise_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2178
                                                 "rise", 10 * PANGO_SCALE, NULL);
 
2179
 
 
2180
  buffer->large_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2181
                                                 "scale", PANGO_SCALE_X_LARGE, NULL);
 
2182
 
 
2183
  buffer->indent_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2184
                                                   "indent", 20, NULL);
 
2185
 
 
2186
  buffer->margin_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2187
                                                   "left_margin", 20, "right_margin", 20, NULL);
 
2188
 
 
2189
  tabs = pango_tab_array_new_with_positions (4,
 
2190
                                             TRUE,
 
2191
                                             PANGO_TAB_LEFT, 10,
 
2192
                                             PANGO_TAB_LEFT, 30,
 
2193
                                             PANGO_TAB_LEFT, 60,
 
2194
                                             PANGO_TAB_LEFT, 120);
 
2195
  
 
2196
  buffer->custom_tabs_tag = gtk_text_buffer_create_tag (buffer->buffer, NULL,
 
2197
                                                        "tabs", tabs,
 
2198
                                                        "foreground", "green", NULL);
 
2199
 
 
2200
  pango_tab_array_free (tabs);
 
2201
  
 
2202
  buffers = g_slist_prepend (buffers, buffer);
 
2203
  
 
2204
  return buffer;
 
2205
}
 
2206
 
 
2207
static char *
 
2208
buffer_pretty_name (Buffer *buffer)
 
2209
{
 
2210
  if (buffer->filename)
 
2211
    {
 
2212
      char *p;
 
2213
      char *result = g_path_get_basename (buffer->filename);
 
2214
      p = strchr (result, '/');
 
2215
      if (p)
 
2216
        *p = '\0';
 
2217
 
 
2218
      return result;
 
2219
    }
 
2220
  else
 
2221
    {
 
2222
      if (buffer->untitled_serial == -1)
 
2223
        buffer->untitled_serial = untitled_serial++;
 
2224
 
 
2225
      if (buffer->untitled_serial == 1)
 
2226
        return g_strdup ("Untitled");
 
2227
      else
 
2228
        return g_strdup_printf ("Untitled #%d", buffer->untitled_serial);
 
2229
    }
 
2230
}
 
2231
 
 
2232
static void
 
2233
buffer_filename_set (Buffer *buffer)
 
2234
{
 
2235
  GSList *tmp_list = views;
 
2236
 
 
2237
  while (tmp_list)
 
2238
    {
 
2239
      View *view = tmp_list->data;
 
2240
 
 
2241
      if (view->buffer == buffer)
 
2242
        view_set_title (view);
 
2243
 
 
2244
      tmp_list = tmp_list->next;
 
2245
    }
 
2246
}
 
2247
 
 
2248
static void
 
2249
buffer_search (Buffer     *buffer,
 
2250
               const char *str,
 
2251
               View       *view,
 
2252
               gboolean forward)
 
2253
{
 
2254
  GtkTextIter iter;
 
2255
  GtkTextIter start, end;
 
2256
  GtkWidget *dialog;
 
2257
  int i;
 
2258
  
 
2259
  /* remove tag from whole buffer */
 
2260
  gtk_text_buffer_get_bounds (buffer->buffer, &start, &end);
 
2261
  gtk_text_buffer_remove_tag (buffer->buffer,  buffer->found_text_tag,
 
2262
                              &start, &end );
 
2263
  
 
2264
  gtk_text_buffer_get_iter_at_mark (buffer->buffer, &iter,
 
2265
                                    gtk_text_buffer_get_mark (buffer->buffer,
 
2266
                                                              "insert"));
 
2267
 
 
2268
  i = 0;
 
2269
  if (*str != '\0')
 
2270
    {
 
2271
      GtkTextIter match_start, match_end;
 
2272
 
 
2273
      if (forward)
 
2274
        {
 
2275
          while (gtk_text_iter_forward_search (&iter, str,
 
2276
                                               GTK_TEXT_SEARCH_VISIBLE_ONLY |
 
2277
                                               GTK_TEXT_SEARCH_TEXT_ONLY,
 
2278
                                               &match_start, &match_end,
 
2279
                                               NULL))
 
2280
            {
 
2281
              ++i;
 
2282
              gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
 
2283
                                         &match_start, &match_end);
 
2284
              
 
2285
              iter = match_end;
 
2286
            }
 
2287
        }
 
2288
      else
 
2289
        {
 
2290
          while (gtk_text_iter_backward_search (&iter, str,
 
2291
                                                GTK_TEXT_SEARCH_VISIBLE_ONLY |
 
2292
                                                GTK_TEXT_SEARCH_TEXT_ONLY,
 
2293
                                                &match_start, &match_end,
 
2294
                                                NULL))
 
2295
            {
 
2296
              ++i;
 
2297
              gtk_text_buffer_apply_tag (buffer->buffer, buffer->found_text_tag,
 
2298
                                         &match_start, &match_end);
 
2299
              
 
2300
              iter = match_start;
 
2301
            }
 
2302
        }
 
2303
    }
 
2304
 
 
2305
  dialog = gtk_message_dialog_new (GTK_WINDOW (view->window),
 
2306
                                   GTK_DIALOG_DESTROY_WITH_PARENT,
 
2307
                                   GTK_MESSAGE_INFO,
 
2308
                                   GTK_BUTTONS_OK,
 
2309
                                   "%d strings found and marked in red",
 
2310
                                   i);
 
2311
 
 
2312
  g_signal_connect_swapped (dialog,
 
2313
                            "response",
 
2314
                            G_CALLBACK (gtk_widget_destroy), dialog);
 
2315
  
 
2316
  gtk_widget_show (dialog);
 
2317
}
 
2318
 
 
2319
static void
 
2320
buffer_search_forward (Buffer *buffer, const char *str,
 
2321
                       View *view)
 
2322
{
 
2323
  buffer_search (buffer, str, view, TRUE);
 
2324
}
 
2325
 
 
2326
static void
 
2327
buffer_search_backward (Buffer *buffer, const char *str,
 
2328
                        View *view)
 
2329
{
 
2330
  buffer_search (buffer, str, view, FALSE);
 
2331
}
 
2332
 
 
2333
static void
 
2334
buffer_ref (Buffer *buffer)
 
2335
{
 
2336
  buffer->refcount++;
 
2337
}
 
2338
 
 
2339
static void
 
2340
buffer_unref (Buffer *buffer)
 
2341
{
 
2342
  buffer->refcount--;
 
2343
  if (buffer->refcount == 0)
 
2344
    {
 
2345
      buffer_set_colors (buffer, FALSE);
 
2346
      buffers = g_slist_remove (buffers, buffer);
 
2347
      g_object_unref (buffer->buffer);
 
2348
      g_free (buffer->filename);
 
2349
      g_free (buffer);
 
2350
    }
 
2351
}
 
2352
 
 
2353
static void
 
2354
hsv_to_rgb (gdouble *h,
 
2355
            gdouble *s,
 
2356
            gdouble *v)
 
2357
{
 
2358
  gdouble hue, saturation, value;
 
2359
  gdouble f, p, q, t;
 
2360
 
 
2361
  if (*s == 0.0)
 
2362
    {
 
2363
      *h = *v;
 
2364
      *s = *v;
 
2365
      *v = *v; /* heh */
 
2366
    }
 
2367
  else
 
2368
    {
 
2369
      hue = *h * 6.0;
 
2370
      saturation = *s;
 
2371
      value = *v;
 
2372
      
 
2373
      if (hue >= 6.0)
 
2374
        hue = 0.0;
 
2375
      
 
2376
      f = hue - (int) hue;
 
2377
      p = value * (1.0 - saturation);
 
2378
      q = value * (1.0 - saturation * f);
 
2379
      t = value * (1.0 - saturation * (1.0 - f));
 
2380
      
 
2381
      switch ((int) hue)
 
2382
        {
 
2383
        case 0:
 
2384
          *h = value;
 
2385
          *s = t;
 
2386
          *v = p;
 
2387
          break;
 
2388
          
 
2389
        case 1:
 
2390
          *h = q;
 
2391
          *s = value;
 
2392
          *v = p;
 
2393
          break;
 
2394
          
 
2395
        case 2:
 
2396
          *h = p;
 
2397
          *s = value;
 
2398
          *v = t;
 
2399
          break;
 
2400
          
 
2401
        case 3:
 
2402
          *h = p;
 
2403
          *s = q;
 
2404
          *v = value;
 
2405
          break;
 
2406
          
 
2407
        case 4:
 
2408
          *h = t;
 
2409
          *s = p;
 
2410
          *v = value;
 
2411
          break;
 
2412
          
 
2413
        case 5:
 
2414
          *h = value;
 
2415
          *s = p;
 
2416
          *v = q;
 
2417
          break;
 
2418
          
 
2419
        default:
 
2420
          g_assert_not_reached ();
 
2421
        }
 
2422
    }
 
2423
}
 
2424
 
 
2425
static void
 
2426
hue_to_color (gdouble   hue,
 
2427
              GdkColor *color)
 
2428
{
 
2429
  gdouble h, s, v;
 
2430
 
 
2431
  h = hue;
 
2432
  s = 1.0;
 
2433
  v = 1.0;
 
2434
 
 
2435
  g_return_if_fail (hue <= 1.0);
 
2436
  
 
2437
  hsv_to_rgb (&h, &s, &v);
 
2438
 
 
2439
  color->red = h * 65535;
 
2440
  color->green = s * 65535;
 
2441
  color->blue = v * 65535;
 
2442
}
 
2443
 
 
2444
 
 
2445
static gint
 
2446
color_cycle_timeout (gpointer data)
 
2447
{
 
2448
  Buffer *buffer = data;
 
2449
 
 
2450
  buffer_cycle_colors (buffer);
 
2451
 
 
2452
  return TRUE;
 
2453
}
 
2454
 
 
2455
static void
 
2456
buffer_set_colors (Buffer  *buffer,
 
2457
                   gboolean enabled)
 
2458
{
 
2459
  GSList *tmp;
 
2460
  gdouble hue = 0.0;
 
2461
 
 
2462
  if (enabled && buffer->color_cycle_timeout == 0)
 
2463
    buffer->color_cycle_timeout = g_timeout_add (200, color_cycle_timeout, buffer);
 
2464
  else if (!enabled && buffer->color_cycle_timeout != 0)
 
2465
    {
 
2466
      g_source_remove (buffer->color_cycle_timeout);
 
2467
      buffer->color_cycle_timeout = 0;
 
2468
    }
 
2469
    
 
2470
  tmp = buffer->color_tags;
 
2471
  while (tmp != NULL)
 
2472
    {
 
2473
      if (enabled)
 
2474
        {
 
2475
          GdkColor color;
 
2476
          
 
2477
          hue_to_color (hue, &color);
 
2478
 
 
2479
          g_object_set (tmp->data,
 
2480
                        "foreground_gdk", &color,
 
2481
                        NULL);
 
2482
        }
 
2483
      else
 
2484
        g_object_set (tmp->data,
 
2485
                      "foreground_set", FALSE,
 
2486
                      NULL);
 
2487
 
 
2488
      hue += 1.0 / N_COLORS;
 
2489
      
 
2490
      tmp = g_slist_next (tmp);
 
2491
    }
 
2492
}
 
2493
 
 
2494
static void
 
2495
buffer_cycle_colors (Buffer *buffer)
 
2496
{
 
2497
  GSList *tmp;
 
2498
  gdouble hue = buffer->start_hue;
 
2499
  
 
2500
  tmp = buffer->color_tags;
 
2501
  while (tmp != NULL)
 
2502
    {
 
2503
      GdkColor color;
 
2504
      
 
2505
      hue_to_color (hue, &color);
 
2506
      
 
2507
      g_object_set (tmp->data,
 
2508
                    "foreground_gdk", &color,
 
2509
                    NULL);
 
2510
 
 
2511
      hue += 1.0 / N_COLORS;
 
2512
      if (hue > 1.0)
 
2513
        hue = 0.0;
 
2514
      
 
2515
      tmp = g_slist_next (tmp);
 
2516
    }
 
2517
 
 
2518
  buffer->start_hue += 1.0 / N_COLORS;
 
2519
  if (buffer->start_hue > 1.0)
 
2520
    buffer->start_hue = 0.0;
 
2521
}
 
2522
 
 
2523
static void
 
2524
close_view (View *view)
 
2525
{
 
2526
  views = g_slist_remove (views, view);
 
2527
  buffer_unref (view->buffer);
 
2528
  gtk_widget_destroy (view->window);
 
2529
  g_object_unref (view->item_factory);
 
2530
  
 
2531
  g_free (view);
 
2532
  
 
2533
  if (!views)
 
2534
    gtk_main_quit ();
 
2535
}
 
2536
 
 
2537
static void
 
2538
check_close_view (View *view)
 
2539
{
 
2540
  if (view->buffer->refcount > 1 ||
 
2541
      check_buffer_saved (view->buffer))
 
2542
    close_view (view);
 
2543
}
 
2544
 
 
2545
static void
 
2546
view_set_title (View *view)
 
2547
{
 
2548
  char *pretty_name = buffer_pretty_name (view->buffer);
 
2549
  char *title = g_strconcat ("testtext - ", pretty_name, NULL);
 
2550
 
 
2551
  gtk_window_set_title (GTK_WINDOW (view->window), title);
 
2552
 
 
2553
  g_free (pretty_name);
 
2554
  g_free (title);
 
2555
}
 
2556
 
 
2557
static void
 
2558
cursor_set_callback (GtkTextBuffer     *buffer,
 
2559
                     const GtkTextIter *location,
 
2560
                     GtkTextMark       *mark,
 
2561
                     gpointer           user_data)
 
2562
{
 
2563
  GtkTextView *text_view;
 
2564
 
 
2565
  /* Redraw tab windows if the cursor moves
 
2566
   * on the mapped widget (windows may not exist before realization...
 
2567
   */
 
2568
  
 
2569
  text_view = GTK_TEXT_VIEW (user_data);
 
2570
  
 
2571
  if (GTK_WIDGET_MAPPED (text_view) &&
 
2572
      mark == gtk_text_buffer_get_insert (buffer))
 
2573
    {
 
2574
      GdkWindow *tab_window;
 
2575
 
 
2576
      tab_window = gtk_text_view_get_window (text_view,
 
2577
                                             GTK_TEXT_WINDOW_TOP);
 
2578
 
 
2579
      gdk_window_invalidate_rect (tab_window, NULL, FALSE);
 
2580
      
 
2581
      tab_window = gtk_text_view_get_window (text_view,
 
2582
                                             GTK_TEXT_WINDOW_BOTTOM);
 
2583
 
 
2584
      gdk_window_invalidate_rect (tab_window, NULL, FALSE);
 
2585
    }
 
2586
}
 
2587
 
 
2588
static gint
 
2589
tab_stops_expose (GtkWidget      *widget,
 
2590
                  GdkEventExpose *event,
 
2591
                  gpointer        user_data)
 
2592
{
 
2593
  gint first_x;
 
2594
  gint last_x;
 
2595
  gint i;
 
2596
  GdkWindow *top_win;
 
2597
  GdkWindow *bottom_win;
 
2598
  GtkTextView *text_view;
 
2599
  GtkTextWindowType type;
 
2600
  GdkDrawable *target;
 
2601
  gint *positions = NULL;
 
2602
  gint size;
 
2603
  GtkTextAttributes *attrs;
 
2604
  GtkTextIter insert;
 
2605
  GtkTextBuffer *buffer;
 
2606
  gboolean in_pixels;
 
2607
  
 
2608
  text_view = GTK_TEXT_VIEW (widget);
 
2609
  
 
2610
  /* See if this expose is on the tab stop window */
 
2611
  top_win = gtk_text_view_get_window (text_view,
 
2612
                                      GTK_TEXT_WINDOW_TOP);
 
2613
 
 
2614
  bottom_win = gtk_text_view_get_window (text_view,
 
2615
                                         GTK_TEXT_WINDOW_BOTTOM);
 
2616
 
 
2617
  if (event->window == top_win)
 
2618
    {
 
2619
      type = GTK_TEXT_WINDOW_TOP;
 
2620
      target = top_win;
 
2621
    }
 
2622
  else if (event->window == bottom_win)
 
2623
    {
 
2624
      type = GTK_TEXT_WINDOW_BOTTOM;
 
2625
      target = bottom_win;
 
2626
    }
 
2627
  else
 
2628
    return FALSE;
 
2629
  
 
2630
  first_x = event->area.x;
 
2631
  last_x = first_x + event->area.width;
 
2632
 
 
2633
  gtk_text_view_window_to_buffer_coords (text_view,
 
2634
                                         type,
 
2635
                                         first_x,
 
2636
                                         0,
 
2637
                                         &first_x,
 
2638
                                         NULL);
 
2639
 
 
2640
  gtk_text_view_window_to_buffer_coords (text_view,
 
2641
                                         type,
 
2642
                                         last_x,
 
2643
                                         0,
 
2644
                                         &last_x,
 
2645
                                         NULL);
 
2646
 
 
2647
  buffer = gtk_text_view_get_buffer (text_view);
 
2648
 
 
2649
  gtk_text_buffer_get_iter_at_mark (buffer,
 
2650
                                    &insert,
 
2651
                                    gtk_text_buffer_get_mark (buffer,
 
2652
                                                              "insert"));
 
2653
  
 
2654
  attrs = gtk_text_attributes_new ();
 
2655
 
 
2656
  gtk_text_iter_get_attributes (&insert, attrs);
 
2657
 
 
2658
  if (attrs->tabs)
 
2659
    {
 
2660
      size = pango_tab_array_get_size (attrs->tabs);
 
2661
      
 
2662
      pango_tab_array_get_tabs (attrs->tabs,
 
2663
                                NULL,
 
2664
                                &positions);
 
2665
 
 
2666
      in_pixels = pango_tab_array_get_positions_in_pixels (attrs->tabs);
 
2667
    }
 
2668
  else
 
2669
    {
 
2670
      size = 0;
 
2671
      in_pixels = FALSE;
 
2672
    }
 
2673
      
 
2674
  gtk_text_attributes_unref (attrs);
 
2675
  
 
2676
  i = 0;
 
2677
  while (i < size)
 
2678
    {
 
2679
      gint pos;
 
2680
 
 
2681
      if (!in_pixels)
 
2682
        positions[i] = PANGO_PIXELS (positions[i]);
 
2683
      
 
2684
      gtk_text_view_buffer_to_window_coords (text_view,
 
2685
                                             type,
 
2686
                                             positions[i],
 
2687
                                             0,
 
2688
                                             &pos,
 
2689
                                             NULL);
 
2690
      
 
2691
      gdk_draw_line (target, 
 
2692
                     widget->style->fg_gc [widget->state],
 
2693
                     pos, 0,
 
2694
                     pos, 15); 
 
2695
      
 
2696
      ++i;
 
2697
    }
 
2698
 
 
2699
  g_free (positions);
 
2700
 
 
2701
  return TRUE;
 
2702
}
 
2703
 
 
2704
static void
 
2705
get_lines (GtkTextView  *text_view,
 
2706
           gint          first_y,
 
2707
           gint          last_y,
 
2708
           GArray       *buffer_coords,
 
2709
           GArray       *numbers,
 
2710
           gint         *countp)
 
2711
{
 
2712
  GtkTextIter iter;
 
2713
  gint count;
 
2714
  gint size;  
 
2715
 
 
2716
  g_array_set_size (buffer_coords, 0);
 
2717
  g_array_set_size (numbers, 0);
 
2718
  
 
2719
  /* Get iter at first y */
 
2720
  gtk_text_view_get_line_at_y (text_view, &iter, first_y, NULL);
 
2721
 
 
2722
  /* For each iter, get its location and add it to the arrays.
 
2723
   * Stop when we pass last_y
 
2724
   */
 
2725
  count = 0;
 
2726
  size = 0;
 
2727
 
 
2728
  while (!gtk_text_iter_is_end (&iter))
 
2729
    {
 
2730
      gint y, height;
 
2731
      gint line_num;
 
2732
      
 
2733
      gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
 
2734
 
 
2735
      g_array_append_val (buffer_coords, y);
 
2736
      line_num = gtk_text_iter_get_line (&iter);
 
2737
      g_array_append_val (numbers, line_num);
 
2738
      
 
2739
      ++count;
 
2740
 
 
2741
      if ((y + height) >= last_y)
 
2742
        break;
 
2743
      
 
2744
      gtk_text_iter_forward_line (&iter);
 
2745
    }
 
2746
 
 
2747
  *countp = count;
 
2748
}
 
2749
 
 
2750
static gint
 
2751
line_numbers_expose (GtkWidget      *widget,
 
2752
                     GdkEventExpose *event,
 
2753
                     gpointer        user_data)
 
2754
{
 
2755
  gint count;
 
2756
  GArray *numbers;
 
2757
  GArray *pixels;
 
2758
  gint first_y;
 
2759
  gint last_y;
 
2760
  gint i;
 
2761
  GdkWindow *left_win;
 
2762
  GdkWindow *right_win;
 
2763
  PangoLayout *layout;
 
2764
  GtkTextView *text_view;
 
2765
  GtkTextWindowType type;
 
2766
  GdkDrawable *target;
 
2767
  
 
2768
  text_view = GTK_TEXT_VIEW (widget);
 
2769
  
 
2770
  /* See if this expose is on the line numbers window */
 
2771
  left_win = gtk_text_view_get_window (text_view,
 
2772
                                       GTK_TEXT_WINDOW_LEFT);
 
2773
 
 
2774
  right_win = gtk_text_view_get_window (text_view,
 
2775
                                        GTK_TEXT_WINDOW_RIGHT);
 
2776
 
 
2777
  if (event->window == left_win)
 
2778
    {
 
2779
      type = GTK_TEXT_WINDOW_LEFT;
 
2780
      target = left_win;
 
2781
    }
 
2782
  else if (event->window == right_win)
 
2783
    {
 
2784
      type = GTK_TEXT_WINDOW_RIGHT;
 
2785
      target = right_win;
 
2786
    }
 
2787
  else
 
2788
    return FALSE;
 
2789
  
 
2790
  first_y = event->area.y;
 
2791
  last_y = first_y + event->area.height;
 
2792
 
 
2793
  gtk_text_view_window_to_buffer_coords (text_view,
 
2794
                                         type,
 
2795
                                         0,
 
2796
                                         first_y,
 
2797
                                         NULL,
 
2798
                                         &first_y);
 
2799
 
 
2800
  gtk_text_view_window_to_buffer_coords (text_view,
 
2801
                                         type,
 
2802
                                         0,
 
2803
                                         last_y,
 
2804
                                         NULL,
 
2805
                                         &last_y);
 
2806
 
 
2807
  numbers = g_array_new (FALSE, FALSE, sizeof (gint));
 
2808
  pixels = g_array_new (FALSE, FALSE, sizeof (gint));
 
2809
  
 
2810
  get_lines (text_view,
 
2811
             first_y,
 
2812
             last_y,
 
2813
             pixels,
 
2814
             numbers,
 
2815
             &count);
 
2816
  
 
2817
  /* Draw fully internationalized numbers! */
 
2818
  
 
2819
  layout = gtk_widget_create_pango_layout (widget, "");
 
2820
  
 
2821
  i = 0;
 
2822
  while (i < count)
 
2823
    {
 
2824
      gint pos;
 
2825
      gchar *str;
 
2826
      
 
2827
      gtk_text_view_buffer_to_window_coords (text_view,
 
2828
                                             type,
 
2829
                                             0,
 
2830
                                             g_array_index (pixels, gint, i),
 
2831
                                             NULL,
 
2832
                                             &pos);
 
2833
 
 
2834
      str = g_strdup_printf ("%d", g_array_index (numbers, gint, i));
 
2835
 
 
2836
      pango_layout_set_text (layout, str, -1);
 
2837
 
 
2838
      gtk_paint_layout (widget->style,
 
2839
                        target,
 
2840
                        GTK_WIDGET_STATE (widget),
 
2841
                        FALSE,
 
2842
                        NULL,
 
2843
                        widget,
 
2844
                        NULL,
 
2845
                        2, pos + 2,
 
2846
                        layout);
 
2847
 
 
2848
      g_free (str);
 
2849
      
 
2850
      ++i;
 
2851
    }
 
2852
 
 
2853
  g_array_free (pixels, TRUE);
 
2854
  g_array_free (numbers, TRUE);
 
2855
  
 
2856
  g_object_unref (layout);
 
2857
 
 
2858
  /* don't stop emission, need to draw children */
 
2859
  return FALSE;
 
2860
}
 
2861
 
 
2862
static void
 
2863
selection_changed (GtkTextBuffer *buffer,
 
2864
                   GParamSpec    *pspec,
 
2865
                   GtkWidget     *copy_menu)
 
2866
{
 
2867
  gtk_widget_set_sensitive (copy_menu, gtk_text_buffer_get_has_selection (buffer));
 
2868
}
 
2869
 
 
2870
static View *
 
2871
create_view (Buffer *buffer)
 
2872
{
 
2873
  View *view;
 
2874
  GtkWidget *copy_menu;
 
2875
  GtkWidget *sw;
 
2876
  GtkWidget *vbox;
 
2877
  
 
2878
  view = g_new0 (View, 1);
 
2879
  views = g_slist_prepend (views, view);
 
2880
 
 
2881
  view->buffer = buffer;
 
2882
  buffer_ref (buffer);
 
2883
  
 
2884
  view->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
2885
  g_object_set_data (G_OBJECT (view->window), "view", view);
 
2886
  
 
2887
  g_signal_connect (view->window, "delete_event",
 
2888
                    G_CALLBACK (delete_event_cb), NULL);
 
2889
 
 
2890
  view->accel_group = gtk_accel_group_new ();
 
2891
  view->item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", view->accel_group);
 
2892
  g_object_set_data (G_OBJECT (view->item_factory), "view", view);
 
2893
  
 
2894
  gtk_item_factory_create_items (view->item_factory, G_N_ELEMENTS (menu_items), menu_items, view);
 
2895
 
 
2896
  /* make the Copy menu item sensitivity update according to the selection */
 
2897
  copy_menu = gtk_item_factory_get_item (view->item_factory, "<main>/Edit/Copy");
 
2898
  gtk_widget_set_sensitive (copy_menu, gtk_text_buffer_get_has_selection (view->buffer->buffer));
 
2899
  g_signal_connect (view->buffer->buffer,
 
2900
                    "notify::has-selection",
 
2901
                    G_CALLBACK (selection_changed),
 
2902
                    copy_menu);
 
2903
 
 
2904
  gtk_window_add_accel_group (GTK_WINDOW (view->window), view->accel_group);
 
2905
 
 
2906
  vbox = gtk_vbox_new (FALSE, 0);
 
2907
  gtk_container_add (GTK_CONTAINER (view->window), vbox);
 
2908
 
 
2909
  gtk_box_pack_start (GTK_BOX (vbox),
 
2910
                      gtk_item_factory_get_widget (view->item_factory, "<main>"),
 
2911
                      FALSE, FALSE, 0);
 
2912
  
 
2913
  sw = gtk_scrolled_window_new (NULL, NULL);
 
2914
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
 
2915
                                 GTK_POLICY_AUTOMATIC,
 
2916
                                 GTK_POLICY_AUTOMATIC);
 
2917
 
 
2918
  view->text_view = gtk_text_view_new_with_buffer (buffer->buffer);
 
2919
  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view->text_view),
 
2920
                               GTK_WRAP_WORD);
 
2921
 
 
2922
  /* Make sure border width works, no real reason to do this other than testing */
 
2923
  gtk_container_set_border_width (GTK_CONTAINER (view->text_view),
 
2924
                                  10);
 
2925
  
 
2926
  /* Draw tab stops in the top and bottom windows. */
 
2927
  
 
2928
  gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
 
2929
                                        GTK_TEXT_WINDOW_TOP,
 
2930
                                        15);
 
2931
 
 
2932
  gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
 
2933
                                        GTK_TEXT_WINDOW_BOTTOM,
 
2934
                                        15);
 
2935
 
 
2936
  g_signal_connect (view->text_view,
 
2937
                    "expose_event",
 
2938
                    G_CALLBACK (tab_stops_expose),
 
2939
                    NULL);  
 
2940
 
 
2941
  g_signal_connect (view->buffer->buffer,
 
2942
                    "mark_set",
 
2943
                    G_CALLBACK (cursor_set_callback),
 
2944
                    view->text_view);
 
2945
  
 
2946
  /* Draw line numbers in the side windows; we should really be
 
2947
   * more scientific about what width we set them to.
 
2948
   */
 
2949
  gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
 
2950
                                        GTK_TEXT_WINDOW_RIGHT,
 
2951
                                        30);
 
2952
  
 
2953
  gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view->text_view),
 
2954
                                        GTK_TEXT_WINDOW_LEFT,
 
2955
                                        30);
 
2956
  
 
2957
  g_signal_connect (view->text_view,
 
2958
                    "expose_event",
 
2959
                    G_CALLBACK (line_numbers_expose),
 
2960
                    NULL);
 
2961
  
 
2962
  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
 
2963
  gtk_container_add (GTK_CONTAINER (sw), view->text_view);
 
2964
 
 
2965
  gtk_window_set_default_size (GTK_WINDOW (view->window), 500, 500);
 
2966
 
 
2967
  gtk_widget_grab_focus (view->text_view);
 
2968
 
 
2969
  view_set_title (view);
 
2970
  view_init_menus (view);
 
2971
 
 
2972
  view_add_example_widgets (view);
 
2973
  
 
2974
  gtk_widget_show_all (view->window);
 
2975
  return view;
 
2976
}
 
2977
 
 
2978
static void
 
2979
view_add_example_widgets (View *view)
 
2980
{
 
2981
  GtkTextChildAnchor *anchor;
 
2982
  Buffer *buffer;
 
2983
 
 
2984
  buffer = view->buffer;
 
2985
  
 
2986
  anchor = g_object_get_data (G_OBJECT (buffer->buffer),
 
2987
                              "anchor");
 
2988
 
 
2989
  if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
 
2990
    {
 
2991
      GtkWidget *widget;
 
2992
 
 
2993
      widget = gtk_button_new_with_label ("Foo");
 
2994
      
 
2995
      gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
 
2996
                                         widget,
 
2997
                                         anchor);
 
2998
 
 
2999
      gtk_widget_show (widget);
 
3000
    }
 
3001
}
 
3002
 
 
3003
void
 
3004
test_init (void)
 
3005
{
 
3006
  if (g_file_test ("../gdk-pixbuf/libpixbufloader-pnm.la",
 
3007
                   G_FILE_TEST_EXISTS))
 
3008
    {
 
3009
      g_setenv ("GDK_PIXBUF_MODULE_FILE", "../gdk-pixbuf/gdk-pixbuf.loaders", TRUE);
 
3010
      g_setenv ("GTK_IM_MODULE_FILE", "../modules/input/gtk.immodules", TRUE);
 
3011
    }
 
3012
}
 
3013
 
 
3014
int
 
3015
main (int argc, char** argv)
 
3016
{
 
3017
  Buffer *buffer;
 
3018
  View *view;
 
3019
  int i;
 
3020
 
 
3021
  test_init ();
 
3022
  gtk_init (&argc, &argv);
 
3023
  
 
3024
  buffer = create_buffer ();
 
3025
  view = create_view (buffer);
 
3026
  buffer_unref (buffer);
 
3027
  
 
3028
  push_active_window (GTK_WINDOW (view->window));
 
3029
  for (i=1; i < argc; i++)
 
3030
    {
 
3031
      char *filename;
 
3032
 
 
3033
      /* Quick and dirty canonicalization - better should be in GLib
 
3034
       */
 
3035
 
 
3036
      if (!g_path_is_absolute (argv[i]))
 
3037
        {
 
3038
          char *cwd = g_get_current_dir ();
 
3039
          filename = g_strconcat (cwd, "/", argv[i], NULL);
 
3040
          g_free (cwd);
 
3041
        }
 
3042
      else
 
3043
        filename = argv[i];
 
3044
 
 
3045
      open_ok_func (filename, view);
 
3046
 
 
3047
      if (filename != argv[i])
 
3048
        g_free (filename);
 
3049
    }
 
3050
  pop_active_window ();
 
3051
  
 
3052
  gtk_main ();
 
3053
 
 
3054
  return 0;
 
3055
}
 
3056
 
 
3057