static void ide_terminal_page_spawn_cb (GObject *object, GAsyncResult *result, gpointer user_data) { IdeTerminalLauncher *launcher = (IdeTerminalLauncher *)object; g_autoptr(IdeTerminalPage) self = user_data; g_autoptr(GError) error = NULL; gint64 now; g_assert (IDE_IS_TERMINAL_LAUNCHER (launcher)); g_assert (G_IS_ASYNC_RESULT (result)); g_assert (IDE_IS_TERMINAL_PAGE (self)); if (!ide_terminal_launcher_spawn_finish (launcher, result, &error)) { g_autofree gchar *format = NULL; format = g_strdup_printf ("%s: %s", _("Subprocess launcher failed"), error->message); ide_terminal_page_feed (self, format); } if (gtk_widget_in_destruction (GTK_WIDGET (self))) return; now = g_get_monotonic_time (); if (ABS (now - self->last_respawn) < FLAPPING_DURATION_USEC) { ide_terminal_page_feed (self, _("Subprocess launcher failed too quickly, will not respawn.")); return; } if (!self->respawn_on_exit) { if (self->close_on_exit) gdk_threads_add_idle_full (G_PRIORITY_LOW + 1000, (GSourceFunc) destroy_widget_in_idle, g_object_ref (self), g_object_unref); return; } g_clear_object (&self->pty); vte_terminal_reset (VTE_TERMINAL (self->terminal_top), TRUE, TRUE); self->pty = vte_pty_new_sync (VTE_PTY_DEFAULT, NULL, NULL); vte_terminal_set_pty (VTE_TERMINAL (self->terminal_top), self->pty); /* Spawn our terminal and wait for it to exit */ self->last_respawn = now; ide_terminal_launcher_spawn_async (self->launcher, self->pty, NULL, ide_terminal_page_spawn_cb, g_object_ref (self)); }
void ide_terminal_page_set_pty (IdeTerminalPage *self, VtePty *pty) { g_return_if_fail (IDE_IS_TERMINAL_PAGE (self)); g_return_if_fail (VTE_IS_PTY (pty)); if (g_set_object (&self->pty, pty)) { vte_terminal_reset (VTE_TERMINAL (self->terminal_top), TRUE, TRUE); vte_terminal_set_pty (VTE_TERMINAL (self->terminal_top), pty); } }
static void gb_terminal_realize (GtkWidget *widget) { GbTerminalView *self = (GbTerminalView *)widget; g_assert (GB_IS_TERMINAL_VIEW (self)); GTK_WIDGET_CLASS (gb_terminal_view_parent_class)->realize (widget); if (self->manage_spawn && !self->top_has_spawned) { self->top_has_spawned = TRUE; gb_terminal_respawn (self, self->terminal_top); } if (!self->manage_spawn && self->pty != NULL) vte_terminal_set_pty (self->terminal_top, self->pty); }
void gb_terminal_view_set_pty (GbTerminalView *self, VtePty *pty) { g_return_if_fail (GB_IS_TERMINAL_VIEW (self)); g_return_if_fail (VTE_IS_PTY (pty)); if (self->manage_spawn) { g_warning ("Cannot set pty when GbTerminalView manages tty"); return; } if (self->terminal_top) { vte_terminal_reset (self->terminal_top, TRUE, TRUE); vte_terminal_set_pty (self->terminal_top, pty); } }
static void vte_spawn(VteTerminal* vte, char* working_directory, char* command, char** environment) { GError* error = NULL; char** command_argv = NULL; /* Parse command into array */ if (!command) command = vte_get_user_shell(); g_shell_parse_argv(command, NULL, &command_argv, &error); if (error) { g_printerr("Failed to parse command: %s\n", error->message); g_error_free(error); exit(EXIT_FAILURE); } /* Create pty object */ VtePty* pty = vte_terminal_pty_new_sync(vte, VTE_PTY_NO_HELPER, NULL, &error); if (error) { g_printerr("Failed to create pty: %s\n", error->message); g_error_free(error); exit(EXIT_FAILURE); } vte_terminal_set_pty(vte, pty); int child_pid; /* Spawn default shell (or specified command) */ g_spawn_async(working_directory, command_argv, environment, (G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN), // flags from GSpawnFlags (GSpawnChildSetupFunc)vte_pty_child_setup, // an extra child setup function to run in the child just before exec() pty, // user data for child_setup &child_pid, // a location to store the child PID &error); // return location for a GError if (error) { g_printerr("%s\n", error->message); g_error_free(error); exit(EXIT_FAILURE); } vte_terminal_watch_child(vte, child_pid); g_strfreev(command_argv); }
static void gbp_terminal_page_realize (GtkWidget *widget) { IdeTerminalPage *self = (IdeTerminalPage *)widget; g_assert (IDE_IS_TERMINAL_PAGE (self)); GTK_WIDGET_CLASS (ide_terminal_page_parent_class)->realize (widget); if (self->did_defered_setup_in_realize) return; self->did_defered_setup_in_realize = TRUE; self->last_respawn = g_get_monotonic_time (); if (self->pty == NULL) { g_autoptr(GError) error = NULL; if (!(self->pty = vte_pty_new_sync (VTE_PTY_DEFAULT, NULL, &error))) { g_critical ("Failed to create PTY for terminal: %s", error->message); return; } } vte_terminal_set_pty (VTE_TERMINAL (self->terminal_top), self->pty); if (!self->manage_spawn) return; /* Spawn our terminal and wait for it to exit */ ide_terminal_launcher_spawn_async (self->launcher, self->pty, NULL, ide_terminal_page_spawn_cb, g_object_ref (self)); }
/* * init debug related GUI (watch tree view) * arguments: */ void debug_init() { /* create watch page */ wtree = wtree_init(on_watch_expanded_callback, on_watch_dragged_callback, on_watch_key_pressed_callback, on_watch_changed, on_watch_button_pressed_callback); wmodel = gtk_tree_view_get_model(GTK_TREE_VIEW(wtree)); wstore = GTK_TREE_STORE(wmodel); tab_watch = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(wtree)), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(wtree)) ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_watch), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tab_watch), wtree); /* create autos page */ atree = atree_init(on_watch_expanded_callback, on_watch_button_pressed_callback); tab_autos = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(atree)), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(atree)) ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_autos), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tab_autos), atree); /* create stack trace page */ stree = stree_init(editor_open_position, on_select_frame); tab_call_stack = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(stree )), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(stree )) ); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_call_stack), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(tab_call_stack), stree); /* create debug terminal page */ terminal = vte_terminal_new(); /* create PTY */ openpty(&pty_master, &pty_slave, NULL, NULL, NULL); grantpt(pty_master); unlockpt(pty_master); vte_terminal_set_pty(VTE_TERMINAL(terminal), pty_master); GtkWidget *scrollbar = gtk_vscrollbar_new(GTK_ADJUSTMENT(VTE_TERMINAL(terminal)->adjustment)); GTK_WIDGET_UNSET_FLAGS(scrollbar, GTK_CAN_FOCUS); tab_terminal = gtk_frame_new(NULL); gtk_frame_set_shadow_type (GTK_FRAME(tab_terminal), GTK_SHADOW_NONE); GtkWidget *hbox = gtk_hbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(tab_terminal), hbox); gtk_box_pack_start(GTK_BOX(hbox), terminal, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0); /* set the default widget size first to prevent VTE expanding too much, * sometimes causing the hscrollbar to be too big or out of view. */ gtk_widget_set_size_request(GTK_WIDGET(terminal), 10, 10); vte_terminal_set_size(VTE_TERMINAL(terminal), 30, 1); /* set terminal font. */ GKeyFile *config = g_key_file_new(); gchar *configfile = g_strconcat(geany_data->app->configdir, G_DIR_SEPARATOR_S, "geany.conf", NULL); g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL); gchar *font = utils_get_setting_string(config, "VTE", "font", "Monospace 10"); vte_terminal_set_font_from_string (VTE_TERMINAL(terminal), font); /* debug messages page */ tab_messages = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tab_messages), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(tab_messages)); vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(tab_messages)); debugger_messages_textview = gtk_text_view_new(); gtk_text_view_set_editable (GTK_TEXT_VIEW (debugger_messages_textview), FALSE); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tab_messages), debugger_messages_textview); /* create tex tags */ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(debugger_messages_textview)); gtk_text_buffer_create_tag(buffer, "black", "foreground", "#000000", NULL); gtk_text_buffer_create_tag(buffer, "grey", "foreground", "#AAAAAA", NULL); gtk_text_buffer_create_tag(buffer, "red", "foreground", "#FF0000", NULL); gtk_text_buffer_create_tag(buffer, "green", "foreground", "#00FF00", NULL); gtk_text_buffer_create_tag(buffer, "blue", "foreground", "#0000FF", NULL); gtk_text_buffer_create_tag(buffer, "yellow", "foreground", "#FFFF00", NULL); gtk_text_buffer_create_tag(buffer, "brown", "foreground", "#BB8915", NULL); gtk_text_buffer_create_tag(buffer, "rose", "foreground", "#BA92B7", NULL); }
void conterm_init(void) { GtkWidget *console; #ifdef G_OS_UNIX gchar *error = NULL; int pty_master; char *pty_name; #endif conterm_load_config(); #ifdef G_OS_UNIX program_window = get_widget("program_window"); console = vte_terminal_new(); gtk_widget_show(console); program_terminal = VTE_TERMINAL(console); g_object_ref(program_terminal); gtk_container_add(GTK_CONTAINER(program_window), console); g_signal_connect_after(program_terminal, "realize", G_CALLBACK(on_vte_realize), NULL); terminal_parent = get_widget("terminal_parent"); g_signal_connect(terminal_parent, "delete-event", G_CALLBACK(on_terminal_parent_delete), NULL); terminal_window = get_widget("terminal_window"); terminal_show = GTK_CHECK_MENU_ITEM(get_widget("terminal_show")); if (pref_terminal_padding) { gint vte_border_x, vte_border_y; #if GTK_CHECK_VERSION(3, 4, 0) GtkStyleContext *context; GtkBorder border; context = gtk_widget_get_style_context (console); gtk_style_context_get_padding (context, GTK_STATE_FLAG_NORMAL, &border); vte_border_x = border.left + border.right; vte_border_y = border.top + border.bottom; #elif VTE_CHECK_VERSION(0, 24, 0) GtkBorder *border = NULL; gtk_widget_style_get(console, "inner-border", &border, NULL); if (border) { vte_border_x = border->left + border->right; vte_border_y = border->top + border->bottom; gtk_border_free(border); } else vte_border_x = vte_border_y = 2; #else /* VTE 0.24.0 */ /* VTE manual says "deprecated since 0.26", but it's since 0.24 */ vte_terminal_get_padding(program_terminal, &vte_border_x, &vte_border_y); #endif /* VTE 0.24.0 */ pref_terminal_width += vte_border_x; pref_terminal_height += vte_border_y; pref_terminal_padding = FALSE; } if (openpty(&pty_master, &pty_slave, NULL, NULL, NULL) == 0 && grantpt(pty_master) == 0 && unlockpt(pty_master) == 0 && (pty_name = ttyname(pty_slave)) != NULL) { #if VTE_CHECK_VERSION(0, 25, 0) GError *gerror = NULL; VtePty *pty = vte_pty_new_foreign(pty_master, &gerror); if (pty) { vte_terminal_set_pty_object(program_terminal, pty); slave_pty_name = g_strdup(pty_name); } else { error = g_strdup(gerror->message); g_error_free(gerror); } #else /* VTE 0.25.0 */ vte_terminal_set_pty(program_terminal, pty_master); slave_pty_name = g_strdup(pty_name); #endif /* VTE 0.25.0 */ } else error = g_strdup_printf("pty: %s", g_strerror(errno)); if (error) { gtk_widget_set_sensitive(program_window, FALSE); gtk_widget_set_sensitive(GTK_WIDGET(terminal_show), FALSE); msgwin_status_add(_("Scope: %s."), error); g_free(error); } else menu_connect("terminal_menu", &terminal_menu_info, GTK_WIDGET(program_terminal)); #else /* G_OS_UNIX */ gtk_widget_hide(get_widget("program_window")); #endif /* G_OS_UNIX */ #ifdef G_OS_UNIX if (pref_debug_console_vte) { console = vte_terminal_new(); gtk_widget_show(console); debug_console = VTE_TERMINAL(console); dc_output = console_output; dc_output_nl = console_output_nl; g_signal_connect_after(debug_console, "realize", G_CALLBACK(on_vte_realize), NULL); menu_connect("console_menu", &console_menu_info, console); } else #endif /* G_OS_UNIX */ { static const char *const colors[NFD] = { "#00C0C0", "#C0C0C0", "#C00000", "#C0C0C0", "#C000C0" }; guint i; console = get_widget("debug_context"); context_apply_config(console); debug_context = GTK_TEXT_VIEW(console); dc_output = context_output; dc_output_nl = context_output_nl; context = gtk_text_view_get_buffer(debug_context); for (i = 0; i < NFD; i++) { fd_tags[i] = gtk_text_buffer_create_tag(context, NULL, "foreground", colors[i], NULL); } g_signal_connect(console, "button-press-event", G_CALLBACK(on_console_button_3_press), menu_connect("console_menu", &console_menu_info, NULL)); } gtk_container_add(GTK_CONTAINER(get_widget("debug_window")), console); g_signal_connect(console, "key-press-event", G_CALLBACK(on_console_key_press), NULL); }
static VALUE term_set_pty(VALUE self, VALUE pty_master) { vte_terminal_set_pty(RVAL2TERM(self), NUM2INT(pty_master)); return Qnil; }
static void gb_terminal_respawn (GbTerminalView *self, VteTerminal *terminal) { g_autoptr(GPtrArray) args = NULL; g_autoptr(IdeSubprocess) subprocess = NULL; g_autoptr(IdeSubprocessLauncher) launcher = NULL; g_autofree gchar *workpath = NULL; g_autofree gchar *shell = NULL; GtkWidget *toplevel; GError *error = NULL; IdeContext *context; IdeVcs *vcs; VtePty *pty = NULL; GFile *workdir; gint64 now; int tty_fd = -1; gint stdout_fd = -1; gint stderr_fd = -1; IDE_ENTRY; g_assert (GB_IS_TERMINAL_VIEW (self)); vte_terminal_reset (terminal, TRUE, TRUE); toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self)); if (!IDE_IS_WORKBENCH (toplevel)) IDE_EXIT; /* Prevent flapping */ now = g_get_monotonic_time (); if ((now - self->last_respawn) < (G_USEC_PER_SEC / 10)) IDE_EXIT; self->last_respawn = now; context = ide_workbench_get_context (IDE_WORKBENCH (toplevel)); vcs = ide_context_get_vcs (context); workdir = ide_vcs_get_working_directory (vcs); workpath = g_file_get_path (workdir); shell = gb_terminal_view_discover_shell (NULL, &error); if (shell == NULL) { g_warning ("Failed to discover user shell: %s", error->message); /* We prefer bash in flatpak over sh */ if (ide_is_flatpak ()) shell = g_strdup ("/bin/bash"); else shell = vte_get_user_shell (); g_clear_error (&error); } args = g_ptr_array_new (); g_ptr_array_add (args, (gchar *)shell); g_ptr_array_add (args, NULL); pty = vte_terminal_pty_new_sync (terminal, VTE_PTY_DEFAULT | VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP, NULL, &error); if (pty == NULL) IDE_GOTO (failure); vte_terminal_set_pty (terminal, pty); if (-1 == (tty_fd = gb_vte_pty_create_slave (pty))) IDE_GOTO (failure); /* dup() is safe as it will inherit O_CLOEXEC */ if (-1 == (stdout_fd = dup (tty_fd)) || -1 == (stderr_fd = dup (tty_fd))) IDE_GOTO (failure); /* XXX: It would be nice to allow using the runtimes launcher */ launcher = ide_subprocess_launcher_new (0); ide_subprocess_launcher_set_run_on_host (launcher, TRUE); ide_subprocess_launcher_set_clear_env (launcher, FALSE); ide_subprocess_launcher_set_cwd (launcher, workpath); ide_subprocess_launcher_push_args (launcher, (const gchar * const *)args->pdata); ide_subprocess_launcher_take_stdin_fd (launcher, tty_fd); ide_subprocess_launcher_take_stdout_fd (launcher, stdout_fd); ide_subprocess_launcher_take_stderr_fd (launcher, stderr_fd); ide_subprocess_launcher_setenv (launcher, "TERM", "xterm-256color", TRUE); ide_subprocess_launcher_setenv (launcher, "INSIDE_GNOME_BUILDER", PACKAGE_VERSION, TRUE); ide_subprocess_launcher_setenv (launcher, "SHELL", shell, TRUE); tty_fd = -1; stdout_fd = -1; stderr_fd = -1; if (NULL == (subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error))) IDE_GOTO (failure); ide_subprocess_wait_async (subprocess, NULL, gb_terminal_view_wait_cb, g_object_ref (terminal)); failure: if (tty_fd != -1) close (tty_fd); if (stdout_fd != -1) close (stdout_fd); g_clear_object (&pty); if (error != NULL) { g_warning ("%s", error->message); g_clear_error (&error); } IDE_EXIT; }