GtkFileChooser is disabled in gvim, because gvim exits gtk_main() level
1 every time an event is received, causing GTK to write to the disk
excessively.
gtk_main() has always stored the clipboard on the same trigger, so it's
fair to say that exiting gtk_main() constantly is not the way the GTK
developers expected an application to work. People who know stuff about
GTK agree:
http://mail.gnome.org/archives/gtk-list/2008-July/msg00131.html
My interest in this started when I discovered that GtkFileChooser had
been disabled. I missed it:
https://bugs.launchpad.net/ubuntu/+source/vim/+bug/365860
It's been 7 months now since that plaintive cry, so I gave up waiting
and wrote a patch. This is my first GTK project but it looks pretty
straightforward. I read the source code for gtk_main() and some other
things.
Emmanuele Bassi's advice was to create a separate GMainLoop:
http://mail.gnome.org/archives/gtk-list/2008-July/msg00146.html
That turns out to be unnecessary, since all GMainLoop does is calls
g_main_context_iteration() repeatedly, until it's time to exit. The
actual task of registering event sources and calling select() is done by
GMainContext, which exists whether or not a GMainLoop has been created.
Thus by calling g_main_context_iteration() at the relevant places, vim
can leave main_loop() unmodified.
My patch does this, and removes all calls to gtk_main_quit() except the
ones in modal dialogs. Modal dialogs are now implemented by calling
gtk_main() once only, and allowing the button handlers to call
gtk_main_quit(), just like in a regular GTK application.
We don't seem to be missing anything substantial by never calling
gtk_main(). You can register callbacks to be called when gtk_main()
exits, but luckily vim isn't doing that or else they'd be called on the
first keypress and then never again. Of course we miss out on that final
sync of recently-used.xbel, but it seems that it's already synced every
time it's changed, via the "changed" signal (see
gtk_recent_manager_changed() and its callers in gtk/gtkrecentmanager.c).
I haven't done cross-version tests on this patch, but
g_main_context_iteration() exists back to at least GLib 1.3.9 (September
2001).
Attached and online at:
http://tstarling.com/stuff/fix-gtk-main.patch
-- Tim Starling
--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---
Index: src/gui_gtk.c
===================================================================
--- src/gui_gtk.c (revision 1658)
+++ src/gui_gtk.c (working copy)
@@ -596,10 +596,6 @@
if (!gui.in_focus)
gui_focus_change(TRUE);
# endif
-
- /* make sure the menu action is taken immediately */
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
# if defined(FEAT_TOOLBAR) && !defined(HAVE_GTK2)
@@ -1145,9 +1141,6 @@
}
gui_drag_scrollbar(sb, value, dragging);
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
/* SBAR_VERT or SBAR_HORIZ */
@@ -1194,10 +1187,7 @@
* Implementation of the file selector related stuff
*/
#if defined(HAVE_GTK2) && GTK_CHECK_VERSION(2,4,0)
-/* This has been disabled, because the GTK library rewrites
- * ~/.recently-used.xbel every time the main loop is quit. For Vim that means
- * on just about any event. */
-/* # define USE_FILE_CHOOSER */
+# define USE_FILE_CHOOSER
#endif
#ifndef USE_FILE_CHOOSER
@@ -1212,8 +1202,6 @@
vw->browse_fname = (char_u *)g_strdup(gtk_file_selection_get_filename(
GTK_FILE_SELECTION(vw->filedlg)));
gtk_widget_hide(vw->filedlg);
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
static void
@@ -1227,8 +1215,6 @@
vw->browse_fname = NULL;
}
gtk_widget_hide(vw->filedlg);
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
static gboolean
@@ -1240,10 +1226,7 @@
gui.browse_fname = NULL;
}
gui.filedlg = NULL;
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
+ gtk_main_quit();
return FALSE;
}
#endif
@@ -1349,8 +1332,7 @@
# endif
gtk_widget_show(gui.filedlg);
- while (gui.filedlg && GTK_WIDGET_DRAWABLE(gui.filedlg))
- gtk_main_iteration_do(TRUE);
+ gtk_main();
#endif
# ifdef HAVE_GTK2
@@ -1642,8 +1624,7 @@
dlg_destroy_cb(int *p)
{
*p = TRUE; /* set dialog_destroyed to break out of the loop */
- if (gtk_main_level() > 0)
- gtk_main_quit();
+ gtk_main_quit();
}
int
@@ -1942,12 +1923,8 @@
GTK_WIDGET(dialog), VW_POS_MOUSE);
gtk_widget_show(dialog);
+ gtk_main();
- /* loop here until the dialog goes away */
- while (dialog_status == -1 && !dialog_destroyed
- && GTK_WIDGET_DRAWABLE(dialog))
- gtk_main_iteration_do(TRUE);
-
if (dialog_status < 0)
dialog_status = 0;
if (dialog_status != 1 && textfield != NULL)
@@ -2990,9 +2967,6 @@
CONVERT_FROM_UTF8_FREE(repl_text);
CONVERT_FROM_UTF8_FREE(find_text);
#endif
-
- if (rc && gtk_main_level() > 0)
- gtk_main_quit(); /* make sure cmd will be handled immediately */
}
/* our usual callback function */
Index: src/gui_gtk_x11.c
===================================================================
--- src/gui_gtk_x11.c (revision 1658)
+++ src/gui_gtk_x11.c (working copy)
@@ -698,9 +698,6 @@
xev.xproperty.window = commWindow;
xev.xproperty.state = PropertyNewValue;
serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev);
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
return FALSE;
}
@@ -834,10 +831,6 @@
if (widget != gui.drawarea)
gtk_widget_grab_focus(gui.drawarea);
- /* make sure the input buffer is read */
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
return TRUE;
}
@@ -851,10 +844,6 @@
if (blink_state != BLINK_NONE)
gui_mch_stop_blink();
- /* make sure the input buffer is read */
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
return TRUE;
}
@@ -1235,9 +1224,6 @@
if (p_mh)
gui_mch_mousehide(TRUE);
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
return TRUE;
}
@@ -1271,9 +1257,6 @@
else
clip_lose_selection(&clip_star);
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
return TRUE;
}
@@ -1311,9 +1294,6 @@
received_selection = RS_FAIL;
/* clip_free_selection(cbd); ??? */
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
return;
}
@@ -1439,9 +1419,6 @@
#ifdef HAVE_GTK2
g_free(tmpbuf_utf8);
#endif
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
/*
@@ -1722,9 +1699,6 @@
/* inform the editor engine about the occurrence of this event */
gui_send_mouse_event(button, x, y, FALSE, vim_modifiers);
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
/*
* Auto repeat timer handling.
*/
@@ -1913,8 +1887,6 @@
vim_modifiers = modifiers_gdk2mouse(event->state);
gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
- if (gtk_main_level() > 0)
- gtk_main_quit(); /* make sure the above will be handled immediately */
return TRUE;
}
@@ -1958,9 +1930,6 @@
gui_send_mouse_event(button, (int)event->x, (int)event->y,
FALSE, vim_modifiers);
- if (gtk_main_level() > 0)
- gtk_main_quit(); /* make sure the above will be handled immediately */
-
return TRUE;
}
#endif /* HAVE_GTK2 */
@@ -1989,8 +1958,6 @@
vim_modifiers = modifiers_gdk2mouse(event->state);
gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, vim_modifiers);
- if (gtk_main_level() > 0)
- gtk_main_quit(); /* make sure it will be handled immediately */
return TRUE;
}
@@ -2163,9 +2130,6 @@
add_to_input_buf(dropkey, (int)sizeof(dropkey));
else
add_to_input_buf(dropkey + 3, (int)(sizeof(dropkey) - 3));
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
/*
@@ -3210,9 +3174,6 @@
{
/* Add the string cmd into input buffer */
send_tabline_menu_event(clicked_page, (int)(long)user_data);
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
static void
@@ -3288,8 +3249,7 @@
{
/* Click after all tabs moves to next tab page. When "x" is
* small guess it's the left button. */
- if (send_tabline_event(x < 50 ? -1 : 0) && gtk_main_level() > 0)
- gtk_main_quit();
+ send_tabline_event(x < 50 ? -1 : 0);
}
#ifndef HAVE_GTK2
else
@@ -3315,8 +3275,7 @@
{
if (!ignore_tabline_evt)
{
- if (send_tabline_event(idx + 1) && gtk_main_level() > 0)
- gtk_main_quit();
+ send_tabline_event(idx + 1);
}
}
@@ -4301,9 +4260,6 @@
{
if (gui.mainwin != NULL)
gtk_widget_destroy(gui.mainwin);
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
/*
@@ -4590,8 +4546,7 @@
vw->fontname = (char_u *)gtk_font_selection_dialog_get_font_name(fs);
gtk_widget_hide(vw->fontdlg);
- if (gtk_main_level() > 0)
- gtk_main_quit();
+ gtk_main_quit();
}
static void
@@ -4600,8 +4555,7 @@
gui_T *vw = (gui_T *)cbdata;
gtk_widget_hide(vw->fontdlg);
- if (gtk_main_level() > 0)
- gtk_main_quit();
+ gtk_main_quit();
}
static void
@@ -4610,8 +4564,7 @@
gui_T *vw = (gui_T *)cbdata;
vw->fontdlg = NULL;
- if (gtk_main_level() > 0)
- gtk_main_quit();
+ gtk_main_quit();
}
#endif /* !HAVE_GTK2 */
@@ -4783,8 +4736,7 @@
}
/* Wait for the font dialog to be closed. */
- while (gui.fontdlg && GTK_WIDGET_DRAWABLE(gui.fontdlg))
- gtk_main_iteration_do(TRUE);
+ gtk_main();
if (gui.fontname != NULL)
{
@@ -6485,8 +6437,8 @@
void
gui_mch_update(void)
{
- while (gtk_events_pending() && !vim_is_input_buf_full())
- gtk_main_iteration_do(FALSE);
+ while (g_main_context_pending(NULL) && !vim_is_input_buf_full())
+ g_main_context_iteration(NULL, TRUE);
}
static gint
@@ -6497,9 +6449,6 @@
/* Just inform the caller about the occurrence of it */
*timed_out = TRUE;
- if (gtk_main_level() > 0)
- gtk_main_quit();
-
return FALSE; /* don't happen again */
}
@@ -6516,9 +6465,6 @@
static char_u bytes[3] = {CSI, (int)KS_EXTRA, (int)KE_SNIFF};
add_to_input_buf(bytes, 3);
-
- if (gtk_main_level() > 0)
- gtk_main_quit();
}
#endif
@@ -6593,7 +6539,7 @@
* situations, sort of race condition).
*/
if (!input_available())
- gtk_main();
+ g_main_context_iteration(NULL, TRUE);
/* Got char, return immediately */
if (input_available())
@@ -6789,7 +6735,7 @@
* during the FocusGained event. */
start = time(NULL);
while (received_selection == RS_NONE && time(NULL) < start + 3)
- gtk_main(); /* wait for selection_received_cb */
+ g_main_context_iteration(NULL, TRUE); /* wait for selection_received_cb */
if (received_selection != RS_FAIL)
return;