예제 #1
0
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));
}
예제 #2
0
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);
    }
}
예제 #3
0
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);
}
예제 #4
0
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);
    }
}
예제 #5
0
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);
}
예제 #6
0
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));
}
예제 #7
0
/*
 * 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);
}
예제 #8
0
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);
}
예제 #9
0
static VALUE
term_set_pty(VALUE self, VALUE pty_master)
{
    vte_terminal_set_pty(RVAL2TERM(self), NUM2INT(pty_master));
    return Qnil;
}
예제 #10
0
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;
}