]>
Commit | Line | Data |
---|---|---|
c6060300 MT |
1 | To: vim_dev@googlegroups.com |
2 | Subject: Patch 7.3.315 | |
3 | Fcc: outbox | |
4 | From: Bram Moolenaar <Bram@moolenaar.net> | |
5 | Mime-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ------------ | |
9 | ||
10 | Patch 7.3.315 | |
11 | Problem: Opening a window before forking causes problems for GTK. | |
12 | Solution: Fork first, create the window in the child and report back to the | |
13 | parent process whether it worked. If successful the parent exits, | |
14 | if unsuccessful the child exits and the parent continues in the | |
15 | terminal. (Tim Starling) | |
16 | Files: src/gui.c | |
17 | ||
18 | ||
19 | *** ../vim-7.3.314/src/gui.c 2011-08-10 17:44:41.000000000 +0200 | |
20 | --- src/gui.c 2011-09-14 17:34:30.000000000 +0200 | |
21 | *************** | |
22 | *** 37,42 **** | |
23 | --- 37,60 ---- | |
24 | static void gui_set_bg_color __ARGS((char_u *name)); | |
25 | static win_T *xy2win __ARGS((int x, int y)); | |
26 | ||
27 | + #if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X) \ | |
28 | + && !defined(__APPLE__) | |
29 | + # define MAY_FORK | |
30 | + static void gui_do_fork __ARGS((void)); | |
31 | + | |
32 | + static int gui_read_child_pipe __ARGS((int fd)); | |
33 | + | |
34 | + /* Return values for gui_read_child_pipe */ | |
35 | + enum { | |
36 | + GUI_CHILD_IO_ERROR, | |
37 | + GUI_CHILD_OK, | |
38 | + GUI_CHILD_FAILED | |
39 | + }; | |
40 | + | |
41 | + #endif /* MAY_FORK */ | |
42 | + | |
43 | + static void gui_attempt_start __ARGS((void)); | |
44 | + | |
45 | static int can_update_cursor = TRUE; /* can display the cursor */ | |
46 | ||
47 | /* | |
48 | *************** | |
49 | *** 59,105 **** | |
50 | gui_start() | |
51 | { | |
52 | char_u *old_term; | |
53 | - #if defined(UNIX) && !defined(__BEOS__) && !defined(MACOS_X) \ | |
54 | - && !defined(__APPLE__) | |
55 | - # define MAY_FORK | |
56 | - int dofork = TRUE; | |
57 | - #endif | |
58 | static int recursive = 0; | |
59 | ||
60 | old_term = vim_strsave(T_NAME); | |
61 | ||
62 | - /* | |
63 | - * Set_termname() will call gui_init() to start the GUI. | |
64 | - * Set the "starting" flag, to indicate that the GUI will start. | |
65 | - * | |
66 | - * We don't want to open the GUI shell until after we've read .gvimrc, | |
67 | - * otherwise we don't know what font we will use, and hence we don't know | |
68 | - * what size the shell should be. So if there are errors in the .gvimrc | |
69 | - * file, they will have to go to the terminal: Set full_screen to FALSE. | |
70 | - * full_screen will be set to TRUE again by a successful termcapinit(). | |
71 | - */ | |
72 | settmode(TMODE_COOK); /* stop RAW mode */ | |
73 | if (full_screen) | |
74 | cursor_on(); /* needed for ":gui" in .vimrc */ | |
75 | - gui.starting = TRUE; | |
76 | full_screen = FALSE; | |
77 | ||
78 | ! #ifdef FEAT_GUI_GTK | |
79 | ! gui.event_time = GDK_CURRENT_TIME; | |
80 | ! #endif | |
81 | ||
82 | #ifdef MAY_FORK | |
83 | ! if (!gui.dofork || vim_strchr(p_go, GO_FORG) || recursive) | |
84 | ! dofork = FALSE; | |
85 | #endif | |
86 | ! ++recursive; | |
87 | ! | |
88 | ! termcapinit((char_u *)"builtin_gui"); | |
89 | ! gui.starting = recursive - 1; | |
90 | ||
91 | if (!gui.in_use) /* failed to start GUI */ | |
92 | { | |
93 | ! termcapinit(old_term); /* back to old term settings */ | |
94 | settmode(TMODE_RAW); /* restart RAW mode */ | |
95 | #ifdef FEAT_TITLE | |
96 | set_title_defaults(); /* set 'title' and 'icon' again */ | |
97 | --- 77,123 ---- | |
98 | gui_start() | |
99 | { | |
100 | char_u *old_term; | |
101 | static int recursive = 0; | |
102 | ||
103 | old_term = vim_strsave(T_NAME); | |
104 | ||
105 | settmode(TMODE_COOK); /* stop RAW mode */ | |
106 | if (full_screen) | |
107 | cursor_on(); /* needed for ":gui" in .vimrc */ | |
108 | full_screen = FALSE; | |
109 | ||
110 | ! ++recursive; | |
111 | ||
112 | #ifdef MAY_FORK | |
113 | ! /* | |
114 | ! * Quit the current process and continue in the child. | |
115 | ! * Makes "gvim file" disconnect from the shell it was started in. | |
116 | ! * Don't do this when Vim was started with "-f" or the 'f' flag is present | |
117 | ! * in 'guioptions'. | |
118 | ! */ | |
119 | ! if (gui.dofork && !vim_strchr(p_go, GO_FORG) && recursive <= 1) | |
120 | ! { | |
121 | ! gui_do_fork(); | |
122 | ! } | |
123 | ! else | |
124 | #endif | |
125 | ! { | |
126 | ! gui_attempt_start(); | |
127 | ! } | |
128 | ||
129 | if (!gui.in_use) /* failed to start GUI */ | |
130 | { | |
131 | ! /* Back to old term settings | |
132 | ! * | |
133 | ! * FIXME: If we got here because a child process failed and flagged to | |
134 | ! * the parent to resume, and X11 is enabled with FEAT_TITLE, this will | |
135 | ! * hit an X11 I/O error and do a longjmp(), leaving recursive | |
136 | ! * permanently set to 1. This is probably not as big a problem as it | |
137 | ! * sounds, because gui_mch_init() in both gui_x11.c and gui_gtk_x11.c | |
138 | ! * return "OK" unconditionally, so it would be very difficult to | |
139 | ! * actually hit this case. | |
140 | ! */ | |
141 | ! termcapinit(old_term); | |
142 | settmode(TMODE_RAW); /* restart RAW mode */ | |
143 | #ifdef FEAT_TITLE | |
144 | set_title_defaults(); /* set 'title' and 'icon' again */ | |
145 | *************** | |
146 | *** 108,113 **** | |
147 | --- 126,166 ---- | |
148 | ||
149 | vim_free(old_term); | |
150 | ||
151 | + #ifdef FEAT_AUTOCMD | |
152 | + /* If the GUI started successfully, trigger the GUIEnter event, otherwise | |
153 | + * the GUIFailed event. */ | |
154 | + gui_mch_update(); | |
155 | + apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED, | |
156 | + NULL, NULL, FALSE, curbuf); | |
157 | + #endif | |
158 | + --recursive; | |
159 | + } | |
160 | + | |
161 | + /* | |
162 | + * Set_termname() will call gui_init() to start the GUI. | |
163 | + * Set the "starting" flag, to indicate that the GUI will start. | |
164 | + * | |
165 | + * We don't want to open the GUI shell until after we've read .gvimrc, | |
166 | + * otherwise we don't know what font we will use, and hence we don't know | |
167 | + * what size the shell should be. So if there are errors in the .gvimrc | |
168 | + * file, they will have to go to the terminal: Set full_screen to FALSE. | |
169 | + * full_screen will be set to TRUE again by a successful termcapinit(). | |
170 | + */ | |
171 | + static void | |
172 | + gui_attempt_start() | |
173 | + { | |
174 | + static int recursive = 0; | |
175 | + | |
176 | + ++recursive; | |
177 | + gui.starting = TRUE; | |
178 | + | |
179 | + #ifdef FEAT_GUI_GTK | |
180 | + gui.event_time = GDK_CURRENT_TIME; | |
181 | + #endif | |
182 | + | |
183 | + termcapinit((char_u *)"builtin_gui"); | |
184 | + gui.starting = recursive - 1; | |
185 | + | |
186 | #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) | |
187 | if (gui.in_use) | |
188 | { | |
189 | *************** | |
190 | *** 123,218 **** | |
191 | display_errors(); | |
192 | } | |
193 | #endif | |
194 | ||
195 | ! #if defined(MAY_FORK) && !defined(__QNXNTO__) | |
196 | ! /* | |
197 | ! * Quit the current process and continue in the child. | |
198 | ! * Makes "gvim file" disconnect from the shell it was started in. | |
199 | ! * Don't do this when Vim was started with "-f" or the 'f' flag is present | |
200 | ! * in 'guioptions'. | |
201 | ! */ | |
202 | ! if (gui.in_use && dofork) | |
203 | { | |
204 | ! int pipefd[2]; /* pipe between parent and child */ | |
205 | ! int pipe_error; | |
206 | ! char dummy; | |
207 | ! pid_t pid = -1; | |
208 | ! | |
209 | ! /* Setup a pipe between the child and the parent, so that the parent | |
210 | ! * knows when the child has done the setsid() call and is allowed to | |
211 | ! * exit. */ | |
212 | ! pipe_error = (pipe(pipefd) < 0); | |
213 | ! pid = fork(); | |
214 | ! if (pid > 0) /* Parent */ | |
215 | { | |
216 | ! /* Give the child some time to do the setsid(), otherwise the | |
217 | ! * exit() may kill the child too (when starting gvim from inside a | |
218 | ! * gvim). */ | |
219 | ! if (pipe_error) | |
220 | ! ui_delay(300L, TRUE); | |
221 | ! else | |
222 | { | |
223 | ! /* The read returns when the child closes the pipe (or when | |
224 | ! * the child dies for some reason). */ | |
225 | ! close(pipefd[1]); | |
226 | ! ignored = (int)read(pipefd[0], &dummy, (size_t)1); | |
227 | ! close(pipefd[0]); | |
228 | } | |
229 | ! | |
230 | ! /* When swapping screens we may need to go to the next line, e.g., | |
231 | ! * after a hit-enter prompt and using ":gui". */ | |
232 | ! if (newline_on_exit) | |
233 | ! mch_errmsg("\r\n"); | |
234 | ! | |
235 | ! /* | |
236 | ! * The parent must skip the normal exit() processing, the child | |
237 | ! * will do it. For example, GTK messes up signals when exiting. | |
238 | ! */ | |
239 | ! _exit(0); | |
240 | } | |
241 | ||
242 | ! # if defined(HAVE_SETSID) || defined(HAVE_SETPGID) | |
243 | /* | |
244 | ! * Change our process group. On some systems/shells a CTRL-C in the | |
245 | ! * shell where Vim was started would otherwise kill gvim! | |
246 | */ | |
247 | ! if (pid == 0) /* child */ | |
248 | # if defined(HAVE_SETSID) | |
249 | ! (void)setsid(); | |
250 | # else | |
251 | ! (void)setpgid(0, 0); | |
252 | # endif | |
253 | # endif | |
254 | ! if (!pipe_error) | |
255 | ! { | |
256 | ! close(pipefd[0]); | |
257 | ! close(pipefd[1]); | |
258 | ! } | |
259 | ||
260 | # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION) | |
261 | ! /* Tell the session manager our new PID */ | |
262 | ! gui_mch_forked(); | |
263 | # endif | |
264 | } | |
265 | - #else | |
266 | - # if defined(__QNXNTO__) | |
267 | - if (gui.in_use && dofork) | |
268 | - procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR | | |
269 | - PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL); | |
270 | - # endif | |
271 | - #endif | |
272 | ||
273 | ! #ifdef FEAT_AUTOCMD | |
274 | ! /* If the GUI started successfully, trigger the GUIEnter event, otherwise | |
275 | ! * the GUIFailed event. */ | |
276 | ! gui_mch_update(); | |
277 | ! apply_autocmds(gui.in_use ? EVENT_GUIENTER : EVENT_GUIFAILED, | |
278 | ! NULL, NULL, FALSE, curbuf); | |
279 | #endif | |
280 | ||
281 | ! --recursive; | |
282 | } | |
283 | ||
284 | /* | |
285 | * Call this when vim starts up, whether or not the GUI is started | |
286 | */ | |
287 | --- 176,346 ---- | |
288 | display_errors(); | |
289 | } | |
290 | #endif | |
291 | + --recursive; | |
292 | + } | |
293 | ||
294 | ! #ifdef MAY_FORK | |
295 | ! | |
296 | ! /* for waitpid() */ | |
297 | ! # if defined(HAVE_SYS_WAIT_H) || defined(HAVE_UNION_WAIT) | |
298 | ! # include <sys/wait.h> | |
299 | ! # endif | |
300 | ! | |
301 | ! /* | |
302 | ! * Create a new process, by forking. In the child, start the GUI, and in | |
303 | ! * the parent, exit. | |
304 | ! * | |
305 | ! * If something goes wrong, this will return with gui.in_use still set | |
306 | ! * to FALSE, in which case the caller should continue execution without | |
307 | ! * the GUI. | |
308 | ! * | |
309 | ! * If the child fails to start the GUI, then the child will exit and the | |
310 | ! * parent will return. If the child succeeds, then the parent will exit | |
311 | ! * and the child will return. | |
312 | ! */ | |
313 | ! static void | |
314 | ! gui_do_fork() | |
315 | ! { | |
316 | ! #ifdef __QNXNTO__ | |
317 | ! procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR | | |
318 | ! PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL); | |
319 | ! gui_attempt_start(); | |
320 | ! return; | |
321 | ! #else | |
322 | ! int pipefd[2]; /* pipe between parent and child */ | |
323 | ! int pipe_error; | |
324 | ! int status; | |
325 | ! int exit_status; | |
326 | ! pid_t pid = -1; | |
327 | ! FILE *parent_file; | |
328 | ! | |
329 | ! /* Setup a pipe between the child and the parent, so that the parent | |
330 | ! * knows when the child has done the setsid() call and is allowed to | |
331 | ! * exit. */ | |
332 | ! pipe_error = (pipe(pipefd) < 0); | |
333 | ! pid = fork(); | |
334 | ! if (pid < 0) /* Fork error */ | |
335 | { | |
336 | ! EMSG(_("E851: Failed to create a new process for the GUI")); | |
337 | ! return; | |
338 | ! } | |
339 | ! else if (pid > 0) /* Parent */ | |
340 | ! { | |
341 | ! /* Give the child some time to do the setsid(), otherwise the | |
342 | ! * exit() may kill the child too (when starting gvim from inside a | |
343 | ! * gvim). */ | |
344 | ! if (!pipe_error) | |
345 | { | |
346 | ! /* The read returns when the child closes the pipe (or when | |
347 | ! * the child dies for some reason). */ | |
348 | ! close(pipefd[1]); | |
349 | ! status = gui_read_child_pipe(pipefd[0]); | |
350 | ! if (status == GUI_CHILD_FAILED) | |
351 | { | |
352 | ! /* The child failed to start the GUI, so the caller must | |
353 | ! * continue. There may be more error information written | |
354 | ! * to stderr by the child. */ | |
355 | ! # ifdef __NeXT__ | |
356 | ! wait4(pid, &exit_status, 0, (struct rusage *)0); | |
357 | ! # else | |
358 | ! waitpid(pid, &exit_status, 0); | |
359 | ! # endif | |
360 | ! EMSG(_("E852: The child process failed to start the GUI")); | |
361 | ! return; | |
362 | } | |
363 | ! else if (status == GUI_CHILD_IO_ERROR) | |
364 | ! { | |
365 | ! pipe_error = TRUE; | |
366 | ! } | |
367 | ! /* else GUI_CHILD_OK: parent exit */ | |
368 | } | |
369 | ||
370 | ! if (pipe_error) | |
371 | ! ui_delay(300L, TRUE); | |
372 | ! | |
373 | ! /* When swapping screens we may need to go to the next line, e.g., | |
374 | ! * after a hit-enter prompt and using ":gui". */ | |
375 | ! if (newline_on_exit) | |
376 | ! mch_errmsg("\r\n"); | |
377 | ! | |
378 | /* | |
379 | ! * The parent must skip the normal exit() processing, the child | |
380 | ! * will do it. For example, GTK messes up signals when exiting. | |
381 | */ | |
382 | ! _exit(0); | |
383 | ! } | |
384 | ! /* Child */ | |
385 | ! | |
386 | ! # if defined(HAVE_SETSID) || defined(HAVE_SETPGID) | |
387 | ! /* | |
388 | ! * Change our process group. On some systems/shells a CTRL-C in the | |
389 | ! * shell where Vim was started would otherwise kill gvim! | |
390 | ! */ | |
391 | # if defined(HAVE_SETSID) | |
392 | ! (void)setsid(); | |
393 | # else | |
394 | ! (void)setpgid(0, 0); | |
395 | # endif | |
396 | # endif | |
397 | ! if (!pipe_error) | |
398 | ! close(pipefd[0]); | |
399 | ||
400 | # if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION) | |
401 | ! /* Tell the session manager our new PID */ | |
402 | ! gui_mch_forked(); | |
403 | # endif | |
404 | + | |
405 | + if (!pipe_error) | |
406 | + parent_file = fdopen(pipefd[1], "w"); | |
407 | + else | |
408 | + parent_file = NULL; | |
409 | + | |
410 | + /* Try to start the GUI */ | |
411 | + gui_attempt_start(); | |
412 | + | |
413 | + /* Notify the parent */ | |
414 | + if (parent_file != NULL) | |
415 | + { | |
416 | + fputs(gui.in_use ? "ok" : "fail", parent_file); | |
417 | + fclose(parent_file); | |
418 | } | |
419 | ||
420 | ! /* If we failed to start the GUI, exit now. */ | |
421 | ! if (!gui.in_use) | |
422 | ! exit(1); | |
423 | #endif | |
424 | + } | |
425 | ||
426 | ! /* | |
427 | ! * Read from a pipe assumed to be connected to the child process (this | |
428 | ! * function is called from the parent). | |
429 | ! * Return GUI_CHILD_OK if the child successfully started the GUI, | |
430 | ! * GUY_CHILD_FAILED if the child failed, or GUI_CHILD_IO_ERROR if there was | |
431 | ! * some other error. | |
432 | ! * | |
433 | ! * The file descriptor will be closed before the function returns. | |
434 | ! */ | |
435 | ! static int | |
436 | ! gui_read_child_pipe(int fd) | |
437 | ! { | |
438 | ! size_t bytes_read; | |
439 | ! FILE *file; | |
440 | ! char buffer[10]; | |
441 | ! | |
442 | ! file = fdopen(fd, "r"); | |
443 | ! if (!file) | |
444 | ! return GUI_CHILD_IO_ERROR; | |
445 | ! | |
446 | ! bytes_read = fread(buffer, sizeof(char), sizeof(buffer)-1, file); | |
447 | ! buffer[bytes_read] = '\0'; | |
448 | ! fclose(file); | |
449 | ! if (strcmp(buffer, "ok") == 0) | |
450 | ! return GUI_CHILD_OK; | |
451 | ! return GUI_CHILD_FAILED; | |
452 | } | |
453 | ||
454 | + #endif /* MAY_FORK */ | |
455 | + | |
456 | /* | |
457 | * Call this when vim starts up, whether or not the GUI is started | |
458 | */ | |
459 | *** ../vim-7.3.314/src/version.c 2011-09-14 19:01:38.000000000 +0200 | |
460 | --- src/version.c 2011-09-14 19:02:45.000000000 +0200 | |
461 | *************** | |
462 | *** 711,712 **** | |
463 | --- 711,714 ---- | |
464 | { /* Add new patch number below this line */ | |
465 | + /**/ | |
466 | + 315, | |
467 | /**/ | |
468 | ||
469 | -- | |
470 | A)bort, R)etry, B)ang it with a large hammer | |
471 | ||
472 | /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ | |
473 | /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ | |
474 | \\\ an exciting new programming language -- http://www.Zimbu.org /// | |
475 | \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |