Add README
[tilda-gobject.git] / tilda-terminal.c
index ed34929..d7c6410 100644 (file)
 #include "tilda.h"
 #include "tilda-terminal.h"
+#include "tilda-config.h"
 #include "tilda-terminal-dbus-glue.h"
 
+#include <stdlib.h>
+
 #define DINGUS1 "(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+(:[0-9]*)?"
 #define DINGUS2 "(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+(:[0-9]*)?/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"]"
 
+/*******************************************************************************
+ * All popup-menu code is below
+ ******************************************************************************/
+
+static void
+menu_add_term_cb (GtkWidget *widget, gpointer data)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(data));
+
+       TildaTerminal *self = TILDA_TERMINAL(data);
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+
+       tilda_window_add_terminal (parent_window);
+}
+
+static void
+menu_remove_term_cb (GtkWidget *widget, gpointer data)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(data));
+
+       TildaTerminal *self = TILDA_TERMINAL(data);
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+
+       tilda_window_remove_terminal (parent_window, self->number);
+}
+
+static void
+menu_copy_cb (GtkWidget *widget, gpointer data)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(data));
+
+       TildaTerminal *self = TILDA_TERMINAL(data);
+
+       vte_terminal_copy_clipboard (VTE_TERMINAL(self->vte_term));
+}
+
+static void
+menu_paste_cb (GtkWidget *widget, gpointer data)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(data));
+
+       TildaTerminal *self = TILDA_TERMINAL(data);
+
+       vte_terminal_paste_clipboard (VTE_TERMINAL(self->vte_term));
+}
+
+static void
+menu_preferences_cb (GtkWidget *widget, gpointer data)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(data));
+
+       TildaTerminal *self = TILDA_TERMINAL(data);
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+
+       /* TODO:
+        *
+        * Note that this lends interesting possibilities for the tilda-wizard
+        * command line interface. Maybe a --window --terminal option, which will
+        * auto-set the preferences to a current window and term :) Neat.
+        */
+
+       g_print ("FIXME: show wizard here\n");
+}
+
+static void
+menu_quit_cb (GtkWidget *widget, gpointer data)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(data));
+
+       TildaTerminal *self = TILDA_TERMINAL(data);
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+       TildaController *controller = TILDA_CONTROLLER(parent_window->controller);
+
+       tilda_controller_remove_window (controller, parent_window->number);
+}
+
+static void
+tilda_terminal_popup_menu (TildaTerminal *self)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(self));
+
+       GtkAction *action;
+       GtkActionGroup *action_group;
+       GtkUIManager *ui_manager;
+       GError *error = NULL;
+       GtkWidget *menu;
+
+       /* Just use a static string here to initialize the GtkUIManager,
+        * rather than installing and reading from a file all the time. */
+       static const gchar menu_str[] =
+               "<ui>"
+                       "<popup name=\"popup-menu\">"
+                               "<menuitem action=\"add-term\" />"
+                               "<menuitem action=\"remove-term\" />"
+                               "<separator />"
+                               "<menuitem action=\"copy\" />"
+                               "<menuitem action=\"paste\" />"
+                               "<separator />"
+                               "<menuitem action=\"preferences\" />"
+                               "<separator />"
+                               "<menuitem action=\"quit\" />"
+                       "</popup>"
+               "</ui>";
+
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+
+       /* Create the action group */
+       action_group = gtk_action_group_new ("popup-menu-action-group");
+
+       /* Add Actions and connect callbacks */
+       action = gtk_action_new ("add-term", _("_Add Terminal"), NULL, GTK_STOCK_ADD);
+       gtk_action_group_add_action_with_accel (action_group, action, parent_window->accel_add_term);
+       g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_add_term_cb), self);
+
+       action = gtk_action_new ("remove-term", _("_Remove Terminal"), NULL, GTK_STOCK_CLOSE);
+       gtk_action_group_add_action_with_accel (action_group, action, parent_window->accel_remove_term);
+       g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_remove_term_cb), self);
+
+       action = gtk_action_new ("copy", NULL, NULL, GTK_STOCK_COPY);
+       gtk_action_group_add_action_with_accel (action_group, action, parent_window->accel_copy);
+       g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_copy_cb), self);
+
+       action = gtk_action_new ("paste", NULL, NULL, GTK_STOCK_PASTE);
+       gtk_action_group_add_action_with_accel (action_group, action, parent_window->accel_paste);
+       g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_paste_cb), self);
+
+       action = gtk_action_new ("preferences", NULL, NULL, GTK_STOCK_PREFERENCES);
+       gtk_action_group_add_action (action_group, action);
+       g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_preferences_cb), self);
+
+       action = gtk_action_new ("quit", NULL, NULL, GTK_STOCK_QUIT);
+       gtk_action_group_add_action_with_accel (action_group, action, parent_window->accel_quit);
+       g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_quit_cb), self);
+
+       /* Create and add actions to the GtkUIManager */
+       ui_manager = gtk_ui_manager_new ();
+       gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+       gtk_ui_manager_add_ui_from_string (ui_manager, menu_str, -1, &error);
+
+       /* Check for an error (REALLY REALLY unlikely, unless the developers screwed up */
+       if (error)
+       {
+               g_critical ("GtkUIManager problem: %s\n", error->message);
+               g_error_free (error);
+       }
+
+       /* Get the popup menu out of the GtkUIManager */
+       menu = gtk_ui_manager_get_widget (ui_manager, "/ui/popup-menu");
+
+       /* Display the menu */
+       gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time());
+       gtk_widget_show_all(menu);
+}
+
+/*******************************************************************************
+ * All TildaTerminal functions below
+ ******************************************************************************/
 
 static void
 tilda_terminal_dbus_register_object (TildaTerminal *tt)
@@ -15,13 +182,42 @@ tilda_terminal_dbus_register_object (TildaTerminal *tt)
        TildaWindow *parent_window = TILDA_WINDOW(tt->parent_window);
        gchar *object_path;
 
-       // Register this object with DBus
+       /* If DBus is not running, leave */
+       if (!dbus_connection)
+               return;
+
+       /* Register this object with DBus */
        object_path = g_strdup_printf ("/net/sourceforge/Tilda/Window%d/Terminal%d",
                                                                   parent_window->number, tt->number);
        dbus_g_connection_register_g_object (dbus_connection, object_path, G_OBJECT(tt));
        g_free (object_path);
 }
 
+gboolean
+tilda_terminal_run_command (TildaTerminal *self, gchar *command, GError **error)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(self));
+
+       vte_terminal_feed_child (VTE_TERMINAL(self->vte_term), command, -1);
+       vte_terminal_feed_child (VTE_TERMINAL(self->vte_term), "\n", -1);
+
+       return TRUE;
+}
+
+gboolean
+tilda_terminal_close (TildaTerminal *self, GError **error)
+{
+       debug_enter  ();
+       debug_assert (TILDA_IS_TERMINAL(self));
+
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+
+       tilda_window_remove_terminal (parent_window, self->number);
+
+       return TRUE;
+}
+
 /**
  * Start the current tt->shell in the given TildaTerminal
  * NOTE: this will kill whatever is running in the terminal,
@@ -110,24 +306,21 @@ tilda_terminal_child_exited_cb (GtkWidget *widget, gpointer data)
 
        TildaTerminal *self = TILDA_TERMINAL(data);
 
-       /* These can stay here. They don't need to go into a header because
-        * they are only used at this point in the code. */
-       enum exit_actions { HOLD_TERMINAL_OPEN, RESTART_COMMAND, EXIT_TERMINAL };
-
        /* Check the user's preference for what to do when the child terminal
         * is closed. Take the appropriate action */
        switch (self->exit_action)
        {
-               case EXIT_TERMINAL:
-                       tilda_window_remove_term (TILDA_WINDOW(self->parent_window), self->number);
+               case TILDA_CHILD_EXIT_ACTION_EXIT:
+                       tilda_window_remove_terminal (TILDA_WINDOW(self->parent_window), self->number);
                        break;
-               case RESTART_COMMAND:
+               case TILDA_CHILD_EXIT_ACTION_RESTART:
                        vte_terminal_feed (VTE_TERMINAL(self->vte_term), "\r\n\r\n", 4);
                        tilda_terminal_start_shell (self);
                        break;
-               case HOLD_TERMINAL_OPEN:
+               case TILDA_CHILD_EXIT_ACTION_HOLD_OPEN:
                        break;
                default:
+                       g_warning ("Bad value in self->exit_action\n");
                        break;
        }
 }
@@ -146,42 +339,32 @@ tilda_terminal_window_title_changed_cb (GtkWidget *widget, gpointer data)
        TildaTerminal *self = TILDA_TERMINAL(data);
        TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
        GtkWidget *label;
-       const gchar *vte_title;
-       gchar *new_title;
-
-       enum dynamic_titles { NOT_DISPLAYED, AFTER_INITIAL, BEFORE_INITIAL, REPLACE_INITIAL };
-       label = gtk_notebook_get_tab_label (GTK_NOTEBOOK(parent_window->notebook), self->hbox);
-
-       /* If we aren't using a dynamic title -- NOT_DISPLAYED -- then just
-        * set it to the static title and exit */
-       if (!self->dynamic_title)
-       {
-               gtk_label_set_text (GTK_LABEL(label), self->title);
-               return;
-       }
+       const gchar *vte_title = NULL;
+       gchar *new_title = NULL;
 
-       /* Get the title from VTE */
        vte_title = vte_terminal_get_window_title (VTE_TERMINAL (widget));
+       label = gtk_notebook_get_tab_label (GTK_NOTEBOOK(parent_window->notebook), self->hbox);
 
-       /* Take the appropriate action */
        switch (self->dynamic_title)
        {
-               case REPLACE_INITIAL:
-                       new_title = g_strdup (vte_title);
+               case TILDA_DYNAMIC_TITLE_DISABLED:
+                       new_title = g_strdup (self->title);
+                       break;
+
+               case TILDA_DYNAMIC_TITLE_AFTER_INITIAL:
+                       new_title = g_strdup_printf ("%s - %s", self->title, vte_title);
                        break;
 
-               case BEFORE_INITIAL:
+               case TILDA_DYNAMIC_TITLE_BEFORE_INITIAL:
                        new_title = g_strdup_printf ("%s - %s", vte_title, self->title);
                        break;
 
-               case AFTER_INITIAL:
-                       new_title = g_strdup_printf ("%s - %s", self->title, vte_title);
+               case TILDA_DYNAMIC_TITLE_REPLACE_INITIAL:
+                       new_title = g_strdup (self->title);
                        break;
 
                default:
-                       debug_printf ("ERROR: Bad value of self->dynamic_title\n");
-               case NOT_DISPLAYED:
-                       new_title = g_strdup(self->title);
+                       g_warning ("Bad value in self->dynamic-title\n");
                        break;
        }
 
@@ -213,9 +396,7 @@ tilda_terminal_button_press_cb (GtkWidget      *widget,
        switch (event->button)
        {
                case 3: /* Right Click */
-                       // FIXME: need to add this
-                       //popup_menu (tt->tw, tt);
-                       g_print ("FIXME: popup_menu() here\n");
+                       tilda_terminal_popup_menu (self);
                        break;
 
                case 2: /* Middle Click */
@@ -304,24 +485,25 @@ tilda_terminal_set_scrollbar_position (TildaTerminal *self)
        debug_enter  ();
        debug_assert (TILDA_IS_TERMINAL(self));
 
-       enum scrollbar_positions { DISABLED, LEFT, RIGHT };
        switch (self->scrollbar_position)
        {
-               case LEFT:
+               case TILDA_SCROLLBAR_RIGHT:
                        gtk_box_reorder_child (GTK_BOX(self->hbox), self->scrollbar, 0);
                        gtk_widget_show (self->scrollbar);
                        break;
 
-               case RIGHT:
+               case TILDA_SCROLLBAR_LEFT:
                        gtk_box_reorder_child (GTK_BOX(self->hbox), self->scrollbar, 1);
                        gtk_widget_show (self->scrollbar);
                        break;
 
-               default:
-                       debug_printf ("ERROR: Bad scrollbar position\n");
-               case DISABLED:
+               case TILDA_SCROLLBAR_DISABLED:
                        gtk_widget_hide (self->scrollbar);
                        break;
+
+               default:
+                       g_warning ("Bad value in self->scrollbar_position\n");
+                       break;
        }
 }
 
@@ -456,29 +638,29 @@ tilda_terminal_set_property (GObject      *object,
                        break;
 
                case TILDA_TERMINAL_BACKSPACE_BINDING:
-                       self->backspace_binding = g_value_get_int (value);
+                       self->backspace_binding = g_value_get_enum (value);
                        vte_terminal_set_backspace_binding (VTE_TERMINAL(self->vte_term), self->backspace_binding);
                        debug_printf ("terminal backspace key: %d\n", self->backspace_binding);
                        break;
 
                case TILDA_TERMINAL_DELETE_BINDING:
-                       self->delete_binding = g_value_get_int (value);
+                       self->delete_binding = g_value_get_enum (value);
                        vte_terminal_set_delete_binding (VTE_TERMINAL(self->vte_term), self->delete_binding);
                        debug_printf ("terminal delete key: %d\n", self->delete_binding);
                        break;
 
                case TILDA_TERMINAL_DYNAMIC_TITLE:
-                       self->dynamic_title = g_value_get_int (value);
+                       self->dynamic_title = g_value_get_enum (value);
                        debug_printf ("terminal dynamic title: %d\n", self->dynamic_title);
                        break;
 
                case TILDA_TERMINAL_EXIT_ACTION:
-                       self->exit_action = g_value_get_int (value);
+                       self->exit_action = g_value_get_enum (value);
                        debug_printf ("terminal exit action: %d\n", self->exit_action);
                        break;
 
                case TILDA_TERMINAL_SCROLLBAR_POSITION:
-                       self->scrollbar_position = g_value_get_int (value);
+                       self->scrollbar_position = g_value_get_enum (value);
                        tilda_terminal_set_scrollbar_position (self);
                        debug_printf ("terminal scrollbar position: %d\n", self->scrollbar_position);
                        break;
@@ -603,23 +785,23 @@ tilda_terminal_get_property (GObject    *object,
                        break;
 
                case TILDA_TERMINAL_BACKSPACE_BINDING:
-                       g_value_set_int (value, self->backspace_binding);
+                       g_value_set_enum (value, self->backspace_binding);
                        break;
 
                case TILDA_TERMINAL_DELETE_BINDING:
-                       g_value_set_int (value, self->delete_binding);
+                       g_value_set_enum (value, self->delete_binding);
                        break;
 
                case TILDA_TERMINAL_DYNAMIC_TITLE:
-                       g_value_set_int (value, self->dynamic_title);
+                       g_value_set_enum (value, self->dynamic_title);
                        break;
 
                case TILDA_TERMINAL_EXIT_ACTION:
-                       g_value_set_int (value, self->exit_action);
+                       g_value_set_enum (value, self->exit_action);
                        break;
 
                case TILDA_TERMINAL_SCROLLBAR_POSITION:
-                       g_value_set_int (value, self->scrollbar_position);
+                       g_value_set_enum (value, self->scrollbar_position);
                        break;
 
                case TILDA_TERMINAL_SCROLL_BACKGROUND:
@@ -713,7 +895,35 @@ tilda_terminal_constructor (GType                  type,
        g_signal_connect (G_OBJECT(self->vte_term), "button-press-event",
                                          G_CALLBACK(tilda_terminal_button_press_cb), self);
 
-       tilda_terminal_start_shell (self);
+       /* Setup all of the defaults from the config file */
+       tilda_terminal_set_property_from_config (self, "background-image");
+       tilda_terminal_set_property_from_config (self, "shell");
+       tilda_terminal_set_property_from_config (self, "font");
+       tilda_terminal_set_property_from_config (self, "title");
+       tilda_terminal_set_property_from_config (self, "working-directory");
+       tilda_terminal_set_property_from_config (self, "web-browser");
+
+       tilda_terminal_set_property_from_config (self, "scrollback-lines");
+       tilda_terminal_set_property_from_config (self, "transparency-percent");
+
+       tilda_terminal_set_property_from_config (self, "backspace-binding");
+       tilda_terminal_set_property_from_config (self, "delete-binding");
+       tilda_terminal_set_property_from_config (self, "dynamic-title");
+       tilda_terminal_set_property_from_config (self, "exit-action");
+       tilda_terminal_set_property_from_config (self, "scrollbar-position");
+
+       tilda_terminal_set_property_from_config (self, "scroll-background");
+       tilda_terminal_set_property_from_config (self, "scroll-on-output");
+       tilda_terminal_set_property_from_config (self, "scroll-on-keystroke");
+       tilda_terminal_set_property_from_config (self, "antialiased");
+       tilda_terminal_set_property_from_config (self, "allow-bold-text");
+       tilda_terminal_set_property_from_config (self, "cursor-blinks");
+       tilda_terminal_set_property_from_config (self, "audible-bell");
+       tilda_terminal_set_property_from_config (self, "visible-bell");
+       tilda_terminal_set_property_from_config (self, "double-buffered");
+       tilda_terminal_set_property_from_config (self, "mouse-autohide");
+
+       /* All right! We're all ready to go, so register with DBus, and lets start! */
        tilda_terminal_dbus_register_object (self);
 
        return obj;
@@ -893,61 +1103,56 @@ tilda_terminal_class_init (gpointer g_class,
                                                                         TILDA_TERMINAL_TRANSPARENCY_PERCENT,
                                                                         pspec);
 
-       pspec = g_param_spec_int ("backspace-binding",
-                                                         _("Terminal's backspace binding"),
-                                                         NULL,
-                                                         VTE_ERASE_AUTO,
-                                                         VTE_ERASE_DELETE_SEQUENCE,
-                                                         VTE_ERASE_AUTO,
-                                                         G_PARAM_READWRITE);
+       pspec = g_param_spec_enum ("backspace-binding",
+                                                          _("Terminal's backspace binding"),
+                                                          NULL,
+                                                          vte_terminal_erase_binding_get_type(),
+                                                          VTE_ERASE_AUTO,
+                                                          G_PARAM_READWRITE);
 
        g_object_class_install_property (gobject_class,
                                                                         TILDA_TERMINAL_BACKSPACE_BINDING,
                                                                         pspec);
 
-       pspec = g_param_spec_int ("delete-binding",
-                                                         _("Terminal's delete binding"),
-                                                         NULL,
-                                                         VTE_ERASE_AUTO,
-                                                         VTE_ERASE_DELETE_SEQUENCE,
-                                                         VTE_ERASE_AUTO,
-                                                         G_PARAM_READWRITE);
+       pspec = g_param_spec_enum ("delete-binding",
+                                                          _("Terminal's delete binding"),
+                                                          NULL,
+                                                          vte_terminal_erase_binding_get_type(),
+                                                          VTE_ERASE_AUTO,
+                                                          G_PARAM_READWRITE);
 
        g_object_class_install_property (gobject_class,
                                                                         TILDA_TERMINAL_DELETE_BINDING,
                                                                         pspec);
 
-       pspec = g_param_spec_int ("dynamic-title",
-                                                         _("Terminal's dynamic title generation method"),
-                                                         NULL,
-                                                         0,
-                                                         INT_MAX,
-                                                         0,
-                                                         G_PARAM_READWRITE);
+       pspec = g_param_spec_enum ("dynamic-title",
+                                                          _("Terminal's dynamic title generation method"),
+                                                          NULL,
+                                                          tilda_dynamic_title_get_type(),
+                                                          TILDA_DYNAMIC_TITLE_DISABLED,
+                                                          G_PARAM_READWRITE);
 
        g_object_class_install_property (gobject_class,
                                                                         TILDA_TERMINAL_DYNAMIC_TITLE,
                                                                         pspec);
 
-       pspec = g_param_spec_int ("exit-action",
-                                                         _("Terminal's action upon child exit"),
-                                                         NULL,
-                                                         0,
-                                                         INT_MAX,
-                                                         0,
-                                                         G_PARAM_READWRITE);
+       pspec = g_param_spec_enum ("exit-action",
+                                                          _("Terminal's action upon child exit"),
+                                                          NULL,
+                                                          tilda_child_exit_action_get_type(),
+                                                          TILDA_CHILD_EXIT_ACTION_EXIT,
+                                                          G_PARAM_READWRITE);
 
        g_object_class_install_property (gobject_class,
                                                                         TILDA_TERMINAL_EXIT_ACTION,
                                                                         pspec);
 
-       pspec = g_param_spec_int ("scrollbar-position",
-                                                         _("Terminal's scrollbar position"),
-                                                         NULL,
-                                                         0,
-                                                         INT_MAX,
-                                                         0,
-                                                         G_PARAM_READWRITE);
+       pspec = g_param_spec_enum ("scrollbar-position",
+                                                          _("Terminal's scrollbar position"),
+                                                          NULL,
+                                                          tilda_scrollbar_position_get_type(),
+                                                          TILDA_SCROLLBAR_RIGHT,
+                                                          G_PARAM_READWRITE);
 
        g_object_class_install_property (gobject_class,
                                                                         TILDA_TERMINAL_SCROLLBAR_POSITION,