Hi, As per Andreas's off-bugtracker request, let me send a skeleton patch. It compiles but sure doesn't run correctly; but at least shows which are the bits that need to be addressed by someone familiar with synaptic and C++. Please make sure to review every line of the patch and address all the comments mentioned within.
In increasing order of importance: - Minor changes around the scrollbar and font handling; I don't think anything could've gone wrong here - No more vtereaper, the API changed here a little bit. Previously it was a global reaper object, so you'd need to know the PID and compare. Now it's a signal connected to a VteTerminal instance, and I believe there can only be one child per terminal at a time (or even if vte allows more, I guess no reasonable app does this), so I hope verifying and comparing the PID is not necessary anymore. Please double check if I'm correct here. - The big piece is spawning a process for the terminal, and here my patch is definitely incomplete as it'd require more thorough understanding of the code: -- argv needs to be populated with the command to be launched -- the possible pty flags and spawn should be carefully revised -- I _think_ that whatever happened so far between the vte_whatever_fork() and the exec() [now I replaced vte_whatever_fork() by vte_whatever_spawn(), but I haven't traced down where the exec() happens], which I believe is probably what DoInstallPostFork() does, needs to be moved into the child_setup method of vte_whatever_spawn(). It's going to be a bit of refactoring. Should you get stuck with these, I recommend to look at (apart from vte's doc obviously) gnome-terminal's source code, as well as the two small self-contained test programs (vteapp.c and app.vala) in vte's source tree. Good luck, egmont
diff --git a/configure.in b/configure.in index 4d802db..ef22639 100644 --- a/configure.in +++ b/configure.in @@ -47,7 +47,7 @@ dnl AC_SUBST(BUILD_wings) dnl we build for gtk3 by default now pkg_modules="gtk+-3.0 >= 2.91.0, pango >= 1.0.0, glib-2.0" -vte_modules="vte-2.90" +vte_modules="vte-2.91" PKG_CHECK_MODULES(GTK, [$pkg_modules]) BUILD_gtk="gtk" diff --git a/gtk/rgdebinstallprogress.cc b/gtk/rgdebinstallprogress.cc index a084860..155ed27 100644 --- a/gtk/rgdebinstallprogress.cc +++ b/gtk/rgdebinstallprogress.cc @@ -54,18 +54,19 @@ #include "i18n.h" -void RGDebInstallProgress::child_exited(VteReaper *vtereaper, - gint child_pid, gint ret, +void RGDebInstallProgress::child_exited(VteTerminal *vteterminal, + gint ret, gpointer data) { RGDebInstallProgress *me = (RGDebInstallProgress*)data; - if(child_pid == me->_child_id) { +// I _guess_ there's no point in checking the pid, since there can be one child per terminal +//XXX if(child_pid == me->_child_id) { // cout << "correct child exited" << endl; // cout << "waitpid returned: " << WEXITSTATUS(ret) << endl; me->res = (pkgPackageManager::OrderResult)WEXITSTATUS(ret); me->child_has_exited=true; - } +//XXX } } ssize_t @@ -289,8 +290,7 @@ void RGDebInstallProgress::conffile(gchar *conffile, gchar *status) void RGDebInstallProgress::startUpdate() { child_has_exited=false; - VteReaper* reaper = vte_reaper_get(); - g_signal_connect(G_OBJECT(reaper), "child-exited", + g_signal_connect(VTE_TERMINAL(_term), "child-exited", G_CALLBACK(child_exited), this); @@ -341,8 +341,9 @@ void RGDebInstallProgress::expander_callback (GObject *object, // this crap here is needed because VteTerminal does not like // it when run hidden. this workaround will scroll to the end of // the current buffer + // TODO is this still true as of libvte-2.91 ??? gtk_widget_realize(GTK_WIDGET(me->_term)); - GtkAdjustment *a = vte_terminal_get_adjustment(VTE_TERMINAL(me->_term)); + GtkAdjustment *a = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(VTE_TERMINAL(me->_term))); gtk_adjustment_set_value(a, gtk_adjustment_get_upper(a) - gtk_adjustment_get_page_size(a)); gtk_adjustment_value_changed(a); @@ -401,15 +402,20 @@ RGDebInstallProgress::RGDebInstallProgress(RGMainWindow *main, _term = vte_terminal_new(); vte_terminal_set_size(VTE_TERMINAL(_term),80,23); - GtkWidget *scrollbar = gtk_vscrollbar_new (vte_terminal_get_adjustment(VTE_TERMINAL(_term))); + GtkWidget *scrollbar = gtk_vscrollbar_new (gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(VTE_TERMINAL(_term)))); gtk_widget_set_can_focus (scrollbar, FALSE); vte_terminal_set_scrollback_lines(VTE_TERMINAL(_term), 10000); + + char *s; if(_config->FindB("Synaptic::useUserTerminalFont")) { - char *s =(char*)_config->Find("Synaptic::TerminalFontName").c_str(); - vte_terminal_set_font_from_string(VTE_TERMINAL(_term), s); + s =(char*)_config->Find("Synaptic::TerminalFontName").c_str(); } else { - vte_terminal_set_font_from_string(VTE_TERMINAL(_term), "monospace 8"); + s = "monospace 8"; } + PangoFontDescription *fontdesc = pango_font_description_from_string(s); + vte_terminal_set_font(VTE_TERMINAL(_term), fontdesc); + pango_font_description_free(fontdesc); + gtk_box_pack_start(GTK_BOX(GTK_WIDGET(gtk_builder_get_object(_builder,"hbox_vte"))), _term, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(_term), "key-press-event", G_CALLBACK(key_press_event), this); g_signal_connect(G_OBJECT(_term), "button-press-event", @@ -549,7 +555,7 @@ void RGDebInstallProgress::terminalAction(GtkWidget *terminal, vte_terminal_select_all(VTE_TERMINAL(terminal)); break; case EDIT_SELECT_NONE: - vte_terminal_select_none(VTE_TERMINAL(terminal)); + vte_terminal_unselect_all(VTE_TERMINAL(terminal)); break; } } @@ -670,6 +676,7 @@ pkgPackageManager::OrderResult RGDebInstallProgress::start(pkgPackageManager *pm void *dummy; pkgPackageManager::OrderResult res; int ret; + GError *err; res = pm->DoInstallPreFork(); if (res == pkgPackageManager::Failed) @@ -677,10 +684,20 @@ pkgPackageManager::OrderResult RGDebInstallProgress::start(pkgPackageManager *pm // we need to send the fds from the pipe over a socket because // the vte_terminal closes all our FDs - _child_id = vte_terminal_forkpty(VTE_TERMINAL(_term),NULL,NULL, - false,false,false); - if (_child_id < 0) { - cerr << "vte_terminal_forkpty() failed. " << strerror(errno) << endl; + if (!vte_terminal_spawn_sync(VTE_TERMINAL(_term), + VTE_PTY_DEFAULT, // ptyflags + NULL, // cwd + NULL, /* XXX */ // command and args <-- put the command to be launched here + NULL, // (additional?) env vars + G_SPAWN_DEFAULT, // spawn flags <-- review this one also + NULL, /* XXX */ // child setup <-- I think the DoInstallPostFork stuff needs to come here + NULL, // data + &_child_id, // pid (out) + NULL, // cancellable + &err)) { // error (out) + + // TODO: I guess the error code is in GError err rather than errno! + cerr << "vte_terminal_spawn_sync() failed. " << strerror(errno) << endl; res = pkgPackageManager::Failed; GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW(window()), @@ -694,7 +711,7 @@ pkgPackageManager::OrderResult RGDebInstallProgress::start(pkgPackageManager *pm gtk_widget_destroy(dialog); return res; } - else if (_child_id == 0) { + else { int fd[2]; pipe(fd); ipc_send_fd(fd[0]); // send the read part of the pipe to the parent diff --git a/gtk/rgdebinstallprogress.h b/gtk/rgdebinstallprogress.h index af6dfcc..15c8c21 100644 --- a/gtk/rgdebinstallprogress.h +++ b/gtk/rgdebinstallprogress.h @@ -32,7 +32,7 @@ #include "rggtkbuilderwindow.h" #include "rguserdialog.h" #include<map> -#include <vte/reaper.h> +#include <vte/vte.h> class RGMainWindow; @@ -111,7 +111,7 @@ class RGDebInstallProgress:public RInstallProgress, public RGGtkBuilderWindow pid_t _child_id; pkgPackageManager::OrderResult res; bool child_has_exited; - static void child_exited(VteReaper *vtereaper,gint child_pid, gint ret, + static void child_exited(VteTerminal *vteterminal, gint ret, gpointer data); static void terminalAction(GtkWidget *terminal, TermAction action); diff --git a/gtk/rgterminstallprogress.cc b/gtk/rgterminstallprogress.cc index 45c8510..248c52d 100644 --- a/gtk/rgterminstallprogress.cc +++ b/gtk/rgterminstallprogress.cc @@ -1,4 +1,4 @@ -/* rgzvtinstallprogress.cc +/* rgterminstallprogress.cc * * Copyright (c) 2002 Michael Vogt * @@ -48,7 +48,6 @@ #include <cstdlib> #include <vte/vte.h> -#include <vte/reaper.h> #include <cstdlib> #include <cstring> @@ -63,15 +62,20 @@ RGTermInstallProgress::RGTermInstallProgress(RGMainWindow *main) _term = vte_terminal_new(); vte_terminal_set_size(VTE_TERMINAL(_term),80,23); - _scrollbar = gtk_vscrollbar_new (vte_terminal_get_adjustment(VTE_TERMINAL(_term))); + _scrollbar = gtk_vscrollbar_new (gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(VTE_TERMINAL(_term)))); gtk_widget_set_can_focus (_scrollbar, FALSE); vte_terminal_set_scrollback_lines(VTE_TERMINAL(_term), 10000); + + char *s; if(_config->FindB("Synaptic::useUserTerminalFont")) { char *s =(char*)_config->Find("Synaptic::TerminalFontName").c_str(); - vte_terminal_set_font_from_string(VTE_TERMINAL(_term), s); } else { - vte_terminal_set_font_from_string(VTE_TERMINAL(_term), "monospace 10"); + s = "monospace 10"; } + PangoFontDescription *fontdesc = pango_font_description_from_string(s); + vte_terminal_set_font(VTE_TERMINAL(_term), fontdesc); + pango_font_description_free(fontdesc); + GtkWidget *box = GTK_WIDGET(gtk_builder_get_object(_builder,"hbox_vte")); gtk_box_pack_start(GTK_BOX(box), _term, TRUE, TRUE, 0); gtk_box_pack_end(GTK_BOX(box), _scrollbar, FALSE, FALSE, 0); @@ -94,17 +98,18 @@ RGTermInstallProgress::RGTermInstallProgress(RGMainWindow *main) } -void RGTermInstallProgress::child_exited(VteReaper *vtereaper, - gint child_pid, gint ret, +void RGTermInstallProgress::child_exited(VteTerminal *vteterminal, + gint ret, gpointer data) { RGTermInstallProgress *me = (RGTermInstallProgress*)data; - if(child_pid == me->_child_id) { +// I _guess_ there's no point in checking the pid, since there can be one child per terminal +// if(child_pid == me->_child_id) { // cout << "child exited" << endl; // cout << "waitpid returned: " << WEXITSTATUS(ret) << endl; me->res = (pkgPackageManager::OrderResult)WEXITSTATUS(ret); me->child_has_exited=true; - } +// } } void RGTermInstallProgress::startUpdate() @@ -114,8 +119,7 @@ void RGTermInstallProgress::startUpdate() gtk_widget_show_all(win); child_has_exited=false; - VteReaper* reaper = vte_reaper_get(); - g_signal_connect(G_OBJECT(reaper), "child-exited", + g_signal_connect(VTE_TERMINAL(_term), "child-exited", G_CALLBACK(child_exited), this); @@ -220,19 +224,22 @@ RGTermInstallProgress::start(pkgPackageManager *pm, void *dummy; int open_max, ret = 250; + GError *err; res = pm->DoInstallPreFork(); if (res == pkgPackageManager::Failed) return res; - _child_id = vte_terminal_forkpty(VTE_TERMINAL(_term),NULL,NULL,false,false,false); - if (_child_id == -1) { + if (!vte_terminal_spawn_sync(VTE_TERMINAL(_term), + // TODO copy from rgdebinstallprogress.cc + VTE_PTY_DEFAULT, NULL, NULL, NULL, G_SPAWN_DEFAULT, NULL, NULL, &_child_id, NULL, &err)) { + cerr << "Internal Error: impossible to fork children. Synaptics is going to stop. Please report." << endl; cerr << "errorcode: " << errno << endl; exit(1); } - if (_child_id == 0) { + else { // we ignore sigpipe as it is thrown sporadic on // debian, kernel 2.6 systems diff --git a/gtk/rgterminstallprogress.h b/gtk/rgterminstallprogress.h index a474f2a..ad0e672 100644 --- a/gtk/rgterminstallprogress.h +++ b/gtk/rgterminstallprogress.h @@ -31,7 +31,6 @@ #include "rgwindow.h" #include <vte/vte.h> -#include <vte/reaper.h> class RGTermInstallProgress : public RInstallProgress, public RGGtkBuilderWindow { GtkWidget *_term; @@ -46,7 +45,7 @@ class RGTermInstallProgress : public RInstallProgress, public RGGtkBuilderWindow protected: bool child_has_exited; - static void child_exited(VteReaper *vtereaper,gint child_pid, gint ret, + static void child_exited(VteTerminal *vteterminal, gint ret, gpointer data); virtual void startUpdate(); virtual void updateInterface();