source: trunk/third/gtksourceview/tests/test-widget.c @ 20969

Revision 20969, 28.0 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20968, which included commits to RCS files with non-trunk default branches.
Line 
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#include <stdio.h>
25#include <string.h>
26#include <gtk/gtk.h>
27#include <libgnomevfs/gnome-vfs-init.h>
28#include <libgnomevfs/gnome-vfs-mime-utils.h>
29#include <libgnomevfs/gnome-vfs-utils.h>
30#include <libgnomeprintui/gnome-print-job-preview.h>
31#include <gtksourceview/gtksourceview.h>
32#include <gtksourceview/gtksourcelanguage.h>
33#include <gtksourceview/gtksourcelanguagesmanager.h>
34#include <gtksourceview/gtksourceprintjob.h>
35
36
37/* Global list of open windows */
38
39static GList *windows = NULL;
40
41
42/* Private data structures */
43
44#define READ_BUFFER_SIZE   4096
45
46#define MARKER_TYPE_1      "one"
47#define MARKER_TYPE_2      "two"
48
49
50/* Private prototypes -------------------------------------------------------- */
51
52static void       open_file_cb                   (GtkAction       *action,
53                                                  gpointer         user_data);
54
55static void       new_view_cb                    (GtkAction       *action,
56                                                  gpointer         user_data);
57static void       numbers_toggled_cb             (GtkAction       *action,
58                                                  gpointer         user_data);
59static void       markers_toggled_cb             (GtkAction       *action,
60                                                  gpointer         user_data);
61static void       margin_toggled_cb              (GtkAction       *action,
62                                                  gpointer         user_data);
63static void       auto_indent_toggled_cb         (GtkAction       *action,
64                                                  gpointer         user_data);
65static void       insert_spaces_toggled_cb       (GtkAction       *action,
66                                                  gpointer         user_data);
67static void       tabs_toggled_cb                (GtkAction       *action,
68                                                  GtkAction       *current,
69                                                  gpointer         user_data);
70static void       print_preview_cb               (GtkAction       *action,
71                                                  gpointer         user_data);
72
73static GtkWidget *create_view_window             (GtkSourceBuffer *buffer,
74                                                  GtkSourceView   *from);
75
76
77/* Actions & UI definition ---------------------------------------------------- */
78
79static GtkActionEntry buffer_action_entries[] = {
80        { "Open", GTK_STOCK_OPEN, "_Open", "<control>O",
81          "Open a file", G_CALLBACK (open_file_cb) },
82        { "Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q",
83          "Exit the application", G_CALLBACK (gtk_main_quit) },
84};
85
86static GtkActionEntry view_action_entries[] = {
87        { "FileMenu", NULL, "_File" },
88        { "ViewMenu", NULL, "_View" },
89        { "PrintPreview", GTK_STOCK_PRINT, "_Print Preview", "<control>P",
90          "Preview printing of the file", G_CALLBACK (print_preview_cb) },
91        { "NewView", GTK_STOCK_NEW, "_New View", NULL,
92          "Create a new view of the file", G_CALLBACK (new_view_cb) },
93        { "TabsWidth", NULL, "_Tabs Width" },
94};
95
96static GtkToggleActionEntry toggle_entries[] = {
97        { "ShowNumbers", NULL, "Show _Line Numbers", NULL,
98          "Toggle visibility of line numbers in the left margin",
99          G_CALLBACK (numbers_toggled_cb), FALSE },
100        { "ShowMarkers", NULL, "Show _Markers", NULL,
101          "Toggle visibility of markers in the left margin",
102          G_CALLBACK (markers_toggled_cb), FALSE },
103        { "ShowMargin", NULL, "Show M_argin", NULL,
104          "Toggle visibility of right margin indicator",
105          G_CALLBACK (margin_toggled_cb), FALSE },
106        { "AutoIndent", NULL, "Enable _Auto Indent", NULL,
107          "Toggle automatic auto indentation of text",
108          G_CALLBACK (auto_indent_toggled_cb), FALSE },
109        { "InsertSpaces", NULL, "Insert _Spaces Instead of Tabs", NULL,
110          "Whether to insert space characters when inserting tabulations",
111          G_CALLBACK (insert_spaces_toggled_cb), FALSE }
112};
113
114static GtkRadioActionEntry radio_entries[] = {
115        { "TabsWidth4", NULL, "4", NULL, "Set tabulation width to 4 spaces", 4 },
116        { "TabsWidth6", NULL, "6", NULL, "Set tabulation width to 6 spaces", 6 },
117        { "TabsWidth8", NULL, "8", NULL, "Set tabulation width to 8 spaces", 8 },
118        { "TabsWidth10", NULL, "10", NULL, "Set tabulation width to 10 spaces", 10 },
119        { "TabsWidth12", NULL, "12", NULL, "Set tabulation width to 12 spaces", 12 }
120};
121
122static const gchar *view_ui_description =
123"<ui>"
124"  <menubar name=\"MainMenu\">"
125"    <menu action=\"FileMenu\">"
126"      <menuitem action=\"PrintPreview\"/>"
127"    </menu>"
128"    <menu action=\"ViewMenu\">"
129"      <menuitem action=\"NewView\"/>"
130"      <separator/>"
131"      <menuitem action=\"ShowNumbers\"/>"
132"      <menuitem action=\"ShowMarkers\"/>"
133"      <menuitem action=\"ShowMargin\"/>"
134"      <separator/>"
135"      <menuitem action=\"AutoIndent\"/>"
136"      <menuitem action=\"InsertSpaces\"/>"
137"      <separator/>"
138"      <menu action=\"TabsWidth\">"
139"        <menuitem action=\"TabsWidth4\"/>"
140"        <menuitem action=\"TabsWidth6\"/>"
141"        <menuitem action=\"TabsWidth8\"/>"
142"        <menuitem action=\"TabsWidth10\"/>"
143"        <menuitem action=\"TabsWidth12\"/>"
144"      </menu>"
145"    </menu>"
146"  </menubar>"
147"</ui>";
148
149static const gchar *buffer_ui_description =
150"<ui>"
151"  <menubar name=\"MainMenu\">"
152"    <menu action=\"FileMenu\">"
153"      <menuitem action=\"Open\"/>"
154"      <separator/>"
155"      <menuitem action=\"Quit\"/>"
156"    </menu>"
157"    <menu action=\"ViewMenu\">"
158"    </menu>"
159"  </menubar>"
160"</ui>";
161
162
163/* File loading code ----------------------------------------------------------------- */
164
165static void
166error_dialog (GtkWindow *parent, const gchar *msg, ...)
167{
168        va_list ap;
169        gchar *tmp;
170        GtkWidget *dialog;
171       
172        va_start (ap, msg);
173        tmp = g_strdup_vprintf (msg, ap);
174        va_end (ap);
175       
176        dialog = gtk_message_dialog_new (parent,
177                                         GTK_DIALOG_DESTROY_WITH_PARENT,
178                                         GTK_MESSAGE_ERROR,
179                                         GTK_BUTTONS_OK,
180                                         tmp);
181        g_free (tmp);
182       
183        gtk_dialog_run (GTK_DIALOG (dialog));
184        gtk_widget_destroy (dialog);
185}
186
187static gboolean
188gtk_source_buffer_load_with_encoding (GtkSourceBuffer *source_buffer,
189                                      const gchar     *filename,
190                                      const gchar     *encoding,
191                                      GError         **error)
192{
193        GIOChannel *io;
194        GtkTextIter iter;
195        gchar *buffer;
196        gboolean reading;
197       
198        g_return_val_if_fail (source_buffer != NULL, FALSE);
199        g_return_val_if_fail (filename != NULL, FALSE);
200        g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (source_buffer), FALSE);
201
202        *error = NULL;
203
204        io = g_io_channel_new_file (filename, "r", error);
205        if (!io)
206        {
207                error_dialog (NULL, "%s\nFile %s", (*error)->message, filename);
208                return FALSE;
209        }
210
211        if (g_io_channel_set_encoding (io, encoding, error) != G_IO_STATUS_NORMAL)
212        {
213                error_dialog (NULL, "Failed to set encoding:\n%s\n%s",
214                              filename, (*error)->message);
215                return FALSE;
216        }
217
218        gtk_source_buffer_begin_not_undoable_action (source_buffer);
219
220        gtk_text_buffer_set_text (GTK_TEXT_BUFFER (source_buffer), "", 0);
221        buffer = g_malloc (READ_BUFFER_SIZE);
222        reading = TRUE;
223        while (reading)
224        {
225                gsize bytes_read;
226                GIOStatus status;
227               
228                status = g_io_channel_read_chars (io, buffer,
229                                                  READ_BUFFER_SIZE, &bytes_read,
230                                                  error);
231                switch (status)
232                {
233                        case G_IO_STATUS_EOF:
234                                reading = FALSE;
235                                /* fall through */
236                               
237                        case G_IO_STATUS_NORMAL:
238                                if (bytes_read == 0)
239                                {
240                                        continue;
241                                }
242                               
243                                gtk_text_buffer_get_end_iter (
244                                        GTK_TEXT_BUFFER (source_buffer), &iter);
245                                gtk_text_buffer_insert (GTK_TEXT_BUFFER (source_buffer),
246                                                        &iter, buffer, bytes_read);
247                                break;
248                               
249                        case G_IO_STATUS_AGAIN:
250                                continue;
251
252                        case G_IO_STATUS_ERROR:
253                        default:
254                                error_dialog (NULL, "%s\nFile %s", (*error)->message, filename);
255
256                                /* because of error in input we clear already loaded text */
257                                gtk_text_buffer_set_text (GTK_TEXT_BUFFER (source_buffer), "", 0);
258                               
259                                reading = FALSE;
260                                break;
261                }
262        }
263        g_free (buffer);
264       
265        gtk_source_buffer_end_not_undoable_action (source_buffer);
266
267        g_io_channel_unref (io);
268
269        if (*error)
270                return FALSE;
271
272        gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (source_buffer), FALSE);
273
274        /* move cursor to the beginning */
275        gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (source_buffer), &iter);
276        gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (source_buffer), &iter);
277
278        return TRUE;
279}
280
281static void
282remove_all_markers (GtkSourceBuffer *buffer)
283{
284        GSList *markers;
285        GtkTextIter begin, end;
286
287        gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (buffer), &begin, &end);
288        markers = gtk_source_buffer_get_markers_in_region (buffer, &begin, &end);
289        while (markers)
290        {
291                GtkSourceMarker *marker = markers->data;
292               
293                gtk_source_buffer_delete_marker (buffer, marker);
294                markers = g_slist_delete_link (markers, markers);
295        }
296}
297
298static gboolean
299open_file (GtkSourceBuffer *buffer, const gchar *filename)
300{
301        GtkSourceLanguagesManager *manager;
302        GtkSourceLanguage *language = NULL;
303        gchar *mime_type;
304        GError *err = NULL;
305        gchar *uri;
306               
307        /* get the new language for the file mimetype */
308        manager = g_object_get_data (G_OBJECT (buffer), "languages-manager");
309
310        /* I hate this! */
311        if (g_path_is_absolute (filename))
312        {
313                uri = gnome_vfs_get_uri_from_local_path (filename);
314        }
315        else
316        {
317                gchar *curdir, *path;
318               
319                curdir = g_get_current_dir ();
320                path = g_strconcat (curdir, "/", filename, NULL);
321                g_free (curdir);
322                uri = gnome_vfs_get_uri_from_local_path (path);
323                g_free (path);
324        }
325
326        mime_type = gnome_vfs_get_mime_type (uri);
327        g_free (uri);
328        if (mime_type)
329        {
330                language = gtk_source_languages_manager_get_language_from_mime_type (manager,
331                                                                                     mime_type);
332
333                if (language == NULL)
334                {
335                        g_print ("No language found for mime type `%s'\n", mime_type);
336                        g_object_set (G_OBJECT (buffer), "highlight", FALSE, NULL);
337                }
338                else
339                {       
340                        g_object_set (G_OBJECT (buffer), "highlight", TRUE, NULL);
341
342                        gtk_source_buffer_set_language (buffer, language);
343                }
344                       
345                g_free (mime_type);
346        }
347        else
348        {
349                g_object_set (G_OBJECT (buffer), "highlight", FALSE, NULL);
350
351                g_warning ("Couldn't get mime type for file `%s'", filename);
352        }
353
354        remove_all_markers (buffer);
355        gtk_source_buffer_load_with_encoding (buffer, filename, "utf-8", &err);
356        g_object_set_data_full (G_OBJECT (buffer),
357                                "filename", g_strdup (filename),
358                                (GDestroyNotify) g_free);
359
360        if (err != NULL)
361        {
362                g_error_free (err);
363                return FALSE;
364        }
365        return TRUE;
366}
367
368
369/* Printing callbacks --------------------------------------------------------- */
370
371static void
372page_cb (GtkSourcePrintJob *job, gpointer user_data)
373{
374        g_print ("Printing %.2f%%    \r",
375                 100.0 * gtk_source_print_job_get_page (job) /
376                 gtk_source_print_job_get_page_count (job));
377}
378
379static void
380finished_cb (GtkSourcePrintJob *job, gpointer user_data)
381{
382        GnomePrintJob *gjob;
383        GtkWidget *preview;
384
385        g_print ("\n");
386        gjob = gtk_source_print_job_get_print_job (job);
387        preview = gnome_print_job_preview_new (gjob, "test-widget print preview");
388        g_object_unref (gjob);
389        g_object_unref (job);
390       
391        gtk_widget_show (preview);
392}
393
394
395/* View action callbacks -------------------------------------------------------- */
396
397static void
398numbers_toggled_cb (GtkAction *action, gpointer user_data)
399{
400        g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
401        gtk_source_view_set_show_line_numbers (
402                GTK_SOURCE_VIEW (user_data),
403                gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
404}
405
406static void
407markers_toggled_cb (GtkAction *action, gpointer user_data)
408{
409        g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
410        gtk_source_view_set_show_line_markers (
411                GTK_SOURCE_VIEW (user_data),
412                gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
413}
414
415static void
416margin_toggled_cb (GtkAction *action, gpointer user_data)
417{
418        g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
419        gtk_source_view_set_show_margin (
420                GTK_SOURCE_VIEW (user_data),
421                gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
422}
423
424static void
425auto_indent_toggled_cb (GtkAction *action,
426                        gpointer   user_data)
427{
428        g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
429        gtk_source_view_set_auto_indent (
430                GTK_SOURCE_VIEW (user_data),
431                gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
432}
433
434static void
435insert_spaces_toggled_cb (GtkAction *action,
436                          gpointer   user_data)
437{
438        g_return_if_fail (GTK_IS_TOGGLE_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
439        gtk_source_view_set_insert_spaces_instead_of_tabs (
440                GTK_SOURCE_VIEW (user_data),
441                gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
442}
443
444static void
445tabs_toggled_cb (GtkAction *action,
446                 GtkAction *current,
447                 gpointer user_data)
448{
449        g_return_if_fail (GTK_IS_RADIO_ACTION (action) && GTK_IS_SOURCE_VIEW (user_data));
450        gtk_source_view_set_tabs_width (
451                GTK_SOURCE_VIEW (user_data),
452                gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)));
453}
454
455static void
456new_view_cb (GtkAction *action, gpointer user_data)
457{
458        GtkSourceBuffer *buffer;
459        GtkSourceView *view;
460        GtkWidget *window;
461       
462        g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
463
464        view = GTK_SOURCE_VIEW (user_data);
465        buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
466
467        window = create_view_window (buffer, view);
468        gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
469        gtk_widget_show (window);
470}
471
472static void
473print_preview_cb (GtkAction *action, gpointer user_data)
474{
475        GtkSourcePrintJob *job;
476        GtkSourceView *view;
477        GtkSourceBuffer *buffer;
478        GtkTextIter start, end;
479        gchar *filename;
480
481        g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
482       
483        view = GTK_SOURCE_VIEW (user_data);
484        buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (user_data)));
485       
486        job = gtk_source_print_job_new (NULL);
487        gtk_source_print_job_setup_from_view (job, view);
488        gtk_source_print_job_set_wrap_mode (job, GTK_WRAP_CHAR);
489        gtk_source_print_job_set_highlight (job, TRUE);
490        gtk_source_print_job_set_print_numbers (job, 5);
491
492        gtk_source_print_job_set_header_format (job,
493                                                "Printed on %A",
494                                                NULL,
495                                                "%F",
496                                                TRUE);
497
498        filename = g_object_get_data (G_OBJECT (buffer), "filename");
499       
500        gtk_source_print_job_set_footer_format (job,
501                                                "%T",
502                                                filename,
503                                                "Page %N/%Q",
504                                                TRUE);
505
506        gtk_source_print_job_set_print_header (job, TRUE);
507        gtk_source_print_job_set_print_footer (job, TRUE);
508       
509        gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (buffer), &start, &end);
510        if (gtk_source_print_job_print_range_async (job, &start, &end))
511        {
512                g_signal_connect (job, "begin_page", (GCallback) page_cb, NULL);
513                g_signal_connect (job, "finished", (GCallback) finished_cb, NULL);
514        }
515        else
516        {
517                g_warning ("Async print failed");
518        }
519}
520
521
522/* Buffer action callbacks ------------------------------------------------------------ */
523
524static void
525open_file_cb (GtkAction *action, gpointer user_data)
526{
527        GtkWidget *chooser;
528        gint response;
529
530        g_return_if_fail (GTK_IS_SOURCE_BUFFER (user_data));
531       
532        chooser = gtk_file_chooser_dialog_new ("Open file...",
533                                               NULL,
534                                               GTK_FILE_CHOOSER_ACTION_OPEN,
535                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
536                                               GTK_STOCK_OPEN, GTK_RESPONSE_OK,
537                                               NULL);
538
539        response = gtk_dialog_run (GTK_DIALOG (chooser));
540        if (response == GTK_RESPONSE_OK)
541        {
542                gchar *filename;
543
544                filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
545                if (filename != NULL)
546                {
547                        open_file (GTK_SOURCE_BUFFER (user_data), filename);
548                        g_free (filename);
549                }
550        }
551       
552        gtk_widget_destroy (chooser);
553}
554
555
556/* View UI callbacks ------------------------------------------------------------------ */
557
558static void
559update_cursor_position (GtkTextBuffer *buffer, gpointer user_data)
560{
561        gchar *msg;
562        gint row, col, chars, tabwidth;
563        GtkTextIter iter, start;
564        GtkSourceView *view;
565        GtkLabel *pos_label;
566
567        g_return_if_fail (GTK_IS_SOURCE_VIEW (user_data));
568       
569        view = GTK_SOURCE_VIEW (user_data);
570        tabwidth = gtk_source_view_get_tabs_width (view);
571        pos_label = GTK_LABEL (g_object_get_data (G_OBJECT (view), "pos_label"));
572       
573        gtk_text_buffer_get_iter_at_mark (buffer,
574                                          &iter,
575                                          gtk_text_buffer_get_insert (buffer));
576       
577        chars = gtk_text_iter_get_offset (&iter);
578        row = gtk_text_iter_get_line (&iter) + 1;
579       
580        start = iter;
581        gtk_text_iter_set_line_offset (&start, 0);
582        col = 0;
583       
584        while (!gtk_text_iter_equal (&start, &iter))
585        {
586                if (gtk_text_iter_get_char (&start) == '\t')
587                {
588                        col += (tabwidth - (col % tabwidth));
589                }
590                else
591                        ++col;
592               
593                gtk_text_iter_forward_char (&start);
594        }
595       
596        msg = g_strdup_printf ("char: %d, line: %d, column: %d", chars, row, col);
597        gtk_label_set_text (pos_label, msg);
598        g_free (msg);
599}
600
601static void
602move_cursor_cb (GtkTextBuffer *buffer,
603                GtkTextIter   *cursoriter,
604                GtkTextMark   *mark,
605                gpointer       user_data)
606{
607        if (mark != gtk_text_buffer_get_insert (buffer))
608                return;
609
610        update_cursor_position (buffer, user_data);
611}
612
613static gboolean
614window_deleted_cb (GtkWidget *widget, GdkEvent *ev, gpointer user_data)
615{
616        g_return_val_if_fail (GTK_IS_SOURCE_VIEW (user_data), TRUE);
617
618        if (g_list_nth_data (windows, 0) == widget)
619        {
620                /* Main (first in the list) window was closed, so exit
621                 * the application */
622                gtk_main_quit ();
623        }
624        else
625        {
626                GtkSourceView *view = GTK_SOURCE_VIEW (user_data);
627                GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (
628                        gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
629               
630                windows = g_list_remove (windows, widget);
631
632                /* deinstall buffer motion signal handlers */
633                g_signal_handlers_disconnect_matched (buffer,
634                                                      G_SIGNAL_MATCH_DATA,
635                                                      0, /* signal_id */
636                                                      0, /* detail */
637                                                      NULL, /* closure */
638                                                      NULL, /* func */
639                                                      user_data);
640
641                /* we return FALSE since we want the window destroyed */
642                return FALSE;
643        }
644       
645        return TRUE;
646}
647
648static gboolean
649button_press_cb (GtkWidget *widget, GdkEventButton *ev, gpointer user_data)
650{
651        GtkSourceView *view;
652        GtkSourceBuffer *buffer;
653       
654        g_return_val_if_fail (GTK_IS_SOURCE_VIEW (widget), FALSE);
655       
656        view = GTK_SOURCE_VIEW (widget);
657        buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
658       
659        if (!gtk_source_view_get_show_line_markers (view))
660                return FALSE;
661       
662        /* check that the click was on the left gutter */
663        if (ev->window == gtk_text_view_get_window (GTK_TEXT_VIEW (view),
664                                                    GTK_TEXT_WINDOW_LEFT))
665        {
666                gint y_buf;
667                GtkTextIter line_start, line_end;
668                GSList *marker_list, *list_iter;
669                GtkSourceMarker *marker;
670                const gchar *marker_type;
671               
672                if (ev->button == 1)
673                        marker_type = MARKER_TYPE_1;
674                else
675                        marker_type = MARKER_TYPE_2;
676               
677                gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
678                                                       GTK_TEXT_WINDOW_LEFT,
679                                                       ev->x, ev->y,
680                                                       NULL, &y_buf);
681
682                /* get line bounds */
683                gtk_text_view_get_line_at_y (GTK_TEXT_VIEW (view),
684                                             &line_start,
685                                             y_buf,
686                                             NULL);
687               
688                line_end = line_start;
689                gtk_text_iter_forward_to_line_end (&line_end);
690
691                /* get the markers already in the line */
692                marker_list = gtk_source_buffer_get_markers_in_region (buffer,
693                                                                       &line_start,
694                                                                       &line_end);
695
696                /* search for the marker corresponding to the button pressed */
697                marker = NULL;
698                for (list_iter = marker_list;
699                     list_iter && !marker;
700                     list_iter = g_slist_next (list_iter))
701                {
702                        GtkSourceMarker *tmp = list_iter->data;
703                        gchar *tmp_type = gtk_source_marker_get_marker_type (tmp);
704                       
705                        if (tmp_type && !strcmp (tmp_type, marker_type))
706                        {
707                                marker = tmp;
708                        }
709                        g_free (tmp_type);
710                }
711                g_slist_free (marker_list);
712               
713                if (marker)
714                {
715                        /* a marker was found, so delete it */
716                        gtk_source_buffer_delete_marker (buffer, marker);
717                }
718                else
719                {
720                        /* no marker found -> create one */
721                        marker = gtk_source_buffer_create_marker (buffer, NULL,
722                                                                  marker_type, &line_start);
723                }
724        }
725       
726        return FALSE;
727}
728
729
730/* Window creation functions -------------------------------------------------------- */
731
732static GtkWidget *
733create_view_window (GtkSourceBuffer *buffer, GtkSourceView *from)
734{
735        GtkWidget *window, *sw, *view, *vbox, *pos_label, *menu;
736        PangoFontDescription *font_desc = NULL;
737        GdkPixbuf *pixbuf;
738        GtkAccelGroup *accel_group;
739        GtkActionGroup *action_group;
740        GtkUIManager *ui_manager;
741        GError *error;
742
743        g_return_val_if_fail (GTK_IS_SOURCE_BUFFER (buffer), NULL);
744        g_return_val_if_fail (from == NULL || GTK_IS_SOURCE_VIEW (from), NULL);
745       
746        /* window */
747        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
748        gtk_container_set_border_width (GTK_CONTAINER (window), 0);
749        gtk_window_set_title (GTK_WINDOW (window), "GtkSourceView Demo");
750        windows = g_list_append (windows, window);
751
752        /* view */
753        view = gtk_source_view_new_with_buffer (buffer);
754       
755        g_signal_connect (buffer, "mark_set", G_CALLBACK (move_cursor_cb), view);
756        g_signal_connect (buffer, "changed", G_CALLBACK (update_cursor_position), view);
757        g_signal_connect (view, "button-press-event", G_CALLBACK (button_press_cb), NULL);
758        g_signal_connect (window, "delete-event", (GCallback) window_deleted_cb, view);
759
760        /* action group and UI manager */
761        action_group = gtk_action_group_new ("ViewActions");
762        gtk_action_group_add_actions (action_group, view_action_entries,
763                                      G_N_ELEMENTS (view_action_entries), view);
764        gtk_action_group_add_toggle_actions (action_group, toggle_entries,
765                                             G_N_ELEMENTS (toggle_entries), view);
766        gtk_action_group_add_radio_actions (action_group, radio_entries,
767                                            G_N_ELEMENTS (radio_entries),
768                                            -1, G_CALLBACK (tabs_toggled_cb), view);
769       
770        ui_manager = gtk_ui_manager_new ();
771        gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
772        g_object_unref (action_group);
773
774        /* save a reference to the ui manager in the window for later use */
775        g_object_set_data_full (G_OBJECT (window), "ui_manager",
776                                ui_manager, (GDestroyNotify) g_object_unref);
777       
778        accel_group = gtk_ui_manager_get_accel_group (ui_manager);
779        gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
780
781        error = NULL;
782        if (!gtk_ui_manager_add_ui_from_string (ui_manager, view_ui_description, -1, &error))
783        {
784                g_message ("building view ui failed: %s", error->message);
785                g_error_free (error);
786                exit (1);
787        }
788
789        /* misc widgets */
790        vbox = gtk_vbox_new (0, FALSE);
791        sw = gtk_scrolled_window_new (NULL, NULL);
792        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
793                                             GTK_SHADOW_IN);
794        pos_label = gtk_label_new ("Position");
795        g_object_set_data (G_OBJECT (view), "pos_label", pos_label);
796        menu = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
797
798        /* layout widgets */
799        gtk_container_add (GTK_CONTAINER (window), vbox);
800        gtk_box_pack_start (GTK_BOX (vbox), menu, FALSE, FALSE, 0);
801        gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
802        gtk_container_add (GTK_CONTAINER (sw), view);
803        gtk_box_pack_start (GTK_BOX (vbox), pos_label, FALSE, FALSE, 0);
804
805        /* setup view */
806        font_desc = pango_font_description_from_string ("monospace 10");
807        if (font_desc != NULL)
808        {
809                gtk_widget_modify_font (view, font_desc);
810                pango_font_description_free (font_desc);
811        }
812
813        /* change view attributes to match those of from */
814        if (from)
815        {
816                gchar *tmp;
817                GtkAction *action;
818
819                action = gtk_action_group_get_action (action_group, "ShowNumbers");
820                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
821                                              gtk_source_view_get_show_line_numbers (from));
822
823                action = gtk_action_group_get_action (action_group, "ShowMarkers");
824                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
825                                              gtk_source_view_get_show_line_markers (from));
826               
827                action = gtk_action_group_get_action (action_group, "ShowMargin");
828                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
829                                              gtk_source_view_get_show_margin (from));
830               
831                action = gtk_action_group_get_action (action_group, "AutoIndent");
832                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
833                                              gtk_source_view_get_auto_indent (from));
834               
835                action = gtk_action_group_get_action (action_group, "InsertSpaces");
836                gtk_toggle_action_set_active (
837                        GTK_TOGGLE_ACTION (action),
838                        gtk_source_view_get_insert_spaces_instead_of_tabs (from));
839               
840
841                tmp = g_strdup_printf ("TabsWidth%d", gtk_source_view_get_tabs_width (from));
842                action = gtk_action_group_get_action (action_group, tmp);
843                if (action)
844                        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
845                g_free (tmp);
846        }
847
848        /* add marker pixbufs */
849        error = NULL;   
850        if ((pixbuf = gdk_pixbuf_new_from_file (DATADIR "/pixmaps/apple-green.png", &error)))
851        {
852                gtk_source_view_set_marker_pixbuf (GTK_SOURCE_VIEW (view), MARKER_TYPE_1, pixbuf);
853                g_object_unref (pixbuf);
854        }
855        else
856        {
857                g_message ("could not load marker 1 image.  Spurious messages might get triggered: %s",
858                error->message);
859                g_error_free (error);
860        }
861       
862        error = NULL;
863        if ((pixbuf = gdk_pixbuf_new_from_file (DATADIR "/pixmaps/apple-red.png", &error)))
864        {
865                gtk_source_view_set_marker_pixbuf (GTK_SOURCE_VIEW (view), MARKER_TYPE_2, pixbuf);
866                g_object_unref (pixbuf);
867        }
868        else
869        {
870                g_message ("could not load marker 2 image.  Spurious messages might get triggered: %s",
871                error->message);
872                g_error_free (error);           
873        }
874       
875        gtk_widget_show_all (vbox);
876
877        return window;
878}
879
880static GtkWidget *
881create_main_window (GtkSourceBuffer *buffer)
882{
883        GtkWidget *window;
884        GtkAction *action;
885        GtkUIManager *ui_manager;
886        GtkActionGroup *action_group;
887        GList *groups;
888        GError *error;
889       
890        window = create_view_window (buffer, NULL);
891        ui_manager = g_object_get_data (G_OBJECT (window), "ui_manager");
892       
893        /* buffer action group */
894        action_group = gtk_action_group_new ("BufferActions");
895        gtk_action_group_add_actions (action_group, buffer_action_entries,
896                                      G_N_ELEMENTS (buffer_action_entries), buffer);
897        gtk_ui_manager_insert_action_group (ui_manager, action_group, 1);
898        g_object_unref (action_group);
899       
900        /* merge buffer ui */
901        error = NULL;
902        if (!gtk_ui_manager_add_ui_from_string (ui_manager, buffer_ui_description, -1, &error))
903        {
904                g_message ("building buffer ui failed: %s", error->message);
905                g_error_free (error);
906                exit (1);
907        }
908
909        /* preselect menu checkitems */
910        groups = gtk_ui_manager_get_action_groups (ui_manager);
911        /* retrieve the view action group at position 0 in the list */
912        action_group = g_list_nth_data (groups, 0);
913
914        action = gtk_action_group_get_action (action_group, "ShowNumbers");
915        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
916
917        action = gtk_action_group_get_action (action_group, "ShowMarkers");
918        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
919
920        action = gtk_action_group_get_action (action_group, "ShowMargin");
921        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
922
923        action = gtk_action_group_get_action (action_group, "AutoIndent");
924        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
925
926        action = gtk_action_group_get_action (action_group, "InsertSpaces");
927        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
928
929        action = gtk_action_group_get_action (action_group, "TabsWidth8");
930        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
931       
932        return window;
933}
934
935
936/* Buffer creation -------------------------------------------------------------- */
937
938static GtkSourceBuffer *
939create_source_buffer (GtkSourceLanguagesManager *manager)
940{
941        GtkSourceBuffer *buffer;
942       
943        buffer = GTK_SOURCE_BUFFER (gtk_source_buffer_new (NULL));
944        g_object_ref (manager);
945        g_object_set_data_full (G_OBJECT (buffer), "languages-manager",
946                                manager, (GDestroyNotify) g_object_unref);
947       
948        return buffer;
949}
950
951
952/* Program entry point ------------------------------------------------------------ */
953
954int
955main (int argc, char *argv[])
956{
957        GtkWidget *window;
958        GtkSourceLanguagesManager *lm;
959        GtkSourceBuffer *buffer;
960       
961        /* initialization */
962        gtk_init (&argc, &argv);
963        gnome_vfs_init ();
964       
965        /* create buffer */
966        lm = gtk_source_languages_manager_new ();
967        buffer = create_source_buffer (lm);
968        g_object_unref (lm);
969
970        if (argc > 1)
971                open_file (buffer, argv [1]);
972        else
973                open_file (buffer, "../gtksourceview/gtksourcebuffer.c");
974
975        /* create first window */
976        window = create_main_window (buffer);
977        gtk_window_set_default_size (GTK_WINDOW (window), 500, 500);
978        gtk_widget_show (window);
979
980        /* ... and action! */
981        gtk_main ();
982
983        /* cleanup */
984        g_list_foreach (windows, (GFunc) gtk_widget_destroy, NULL);
985        g_list_free (windows);
986        g_object_unref (buffer);
987
988        gnome_vfs_shutdown ();
989       
990        return 0;
991}
Note: See TracBrowser for help on using the repository browser.