Index: configure.in =================================================================== RCS file: /cvsroot/emacs/emacs/configure.in,v retrieving revision 1.315 diff -u -I*~ -r1.315 configure.in --- configure.in 27 Nov 2002 22:53:51 -0000 1.315 +++ configure.in 9 Dec 2002 04:45:16 -0000 @@ -107,6 +107,10 @@ [ --with-gif use -lungif for displaying GIF images]) AC_ARG_WITH(png, [ --with-png use -lpng for displaying PNG images]) +AC_ARG_WITH(gtk, +[ --with-gtk use GTK]) +AC_ARG_WITH(pkg-config-prog, +[ --with-pkg-config-prog Path to pkg-config to use for finding GTK]) AC_ARG_WITH(toolkit-scroll-bars, [ --without-toolkit-scroll-bars don't use Motif or Xaw3d scroll bars]) @@ -1781,6 +1785,86 @@ fi fi +dnl This function defintion taken from Gnome 2.0 +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN(PKG_CHECK_MODULES, [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or give the full path to pkg-config with" + echo "*** the PKG_CONFIG environment variable or --with-pkg-config-prog." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + +HAVE_GTK=no +if test "${with_gtk}" = "yes"; then + GLIB_REQUIRED=2.0.1 + GTK_REQUIRED=2.0.1 + GTK_MODULES="gtk+-2.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED" + + dnl Check if --with-pkg-config-prog has been given. + if test "X${with_pkg_config_prog}" != X; then + PKG_CONFIG="${with_pkg_config_prog}" + fi + dnl Checks for libraries. + PKG_CHECK_MODULES(GTK, $GTK_MODULES) + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + C_SWITCH_X_SITE="$C_SWITCH_X_SITE $GTK_CFLAGS" + HAVE_GTK=yes + AC_DEFINE(HAVE_GTK) + USE_X_TOOLKIT=none + + dnl Gtk scrollbars resembles toolkit scrollbars alot, so to avoid + dnl a lot if #ifdef:s, say we have toolkit scrollbars. + with_toolkit_scroll_bars=yes +fi + dnl Do not put whitespace before the #include statements below. dnl Older compilers (eg sunos4 cc) choke on it. if test x"${USE_X_TOOLKIT}" = xmaybe; then @@ -1903,7 +1987,7 @@ fi fi -dnl Use toolkit scroll bars if configured for X toolkit and either +dnl Use toolkit scroll bars if configured for GTK or X toolkit and either dnl using Motif or Xaw3d is available, and unless dnl --with-toolkit-scroll-bars=no was specified. @@ -1920,6 +2004,9 @@ AC_DEFINE(USE_TOOLKIT_SCROLL_BARS) USE_TOOLKIT_SCROLL_BARS=yes fi + elif test "${HAVE_GTK}" = "yes"; then + AC_DEFINE(USE_TOOLKIT_SCROLL_BARS) + USE_TOOLKIT_SCROLL_BARS=yes fi fi @@ -2723,6 +2810,13 @@ ])dnl #### Report on what we decided to do. +#### Report GTK as a toolkit, even if it doesn't use Xt. +#### It makes printing result more understandable as using GTK sets +#### toolkit_scroll_bars to yes by default. +if test "${HAVE_GTK}" = "yes"; then + USE_X_TOOLKIT=GTK +fi + echo " Configured for \`${canonical}'. Index: src/Makefile.in =================================================================== RCS file: /cvsroot/emacs/emacs/src/Makefile.in,v retrieving revision 1.262 diff -u -I*~ -r1.262 Makefile.in --- src/Makefile.in 25 Nov 2002 19:08:14 -0000 1.262 +++ src/Makefile.in 9 Dec 2002 04:45:20 -0000 @@ -252,12 +252,19 @@ #define C_SWITCH_ASM #endif +#ifdef HAVE_GTK +#define USE_GTK +TOOLKIT_DEFINES = -DUSE_GTK +#endif + #ifdef USE_X_TOOLKIT #define address@hidden@ TOOLKIT_DEFINES = address@hidden@ #else +#ifndef USE_GTK TOOLKIT_DEFINES = #endif +#endif /* DO NOT use -R. There is a special hack described in lastfile.c which is used instead. Some initialized data areas are modified @@ -300,7 +307,12 @@ #ifdef HAVE_MENUS /* Include xmenu.o in the list of X object files. */ + +#ifdef USE_GTK +XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o gtkutil.o +#else XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o +#endif /* The X Menu stuff is present in the X10 distribution, but missing from X11. If we have X10, just use the installed library; @@ -372,10 +384,17 @@ #endif /* not LIBXT_STATIC */ #else /* not USE_X_TOOLKIT */ + +#ifdef USE_GTK address@hidden@ +OLDXMENU= +LIBXMENU= +#endif /* USE_GTK */ + #ifdef HAVE_X_SM -LIBXT=-lSM -lICE +LIBXT=$(LIBW) -lSM -lICE #else -LIBXT= +LIBXT=$(LIBW) #endif #endif /* not USE_X_TOOLKIT */ @@ -1143,18 +1162,21 @@ window.h charset.h msdos.h dosfns.h composite.h atimer.h systime.h $(config_h) xfns.o: xfns.c buffer.h frame.h window.h keyboard.h xterm.h dispextern.h \ $(srcdir)/../lwlib/lwlib.h blockinput.h atimer.h systime.h epaths.h \ - charset.h $(config_h) + charset.h gtkutil.h $(config_h) xmenu.o: xmenu.c xterm.h termhooks.h window.h dispextern.h frame.h buffer.h \ keyboard.h $(srcdir)/../lwlib/lwlib.h blockinput.h atimer.h systime.h \ - msdos.h $(config_h) + gtkutil.h msdos.h $(config_h) xterm.o: xterm.c xterm.h termhooks.h termopts.h termchar.h window.h buffer.h \ dispextern.h frame.h disptab.h blockinput.h atimer.h systime.h syssignal.h \ keyboard.h gnu.h charset.h ccl.h fontset.h composite.h \ - coding.h process.h $(config_h) + coding.h process.h gtkutil.h $(config_h) xselect.o: xselect.c process.h dispextern.h frame.h xterm.h blockinput.h \ charset.h coding.h ccl.h buffer.h atimer.h systime.h $(config_h) xrdb.o: xrdb.c $(config_h) epaths.h xsmfns.o: xsmfns.c $(config_h) systime.h sysselect.h termhooks.h +gtkutil.o: gtkutil.c gtkutil.h xterm.h lisp.h frame.h $(config_h) \ + blockinput.h + hftctl.o: hftctl.c $(config_h) sound.o: sound.c dispextern.h $(config_h) atimer.o: atimer.c atimer.h systime.h $(config_h) Index: src/alloc.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/alloc.c,v retrieving revision 1.282 diff -u -I*~ -r1.282 alloc.c --- src/alloc.c 14 Nov 2002 14:12:12 -0000 1.282 +++ src/alloc.c 9 Dec 2002 04:45:23 -0000 @@ -4245,6 +4245,13 @@ mark_stack (); #endif +#ifdef USE_GTK + { + extern void xg_mark_data (); + xg_mark_data (); + } +#endif + gc_sweep (); /* Clear the mark bits that we set in certain root slots. */ Index: src/config.in =================================================================== RCS file: /cvsroot/emacs/emacs/src/config.in,v retrieving revision 1.178 diff -u -I*~ -r1.178 config.in --- src/config.in 29 Nov 2002 06:25:05 -0000 1.178 +++ src/config.in 9 Dec 2002 04:45:23 -0000 @@ -721,6 +721,10 @@ /* Define to 1 if using an X toolkit. */ #undef USE_X_TOOLKIT +/* Define if using GTK. */ +#undef HAVE_GTK + + /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ Index: src/fileio.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/fileio.c,v retrieving revision 1.467 diff -u -I*~ -r1.467 fileio.c --- src/fileio.c 7 Dec 2002 21:39:50 -0000 1.467 +++ src/fileio.c 9 Dec 2002 04:45:27 -0000 @@ -6105,7 +6105,7 @@ GCPRO2 (insdef, default_filename); -#if defined (USE_MOTIF) || defined (HAVE_NTGUI) +#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event)) && use_dialog_box && have_menus_p ()) Index: src/frame.h =================================================================== RCS file: /cvsroot/emacs/emacs/src/frame.h,v retrieving revision 1.98 diff -u -I*~ -r1.98 frame.h --- src/frame.h 14 Nov 2002 14:15:48 -0000 1.98 +++ src/frame.h 9 Dec 2002 04:45:28 -0000 @@ -270,7 +270,8 @@ /* Number of lines of menu bar. */ int menu_bar_lines; -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) /* Nonzero means using a menu bar that comes from the X toolkit. */ int external_menu_bar; #endif @@ -468,7 +469,8 @@ /* Nonzero if this frame should display a menu bar in a way that does not use any text lines. */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) #define FRAME_EXTERNAL_MENU_BAR(f) (f)->external_menu_bar #else #define FRAME_EXTERNAL_MENU_BAR(f) 0 Index: src/keyboard.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/keyboard.c,v retrieving revision 1.716 diff -u -I*~ -r1.716 keyboard.c --- src/keyboard.c 22 Nov 2002 12:23:13 -0000 1.716 +++ src/keyboard.c 9 Dec 2002 04:45:33 -0000 @@ -3857,7 +3862,8 @@ XSETBUFFER (obj, current_buffer); kbd_fetch_ptr = event + 1; } -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) else if (event->kind == MENU_BAR_ACTIVATE_EVENT) { kbd_fetch_ptr = event + 1; @@ -3964,7 +3970,8 @@ { obj = make_lispy_event (event); -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined(MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined(MAC_OS) \ + || defined (USE_GTK) /* If this was a menu selection, then set the flag to inhibit writing to last_nonmenu_event. Don't do this if the event we're returning is (menu-bar), though; that indicates the @@ -5027,7 +5034,7 @@ pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), &column, &row, NULL, 1); -#ifndef USE_X_TOOLKIT +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) /* In the non-toolkit version, clicks on the menu bar are ordinary button events in the event buffer. Distinguish them, and invoke the menu. @@ -5079,7 +5086,7 @@ return Fcons (item, Fcons (position, Qnil)); } -#endif /* not USE_X_TOOLKIT */ +#endif /* not USE_X_TOOLKIT && not USE_GTK */ /* Set `window' to the window under frame pixel coordinates event->x/event->y. */ @@ -5317,7 +5324,7 @@ } } -#ifdef USE_TOOLKIT_SCROLL_BARS +#if USE_TOOLKIT_SCROLL_BARS /* We don't have down and up events if using toolkit scroll bars, so make this always a click event. Store in the `part' of @@ -5568,7 +5575,8 @@ } #endif /* HAVE_MOUSE */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) case MENU_BAR_EVENT: if (EQ (event->arg, event->frame_or_window)) /* This is the prefix key. We translate this to Index: src/lisp.h =================================================================== RCS file: /cvsroot/emacs/emacs/src/lisp.h,v retrieving revision 1.443 diff -u -I*~ -r1.443 lisp.h --- src/lisp.h 25 Nov 2002 19:06:07 -0000 1.443 +++ src/lisp.h 9 Dec 2002 04:45:35 -0000 @@ -3122,6 +3122,7 @@ extern void syms_of_xfns P_ ((void)); extern void init_xfns P_ ((void)); extern Lisp_Object Vx_resource_name; +extern Lisp_Object Vx_resource_class; EXFUN (Fxw_display_color_p, 1); EXFUN (Fx_file_dialog, 4); #endif /* HAVE_X_WINDOWS */ Index: src/xdisp.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xdisp.c,v retrieving revision 1.793 diff -u -I*~ -r1.793 xdisp.c --- src/xdisp.c 29 Nov 2002 16:19:26 -0000 1.793 +++ src/xdisp.c 9 Dec 2002 04:45:44 -0000 @@ -200,7 +200,8 @@ #define INFINITY 10000000 -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) extern void set_frame_menubar P_ ((struct frame *f, int, int)); extern int pending_menu_activation; #endif @@ -7512,7 +7513,8 @@ if (FRAME_WINDOW_P (f) ? -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) FRAME_EXTERNAL_MENU_BAR (f) #else FRAME_MENU_BAR_LINES (f) > 0 @@ -7563,7 +7565,8 @@ FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); /* Redisplay the menu bar in case we changed it. */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) if (FRAME_WINDOW_P (f) #if defined (MAC_OS) /* All frames on Mac OS share the same menubar. So only the @@ -7576,11 +7579,11 @@ /* On a terminal screen, the menu bar is an ordinary screen line, and this makes it get updated. */ w->update_mode_line = Qt; -#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */ +#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI || MAC_OS || USE_GTK) */ /* In the non-toolkit version, the menu bar is an ordinary screen line, and this makes it get updated. */ w->update_mode_line = Qt; -#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */ +#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || MAC_OS || USE_GTK) */ unbind_to (count, Qnil); set_buffer_internal_1 (prev); @@ -8544,7 +8547,7 @@ return; } -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) if (popup_activated ()) return; #endif @@ -10761,7 +10764,8 @@ if (FRAME_WINDOW_P (f)) { -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f); #else redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0; Index: src/xfns.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xfns.c,v retrieving revision 1.567 diff -u -I*~ -r1.567 xfns.c --- src/xfns.c 6 Dec 2002 17:05:15 -0000 1.567 +++ src/xfns.c 9 Dec 2002 04:45:50 -0000 @@ -65,6 +65,10 @@ #include "[.bitmaps]gray.xbm" #endif +#ifdef USE_GTK +#include "gtkutil.h" +#endif + #ifdef USE_X_TOOLKIT #include @@ -340,6 +344,15 @@ || f->output_data.x->icon_desc == wdesc) return f; #else /* not USE_X_TOOLKIT */ +#ifdef USE_GTK + if (f->output_data.x->edit_widget) + { + GtkWidget *gwdesc = xg_win_to_widget (wdesc); + struct x_output *x = f->output_data.x; + if (gwdesc != 0 && gwdesc == x->edit_widget) + return f; + } +#endif /* USE_GTK */ if (FRAME_X_WINDOW (f) == wdesc || f->output_data.x->icon_desc == wdesc) return f; @@ -348,7 +361,7 @@ return 0; } -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Like x_window_to_frame but also compares the window with the widget's windows. */ @@ -377,13 +390,23 @@ found = f; else if (x->widget) { - if (wdesc == XtWindow (x->widget) - || wdesc == XtWindow (x->column_widget) +#ifdef USE_GTK + GtkWidget *gwdesc = xg_win_to_widget (wdesc); + if (gwdesc != 0 + && (gwdesc == x->widget + || gwdesc == x->edit_widget + || gwdesc == x->vbox_widget + || gwdesc == x->menubar_widget)) + found = f; +#else + if (wdesc == XtWindow (x->widget) + || wdesc == XtWindow (x->column_widget) || wdesc == XtWindow (x->edit_widget)) found = f; /* Match if the window is this frame's menubar. */ else if (lw_window_is_in_menubar (wdesc, x->menubar_widget)) found = f; +#endif } else if (FRAME_X_WINDOW (f) == wdesc) /* A tooltip frame. */ @@ -419,10 +442,19 @@ return f; else if (x->widget) { - if (wdesc == XtWindow (x->widget) - || wdesc == XtWindow (x->column_widget) +#ifdef USE_GTK + GtkWidget *gwdesc = xg_win_to_widget (wdesc); + if (gwdesc != 0 + && (gwdesc == x->widget + || gwdesc == x->edit_widget + || gwdesc == x->vbox_widget)) + return f; +#else + if (wdesc == XtWindow (x->widget) + || wdesc == XtWindow (x->column_widget) || wdesc == XtWindow (x->edit_widget)) return f; +#endif } else if (FRAME_X_WINDOW (f) == wdesc) /* A tooltip frame. */ @@ -452,9 +484,25 @@ continue; x = f->output_data.x; /* Match if the window is this frame's menubar. */ +#ifdef USE_GTK + if (x->menubar_widget) + { + GtkWidget *gwdesc = xg_win_to_widget (wdesc); + int found = 0; + + BLOCK_INPUT; + if (gwdesc != 0 + && (gwdesc == x->menubar_widget + || gtk_widget_get_parent (gwdesc) == x->menubar_widget)) + found = 1; + UNBLOCK_INPUT; + if (found) return f; + } +#else if (x->menubar_widget && lw_window_is_in_menubar (wdesc, x->menubar_widget)) return f; +#endif } return 0; } @@ -484,6 +532,11 @@ if (x->widget) { /* This frame matches if the window is its topmost widget. */ +#ifdef USE_GTK + GtkWidget *gwdesc = xg_win_to_widget (wdesc); + if (gwdesc == x->widget) + return f; +#else if (wdesc == XtWindow (x->widget)) return f; #if 0 /* I don't know why it did this, @@ -494,6 +547,7 @@ && wdesc == XtWindow (x->menubar_widget)) return f; #endif +#endif } else if (FRAME_X_WINDOW (f) == wdesc) /* Tooltip frame. */ @@ -501,7 +555,7 @@ } return 0; } -#endif /* USE_X_TOOLKIT */ +#endif /* USE_X_TOOLKIT || USE_GTK */ @@ -2119,7 +2173,7 @@ /* Make sure we redisplay all windows in this frame. */ windows_or_buffers_changed++; -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) FRAME_MENU_BAR_LINES (f) = 0; if (nlines) { @@ -2136,7 +2190,7 @@ if (FRAME_X_P (f)) f->output_data.x->menubar_widget = 0; } -#else /* not USE_X_TOOLKIT */ +#else /* not USE_X_TOOLKIT && not USE_GTK */ FRAME_MENU_BAR_LINES (f) = nlines; x_change_window_heights (f->root_window, nlines - olines); #endif /* not USE_X_TOOLKIT */ @@ -2465,8 +2519,13 @@ XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget), &icon); #else /* not USE_X_TOOLKIT */ +#ifdef USE_GTK + gtk_window_set_title (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + SDATA (name)); +#else /* not USE_GTK */ XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text); XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon); +#endif /* not USE_GTK */ #endif /* not USE_X_TOOLKIT */ if (!NILP (f->icon_name) && icon.value != (unsigned char *) SDATA (f->icon_name)) @@ -3938,7 +3997,16 @@ } #else /* not USE_X_TOOLKIT */ +#ifdef USE_GTK +void +x_window (f) + FRAME_PTR f; +{ + if (! xg_create_frame_widgets (f)) + error ("Unable to create window"); +} +#else /*! USE_GTK */ /* Create and set up the X window for frame F. */ void @@ -4041,6 +4109,7 @@ error ("Unable to create window"); } +#endif /* not USE_GTK */ #endif /* not USE_X_TOOLKIT */ /* Handle the icon stuff for this window. Perhaps later we might @@ -4618,7 +4687,7 @@ new frames. */ call1 (Qface_set_after_frame_default, frame); -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Create the menu bar. */ if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) { @@ -4626,13 +4695,15 @@ frame and we didn't make it visible. */ initialize_frame_menubar (f); +#ifndef USE_GTK /* This is a no-op, except under Motif where it arranges the main window for the widgets on it. */ lw_set_main_areas (f->output_data.x->column_widget, f->output_data.x->menubar_widget, f->output_data.x->edit_widget); +#endif /* not USE_GTK */ } -#endif /* USE_X_TOOLKIT */ +#endif /* USE_X_TOOLKIT || USE_GTK */ /* Tell the server what size and position, etc, we want, and how badly we want them. This should be done after we have the menu @@ -11692,6 +11763,177 @@ #endif /* USE_MOTIF */ +#ifdef USE_GTK + +enum +{ + GTK_FILE_NOT_DONE, + GTK_FILE_OK, + GTK_FILE_CANCEL, + GTK_FILE_DESTROY, + GTK_FILE_ACTIVATE +}; + +static void +FileSelOk (w, arg) + GtkWidget *w; + gpointer arg; +{ + *(int*)arg = GTK_FILE_OK; +} + +static void +FileSelCancel (w, arg) + GtkWidget *w; + gpointer arg; +{ + *(int*)arg = GTK_FILE_CANCEL; +} + +static void +FileSelDestroy (w, arg) + GtkWidget *w; + gpointer arg; +{ + *(int*)arg = GTK_FILE_DESTROY; +} + +static void +FileSelActivated (w, arg) + GtkWidget *w; + gpointer arg; +{ + *(int*)arg = GTK_FILE_ACTIVATE; +} + +DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0, + "Read file name, prompting with PROMPT in directory DIR.\n\ +Use a file selection dialog.\n\ +Select DEFAULT-FILENAME in the dialog's file selection box, if\n\ +specified. Don't let the user enter a file name in the file\n\ +selection dialog's entry field, if MUSTMATCH is non-nil.") + (prompt, dir, default_filename, mustmatch) + Lisp_Object prompt, dir, default_filename, mustmatch; +{ + GtkWidget* filewin; + GtkFileSelection* filesel; + char *fn; + int gtk_file_done = GTK_FILE_NOT_DONE; + Lisp_Object file = Qnil; + Lisp_Object def_nodir = Qnil; + int count = specpdl_ptr - specpdl; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; + + GCPRO6 (prompt, dir, default_filename, mustmatch, def_nodir, file); + CHECK_STRING (prompt); + CHECK_STRING (dir); + + /* Prevent redisplay. */ + specbind (Qinhibit_redisplay, Qt); + + BLOCK_INPUT; + + filewin = gtk_file_selection_new (SDATA (prompt)); + filesel = GTK_FILE_SELECTION (filewin); + + g_signal_connect (filesel->ok_button, + "clicked", + G_CALLBACK (FileSelOk), + >k_file_done); + g_signal_connect (filesel->cancel_button, + "clicked", + G_CALLBACK (FileSelCancel), + >k_file_done); + g_signal_connect (filesel, + "destroy", + G_CALLBACK (FileSelDestroy), + >k_file_done); + + /* KOKO: GTK fileselection dialog does not have separate directory and + default filename options. */ + /* dir = Fexpand_file_name (dir, Qnil);*/ + if (STRINGP (default_filename)) + { + gtk_file_selection_set_filename (filesel, SDATA (default_filename)); + } + + if (! NILP (mustmatch)) + { + GtkTreeSelection *sel; + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list)); + g_signal_connect (sel, + "changed", + G_CALLBACK (FileSelActivated), + >k_file_done); + gtk_widget_set_sensitive (filesel->ok_button, FALSE); + gtk_widget_set_sensitive (filesel->file_list, FALSE); + gtk_file_selection_hide_fileop_buttons (filesel); + if (STRINGP (default_filename)) + { + def_nodir = Ffile_name_nondirectory (default_filename); + /* The row below doesn't seem to work the way it does in Motif, + i.e. only show files with this name. Must do this some + other way. + gtk_file_selection_complete(filesel, SDATA (def_nodir)); + */ + } + } + + + gtk_widget_show (filewin); + while (gtk_file_done == GTK_FILE_NOT_DONE) + { + gtk_main_iteration (); + if (NILP (mustmatch) + || NILP (def_nodir) + || gtk_file_done == GTK_FILE_CANCEL + || gtk_file_done == GTK_FILE_DESTROY + || gtk_file_done == GTK_FILE_OK) + continue; + + fn = (char*)gtk_file_selection_get_filename (filesel); + file = build_string (fn); + + gtk_widget_set_sensitive (filesel->ok_button, + ! NILP (Ffile_exists_p (file))); + + file = Ffile_name_nondirectory (file); + + /* This is not so nice, but there is no official way to do this + i.e. without using undocumented things in filesel. */ + if (strcmp (SDATA (def_nodir), SDATA (file)) != 0) + { + gtk_file_selection_set_filename (filesel, SDATA (def_nodir)); + gtk_widget_set_sensitive (filesel->ok_button, FALSE); + } + + gtk_file_done = GTK_FILE_NOT_DONE; + } + + + if (gtk_file_done == GTK_FILE_OK) + { + fn = (char*)gtk_file_selection_get_filename (filesel); + file = build_string (fn); + } + else if (gtk_file_done == GTK_FILE_DESTROY) + { + filesel = 0; + } + + if (filesel) gtk_widget_destroy (filewin); + + UNBLOCK_INPUT; + UNGCPRO; + + /* Make "Cancel" equivalent to C-g. */ + if (NILP (file)) + Fsignal (Qquit, Qnil); + + return unbind_to (count, file); +} + +#endif /* USE_GTK */ /*********************************************************************** Index: src/xmenu.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xmenu.c,v retrieving revision 1.237 diff -u -I*~ -r1.237 xmenu.c --- src/xmenu.c 14 Nov 2002 14:21:11 -0000 1.237 +++ src/xmenu.c 9 Dec 2002 04:45:52 -0000 @@ -81,7 +81,9 @@ #endif /* USE_LUCID */ #include "../lwlib/lwlib.h" #else /* not USE_X_TOOLKIT */ +#ifndef USE_GTK #include "../oldXMenu/XMenu.h" +#endif #endif /* not USE_X_TOOLKIT */ #endif /* HAVE_X_WINDOWS */ @@ -117,6 +119,13 @@ /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ #define HAVE_BOXES 1 +#endif /* USE_X_TOOLKIT */ + +#ifdef USE_GTK +#include "gtkutil.h" +#define HAVE_BOXES 1 +extern void set_frame_menubar (); +static Lisp_Object xdialog_show (); #endif static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, @@ -592,7 +601,7 @@ } #endif /* not HAVE_BOXES */ -#ifndef USE_X_TOOLKIT +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) if (!NILP(map)) /* Indicate visually that this is a submenu. */ item_string = concat2 (item_string, build_string (" >")); @@ -605,7 +614,7 @@ XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Display a submenu using the toolkit. */ if (! (NILP (map) || NILP (enabled))) { @@ -972,7 +981,7 @@ but I don't want to make one now. */ CHECK_WINDOW (window); -#ifndef USE_X_TOOLKIT +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) /* Display a menu with these alternatives in the middle of frame F. */ { @@ -1013,7 +1022,7 @@ #endif } -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Loop in Xt until the menu pulldown or dialog popup has been popped down (deactivated). This is used for x-popup-menu @@ -1022,6 +1031,7 @@ NOTE: All calls to popup_get_selection should be protected with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ +#ifdef USE_X_TOOLKIT void popup_get_selection (initial_event, dpyinfo, id) XEvent *initial_event; @@ -1122,6 +1132,25 @@ interrupt_input_pending = 1; } } +#endif /* USE_X_TOOLKIT */ + +#ifdef USE_GTK +/* Loop util popup_activated_flag is set to zero in a callback. + Used for popup menus and dialogs. */ +static void +popup_widget_loop () +{ + popup_activated_flag = 1; + + /* Process events in the Gtk event loop until done. */ + xg_pass_through_events = TRUE; + while (popup_activated_flag) + { + gtk_main_iteration (); + } + xg_pass_through_events = FALSE; +} +#endif /* Activate the menu bar of frame F. This is called from keyboard.c when it gets the @@ -1144,9 +1173,20 @@ if (!f->output_data.x->saved_menu_event->type) return; +#ifdef USE_GTK + if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window)) + return; +#endif + set_frame_menubar (f, 0, 1); BLOCK_INPUT; +#ifdef USE_GTK + XPutBackEvent (f->output_data.x->display_info->display, + f->output_data.x->saved_menu_event); + popup_activated_flag = 1; +#else XtDispatchEvent (f->output_data.x->saved_menu_event); +#endif UNBLOCK_INPUT; #ifdef USE_MOTIF if (f->output_data.x->saved_menu_event->type == ButtonRelease) @@ -1168,11 +1208,18 @@ /* This callback is invoked when the user selects a menubar cascade pushbutton, but before the pulldown menu is posted. */ +#ifdef USE_GTK +static void +popup_activate_callback (widget, client_data) + GtkWidget *widget; + gpointer client_data; +#else static void popup_activate_callback (widget, id, client_data) Widget widget; LWLIB_ID id; XtPointer client_data; +#endif { popup_activated_flag = 1; } @@ -1180,35 +1227,64 @@ /* This callback is invoked when a dialog or menu is finished being used and has been unposted. */ +#ifdef USE_GTK +static void +popup_deactivate_callback (widget, client_data) + GtkWidget *widget; + gpointer client_data; +#else static void popup_deactivate_callback (widget, id, client_data) Widget widget; LWLIB_ID id; XtPointer client_data; +#endif { popup_activated_flag = 0; } -/* Lwlib callback called when menu items are highlighted/unhighlighted +/* Callback called when menu items are highlighted/unhighlighted while moving the mouse over them. WIDGET is the menu bar or menu popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to the widget_value structure for the menu item, or null in case of unhighlighting. */ +#ifdef USE_GTK +void +menu_highlight_callback (widget, call_data) + GtkWidget *widget; + gpointer call_data; +#else void menu_highlight_callback (widget, id, call_data) Widget widget; LWLIB_ID id; void *call_data; +#endif { - widget_value *wv = (widget_value *) call_data; struct frame *f; Lisp_Object frame, help; +#ifdef USE_GTK + struct menu_gtk_data *cl_data; + cl_data = (struct menu_gtk_data*) g_object_get_data (G_OBJECT (widget), + G_FRAME_DATA); + if (! cl_data) return; + + f = cl_data->f; + + /* NYI */ + return; + +#else + widget_value *wv = (widget_value *) call_data; + help = wv ? wv->help : Qnil; /* Determine the frame for the help event. */ f = menubar_id_to_frame (id); +#endif + if (f) { XSETFRAME (frame, f); @@ -1218,7 +1294,11 @@ { /* WIDGET is the popup menu. It's parent is the frame's widget. See which frame that is. */ +#ifdef USE_GTK + GtkWidget *frame_widget = gtk_widget_get_parent (widget); +#else Widget frame_widget = XtParent (widget); +#endif Lisp_Object tail; for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) @@ -1234,32 +1314,66 @@ } } +/* Gtk calls callbacks just because we tell it what item should be + selected in a radio group. If this variable is set to z non-zero + value, we are creating menus and don't want callbacks right now. +*/ +#ifdef USE_GTK +static int xg_crazy_callback_abort = 0; +#endif + /* This callback is called from the menu bar pulldown menu when the user makes a selection. Figure out what the user chose and put the appropriate events into the keyboard buffer. */ - +#ifdef USE_GTK +static void +menubar_selection_callback (widget, client_data) + GtkWidget *widget; + gpointer client_data; +#else static void menubar_selection_callback (widget, id, client_data) Widget widget; LWLIB_ID id; XtPointer client_data; +#endif { Lisp_Object prefix, entry; - FRAME_PTR f = menubar_id_to_frame (id); Lisp_Object vector; Lisp_Object *subprefix_stack; int submenu_depth = 0; int i; + int menu_bar_items_used; + +#ifdef USE_GTK + FRAME_PTR f; + struct menu_gtk_data *cl_data; + + if (xg_crazy_callback_abort) + return; + + cl_data = (struct menu_gtk_data*) g_object_get_data (G_OBJECT (widget), + G_FRAME_DATA); + if (! cl_data || ! cl_data->f) + return; + menu_bar_items_used = cl_data->menu_bar_items_used; + f = cl_data->f; + vector = cl_data->menu_bar_vector; +#else + FRAME_PTR f = menubar_id_to_frame (id); + menu_bar_items_used = f->menu_bar_items_used; if (!f) return; - entry = Qnil; - subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); vector = f->menu_bar_vector; +#endif + + entry = Qnil; + subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object)); prefix = Qnil; i = 0; - while (i < f->menu_bar_items_used) + while (i < menu_bar_items_used) { if (EQ (XVECTOR (vector)->contents[i], Qnil)) { @@ -1592,6 +1706,9 @@ update_frame_menubar (f) FRAME_PTR f; { +#ifdef USE_GTK + return xg_update_frame_menubar (f); +#else struct x_output *x = f->output_data.x; int columns, rows; @@ -1626,6 +1743,7 @@ /* Force the pane widget to resize itself with the right values. */ EmacsFrameSetCharSize (x->edit_widget, columns, rows); UNBLOCK_INPUT; +#endif return 1; } @@ -1639,20 +1757,26 @@ int first_time; int deep_p; { +#ifdef USE_GTK + GtkWidget *menubar_widget = f->output_data.x->menubar_widget; +#else Widget menubar_widget = f->output_data.x->menubar_widget; + LWLIB_ID id; +#endif Lisp_Object items; widget_value *wv, *first_wv, *prev_wv = 0; int i, last_i; int *submenu_start, *submenu_end; int *submenu_top_level_items; - LWLIB_ID id; XSETFRAME (Vmenu_updating_frame, f); +#ifdef USE_X_TOOLKIT if (f->output_data.x->id == 0) f->output_data.x->id = next_menubar_widget_id++; id = f->output_data.x->id; +#endif if (! menubar_widget) deep_p = 1; @@ -1859,6 +1983,38 @@ BLOCK_INPUT; +#ifdef USE_GTK + xg_crazy_callback_abort = 1; + if (menubar_widget) + { + /* The third arg is DEEP_P, which says to consider the entire + menu trees we supply, rather than just the menu bar item names. */ + xg_modify_menubar_widgets (menubar_widget, + f, + first_wv, + deep_p, + G_CALLBACK (popup_activate_callback), + G_CALLBACK (menubar_selection_callback), + G_CALLBACK (popup_deactivate_callback), + G_CALLBACK (menu_highlight_callback)); + } + else + { + GtkWidget *wvbox = f->output_data.x->vbox_widget; + + menubar_widget + = xg_create_widget ("menubar", "menubar", f, first_wv, + 0, + G_CALLBACK (popup_activate_callback), + G_CALLBACK (menubar_selection_callback), + G_CALLBACK (popup_deactivate_callback), + G_CALLBACK (menu_highlight_callback)); + + f->output_data.x->menubar_widget = menubar_widget; + } + + +#else /* not USE_GTK */ if (menubar_widget) { /* Disable resizing (done for Motif!) */ @@ -1902,13 +2058,17 @@ } #endif /* USE_LUCID */ #endif /* 0 */ - f->output_data.x->menubar_height = menubar_size; } +#endif /* not USE_GTK */ free_menubar_widget_value_tree (first_wv); update_frame_menubar (f); +#ifdef USE_GTK + xg_crazy_callback_abort = 0; +#endif + UNBLOCK_INPUT; } @@ -1935,6 +2095,9 @@ free_frame_menubar (f) FRAME_PTR f; { +#ifdef USE_GTK + xg_free_frame_menubar (f); +#else /* not USE_GTK */ Widget menubar_widget; menubar_widget = f->output_data.x->menubar_widget; @@ -1976,9 +2139,10 @@ UNBLOCK_INPUT; } +#endif /* not USE_GTK */ } -#endif /* USE_X_TOOLKIT */ +#endif /* USE_X_TOOLKIT || USE_GTK */ /* xmenu_show actually displays a menu using the panes and items in menu_items and returns the value selected from it. @@ -1996,7 +2160,7 @@ ERROR is a place to store an error message string in case of failure. (We return nil on failure, but the value doesn't actually matter.) */ -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* We need a unique id for each widget handled by the Lucid Widget library. @@ -2006,15 +2170,24 @@ For menu bars, we use numbers starting at 0, counted in next_menubar_widget_id. */ +#ifdef USE_X_TOOLKIT LWLIB_ID widget_id_tick; +#endif static Lisp_Object *volatile menu_item_selection; +#ifdef USE_GTK +static void +popup_selection_callback (widget, client_data) + GtkWidget *widget; + gpointer client_data; +#else static void popup_selection_callback (widget, id, client_data) Widget widget; LWLIB_ID id; XtPointer client_data; +#endif { menu_item_selection = (Lisp_Object *) client_data; } @@ -2030,17 +2203,21 @@ char **error; { int i; +#ifdef USE_GTK + GtkWidget *menu; +#else LWLIB_ID menu_id; Widget menu; Arg av[2]; int ac = 0; + XButtonPressedEvent dummy; +#endif widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; widget_value **submenu_stack = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); Lisp_Object *subprefix_stack = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); int submenu_depth = 0; - XButtonPressedEvent dummy; int first_pane; @@ -2233,6 +2410,14 @@ } /* Actually create the menu. */ +#ifdef USE_GTK + menu = xg_create_widget ("popup", first_wv->name, f, first_wv, + 1, + 0, + G_CALLBACK (popup_selection_callback), + G_CALLBACK (popup_deactivate_callback), + G_CALLBACK (menu_highlight_callback)); +#else menu_id = widget_id_tick++; menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, f->output_data.x->widget, 1, 0, @@ -2240,6 +2425,7 @@ popup_deactivate_callback, menu_highlight_callback); +#endif /* Adjust coordinates to relative to the outer (window manager) window. */ { Window child; @@ -2271,6 +2457,30 @@ x += f->output_data.x->left_pos; y += f->output_data.x->top_pos; +#ifdef USE_GTK + for (i = 0; i < 5; i++) + if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) + break; + + /* Free the widget_value objects we used to specify the contents. */ + free_menubar_widget_value_tree (first_wv); + + /* No selection has been chosen yet. */ + menu_item_selection = 0; + + /* Display the menu. */ + gtk_menu_popup (GTK_MENU (menu), 0, 0, 0, 0, i, 0); + + /* Process events that apply to the menu. */ + popup_widget_loop (); + + gtk_widget_destroy (menu); + + /* Must reset this manually because the button release event is not passed + to Emacs event loop. */ + FRAME_X_DISPLAY_INFO (f)->grabbed = 0; + +#else /* not USE_GTK */ dummy.type = ButtonPress; dummy.serial = 0; dummy.send_event = 0; @@ -2311,6 +2521,7 @@ Nowadays the menu disappears ok, all right, but we need to delete the widgets or multiple ones will pile up. */ lw_destroy_all_widgets (menu_id); +#endif /* not USE_GTK */ /* Find the selected item, and its pane, to return the proper value. */ @@ -2370,19 +2581,28 @@ return Qnil; } +#ifdef USE_GTK +static void +dialog_selection_callback (widget, client_data) + GtkWidget *widget; + gpointer client_data; +#else static void dialog_selection_callback (widget, id, client_data) Widget widget; LWLIB_ID id; XtPointer client_data; +#endif { /* The EMACS_INT cast avoids a warning. There's no problem as long as pointers have enough bits to hold small integers. */ if ((int) (EMACS_INT) client_data != -1) menu_item_selection = (Lisp_Object *) client_data; +#ifdef USE_X_TOOLKIT BLOCK_INPUT; lw_destroy_all_widgets (id); UNBLOCK_INPUT; +#endif popup_activated_flag = 0; } @@ -2398,8 +2618,12 @@ char **error; { int i, nb_buttons=0; +#ifdef USE_GTK + GtkWidget *menu; +#else LWLIB_ID dialog_id; Widget menu; +#endif char dialog_name[6]; widget_value *wv, *first_wv = 0, *prev_wv = 0; @@ -2510,11 +2734,19 @@ } /* Actually create the dialog. */ +#ifdef USE_GTK + menu = xg_create_widget ("dialog", first_wv->name, f, first_wv, + 0, 0, + G_CALLBACK (dialog_selection_callback), + G_CALLBACK (popup_deactivate_callback), + 0); +#else dialog_id = widget_id_tick++; menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, f->output_data.x->widget, 1, 0, dialog_selection_callback, 0, 0); lw_modify_all_widgets (dialog_id, first_wv->contents, True); +#endif /* Free the widget_value objects we used to specify the contents. */ free_menubar_widget_value_tree (first_wv); @@ -2522,6 +2754,18 @@ menu_item_selection = 0; /* Display the menu. */ +#ifdef USE_GTK + if (menu) + { + /* Display the menu. */ + gtk_widget_show_all (menu); + + /* Process events that apply to the menu. */ + popup_widget_loop (); + + if (menu_item_selection != 0) gtk_widget_destroy (menu); + } +#else lw_pop_up_all_widgets (dialog_id); popup_activated_flag = 1; @@ -2529,7 +2773,7 @@ popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id); lw_destroy_all_widgets (dialog_id); - +#endif /* Find the selected item, and its pane, to return the proper value. */ if (menu_item_selection != 0) @@ -2576,7 +2820,7 @@ return Qnil; } -#else /* not USE_X_TOOLKIT */ +#else /* not USE_X_TOOLKIT && not USE_GTK */ /* The frame of the last activated non-toolkit menu bar. Used to generate menu help events. */ Index: src/xterm.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/xterm.c,v retrieving revision 1.764 diff -u -I*~ -r1.764 xterm.c --- src/xterm.c 17 Nov 2002 23:49:32 -0000 1.764 +++ src/xterm.c 9 Dec 2002 04:46:00 -0000 @@ -97,17 +97,23 @@ #include #endif +#ifdef USE_GTK +#include "gtkutil.h" +#endif + #ifdef USE_LUCID extern int xlwmenu_window_p P_ ((Widget w, Window window)); extern void xlwmenu_redisplay P_ ((Widget)); #endif -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) extern void free_frame_menubar P_ ((struct frame *)); extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *, int)); +#endif +#ifdef USE_X_TOOLKIT #if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES) #define HACK_EDITRES extern void _XEditResCheckMessages (); @@ -138,7 +144,7 @@ #endif /* USE_X_TOOLKIT */ -#ifndef USE_X_TOOLKIT +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) #define x_any_window_to_frame x_window_to_frame #define x_top_window_to_frame x_window_to_frame #endif @@ -7074,7 +7080,7 @@ struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) if (popup_activated ()) return; #endif @@ -8494,10 +8500,6 @@ int, int, int)); -/* Id of action hook installed for scroll bars. */ - -static XtActionHookId action_hook_id; - /* Lisp window being scrolled. Set when starting to interact with a toolkit scroll bar, reset to nil when ending the interaction. */ @@ -8510,6 +8512,11 @@ /* Whether this is an Xaw with arrow-scrollbars. This should imply that movements of 1/20 of the screen size are mapped to up/down. */ +#ifndef USE_GTK +/* Id of action hook installed for scroll bars. */ + +static XtActionHookId action_hook_id; + static Boolean xaw3d_arrow_scroll; /* Whether the drag scrolling maintains the mouse at the top of the @@ -8562,6 +8569,7 @@ toolkit_scroll_bar_interaction = 0; } } +#endif /* not USE_GTK */ /* A vector of windows used for communication between x_send_scroll_bar_event and x_scroll_bar_to_input_event. */ @@ -8655,7 +8663,11 @@ ievent->kind = SCROLL_BAR_CLICK_EVENT; ievent->frame_or_window = window; ievent->arg = Qnil; +#ifdef USE_GTK + ievent->timestamp = CurrentTime; +#else ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f)); +#endif ievent->part = ev->data.l[1]; ievent->code = ev->data.l[2]; ievent->x = make_number ((int) ev->data.l[3]); @@ -8663,7 +8675,6 @@ ievent->modifiers = 0; } - #ifdef USE_MOTIF /* Minimum and maximum values used for Motif scroll bars. */ @@ -8749,8 +8760,82 @@ } -#else /* !USE_MOTIF, i.e. Xaw. */ +#else /* !USE_MOTIF, i.e. Xaw or GTK */ +#ifdef USE_GTK +/* Scroll bar callback for Gtk scroll bars. WIDGET is the scroll + bar adjustment widget. DATA is a pointer to the scroll_bar structure. */ + +static void +xg_scroll_callback (widget, data) + GtkWidget *widget; + gpointer data; +{ + struct scroll_bar *bar = (struct scroll_bar *) data; + gdouble previous; + gdouble position; + gdouble slider_size; + gdouble *p; + int diff; + + int part = -1, whole = 0, portion = 0; + GtkAdjustment *adj = GTK_ADJUSTMENT (widget); + + if (xg_ignore_gtk_scrollbar) return; + + position = gtk_adjustment_get_value (adj); + slider_size = (adj->upper - adj->lower)/adj->page_size; + + p = g_object_get_data (G_OBJECT (widget), G_LAST_SB_DATA); + if (! p) + { + p = (gdouble*) xmalloc (sizeof (gdouble)); + *p = GTK_SB_MIN; + g_object_set_data (G_OBJECT (widget), G_LAST_SB_DATA, p); + } + + previous = *p; + *p = position; + + diff = (int) (position - previous); + + if (diff == (int) adj->step_increment) + { + part = scroll_bar_down_arrow; + bar->dragging = Qnil; + } + else if (-diff == (int) adj->step_increment) + { + part = scroll_bar_up_arrow; + bar->dragging = Qnil; + } + else if (diff == (int) adj->page_increment) + { + part = scroll_bar_below_handle; + bar->dragging = Qnil; + } + else if (-diff == (int) adj->page_increment) + { + part = scroll_bar_above_handle; + bar->dragging = Qnil; + } + else + { + part = scroll_bar_handle; + whole = GTK_SB_RANGE; + portion = position; + bar->dragging = make_number (portion); + } + + if (part >= 0) + { + xg_ignore_next_thumb = 1; + window_being_scrolled = bar->window; + last_scroll_bar_part = part; + x_send_scroll_bar_event (bar->window, part, portion, whole); + } +} +#else /* not USE_GTK */ /* Xaw scroll bar callback. Invoked when the thumb is dragged. WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the @@ -8833,7 +8918,7 @@ x_send_scroll_bar_event (bar->window, part, position, height); } - +#endif /* not USE_GTK */ #endif /* not USE_MOTIF */ @@ -8845,15 +8930,21 @@ struct frame *f; struct scroll_bar *bar; { +#ifndef USE_GTK Window xwindow; Widget widget; Arg av[20]; int ac = 0; +#endif char *scroll_bar_name = "verticalScrollBar"; unsigned long pixel; BLOCK_INPUT; +#ifdef USE_GTK + xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback), + scroll_bar_name); +#else /* not USE_GTK */ #ifdef USE_MOTIF /* Set resources. Create the widget. */ XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac; @@ -9020,6 +9111,7 @@ xwindow = XtWindow (widget); SET_SCROLL_BAR_X_WINDOW (bar, xwindow); +#endif /* not USE_GTK */ UNBLOCK_INPUT; } @@ -9032,12 +9124,17 @@ struct scroll_bar *bar; int portion, position, whole; { +#ifndef USE_GTK struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); float top, shown; +#endif BLOCK_INPUT; +#ifdef USE_GTK + xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole); +#else #ifdef USE_MOTIF /* We use an estimate of 30 chars per line rather than the real @@ -9146,6 +9243,7 @@ } } #endif /* !USE_MOTIF */ +#endif /* not USE_GTK */ UNBLOCK_INPUT; } @@ -9237,6 +9335,15 @@ /* Map the window/widget. */ #ifdef USE_TOOLKIT_SCROLL_BARS { +#ifdef USE_GTK + xg_update_scrollbar_pos (f, + SCROLL_BAR_X_WINDOW (bar), + top, + left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, + max (height, 1)); + xg_show_scroll_bar (SCROLL_BAR_X_WINDOW (bar)); +#else /* not USE_GTK */ Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); XtConfigureWidget (scroll_bar, left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, @@ -9244,6 +9351,7 @@ width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, max (height, 1), 0); XtMapWidget (scroll_bar); +#endif /* not USE_GTK */ } #else /* not USE_TOOLKIT_SCROLL_BARS */ XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar)); @@ -9378,7 +9486,11 @@ BLOCK_INPUT; #ifdef USE_TOOLKIT_SCROLL_BARS +#ifdef USE_GTK + xg_remove_scroll_bar (f, SCROLL_BAR_X_WINDOW (bar)); +#else /* not USE_GTK */ XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar)); +#endif /* not USE_GTK */ #else XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar)); #endif @@ -9471,6 +9583,17 @@ mask |= CWHeight; #ifdef USE_TOOLKIT_SCROLL_BARS +#ifdef USE_GTK + if (mask) + { + xg_update_scrollbar_pos (f, + SCROLL_BAR_X_WINDOW (bar), + top, + left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, + max (height, 1)); + } +#else /* not USE_GTK */ /* Since toolkit scroll bars are smaller than the space reserved for them on the frame, we have to clear "under" them. */ @@ -9486,6 +9609,7 @@ sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, max (height, 1), 0); +#endif /* not USE_GTK */ #else /* not USE_TOOLKIT_SCROLL_BARS */ /* Clear areas not covered by the scroll bar because of @@ -10107,111 +10231,106 @@ #define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent)) #define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent)) -/* Read events coming from the X server. - This routine is called by the SIGIO handler. - We return as soon as there are no more events to be read. +enum +{ + X_EVENT_NORMAL, + X_EVENT_GOTO_OUT, + X_EVENT_GOTO_OTHER +}; - Events representing keys are stored in buffer BUFP, - which can hold up to NUMCHARS characters. - We return the number of characters stored into the buffer, - thus pretending to be `read'. +#ifdef USE_GTK +static struct x_display_info *current_dpyinfo; +static struct input_event **current_bufp; +static int *current_numcharsp; +static int current_count; +static int current_finish; +static int xg_drop_event; + +static int handle_one_xevent P_ ((struct x_display_info *dpyinfo, + XEvent *eventp, + struct input_event **bufp_r, + int *numcharsp, + int *finish)); + +/* This is the filter function invoked by the GTK event loop. + It is invoked before the XEvent is translated to a GdkEvent, + so we have a chanse to act on the event before GTK. */ +static GdkFilterReturn +event_handler_gdk (gxev, ev, data) + GdkXEvent* gxev; + GdkEvent* ev; + gpointer data; +{ + XEvent *xev = (XEvent*)gxev; + + /* If gtk_pass_through_events is TRUE we want events to go to GTK only. + But Expose is passed to the Emacs loop so redraw is done correctly. + gtk_pass_through_events is set to TRUE by menu popups and dialogs. */ + if (xg_pass_through_events && xev->type != Expose) + return GDK_FILTER_CONTINUE; + + xg_drop_event = 0; + if (current_numcharsp) + { + current_count += handle_one_xevent (current_dpyinfo, + xev, + current_bufp, + current_numcharsp, + ¤t_finish); + } + else + { + struct x_display_info *dpyinfo; + struct input_event bufp[10]; + struct input_event *bufpp = bufp; + int numchars = 10; + + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) + if (dpyinfo->display == GDK_DISPLAY ()) + break; + + if (dpyinfo) + handle_one_xevent (dpyinfo, + xev, + &bufpp, + &numchars, + ¤t_finish); + + /* KOKO: Store emacs events? */ + } + + if (current_finish == X_EVENT_GOTO_OUT || xg_drop_event) + return GDK_FILTER_REMOVE; + + return GDK_FILTER_CONTINUE; + } +#endif /* USE_GTK */ + +/* Handles the XEvent EVENT on display DPYINFO. + + *FINISH is non-zero if caller should stop processing events, + *FINISH is zero if caller should continue reading events. + + Events representing keys are stored in buffer *BUFP_R, + which can hold up to *NUMCHARSP characters. + We return the number of characters stored into the buffer. */ - EXPECTED is nonzero if the caller knows input is available. */ static int -XTread_socket (sd, bufp, numchars, expected) - register int sd; - /* register */ struct input_event *bufp; - /* register */ int numchars; - int expected; -{ +handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) + struct x_display_info *dpyinfo; + XEvent *eventp; + /* register */ struct input_event **bufp_r; + /* register */ int *numcharsp; + int *finish; + { int count = 0; int nbytes = 0; - XEvent event; struct frame *f; - int event_found = 0; - struct x_display_info *dpyinfo; struct coding_system coding; - - if (interrupt_input_blocked) - { - interrupt_input_pending = 1; - return -1; - } - - interrupt_input_pending = 0; - BLOCK_INPUT; - - /* So people can tell when we have read the available input. */ - input_signal_count++; - - if (numchars <= 0) - abort (); /* Don't think this happens. */ - - ++handling_signal; - - /* Find the display we are supposed to read input for. - It's the one communicating on descriptor SD. */ - for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) - { -#if 0 /* This ought to be unnecessary; let's verify it. */ -#ifdef FIOSNBIO - /* If available, Xlib uses FIOSNBIO to make the socket - non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set, - FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK, - a read returns 0, which Xlib interprets as equivalent to EPIPE. */ - fcntl (dpyinfo->connection, F_SETFL, 0); -#endif /* ! defined (FIOSNBIO) */ -#endif - -#if 0 /* This code can't be made to work, with multiple displays, - and appears not to be used on any system any more. - Also keyboard.c doesn't turn O_NDELAY on and off - for X connections. */ -#ifndef SIGIO -#ifndef HAVE_SELECT - if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY)) - { - extern int read_alarm_should_throw; - read_alarm_should_throw = 1; - XPeekEvent (dpyinfo->display, &event); - read_alarm_should_throw = 0; - } -#endif /* HAVE_SELECT */ -#endif /* SIGIO */ -#endif - - /* For debugging, this gives a way to fake an I/O error. */ - if (dpyinfo == XTread_socket_fake_io_error) - { - XTread_socket_fake_io_error = 0; - x_io_error_quitter (dpyinfo->display); - } - -#ifdef HAVE_X_SM - BLOCK_INPUT; - count += x_session_check_input (bufp, &numchars); - UNBLOCK_INPUT; -#endif - - while (XPending (dpyinfo->display)) - { - XNextEvent (dpyinfo->display, &event); - -#ifdef HAVE_X_I18N - { - /* Filter events for the current X input method. - XFilterEvent returns non-zero if the input method has - consumed the event. We pass the frame's X window to - XFilterEvent because that's the one for which the IC - was created. */ - struct frame *f1 = x_any_window_to_frame (dpyinfo, - event.xclient.window); - if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None)) - break; - } -#endif - event_found = 1; + struct input_event *bufp = *bufp_r; + int numchars = *numcharsp; + XEvent event = *eventp; switch (event.type) { @@ -10316,11 +10435,17 @@ bufp->arg = Qnil; bufp++; - count += 1; - numchars -= 1; - } - } - } + + count += 1; + numchars -= 1; +#ifdef USE_GTK + /* Can't pass this to GTK, it will delete + widgets beyond our control. Go figure. */ + xg_drop_event = 1; +#endif + } + } + } else if (event.xclient.message_type == dpyinfo->Xatom_wm_configure_denied) { @@ -10526,12 +10651,15 @@ case GraphicsExpose: /* This occurs when an XCopyArea's source area was obscured or not available. */ - f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable); - if (f) - { - expose_frame (f, - event.xgraphicsexpose.x, event.xgraphicsexpose.y, - event.xgraphicsexpose.width, + f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable); + if (f) + { +#ifdef USE_GTK + xg_drop_event = 1; +#endif + expose_frame (f, + event.xgraphicsexpose.x, event.xgraphicsexpose.y, + event.xgraphicsexpose.width, event.xgraphicsexpose.height); } #ifdef USE_X_TOOLKIT @@ -11186,12 +11314,16 @@ case ConfigureNotify: f = x_top_window_to_frame (dpyinfo, event.xconfigure.window); - if (f) - { + if (f) + { #ifndef USE_X_TOOLKIT - /* If there is a pending resize for fullscreen, don't - do this one, the right one will come later. - The toolkit version doesn't seem to need this, but we +#ifdef USE_GTK + xg_resize_widgets(f, event.xconfigure.width, + event.xconfigure.height); +#else /* not USE_GTK */ + /* If there is a pending resize for fullscreen, don't + do this one, the right one will come later. + The toolkit version doesn't seem to need this, but we need to reset it below. */ int dont_resize = ((f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) @@ -11214,26 +11346,37 @@ || event.xconfigure.height != f->output_data.x->pixel_height) { change_frame_size (f, rows, columns, 0, 1, 0); - SET_FRAME_GARBAGED (f); - cancel_mouse_face (f); - } + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + } +#endif /* not USE_GTK */ #endif - f->output_data.x->pixel_width = event.xconfigure.width; - f->output_data.x->pixel_height = event.xconfigure.height; + f->output_data.x->pixel_width = event.xconfigure.width; + f->output_data.x->pixel_height = event.xconfigure.height; - /* What we have now is the position of Emacs's own window. - Convert that to the position of the window manager window. */ - x_real_positions (f, &f->output_data.x->left_pos, +#ifdef USE_GTK + /* GTK creates windows but doesn't map them. + Only get real positions and check fullscreen when mapped. */ + if (FRAME_GTK_OUTER_WIDGET (f) + && GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f))) + { +#endif + /* What we have now is the position of Emacs's own window. + Convert that to the position of the window manager window. */ + x_real_positions (f, &f->output_data.x->left_pos, &f->output_data.x->top_pos); x_check_fullscreen_move(f); - if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) - f->output_data.x->want_fullscreen &= - ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); + if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) + f->output_data.x->want_fullscreen &= + ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); +#ifdef USE_GTK + } +#endif #ifdef HAVE_X_I18N - if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) - xic_set_statusarea (f); + if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) + xic_set_statusarea (f); #endif if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) @@ -11328,14 +11471,19 @@ numchars--; } -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window); /* For a down-event in the menu bar, don't pass it to Xt right now. Instead, save it away and we will pass it to Xt from kbd_buffer_get_event. That way, we can run some Lisp code first. */ - if (f && event.type == ButtonPress + if ( +#ifdef USE_GTK + ! popup_activated_flag + && +#endif + f && event.type == ButtonPress /* Verify the event is really within the menu bar and not just sent to it due to grabbing. */ && event.xbutton.x >= 0 @@ -11343,12 +11491,15 @@ && event.xbutton.y >= 0 && event.xbutton.y < f->output_data.x->menubar_height && event.xbutton.same_screen) - { - SET_SAVED_BUTTON_EVENT; - XSETFRAME (last_mouse_press_frame, f); - } - else if (event.type == ButtonPress) - { + { + SET_SAVED_BUTTON_EVENT; + XSETFRAME (last_mouse_press_frame, f); +#ifdef USE_GTK + xg_drop_event = 1; +#endif + } + else if (event.type == ButtonPress) + { last_mouse_press_frame = Qnil; goto OTHER; } @@ -11369,7 +11520,7 @@ #endif /* USE_MOTIF */ else goto OTHER; -#endif /* USE_X_TOOLKIT */ +#endif /* USE_X_TOOLKIT || USE_GTK */ } break; @@ -11399,16 +11550,171 @@ OTHER: #ifdef USE_X_TOOLKIT BLOCK_INPUT; - XtDispatchEvent (&event); - UNBLOCK_INPUT; + XtDispatchEvent (&event); + UNBLOCK_INPUT; #endif /* USE_X_TOOLKIT */ - break; - } + *finish = X_EVENT_GOTO_OTHER; + break; + goto ret; + } + + *finish = X_EVENT_NORMAL; + goto ret; + + out: + *finish = X_EVENT_GOTO_OUT; + + ret: + *bufp_r = bufp; + *numcharsp = numchars; + *eventp = event; + + return count; +} + +/* Read events coming from the X server. + This routine is called by the SIGIO handler. + We return as soon as there are no more events to be read. + + Events representing keys are stored in buffer BUFP, + which can hold up to NUMCHARS characters. + We return the number of characters stored into the buffer, + thus pretending to be `read'. + + EXPECTED is nonzero if the caller knows input is available. */ + +static int +XTread_socket (sd, bufp, numchars, expected) + register int sd; + /* register */ struct input_event *bufp; + /* register */ int numchars; + int expected; +{ + int count = 0; + int nbytes = 0; + XEvent event; + int event_found = 0; + struct x_display_info *dpyinfo; + + if (interrupt_input_blocked) + { + interrupt_input_pending = 1; + return -1; + } + + interrupt_input_pending = 0; + BLOCK_INPUT; + + /* So people can tell when we have read the available input. */ + input_signal_count++; + + if (numchars <= 0) + abort (); /* Don't think this happens. */ + + ++handling_signal; + + /* Find the display we are supposed to read input for. + It's the one communicating on descriptor SD. */ + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) + { +#if 0 /* This ought to be unnecessary; let's verify it. */ +#ifdef FIOSNBIO + /* If available, Xlib uses FIOSNBIO to make the socket + non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set, + FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK, + a read returns 0, which Xlib interprets as equivalent to EPIPE. */ + fcntl (dpyinfo->connection, F_SETFL, 0); +#endif /* ! defined (FIOSNBIO) */ +#endif + +#if 0 /* This code can't be made to work, with multiple displays, + and appears not to be used on any system any more. + Also keyboard.c doesn't turn O_NDELAY on and off + for X connections. */ +#ifndef SIGIO +#ifndef HAVE_SELECT + if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY)) + { + extern int read_alarm_should_throw; + read_alarm_should_throw = 1; + XPeekEvent (dpyinfo->display, &event); + read_alarm_should_throw = 0; } +#endif /* HAVE_SELECT */ +#endif /* SIGIO */ +#endif + + /* For debugging, this gives a way to fake an I/O error. */ + if (dpyinfo == XTread_socket_fake_io_error) + { + XTread_socket_fake_io_error = 0; + x_io_error_quitter (dpyinfo->display); + } + +#ifdef HAVE_X_SM + BLOCK_INPUT; + count += x_session_check_input (bufp, &numchars); + UNBLOCK_INPUT; +#endif + +#ifdef USE_GTK + /* For GTK we must use the GTK event loop. But XEvents gets passed + to our filter function above, and then to the big event switch. + We use a bunch of globals to communicate with our filter function, + that is kind of ugly, but it works. */ + current_dpyinfo = dpyinfo; + + while (gtk_events_pending ()) + { + current_count = count; + current_numcharsp = &numchars; + current_bufp = &bufp; + + gtk_main_iteration (); + + count = current_count; + current_bufp = 0; + current_numcharsp = 0; + + if (current_finish == X_EVENT_GOTO_OUT) + goto out; + } + +#else /* not USE_GTK */ + while (XPending (dpyinfo->display)) + { + int finish; + + XNextEvent (dpyinfo->display, &event); + +#ifdef HAVE_X_I18N + { + /* Filter events for the current X input method. + XFilterEvent returns non-zero if the input method has + consumed the event. We pass the frame's X window to + XFilterEvent because that's the one for which the IC + was created. */ + struct frame *f1 = x_any_window_to_frame (dpyinfo, + event.xclient.window); + if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None)) + break; + } +#endif + event_found = 1; + + count += handle_one_xevent (dpyinfo, + &event, + &bufp, + &numchars, + &finish); + + if (finish == X_EVENT_GOTO_OUT) + goto out; + } +#endif /* USE_GTK */ } out:; - /* On some systems, an X bug causes Emacs to get no more events when the window is destroyed. Detect that. (1994.) */ if (! event_found) @@ -12862,11 +13168,7 @@ if (! ((flags & XNegative) || (flags & YNegative))) return; -#ifdef USE_X_TOOLKIT - this_window = XtWindow (f->output_data.x->widget); -#else - this_window = FRAME_X_WINDOW (f); -#endif + this_window = FRAME_OUTER_WINDOW (f); /* Find the position of the outside upper-left corner of the inner window, with respect to the outer window. @@ -12997,13 +13299,8 @@ } #endif -#ifdef USE_X_TOOLKIT - XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget), - modified_left, modified_top); -#else /* not USE_X_TOOLKIT */ - XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), modified_left, modified_top); -#endif /* not USE_X_TOOLKIT */ UNBLOCK_INPUT; } @@ -13189,7 +13486,12 @@ { BLOCK_INPUT; -#ifdef USE_X_TOOLKIT +#ifdef USE_GTK + if (FRAME_GTK_WIDGET (f)) + xg_frame_set_char_size (f, cols, rows); + else + x_set_window_size_1 (f, change_gravity, cols, rows); +#elif USE_X_TOOLKIT if (f->output_data.x->widget != NULL) { @@ -13385,7 +13687,11 @@ /* This was XtPopup, but that did nothing for an iconified frame. */ XtMapWidget (f->output_data.x->widget); #else /* not USE_X_TOOLKIT */ +#ifdef USE_GTK + gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); +#else XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); +#endif /* not USE_GTK */ #endif /* not USE_X_TOOLKIT */ #if 0 /* This seems to bring back scroll bars in the wrong places if the window configuration has changed. They seem @@ -13536,6 +13842,14 @@ by hand again (they have already done that once for this window.) */ x_wm_set_size_hint (f, (long) 0, 1); +#ifdef USE_GTK + if (FRAME_GTK_OUTER_WIDGET (f)) + { + gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f)); + goto out; + } +#endif + #ifdef HAVE_X11R4 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window, @@ -13570,6 +13884,7 @@ XUnmapWindow (FRAME_X_DISPLAY (f), window); #endif /* ! defined (HAVE_X11R4) */ + out: /* We can't distinguish this from iconification just by the event that we get from the server. So we can't win using the usual strategy of letting @@ -13609,6 +13924,22 @@ if (!NILP (type)) x_bitmap_icon (f, type); +#ifdef USE_GTK + if (FRAME_GTK_OUTER_WIDGET (f)) + { + if (! FRAME_VISIBLE_P (f)) + gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f)); + + gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); + f->iconified = 1; + f->visible = 1; + f->async_iconified = 1; + f->async_visible = 0; + UNBLOCK_INPUT; + return; + } +#endif + #ifdef USE_X_TOOLKIT if (! FRAME_VISIBLE_P (f)) @@ -13743,6 +14074,18 @@ free_frame_menubar (f); #else /* !USE_X_TOOLKIT */ + +#ifdef USE_GTK + /* In the GTK version, tooltips are normal X + frames. We must check and free both types. */ + if (FRAME_GTK_OUTER_WIDGET (f)) + { + gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); + FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow below */ + FRAME_GTK_OUTER_WIDGET (f) = 0; + } +#endif /* USE_GTK */ + if (FRAME_X_WINDOW (f)) XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); #endif /* !USE_X_TOOLKIT */ @@ -13836,16 +14179,20 @@ long flags; int user_position; { +#ifdef USE_GTK + /* Must use GTK routines here, otherwise Gtk resets the size hints + to its own defaults. */ + xg_set_wm_size_hints (f, flags, user_position); +#else /* not USE_GTK */ XSizeHints size_hints; #ifdef USE_X_TOOLKIT Arg al[2]; int ac = 0; Dimension widget_width, widget_height; - Window window = XtWindow (f->output_data.x->widget); -#else /* not USE_X_TOOLKIT */ - Window window = FRAME_X_WINDOW (f); -#endif /* not USE_X_TOOLKIT */ +#endif + + Window window = FRAME_OUTER_WINDOW (f); /* Setting PMaxSize caused various problems. */ size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */; @@ -13971,6 +14318,7 @@ #else XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints); #endif +#endif /* not USE_GTK */ } /* Used for IconicState or NormalState */ @@ -14804,6 +15152,28 @@ x_initialized = 1; } +#ifdef USE_GTK + { + int argc = 0; + char *argv[3]; + char **argv2 = argv; + GdkAtom atom; + + /* KOKO, must pass -display and such */ + argv[0] = initial_argv[0]; + argv[1] = argv[2] = 0; + argc = 1; + + gtk_init (&argc, &argv2); + + dpy = GDK_DISPLAY (); + /* NULL window -> events for all windows go to our function */ + gdk_window_add_filter (NULL, event_handler_gdk, NULL); + + XSetErrorHandler (x_error_handler); + XSetIOErrorHandler (x_io_error_quitter); + } +#else /* not USE_GTK */ #ifdef USE_X_TOOLKIT /* address@hidden reports that this causes errors with X11R5: @@ -14844,6 +15214,7 @@ #endif dpy = XOpenDisplay (SDATA (display_name)); #endif /* not USE_X_TOOLKIT */ +#endif /* not USE_GTK*/ /* Detect failure. */ if (dpy == 0) @@ -15303,9 +15674,11 @@ #endif #ifdef USE_TOOLKIT_SCROLL_BARS +#ifndef USE_GTK xaw3d_arrow_scroll = False; xaw3d_pick_top = True; #endif +#endif /* Note that there is no real way portable across R3/R4 to get the original error handler. */ @@ -15385,6 +15758,8 @@ Vx_toolkit_scroll_bars = intern ("motif"); #elif defined HAVE_XAW3D Vx_toolkit_scroll_bars = intern ("xaw3d"); +#elif USE_GTK + Vx_toolkit_scroll_bars = intern ("gtk"); #else Vx_toolkit_scroll_bars = intern ("xaw"); #endif Index: src/xterm.h =================================================================== RCS file: /cvsroot/emacs/emacs/src/xterm.h,v retrieving revision 1.136 diff -u -I*~ -r1.136 xterm.h --- src/xterm.h 30 Aug 2002 12:05:31 -0000 1.136 +++ src/xterm.h 9 Dec 2002 04:46:00 -0000 @@ -35,6 +35,11 @@ #include #endif +#ifdef USE_GTK +#include +#include +#endif + /* The class of this X application. */ #define EMACS_CLASS "Emacs" @@ -348,7 +353,7 @@ extern struct frame *x_window_to_frame P_ ((struct x_display_info *, int)); -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) extern struct frame *x_any_window_to_frame P_ ((struct x_display_info *, int)); extern struct frame *x_non_menubar_window_to_frame P_ ((struct x_display_info *, int)); extern struct frame *x_top_window_to_frame P_ ((struct x_display_info *, int)); @@ -446,6 +451,21 @@ Widget menubar_widget; #endif +#ifdef USE_GTK + /* The widget of this screen. This is the window of a top widget. */ + GtkWidget* widget; + /* The widget of the edit portion of this screen; the window in + "window_desc" is inside of this. */ + GtkWidget* edit_widget; + /* The widget used for laying out widgets vertically. */ + GtkWidget* vbox_widget; + /* The menubar in this frame. */ + GtkWidget* menubar_widget; + /* The last size hints set. */ + GdkGeometry size_hints; + long hint_flags; +#endif + /* If >=0, a bitmap index. The indicated bitmap is used for the icon. */ int icon_bitmap; @@ -619,7 +639,7 @@ enum { /* Values for focus_state, used as bit mask. - EXPLICIT means if we received a FocusIn for the frame and know it has + EXPLICIT means we received a FocusIn for the frame and know it has the focus. IMPLICIT means we recevied an EnterNotify and the frame may have the focus if no window manager is running. FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */ @@ -638,8 +658,22 @@ XtWindow ((f)->output_data.x->widget) : \ FRAME_X_WINDOW (f)) #else +#ifdef USE_GTK +#define GTK_WIDGET_TO_X_WIN(w) \ + ((w) && (w)->window ? GDK_WINDOW_XWINDOW ((w)->window) : 0) + +#define FRAME_GTK_OUTER_WIDGET(f) ((f)->output_data.x->widget) +#define FRAME_GTK_WIDGET(f) ((f)->output_data.x->edit_widget) +#define FRAME_OUTER_WINDOW(f) \ + (FRAME_GTK_OUTER_WIDGET (f) ? \ + GTK_WIDGET_TO_X_WIN (FRAME_GTK_OUTER_WIDGET (f)) : \ + FRAME_X_WINDOW (f)) + +#else /* !USE_GTK */ #define FRAME_OUTER_WINDOW(f) (FRAME_X_WINDOW (f)) +#endif /* !USE_GTK */ #endif + #define FRAME_FONT(f) ((f)->output_data.x->font) #define FRAME_FONTSET(f) ((f)->output_data.x->fontset)