gchar *get_window_title (GtkWidget *widget) { DEBUG_FUNCTION ("get_window_title"); DEBUG_ASSERT (widget != NULL); const gchar *vte_title; gchar *window_title; gchar *initial; gchar *title; vte_title = vte_terminal_get_window_title (VTE_TERMINAL (widget)); window_title = g_strdup (vte_title); initial = g_strdup (config_getstr ("title")); /* These are not needed anywhere else. If they ever are, move them to a header file */ enum d_set_title { NOT_DISPLAYED, AFTER_INITIAL, BEFORE_INITIAL, REPLACE_INITIAL }; switch (config_getint ("d_set_title")) { case REPLACE_INITIAL: title = (window_title != NULL) ? g_strdup (window_title) : g_strdup (_("Untitled")); break; case BEFORE_INITIAL: title = (window_title != NULL) ? g_strdup_printf ("%s - %s", window_title, initial) : g_strdup (initial); break; case AFTER_INITIAL: title = (window_title != NULL) ? g_strdup_printf ("%s - %s", initial, window_title) : g_strdup (initial); break; case NOT_DISPLAYED: title = g_strdup (initial); break; default: g_printerr (_("Bad value for \"d_set_title\" in config file\n")); title = g_strdup (""); break; } g_free (window_title); g_free (initial); return title; }
/* * Compare config file versions and see if we know about a new version. * * If we have a version newer than what we know about, we need to stop * anything from writing to the config file. * * If we are at the same config version, we're done, so exit early. * * If the config is older than we are now, update it and then write * it to disk. */ static void try_to_update_config_file (const gchar *config_file) { DEBUG_FUNCTION ("try_to_update_config_file"); DEBUG_ASSERT (config_file != NULL); gboolean changed = FALSE; gchar *current_config = config_getstr ("tilda_config_version"); if (compare_config_versions (current_config, PACKAGE_VERSION) == CONFIGS_SAME) return; // Same version as ourselves, we're done! if (compare_config_versions (current_config, PACKAGE_VERSION) == CONFIG1_NEWER) { // We have a version newer than ourselves! // Disable writing to the config for safety. config_writing_disabled = TRUE; return; // Out early, since we won't be able to update anyway! } /* NOTE: Start with the oldest config version first, and work our way up to the * NOTE: newest that we support, updating our current version each time. * * NOTE: You may need to re-read the config each time! Probably not though, * NOTE: since you should be updating VALUES not names directly in the config. * NOTE: Try to rely on libconfuse to generate the configs :) */ /* Below is a template for creating new entries in the updater. If you ever * change anything between versions, copy this, replacing YOUR_VERSION * with the new version that you are making. */ #if 0 if (compare_config_versions (current_config, YOUR_VERSION) == CONFIG1_OLDER) { // TODO: Add things here to migrate from whatever we are to YOUR_VERSION current_config = YOUR_VERSION; changed = TRUE; } #endif if (compare_config_versions (current_config, "0.09.4") == CONFIG1_OLDER) { /* Nothing to update here. All we did was add an option, there is no * need to rewrite the config file here, since the writer at the end * will automatically add the default value of the new option. */ current_config = "0.09.4"; changed = TRUE; } if (compare_config_versions (current_config, "0.9.5") == CONFIG1_OLDER) { char *old_key; char *new_key; old_key = config_getstr ("key"); new_key = upgrade_key_to_095 (old_key); config_setstr ("key", new_key); free (new_key); current_config = "0.9.5"; changed = TRUE; } /* We've run through all the updates, so set our config file version to the * version we're at now, then write out the config file. * * NOTE: this only happens if we upgraded the config, due to some early-exit * logic above. */ if (changed) { config_setstr ("tilda_config_version", current_config); config_write (config_file); } }
/** * tilda_term_config_defaults () * * Read and set all of the defaults for this terminal from the current configuration. * * Success: return 0 * Failure: return non-zero */ static gint tilda_term_config_defaults (tilda_term *tt) { DEBUG_FUNCTION ("tilda_term_config_defaults"); DEBUG_ASSERT (tt != NULL); gdouble transparency_level = 0.0; GdkRGBA fg, bg, cc; gchar* word_chars; gint i; gint cursor_shape; /** Colors & Palette **/ bg.red = GUINT16_TO_FLOAT(config_getint ("back_red")); bg.green = GUINT16_TO_FLOAT(config_getint ("back_green")); bg.blue = GUINT16_TO_FLOAT(config_getint ("back_blue")); bg.alpha = 1.0; fg.red = GUINT16_TO_FLOAT(config_getint ("text_red")); fg.green = GUINT16_TO_FLOAT(config_getint ("text_green")); fg.blue = GUINT16_TO_FLOAT(config_getint ("text_blue")); fg.alpha = 1.0; cc.red = GUINT16_TO_FLOAT(config_getint ("cursor_red")); cc.green = GUINT16_TO_FLOAT(config_getint ("cursor_green")); cc.blue = GUINT16_TO_FLOAT(config_getint ("cursor_blue")); cc.alpha = 1.0; for(i = 0;i < TERMINAL_PALETTE_SIZE; i++) { current_palette[i].red = GUINT16_TO_FLOAT(config_getnint ("palette", i*3)); current_palette[i].green = GUINT16_TO_FLOAT(config_getnint ("palette", i*3+1)); current_palette[i].blue = GUINT16_TO_FLOAT(config_getnint ("palette", i*3+2)); current_palette[i].alpha = 1.0; } vte_terminal_set_colors_rgba (VTE_TERMINAL(tt->vte_term), &fg, &bg, current_palette, TERMINAL_PALETTE_SIZE); /** Bells **/ vte_terminal_set_audible_bell (VTE_TERMINAL(tt->vte_term), config_getbool ("bell")); vte_terminal_set_visible_bell (VTE_TERMINAL(tt->vte_term), config_getbool ("bell")); /** Cursor **/ vte_terminal_set_cursor_blink_mode (VTE_TERMINAL(tt->vte_term), (config_getbool ("blinks"))?VTE_CURSOR_BLINK_ON:VTE_CURSOR_BLINK_OFF); vte_terminal_set_color_cursor_rgba (VTE_TERMINAL(tt->vte_term), &cc); cursor_shape = config_getint("cursor_shape"); if (cursor_shape < 0 || cursor_shape > 2) { config_setint("cursor_shape", 0); cursor_shape = 0; } vte_terminal_set_cursor_shape(VTE_TERMINAL(tt->vte_term), (VteTerminalCursorShape)cursor_shape); /** Scrolling **/ vte_terminal_set_scroll_background (VTE_TERMINAL(tt->vte_term), config_getbool ("scroll_background")); vte_terminal_set_scroll_on_output (VTE_TERMINAL(tt->vte_term), config_getbool ("scroll_on_output")); vte_terminal_set_scroll_on_keystroke (VTE_TERMINAL(tt->vte_term), config_getbool ("scroll_on_key")); /** Mouse **/ vte_terminal_set_mouse_autohide (VTE_TERMINAL(tt->vte_term), FALSE); /* TODO: make this configurable */ /** Text Properties **/ vte_terminal_set_allow_bold (VTE_TERMINAL(tt->vte_term), config_getbool ("bold")); gtk_widget_set_double_buffered (tt->vte_term, config_getbool("double_buffer")); PangoFontDescription *description = pango_font_description_from_string (config_getstr ("font")); vte_terminal_set_font (VTE_TERMINAL (tt->vte_term), description); /** Scrollback **/ vte_terminal_set_scrollback_lines (VTE_TERMINAL(tt->vte_term), config_getbool("scroll_history_infinite") ? -1 : config_getint ("lines")); /** Keys **/ switch (config_getint ("backspace_key")) { case ASCII_DELETE: vte_terminal_set_backspace_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_ASCII_DELETE); break; case DELETE_SEQUENCE: vte_terminal_set_backspace_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_DELETE_SEQUENCE); break; case ASCII_BACKSPACE: vte_terminal_set_backspace_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_ASCII_BACKSPACE); break; case AUTO: default: vte_terminal_set_backspace_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_AUTO); break; } switch (config_getint ("delete_key")) { case ASCII_DELETE: vte_terminal_set_delete_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_ASCII_DELETE); break; case DELETE_SEQUENCE: vte_terminal_set_delete_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_DELETE_SEQUENCE); break; case ASCII_BACKSPACE: vte_terminal_set_delete_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_ASCII_BACKSPACE); break; case AUTO: default: vte_terminal_set_delete_binding (VTE_TERMINAL(tt->vte_term), VTE_ERASE_AUTO); break; } /** Word chars **/ word_chars = config_getstr ("word_chars"); if (NULL == word_chars || '\0' == *word_chars) { word_chars = DEFAULT_WORD_CHARS; } vte_terminal_set_word_chars (VTE_TERMINAL(tt->vte_term), word_chars); /** Background **/ if (config_getbool ("use_image")) vte_terminal_set_background_image_file (VTE_TERMINAL(tt->vte_term), config_getstr ("image")); else vte_terminal_set_background_image_file (VTE_TERMINAL(tt->vte_term), NULL); transparency_level = ((gdouble) config_getint ("transparency"))/100; if (config_getbool ("enable_transparency") && transparency_level > 0) { vte_terminal_set_background_saturation (VTE_TERMINAL (tt->vte_term), transparency_level); vte_terminal_set_opacity (VTE_TERMINAL (tt->vte_term), (1.0 - transparency_level) * 0xffff); vte_terminal_set_background_transparent (VTE_TERMINAL(tt->vte_term), !tt->tw->have_argb_visual); } return 0; }
/* Fork a shell into the VTE Terminal * * @param tt the tilda_term to fork into * * SUCCESS: return 0 * FAILURE: return non-zero */ static gint start_shell (struct tilda_term_ *tt, gboolean ignore_custom_command, const char* working_dir) { DEBUG_FUNCTION ("start_shell"); DEBUG_ASSERT (tt != NULL); gint ret; gint argc; gchar **argv; GError *error = NULL; gchar *default_command; if (working_dir == NULL || config_getbool ("inherit_working_dir") == FALSE) { working_dir = config_getstr ("working_dir"); } if (config_getbool ("run_command") && !ignore_custom_command) { ret = g_shell_parse_argv (config_getstr ("command"), &argc, &argv, &error); /* Check for error */ if (ret == FALSE) { g_printerr (_("Problem parsing custom command: %s\n"), error->message); g_printerr (_("Launching default shell instead\n")); g_error_free (error); goto launch_default_shell; } char **envv = malloc(2*sizeof(void *)); envv[0] = getenv("PATH"); envv[1] = NULL; ret = vte_terminal_fork_command_full (VTE_TERMINAL (tt->vte_term), VTE_PTY_DEFAULT, /* VtePtyFlags pty_flags */ working_dir, /* const char *working_directory */ argv, /* char **argv */ envv, /* char **envv */ G_SPAWN_SEARCH_PATH, /* GSpawnFlags spawn_flags */ NULL, /* GSpawnChildSetupFunc child_setup */ NULL, /* gpointer child_setup_data */ &tt->pid, /* GPid *child_pid */ NULL /* GError **error */ ); g_strfreev (argv); g_free (envv); /* Check for error */ if (ret == FALSE) { g_printerr (_("Unable to launch custom command: %s\n"), config_getstr ("command")); g_printerr (_("Launching default shell instead\n")); goto launch_default_shell; } return 0; /* SUCCESS: the early way out */ } launch_default_shell: /* If we have dropped to the default shell before, then this time, we * do not spawn a new shell, but instead close the current shell. This will * cause the current tab to close. */ if (tt->dropped_to_default_shell) { gint index = gtk_notebook_page_num (GTK_NOTEBOOK(tt->tw->notebook), tt->hbox); tilda_window_close_tab (tt->tw, index, FALSE); return 0; } if (ignore_custom_command) { tt->dropped_to_default_shell = TRUE; } /* No custom command, get it from the environment */ default_command = (gchar *) g_getenv ("SHELL"); /* Check for error */ if (default_command == NULL) default_command = "/bin/sh"; /* We need to create a NULL terminated list of arguments. * The first item is the command to execute in the shell, in this * case there are no further arguments being passed. */ GSpawnFlags flags = 0; gchar* argv1 = NULL; if(config_getbool("command_login_shell")) { argv1 = g_strdup_printf("-%s", default_command); argv = malloc(3 * sizeof(void *)); argv[0] = default_command; argv[1] = argv1; argv[2] = NULL; /* This is needed so that argv[1] becomes the argv[0] of the new process. Otherwise * glib just duplicates argv[0] when it executes the command and it is not possible * to modify the argv[0] that the new command sees. */ flags |= G_SPAWN_FILE_AND_ARGV_ZERO; } else { argv = malloc(1 * sizeof(void *)); argv[0] = default_command; argv[1] = NULL; } ret = vte_terminal_fork_command_full (VTE_TERMINAL (tt->vte_term), VTE_PTY_DEFAULT, /* VtePtyFlags pty_flags */ working_dir, /* const char *working_directory */ argv, /* char **argv */ NULL, /* char **envv */ flags, /* GSpawnFlags spawn_flags */ NULL, /* GSpawnChildSetupFunc child_setup */ NULL, /* gpointer child_setup_data */ &tt->pid, /* GPid *child_pid */ NULL /* GError **error */ ); g_free(argv1); g_free (argv); if (ret == -1) { g_printerr (_("Unable to launch default shell: %s\n"), default_command); return ret; } return 0; }
static int button_press_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { DEBUG_FUNCTION ("button_press_cb"); DEBUG_ASSERT (data != NULL); VteTerminal *terminal; tilda_term *tt; gchar *match; gint tag; gint xpad, ypad; gchar *cmd; gchar *web_browser_cmd; gboolean ret = FALSE; tt = TILDA_TERM(data); switch (event->button) { case 3: /* Right Click */ popup_menu (tt->tw, tt); break; case 2: /* Middle Click */ break; case 1: /* Left Click */ terminal = VTE_TERMINAL(tt->vte_term); GtkBorder border; gtk_widget_style_get (GTK_WIDGET (terminal), "inner-border", &border, NULL); xpad = border.left; ypad = border.bottom; match = vte_terminal_match_check (terminal, (event->x - ypad) / vte_terminal_get_char_width (terminal), (event->y - ypad) / vte_terminal_get_char_height (terminal), &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 (config_getstr ("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, NULL); /* Check that the command launched */ if (!ret) { g_printerr (_("Failed to launch the web browser. The command was `%s'\n"), cmd); TILDA_PERROR (); } g_free (cmd); } /* Always free match if it is non NULL */ if (match) g_free (match); break; default: break; } return FALSE; }
static void popup_menu (tilda_window *tw, tilda_term *tt) { DEBUG_FUNCTION ("popup_menu"); DEBUG_ASSERT (tw != NULL); DEBUG_ASSERT (tt != NULL); 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=\"new-tab\" />" "<menuitem action=\"close-tab\" />" "<separator />" "<menuitem action=\"copy\" />" "<menuitem action=\"paste\" />" "<separator />" "<menuitem action=\"fullscreen\" />" "<separator />" "<menuitem action=\"preferences\" />" "<separator />" "<menuitem action=\"quit\" />" "</popup>" "</ui>"; /* Create the action group */ action_group = gtk_action_group_new ("popup-menu-action-group"); /* Add Actions and connect callbacks */ action = gtk_action_new ("new-tab", _("_New Tab"), NULL, GTK_STOCK_ADD); gtk_action_group_add_action_with_accel (action_group, action, config_getstr("addtab_key")); g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_add_tab_cb), tw); action = gtk_action_new ("close-tab", _("_Close Tab"), NULL, GTK_STOCK_CLOSE); gtk_action_group_add_action_with_accel (action_group, action, config_getstr("closetab_key")); g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_close_tab_cb), tw); action = gtk_action_new ("copy", NULL, NULL, GTK_STOCK_COPY); gtk_action_group_add_action_with_accel (action_group, action, config_getstr("copy_key")); g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_copy_cb), tt); action = gtk_action_new ("paste", NULL, NULL, GTK_STOCK_PASTE); gtk_action_group_add_action_with_accel (action_group, action, config_getstr("paste_key")); g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_paste_cb), tt); action = gtk_action_new ("fullscreen", _("Toggle fullscreen"), NULL, NULL); gtk_action_group_add_action (action_group, action); g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_fullscreen_cb), tw); 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), tw); action = gtk_action_new ("quit", NULL, NULL, GTK_STOCK_QUIT); gtk_action_group_add_action_with_accel (action_group, action, config_getstr("quit_key")); g_signal_connect (G_OBJECT(action), "activate", G_CALLBACK(menu_quit_cb), tw); /* 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) { DEBUG_ERROR ("GtkUIManager problem\n"); g_printerr ("Error message: %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"); /* Disable auto hide */ tw->disable_auto_hide = TRUE; g_signal_connect (G_OBJECT(menu), "unmap", G_CALLBACK(on_popup_hide), tw); /* Display the menu */ gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time()); gtk_widget_show_all(menu); }
/* Fork a shell into the VTE Terminal * * @param tt the tilda_term to fork into * * SUCCESS: return 0 * FAILURE: return non-zero */ static gint start_shell (struct tilda_term_ *tt) { DEBUG_FUNCTION ("start_shell"); DEBUG_ASSERT (tt != NULL); gint ret; gint argc; gchar **argv; GError *error = NULL; gchar *default_command; if (config_getbool ("run_command")) { ret = g_shell_parse_argv (config_getstr ("command"), &argc, &argv, &error); /* Check for error */ if (ret == FALSE) { g_printerr (_("Problem parsing custom command: %s\n"), error->message); g_printerr (_("Launching default shell instead\n")); g_error_free (error); goto launch_default_shell; } char **envv = malloc(2*sizeof(void *)); envv[0] = getenv("PATH"); envv[1] = NULL; ret = vte_terminal_fork_command_full (VTE_TERMINAL (tt->vte_term), VTE_PTY_DEFAULT, /* VtePtyFlags pty_flags */ config_getstr ("working_dir"), /* const char *working_directory */ argv, /* char **argv */ envv, /* char **envv */ G_SPAWN_SEARCH_PATH, /* GSpawnFlags spawn_flags */ NULL, /* GSpawnChildSetupFunc child_setup */ NULL, /* gpointer child_setup_data */ NULL, /* GPid *child_pid */ NULL /* GError **error */ ); g_strfreev (argv); g_free (envv); /* Check for error */ if (ret == -1) { g_printerr (_("Unable to launch custom command: %s\n"), config_getstr ("command")); g_printerr (_("Launching default shell instead\n")); goto launch_default_shell; } return 0; /* SUCCESS: the early way out */ } launch_default_shell: /* No custom command, get it from the environment */ default_command = (gchar *) g_getenv ("SHELL"); /* Check for error */ if (default_command == NULL) default_command = "/bin/sh"; /* We need to create a NULL terminated list of arguments. * The first item is the command to execute in the shell, in this * case there are no further arguments being passed. */ argv = malloc(2 * sizeof(void *)); argv[0] = default_command; argv[1] = NULL; ret = vte_terminal_fork_command_full (VTE_TERMINAL (tt->vte_term), VTE_PTY_DEFAULT, /* VtePtyFlags pty_flags */ config_getstr ("working_dir"), /* const char *working_directory */ argv, /* char **argv */ NULL, /* char **envv */ 0, /* GSpawnFlags spawn_flags */ NULL, /* GSpawnChildSetupFunc child_setup */ NULL, /* gpointer child_setup_data */ NULL, /* GPid *child_pid */ NULL /* GError **error */ ); g_free (argv); if (ret == -1) { g_printerr (_("Unable to launch default shell: %s\n"), default_command); return ret; } return 0; }