diff options
Diffstat (limited to 'tools/glade/examples/editor/src/callbacks.c')
-rw-r--r-- | tools/glade/examples/editor/src/callbacks.c | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/tools/glade/examples/editor/src/callbacks.c b/tools/glade/examples/editor/src/callbacks.c new file mode 100644 index 00000000..bb653be2 --- /dev/null +++ b/tools/glade/examples/editor/src/callbacks.c @@ -0,0 +1,670 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gtk/gtk.h> + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +/* We create the dialog boxes once and keep pointers to them in static + variables so we can reuse them. */ +static GtkWidget *open_filesel = NULL; +static GtkWidget *save_filesel = NULL; +static GtkWidget *fontsel = NULL; + +/* This is the filename of the file currently being edited, in on-disk + encoding (which may be UTF-8 or the locale's encoding). */ +static gchar *current_filename = NULL; + +/* This flag is set to TRUE if the file has been changed. We don't actually + use it here, but the program could be extended to prompt to save changes. */ +static gboolean file_changed = FALSE; + +/* A key used to store pointers to the main window. */ +static const gchar *MainWindowKey = "MainWindowKey"; + +/* The size of chunks to read in when opening files. */ +#define BUFFER_SIZE 8192 + + +/* Static functions. */ +static void new_file (GtkWidget *main_window); +static void open_file (GtkWidget *main_window); +static void save_as (GtkWidget *main_window); + +static void real_open_file (GtkWidget *main_window, + const gchar *filename); +static void real_save_file (GtkWidget *main_window, + const gchar *filename); + + +/*************************************************************************** + * Main Window Signals. + ***************************************************************************/ + +/* This is called when the main window gets a "delete_event" signal, which + typically happens when the user clicks on the close icon on the window's + title bar. If we didn't handle this, the window would be destroyed but + our application would not exit. */ +gboolean +on_main_window_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + exit (0); + + /* Shouldn't reach here, but we add it to stop compiler warnings. */ + return FALSE; +} + + +/*************************************************************************** + * File Menu Commands. + ***************************************************************************/ +void +on_New_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *main_window; + + /* We use the Glade utility function lookup_widget() to get a pointer to the + main window. The first argument is any widget in the window/dialog and + the second argument is the name of the widget you want to get. */ + main_window = lookup_widget (GTK_WIDGET (menuitem), "main_window"); + new_file (main_window); +} + + +void +on_Open_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (menuitem), "main_window"); + open_file (main_window); +} + + +void +on_Save_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (menuitem), "main_window"); + + /* If the current document doesn't have a filename yet, we call save_as + to show the file selection dialog. */ + if (current_filename == NULL) + save_as (main_window); + else + real_save_file (main_window, current_filename); +} + + +void +on_Save_As_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (menuitem), "main_window"); + save_as (main_window); +} + + +void +on_Exit_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + gtk_exit (0); +} + + +/*************************************************************************** + * Edit Menu Commands. + * The GtkTextView class makes this very easy for us by providing action + * signals that perform clipboard functions. + ***************************************************************************/ + +void +on_Cut_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *text, *statusbar; + + text = lookup_widget (GTK_WIDGET (menuitem), "text1"); + g_signal_emit_by_name (G_OBJECT (text), "cut_clipboard", NULL); + + statusbar = lookup_widget (GTK_WIDGET (menuitem), "statusbar1"); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Text cut to clipboard."); +} + + +void +on_Copy_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *text, *statusbar; + + text = lookup_widget (GTK_WIDGET (menuitem), "text1"); + g_signal_emit_by_name (G_OBJECT (text), "copy_clipboard", NULL); + + statusbar = lookup_widget (GTK_WIDGET (menuitem), "statusbar1"); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Text copied."); +} + + +void +on_Paste_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *text, *statusbar; + + text = lookup_widget (GTK_WIDGET (menuitem), "text1"); + g_signal_emit_by_name (G_OBJECT (text), "paste_clipboard", NULL); + + statusbar = lookup_widget (GTK_WIDGET (menuitem), "statusbar1"); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Text pasted."); +} + + +void +on_Clear_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *text, *statusbar; + GtkTextBuffer *buffer; + + text = lookup_widget (GTK_WIDGET (menuitem), "text1"); + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); + + statusbar = lookup_widget (GTK_WIDGET (menuitem), "statusbar1"); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Text deleted."); +} + + +/*************************************************************************** + * Toolbar Buttons. + ***************************************************************************/ + +void +on_new_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (button), "main_window"); + new_file (main_window); +} + + +void +on_open_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (button), "main_window"); + open_file (main_window); +} + + +void +on_save_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (button), "main_window"); + + if (current_filename == NULL) + save_as (main_window); + else + real_save_file (main_window, current_filename); +} + + +/*************************************************************************** + * Font Selection Dialog. + ***************************************************************************/ + +/* This is called when the 'Change Font' command is used. We just need to + show the font selection dialog. */ +void +on_Font_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + GtkWidget *main_window; + + main_window = lookup_widget (GTK_WIDGET (menuitem), "main_window"); + if (!fontsel) + { + fontsel = create_font_selection (); + gtk_object_set_data (GTK_OBJECT (fontsel), MainWindowKey, main_window); + + /* Make sure the dialog doesn't disappear behind the main window. */ + gtk_window_set_transient_for (GTK_WINDOW (fontsel), + GTK_WINDOW (main_window)); + } + gtk_widget_show (fontsel); + + /* We make sure the dialog is visible. */ + gtk_window_present (GTK_WINDOW (fontsel)); +} + + +gboolean +on_fontsel_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_widget_hide (gtk_widget_get_toplevel (widget)); + return TRUE; +} + + +void +on_fontsel_ok_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *fontsel; + + /* We do the same thing as apply, but we close the dialog after. */ + on_fontsel_apply_button_clicked (button, NULL); + fontsel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + gtk_widget_hide (fontsel); +} + + +void +on_fontsel_cancel_button_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_widget_hide (gtk_widget_get_toplevel (GTK_WIDGET (button))); +} + + +void +on_fontsel_apply_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *fontsel, *main_window, *text, *statusbar; + gchar *font_name; + PangoFontDescription *font_desc; + + fontsel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + main_window = gtk_object_get_data (GTK_OBJECT (fontsel), MainWindowKey); + text = lookup_widget (main_window, "text1"); + statusbar = lookup_widget (main_window, "statusbar1"); + + font_name = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (fontsel)); + font_desc = pango_font_description_from_string (font_name); + g_free (font_name); + + /* We copy the current style, and update the font. */ + gtk_widget_modify_font (text, font_desc); + pango_font_description_free (font_desc); + + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Font updated."); +} + + +/*************************************************************************** + * Open File Selection Dialog. + ***************************************************************************/ + +void +on_open_filesel_ok_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *filesel, *main_window; + const gchar *filename; + + filesel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + main_window = gtk_object_get_data (GTK_OBJECT (filesel), MainWindowKey); + gtk_widget_hide (filesel); + filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)); + real_open_file (main_window, filename); +} + + +void +on_open_filesel_cancel_button_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_widget_hide (gtk_widget_get_toplevel (GTK_WIDGET (button))); +} + + +gboolean +on_open_filesel_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_widget_hide (gtk_widget_get_toplevel (widget)); + return TRUE; +} + + +/*************************************************************************** + * Save File Selection Dialog. + ***************************************************************************/ + +void +on_save_filesel_ok_button_clicked (GtkButton *button, + gpointer user_data) +{ + GtkWidget *filesel, *main_window; + const gchar *filename; + + filesel = gtk_widget_get_toplevel (GTK_WIDGET (button)); + main_window = gtk_object_get_data (GTK_OBJECT (filesel), MainWindowKey); + gtk_widget_hide (filesel); + filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)); + real_save_file (main_window, filename); +} + + +void +on_save_filesel_cancel_button_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_widget_hide (gtk_widget_get_toplevel (GTK_WIDGET (button))); +} + + +gboolean +on_save_filesel_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_widget_hide (gtk_widget_get_toplevel (widget)); + return TRUE; +} + + +/*************************************************************************** + * About Dialog. + ***************************************************************************/ + +void +on_About_activate (GtkMenuItem *menuitem, + gpointer user_data) +{ + static GtkWidget *about = NULL; + + if (about == NULL) + { + GtkWidget *main_window; + + about = create_about_dialog (); + /* set the widget pointer to NULL when the widget is destroyed */ + g_signal_connect (G_OBJECT (about), + "destroy", + G_CALLBACK (gtk_widget_destroyed), + &about); + + main_window = lookup_widget (GTK_WIDGET (menuitem), "main_window"); + /* Make sure the dialog doesn't disappear behind the main window. */ + gtk_window_set_transient_for (GTK_WINDOW (about), + GTK_WINDOW (main_window)); + /* Do not allow user to resize the dialog */ + gtk_window_set_resizable (GTK_WINDOW (about), FALSE); + } + + /* Make sure the dialog is visible. */ + gtk_window_present (GTK_WINDOW (about)); +} + + +void +on_about_ok_clicked (GtkButton *button, + gpointer user_data) +{ + gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (button))); +} + + +/*************************************************************************** + * Text Widget signals. + ***************************************************************************/ + +/* + * Text changed callback. This signal is emitted whenever the text in the + * GtkTextView changes. We don't use this at present, but it could be used to + * prompt to save changes before opening new files or quitting. + */ +void +on_text_changed (GtkTextBuffer *buffer, + gpointer user_data) +{ + file_changed = TRUE; +} + + +/*************************************************************************** + * Private functions. + ***************************************************************************/ + +/* This sets the window title according to the current filename. */ +void +set_window_title (GtkWidget *main_window) +{ + gchar *title, *filename_utf8 = NULL; + + /* We need to convert the filename to UTF-8. */ + if (current_filename) + filename_utf8 = g_filename_to_utf8 (current_filename, -1, NULL, NULL, + NULL); + + title = g_strdup_printf ("Editor: %s\n", + filename_utf8 ? g_basename (filename_utf8) + : "untitled"); + + gtk_window_set_title (GTK_WINDOW (main_window), title); + g_free (title); + g_free (filename_utf8); +} + + +/* This creates a new document, by clearing the text widget and setting the + current filename to NULL. */ +static void +new_file (GtkWidget *main_window) +{ + GtkWidget *text, *statusbar; + GtkTextBuffer *buffer; + GtkTextIter start, end; + + text = lookup_widget (GTK_WIDGET (main_window), "text1"); + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + gtk_text_buffer_get_bounds (buffer, &start, &end); + gtk_text_buffer_delete (buffer, &start, &end); + + g_free (current_filename); + current_filename = NULL; + file_changed = FALSE; + set_window_title (main_window); + + statusbar = lookup_widget (main_window, "statusbar1"); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "New file."); +} + + +/* This shows the file selection dialog to open a file. */ +static void +open_file (GtkWidget *main_window) +{ + /* We use the same file selection widget each time, so first + of all we create it if it hasn't already been created. */ + if (open_filesel == NULL) + { + open_filesel = create_open_file_selection (); + /* Make sure the dialog doesn't disappear behind the main window. */ + gtk_window_set_transient_for (GTK_WINDOW (open_filesel), + GTK_WINDOW (main_window)); + } + + /* We save a pointer to the main window inside the file selection's + data list, so we can get it easily in the callbacks. */ + gtk_object_set_data (GTK_OBJECT (open_filesel), MainWindowKey, main_window); + + /* We make sure the dialog is visible. */ + gtk_window_present (GTK_WINDOW (open_filesel)); +} + + +/* This shows the file selection dialog to save a file. */ +static void +save_as (GtkWidget *main_window) +{ + if (save_filesel == NULL) + { + save_filesel = create_save_file_selection (); + /* Make sure the dialog doesn't disappear behind the main window. */ + gtk_window_set_transient_for (GTK_WINDOW (save_filesel), + GTK_WINDOW (main_window)); + } + + gtk_object_set_data (GTK_OBJECT (save_filesel), MainWindowKey, main_window); + + /* If the current document has a filename we use that as the default. */ + if (current_filename) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (save_filesel), + current_filename); + + /* We make sure the dialog is visible. */ + gtk_window_present (GTK_WINDOW (save_filesel)); +} + + +/* This loads the given file, which is in on-disk encoding (which may not + be UTF-8). */ +static void +real_open_file (GtkWidget *main_window, const gchar *filename) +{ + GtkWidget *text, *statusbar; + GtkTextBuffer *text_buffer; + GtkTextIter start, end; + FILE *fp; + gchar buffer[BUFFER_SIZE]; + gint bytes_read; + + text = lookup_widget (main_window, "text1"); + text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + statusbar = lookup_widget (main_window, "statusbar1"); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_text_buffer_get_bounds (text_buffer, &start, &end); + gtk_text_buffer_delete (text_buffer, &start, &end); + g_free (current_filename); + current_filename = NULL; + file_changed = FALSE; + + fp = fopen (filename, "r"); + if (fp == NULL) + { + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Couldn't open file."); + return; + } + + for (;;) + { + bytes_read = fread (buffer, sizeof (gchar), BUFFER_SIZE, fp); + + if (bytes_read > 0) + { + gtk_text_buffer_get_end_iter (text_buffer, &end); + gtk_text_buffer_insert (text_buffer, &end, buffer, bytes_read); + } + + if (bytes_read != BUFFER_SIZE && (feof (fp) || ferror (fp))) + break; + } + + /* If there is an error while loading, we reset everything to a good state. + */ + if (ferror (fp)) + { + fclose (fp); + gtk_text_buffer_get_bounds (text_buffer, &start, &end); + gtk_text_buffer_delete (text_buffer, &start, &end); + set_window_title (main_window); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Error loading file."); + return; + } + + fclose (fp); + + current_filename = g_strdup (filename); + set_window_title (main_window); + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "File opened."); +} + + +/* This saves the file, which is in on-disk encoding (which may not + be UTF-8). */ +static void +real_save_file (GtkWidget *main_window, const gchar *filename) +{ + GtkWidget *text, *statusbar; + GtkTextBuffer *text_buffer; + GtkTextIter start, end; + gchar *data; + FILE *fp; + gint bytes_written, len; + + if (current_filename == NULL || strcmp (current_filename, filename)) + { + g_free (current_filename); + current_filename = g_strdup (filename); + set_window_title (main_window); + } + + text = lookup_widget (GTK_WIDGET (main_window), "text1"); + text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + statusbar = lookup_widget (main_window, "statusbar1"); + + gtk_text_buffer_get_bounds (text_buffer, &start, &end); + data = gtk_text_buffer_get_text (text_buffer, &start, &end, TRUE); + + fp = fopen (filename, "w"); + if (fp == NULL) + { + g_free (data); + return; + } + + len = strlen (data); + bytes_written = fwrite (data, sizeof (gchar), len, fp); + fclose (fp); + + g_free (data); + + gtk_statusbar_pop (GTK_STATUSBAR (statusbar), 1); + if (len != bytes_written) + { + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Error saving file."); + return; + } + + file_changed = FALSE; + gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "File saved."); +} + |