X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a8303f92b3155190cfda1061808925bb5e15e7e9..f303762dc1885b861fe9e9a9a6a5ec618c23ef31:/src/gtkutil.c diff --git a/src/gtkutil.c b/src/gtkutil.c index 3bbac91bc4..84aa9f46d4 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -31,10 +31,134 @@ Boston, MA 02111-1307, USA. */ #include "atimer.h" #include "gtkutil.h" #include "termhooks.h" +#include "keyboard.h" +#include "charset.h" +#include "coding.h" #include + #define FRAME_TOTAL_PIXEL_HEIGHT(f) \ - (PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_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 */ +} + /*********************************************************************** Utility functions @@ -43,10 +167,6 @@ Boston, MA 02111-1307, USA. */ 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; @@ -98,24 +218,125 @@ free_widget_value (wv) } } -/* 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 +/* 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 GtkImage. For displays with + 8 planes or less we must make a GdkPixbuf and apply the mask manually. + Otherwise the highlightning and dimming the tool bar code in GTK does + will look bad. For display with more than 8 planes we just use the + pixmap and mask directly. For monochrome displays, GTK doesn't seem + able to use external pixmaps, it looks bad whatever we do. + The image is defined on the display where frame F is. + WIDGET is used to find the GdkColormap to use for the GdkPixbuf. + If OLD_WIDGET is NULL, a new widget is constructed and returned. + If OLD_WIDGET is not NULL, that widget is modified. */ +static GtkWidget * +xg_get_image_for_pixmap (f, img, widget, old_widget) + FRAME_PTR f; + struct image *img; + GtkWidget *widget; + GtkImage *old_widget; +{ + GdkPixmap *gpix; + GdkPixmap *gmask; + GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); + + gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap); + gmask = img->mask ? gdk_pixmap_foreign_new_for_display (gdpy, img->mask) : 0; + + if (x_screen_planes (f) > 8 || x_screen_planes (f) == 1) + { + if (! old_widget) + old_widget = GTK_IMAGE (gtk_image_new_from_pixmap (gpix, gmask)); + else + gtk_image_set_from_pixmap (old_widget, gpix, gmask); + } + else + { + int x, y, width, height, rowstride, mask_rowstride; + GdkPixbuf *icon_buf, *tmp_buf; + guchar *pixels; + guchar *mask_pixels; + + gdk_drawable_get_size (gpix, &width, &height); + tmp_buf = gdk_pixbuf_get_from_drawable (NULL, + gpix, + gtk_widget_get_colormap (widget), + 0, 0, 0, 0, width, height); + icon_buf = gdk_pixbuf_add_alpha (tmp_buf, FALSE, 0, 0, 0); + g_object_unref (G_OBJECT (tmp_buf)); + + if (gmask) + { + GdkPixbuf *mask_buf = gdk_pixbuf_get_from_drawable (NULL, + gmask, + NULL, + 0, 0, 0, 0, + width, height); + guchar *pixels = gdk_pixbuf_get_pixels (icon_buf); + guchar *mask_pixels = gdk_pixbuf_get_pixels (mask_buf); + int rowstride = gdk_pixbuf_get_rowstride (icon_buf); + int mask_rowstride = gdk_pixbuf_get_rowstride (mask_buf); + int y; + + for (y = 0; y < height; ++y) + { + guchar *iconptr, *maskptr; + int x; + + iconptr = pixels + y * rowstride; + maskptr = mask_pixels + y * mask_rowstride; + + for (x = 0; x < width; ++x) + { + /* In a bitmap, RGB is either 255/255/255 or 0/0/0. Checking + just R is sufficient. */ + if (maskptr[0] == 0) + iconptr[3] = 0; /* 0, 1, 2 is R, G, B. 3 is alpha. */ + + iconptr += rowstride/width; + maskptr += mask_rowstride/width; + } + } + + g_object_unref (G_OBJECT (gmask)); + g_object_unref (G_OBJECT (mask_buf)); + } + + g_object_unref (G_OBJECT (gpix)); + + if (! old_widget) + old_widget = GTK_IMAGE (gtk_image_new_from_pixbuf (icon_buf)); + else + gtk_image_set_from_pixbuf (old_widget, icon_buf); + + g_object_unref (G_OBJECT (icon_buf)); + } + + return GTK_WIDGET (old_widget); +} + + +/* 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. */ +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 @@ -123,7 +344,7 @@ xg_set_cursor (w, cursor) 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. @@ -149,7 +370,7 @@ xg_process_timeouts (timer) /* Start the xg_timer with an interval of 0.1 seconds, if not already started. xg_process_timeouts is called when the timer expires. The timer - stared is continuous, i.e. runs until xg_stop_timer is called. */ + started is continuous, i.e. runs until xg_stop_timer is called. */ static void xg_start_timer () { @@ -235,12 +456,12 @@ static void xg_set_geometry (f) FRAME_PTR f; { - if (f->output_data.x->size_hint_flags & USPosition) + if (f->size_hint_flags & USPosition) { - int left = f->output_data.x->left_pos; - int xneg = f->output_data.x->size_hint_flags & XNegative; - int top = f->output_data.x->top_pos; - int yneg = f->output_data.x->size_hint_flags & YNegative; + int left = f->left_pos; + int xneg = f->size_hint_flags & XNegative; + int top = f->top_pos; + int yneg = f->size_hint_flags & YNegative; char geom_str[32]; if (xneg) @@ -249,7 +470,7 @@ xg_set_geometry (f) top = -top; sprintf (geom_str, "=%dx%d%c%d%c%d", - PIXEL_WIDTH (f), + FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f), (xneg ? '-' : '+'), left, (yneg ? '-' : '+'), top); @@ -271,7 +492,7 @@ xg_resize_outer_widget (f, columns, rows) int rows; { gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f)); + FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f)); /* base_height is now changed. */ x_wm_set_size_hint (f, 0, 0); @@ -285,6 +506,24 @@ xg_resize_outer_widget (f, columns, rows) gdk_window_process_all_updates (); } +/* This gets called after the frame F has been cleared. Since that is + done with X calls, we need to redraw GTK widget (scroll bars). */ +void +xg_frame_cleared (f) + FRAME_PTR f; +{ + GtkWidget *w = f->output_data.x->widget; + + if (w) + { + gtk_container_set_reallocate_redraws (GTK_CONTAINER (w), TRUE); + gtk_container_foreach (GTK_CONTAINER (w), + (GtkCallback) gtk_widget_queue_draw, + 0); + gdk_window_process_all_updates (); + } +} + /* Function to handle resize of our widgets. Since Emacs has some layouts that does not fit well with GTK standard containers, we do most layout manually. @@ -297,12 +536,13 @@ xg_resize_widgets (f, pixelwidth, pixelheight) { int mbheight = FRAME_MENUBAR_HEIGHT (f); int tbheight = FRAME_TOOLBAR_HEIGHT (f); - int rows = PIXEL_TO_CHAR_HEIGHT (f, pixelheight - mbheight - tbheight); - int columns = PIXEL_TO_CHAR_WIDTH (f, pixelwidth); + int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (pixelheight + - mbheight - tbheight)); + int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth); if (FRAME_GTK_WIDGET (f) - && (columns != FRAME_WIDTH (f) || rows != FRAME_HEIGHT (f) - || pixelwidth != PIXEL_WIDTH (f) || pixelheight != PIXEL_HEIGHT (f))) + && (columns != FRAME_COLS (f) || rows != FRAME_LINES (f) + || pixelwidth != FRAME_PIXEL_WIDTH (f) || pixelheight != FRAME_PIXEL_HEIGHT (f))) { struct x_output *x = f->output_data.x; GtkAllocation all; @@ -314,7 +554,6 @@ xg_resize_widgets (f, pixelwidth, pixelheight) all.height = pixelheight - mbheight - tbheight; gtk_widget_size_allocate (x->edit_widget, &all); - gdk_window_process_all_updates (); change_frame_size (f, rows, columns, 0, 1, 0); SET_FRAME_GARBAGED (f); @@ -330,44 +569,51 @@ xg_frame_set_char_size (f, cols, rows) int cols; int rows; { - int pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows) + int pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f); - int pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols); + int pixelwidth; /* Take into account the size of the scroll bar. Always use the number of columns occupied by the scroll bar here otherwise we might end up with a frame width that is not a multiple of the frame's character width which is bad for vertically split windows. */ - f->output_data.x->vertical_scroll_bar_extra - = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f) - ? 0 - : (FRAME_SCROLL_BAR_COLS (f) - * FONT_WIDTH (f->output_data.x->font))); + f->scroll_bar_actual_width + = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f); compute_fringe_widths (f, 0); + /* FRAME_TEXT_COLS_TO_PIXEL_WIDTH uses scroll_bar_actual_width, so call it + after calculating that value. */ + pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols); + /* Must resize our top level widget. Font size may have changed, but not rows/cols. */ gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixelwidth, pixelheight); xg_resize_widgets (f, pixelwidth, pixelheight); + x_wm_set_size_hint (f, 0, 0); + SET_FRAME_GARBAGED (f); + 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; @@ -391,6 +637,54 @@ xg_pix_to_gcolor (w, pixel, c) gdk_colormap_query_color (map, pixel, c); } +/* Turning off double buffering for our GtkFixed widget has the side + effect of turning it off also for its children (scroll bars). + But we want those to be double buffered to not flicker so handle + expose manually here. + WIDGET is the GtkFixed widget that gets exposed. + EVENT is the expose event. + USER_DATA is unused. + + 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) +{ + GList *iter; + + for (iter = GTK_FIXED (widget)->children; iter; iter = g_list_next (iter)) + { + GtkFixedChild *child_data = (GtkFixedChild *) iter->data; + GtkWidget *child = child_data->widget; + GdkWindow *window = child->window; + GdkRegion *region = gtk_widget_region_intersect (child, event->region); + + if (! gdk_region_empty (region)) + { + GdkEvent child_event; + child_event.expose = *event; + child_event.expose.region = region; + + /* Turn on double buffering, i.e. draw to an off screen area. */ + gdk_window_begin_paint_region (window, region); + + /* Tell child to redraw itself. */ + gdk_region_get_clipbox (region, &child_event.expose.area); + gtk_widget_send_expose (child, &child_event); + gdk_window_process_updates (window, TRUE); + + /* Copy off screen area to the window. */ + gdk_window_end_paint (window); + } + + gdk_region_destroy (region); + } + + return TRUE; +} + /* Create and set up the GTK widgets for frame F. Return 0 if creation failed, non-zero otherwise. */ int @@ -408,6 +702,8 @@ xg_create_frame_widgets (f) 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 */ @@ -426,8 +722,8 @@ xg_create_frame_widgets (f) gtk_widget_set_name (wfixed, SDATA (Vx_resource_name)); /* If this frame has a title or name, set it in the title bar. */ - if (! NILP (f->title)) title = SDATA (f->title); - else if (! NILP (f->name)) title = SDATA (f->name); + if (! NILP (f->title)) title = SDATA (ENCODE_UTF_8 (f->title)); + else if (! NILP (f->name)) title = SDATA (ENCODE_UTF_8 (f->name)); if (title) gtk_window_set_title (GTK_WINDOW (wtop), title); @@ -437,9 +733,8 @@ xg_create_frame_widgets (f) gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE); - gtk_widget_set_size_request (wfixed, - PIXEL_WIDTH (f), - 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); @@ -457,9 +752,19 @@ xg_create_frame_widgets (f) if (FRAME_EXTERNAL_TOOL_BAR (f) && FRAME_TOOLBAR_HEIGHT (f) == 0) FRAME_TOOLBAR_HEIGHT (f) = 34; - gtk_widget_set_double_buffered (wvbox, FALSE); + + /* We don't want this widget double buffered, because we draw on it + with regular X drawing primitives, so from a GTK/GDK point of + view, the widget is totally blank. When an expose comes, this + will make the widget blank, and then Emacs redraws it. This flickers + a lot, so we turn off double buffering. */ gtk_widget_set_double_buffered (wfixed, FALSE); - gtk_widget_set_double_buffered (wtop, FALSE); + + /* Turning off double buffering above has the side effect of turning + it off also for its children (scroll bars). But we want those + to be double buffered to not flicker so handle expose manually. */ + g_signal_connect (G_OBJECT (wfixed), "expose-event", + G_CALLBACK (xg_fixed_handle_expose), 0); /* GTK documents says use gtk_window_set_resizable. But then a user can't shrink the window from its starting size. */ @@ -510,8 +815,8 @@ xg_create_frame_widgets (f) gtk_widget_modify_style (wfixed, style); /* GTK does not set any border, and they look bad with GTK. */ - f->output_data.x->border_width = 0; - f->output_data.x->internal_border_width = 0; + f->border_width = 0; + f->internal_border_width = 0; UNBLOCK_INPUT; @@ -537,7 +842,7 @@ x_wm_set_size_hint (f, flags, user_position) gint hint_flags = 0; int base_width, base_height; int min_rows = 0, min_cols = 0; - int win_gravity = f->output_data.x->win_gravity; + int win_gravity = f->win_gravity; if (flags) { @@ -546,18 +851,18 @@ x_wm_set_size_hint (f, flags, user_position) f->output_data.x->hint_flags = hint_flags; } else - flags = f->output_data.x->size_hint_flags; + flags = f->size_hint_flags; size_hints = f->output_data.x->size_hints; hint_flags = f->output_data.x->hint_flags; hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE; - size_hints.width_inc = FONT_WIDTH (f->output_data.x->font); - size_hints.height_inc = f->output_data.x->line_height; + size_hints.width_inc = FRAME_COLUMN_WIDTH (f); + size_hints.height_inc = FRAME_LINE_HEIGHT (f); hint_flags |= GDK_HINT_BASE_SIZE; - base_width = CHAR_TO_PIXEL_WIDTH (f, 0); - base_height = CHAR_TO_PIXEL_HEIGHT (f, 0) + base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0); + base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f); check_frame_size (f, &min_rows, &min_cols); @@ -782,7 +1087,7 @@ create_dialog (wv, select_cb, deactivate_cb) else { /* This is one button to add to the dialog. */ - w = gtk_button_new_with_mnemonic (utf8_label); + w = gtk_button_new_with_label (utf8_label); if (! item->enabled) gtk_widget_set_sensitive (w, FALSE); if (select_cb) @@ -880,6 +1185,8 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p) 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), @@ -1025,14 +1332,14 @@ xg_mark_data () xg_list_node *iter; for (iter = xg_menu_cb_list.next; iter; iter = iter->next) - mark_object (&((xg_menu_cb_data *) iter)->menu_bar_vector); + mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector); for (iter = xg_menu_item_cb_list.next; iter; iter = iter->next) { xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data *) iter; if (! NILP (cb_data->help)) - mark_object (&cb_data->help); + mark_object (cb_data->help); } } @@ -1127,7 +1434,7 @@ make_widget_for_menu_item (utf8_label, utf8_key) GtkWidget *wbox; wbox = gtk_hbox_new (FALSE, 0); - wlbl = gtk_label_new_with_mnemonic (utf8_label); + wlbl = gtk_label_new (utf8_label); wkey = gtk_label_new (utf8_key); gtk_misc_set_alignment (GTK_MISC (wlbl), 0.0, 0.5); @@ -1138,6 +1445,7 @@ make_widget_for_menu_item (utf8_label, utf8_key) gtk_widget_set_name (wlbl, MENU_ITEM_NAME); gtk_widget_set_name (wkey, MENU_ITEM_NAME); + gtk_widget_set_name (wbox, MENU_ITEM_NAME); return wbox; } @@ -1165,6 +1473,12 @@ make_menu_item (utf8_label, utf8_key, item, group) GtkWidget *w; GtkWidget *wtoadd = 0; + /* It has been observed that some menu items have a NULL name field. + This will lead to this function being called with a NULL utf8_label. + GTK crashes on that so we set a blank label. Why there is a NULL + name remains to be investigated. */ + if (! utf8_label) utf8_label = " "; + if (utf8_key) wtoadd = make_widget_for_menu_item (utf8_label, utf8_key); @@ -1172,13 +1486,13 @@ make_menu_item (utf8_label, utf8_key, item, group) { *group = NULL; if (utf8_key) w = gtk_check_menu_item_new (); - else w = gtk_check_menu_item_new_with_mnemonic (utf8_label); + else w = gtk_check_menu_item_new_with_label (utf8_label); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), item->selected); } else if (item->button_type == BUTTON_TYPE_RADIO) { if (utf8_key) w = gtk_radio_menu_item_new (*group); - else w = gtk_radio_menu_item_new_with_mnemonic (*group, utf8_label); + else w = gtk_radio_menu_item_new_with_label (*group, utf8_label); *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (w)); if (item->selected) gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); @@ -1187,7 +1501,7 @@ make_menu_item (utf8_label, utf8_key, item, group) { *group = NULL; if (utf8_key) w = gtk_menu_item_new (); - else w = gtk_menu_item_new_with_mnemonic (utf8_label); + else w = gtk_menu_item_new_with_label (utf8_label); } if (wtoadd) gtk_container_add (GTK_CONTAINER (w), wtoadd); @@ -1196,39 +1510,76 @@ make_menu_item (utf8_label, utf8_key, item, group) return w; } -/* Return non-zero if NAME specifies a separator (GTK only has one +/* Return non-zero if LABEL specifies a separator (GTK only has one separator type) */ static int -xg_separator_p (char *name) +xg_separator_p (char *label) { - if (! name) return 0; + if (! label) return 0; + else if (strlen (label) > 3 + && strncmp (label, "--", 2) == 0 + && label[2] != '-') + { + static char* separator_names[] = { + "space", + "no-line", + "single-line", + "double-line", + "single-dashed-line", + "double-dashed-line", + "shadow-etched-in", + "shadow-etched-out", + "shadow-etched-in-dash", + "shadow-etched-out-dash", + "shadow-double-etched-in", + "shadow-double-etched-out", + "shadow-double-etched-in-dash", + "shadow-double-etched-out-dash", + 0, + }; + + int i; + + label += 2; + for (i = 0; separator_names[i]; ++i) + if (strcmp (label, separator_names[i]) == 0) + return 1; + } + else + { + /* Old-style separator, maybe. It's a separator if it contains + only dashes. */ + while (*label == '-') + ++label; + if (*label == 0) return 1; + } - return strcmp (name, "--") == 0 - || strncmp (name, "--:", 3) == 0 - || strcmp (name, "---") == 0; + return 0; } -GtkWidget *xg_did_tearoff; +static int xg_detached_menus; + +/* Returns non-zero if there are detached menus. */ +int +xg_have_tear_offs () +{ + return xg_detached_menus > 0; +} /* Callback invoked when a detached menu window is removed. Here we - delete the popup menu. + decrease the xg_detached_menus count. WIDGET is the top level window that is removed (the parent of the menu). - EVENT is the event that triggers the window removal. - CLIENT_DATA points to the menu that is detached. - - Returns TRUE to tell GTK to stop processing this event. */ -static gboolean -tearoff_remove (widget, event, client_data) + CLIENT_DATA is not used. */ +static void +tearoff_remove (widget, client_data) GtkWidget *widget; - GdkEvent *event; gpointer client_data; { - gtk_widget_destroy (GTK_WIDGET (client_data)); - return TRUE; + if (xg_detached_menus > 0) --xg_detached_menus; } -/* Callback invoked when a menu is detached. It sets the xg_did_tearoff - variable. +/* Callback invoked when a menu is detached. It increases the + xg_detached_menus count. WIDGET is the GtkTearoffMenuItem. CLIENT_DATA is not used. */ static void @@ -1237,33 +1588,15 @@ tearoff_activate (widget, client_data) gpointer client_data; { GtkWidget *menu = gtk_widget_get_parent (widget); - if (! gtk_menu_get_tearoff_state (GTK_MENU (menu))) - return; - - xg_did_tearoff = menu; -} - -/* If a detach of a popup menu is done, this function should be called - to keep the menu around until the detached window is removed. - MENU is the top level menu for the popup, - SUBMENU is the menu that got detached (that is MENU or a - submenu of MENU), see the xg_did_tearoff variable. */ -void -xg_keep_popup (menu, submenu) - GtkWidget *menu; - GtkWidget *submenu; -{ - GtkWidget *p; - - /* Find the top widget for the detached menu. */ - p = gtk_widget_get_toplevel (submenu); - - /* Delay destroying the menu until the detached menu is removed. */ - g_signal_connect (G_OBJECT (p), "unmap_event", - G_CALLBACK (tearoff_remove), menu); + if (gtk_menu_get_tearoff_state (GTK_MENU (menu))) + { + ++xg_detached_menus; + g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)), + "destroy", + G_CALLBACK (tearoff_remove), 0); + } } -int xg_debug = 0; /* Create a menu item widget, and connect the callbacks. ITEM decribes the menu item. @@ -1344,6 +1677,10 @@ xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group) return w; } +static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback, + GCallback, GCallback, int, int, int, + GtkWidget *, xg_menu_cb_data *, char *)); + /* Create a full menu tree specified by DATA. F is the frame the created menu belongs to. SELECT_CB is the callback to use when a menu item is selected. @@ -1387,7 +1724,11 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb, 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. */ @@ -1430,7 +1771,7 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb, utf8_label = get_utf8_string (item->name); gtk_menu_set_title (GTK_MENU (wmenu), utf8_label); - w = gtk_menu_item_new_with_mnemonic (utf8_label); + w = gtk_menu_item_new_with_label (utf8_label); gtk_widget_set_sensitive (w, FALSE); if (utf8_label && utf8_label != item->name) g_free (utf8_label); } @@ -1458,7 +1799,7 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb, highlight_cb, 0, 0, - 1, + add_tearoff_p, 0, cl_data, 0); @@ -1499,37 +1840,39 @@ xg_create_widget (type, name, f, val, GCallback highlight_cb; { GtkWidget *w = 0; + int menu_bar_p = strcmp (type, "menubar") == 0; + int pop_up_p = strcmp (type, "popup") == 0; + 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 (strcmp (type, "menubar") == 0 || strcmp (type, "popup") == 0) + else if (menu_bar_p || pop_up_p) { w = create_menus (val->contents, f, select_cb, deactivate_cb, highlight_cb, - strcmp (type, "popup") == 0, - strcmp (type, "menubar") == 0, - 1, + pop_up_p, + menu_bar_p, + menu_bar_p, 0, 0, name); /* Set the cursor to an arrow for popup menus when they are mapped. This is done by default for menu bar menus. */ - if (strcmp (type, "popup") == 0) + if (pop_up_p) { /* 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 @@ -1707,8 +2050,15 @@ xg_update_menubar (menubar, f, list, iter, pos, val, is up to date when leaving the minibuffer. */ GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem))); char *utf8_label = get_utf8_string (val->name); + GtkWidget *submenu = gtk_menu_item_get_submenu (witem); + + gtk_label_set_text (wlabel, utf8_label); - gtk_label_set_text_with_mnemonic (wlabel, utf8_label); + /* If this item has a submenu that has been detached, change + the title in the WM decorations also. */ + if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu))) + /* Set the title of the detached window. */ + gtk_menu_set_title (GTK_MENU (submenu), utf8_label); iter = g_list_next (iter); val = val->next; @@ -1838,7 +2188,7 @@ xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data) gtk_label_set_text (wkey, utf8_key); if (! old_label || strcmp (utf8_label, old_label) != 0) - gtk_label_set_text_with_mnemonic (wlbl, utf8_label); + gtk_label_set_text (wlbl, utf8_label); if (utf8_key && utf8_key != val->key) g_free (utf8_key); if (utf8_label && utf8_label != val->name) g_free (utf8_label); @@ -2095,18 +2445,15 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p, cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar), XG_FRAME_DATA); - if (! deep_p) - { - widget_value *cur = val->contents; - xg_update_menubar (menubar, f, &list, list, 0, cur, - select_cb, highlight_cb, cl_data); - } - else + xg_update_menubar (menubar, f, &list, list, 0, val->contents, + select_cb, highlight_cb, cl_data); + + if (deep_p); { widget_value *cur; /* Update all sub menus. - We must keep the submenu names (GTK menu item widgets) since the + We must keep the submenus (GTK menu item widgets) since the X Window in the XEvent that activates the menu are those widgets. */ /* Update cl_data, menu_item things in F may have changed. */ @@ -2141,8 +2488,10 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p, 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); + } } } @@ -2176,7 +2525,7 @@ xg_update_frame_menubar (f) /* The height has changed, resize outer widget and set columns rows to what we had before adding the menu bar. */ - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); SET_FRAME_GARBAGED (f); UNBLOCK_INPUT; @@ -2205,7 +2554,7 @@ free_frame_menubar (f) /* The height has changed, resize outer widget and set columns rows to what we had before removing the menu bar. */ - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); SET_FRAME_GARBAGED (f); UNBLOCK_INPUT; @@ -2223,11 +2572,6 @@ free_frame_menubar (f) to indicate that callback should do nothing. */ int xg_ignore_gtk_scrollbar; -/* After we send a scroll bar event, x_set_toolkit_scroll_bar_thumb will - be called. For some reason that needs to be debugged, it gets called - with bad values. Thus, we set this variable to ignore those calls. */ -int xg_ignore_next_thumb; - /* SET_SCROLL_BAR_X_WINDOW assumes the second argument fits in 32 bits. But we want to store pointers, and they may be larger than 32 bits. Keep a mapping from integer index to widget pointers @@ -2303,16 +2647,17 @@ xg_get_widget_from_map (idx) 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) { @@ -2326,7 +2671,7 @@ xg_get_scroll_id_for_window (wid) /* Callback invoked when scroll bar WIDGET is destroyed. DATA is the index into id_to_widget for WIDGET. - We free pointer to last scroll bar value here and remove the index. */ + We free pointer to last scroll bar values here and remove the index. */ static void xg_gtk_scroll_destroy (widget, data) GtkWidget *widget; @@ -2342,9 +2687,10 @@ xg_gtk_scroll_destroy (widget, data) /* Callback for button press/release events. Used to start timer so that the scroll bar repetition timer in GTK gets handeled. + Also, sets bar->dragging to Qnil when dragging (button release) is done. WIDGET is the scroll bar widget the event is for (not used). EVENT contains the event. - USER_DATA is 0 (not used). + USER_DATA points to the struct scrollbar structure. Returns FALSE to tell GTK that it shall continue propagate the event to widgets. */ @@ -2356,9 +2702,13 @@ scroll_bar_button_cb (widget, event, user_data) { if (event->type == GDK_BUTTON_PRESS && ! xg_timer) xg_start_timer (); - else if (event->type == GDK_BUTTON_RELEASE && xg_timer) - xg_stop_timer (); - + else if (event->type == GDK_BUTTON_RELEASE) + { + struct scroll_bar *bar = (struct scroll_bar *) user_data; + if (xg_timer) xg_stop_timer (); + bar->dragging = Qnil; + } + return FALSE; } @@ -2390,31 +2740,31 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name) scroll_id = xg_store_widget_in_map (wscroll); - g_signal_connect (G_OBJECT (vadj), + g_signal_connect (G_OBJECT (wscroll), "value-changed", scroll_callback, - (gpointer)bar); + (gpointer) bar); g_signal_connect (G_OBJECT (wscroll), "destroy", G_CALLBACK (xg_gtk_scroll_destroy), - (gpointer)scroll_id); + (gpointer) scroll_id); /* Connect to button press and button release to detect if any scroll bar has the pointer. */ g_signal_connect (G_OBJECT (wscroll), "button-press-event", G_CALLBACK (scroll_bar_button_cb), - 0); + (gpointer) bar); g_signal_connect (G_OBJECT (wscroll), "button-release-event", G_CALLBACK (scroll_bar_button_cb), - 0); + (gpointer) bar); gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), - wscroll, 0, 0); + 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); } @@ -2443,13 +2793,37 @@ xg_remove_scroll_bar (f, scrollbar_id) } } +/* Find left/top for widget W in GtkFixed widget WFIXED. */ +static void +xg_find_top_left_in_fixed (w, wfixed, left, top) + GtkWidget *w, *wfixed; + int *left, *top; +{ + GList *iter; + + for (iter = GTK_FIXED (wfixed)->children; iter; iter = g_list_next (iter)) + { + GtkFixedChild *child = (GtkFixedChild *) iter->data; + + if (child->widget == w) + { + *left = child->x; + *top = child->y; + return; + } + } + + /* Shall never end up here. */ + abort (); +} /* Update the position of the vertical scroll bar represented by SCROLLBAR_ID in frame F. TOP/LEFT are the new pixel positions where the bar shall appear. WIDTH, HEIGHT is the size in pixels the bar shall have. */ void -xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height) +xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height, + real_left, canon_width) FRAME_PTR f; int scrollbar_id; int top; @@ -2462,26 +2836,45 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height) if (wscroll) { - int gheight = max (height, 1); + GtkWidget *wfixed = f->output_data.x->edit_widget; - gtk_fixed_move (GTK_FIXED (f->output_data.x->edit_widget), - wscroll, left, top); - - gtk_widget_set_size_request (wscroll, width, gheight); - - /* Must force out update so wscroll gets the resize. - Otherwise, the gdk_window_clear clears the old window size. */ - gdk_window_process_all_updates (); + gtk_container_set_reallocate_redraws (GTK_CONTAINER (wfixed), TRUE); - /* The scroll bar doesn't explicitly redraw the whole window - when a resize occurs. Since the scroll bar seems to be fixed - in width it doesn't fill the space reserved, so we must clear - the whole window. */ - gdk_window_clear (wscroll->window); + /* Move and resize to new values. */ + gtk_fixed_move (GTK_FIXED (wfixed), wscroll, left, top); + gtk_widget_set_size_request (wscroll, width, height); - /* Since we are not using a pure gtk event loop, we must force out - pending update events with this call. */ + /* Must force out update so changed scroll bars gets redrawn. */ gdk_window_process_all_updates (); + + /* Scroll bars in GTK has a fixed width, so if we say width 16, it + will only be its fixed width (14 is default) anyway, the rest is + blank. We are drawing the mode line across scroll bars when + the frame is split: + |bar| |fringe| + ---------------- + mode line + ---------------- + |bar| |fringe| + + When we "unsplit" the frame: + + |bar| |fringe| + -| |-| | + m¦ |i| | + -| |-| | + | | | | + + + the remains of the mode line can be seen in these blank spaces. + So we must clear them explicitly. + GTK scroll bars should do that, but they don't. + Also, the canonical width may be wider than the width for the + scroll bar so that there is some space (typically 1 pixel) between + the scroll bar and the edge of the window and between the scroll + bar and the fringe. */ + + XClearWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (wscroll)); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); @@ -2499,53 +2892,74 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); - BLOCK_INPUT; - if (wscroll && ! xg_ignore_next_thumb) + if (wscroll && NILP (bar->dragging)) { GtkAdjustment *adj; gdouble shown; gdouble top; int size, value; + int new_step; + int changed = 0; adj = gtk_range_get_adjustment (GTK_RANGE (wscroll)); + /* We do the same as for MOTIF in xterm.c, assume 30 chars per line + rather than the real portion value. This makes the thumb less likely + to resize and that looks better. */ + portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30; + /* When the thumb is at the bottom, position == whole. + So we need to increase `whole' to make space for the thumb. */ + whole += portion; + if (whole <= 0) top = 0, shown = 1; else { - shown = (gdouble) portion / whole; top = (gdouble) position / whole; + shown = (gdouble) portion / whole; } - size = shown * whole; - size = min (size, whole); + size = shown * XG_SB_RANGE; + size = min (size, XG_SB_RANGE); size = max (size, 1); - value = top * whole; - value = min (value, whole - size); + value = top * XG_SB_RANGE; + value = min (value, XG_SB_MAX - size); value = max (value, XG_SB_MIN); - adj->upper = max (whole, size); - adj->page_size = (int)size; + /* Assume all lines are of equal size. */ + new_step = size / max (1, FRAME_LINES (f)); - /* Assume a page increment is about 95% of the page size */ - adj->page_increment = (int) (0.95*adj->page_size); + if ((int) adj->page_size != size + || (int) adj->step_increment != new_step) + { + adj->page_size = size; + adj->step_increment = new_step; + /* Assume a page increment is about 95% of the page size */ + adj->page_increment = (int) (0.95*adj->page_size); + changed = 1; + } - /* Assume all lines are equal. */ - adj->step_increment = portion / max (1, FRAME_HEIGHT (f)); + if (changed || (int) gtk_range_get_value (GTK_RANGE (wscroll)) != value) + { + GtkWidget *wfixed = f->output_data.x->edit_widget; - /* gtk_range_set_value invokes the callback. Set - ignore_gtk_scrollbar to make the callback do nothing */ - xg_ignore_gtk_scrollbar = 1; - gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); - xg_ignore_gtk_scrollbar = 0; - } + BLOCK_INPUT; - /* Make sure the scroll bar is redrawn with new thumb */ - gtk_widget_queue_draw (wscroll); - gdk_window_process_all_updates (); - xg_ignore_next_thumb = 0; - UNBLOCK_INPUT; + /* gtk_range_set_value invokes the callback. Set + ignore_gtk_scrollbar to make the callback do nothing */ + xg_ignore_gtk_scrollbar = 1; + + if ((int) gtk_range_get_value (GTK_RANGE (wscroll)) != value) + gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); + else if (changed) + gtk_adjustment_changed (adj); + + xg_ignore_gtk_scrollbar = 0; + + UNBLOCK_INPUT; + } + } } @@ -2570,6 +2984,7 @@ xg_tool_bar_callback (w, client_data) FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA); Lisp_Object key, frame; struct input_event event; + EVENT_INIT (event); if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items)) return; @@ -2614,7 +3029,7 @@ xg_tool_bar_detach_callback (wbox, w, client_data) /* The height has changed, resize outer widget and set columns rows to what we had before detaching the tool bar. */ - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); } } @@ -2641,7 +3056,7 @@ xg_tool_bar_attach_callback (wbox, w, client_data) /* The height has changed, resize outer widget and set columns rows to what we had before detaching the tool bar. */ - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); } } @@ -2669,7 +3084,7 @@ xg_tool_bar_help_callback (w, event, client_data) } if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items)) - return; + return FALSE; if (event->type == GDK_ENTER_NOTIFY) { @@ -2704,8 +3119,19 @@ xg_tool_bar_item_expose_callback (w, event, client_data) GdkEventExpose *event; gpointer client_data; { - event->area.x = event->area.y = 0; - event->area.width = event->area.height = 1000; + gint width, height; + + gdk_drawable_get_size (event->window, &width, &height); + + 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.width = max (width, event->area.width); + event->area.height = max (height, event->area.height); + return FALSE; } @@ -2723,7 +3149,7 @@ xg_tool_bar_expose_callback (w, event, client_data) GdkEventExpose *event; gpointer client_data; { - update_frame_tool_bar((FRAME_PTR)client_data); + update_frame_tool_bar ((FRAME_PTR) client_data); return FALSE; } @@ -2775,7 +3201,7 @@ xg_create_tool_bar (f) /* The height has changed, resize outer widget and set columns rows to what we had before adding the tool bar. */ - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); SET_FRAME_GARBAGED (f); } @@ -2856,11 +3282,8 @@ update_frame_tool_bar (f) if (! wicon) { - GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap); - GdkBitmap *gmask = img->mask ? - (GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0; + GtkWidget *w = xg_get_image_for_pixmap (f, img, x->widget, NULL); - GtkWidget *w = gtk_image_new_from_pixmap (gpix, gmask); gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget), 0, 0, 0, w, @@ -2917,13 +3340,7 @@ update_frame_tool_bar (f) g_list_free (chlist); 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; - - gtk_image_set_from_pixmap (wimage, gpix, gmask); - } + (void) xg_get_image_for_pixmap (f, img, x->widget, wimage); g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, (gpointer)img->pixmap); @@ -2948,12 +3365,9 @@ update_frame_tool_bar (f) if (old_req.height != new_req.height) { FRAME_TOOLBAR_HEIGHT (f) = new_req.height; - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); } - /* Must force out update so changed images gets redrawn. */ - gdk_window_process_all_updates (); - if (icon_list) g_list_free (icon_list); UNBLOCK_INPUT; @@ -2976,7 +3390,7 @@ free_frame_tool_bar (f) /* The height has changed, resize outer widget and set columns rows to what we had before removing the tool bar. */ - xg_resize_outer_widget (f, FRAME_WIDTH (f), FRAME_HEIGHT (f)); + xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); SET_FRAME_GARBAGED (f); UNBLOCK_INPUT; @@ -2992,10 +3406,7 @@ void xg_initialize () { xg_ignore_gtk_scrollbar = 0; - xg_ignore_next_thumb = 0; - xg_left_ptr_cursor = 0; - xg_did_tearoff = 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; @@ -3019,3 +3430,6 @@ xg_initialize () } #endif /* USE_GTK */ + +/* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3 + (do not change this comment) */