diff --git a/7.3.315 b/7.3.315 new file mode 100644 index 0000000..2240f7b --- /dev/null +++ b/7.3.315 @@ -0,0 +1,475 @@ +To: vim_dev@googlegroups.com +Subject: Patch 7.3.315 +Fcc: outbox +From: Bram Moolenaar +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 7.3.315 +Problem: Opening a window before forking causes problems for GTK. +Solution: Fork first, create the window in the child and report back to the + parent process whether it worked. If successful the parent exits, + if unsuccessful the child exits and the parent continues in the + terminal. (Tim Starling) +Files: src/gui.c + + +*** ../vim-7.3.314/src/gui.c 2011-08-10 17:44:41.000000000 +0200 +--- src/gui.c 2011-09-14 17:34:30.000000000 +0200 +*************** +*** 37,42 **** +--- 37,60 ---- + static void gui_set_bg_color __ARGS((char_u *name)); + static win_T *xy2win __ARGS((int x, int y)); + ++ #if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X) \ ++ && !defined(__APPLE__) ++ # define MAY_FORK ++ static void gui_do_fork __ARGS((void)); ++ ++ static int gui_read_child_pipe __ARGS((int fd)); ++ ++ /* Return values for gui_read_child_pipe */ ++ enum { ++ GUI_CHILD_IO_ERROR, ++ GUI_CHILD_OK, ++ GUI_CHILD_FAILED ++ }; ++ ++ #endif /* MAY_FORK */ ++ ++ static void gui_attempt_start __ARGS((void)); ++ + static int can_update_cursor = TRUE; /* can display the cursor */ + + /* +*************** +*** 59,105 **** + gui_start() + { + char_u *old_term; +- #if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X) \ +- && !defined(__APPLE__) +- # define MAY_FORK +- int dofork = TRUE; +- #endif + static int recursive = 0; + + old_term = vim_strsave(T_NAME); + +- /* +- * Set_termname() will call gui_init() to start the GUI. +- * Set the "starting" flag, to indicate that the GUI will start. +- * +- * We don't want to open the GUI shell until after we've read .gvimrc, +- * otherwise we don't know what font we will use, and hence we don't know +- * what size the shell should be. So if there are errors in the .gvimrc +- * file, they will have to go to the terminal: Set full_screen to FALSE. +- * full_screen will be set to TRUE again by a successful termcapinit(). +- */ + settmode(TMODE_COOK); /* stop RAW mode */ + if (full_screen) + cursor_on(); /* needed for ":gui" in .vimrc */ +- gui.starting = TRUE; + full_screen = FALSE; + +! #ifdef FEAT_GUI_GTK +! gui.event_time = GDK_CURRENT_TIME; +! #endif + + #ifdef MAY_FORK +! if (!gui.dofork || vim_strchr(p_go, GO_FORG) || recursive) +! dofork = FALSE; + #endif +! ++recursive; +! +! termcapinit((char_u *)"builtin_gui"); +! gui.starting = recursive - 1; + + if (!gui.in_use) /* failed to start GUI */ + { +! termcapinit(old_term); /* back to old term settings */ + settmode(TMODE_RAW); /* restart RAW mode */ + #ifdef FEAT_TITLE + set_title_defaults(); /* set 'title' and 'icon' again */ +--- 77,123 ---- + gui_start() + { + char_u *old_term; + static int recursive = 0; + + old_term = vim_strsave(T_NAME); + + settmode(TMODE_COOK); /* stop RAW mode */ + if (full_screen) + cursor_on(); /* needed for ":gui" in .vimrc */ + full_screen = FALSE; + +! ++recursive; + + #ifdef MAY_FORK +! /* +! * Quit the current process and continue in the child. +! * Makes "gvim file" disconnect from the shell it was started in. +! * Don't do this when Vim was started with "-f" or the 'f' flag is present +! * in 'guioptions'. +! */ +! if (gui.dofork && !vim_strchr(p_go, GO_FORG) && recursive <= 1) +! { +! gui_do_fork(); +! } +! else + #endif +! { +! gui_attempt_start(); +! } + + if (!gui.in_use) /* failed to start GUI */ + { +! /* Back to old term settings +! * +! * FIXME: If we got here because a child process failed and flagged to +! * the parent to resume, and X11 is enabled with FEAT_TITLE, this will +! * hit an X11 I/O error and do a longjmp(), leaving recursive +! * permanently set to 1. This is probably not as big a problem as it +! * sounds, because gui_mch_init() in both gui_x11.c and gui_gtk_x11.c +! * return "OK" unconditionally, so it would be very difficult to +! * actually hit this case. +! */ +! termcapinit(old_term); + settmode(TMODE_RAW); /* restart RAW mode */ + #ifdef FEAT_TITLE + set_title_defaults(); /* set 'title' and 'icon' again */ +*************** +*** 108,113 **** +--- 126,166 ---- + + vim_free(old_term); + ++ #ifdef FEAT_AUTOCMD ++ /* If the GUI started successfully, trigger the GUIEnter event, otherwise ++ * the GUIFailed event. */ ++ gui_mch_update(); ++ apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED, ++ NULL, NULL, FALSE, curbuf); ++ #endif ++ --recursive; ++ } ++ ++ /* ++ * Set_termname() will call gui_init() to start the GUI. ++ * Set the "starting" flag, to indicate that the GUI will start. ++ * ++ * We don't want to open the GUI shell until after we've read .gvimrc, ++ * otherwise we don't know what font we will use, and hence we don't know ++ * what size the shell should be. So if there are errors in the .gvimrc ++ * file, they will have to go to the terminal: Set full_screen to FALSE. ++ * full_screen will be set to TRUE again by a successful termcapinit(). ++ */ ++ static void ++ gui_attempt_start() ++ { ++ static int recursive = 0; ++ ++ ++recursive; ++ gui.starting = TRUE; ++ ++ #ifdef FEAT_GUI_GTK ++ gui.event_time = GDK_CURRENT_TIME; ++ #endif ++ ++ termcapinit((char_u *)"builtin_gui"); ++ gui.starting = recursive - 1; ++ + #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) + if (gui.in_use) + { +*************** +*** 123,218 **** + display_errors(); + } + #endif + +! #if defined(MAY_FORK) && !defined(__QNXNTO__) +! /* +! * Quit the current process and continue in the child. +! * Makes "gvim file" disconnect from the shell it was started in. +! * Don't do this when Vim was started with "-f" or the 'f' flag is present +! * in 'guioptions'. +! */ +! if (gui.in_use && dofork) + { +! int pipefd[2]; /* pipe between parent and child */ +! int pipe_error; +! char dummy; +! pid_t pid = -1; +! +! /* Setup a pipe between the child and the parent, so that the parent +! * knows when the child has done the setsid() call and is allowed to +! * exit. */ +! pipe_error = (pipe(pipefd) < 0); +! pid = fork(); +! if (pid > 0) /* Parent */ + { +! /* Give the child some time to do the setsid(), otherwise the +! * exit() may kill the child too (when starting gvim from inside a +! * gvim). */ +! if (pipe_error) +! ui_delay(300L, TRUE); +! else + { +! /* The read returns when the child closes the pipe (or when +! * the child dies for some reason). */ +! close(pipefd[1]); +! ignored = (int)read(pipefd[0], &dummy, (size_t)1); +! close(pipefd[0]); + } +! +! /* When swapping screens we may need to go to the next line, e.g., +! * after a hit-enter prompt and using ":gui". */ +! if (newline_on_exit) +! mch_errmsg("\r\n"); +! +! /* +! * The parent must skip the normal exit() processing, the child +! * will do it. For example, GTK messes up signals when exiting. +! */ +! _exit(0); + } + +! # if defined(HAVE_SETSID) || defined(HAVE_SETPGID) + /* +! * Change our process group. On some systems/shells a CTRL-C in the +! * shell where Vim was started would otherwise kill gvim! + */ +! if (pid == 0) /* child */ + # if defined(HAVE_SETSID) +! (void)setsid(); + # else +! (void)setpgid(0, 0); + # endif + # endif +! if (!pipe_error) +! { +! close(pipefd[0]); +! close(pipefd[1]); +! } + + # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION) +! /* Tell the session manager our new PID */ +! gui_mch_forked(); + # endif + } +- #else +- # if defined(__QNXNTO__) +- if (gui.in_use && dofork) +- procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR | +- PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL); +- # endif +- #endif + +! #ifdef FEAT_AUTOCMD +! /* If the GUI started successfully, trigger the GUIEnter event, otherwise +! * the GUIFailed event. */ +! gui_mch_update(); +! apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED, +! NULL, NULL, FALSE, curbuf); + #endif + +! --recursive; + } + + /* + * Call this when vim starts up, whether or not the GUI is started + */ +--- 176,346 ---- + display_errors(); + } + #endif ++ --recursive; ++ } + +! #ifdef MAY_FORK +! +! /* for waitpid() */ +! # if defined(HAVE_SYS_WAIT_H) || defined(HAVE_UNION_WAIT) +! # include +! # endif +! +! /* +! * Create a new process, by forking. In the child, start the GUI, and in +! * the parent, exit. +! * +! * If something goes wrong, this will return with gui.in_use still set +! * to FALSE, in which case the caller should continue execution without +! * the GUI. +! * +! * If the child fails to start the GUI, then the child will exit and the +! * parent will return. If the child succeeds, then the parent will exit +! * and the child will return. +! */ +! static void +! gui_do_fork() +! { +! #ifdef __QNXNTO__ +! procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR | +! PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL); +! gui_attempt_start(); +! return; +! #else +! int pipefd[2]; /* pipe between parent and child */ +! int pipe_error; +! int status; +! int exit_status; +! pid_t pid = -1; +! FILE *parent_file; +! +! /* Setup a pipe between the child and the parent, so that the parent +! * knows when the child has done the setsid() call and is allowed to +! * exit. */ +! pipe_error = (pipe(pipefd) < 0); +! pid = fork(); +! if (pid < 0) /* Fork error */ + { +! EMSG(_("E851: Failed to create a new process for the GUI")); +! return; +! } +! else if (pid > 0) /* Parent */ +! { +! /* Give the child some time to do the setsid(), otherwise the +! * exit() may kill the child too (when starting gvim from inside a +! * gvim). */ +! if (!pipe_error) + { +! /* The read returns when the child closes the pipe (or when +! * the child dies for some reason). */ +! close(pipefd[1]); +! status = gui_read_child_pipe(pipefd[0]); +! if (status == GUI_CHILD_FAILED) + { +! /* The child failed to start the GUI, so the caller must +! * continue. There may be more error information written +! * to stderr by the child. */ +! # ifdef __NeXT__ +! wait4(pid, &exit_status, 0, (struct rusage *)0); +! # else +! waitpid(pid, &exit_status, 0); +! # endif +! EMSG(_("E852: The child process failed to start the GUI")); +! return; + } +! else if (status == GUI_CHILD_IO_ERROR) +! { +! pipe_error = TRUE; +! } +! /* else GUI_CHILD_OK: parent exit */ + } + +! if (pipe_error) +! ui_delay(300L, TRUE); +! +! /* When swapping screens we may need to go to the next line, e.g., +! * after a hit-enter prompt and using ":gui". */ +! if (newline_on_exit) +! mch_errmsg("\r\n"); +! + /* +! * The parent must skip the normal exit() processing, the child +! * will do it. For example, GTK messes up signals when exiting. + */ +! _exit(0); +! } +! /* Child */ +! +! # if defined(HAVE_SETSID) || defined(HAVE_SETPGID) +! /* +! * Change our process group. On some systems/shells a CTRL-C in the +! * shell where Vim was started would otherwise kill gvim! +! */ + # if defined(HAVE_SETSID) +! (void)setsid(); + # else +! (void)setpgid(0, 0); + # endif + # endif +! if (!pipe_error) +! close(pipefd[0]); + + # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION) +! /* Tell the session manager our new PID */ +! gui_mch_forked(); + # endif ++ ++ if (!pipe_error) ++ parent_file = fdopen(pipefd[1], "w"); ++ else ++ parent_file = NULL; ++ ++ /* Try to start the GUI */ ++ gui_attempt_start(); ++ ++ /* Notify the parent */ ++ if (parent_file != NULL) ++ { ++ fputs(gui.in_use ? "ok" : "fail", parent_file); ++ fclose(parent_file); + } + +! /* If we failed to start the GUI, exit now. */ +! if (!gui.in_use) +! exit(1); + #endif ++ } + +! /* +! * Read from a pipe assumed to be connected to the child process (this +! * function is called from the parent). +! * Return GUI_CHILD_OK if the child successfully started the GUI, +! * GUY_CHILD_FAILED if the child failed, or GUI_CHILD_IO_ERROR if there was +! * some other error. +! * +! * The file descriptor will be closed before the function returns. +! */ +! static int +! gui_read_child_pipe(int fd) +! { +! size_t bytes_read; +! FILE *file; +! char buffer[10]; +! +! file = fdopen(fd, "r"); +! if (!file) +! return GUI_CHILD_IO_ERROR; +! +! bytes_read = fread(buffer, sizeof(char), sizeof(buffer)-1, file); +! buffer[bytes_read] = '\0'; +! fclose(file); +! if (strcmp(buffer, "ok") == 0) +! return GUI_CHILD_OK; +! return GUI_CHILD_FAILED; + } + ++ #endif /* MAY_FORK */ ++ + /* + * Call this when vim starts up, whether or not the GUI is started + */ +*** ../vim-7.3.314/src/version.c 2011-09-14 19:01:38.000000000 +0200 +--- src/version.c 2011-09-14 19:02:45.000000000 +0200 +*************** +*** 711,712 **** +--- 711,714 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 315, + /**/ + +-- +A)bort, R)etry, B)ang it with a large hammer + + /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ +/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ +\\\ an exciting new programming language -- http://www.Zimbu.org /// + \\\ help me help AIDS victims -- http://ICCF-Holland.org ///