Difficulties in using GTK from Emacs



Jan Djarv mbox200 swipnet se, who is trying to make Emacs use GTK 1.2
as an alternative to the other toolkits it now supports, has
encountered some aspects that are painful to use or seem to require
major changes in Emacs.

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.

I asked him for details, and he explained two problems.  I put several
messages together to form one coherent description.

Problem 1.

Currently in GTK it seems to be hard to write your own event loop.  It
isn't straightforward to get the next event and later tell GTK to act
upon that event.

For instance, Emacs needs to handle menu events before passing it to
the toolkit that implements the menu--it has to execute Lisp code
first.  Other reasons for having your own event loop include handling
other input sources, signals handling, etc.

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);
            }
        }

This, however, fails to pass the events to GTK widgets.

A solution that does pass events to GTK widgets is to override the GTK
event handler by calling gdk_event_handler_set with a function that
copies the event.  Then one can later pass the event to
gtk_main_do_event.  But it is a mystery why this doesn't work, Why
doesn't gtk_main_do_event do this in the loop above?

It is also hard to use GTK in programs that have event loops that use
X events.

The only way to get the XEvent seems to call gdk_window_add_filter for
all windows created (I can imagine some GTK widgets creating several
windows, so just doing this is hard).  Then the XEvent is available
for the filter function.  To prevent GDK from passing this event
further on, the filter function needs to return GDK_FILTER_REMOVE.
Then one gets the XEvent, but no GdkEvent to pass to gtk_main_do_event
later on.

The solution would be if GTK/GDK could supply a function that takes
an XEvent and acts upon it, gdk_act_on_xevent for example.  It would
be the equivalent to the XtAppProcessEvent function in Xt.

A function like gdk_act_on_xevent would make it much easier to
integrate GTK into existing programs.  Each X event has a straight
forward translation to a GdkEvent.


He also tried callung gtk_main_iteration instead.
So the code looked like this:

   while (XPending())
     {
       XPeekEvent();
       /* Normal Emacs event handling */

       gtk_main_iteration(); /* Unfortunately, does not do XNextEvent always,
				see below */
     }


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.


Problem 2.

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.

He tried installing his filter and passing some events to the standard
filter.  He said that then you have the event in a callback function,
not in the event loop, so it will be flags to check, it is not pretty.
Instead of this:

   XNextEvent(&event);
   switch (event->type)
   ...
   case ClientMessage:
     /* Handle wm protocols */

we would have to do something like (pseudo code):

static XEvent save_event;
static got_vm_event = FALSE;

void
wm_filter_func(XEvent ev)
{
   save_event = ev;
   got_vm_event = TRUE;
}

...
  /* In the event loop in XTread_socket */
   got_wm_event = FALSE;
   gtk_main_iteration ();
   if (got_wm_event) ... /* Handle wm protocols */
   else ... /* Handle other events */
...



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]