[Window] Bugfixes in pull() code
[tilda-gobject.git] / tilda-terminal.c
index 841b2a3..c765eca 100644 (file)
@@ -7,6 +7,10 @@
 #define _(X) X
 #define N_(X) X
 
+#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_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"]"
+
+
 static void
 tilda_terminal_dbus_register_object (TildaTerminal *tt)
 {
@@ -92,6 +96,215 @@ launch_default_shell:
        return TRUE;
 }
 
+/**
+ * Called when the child process running in the VteTerminal exits.
+ */
+static void
+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);
+                       break;
+               case RESTART_COMMAND:
+                       vte_terminal_feed (VTE_TERMINAL(self->vte_term), "\r\n\r\n", 4);
+                       tilda_terminal_start_shell (self);
+                       break;
+               case HOLD_TERMINAL_OPEN:
+                       break;
+               default:
+                       break;
+       }
+}
+
+/**
+ * Called when the child window title changes. Determines if a new
+ * title needs to be put into the notebook's tab label.
+ */
+static void
+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;
+       }
+
+       /* Get the title from VTE */
+       vte_title = vte_terminal_get_window_title (VTE_TERMINAL (widget));
+
+       /* Take the appropriate action */
+       switch (self->dynamic_title)
+       {
+               case REPLACE_INITIAL:
+                       new_title = g_strdup (vte_title);
+                       break;
+
+               case 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);
+                       break;
+
+               case NOT_DISPLAYED:
+               default:
+                       g_printerr (_("FIXME: Bad value of self->dynamic_title\n"));
+                       new_title = g_strdup(self->title);
+                       break;
+       }
+
+       gtk_label_set_text (GTK_LABEL(label), new_title);
+       g_free (new_title);
+}
+
+/**
+ * Gets called whenever there is a button-press event in the VteTerminal. It
+ * is used to open the user's web browser, for example.
+ */
+static gint
+tilda_terminal_button_press_cb (GtkWidget      *widget,
+                                                               GdkEventButton *event,
+                                                               gpointer        data)
+{
+       GError *error = NULL;
+       TildaTerminal *self = TILDA_TERMINAL(data);
+       VteTerminal *terminal = VTE_TERMINAL(self->vte_term);
+       gint tag, xpad, ypad;
+       gchar *match, *cmd, *web_browser_cmd;
+       gboolean ret = FALSE;
+
+       switch (event->button)
+       {
+               case 3: /* Right Click */
+                       // FIXME: need to add this
+                       //popup_menu (tt->tw, tt);
+                       g_print ("FIXME: popup_menu() here\n");
+                       break;
+
+               case 2: /* Middle Click */
+                       break;
+
+               case 1: /* Left Click */
+                       vte_terminal_get_padding (terminal, &xpad, &ypad);
+                       match = vte_terminal_match_check (terminal,
+                                       (event->x - ypad) / terminal->char_width,
+                                       (event->y - ypad) / terminal->char_height,
+                                       &tag);
+
+                       /* Check if we can launch a web browser, and do so if possible */
+                       if ((event->state & GDK_CONTROL_MASK) && match != NULL)
+                       {
+#if DEBUG
+                               g_print ("Got a Ctrl+Left Click -- Matched: `%s' (%d)\n", match, tag);
+#endif
+                               web_browser_cmd = g_strescape (self->web_browser, NULL);
+                               cmd = g_strdup_printf ("%s %s", web_browser_cmd, match);
+#if DEBUG
+                               g_print ("Launching command: `%s'\n", cmd);
+#endif
+                               ret = g_spawn_command_line_async(cmd, &error);
+
+                               /* Check that the command launched */
+                               if (!ret)
+                               {
+                                       g_printerr (_("Failed to launch web browser command: `%s'\n"), cmd);
+                                       g_printerr (_("Error message: %s\n"), error->message);
+                               }
+
+                               /* Free allocated memory */
+                               g_free (web_browser_cmd);
+                               g_free (cmd);
+                       }
+
+                       /* Always free match if it is non NULL */
+                       g_free (match);
+                       break;
+
+               default:
+                       break;
+       }
+
+       return FALSE;
+}
+
+/**
+ * Set the given TildaTerminal to the appropriate transparency level
+ * based on the self->transparency_percent member. */
+static void
+tilda_terminal_set_transparent (TildaTerminal *self)
+{
+       TildaWindow *parent_window = TILDA_WINDOW(self->parent_window);
+       gdouble temp;
+
+       /* Convert the transparency to VTE's format */
+       temp = ((gdouble) self->transparency_percent) / 100.0;
+
+       if (self->transparency_percent > 0)
+       {
+               vte_terminal_set_background_saturation (VTE_TERMINAL(self->vte_term), temp);
+               vte_terminal_set_opacity (VTE_TERMINAL(self->vte_term), (1.0 - temp) * 0xffff);
+
+               /* Use fake transparency if necessary */
+               vte_terminal_set_background_transparent (VTE_TERMINAL(self->vte_term),
+                                                                                                !parent_window->have_real_transparency);
+               return;
+       }
+
+       /* Turn off transparency */
+       vte_terminal_set_background_saturation (VTE_TERMINAL(self->vte_term), 0);
+       vte_terminal_set_opacity (VTE_TERMINAL(self->vte_term), 0xffff);
+       vte_terminal_set_background_transparent (VTE_TERMINAL(self->vte_term), FALSE);
+}
+
+/**
+ * Set the scrollbar position of the given TildaTerminal to
+ * the value in self->scrollbar_position.
+ */
+static void
+tilda_terminal_set_scrollbar_position (TildaTerminal *self)
+{
+       enum scrollbar_positions { DISABLED, LEFT, RIGHT };
+       switch (self->scrollbar_position)
+       {
+               case LEFT:
+                       gtk_box_reorder_child (GTK_BOX(self->hbox), self->scrollbar, 0);
+                       gtk_widget_show (self->scrollbar);
+                       break;
+
+               case RIGHT:
+                       gtk_box_reorder_child (GTK_BOX(self->hbox), self->scrollbar, 1);
+                       gtk_widget_show (self->scrollbar);
+                       break;
+
+               case DISABLED:
+               default:
+                       gtk_widget_hide (self->scrollbar);
+                       break;
+       }
+}
+
 /*******************************************************************************
  * All GObject stuff is below. You probably don't need to change this...
  ******************************************************************************/
@@ -109,6 +322,7 @@ enum tilda_terminal_properties {
        TILDA_TERMINAL_FONT,
        TILDA_TERMINAL_TITLE,
        TILDA_TERMINAL_WORKING_DIRECTORY,
+       TILDA_TERMINAL_WEB_BROWSER,
 
        TILDA_TERMINAL_SCROLLBACK_LINES,
        TILDA_TERMINAL_TRANSPARENCY_PERCENT,
@@ -117,6 +331,7 @@ enum tilda_terminal_properties {
        TILDA_TERMINAL_DELETE_BINDING,
        TILDA_TERMINAL_DYNAMIC_TITLE,
        TILDA_TERMINAL_EXIT_ACTION,
+       TILDA_TERMINAL_SCROLLBAR_POSITION,
 
        TILDA_TERMINAL_SCROLL_BACKGROUND,
        TILDA_TERMINAL_SCROLL_ON_OUTPUT,
@@ -207,6 +422,12 @@ tilda_terminal_set_property (GObject      *object,
                        g_print ("terminal wrk dir: %s\n", self->working_directory);
                        break;
 
+               case TILDA_TERMINAL_WEB_BROWSER:
+                       g_free (self->web_browser);
+                       self->web_browser = g_value_dup_string (value);
+                       g_print ("terminal web browser: %s\n", self->web_browser);
+                       break;
+
                case TILDA_TERMINAL_SCROLLBACK_LINES:
                        self->scrollback_lines = g_value_get_int (value);
                        vte_terminal_set_scrollback_lines (VTE_TERMINAL(self->vte_term), self->scrollback_lines);
@@ -215,6 +436,7 @@ tilda_terminal_set_property (GObject      *object,
 
                case TILDA_TERMINAL_TRANSPARENCY_PERCENT:
                        self->transparency_percent = g_value_get_int (value);
+                       tilda_terminal_set_transparent (self);
                        g_print ("terminal transp percent: %d\n", self->transparency_percent);
                        break;
 
@@ -240,6 +462,12 @@ tilda_terminal_set_property (GObject      *object,
                        g_print ("terminal exit action: %d\n", self->exit_action);
                        break;
 
+               case TILDA_TERMINAL_SCROLLBAR_POSITION:
+                       self->scrollbar_position = g_value_get_int (value);
+                       tilda_terminal_set_scrollbar_position (self);
+                       g_print ("terminal scrollbar position: %d\n", self->scrollbar_position);
+                       break;
+
                case TILDA_TERMINAL_SCROLL_BACKGROUND:
                        self->scroll_background = g_value_get_boolean (value);
                        vte_terminal_set_scroll_background (VTE_TERMINAL(self->vte_term), self->scroll_background);
@@ -351,6 +579,10 @@ tilda_terminal_get_property (GObject    *object,
                        g_value_set_string (value, self->working_directory);
                        break;
 
+               case TILDA_TERMINAL_WEB_BROWSER:
+                       g_value_set_string (value, self->web_browser);
+                       break;
+
                case TILDA_TERMINAL_SCROLLBACK_LINES:
                        g_value_set_int (value, self->scrollback_lines);
                        break;
@@ -375,6 +607,10 @@ tilda_terminal_get_property (GObject    *object,
                        g_value_set_int (value, self->exit_action);
                        break;
 
+               case TILDA_TERMINAL_SCROLLBAR_POSITION:
+                       g_value_set_int (value, self->scrollbar_position);
+                       break;
+
                case TILDA_TERMINAL_SCROLL_BACKGROUND:
                        g_value_set_boolean (value, self->scroll_background);
                        break;
@@ -413,7 +649,6 @@ tilda_terminal_get_property (GObject    *object,
 
                case TILDA_TERMINAL_MOUSE_AUTOHIDE:
                        g_value_set_boolean (value, self->mouse_autohide);
-                       break;
 
                default:
                        /* We don't have this property... */
@@ -429,6 +664,7 @@ tilda_terminal_constructor (GType                  type,
 {
        GObject *obj;
        TildaTerminal *self;
+       gint ret;
 
        /* Invoke parent constructor */
        TildaTerminalClass *klass;
@@ -448,9 +684,21 @@ tilda_terminal_constructor (GType                  type,
        gtk_box_pack_end (GTK_BOX(self->hbox), self->vte_term, TRUE, TRUE, 0);
        gtk_widget_show (self->scrollbar);
 
+       /* Match URL's, etc */
+       ret = vte_terminal_match_add (VTE_TERMINAL(self->vte_term), DINGUS1);
+       vte_terminal_match_set_cursor_type (VTE_TERMINAL(self->vte_term), ret, GDK_HAND2);
+       ret = vte_terminal_match_add(VTE_TERMINAL(self->vte_term), DINGUS2);
+       vte_terminal_match_set_cursor_type (VTE_TERMINAL(self->vte_term), ret, GDK_HAND2);
 
+       /* Connect Signals */
        g_signal_connect (G_OBJECT(self->vte_term), "child-exited",
-                                         G_CALLBACK(gtk_main_quit), self);
+                                         G_CALLBACK(tilda_terminal_child_exited_cb), self);
+       g_signal_connect (G_OBJECT(self->vte_term), "eof",
+                                         G_CALLBACK(tilda_terminal_child_exited_cb), self);
+       g_signal_connect (G_OBJECT(self->vte_term), "window-title-changed",
+                                         G_CALLBACK(tilda_terminal_window_title_changed_cb), self);
+       g_signal_connect (G_OBJECT(self->vte_term), "button-press-event",
+                                         G_CALLBACK(tilda_terminal_button_press_cb), self);
 
        tilda_terminal_start_shell (self);
        tilda_terminal_dbus_register_object (self);
@@ -606,6 +854,16 @@ tilda_terminal_class_init (gpointer g_class,
                                                                         TILDA_TERMINAL_WORKING_DIRECTORY,
                                                                         pspec);
 
+       pspec = g_param_spec_string ("web-browser",
+                                                                "Terminal's web browser command",
+                                                                NULL,
+                                                                NULL,
+                                                                G_PARAM_READWRITE);
+
+       g_object_class_install_property (gobject_class,
+                                                                        TILDA_TERMINAL_WEB_BROWSER,
+                                                                        pspec);
+
        pspec = g_param_spec_int ("scrollback-lines",
                                                          "Terminal's scrollback amount (lines)",
                                                          "Get/Set terminal's scrollback amount",
@@ -678,6 +936,18 @@ tilda_terminal_class_init (gpointer g_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);
+
+       g_object_class_install_property (gobject_class,
+                                                                        TILDA_TERMINAL_SCROLLBAR_POSITION,
+                                                                        pspec);
+
        pspec = g_param_spec_boolean ("scroll-background",
                                                                  "Controls terminal's scrolling behavior",
                                                                  "Get/Set terminal's scrolling behavior",