changeset 53069:1218a42792ea

Implement multiple display handling for GTK.
author Jan Djärv <jan.h.d@swipnet.se>
date Sun, 16 Nov 2003 16:05:24 +0000
parents 6c9f84d07fa3
children 2a9957bfae3f
files src/ChangeLog src/gtkutil.c src/gtkutil.h src/xdisp.c src/xfns.c src/xmenu.c src/xterm.c src/xterm.h
diffstat 8 files changed, 425 insertions(+), 174 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/ChangeLog	Sun Nov 16 16:05:24 2003 +0000
@@ -1,3 +1,55 @@
+2003-11-16  Jan Dj,Ad(Brv  <jan.h.d@swipnet.se>
+
+	* xfns.c (x_window_to_frame, x_any_window_to_frame)
+	(x_non_menubar_window_to_frame, x_menubar_window_to_frame)
+	(x_top_window_to_frame): Add Display* argument to xg_win_to_widget.
+	(x_create_bitmap_mask, xg_set_icon, create_frame_xic)
+	(xic_set_statusarea, x_window, gif_load): Formatting adjustments.
+
+	* xterm.h (struct x_display_info): New field xg_cursor for GTK.
+
+	* xterm.c: Add Display * to x_window_to_scroll_bar declaration.
+	(XTmouse_position, handle_one_xevent): Pass Display* to
+	x_window_to_scroll_bar.
+	(x_window_to_scroll_bar): Take a Display* argument.
+	Check that display for frame is equal to Display* argument.
+	(event_handler_gdk): current_dpyinfo removed.  Get dpyinfo from
+	x_display_info_for_display instead.  Use Display in xev instead
+	of GDK_DISPLAY.
+	(x_dispatch_event): Call x_display_info_for_display.
+	(XTread_socket): Move GTK part out of loop. current_dpyinfo removed.
+	(x_connection_closed): Call xg_display_close for GTK.
+	(x_term_init): Call xg_display_open for additional displays.
+	Initiate dpyinfo->xg_cursor with call to xg_create_default_cursor
+	for GTK.
+
+	* xmenu.c (single_menu_item, mouse_position_for_popup)
+	(x_activate_menubar): Formatting adjustments.
+
+	* xdisp.c (update_tool_bar, redisplay_tool_bar): Formatting
+	adjustments.
+
+	* gtkutil.c (xg_get_gdk_display, xg_set_screen, xg_display_open)
+	(xg_display_close, xg_create_default_cursor)
+	(xg_get_gdk_pixmap_and_mask): New functions for multiple display
+	handling.
+	(xg_left_ptr_cursor): Removed.
+	(xg_set_cursor): cursor changed to GdkCursor*.  Do not create
+	cursor here.
+	(xg_win_to_widget): Take Display* argument, call
+	gdk_xid_table_lookup_for_display.
+	(xg_create_frame_widgets, xg_get_file_name, create_menus)
+	(xg_create_widget, xg_modify_menubar_widgets): Call xg_set_screen.
+	(xg_create_widget, xg_create_scroll_bar): Use xg_cursor
+	in FRAME_X_DISPLAY_INFO.
+	(xg_get_scroll_id_for_window): Take Display* argument.
+	(update_frame_tool_bar): Call xg_get_gdk_pixmap_and_mask.
+	(xg_initialize): xg_left_ptr_cursor removed.
+
+	* gtkutil.h: xg_get_scroll_id_for_window, xg_win_to_widget takes
+	Display* argument also.  Declare xg_display_open,
+	xg_display_close, xg_create_default_cursor.
+
 2003-11-14  Jan Dj,Ad(Brv  <jan.h.d@swipnet.se>
 
 	* xterm.c (x_detect_focus_change): Do not change focus frame for
--- a/src/gtkutil.c	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/gtkutil.c	Sun Nov 16 16:05:24 2003 +0000
@@ -36,9 +36,128 @@
 #include "coding.h"
 #include <gdk/gdkkeysyms.h>
 
+
 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
   (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
 
+
+/***********************************************************************
+                      Display handling functions
+ ***********************************************************************/
+
+#ifdef HAVE_GTK_MULTIDISPLAY
+
+/* Return the GdkDisplay that corresponds to the X display DPY.  */
+static GdkDisplay *
+xg_get_gdk_display (dpy)
+     Display *dpy;
+{
+  return gdk_x11_lookup_xdisplay (dpy);
+}
+
+/* When the GTK widget W is to be created on a display for F that
+   is not the default display, set the display for W.
+   W can be a GtkMenu or a GtkWindow widget.  */
+static void
+xg_set_screen (w, f)
+     GtkWidget *w;
+     FRAME_PTR f;
+{
+  if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ())
+    {
+      GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
+      GdkScreen *gscreen = gdk_display_get_default_screen (gdpy);
+
+      if (GTK_IS_MENU (w))
+        gtk_menu_set_screen (GTK_MENU (w), gscreen);
+      else
+        gtk_window_set_screen (GTK_WINDOW (w), gscreen);
+    }
+}
+
+
+#else /* not HAVE_GTK_MULTIDISPLAY */
+
+/* Make some defines so we can use the GTK 2.2 functions when
+   compiling with GTK 2.0.  */
+#define xg_set_screen(w, f)
+#define gdk_xid_table_lookup_for_display(dpy, w)    gdk_xid_table_lookup (w)
+#define gdk_pixmap_foreign_new_for_display(dpy, p)  gdk_pixmap_foreign_new (p)
+#define gdk_cursor_new_for_display(dpy, c)          gdk_cursor_new (c)
+#define gdk_x11_lookup_xdisplay(dpy)                0
+#define GdkDisplay                                  void
+
+#endif /* not HAVE_GTK_MULTIDISPLAY */
+
+/* Open a display named by DISPLAY_NAME.  The display is returned in *DPY.
+   *DPY is set to NULL if the display can't be opened.
+
+   Returns non-zero if display could be opened, zero if display could not
+   be opened, and less than zero if the GTK version doesn't support
+   multipe displays.  */
+int
+xg_display_open (display_name, dpy)
+     char *display_name;
+     Display **dpy;
+{
+#ifdef HAVE_GTK_MULTIDISPLAY
+  GdkDisplay *gdpy;
+
+  gdpy = gdk_display_open (display_name);
+  *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
+
+  return gdpy != NULL;
+
+#else /* not HAVE_GTK_MULTIDISPLAY */
+
+  return -1;
+#endif /* not HAVE_GTK_MULTIDISPLAY */
+}
+
+
+void
+xg_display_close (Display *dpy)
+{
+#ifdef HAVE_GTK_MULTIDISPLAY
+  GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
+
+  /* GTK 2.2 has a bug that makes gdk_display_close crash (bug
+     http://bugzilla.gnome.org/show_bug.cgi?id=85715).  This way
+     we can continue running, but there will be memory leaks.  */
+
+#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4
+
+  /* If this is the default display, we must change it before calling
+     dispose, otherwise it will crash.  */
+  if (gdk_display_get_default () == gdpy)
+    {
+      struct x_display_info *dpyinfo;
+      Display *new_dpy = 0;
+      GdkDisplay *gdpy_new;
+
+      /* Find another display.  */
+      for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
+        if (dpyinfo->display != dpy)
+          {
+            new_dpy = dpyinfo->display;
+            break;
+          }
+
+      if (! new_dpy) return; /* Emacs will exit anyway.  */
+
+      gdpy_new = gdk_x11_lookup_xdisplay (new_dpy);
+      gdk_display_manager_set_default_display (gdk_display_manager_get (),
+                                               gdpy_new);
+    }
+
+  g_object_run_dispose (G_OBJECT (gdpy));
+
+#else
+  /* I hope this will be fixed in GTK 2.4.  It is what bug 85715 says.  */
+  gdk_display_close (gdpy);
+#endif
+#endif /* HAVE_GTK_MULTIDISPLAY */
+}
 
 
 /***********************************************************************
@@ -48,10 +167,6 @@
    NULL if no timer is started.  */
 static struct atimer *xg_timer;
 
-/* The cursor used for scroll bars and popup menus.
-   We only have one cursor for all scroll bars and all popup menus.  */
-static GdkCursor *xg_left_ptr_cursor;
-
 
 /* The next two variables and functions are taken from lwlib.  */
 static widget_value *widget_value_free_list;
@@ -103,24 +218,48 @@
     }
 }
 
-/* Set *CURSOR on W and all widgets W contain.  We must do like this
+
+/* Create and return the cursor to be used for popup menus and
+   scroll bars on display DPY.  */
+GdkCursor *
+xg_create_default_cursor (dpy)
+     Display *dpy;
+{
+  GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
+  return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR);
+}
+
+/* For the image defined in IMG, make and return a GdkPixmap for
+   the pixmap in *GPIX, and a GdkBitmap for the mask in *GMASK.
+   If IMG has no mask, *GMASK is set to NULL.
+   The image is defined on the display where frame F is.  */
+static void
+xg_get_gdk_pixmap_and_mask (f, img, gpix, gmask)
+     FRAME_PTR f;
+     struct image *img;
+     GdkPixmap **gpix;
+     GdkBitmap **gmask;
+{
+  GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
+
+  *gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap);
+  *gmask = img->mask ?
+    (GdkBitmap*) gdk_pixmap_foreign_new_for_display (gdpy, img->mask)
+    : 0;
+}
+
+
+/* Set CURSOR on W and all widgets W contain.  We must do like this
    for scroll bars and menu because they create widgets internally,
-   and it is those widgets that are visible.
-
-   If *CURSOR is NULL, create a GDK_LEFT_PTR cursor and set *CURSOR to
-   the created cursor.  */
-void
+   and it is those widgets that are visible.  */
+static void
 xg_set_cursor (w, cursor)
      GtkWidget *w;
-     GdkCursor **cursor;
+     GdkCursor *cursor;
 {
   GList *children = gdk_window_peek_children (w->window);
 
-  /* Create the cursor unless already created.  */
-  if (! *cursor)
-    *cursor = gdk_cursor_new (GDK_LEFT_PTR);
-
-  gdk_window_set_cursor (w->window, *cursor);
+  gdk_window_set_cursor (w->window, cursor);
 
   /* The scroll bar widget has more than one GDK window (had to look at
      the source to figure this out), and there is no way to set cursor
@@ -128,7 +267,7 @@
      Ditto for menus.  */
 
   for ( ; children; children = g_list_next (children))
-    gdk_window_set_cursor (GDK_WINDOW (children->data), *cursor);
+    gdk_window_set_cursor (GDK_WINDOW (children->data), cursor);
 }
 
 /*  Timer function called when a timeout occurs for xg_timer.
@@ -381,20 +520,23 @@
   cancel_mouse_face (f);
 }
 
-/* Convert an X Window WSESC to its corresponding GtkWidget.
+/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget.
    Must be done like this, because GtkWidget:s can have "hidden"
    X Window that aren't accessible.
 
    Return 0 if no widget match WDESC.  */
 GtkWidget *
-xg_win_to_widget (wdesc)
+xg_win_to_widget (dpy, wdesc)
+     Display *dpy;
      Window wdesc;
 {
   gpointer gdkwin;
   GtkWidget *gwdesc = 0;
 
   BLOCK_INPUT;
-  gdkwin = gdk_xid_table_lookup (wdesc);
+
+  gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy),
+                                             wdesc);
   if (gdkwin)
     {
       GdkEvent event;
@@ -429,9 +571,9 @@
    Return TRUE to tell GTK that this expose event has been fully handeled
    and that GTK shall do nothing more with it.  */
 static gboolean
-xg_fixed_handle_expose(GtkWidget *widget,
-                       GdkEventExpose *event,
-                       gpointer user_data)
+xg_fixed_handle_expose (GtkWidget *widget,
+                        GdkEventExpose *event,
+                        gpointer user_data)
 {
   GList *iter;
 
@@ -483,6 +625,8 @@
   BLOCK_INPUT;
 
   wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  xg_set_screen (wtop, f);
+
   wvbox = gtk_vbox_new (FALSE, 0);
   wfixed = gtk_fixed_new ();  /* Must have this to place scroll bars  */
 
@@ -512,7 +656,8 @@
 
   gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE);
 
-  gtk_widget_set_size_request (wfixed, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
+  gtk_widget_set_size_request (wfixed, FRAME_PIXEL_WIDTH (f),
+                               FRAME_PIXEL_HEIGHT (f));
 
   gtk_container_add (GTK_CONTAINER (wtop), wvbox);
   gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0);
@@ -963,6 +1108,8 @@
   filewin = gtk_file_selection_new (prompt);
   filesel = GTK_FILE_SELECTION (filewin);
 
+  xg_set_screen (filewin, f);
+
   gtk_widget_set_name (filewin, "emacs-filedialog");
 
   gtk_window_set_transient_for (GTK_WINDOW (filewin),
@@ -1500,7 +1647,11 @@
 
   if (! topmenu)
     {
-      if (! menu_bar_p) wmenu = gtk_menu_new ();
+      if (! menu_bar_p)
+      {
+        wmenu = gtk_menu_new ();
+        xg_set_screen (wmenu, f);
+      }
       else wmenu = gtk_menu_bar_new ();
 
       /* Put cl_data on the top menu for easier access.  */
@@ -1618,12 +1769,11 @@
   if (strcmp (type, "dialog") == 0)
     {
       w = create_dialog (val, select_cb, deactivate_cb);
+      xg_set_screen (w, f);
       gtk_window_set_transient_for (GTK_WINDOW (w),
                                     GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
       gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE);
-
-      if (w)
-        gtk_widget_set_name (w, "emacs-dialog");
+      gtk_widget_set_name (w, "emacs-dialog");
     }
   else if (menu_bar_p || pop_up_p)
     {
@@ -1645,7 +1795,7 @@
         {
           /* Must realize so the GdkWindow inside the widget is created.  */
           gtk_widget_realize (w);
-          xg_set_cursor (w, &xg_left_ptr_cursor);
+          xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
         }
     }
   else
@@ -2261,7 +2411,10 @@
              a new menu bar item, it has no sub menu yet.  So we set the
              newly created sub menu under witem.  */
           if (newsub != sub)
-            gtk_menu_item_set_submenu (witem, newsub);
+            {
+              xg_set_screen (newsub, f);
+              gtk_menu_item_set_submenu (witem, newsub);
+            }
         }
     }
 
@@ -2417,16 +2570,17 @@
   return 0;
 }
 
-/* Return the scrollbar id for X Window WID.
+/* Return the scrollbar id for X Window WID on display DPY.
    Return -1 if WID not in id_to_widget.  */
 int
-xg_get_scroll_id_for_window (wid)
+xg_get_scroll_id_for_window (dpy, wid)
+     Display *dpy;
      Window wid;
 {
   int idx;
   GtkWidget *w;
 
-  w = xg_win_to_widget (wid);
+  w = xg_win_to_widget (dpy, wid);
 
   if (w)
     {
@@ -2533,7 +2687,7 @@
                  wscroll, -1, -1);
 
   /* Set the cursor to an arrow.  */
-  xg_set_cursor (wscroll, &xg_left_ptr_cursor);
+  xg_set_cursor (wscroll, FRAME_X_DISPLAY_INFO (f)->xg_cursor);
 
   SET_SCROLL_BAR_X_WINDOW (bar, scroll_id);
 }
@@ -2952,8 +3106,8 @@
   event->area.x -= width > event->area.width ? width-event->area.width : 0;
   event->area.y -= height > event->area.height ? height-event->area.height : 0;
 
-  event->area.x = max(0, event->area.x);
-  event->area.y = max(0, event->area.y);
+  event->area.x = max (0, event->area.x);
+  event->area.y = max (0, event->area.y);
   
   event->area.width = max (width, event->area.width);
   event->area.height = max (height, event->area.height);
@@ -2975,7 +3129,7 @@
      GdkEventExpose *event;
      gpointer client_data;
 {
-  update_frame_tool_bar((FRAME_PTR)client_data);
+  update_frame_tool_bar ((FRAME_PTR) client_data);
   return FALSE;
 }
 
@@ -3108,11 +3262,12 @@
 
       if (! wicon)
         {
-          GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap);
-          GdkBitmap *gmask = img->mask ?
-            (GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0;
-
-          GtkWidget *w = gtk_image_new_from_pixmap (gpix, gmask);
+          GdkPixmap *gpix;
+          GdkBitmap *gmask;
+          GtkWidget *w;
+
+          xg_get_gdk_pixmap_and_mask (f, img, &gpix, &gmask);
+          w = gtk_image_new_from_pixmap (gpix, gmask);
           gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget),
                                    0, 0, 0,
                                    w,
@@ -3170,10 +3325,10 @@
 
           if (old_img != img->pixmap)
             {
-              GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap);
-              GdkBitmap *gmask = img->mask ?
-                (GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0;
-
+              GdkPixmap *gpix;
+              GdkBitmap *gmask;
+
+              xg_get_gdk_pixmap_and_mask (f, img, &gpix, &gmask);
               gtk_image_set_from_pixmap (wimage, gpix, gmask);
             }
 
@@ -3241,7 +3396,6 @@
 xg_initialize ()
 {
   xg_ignore_gtk_scrollbar = 0;
-  xg_left_ptr_cursor = 0;
   xg_detached_menus = 0;
   xg_menu_cb_list.prev = xg_menu_cb_list.next =
     xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0;
--- a/src/gtkutil.h	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/gtkutil.h	Sun Nov 16 16:05:24 2003 +0000
@@ -152,7 +152,7 @@
 
 extern int xg_have_tear_offs P_ ((void));
 
-extern int xg_get_scroll_id_for_window P_ ((Window wid));
+extern int xg_get_scroll_id_for_window P_ ((Display *dpy, Window wid));
 
 extern void xg_create_scroll_bar P_ ((FRAME_PTR f,
                                       struct scroll_bar *bar,
@@ -184,7 +184,12 @@
                                    int pixelheight));
 extern void xg_frame_cleared P_ ((FRAME_PTR f));
 extern void xg_frame_set_char_size P_ ((FRAME_PTR f, int cols, int rows));
-extern GtkWidget * xg_win_to_widget P_ ((Window));
+extern GtkWidget * xg_win_to_widget P_ ((Display *dpy, Window wdesc));
+
+extern int xg_display_open P_ ((char *display_name, Display **dpy));
+extern void xg_display_close P_ ((Display *dpy));
+extern GdkCursor * xg_create_default_cursor P_ ((Display *dpy));
+
 extern int xg_create_frame_widgets P_ ((FRAME_PTR f));
 extern void x_wm_set_size_hint P_ ((FRAME_PTR f,
                                     long flags,
--- a/src/xdisp.c	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/xdisp.c	Sun Nov 16 16:05:24 2003 +0000
@@ -8142,7 +8142,7 @@
      int save_match_data;
 {
 #ifdef USE_GTK
-  int do_update = FRAME_EXTERNAL_TOOL_BAR(f);
+  int do_update = FRAME_EXTERNAL_TOOL_BAR (f);
 #else
   int do_update = WINDOWP (f->tool_bar_window)
     && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
@@ -8539,7 +8539,7 @@
   int change_height_p = 0;
 
 #ifdef USE_GTK
-  if (FRAME_EXTERNAL_TOOL_BAR(f))
+  if (FRAME_EXTERNAL_TOOL_BAR (f))
     update_frame_tool_bar (f);
   return 0;
 #endif
--- a/src/xfns.c	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/xfns.c	Sun Nov 16 16:05:24 2003 +0000
@@ -308,7 +308,7 @@
 #ifdef USE_GTK
       if (f->output_data.x->edit_widget)
       {
-        GtkWidget *gwdesc = xg_win_to_widget (wdesc);
+        GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
         struct x_output *x = f->output_data.x;
         if (gwdesc != 0 && gwdesc == x->edit_widget)
           return f;
@@ -352,7 +352,7 @@
 	  else if (x->widget)
 	    {
 #ifdef USE_GTK
-              GtkWidget *gwdesc = xg_win_to_widget (wdesc);
+              GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
               if (gwdesc != 0
                   && (gwdesc == x->widget
                       || gwdesc == x->edit_widget
@@ -404,7 +404,7 @@
       else if (x->widget)
 	{
 #ifdef USE_GTK
-          GtkWidget *gwdesc = xg_win_to_widget (wdesc);
+          GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
           if (gwdesc != 0
               && (gwdesc == x->widget
                   || gwdesc == x->edit_widget
@@ -448,7 +448,7 @@
 #ifdef USE_GTK
       if (x->menubar_widget)
         {
-          GtkWidget *gwdesc = xg_win_to_widget (wdesc);
+          GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
           int found = 0;
 
           BLOCK_INPUT;
@@ -494,7 +494,7 @@
 	{
 	  /* This frame matches if the window is its topmost widget.  */
 #ifdef USE_GTK
-          GtkWidget *gwdesc = xg_win_to_widget (wdesc);
+          GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
           if (gwdesc == x->widget)
             return f;
 #else
@@ -762,7 +762,7 @@
    It's nicer with some borders in this context */
 
 int
-x_create_bitmap_mask(f, id)
+x_create_bitmap_mask (f, id)
      struct frame *f;
      int id;
 {
@@ -780,9 +780,9 @@
   if (!(id > 0))
     return -1;
 
-  pixmap = x_bitmap_pixmap(f, id);
-  width = x_bitmap_width(f, id);
-  height = x_bitmap_height(f, id);
+  pixmap = x_bitmap_pixmap (f, id);
+  width = x_bitmap_width (f, id);
+  height = x_bitmap_height (f, id);
 
   BLOCK_INPUT;
   ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
@@ -799,7 +799,7 @@
   UNBLOCK_INPUT;
   if (!result)
     {
-      XDestroyImage(ximg);
+      XDestroyImage (ximg);
       return -1;
     }
 
@@ -838,7 +838,7 @@
   dpyinfo->bitmaps[id - 1].mask = mask;
 
   XDestroyImage (ximg);
-  x_destroy_x_image(mask_img);
+  x_destroy_x_image (mask_img);
 
   return 0;
 }
@@ -1106,7 +1106,7 @@
    may be any format that GdkPixbuf knows about, i.e. not just bitmaps.  */
 
 int
-xg_set_icon(f, file)
+xg_set_icon (f, file)
     FRAME_PTR f;
     Lisp_Object file;
 {
@@ -2458,8 +2458,8 @@
 
       xic = XCreateIC (xim,
 		       XNInputStyle, xic_style,
-		       XNClientWindow, FRAME_X_WINDOW(f),
-		       XNFocusWindow, FRAME_X_WINDOW(f),
+		       XNClientWindow, FRAME_X_WINDOW (f),
+		       XNFocusWindow, FRAME_X_WINDOW (f),
 		       XNStatusAttributes, status_attr,
 		       XNPreeditAttributes, preedit_attr,
 		       NULL);
@@ -2550,7 +2550,7 @@
   XFree (needed);
 
   attr = XVaCreateNestedList (0, XNArea, &area, NULL);
-  XSetICValues(xic, XNStatusAttributes, attr, NULL);
+  XSetICValues (xic, XNStatusAttributes, attr, NULL);
   XFree (attr);
 }
 
@@ -2793,7 +2793,7 @@
     {
       /* XIM server might require some X events. */
       unsigned long fevent = NoEventMask;
-      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      XGetICValues (FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
       attributes.event_mask |= fevent;
     }
 #endif /* HAVE_X_I18N */
@@ -2847,7 +2847,7 @@
       {
 	/* XIM server might require some X events. */
 	unsigned long fevent = NoEventMask;
-	XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+	XGetICValues (FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
 
 	if (fevent != NoEventMask)
 	  {
@@ -2911,7 +2911,7 @@
 	{
 	  /* XIM server might require some X events. */
 	  unsigned long fevent = NoEventMask;
-	  XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+	  XGetICValues (FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
 	  attributes.event_mask |= fevent;
 	  attribute_mask = CWEventMask;
 	  XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
@@ -9166,7 +9166,7 @@
       memsrc.len = SBYTES (specified_data);
       memsrc.index = 0;
 
-      gif = DGifOpen(&memsrc, gif_read_from_memory);
+      gif = DGifOpen (&memsrc, gif_read_from_memory);
       if (!gif)
 	{
 	  image_error ("Cannot open memory source `%s'", img->spec, Qnil);
--- a/src/xmenu.c	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/xmenu.c	Sun Nov 16 16:05:24 2003 +0000
@@ -610,7 +610,7 @@
 #endif /* not HAVE_BOXES */
 
 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
-  if (!NILP(map))
+  if (!NILP (map))
     /* Indicate visually that this is a submenu.  */
     item_string = concat2 (item_string, build_string (" >"));
 #endif
@@ -696,7 +696,7 @@
    the scroll bar or the edit window.  Fx_popup_menu needs to be
    sure it is the edit window.  */
 static void
-mouse_position_for_popup(f, x, y)
+mouse_position_for_popup (f, x, y)
      FRAME_PTR f;
      int *x;
      int *y;
@@ -1217,7 +1217,8 @@
     return;
 
 #ifdef USE_GTK
-  if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window))
+  if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
+                          f->output_data.x->saved_menu_event->xany.window))
     return;
 #endif
 
--- a/src/xterm.c	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/xterm.c	Sun Nov 16 16:05:24 2003 +0000
@@ -357,7 +357,7 @@
 static void x_update_begin P_ ((struct frame *));
 static void x_update_window_begin P_ ((struct window *));
 static void x_after_update_window_line P_ ((struct glyph_row *));
-static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
+static struct scroll_bar *x_window_to_scroll_bar P_ ((Display *, Window));
 static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
 					    enum scroll_bar_part *,
 					    Lisp_Object *, Lisp_Object *,
@@ -3777,7 +3777,9 @@
 	/* If not, is it one of our scroll bars?  */
 	if (! f1)
 	  {
-	    struct scroll_bar *bar = x_window_to_scroll_bar (win);
+	    struct scroll_bar *bar;
+
+            bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win);
 
 	    if (bar)
 	      {
@@ -3848,18 +3850,20 @@
 
 /* Scroll bar support.  */
 
-/* Given an X window ID, find the struct scroll_bar which manages it.
+/* Given an X window ID and a DISPLAY, find the struct scroll_bar which
+   manages it.
    This can be called in GC, so we have to make sure to strip off mark
    bits.  */
 
 static struct scroll_bar *
-x_window_to_scroll_bar (window_id)
+x_window_to_scroll_bar (display, window_id)
+     Display *display;
      Window window_id;
 {
   Lisp_Object tail;
 
 #ifdef USE_GTK
-  window_id = (Window) xg_get_scroll_id_for_window (window_id);
+  window_id = (Window) xg_get_scroll_id_for_window (display, window_id);
 #endif /* USE_GTK */
 
   for (tail = Vframe_list;
@@ -3873,6 +3877,9 @@
       if (! GC_FRAMEP (frame))
 	abort ();
 
+      if (FRAME_X_DISPLAY (XFRAME (frame)) != display)
+        continue;
+
       /* Scan this frame's scroll bar list for a scroll bar with the
          right window ID.  */
       condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
@@ -5669,7 +5676,6 @@
 #endif
 
 #ifdef USE_GTK
-static struct x_display_info *current_dpyinfo;
 static struct input_event **current_bufp;
 static int *current_numcharsp;
 static int current_count;
@@ -5684,26 +5690,34 @@
      GdkEvent *ev;
      gpointer data;
 {
-  XEvent *xev = (XEvent*)gxev;
+  XEvent *xev = (XEvent *) gxev;
 
   if (current_numcharsp)
     {
+      struct x_display_info *dpyinfo;
+
+      dpyinfo = x_display_info_for_display (xev->xany.display);
+
 #ifdef HAVE_X_I18N
       /* Filter events for the current X input method.
          GTK calls XFilterEvent but not for key press and release,
          so we do it here.  */
       if (xev->type == KeyPress || xev->type == KeyRelease)
-        if (x_filter_event (current_dpyinfo, xev))
+        if (dpyinfo && x_filter_event (dpyinfo, xev))
           return GDK_FILTER_REMOVE;
 #endif
-      current_count += handle_one_xevent (current_dpyinfo,
-                                          xev,
-                                          current_bufp,
-                                          current_numcharsp,
-                                          &current_finish);
+
+      if (! dpyinfo)
+        current_finish = X_EVENT_NORMAL;
+      else
+        current_count += handle_one_xevent (dpyinfo,
+                                            xev,
+                                            current_bufp,
+                                            current_numcharsp,
+                                            &current_finish);
     }
   else
-    current_finish = x_dispatch_event (xev, GDK_DISPLAY ());
+    current_finish = x_dispatch_event (xev, xev->xany.display);
 
   if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
     return GDK_FILTER_REMOVE;
@@ -6043,7 +6057,8 @@
           /* Dispatch event to the widget.  */
           goto OTHER;
 #else /* not USE_TOOLKIT_SCROLL_BARS */
-          bar = x_window_to_scroll_bar (event.xexpose.window);
+          bar = x_window_to_scroll_bar (event.xexpose.display,
+                                        event.xexpose.window);
 
           if (bar)
             x_scroll_bar_expose (bar, &event);
@@ -6669,7 +6684,7 @@
                 /* Window will be selected only when it is not selected now and
                    last mouse movement event was not in it.  Minibuffer window
                    will be selected iff it is active.  */
-                if (WINDOWP(window)
+                if (WINDOWP (window)
                     && !EQ (window, last_window)
                     && !EQ (window, selected_window)
                     && numchars > 0)
@@ -6688,7 +6703,8 @@
           {
 #ifndef USE_TOOLKIT_SCROLL_BARS
             struct scroll_bar *bar
-              = x_window_to_scroll_bar (event.xmotion.window);
+              = x_window_to_scroll_bar (event.xmotion.display,
+                                        event.xmotion.window);
 
             if (bar)
               x_scroll_bar_note_movement (bar, &event);
@@ -6851,7 +6867,8 @@
         else
           {
             struct scroll_bar *bar
-              = x_window_to_scroll_bar (event.xbutton.window);
+              = x_window_to_scroll_bar (event.xbutton.display,
+                                        event.xbutton.window);
 
 #ifdef USE_TOOLKIT_SCROLL_BARS
             /* Make the "Ctrl-Mouse-2 splits window" work for toolkit
@@ -7012,9 +7029,7 @@
     EVENT_INIT (*bufpp);
   bufpp = bufp;
 
-  for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
-    if (dpyinfo->display == display)
-      break;
+  dpyinfo = x_display_info_for_display (display);
 
   if (dpyinfo)
     {
@@ -7116,30 +7131,7 @@
       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 */
+#ifndef USE_GTK
       while (XPending (dpyinfo->display))
 	{
           int finish;
@@ -7162,8 +7154,35 @@
           if (finish == X_EVENT_GOTO_OUT)
             goto out;
         }
+#endif /* not USE_GTK */
+    }
+
+#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.
+
+     There is no way to do one display at the time, GTK just does events
+     from all displays.  */
+
+  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)
+        break;
+    }
 #endif /* USE_GTK */
-    }
 
  out:;
 
@@ -7482,13 +7501,13 @@
   if (STRINGP (file))
     {
 #ifdef USE_GTK
-      /* Use gtk_window_set_icon_from_file() if available,
+      /* Use gtk_window_set_icon_from_file () if available,
 	 It's not restricted to bitmaps */
-      if (xg_set_icon(f, file))
+      if (xg_set_icon (f, file))
 	return 0;
 #endif /* USE_GTK */
       bitmap_id = x_create_bitmap_from_file (f, file);
-      x_create_bitmap_mask(f, bitmap_id);
+      x_create_bitmap_mask (f, bitmap_id);
     }
   else
     {
@@ -7498,7 +7517,7 @@
 	  FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
 	    = x_create_bitmap_from_data (f, gnu_bits,
 					 gnu_width, gnu_height);
-	  x_create_bitmap_mask(f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
+	  x_create_bitmap_mask (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
 	}
 
       /* The first time we create the GNU bitmap and mask,
@@ -7767,6 +7786,11 @@
     }
 #endif
 
+#ifdef USE_GTK
+  if (dpyinfo)
+    xg_display_close (dpyinfo->display);
+#endif
+
   /* Indicate that this display is dead.  */
   if (dpyinfo)
     dpyinfo->display = 0;
@@ -10211,60 +10235,65 @@
     char **argv2 = argv;
     GdkAtom atom;
 
-    /* GTK 2.0 can only handle one display, GTK 2.2 can handle more
-       than one, but this remains to be implemented.  */
-    if (x_initialized > 1)
-      error ("Sorry, the GTK port can only handle one display.");
-    ++x_initialized;
-
-    for (argc = 0; argc < NUM_ARGV; ++argc)
-      argv[argc] = 0;
-
-    argc = 0;
-    argv[argc++] = initial_argv[0];
-
-    if (! NILP (display_name))
+    if (x_initialized++ > 1)
+      {
+        /* Opening another display.  If xg_display_open returns less
+           than zero, we are probably on GTK 2.0, which can only handle
+           one display.  GTK 2.2 or later can handle more than one.  */
+        if (xg_display_open (SDATA (display_name), &dpy) < 0)
+          error ("Sorry, this version of GTK can only handle one display");
+     }
+    else
       {
-        argv[argc++] = "--display";
-        argv[argc++] = SDATA (display_name);
-      }
-
-    argv[argc++] = "--name";
-    argv[argc++] = resource_name;
+        for (argc = 0; argc < NUM_ARGV; ++argc)
+          argv[argc] = 0;
+
+        argc = 0;
+        argv[argc++] = initial_argv[0];
+
+        if (! NILP (display_name))
+          {
+            argv[argc++] = "--display";
+            argv[argc++] = SDATA (display_name);
+          }
+
+        argv[argc++] = "--name";
+        argv[argc++] = resource_name;
 
 #ifdef HAVE_X11R5
-    XSetLocaleModifiers ("");
-#endif
-
-    gtk_init (&argc, &argv2);
-
-    /* gtk_init does set_locale.  We must fix locale after calling it.  */
-    fixup_locale ();
-    xg_initialize ();
-
-    dpy = GDK_DISPLAY ();
-
-    /* NULL window -> events for all windows go to our function */
-    gdk_window_add_filter (NULL, event_handler_gdk, NULL);
-
-    /* Load our own gtkrc if it exists.  */
-    {
-      struct gcpro gcpro1, gcpro2;
-      char *file = "~/.emacs.d/gtkrc";
-      Lisp_Object s, abs_file;
-
-      GCPRO2 (s, abs_file);
-      s = make_string (file, strlen (file));
-      abs_file = Fexpand_file_name(s, Qnil);
-
-      if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
-        gtk_rc_parse (SDATA (abs_file));
-
-      UNGCPRO;
-    }
-
-    XSetErrorHandler (x_error_handler);
-    XSetIOErrorHandler (x_io_error_quitter);
+        XSetLocaleModifiers ("");
+#endif
+
+        gtk_init (&argc, &argv2);
+
+        /* gtk_init does set_locale.  We must fix locale after calling it.  */
+        fixup_locale ();
+        xg_initialize ();
+
+        dpy = GDK_DISPLAY ();
+
+        /* NULL window -> events for all windows go to our function */
+        gdk_window_add_filter (NULL, event_handler_gdk, NULL);
+
+        /* Load our own gtkrc if it exists.  */
+        {
+          struct gcpro gcpro1, gcpro2;
+          char *file = "~/.emacs.d/gtkrc";
+          Lisp_Object s, abs_file;
+
+          GCPRO2 (s, abs_file);
+          s = make_string (file, strlen (file));
+          abs_file = Fexpand_file_name (s, Qnil);
+
+          if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
+            gtk_rc_parse (SDATA (abs_file));
+
+          UNGCPRO;
+        }
+
+        XSetErrorHandler (x_error_handler);
+        XSetIOErrorHandler (x_io_error_quitter);
+      }
   }
 #else /* not USE_GTK */
 #ifdef USE_X_TOOLKIT
@@ -10385,6 +10414,11 @@
   x_find_modifier_meanings (dpyinfo);
 
   /* Get the scroll bar cursor.  */
+#ifdef USE_GTK
+  /* We must create a GTK cursor, it is required for GTK widgets.  */
+  dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display);
+#endif /* USE_GTK */
+
   dpyinfo->vertical_scroll_bar_cursor
     = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
 
--- a/src/xterm.h	Sun Nov 16 14:08:34 2003 +0000
+++ b/src/xterm.h	Sun Nov 16 16:05:24 2003 +0000
@@ -189,6 +189,11 @@
   /* The cursor to use for vertical scroll bars.  */
   Cursor vertical_scroll_bar_cursor;
 
+#ifdef USE_GTK
+  /* The GDK cursor for scroll bars and popup menus.  */
+  GdkCursor *xg_cursor;
+#endif
+
   /* X Resource data base */
   XrmDatabase xrdb;