Parent Directory Parent Directory | Revision Log Revision Log


Revision 2185 - (show annotations)
Wed Feb 25 23:35:55 2009 UTC (10 months ago) by thomashpa
File MIME type: text/x-csrc
File size: 47768 byte(s)
Replace deprecated gtk symbol. Bug #572085
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
2 * test-widget.c
3 *
4 * Copyright (C) 2001
5 * Mikael Hermansson<tyan@linux.se>
6 *
7 * Copyright (C) 2003 - Gustavo Giráldez <gustavo.giraldez@gmx.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 /* If TEST_XML_MEM is defined the test program will try to detect memory
25 * allocated by xmlMalloc() but not freed by xmlFree() or freed by xmlFree()
26 * but not allocated by xmlMalloc(). */
27 #define TEST_XML_MEM
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <gtk/gtk.h>
33 #include <gio/gio.h>
34 #include <gtksourceview/gtksourceview.h>
35 #include <gtksourceview/gtksourcelanguage.h>
36 #include <gtksourceview/gtksourcelanguagemanager.h>
37 #include <gtksourceview/gtksourcestyleschememanager.h>
38 #include <gtksourceview/gtksourceprintcompositor.h>
39 #include <gtksourceview/gtksourceiter.h>
40 #ifdef TEST_XML_MEM
41 #include <libxml/xmlreader.h>
42 #endif
43
44 /* Global list of open windows */
45
46 static GList *windows = NULL;
47 static GtkSourceStyleScheme *style_scheme = NULL;
48
49 /* Private data structures */
50
51 #define READ_BUFFER_SIZE 4096
52
53 #define MARK_TYPE_1 "one"
54 #define MARK_TYPE_2 "two"
55
56
57 /* Private prototypes -------------------------------------------------------- */
58
59 static void open_file_cb (GtkAction *action,
60 gpointer user_data);
61 static void print_file_cb (GtkAction *action,
62 gpointer user_data);
63 static void find_cb (GtkAction *action,
64 gpointer user_data);
65 static void replace_cb (GtkAction *action,
66 gpointer user_data);
67
68 static void new_view_cb (GtkAction *action,
69 gpointer user_data);
70 static void numbers_toggled_cb (GtkAction *action,
71 gpointer user_data);
72 static void marks_toggled_cb (GtkAction *action,
73 gpointer user_data);
74 static void margin_toggled_cb (GtkAction *action,
75 gpointer user_data);
76 static void hl_bracket_toggled_cb (GtkAction *action,
77 gpointer user_data);
78 static void hl_line_toggled_cb (GtkAction *action,
79 gpointer user_data);
80 static void draw_spaces_toggled_cb (GtkAction *action,
81 gpointer user_data);
82 static void wrap_lines_toggled_cb (GtkAction *action,
83 gpointer user_data);
84 static void auto_indent_toggled_cb (GtkAction *action,
85 gpointer user_data);
86 static void insert_spaces_toggled_cb (GtkAction *action,
87 gpointer user_data);
88 static void tabs_toggled_cb (GtkAction *action,
89 GtkAction *current,
90 gpointer user_data);
91 static void indent_toggled_cb (GtkAction *action,
92 GtkAction *current,
93 gpointer user_data);
94
95 static GtkWidget *create_view_window (GtkSourceBuffer *buffer,
96 GtkSourceView *from);
97
98
99 /* Actions & UI definition ---------------------------------------------------- */
100
101 static GtkActionEntry buffer_action_entries[] = {
102 { "Open", GTK_STOCK_OPEN, "_Open", "<control>O",
103 "Open a file", G_CALLBACK (open_file_cb) },
104 { "Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q",
105 "Exit the application", G_CALLBACK (gtk_main_quit) }
106 };
107
108 static GtkActionEntry view_action_entries[] = {
109 { "FileMenu", NULL, "_File" },
110 { "Print", GTK_STOCK_PRINT, "_Print", "<control>P",
111 "Print the current file", G_CALLBACK (print_file_cb) },
112 { "ViewMenu", NULL, "_View" },
113 { "NewView", GTK_STOCK_NEW, "_New View", NULL,
114 "Create a new view of the file", G_CALLBACK (new_view_cb) },
115 { "TabWidth", NULL, "_Tab Width" },
116 { "IndentWidth", NULL, "I_ndent Width" },
117 { "SmartHomeEnd", NULL, "_Smart Home/End" },
118 { "Find", GTK_STOCK_FIND, "_Find", "<control>F",
119 "Find", G_CALLBACK (find_cb) },
120 { "Replace", GTK_STOCK_FIND_AND_REPLACE, "Search and _Replace", "<control>R",
121 "Search and Replace", G_CALLBACK (replace_cb) },
122 };
123
124 static GtkToggleActionEntry toggle_entries[] = {
125 { "HlBracket", NULL, "Highlight Matching _Bracket", NULL,
126 "Toggle highlighting of matching bracket",
127 G_CALLBACK (hl_bracket_toggled_cb), FALSE },
128 { "ShowNumbers", NULL, "Show _Line Numbers", NULL,
129 "Toggle visibility of line numbers in the left margin",
130 G_CALLBACK (numbers_toggled_cb), FALSE },
131 { "ShowMarks", NULL, "Show Line _Marks", NULL,
132 "Toggle visibility of marks in the left margin",
133 G_CALLBACK (marks_toggled_cb), FALSE },
134 { "ShowMargin", NULL, "Show Right M_argin", NULL,
135 "Toggle visibility of right margin indicator",
136 G_CALLBACK (margin_toggled_cb), FALSE },
137 { "HlLine", NULL, "_Highlight Current Line", NULL,
138 "Toggle highlighting of current line",
139 G_CALLBACK (hl_line_toggled_cb), FALSE },
140 { "DrawSpaces", NULL, "_Draw Spaces", NULL,
141 "Draw Spaces",
142 G_CALLBACK (draw_spaces_toggled_cb), FALSE },
143 { "WrapLines", NULL, "_Wrap Lines", NULL,
144 "Toggle line wrapping",
145 G_CALLBACK (wrap_lines_toggled_cb), FALSE },
146 { "AutoIndent", NULL, "Enable _Auto Indent", NULL,
147 "Toggle automatic auto indentation of text",
148 G_CALLBACK (auto_indent_toggled_cb), FALSE },
149 { "InsertSpaces", NULL, "Insert _Spaces Instead of Tabs", NULL,
150 "Whether to insert space characters when inserting tabulations",
151 G_CALLBACK (insert_spaces_toggled_cb), FALSE }
152 };
153
154 static GtkRadioActionEntry tabs_radio_entries[] = {
155 { "TabWidth4", NULL, "4", NULL, "Set tabulation width to 4 spaces", 4 },
156 { "TabWidth6", NULL, "6", NULL, "Set tabulation width to 6 spaces", 6 },
157 { "TabWidth8", NULL, "8", NULL, "Set tabulation width to 8 spaces", 8 },
158 { "TabWidth10", NULL, "10", NULL, "Set tabulation width to 10 spaces", 10 },
159 { "TabWidth12", NULL, "12", NULL, "Set tabulation width to 12 spaces", 12 }
160 };
161
162 static GtkRadioActionEntry indent_radio_entries[] = {
163 { "IndentWidthUnset", NULL, "Use Tab Width", NULL, "Set indent width same as tab width", -1 },
164 { "IndentWidth4", NULL, "4", NULL, "Set indent width to 4 spaces", 4 },
165 { "IndentWidth6", NULL, "6", NULL, "Set indent width to 6 spaces", 6 },
166 { "IndentWidth8", NULL, "8", NULL, "Set indent width to 8 spaces", 8 },
167 { "IndentWidth10", NULL, "10", NULL, "Set indent width to 10 spaces", 10 },
168 { "IndentWidth12", NULL, "12", NULL, "Set indent width to 12 spaces", 12 }
169 };
170
171 static GtkRadioActionEntry smart_home_end_entries[] = {
172 { "SmartHomeEndDisabled", NULL, "Disabled", NULL,
173 "Smart Home/End disabled", GTK_SOURCE_SMART_HOME_END_DISABLED },
174 { "SmartHomeEndBefore", NULL, "Before", NULL,
175 "Smart Home/End before", GTK_SOURCE_SMART_HOME_END_BEFORE },
176 { "SmartHomeEndAfter", NULL, "After", NULL,
177 "Smart Home/End after", GTK_SOURCE_SMART_HOME_END_AFTER },
178 { "SmartHomeEndAlways", NULL, "Always", NULL,
179 "Smart Home/End always", GTK_SOURCE_SMART_HOME_END_ALWAYS }
180 };
181
182 static const gchar *view_ui_description =
183 "<ui>"
184 " <menubar name=\"MainMenu\">"
185 " <menu action=\"FileMenu\">"
186 " <!--"
187 " <menuitem action=\"PrintPreview\"/>"
188 " -->"
189 " </menu>"
190 " <menu action=\"ViewMenu\">"
191 " <menuitem action=\"NewView\"/>"
192 " <separator/>"
193 " <menuitem action=\"HlBracket\"/>"
194 " <menuitem action=\"ShowNumbers\"/>"
195 " <menuitem action=\"ShowMarks\"/>"
196 " <menuitem action=\"ShowMargin\"/>"
197 " <menuitem action=\"HlLine\"/>"
198 " <menuitem action=\"DrawSpaces\"/>"
199 " <menuitem action=\"WrapLines\"/>"
200 " <separator/>"
201 " <menuitem action=\"AutoIndent\"/>"
202 " <menuitem action=\"InsertSpaces\"/>"
203 " <separator/>"
204 " <menu action=\"TabWidth\">"
205 " <menuitem action=\"TabWidth4\"/>"
206 " <menuitem action=\"TabWidth6\"/>"
207 " <menuitem action=\"TabWidth8\"/>"
208 " <menuitem action=\"TabWidth10\"/>"
209 " <menuitem action=\"TabWidth12\"/>"
210 " </menu>"
211 " <menu action=\"IndentWidth\">"
212 " <menuitem action=\"IndentWidthUnset\"/>"
213 " <menuitem action=\"IndentWidth4\"/>"
214 " <menuitem action=\"IndentWidth6\"/>"
215 " <menuitem action=\"IndentWidth8\"/>"
216 " <menuitem action=\"IndentWidth10\"/>"
217 " <menuitem action=\"IndentWidth12\"/>"
218 " </menu>"
219 " <separator/>"
220 " <menu action=\"SmartHomeEnd\">"
221 " <menuitem action=\"SmartHomeEndDisabled\"/>"
222 " <menuitem action=\"SmartHomeEndBefore\"/>"
223 " <menuitem action=\"SmartHomeEndAfter\"/>"
224 " <menuitem action=\"SmartHomeEndAlways\"/>"
225 " </menu>"
226 " </menu>"
227 " </menubar>"
228 "</ui>";
229
230 static const gchar *buffer_ui_description =
231 "<ui>"
232 " <menubar name=\"MainMenu\">"
233 " <menu action=\"FileMenu\">"
234 " <menuitem action=\"Open\"/>"
235 " <menuitem action=\"Print\"/>"
236 " <menuitem action=\"Find\"/>"
237 " <menuitem action=\"Replace\"/>"
238 " <separator/>"
239 " <menuitem action=\"Quit\"/>"
240 " </menu>"
241 " <menu action=\"ViewMenu\">"
242 " </menu>"
243 " </menubar>"
244 "</ui>";
245
246
247 /* File loading code ----------------------------------------------------------------- */
248
249 static void
250 error_dialog (GtkWindow *parent, const gchar *msg, ...)
251 {
252 va_list ap;
253 gchar *tmp;
254 GtkWidget *dialog;
255
256 va_start (ap, msg);
257 tmp = g_strdup_vprintf (msg, ap);
258 va_end (ap);
259
260 dialog = gtk_message_dialog_new (parent,
261 GTK_DIALOG_DESTROY_WITH_PARENT,
262 GTK_MESSAGE_ERROR,
263 GTK_BUTTONS_OK,
264 tmp);
265 g_free (tmp);
266
267 gtk_dialog_run (GTK_DIALOG (dialog));
268 gtk_widget_destroy (dialog);
269 }
270
271 static gboolean
272 gtk_source_buffer_load_file (GtkSourceBuffer *source_buffer,
273 const gchar *filename,
274 GError **error)
275 {
276 GtkTextIter iter;
277 gchar *buffer;
278 GError *error_here = NULL;
279
280 g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (source_buffer), FALSE);
281 g_return_val_if_fail (filename != NULL, FALSE);
282
283 if (!g_file_get_contents (filename, &buffer, NULL, &error_here))
284 {
285 error_dialog (NULL, "%s\nFile %s", error_here->message, filename);
286 g_propagate_error (error, error_here);
287 return FALSE;
288 }
289
290 gtk_source_buffer_begin_not_undoable_action (source_buffer);
291 gtk_text_buffer_set_text (GTK_TEXT_BUFFER (source_buffer), buffer, -1);
292 gtk_source_buffer_end_not_undoable_action (source_buffer);
293 gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (source_buffer), FALSE);
294
295 /* move cursor to the beginning */
296 gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (source_buffer), &iter);
297 gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (source_buffer), &iter);
298
299 {
300 GtkTextIter start, end;
301 char *text;
302 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (source_buffer), &start, &end);
303 text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (source_buffer), &start, &end, TRUE);
304 g_assert (!strcmp (text, buffer));
305 g_free (text);
306 }
307
308 g_free (buffer);
309 return TRUE;
310 }
311
312 static void
313 remove_all_marks (GtkSourceBuffer *buffer)
314 {
315 GtkTextIter s, e;
316
317 gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (buffer), &s, &e);
318
319 gtk_source_buffer_remove_source_marks (buffer, &s, &e, NULL);
320 }
321
322 static GtkSourceLanguage *
323 get_language_for_file (GtkTextBuffer *buffer, const gchar *filename)
324 {
325 GtkSourceLanguageManager *manager;
326 GtkSourceLanguage *language;
327 GtkTextIter start, end;
328 gchar *text;
329 gchar *content_type;
330 gboolean result_uncertain;
331
332 gtk_text_buffer_get_start_iter (buffer, &start);
333 if (gtk_text_buffer_get_char_count (buffer) < 1024)
334 gtk_text_buffer_get_end_iter (buffer, &end);
335 else
336 gtk_text_buffer_get_iter_at_offset (buffer, &end, 1024);
337 text = gtk_text_buffer_get_slice (buffer, &start, &end, TRUE);
338
339 content_type = g_content_type_guess (filename,
340 (guchar*) text,
341 strlen (text),
342 &result_uncertain);
343 if (result_uncertain)
344 {
345 g_free (content_type);
346 content_type = NULL;
347 }
348
349 manager = gtk_source_language_manager_get_default ();
350 language = gtk_source_language_manager_guess_language (manager,
351 filename,
352 content_type);
353
354 g_message ("Detected '%s' mime type for file %s, chose language %s",
355 content_type ? content_type : "(null)",
356 filename,
357 language ? gtk_source_language_get_id (language) : "(none)");
358
359 g_free (content_type);
360 g_free (text);
361 return language;
362 }
363
364 static GtkSourceLanguage *
365 get_language_by_id (const gchar *id)
366 {
367 GtkSourceLanguageManager *manager;
368 manager = gtk_source_language_manager_get_default ();
369 return gtk_source_language_manager_get_language (manager, id);
370 }
371
372 static GtkSourceLanguage *
373 get_language (GtkTextBuffer *buffer, const gchar *filename)
374 {
375 GtkSourceLanguage *language = NULL;
376 GtkTextIter start, end;
377 gchar *text;
378 gchar *lang_string;
379
380 gtk_text_buffer_get_start_iter (buffer, &start);
381 end = start;
382 gtk_text_iter_forward_line (&end);
383
384 #define LANG_STRING "gtk-source-lang:"
385 text = gtk_text_iter_get_slice (&start, &end);
386 lang_string = strstr (text, LANG_STRING);
387 if (lang_string != NULL)
388 {
389 gchar **tokens;
390
391 lang_string += strlen (LANG_STRING);
392 g_strchug (lang_string);
393
394 tokens = g_strsplit_set (lang_string, " \t\n", 2);
395
396 if (tokens != NULL && tokens[0] != NULL)
397 language = get_language_by_id (tokens[0]);
398
399 g_strfreev (tokens);
400 }
401
402 if (!language)
403 language = get_language_for_file (buffer, filename);
404
405 g_free (text);
406 return language;
407 }
408
409 static gboolean
410 open_file (GtkSourceBuffer *buffer, const gchar *filename)
411 {
412 GtkSourceLanguage *language = NULL;
413 gchar *freeme = NULL;
414 gboolean success = FALSE;
415
416 if (!g_path_is_absolute (filename))
417 {
418 gchar *curdir = g_get_current_dir ();
419 freeme = g_build_filename (curdir, filename, NULL);
420 filename = freeme;
421 g_free (curdir);
422 }
423
424 remove_all_marks (buffer);
425
426 success = gtk_source_buffer_load_file (buffer, filename, NULL);
427
428 if (!success)
429 goto out;
430
431 language = get_language (GTK_TEXT_BUFFER (buffer), filename);
432
433 if (language == NULL)
434 g_print ("No language found for file `%s'\n", filename);
435
436 gtk_source_buffer_set_language (buffer, language);
437 g_object_set_data_full (G_OBJECT (buffer),
438 "filename", g_strdup (filename),
439 (GDestroyNotify) g_free);
440
441 if (language != NULL)
442 {
443 gchar **styles;
444
445 styles = gtk_source_language_get_style_ids (language);
446
447 if (styles == NULL)
448 g_print ("No styles in language '%s'\n", gtk_source_language_get_name (language));
449 else
450 {
451 gchar **ids;
452 g_print ("Styles in in language '%s':\n", gtk_source_language_get_name (language));
453
454 ids = styles;
455
456 while (*ids != NULL)
457 {
458 const gchar *name;
459
460 name = gtk_source_language_get_style_name (language, *ids);
461
462 g_print ("- %s (name: '%s')\n", *ids, name);
463
464 ++ids;
465 }
466
467 g_strfreev (styles);
468 }
469
470 g_print("\n");
471 }
472 out:
473 g_free (freeme);
474 return success;
475 }
476
477
478 /* View action callbacks -------------------------------------------------------- */
479
480 static void
481 numbers_toggled_cb (GtkAction *action, gpointer user_data)
482 {
483 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
484 gtk_source_view_set_show_line_numbers (
485 GTK_SOURCE_VIEW (user_data),
486 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
487 }
488
489 static void
490 marks_toggled_cb (GtkAction *action, gpointer user_data)
491 {
492 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
493 gtk_source_view_set_show_line_marks (
494 GTK_SOURCE_VIEW (user_data),
495 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
496 }
497
498 static void
499 margin_toggled_cb (GtkAction *action, gpointer user_data)
500 {
501 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
502 gtk_source_view_set_show_right_margin (
503 GTK_SOURCE_VIEW (user_data),
504 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
505 }
506
507 static void
508 hl_bracket_toggled_cb (GtkAction *action, gpointer user_data)
509 {
510 GtkTextBuffer *buffer;
511 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
512 buffer = gtk_text_view_get_buffer (user_data);
513 gtk_source_buffer_set_highlight_matching_brackets (
514 GTK_SOURCE_BUFFER (buffer),
515 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
516 }
517
518 static void
519 hl_line_toggled_cb (GtkAction *action, gpointer user_data)
520 {
521 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
522 gtk_source_view_set_highlight_current_line (
523 GTK_SOURCE_VIEW (user_data),
524 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
525 }
526
527 static void
528 draw_spaces_toggled_cb (GtkAction *action, gpointer user_data)
529 {
530 gboolean draw_spaces;
531
532 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
533 draw_spaces = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
534
535 if (draw_spaces)
536 gtk_source_view_set_draw_spaces (GTK_SOURCE_VIEW (user_data),
537 GTK_SOURCE_DRAW_SPACES_ALL);
538 else
539 gtk_source_view_set_draw_spaces (GTK_SOURCE_VIEW (user_data),
540 0);
541 }
542
543 static void
544 wrap_lines_toggled_cb (GtkAction *action, gpointer user_data)
545 {
546 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
547 gtk_text_view_set_wrap_mode (user_data,
548 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) ?
549 GTK_WRAP_WORD : GTK_WRAP_NONE);
550 }
551
552 static void
553 auto_indent_toggled_cb (GtkAction *action,
554 gpointer user_data)
555 {
556 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
557 gtk_source_view_set_auto_indent (
558 GTK_SOURCE_VIEW (user_data),
559 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
560 }
561
562 static void
563 insert_spaces_toggled_cb (GtkAction *action,
564 gpointer user_data)
565 {
566 g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
567 gtk_source_view_set_insert_spaces_instead_of_tabs (
568 GTK_SOURCE_VIEW (user_data),
569 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
570 }
571
572 static void
573 tabs_toggled_cb (GtkAction *action,
574 GtkAction *current,
575 gpointer user_data)
576 {
577 g_return_if_fail (GTK_IS_RADIO_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
578 gtk_source_view_set_tab_width (
579 GTK_SOURCE_VIEW (user_data),
580 gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)));
581 }
582
583 static void
584 indent_toggled_cb (GtkAction *action,
585 GtkAction *current,
586 gpointer user_data)
587 {
588 g_return_if_fail (GTK_IS_RADIO_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
589 gtk_source_view_set_indent_width (
590 GTK_SOURCE_VIEW (user_data),
591 gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)));
592 }
593
594 static void
595 smart_home_end_toggled_cb (GtkAction *action,
596 GtkAction *current,
597 gpointer user_data)
598 {
599 g_return_if_fail (GTK_IS_RADIO_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
600 gtk_source_view_set_smart_home_end (
601 GTK_SOURCE_VIEW (user_data),
602 gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)));
603 }
604
605 static void
606 new_view_cb (GtkAction *action, gpointer user_data)
607 {
608 GtkSourceBuffer *buffer;
609 GtkSourceView *view;
610 GtkWidget *window;
611
612 g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
613
614 view = GTK_SOURCE_VIEW (user_data);
615 buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
616
617 window = create_view_window (buffer, view);
618 gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
619 gtk_widget_show (window);
620 }
621
622
623 /* Buffer action callbacks ------------------------------------------------------------ */
624
625 static struct {
626 char *what;
627 char *replacement;
628 GtkSourceSearchFlags flags;
629 } search_data = {
630 NULL,
631 NULL,
632 GTK_SOURCE_SEARCH_CASE_INSENSITIVE
633 };
634
635 static gboolean
636 search_dialog (GtkWidget *widget,
637 gboolean replace,
638 char **what_p,
639 char **replacement_p,
640 GtkSourceSearchFlags *flags_p)
641 {
642 GtkWidget *dialog;
643 GtkEntry *entry1, *entry2;
644 GtkToggleButton *case_sensitive;
645
646 dialog = gtk_dialog_new_with_buttons (replace ? "Replace" : "Find",
647 GTK_WINDOW (gtk_widget_get_toplevel (widget)),
648 GTK_DIALOG_MODAL,
649 GTK_STOCK_CANCEL,
650 GTK_RESPONSE_CANCEL,
651 GTK_STOCK_OK,
652 GTK_RESPONSE_OK,
653 NULL);
654 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
655
656 entry1 = g_object_new (GTK_TYPE_ENTRY,
657 "visible", TRUE,
658 "text", search_data.what ? search_data.what : "",
659 "activates-default", TRUE,
660 NULL);
661 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
662 GTK_WIDGET (entry1), TRUE, TRUE, 0);
663 entry2 = g_object_new (GTK_TYPE_ENTRY,
664 "visible", replace,
665 "text", search_data.replacement ? search_data.replacement : "",
666 "activates-default", TRUE,
667 NULL);
668 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
669 GTK_WIDGET (entry2), TRUE, TRUE, 0);
670
671 case_sensitive = g_object_new (GTK_TYPE_CHECK_BUTTON,
672 "visible", TRUE,
673 "label", "Case sensitive",
674 "active", !(search_data.flags & GTK_SOURCE_SEARCH_CASE_INSENSITIVE),
675 NULL);
676 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
677 GTK_WIDGET (case_sensitive), FALSE, FALSE, 0);
678
679 while (TRUE)
680 {
681 if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
682 {
683 gtk_widget_destroy (dialog);
684 return FALSE;
685 }
686
687 if (*gtk_entry_get_text (entry1))
688 break;
689 }
690
691 g_free (search_data.what);
692 *what_p = search_data.what = g_strdup (gtk_entry_get_text (entry1));
693 g_free (search_data.replacement);
694 *replacement_p = search_data.replacement = g_strdup (gtk_entry_get_text (entry2));
695 *flags_p = search_data.flags = gtk_toggle_button_get_active (case_sensitive) ?
696 0 : GTK_SOURCE_SEARCH_CASE_INSENSITIVE;
697
698 gtk_widget_destroy (dialog);
699 return TRUE;
700 }
701
702 static void
703 do_search_replace (GtkTextView *view,
704 gboolean replace)
705 {
706 GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
707 GtkTextIter iter;
708 char *what, *replacement;
709 GtkSourceSearchFlags flags;
710
711 if (!search_dialog (GTK_WIDGET (view), replace, &what, &replacement, &flags))
712 return;
713
714 if (replace)
715 {
716 gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
717
718 while (TRUE)
719 {
720 GtkTextIter match_start, match_end;
721
722 if (!gtk_source_iter_forward_search (&iter, what, flags,
723 &match_start,
724 &match_end,
725 NULL))
726 {
727 break;
728 }
729
730 gtk_text_buffer_delete (buffer, &match_start, &match_end);
731 gtk_text_buffer_insert (buffer, &match_start, replacement, -1);
732 iter = match_start;
733 }
734 }
735 else
736 {
737 GtkTextIter match_start, match_end;
738
739 gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
740
741 if (gtk_source_iter_forward_search (&iter, what, flags, &match_start, &match_end, NULL))
742 {
743 gtk_text_buffer_select_range (buffer, &match_start, &match_end);
744 }
745 else
746 {
747 GtkTextIter insert = iter;
748 gtk_text_buffer_get_start_iter (buffer, &iter);
749 if (gtk_source_iter_forward_search (&iter, what, flags, &match_start, &match_end, &insert))
750 gtk_text_buffer_select_range (buffer, &match_start, &match_end);
751 }
752 }
753 }
754
755 static void
756 find_cb (GtkAction *action,
757 gpointer user_data)
758 {
759 do_search_replace (user_data, FALSE);
760 }
761
762 static void
763 replace_cb (GtkAction *action,
764 gpointer user_data)
765 {
766 do_search_replace (user_data, TRUE);
767 }
768
769 static void
770 open_file_cb (GtkAction *action, gpointer user_data)
771 {
772 GtkWidget *chooser;
773 gint response;
774 static gchar *last_dir;
775
776 g_return_if_fail (GTK_IS_SOURCE_BUFFER (user_data));
777
778 chooser = gtk_file_chooser_dialog_new ("Open file...",
779 NULL,
780 GTK_FILE_CHOOSER_ACTION_OPEN,
781 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
782 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
783 NULL);
784
785 if (last_dir == NULL)
786 last_dir = g_strdup (TOP_SRCDIR "/gtksourceview");
787
788 if (last_dir != NULL && g_path_is_absolute (last_dir))
789 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
790 last_dir);
791
792 response = gtk_dialog_run (GTK_DIALOG (chooser));
793
794 if (response == GTK_RESPONSE_OK)
795 {
796 gchar *filename;
797
798 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
799
800 if (filename != NULL)
801 {
802 g_free (last_dir);
803 last_dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (chooser));
804 open_file (GTK_SOURCE_BUFFER (user_data), filename);
805 g_free (filename);
806 }
807 }
808
809 gtk_widget_destroy (chooser);
810 }
811
812 #define NON_BLOCKING_PAGINATION
813
814 #ifndef NON_BLOCKING_PAGINATION
815
816 static void
817 begin_print (GtkPrintOperation *operation,
818 GtkPrintContext *context,
819 GtkSourcePrintCompositor *compositor)
820 {
821 gint n_pages;
822
823 while (!gtk_source_print_compositor_paginate (compositor, context))
824 ;
825
826 n_pages = gtk_source_print_compositor_get_n_pages (compositor);
827 gtk_print_operation_set_n_pages (operation, n_pages);
828 }
829
830 #else
831
832 static gboolean
833 paginate (GtkPrintOperation *operation,
834 GtkPrintContext *context,
835 GtkSourcePrintCompositor *compositor)
836 {
837 g_print ("Pagination progress: %.2f %%\n", gtk_source_print_compositor_get_pagination_progress (compositor) * 100.0);
838
839 if (gtk_source_print_compositor_paginate (compositor, context))
840 {
841 gint n_pages;
842
843 g_assert (gtk_source_print_compositor_get_pagination_progress (compositor) == 1.0);
844 g_print ("Pagination progress: %.2f %%\n", gtk_source_print_compositor_get_pagination_progress (compositor) * 100.0);
845
846 n_pages = gtk_source_print_compositor_get_n_pages (compositor);
847 gtk_print_operation_set_n_pages (operation, n_pages);
848
849
850
851 return TRUE;
852 }
853
854 return FALSE;
855 }
856
857 #endif
858
859 #define ENABLE_CUSTOM_OVERLAY
860
861 static void
862 draw_page (GtkPrintOperation *operation,
863 GtkPrintContext *context,
864 gint page_nr,
865 GtkSourcePrintCompositor *compositor)
866 {
867 #ifdef ENABLE_CUSTOM_OVERLAY
868
869 /* This part of the code shows how to add a custom overlay to the
870 printed text generated by GtkSourcePrintCompositor */
871
872 cairo_t *cr;
873 PangoLayout *layout;
874 PangoFontDescription *desc;
875 PangoRectangle rect;
876
877
878 cr = gtk_print_context_get_cairo_context (context);
879
880 cairo_save (cr);
881
882 layout = gtk_print_context_create_pango_layout (context);
883
884 pango_layout_set_text (layout, "Draft", -1);
885
886 desc = pango_font_description_from_string ("Sans Bold 120");
887 pango_layout_set_font_description (layout, desc);
888 pango_font_description_free (desc);
889
890
891 pango_layout_get_extents (layout, NULL, &rect);
892
893 cairo_move_to (cr,
894 (gtk_print_context_get_width (context) - ((double) rect.width / (double) PANGO_SCALE)) / 2,
895 (gtk_print_context_get_height (context) - ((double) rect.height / (double) PANGO_SCALE)) / 2);
896
897 pango_cairo_layout_path (cr, layout);
898
899 /* Font Outline */
900 cairo_set_source_rgba (cr, 0.85, 0.85, 0.85, 0.80);
901 cairo_set_line_width (cr, 0.5);
902 cairo_stroke_preserve (cr);
903
904 /* Font Fill */
905 cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.60);
906 cairo_fill (cr);
907
908 g_object_unref (layout);
909 cairo_restore (cr);
910 #endif
911
912 /* To print page_nr you only need to call the following function */
913 gtk_source_print_compositor_draw_page (compositor, context, page_nr);
914 }
915
916 static void
917 end_print (GtkPrintOperation *operation,
918 GtkPrintContext *context,
919 GtkSourcePrintCompositor *compositor)
920 {
921 g_object_unref (compositor);
922 }
923
924 #define LINE_NUMBERS_FONT_NAME "Sans 8"
925 #define HEADER_FONT_NAME "Sans 11"
926 #define FOOTER_FONT_NAME "Sans 11"
927 #define BODY_FONT_NAME "Monospace 9"
928
929 /*
930 #define SETUP_FROM_VIEW
931 */
932
933 #undef SETUP_FROM_VIEW
934
935
936 static void
937 print_file_cb (GtkAction *action, gpointer user_data)
938 {
939 GtkSourceView *view;
940 GtkSourceBuffer *buffer;
941 GtkSourcePrintCompositor *compositor;
942 GtkPrintOperation *operation;
943 const gchar *filename;
944 gchar *basename;
945
946 g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
947
948 view = GTK_SOURCE_VIEW (user_data);
949
950 buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
951
952 filename = g_object_get_data (G_OBJECT (buffer), "filename");
953 basename = g_filename_display_basename (filename);
954
955 #ifdef SETUP_FROM_VIEW
956 compositor = gtk_source_print_compositor_new_from_view (view);
957 #else
958
959 compositor = gtk_source_print_compositor_new (buffer);
960
961 gtk_source_print_compositor_set_tab_width (compositor,
962 gtk_source_view_get_tab_width (view));
963
964 gtk_source_print_compositor_set_wrap_mode (compositor,
965 gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (view)));
966
967 gtk_source_print_compositor_set_print_line_numbers (compositor, 1);
968
969 gtk_source_print_compositor_set_body_font_name (compositor,
970 BODY_FONT_NAME);
971
972 /* To test line numbers font != text font */
973 gtk_source_print_compositor_set_line_numbers_font_name (compositor,
974 LINE_NUMBERS_FONT_NAME);
975
976 gtk_source_print_compositor_set_header_format (compositor,
977 TRUE,
978 "Printed on %A",
979 "test-widget",
980 "%F");
981
982 gtk_source_print_compositor_set_footer_format (compositor,
983 TRUE,
984 "%T",
985 basename,
986 "Page %N/%Q");
987
988 gtk_source_print_compositor_set_print_header (compositor, TRUE);
989 gtk_source_print_compositor_set_print_footer (compositor, TRUE);
990
991 gtk_source_print_compositor_set_header_font_name (compositor,
992 HEADER_FONT_NAME);
993
994 gtk_source_print_compositor_set_footer_font_name (compositor,
995 FOOTER_FONT_NAME);
996 #endif
997 operation = gtk_print_operation_new ();
998
999 gtk_print_operation_set_job_name (operation, basename);
1000
1001 gtk_print_operation_set_show_progress (operation, TRUE);
1002
1003 #ifndef NON_BLOCKING_PAGINATION
1004 g_signal_connect (G_OBJECT (operation), "begin-print",
1005 G_CALLBACK (begin_print), compositor);
1006 #else
1007 g_signal_connect (G_OBJECT (operation), "paginate",
1008 G_CALLBACK (paginate), compositor);
1009 #endif
1010 g_signal_connect (G_OBJECT (operation), "draw-page",
1011 G_CALLBACK (draw_page), compositor);
1012 g_signal_connect (G_OBJECT (operation), "end-print",
1013 G_CALLBACK (end_print), compositor);
1014
1015 gtk_print_operation_run (operation,
1016 GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
1017 NULL, NULL);
1018
1019 g_object_unref (operation);
1020 g_free (basename);
1021 }
1022
1023 /* View UI callbacks ------------------------------------------------------------------ */
1024
1025 static void
1026 update_cursor_position (GtkTextBuffer *buffer, gpointer user_data)
1027 {
1028 gchar *msg;
1029 gint row, col, chars, tabwidth;
1030 GtkTextIter iter, start;
1031 GtkSourceView *view;
1032 GtkLabel *pos_label;
1033
1034 g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
1035
1036 view = GTK_SOURCE_VIEW (user_data);
1037 tabwidth = gtk_source_view_get_tab_width (view);
1038 pos_label = GTK_LABEL (g_object_get_data (G_OBJECT (view), "pos_label"));
1039
1040 gtk_text_buffer_get_iter_at_mark (buffer,
1041 &iter,
1042 gtk_text_buffer_get_insert (buffer));
1043
1044 chars = gtk_text_iter_get_offset (&iter);
1045 row = gtk_text_iter_get_line (&iter) + 1;
1046
1047 start = iter;
1048 gtk_text_iter_set_line_offset (&start, 0);
1049 col = 0;
1050
1051 while (!gtk_text_iter_equal (&start, &iter))
1052 {
1053 if (gtk_text_iter_get_char (&start) == '\t')
1054 {
1055 col += (tabwidth - (col % tabwidth));
1056 }
1057 else
1058 ++col;
1059
1060 gtk_text_iter_forward_char (&start);
1061 }
1062
1063 msg = g_strdup_printf ("char: %d, line: %d, column: %d", chars, row, col);
1064 gtk_label_set_text (pos_label, msg);
1065 g_free (msg);
1066 }
1067
1068 static void
1069 move_cursor_cb (GtkTextBuffer *buffer,
1070 GtkTextIter *cursoriter,
1071 GtkTextMark *mark,
1072 gpointer user_data)
1073 {
1074 if (mark != gtk_text_buffer_get_insert (buffer))
1075 return;
1076
1077 update_cursor_position (buffer, user_data);
1078 }
1079
1080 static gboolean
1081 window_deleted_cb (GtkWidget *widget, GdkEvent *ev, gpointer user_data)
1082 {
1083 g_return_val_if_fail (GTK_IS_SOURCE_VIEW (user_data), TRUE);
1084
1085 if (g_list_nth_data (windows, 0) == widget)
1086 {
1087 /* Main (first in the list) window was closed, so exit
1088 * the application */
1089 gtk_main_quit ();
1090 }
1091 else
1092 {
1093 GtkSourceView *view = GTK_SOURCE_VIEW (user_data);
1094 GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (
1095 gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
1096
1097 windows = g_list_remove (windows, widget);
1098
1099 /* deinstall buffer motion signal handlers */
1100 g_signal_handlers_disconnect_matched (buffer,
1101 G_SIGNAL_MATCH_DATA,
1102 0, /* signal_id */
1103 0, /* detail */
1104 NULL, /* closure */
1105 NULL, /* func */
1106 user_data);
1107
1108 /* we return FALSE since we want the window destroyed */
1109 return FALSE;
1110 }
1111
1112 return TRUE;
1113 }
1114
1115 static gboolean
1116 button_press_cb (GtkWidget *widget, GdkEventButton *ev, gpointer user_data)
1117 {
1118 GtkSourceView *view;
1119 GtkSourceBuffer *buffer;
1120
1121 g_return_val_if_fail (GTK_IS_SOURCE_VIEW (widget), FALSE);
1122
1123 view = GTK_SOURCE_VIEW (widget);
1124 buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
1125
1126 if (!gtk_source_view_get_show_line_marks (view))
1127 return FALSE;
1128
1129 /* check that the click was on the left gutter */
1130 if (ev->window == gtk_text_view_get_window (GTK_TEXT_VIEW (view),
1131 GTK_TEXT_WINDOW_LEFT))
1132 {
1133 gint y_buf;
1134 GtkTextIter line_start;
1135 GSList *mark_list;
1136 const gchar *mark_type;
1137
1138 if (ev->button == 1)
1139 mark_type = MARK_TYPE_1;
1140 else
1141 mark_type = MARK_TYPE_2;
1142
1143 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
1144 GTK_TEXT_WINDOW_LEFT,
1145 ev->x, ev->y,
1146 NULL, &y_buf);
1147
1148 /* get line bounds */
1149 gtk_text_view_get_line_at_y (GTK_TEXT_VIEW (view),
1150 &line_start,
1151 y_buf,
1152 NULL);
1153
1154 /* get the marks already in the line */
1155 mark_list = gtk_source_buffer_get_source_marks_at_line (buffer,
1156 gtk_text_iter_get_line (&line_start),
1157 mark_type);
1158
1159 if (mark_list != NULL)
1160 {
1161 /* just take the first and delete it */
1162 gtk_text_buffer_delete_mark (GTK_TEXT_BUFFER (buffer),
1163 GTK_TEXT_MARK (mark_list->data));
1164 }
1165 else
1166 {
1167 /* no mark found: create one */
1168 gtk_source_buffer_create_source_mark (buffer,
1169 NULL,
1170 mark_type,
1171 &line_start);
1172 }
1173
1174 g_slist_free (mark_list);
1175 }
1176
1177 return FALSE;
1178 }
1179
1180
1181 /* Window creation functions -------------------------------------------------------- */
1182
1183 static GtkWidget *
1184 create_view_window (GtkSourceBuffer *buffer, GtkSourceView *from)
1185 {
1186 GtkWidget *window, *sw, *view, *vbox, *pos_label, *menu;
1187 PangoFontDescription *font_desc = NULL;
1188 GdkPixbuf *pixbuf;
1189 GtkAccelGroup *accel_group;
1190 GtkActionGroup *action_group;
1191 GtkUIManager *ui_manager;
1192 GError *error;
1193
1194 g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
1195 g_return_val_if_fail (from == NULL || GTK_IS_SOURCE_VIEW (from), NULL);
1196
1197 /* window */
1198 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1199 gtk_container_set_border_width (GTK_CONTAINER (window), 0);
1200 gtk_window_set_title (GTK_WINDOW (window), "GtkSourceView Demo");
1201 windows = g_list_append (windows, window);
1202
1203 /* view */
1204 view = gtk_source_view_new_with_buffer (buffer);
1205
1206 if (style_scheme)
1207 gtk_source_buffer_set_style_scheme (buffer, style_scheme);
1208
1209 g_signal_connect (buffer, "mark-set", G_CALLBACK (move_cursor_cb), view);
1210 g_signal_connect (buffer, "changed", G_CALLBACK (update_cursor_position), view);
1211 g_signal_connect (view, "button-press-event", G_CALLBACK (button_press_cb), NULL);
1212 g_signal_connect (window, "delete-event", (GCallback) window_deleted_cb, view);
1213
1214 /* action group and UI manager */
1215 action_group = gtk_action_group_new ("ViewActions");
1216 gtk_action_group_add_actions (action_group, view_action_entries,
1217 G_N_ELEMENTS (view_action_entries), view);
1218 gtk_action_group_add_toggle_actions (action_group, toggle_entries,
1219 G_N_ELEMENTS (toggle_entries), view);
1220 gtk_action_group_add_radio_actions (action_group, tabs_radio_entries,
1221 G_N_ELEMENTS (tabs_radio_entries),
1222 -1, G_CALLBACK (tabs_toggled_cb), view);
1223 gtk_action_group_add_radio_actions (action_group, indent_radio_entries,
1224 G_N_ELEMENTS (indent_radio_entries),
1225 -1, G_CALLBACK (indent_toggled_cb), view);
1226 gtk_action_group_add_radio_actions (action_group, smart_home_end_entries,
1227 G_N_ELEMENTS (smart_home_end_entries),
1228 -1, G_CALLBACK (smart_home_end_toggled_cb), view);
1229
1230 ui_manager = gtk_ui_manager_new ();
1231 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1232 g_object_unref (action_group);
1233
1234 /* save a reference to the ui manager in the window for later use */
1235 g_object_set_data_full (G_OBJECT (window), "ui_manager",
1236 ui_manager, (GDestroyNotify) g_object_unref);
1237
1238 accel_group = gtk_ui_manager_get_accel_group (ui_manager);
1239 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
1240
1241 error = NULL;
1242 if (!gtk_ui_manager_add_ui_from_string (ui_manager, view_ui_description, -1, &error))
1243 {
1244 g_message ("building view ui failed: %s", error->message);
1245 g_error_free (error);
1246 exit (1);
1247 }
1248
1249 /* misc widgets */
1250 vbox = gtk_vbox_new (0, FALSE);
1251 sw = gtk_scrolled_window_new (NULL, NULL);
1252 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
1253 GTK_SHADOW_IN);
1254 pos_label = gtk_label_new ("Position");
1255 g_object_set_data (G_OBJECT (view), "pos_label", pos_label);
1256 menu = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
1257
1258 /* layout widgets */
1259 gtk_container_add (GTK_CONTAINER (window), vbox);
1260 gtk_box_pack_start (GTK_BOX (vbox), menu, FALSE, FALSE, 0);
1261 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
1262 gtk_container_add (GTK_CONTAINER (sw), view);
1263 gtk_box_pack_start (GTK_BOX (vbox), pos_label, FALSE, FALSE, 0);
1264
1265 /* setup view */
1266 font_desc = pango_font_description_from_string ("monospace");
1267 if (font_desc != NULL)
1268 {
1269 gtk_widget_modify_font (view, font_desc);
1270 pango_font_description_free (font_desc);
1271 }
1272
1273 /* change view attributes to match those of from */
1274 if (from)
1275 {
1276 gchar *tmp;
1277 gint i;
1278 GtkAction *action;
1279
1280 action = gtk_action_group_get_action (action_group, "ShowNumbers");
1281 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1282 gtk_source_view_get_show_line_numbers (from));
1283
1284 action = gtk_action_group_get_action (action_group, "ShowMarks");
1285 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1286 gtk_source_view_get_show_line_marks (from));
1287
1288 action = gtk_action_group_get_action (action_group, "ShowMargin");
1289 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1290 gtk_source_view_get_show_right_margin (from));
1291
1292 action = gtk_action_group_get_action (action_group, "HlLine");
1293 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1294 gtk_source_view_get_highlight_current_line (from));
1295
1296 action = gtk_action_group_get_action (action_group, "WrapLines");
1297 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1298 gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (from)) != GTK_WRAP_NONE);
1299
1300 action = gtk_action_group_get_action (action_group, "AutoIndent");
1301 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1302 gtk_source_view_get_auto_indent (from));
1303
1304 action = gtk_action_group_get_action (action_group, "InsertSpaces");
1305 gtk_toggle_action_set_active (
1306 GTK_TOGGLE_ACTION (action),
1307 gtk_source_view_get_insert_spaces_instead_of_tabs (from));
1308
1309 tmp = g_strdup_printf ("TabWidth%d", gtk_source_view_get_tab_width (from));
1310 action = gtk_action_group_get_action (action_group, tmp);
1311 if (action)
1312 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1313 g_free (tmp);
1314
1315 i = gtk_source_view_get_indent_width (from);
1316 tmp = i < 0 ? g_strdup ("IndentWidthUnset") : g_strdup_printf ("IndentWidth%d", i);
1317 action = gtk_action_group_get_action (action_group, tmp);
1318 if (action)
1319 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1320 g_free (tmp);
1321 }
1322
1323 /* add source mark pixbufs */
1324 error = NULL;
1325 if ((pixbuf = gdk_pixbuf_new_from_file (TOP_SRCDIR "/tests/gnome-gmush.png", &error)))
1326 {
1327 GdkColor color;
1328 gdk_color_parse ("lightgreen", &color);
1329 gtk_source_view_set_mark_category_background (GTK_SOURCE_VIEW (view), MARK_TYPE_1, &color);
1330 gtk_source_view_set_mark_category_pixbuf (GTK_SOURCE_VIEW (view), MARK_TYPE_1, pixbuf);
1331 gtk_source_view_set_mark_category_priority (GTK_SOURCE_VIEW (view), MARK_TYPE_1, 1);
1332 g_object_unref (pixbuf);
1333 }
1334 else
1335 {
1336 g_message ("could not load source mark 1 image. Spurious messages might get triggered: %s\n",
1337 error->message);
1338 g_error_free (error);
1339 }
1340
1341 error = NULL;
1342 if ((pixbuf = gdk_pixbuf_new_from_file (TOP_SRCDIR "/tests/apple-red.png", &error)))
1343 {
1344 GdkColor color;
1345 gdk_color_parse ("pink", &color);
1346 gtk_source_view_set_mark_category_background (GTK_SOURCE_VIEW (view), MARK_TYPE_2, &color);
1347 gtk_source_view_set_mark_category_pixbuf (GTK_SOURCE_VIEW (view), MARK_TYPE_2, pixbuf);
1348 gtk_source_view_set_mark_category_priority (GTK_SOURCE_VIEW (view), MARK_TYPE_2, 2);
1349 g_object_unref (pixbuf);
1350 }
1351 else
1352 {
1353 g_message ("could not load source mark 2 image. Spurious messages might get triggered: %s\n",
1354 error->message);
1355 g_error_free (error);
1356 }
1357
1358 gtk_widget_show_all (vbox);
1359
1360 return window;
1361 }
1362
1363 static GtkWidget *
1364 create_main_window (GtkSourceBuffer *buffer)
1365 {
1366 GtkWidget *window;
1367 GtkAction *action;
1368 GtkUIManager *ui_manager;
1369 GtkActionGroup *action_group;
1370 GList *groups;
1371 GError *error;
1372
1373 window = create_view_window (buffer, NULL);
1374 ui_manager = g_object_get_data (G_OBJECT (window), "ui_manager");
1375
1376 /* buffer action group */
1377 action_group = gtk_action_group_new ("BufferActions");
1378 gtk_action_group_add_actions (action_group, buffer_action_entries,
1379 G_N_ELEMENTS (buffer_action_entries), buffer);
1380 gtk_ui_manager_insert_action_group (ui_manager, action_group, 1);
1381 g_object_unref (action_group);
1382
1383 /* merge buffer ui */
1384 error = NULL;
1385 if (!gtk_ui_manager_add_ui_from_string (ui_manager, buffer_ui_description, -1, &error))
1386 {
1387 g_message ("building buffer ui failed: %s", error->message);
1388 g_error_free (error);
1389 exit (1);
1390 }
1391
1392 /* preselect menu checkitems */
1393 groups = gtk_ui_manager_get_action_groups (ui_manager);
1394 /* retrieve the view action group at position 0 in the list */
1395 action_group = g_list_nth_data (groups, 0);
1396
1397 action = gtk_action_group_get_action (action_group, "HlBracket");
1398 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1399
1400 action = gtk_action_group_get_action (action_group, "ShowNumbers");
1401 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1402
1403 action = gtk_action_group_get_action (action_group, "ShowMarks");
1404 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1405
1406 action = gtk_action_group_get_action (action_group, "ShowMargin");
1407 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
1408
1409 action = gtk_action_group_get_action (action_group, "AutoIndent");
1410 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1411
1412 action = gtk_action_group_get_action (action_group, "InsertSpaces");
1413 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
1414
1415 action = gtk_action_group_get_action (action_group, "TabWidth8");
1416 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1417
1418 action = gtk_action_group_get_action (action_group, "IndentWidthUnset");
1419 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1420
1421 return window;
1422 }
1423
1424
1425 /* XML memory management and verification functions ----------------------------- */
1426
1427 #ifdef TEST_XML_MEM
1428
1429 #define ALIGN 8
1430
1431 /* my_free(malloc(n)) and free(my_malloc(n)) are invalid and
1432 * abort on glibc */
1433
1434 static gpointer
1435 my_malloc (gsize n_bytes)
1436 {
1437 char *mem = malloc (n_bytes + ALIGN);
1438 return mem ? mem + ALIGN : NULL;
1439 }
1440
1441 static gpointer
1442 my_realloc (gpointer mem,
1443 gsize n_bytes)
1444 {
1445 if (mem)
1446 {
1447 char *new_mem = realloc ((char*) mem - ALIGN, n_bytes + ALIGN);
1448 return new_mem ? new_mem + ALIGN : NULL;
1449 }
1450 else
1451 {
1452 return my_malloc (n_bytes);
1453 }
1454 }
1455
1456 static char *
1457 my_strdup (const char *s)
1458 {
1459 if (s)
1460 {
1461 char *new_s = my_malloc (strlen (s) + 1);
1462 strcpy (new_s, s);
1463 return new_s;
1464 }
1465 else
1466 {
1467 return NULL;
1468 }
1469 }
1470
1471 static void
1472 my_free (gpointer mem)
1473 {
1474 if (mem)
1475 free ((char*) mem - ALIGN);
1476 }
1477
1478 static void
1479 init_mem_stuff (void)
1480 {
1481 if (1)
1482 {
1483 if (xmlMemSetup (my_free, my_malloc, my_realloc, my_strdup) != 0)
1484 g_warning ("xmlMemSetup() failed");
1485 }
1486 else
1487 {
1488 GMemVTable mem_table = {
1489 my_malloc,
1490 my_realloc,
1491 my_free,
1492 NULL, NULL, NULL
1493 };
1494
1495 g_mem_set_vtable (&mem_table);
1496 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE);
1497 }
1498 }
1499
1500 #endif /* TEST_XML_MEM */
1501
1502
1503 /* Program entry point ------------------------------------------------------------ */
1504
1505 int
1506 main (int argc, char *argv[])
1507 {
1508 GtkWidget *window;
1509 GtkSourceLanguageManager *lm;
1510 GtkSourceStyleSchemeManager *sm;
1511 GtkSourceBuffer *buffer;
1512
1513 gchar *builtin_lang_dirs[] = {TOP_SRCDIR "/gtksourceview/language-specs", NULL};
1514 gchar *builtin_sm_dirs[] = {TOP_SRCDIR "/gtksourceview/language-specs", NULL};
1515 gchar **lang_dirs;
1516 const gchar * const * schemes;
1517 gboolean use_default_paths = FALSE;
1518
1519 gchar *style_scheme_id = NULL;
1520 GOptionContext *context;
1521
1522 GOptionEntry entries[] = {
1523 { "style-scheme", 's', 0, G_OPTION_ARG_STRING, &style_scheme_id, "Style scheme name to use", "SCHEME"},
1524 { "default-paths", 'd', 0, G_OPTION_ARG_NONE, &use_default_paths, "Use default search paths", NULL},
1525 { NULL }
1526 };
1527
1528 #ifdef TEST_XML_MEM
1529 init_mem_stuff ();
1530 #endif
1531
1532 context = g_option_context_new ("- test GtkSourceView widget");
1533 g_option_context_add_main_entries (context, entries, NULL);
1534 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1535 g_option_context_parse (context, &argc, &argv, NULL);
1536
1537 // gdk_window_set_debug_updates (TRUE);
1538
1539 /* we do not use defaults so we don't need to install the library */
1540 lang_dirs = use_default_paths ? NULL : builtin_lang_dirs;
1541 lm = gtk_source_language_manager_get_default ();
1542 gtk_source_language_manager_set_search_path (lm, lang_dirs);
1543
1544 lang_dirs = use_default_paths ? NULL : builtin_sm_dirs;
1545
1546 sm = gtk_source_style_scheme_manager_get_default ();
1547 gtk_source_style_scheme_manager_set_search_path (sm, lang_dirs);
1548
1549 if (!use_default_paths)
1550 gtk_source_style_scheme_manager_append_search_path (sm, TOP_SRCDIR "/tests/test-scheme.xml");
1551
1552 schemes = gtk_source_style_scheme_manager_get_scheme_ids (sm);
1553 g_print ("Available style schemes:\n");
1554 while (*schemes != NULL)
1555 {
1556 const gchar* const *authors;
1557 gchar *authors_str = NULL;
1558
1559 style_scheme = gtk_source_style_scheme_manager_get_scheme (sm, *schemes);
1560
1561 authors = gtk_source_style_scheme_get_authors (style_scheme);
1562 if (authors != NULL)
1563 authors_str = g_strjoinv (", ", (gchar **)authors);
1564
1565 g_print (" - [%s] %s: %s\n",
1566 gtk_source_style_scheme_get_id (style_scheme),
1567 gtk_source_style_scheme_get_name (style_scheme),
1568 gtk_source_style_scheme_get_description (style_scheme) ?
1569 gtk_source_style_scheme_get_description (style_scheme) : "");
1570
1571 if (authors_str) {
1572 g_print (" by %s\n", authors_str);
1573 g_free (authors_str);
1574 }
1575
1576 ++schemes;
1577 }
1578 g_print("\n");
1579
1580 if (style_scheme_id != NULL)
1581 style_scheme = gtk_source_style_scheme_manager_get_scheme (sm, style_scheme_id);
1582 else
1583 style_scheme = NULL;
1584
1585 /* create buffer */
1586 buffer = gtk_source_buffer_new (NULL);
1587
1588 if (argc > 1)
1589 open_file (buffer, argv [1]);
1590 else
1591 open_file (buffer, TOP_SRCDIR "/gtksourceview/gtksourcebuffer.c");
1592
1593 /* create first window */
1594 window = create_main_window (buffer);
1595 gtk_window_set_default_size (GTK_WINDOW (window), 500, 500);
1596 gtk_widget_show (window);
1597
1598 /* ... and action! */
1599 gtk_main ();
1600
1601 /* cleanup */
1602 g_list_foreach (windows, (GFunc) gtk_widget_destroy, NULL);
1603 g_list_free (windows);
1604 g_object_unref (buffer);
1605
1606 g_free (style_scheme_id);
1607
1608 return 0;
1609 }

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision
svn:mime-type text/x-csrc