Richard Stallman <[EMAIL PROTECTED]> writes: > In order for GTK to do its job well, it needs to make this kind of use > easy. Making it easy to put GTK into existing X applications has to > be easy, and should not require major redesign of the application. > Developers may wish, for various reasons, to keep some of the code > using X directly; GTK needs to support that.
For this purpose it's very important to use GTK 2, which explicitly addresses this issue via changes in the main loop interface. I believe Owen wrote a mail a long time ago to someone else trying to port Emacs to GTK, about main loop integration issues. Maybe he still has that or you still have it. I'll append a mail I wrote to the Eclipse project about the same topic which may be useful, though some context is no doubt missing. There's also documentation here: http://developer.gnome.org/doc/API/2.0/glib/glib-the-main-event-loop.html > GTK uses GdkEvents, so one would think this would work: > > while (gdk_events_pending ()) > /* He tried gtk_events_pending too; it doesn't affect the issue. */ > { > GdkEvent* ev = gdk_event_get (); > if (ev) > { > gtk_main_do_event (ev); > gdk_event_free (ev); > } > } A conceptual misunderstanding here is that the queue of GdkEvents makes up the entire GTK+ main loop. The main loop is much more general than that, it represents any kind of task, including tasks done at certain intervals (timeouts) and tasks done when there are no other tasks (idles). Tasks also have priorities and are scheduled. Processing the queue of GdkEvents is just one task among many, and all the tasks are needed for GTK to operate correctly, especially in GTK 2. > It is also hard to use GTK in programs that have event loops that use > X events. I wrote a window manager using GTK that uses X directly for most of the window manager code. This is done using an event filter, gdk_window_add_filter(). Somewhat obscurely, if you pass NULL here you get events for all windows. I just added that point to the docs. But it should make things much easier for you to know this. > Alas, this didn't work either, because gtk_main_iteration does not use > XPending to see if it should do any work, it looks at the filedescriptor > to the X connection to see if there is something to read. Since we did > XPeekEvent, there isn't anythingto read from the file descriptor, but > there is an event in the X input queue. gtk_main_iteration ignores > the X input queue. This is no longer the case in GTK 2, GTK 2 will call XPending() always. > GDK has a function that lets the programmer set a filter for > ClientMessages and specific Atoms. By default, gdk installs its own > filter for WM protocols. This filter turns wm_delete_window events to > an GDK event of type GDK_DELETE and drops all others (like > wm_take_focus, wm_save_yourself that Emacs acts upon). Emacs would > have to put in its own filter that would override the GDK default > filter. Since wm_save_yourself and so on are useful, it should be > made easy for programs to handle them. If you're using GtkWindow (as you are required to if you're going to put GTK widgets in the window) then wm_take_focus and wm_delete_window are handled by GTK and you're going to have to be careful not to get GTK confused if you also try to deal with them. GTK will for example get confused if you change its "input model" (see table of four input models in the ICCCM) and no doubt Emacs code also assumes one of these, so if they are different something has to give. You also have the problem that you can't change what GTK sets for the WM_PROTOCOLS hint, so you can't tell the WM that you support wm_save_yourself or other protocols that GTK ignores. Using gdk_window_add_filter() and some careful hacks you should be able to work around all this - but you're going to need to understand what GTK does internally, and rely on that information to an uncomfortable degree. (BTW, wm_save_yourself is an old deprecated feature as of the 1994 SM specification, so Emacs should really be thinking about using the "new" (8-year-old) spec instead...) Havoc Here are those mails to the Eclipse project: From: Havoc Pennington <[EMAIL PROTECTED]> Subject: Re: [platform-swt-dev] GTK in CVS To: [EMAIL PROTECTED] Date: 05 Dec 2001 16:23:25 -0500 [EMAIL PROTECTED] writes: > - positioning widgets such that they do not move when the parent is > resized (we are using a fixed + hacks) > > - everything to do with redraw, damaged areas, forcing paints, etc. Things don't quite compile for me here yet, so I can't look at the actual problems - glancing through the code, a "mismatch" between the way GTK wants to do things and the way SWT wants to do things is that you're expecting certain things to be synchronous (resulting in calls go gtk_widget_show_now(), forced gtk_widget_realize(), the size request/allocation process, and so on), while GTK wants those things to happen "lazily" in an idle handler. I would expect to have a lot of problems with flicker/jumping, and plain old inefficiency, unless we're careful about how this is set up. > - making Display.sleep() work properly Spent some time talking to Owen about this. GLib 2.0 has a revised main loop that's intended to make this kind of thing easier to do. There are some possible hacks for GLib 1.2. As you know the GLib main loop is a general-purpose thing that can contain any kind of "event source." Built-in sources are timeouts, idles, and input handlers, for example. In both versions the loop has four "steps": prepare - ask all sources a) do they already have events and b) when they definitely need to be asked again (when do we need to wake up and ask again - e.g. a timeout requires that we wake up after the remaining time elapses) poll - sleep on all file descriptors (descriptors are provided by certain kinds of source), with the min timeout from all prepared sources, until we get a descriptor event or a timeout check - ask all sources if they have events now, taking into account the results of the poll dispatch - dispatch the sources with events ready In GTK 1.2, there is no way to break these apart. The available API is: g_main_pending(): prepare, if there are events return right away, else poll with timeout of 0 and check, then return whether we have events. (Different in 2.0 in that it always polls, even if the prepare has events already, in order to handle source priorities correctly.) g_main_iteration(): do the whole cycle including dispatch > From looking at Display.sleep() what we want to do is prepare/poll/check, but not dispatch, and with the usual poll timeout, not a poll timeout of 0 as g_main_pending() uses. So GTK 1.2 does not give us the appropriate API. In GLib 2.0, we have exported API to do each of the steps. So there are g_main_context_prepare(), g_main_context_poll(), g_main_context_check(), etc. functions. Display.sleep() needs to call g_main_context_prepare(), then get poll info with g_main_context_query(), do the g_main_context_poll() with that info, and then g_main_context_check(). In readAndDispatch(), I'm not sure if we want just the g_main_context_dispatch(), or a full g_main_context_iteration(), but something along those lines. Basically the idea is to copy the code out of the static function g_main_context_iterate() in glib/glib/gmain.c, removing the places where it uses private API, those are just efficiency hacks. (The code copy really shouldn't be required, I filed this bug report on that: http://bugzilla.gnome.org/show_bug.cgi?id=66290 but it's past 2.0 API freeze so for now we have to reimplement a few lines, not a huge deal.) Anyway, this should give us what I take to be the correct semantics for SWT, which is that Display.sleep() never processes events, just sleeps until some arrive. (From the XtAppPeekEvent() man page, current Motif Display.sleep() processes timeouts without returning however - so maybe it's supposed to sleep until widget events arrive, and just process other kinds of event?) For GLib 1.2, things are going to be more exciting. The hack we came up with for Display.sleep() is pretty broken, but is: while (g_main_iteration (FALSE)) /* FALSE means don't block, just * run already-ready events */ { /* Here we get the X display connection file descriptor, * and block until it has data using poll() system call * directly on that single descriptor */ } The problem is that timeout and input event sources are not going to wake us up out of the sleep. I don't think GTK 1.2 itself relies on either of these, but if SWT uses timers, we'd need to do a custom SWT-specific hack to track those and be sure we pass an appropriate timeout to poll(). Another possible hack is to _always_ pass say a 50 ms timeout to poll(), so we never accidentally lock up forever, but of course that will mean constantly eating CPU at some low level. No more than the current Display.sleep() implementation, of course. Docs for 2.0 main loop stuff can be found here: http://developer.gnome.org/doc/API/2.0/glib/glib-the-main-event-loop.html It may not be clear that gtk_main_iteration(), gtk_main(), etc. are just trivial wrappers around the GLib stuff - the main loop was moved to GLib in the 1.0->1.2 transition, and gtk_main_* remains as a compatibility layer. Havoc From: Havoc Pennington <[EMAIL PROTECTED]> Subject: Re: [platform-swt-dev] GTK in CVS To: [EMAIL PROTECTED] Date: 05 Dec 2001 16:31:49 -0500 Havoc Pennington <[EMAIL PROTECTED]> writes: > For GLib 1.2, things are going to be more exciting. The hack > we came up with for Display.sleep() is pretty broken, but is: > > while (g_main_iteration (FALSE)) /* FALSE means don't block, just > * run already-ready events > */ > { > /* Here we get the X display connection file descriptor, > * and block until it has data using poll() system call > * directly on that single descriptor > */ > } > Oops - this was intended to be a conceptual description of the whole "SWT main loop" including both sleep() and readAndDispatch(). sleep() would just be something like: if (g_main_pending()) return true; else { /* first poll on X file descriptor */ return g_main_pending (); } while readAndDispatch() would do the "while (g_main_iteration (FALSE))" part. Havoc _______________________________________________ gtk-list mailing list [EMAIL PROTECTED] http://mail.gnome.org/mailman/listinfo/gtk-list
