diff src/gtkutil.c @ 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 54482f5ea7be
children a07a0bae1990
line wrap: on
line diff
--- 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;