Mercurial > emacs
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;