Parent Directory
|
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)
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 |