X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/1259009aa17da6dc038afff96963f6d9bbd3b8e1..1088b9226e7dac7314dab52ef0696a5f540900cd:/src/gtkutil.c diff --git a/src/gtkutil.c b/src/gtkutil.c index f7983fdd5a..3bce5be9cd 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -24,6 +24,9 @@ along with GNU Emacs. If not, see . */ #include #include #include + +#include + #include "lisp.h" #include "xterm.h" #include "blockinput.h" @@ -75,6 +78,18 @@ along with GNU Emacs. If not, see . */ #define remove_submenu(w) gtk_menu_item_remove_submenu ((w)) #endif +#if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 2) +#define USE_NEW_GTK_FONT_CHOOSER 1 +#else +#define USE_NEW_GTK_FONT_CHOOSER 0 +#define gtk_font_chooser_dialog_new(x, y) \ + gtk_font_selection_dialog_new (x) +#undef GTK_FONT_CHOOSER +#define GTK_FONT_CHOOSER(x) GTK_FONT_SELECTION_DIALOG (x) +#define gtk_font_chooser_set_font(x, y) \ + gtk_font_selection_dialog_set_font_name (x, y) +#endif + #ifndef HAVE_GTK3 #ifdef USE_GTK_TOOLTIP #define gdk_window_get_screen(w) gdk_drawable_get_screen (w) @@ -83,15 +98,31 @@ along with GNU Emacs. If not, see . */ gdk_window_get_geometry (w, a, b, c, d, 0) #define gdk_x11_window_lookup_for_display(d, w) \ gdk_xid_table_lookup_for_display (d, w) +#define gtk_box_new(ori, spacing) \ + ((ori) == GTK_ORIENTATION_HORIZONTAL \ + ? gtk_hbox_new (FALSE, (spacing)) : gtk_vbox_new (FALSE, (spacing))) +#define gtk_scrollbar_new(ori, spacing) \ + ((ori) == GTK_ORIENTATION_HORIZONTAL \ + ? gtk_hscrollbar_new ((spacing)) : gtk_vscrollbar_new ((spacing))) #ifndef GDK_KEY_g #define GDK_KEY_g GDK_g #endif -#endif +#endif /* HAVE_GTK3 */ #define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x)) static void update_theme_scrollbar_width (void); +#define TB_INFO_KEY "xg_frame_tb_info" +struct xg_frame_tb_info +{ + Lisp_Object last_tool_bar; + Lisp_Object style; + int n_last_items; + int hmargin, vmargin; + GtkTextDirection dir; +}; + /*********************************************************************** Display handling functions @@ -209,7 +240,7 @@ malloc_widget_value (void) } else { - wv = (widget_value *) xmalloc (sizeof (widget_value)); + wv = xmalloc (sizeof *wv); malloc_cpt++; } memset (wv, 0, sizeof (widget_value)); @@ -223,7 +254,7 @@ void free_widget_value (widget_value *wv) { if (wv->free_list) - abort (); + emacs_abort (); if (malloc_cpt > 25) { @@ -523,9 +554,8 @@ get_utf8_string (const char *str) &bytes_written, &err)) && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE) { - strncpy (up, (char *)p, bytes_written); + memcpy (up, p, bytes_written); sprintf (up + bytes_written, "\\%03o", p[bytes_written]); - up[bytes_written+4] = '\0'; up += bytes_written+4; p += bytes_written+1; g_error_free (err); @@ -1090,13 +1120,18 @@ xg_create_frame_widgets (FRAME_PTR f) GtkWidget *wtop; GtkWidget *wvbox, *whbox; GtkWidget *wfixed; +#ifndef HAVE_GTK3 GtkRcStyle *style; +#endif char *title = 0; BLOCK_INPUT; if (FRAME_X_EMBEDDED_P (f)) - wtop = gtk_plug_new (f->output_data.x->parent_desc); + { + GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); + wtop = gtk_plug_new_for_display (gdpy, f->output_data.x->parent_desc); + } else wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL); @@ -1110,8 +1145,10 @@ xg_create_frame_widgets (FRAME_PTR f) xg_set_screen (wtop, f); - wvbox = gtk_vbox_new (FALSE, 0); - whbox = gtk_hbox_new (FALSE, 0); + wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + whbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous (GTK_BOX (wvbox), FALSE); + gtk_box_set_homogeneous (GTK_BOX (whbox), FALSE); #ifdef HAVE_GTK3 wfixed = emacs_fixed_new (f); @@ -1136,8 +1173,10 @@ xg_create_frame_widgets (FRAME_PTR f) gtk_widget_set_name (wfixed, SSDATA (Vx_resource_name)); /* If this frame has a title or name, set it in the title bar. */ - if (! NILP (f->title)) title = SSDATA (ENCODE_UTF_8 (f->title)); - else if (! NILP (f->name)) title = SSDATA (ENCODE_UTF_8 (f->name)); + if (! NILP (f->title)) + title = SSDATA (ENCODE_UTF_8 (f->title)); + else if (! NILP (f->name)) + title = SSDATA (ENCODE_UTF_8 (f->name)); if (title) gtk_window_set_title (GTK_WINDOW (wtop), title); @@ -1251,6 +1290,12 @@ xg_free_frame_widgets (FRAME_PTR f) #ifdef USE_GTK_TOOLTIP struct x_output *x = f->output_data.x; #endif + struct xg_frame_tb_info *tbinfo + = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY); + if (tbinfo) + xfree (tbinfo); + gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */ FRAME_GTK_OUTER_WIDGET (f) = 0; @@ -1303,11 +1348,15 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, int user_position) size_hints.height_inc = FRAME_LINE_HEIGHT (f); hint_flags |= GDK_HINT_BASE_SIZE; - base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0) + FRAME_TOOLBAR_WIDTH (f); - base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0) + /* Use one row/col here so base_height/width does not become zero. + Gtk+ and/or Unity on Ubuntu 12.04 can't handle it. */ + base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 1) + FRAME_TOOLBAR_WIDTH (f); + base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f); check_frame_size (f, &min_rows, &min_cols); + if (min_cols > 0) --min_cols; /* We used one col in base_width = ... 1); */ + if (min_rows > 0) --min_rows; /* We used one row in base_height = ... 1); */ size_hints.base_width = base_width; size_hints.base_height = base_height; @@ -1483,9 +1532,12 @@ create_dialog (widget_value *wv, if (make_two_rows) { - GtkWidget *wvbox = gtk_vbox_new (TRUE, button_spacing); - GtkWidget *whbox_up = gtk_hbox_new (FALSE, 0); - whbox_down = gtk_hbox_new (FALSE, 0); + GtkWidget *wvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, button_spacing); + GtkWidget *whbox_up = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous (GTK_BOX (wvbox), TRUE); + gtk_box_set_homogeneous (GTK_BOX (whbox_up), FALSE); + whbox_down = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous (GTK_BOX (whbox_down), FALSE); gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0); @@ -1607,16 +1659,16 @@ xg_maybe_add_timer (gpointer data) { struct xg_dialog_data *dd = (struct xg_dialog_data *) data; EMACS_TIME next_time = timer_check (); - long secs = EMACS_SECS (next_time); - long usecs = EMACS_USECS (next_time); dd->timerid = 0; - if (secs >= 0 && usecs >= 0 && secs < ((guint)-1)/1000) + if (EMACS_TIME_VALID_P (next_time)) { - dd->timerid = g_timeout_add (secs * 1000 + usecs/1000, - xg_maybe_add_timer, - dd); + time_t s = EMACS_SECS (next_time); + int per_ms = EMACS_TIME_RESOLUTION / 1000; + int ms = (EMACS_NSECS (next_time) + per_ms - 1) / per_ms; + if (s <= ((guint) -1 - ms) / 1000) + dd->timerid = g_timeout_add (s * 1000 + ms, xg_maybe_add_timer, dd); } return FALSE; } @@ -1629,7 +1681,7 @@ xg_maybe_add_timer (gpointer data) static int xg_dialog_run (FRAME_PTR f, GtkWidget *w) { - int count = SPECPDL_INDEX (); + ptrdiff_t count = SPECPDL_INDEX (); struct xg_dialog_data dd; xg_set_screen (w, f); @@ -1741,8 +1793,9 @@ xg_toggle_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data) PROMPT is a prompt to show to the user. May not be NULL. DEFAULT_FILENAME is a default selection to be displayed. May be NULL. If MUSTMATCH_P is non-zero, the returned file name must be an existing - file. *FUNC is set to a function that can be used to retrieve the - selected file name from the returned widget. + file. (Actually, this only has cosmetic effects, the user can + still enter a non-existing file.) *FUNC is set to a function that + can be used to retrieve the selected file name from the returned widget. Returns the created widget. */ @@ -1772,7 +1825,8 @@ xg_get_file_with_chooser (FRAME_PTR f, NULL); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE); - wbox = gtk_vbox_new (FALSE, 0); + wbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_box_set_homogeneous (GTK_BOX (wbox), FALSE); gtk_widget_show (wbox); wtoggle = gtk_check_button_new_with_label ("Show hidden files."); @@ -1957,7 +2011,35 @@ xg_get_file_name (FRAME_PTR f, return fn; } +/*********************************************************************** + GTK font chooser + ***********************************************************************/ + #ifdef HAVE_FREETYPE + +#if USE_NEW_GTK_FONT_CHOOSER + +#define XG_WEIGHT_TO_SYMBOL(w) \ + (w <= PANGO_WEIGHT_THIN ? Qextra_light \ + : w <= PANGO_WEIGHT_ULTRALIGHT ? Qlight \ + : w <= PANGO_WEIGHT_LIGHT ? Qsemi_light \ + : w < PANGO_WEIGHT_MEDIUM ? Qnormal \ + : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold \ + : w <= PANGO_WEIGHT_BOLD ? Qbold \ + : w <= PANGO_WEIGHT_HEAVY ? Qextra_bold \ + : Qultra_bold) + +#define XG_STYLE_TO_SYMBOL(s) \ + (s == PANGO_STYLE_OBLIQUE ? Qoblique \ + : s == PANGO_STYLE_ITALIC ? Qitalic \ + : Qnormal) + +#endif /* USE_NEW_GTK_FONT_CHOOSER */ + + +static char *x_last_font_name; +extern Lisp_Object Qxft; + /* Pop up a GTK font selector and return the name of the font the user selects, as a C string. The returned font name follows GTK's own format: @@ -1967,25 +2049,40 @@ xg_get_file_name (FRAME_PTR f, This can be parsed using font_parse_fcname in font.c. DEFAULT_NAME, if non-zero, is the default font name. */ -char * -xg_get_font_name (FRAME_PTR f, const char *default_name) +Lisp_Object +xg_get_font (FRAME_PTR f, const char *default_name) { GtkWidget *w; - char *fontname = NULL; int done = 0; + Lisp_Object font = Qnil; #if defined (HAVE_PTHREAD) && defined (__SIGRTMIN) sigblock (sigmask (__SIGRTMIN)); #endif /* HAVE_PTHREAD */ - w = gtk_font_selection_dialog_new ("Pick a font"); - if (!default_name) - default_name = "Monospace 10"; - gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w), - default_name); + w = gtk_font_chooser_dialog_new + ("Pick a font", GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); - gtk_widget_set_name (w, "emacs-fontdialog"); + if (default_name) + { + /* Convert fontconfig names to Gtk names, i.e. remove - before + number */ + char *p = strrchr (default_name, '-'); + if (p) + { + char *ep = p+1; + while (c_isdigit (*ep)) + ++ep; + if (*ep == '\0') *p = ' '; + } + } + else if (x_last_font_name) + default_name = x_last_font_name; + + if (default_name) + gtk_font_chooser_set_font (GTK_FONT_CHOOSER (w), default_name); + gtk_widget_set_name (w, "emacs-fontdialog"); done = xg_dialog_run (f, w); #if defined (HAVE_PTHREAD) && defined (__SIGRTMIN) @@ -1993,11 +2090,58 @@ xg_get_font_name (FRAME_PTR f, const char *default_name) #endif if (done == GTK_RESPONSE_OK) - fontname = gtk_font_selection_dialog_get_font_name - (GTK_FONT_SELECTION_DIALOG (w)); + { +#if USE_NEW_GTK_FONT_CHOOSER + /* Use the GTK3 font chooser. */ + PangoFontDescription *desc + = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (w)); + + if (desc) + { + Lisp_Object args[10]; + const char *name = pango_font_description_get_family (desc); + gint size = pango_font_description_get_size (desc); + PangoWeight weight = pango_font_description_get_weight (desc); + PangoStyle style = pango_font_description_get_style (desc); + + args[0] = QCname; + args[1] = build_string (name); + + args[2] = QCsize; + args[3] = make_float (pango_units_to_double (size)); + + args[4] = QCweight; + args[5] = XG_WEIGHT_TO_SYMBOL (weight); + + args[6] = QCslant; + args[7] = XG_STYLE_TO_SYMBOL (style); + + args[8] = QCtype; + args[9] = Qxft; + + font = Ffont_spec (8, args); + + pango_font_description_free (desc); + xfree (x_last_font_name); + x_last_font_name = xstrdup (name); + } + +#else /* Use old font selector, which just returns the font name. */ + + char *font_name + = gtk_font_selection_dialog_get_font_name (GTK_FONT_CHOOSER (w)); + + if (font_name) + { + font = build_string (font_name); + g_free (x_last_font_name); + x_last_font_name = font_name; + } +#endif /* USE_NEW_GTK_FONT_CHOOSER */ + } gtk_widget_destroy (w); - return fontname; + return font; } #endif /* HAVE_FREETYPE */ @@ -2037,7 +2181,7 @@ make_cl_data (xg_menu_cb_data *cl_data, FRAME_PTR f, GCallback highlight_cb) { if (! cl_data) { - cl_data = (xg_menu_cb_data*) xmalloc (sizeof (*cl_data)); + cl_data = xmalloc (sizeof *cl_data); cl_data->f = f; cl_data->menu_bar_vector = f->menu_bar_vector; cl_data->menu_bar_items_used = f->menu_bar_items_used; @@ -2100,6 +2244,7 @@ void xg_mark_data (void) { xg_list_node *iter; + Lisp_Object rest, frame; for (iter = xg_menu_cb_list.next; iter; iter = iter->next) mark_object (((xg_menu_cb_data *) iter)->menu_bar_vector); @@ -2111,6 +2256,23 @@ xg_mark_data (void) if (! NILP (cb_data->help)) mark_object (cb_data->help); } + + FOR_EACH_FRAME (rest, frame) + { + FRAME_PTR f = XFRAME (frame); + + if (FRAME_X_P (f) && FRAME_GTK_OUTER_WIDGET (f)) + { + struct xg_frame_tb_info *tbinfo + = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY); + if (tbinfo) + { + mark_object (tbinfo->last_tool_bar); + mark_object (tbinfo->style); + } + } + } } @@ -2184,7 +2346,8 @@ make_widget_for_menu_item (const char *utf8_label, const char *utf8_key) GtkWidget *wkey; GtkWidget *wbox; - wbox = gtk_hbox_new (FALSE, 0); + wbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous (GTK_BOX (wbox), FALSE); wlbl = gtk_label_new (utf8_label); wkey = gtk_label_new (utf8_key); @@ -2336,7 +2499,7 @@ xg_create_one_menuitem (widget_value *item, if (utf8_label) g_free (utf8_label); if (utf8_key) g_free (utf8_key); - cb_data = xmalloc (sizeof (xg_menu_item_cb_data)); + cb_data = xmalloc (sizeof *cb_data); xg_list_insert (&xg_menu_item_cb_list, &cb_data->ptrs); @@ -2841,7 +3004,7 @@ xg_update_menu_item (widget_value *val, utf8_key = get_utf8_string (val->key); /* See if W is a menu item with a key. See make_menu_item above. */ - if (GTK_IS_HBOX (wchild)) + if (GTK_IS_BOX (wchild)) { GList *list = gtk_container_get_children (GTK_CONTAINER (wchild)); @@ -3356,7 +3519,7 @@ xg_store_widget_in_map (GtkWidget *w) } /* Should never end up here */ - abort (); + emacs_abort (); } /* Remove pointer at IDX from id_to_widget. @@ -3395,7 +3558,7 @@ update_theme_scrollbar_width (void) int w = 0, b = 0; vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX, 0.1, 0.1, 0.1); - wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj)); + wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj)); g_object_ref_sink (G_OBJECT (wscroll)); gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL); gtk_widget_destroy (wscroll); @@ -3472,7 +3635,7 @@ xg_create_scroll_bar (FRAME_PTR f, vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX, 0.1, 0.1, 0.1); - wscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT (vadj)); + wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj)); webox = gtk_event_box_new (); gtk_widget_set_name (wscroll, scroll_bar_name); #ifndef HAVE_GTK3 @@ -3705,8 +3868,15 @@ xg_event_is_for_scrollbar (FRAME_PTR f, XEvent *event) { /* Check if press occurred outside the edit widget. */ GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); - retval = gdk_display_get_window_at_pointer (gdpy, NULL, NULL) - != gtk_widget_get_window (f->output_data.x->edit_widget); + GdkWindow *gwin; +#ifdef HAVE_GTK3 + GdkDevice *gdev = gdk_device_manager_get_client_pointer + (gdk_display_get_device_manager (gdpy)); + gwin = gdk_device_get_window_at_position (gdev, NULL, NULL); +#else + gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL); +#endif + retval = gwin != gtk_widget_get_window (f->output_data.x->edit_widget); } else if (f && ((event->type == ButtonRelease && event->xbutton.button < 4) @@ -3917,7 +4087,7 @@ xg_tool_bar_menu_proxy (GtkToolItem *toolitem, gpointer user_data) else { fprintf (stderr, "internal error: GTK_IMAGE_PIXBUF failed\n"); - abort (); + emacs_abort (); } } else if (store_type == GTK_IMAGE_ICON_NAME) @@ -3932,7 +4102,7 @@ xg_tool_bar_menu_proxy (GtkToolItem *toolitem, gpointer user_data) else { fprintf (stderr, "internal error: store_type is %d\n", store_type); - abort (); + emacs_abort (); } } if (wmenuimage) @@ -4175,6 +4345,24 @@ static void xg_create_tool_bar (FRAME_PTR f) { struct x_output *x = f->output_data.x; +#if GTK_CHECK_VERSION (3, 3, 6) + GtkStyleContext *gsty; +#endif + struct xg_frame_tb_info *tbinfo + = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY); + if (! tbinfo) + { + tbinfo = xmalloc (sizeof (*tbinfo)); + tbinfo->last_tool_bar = Qnil; + tbinfo->style = Qnil; + tbinfo->hmargin = tbinfo->vmargin = 0; + tbinfo->dir = GTK_TEXT_DIR_NONE; + tbinfo->n_last_items = 0; + g_object_set_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY, + tbinfo); + } x->toolbar_widget = gtk_toolbar_new (); x->toolbar_detached = 0; @@ -4183,6 +4371,10 @@ xg_create_tool_bar (FRAME_PTR f) gtk_toolbar_set_style (GTK_TOOLBAR (x->toolbar_widget), GTK_TOOLBAR_ICONS); toolbar_set_orientation (x->toolbar_widget, GTK_ORIENTATION_HORIZONTAL); +#if GTK_CHECK_VERSION (3, 3, 6) + gsty = gtk_widget_get_style_context (x->toolbar_widget); + gtk_style_context_add_class (gsty, "primary-toolbar"); +#endif } @@ -4208,7 +4400,7 @@ find_rtl_image (FRAME_PTR f, Lisp_Object image, Lisp_Object rtl) { file = call1 (intern ("file-name-sans-extension"), Ffile_name_nondirectory (file)); - if (EQ (Fequal (file, rtl_name), Qt)) + if (! NILP (Fequal (file, rtl_name))) { image = rtl_image; break; @@ -4227,10 +4419,31 @@ xg_make_tool_item (FRAME_PTR f, int i, int horiz, int text_image) { GtkToolItem *ti = gtk_tool_item_new (); - GtkWidget *vb = horiz ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 0); + GtkWidget *vb = gtk_box_new (horiz + ? GTK_ORIENTATION_HORIZONTAL + : GTK_ORIENTATION_VERTICAL, + 0); GtkWidget *wb = gtk_button_new (); /* The eventbox is here so we can have tooltips on disabled items. */ GtkWidget *weventbox = gtk_event_box_new (); +#if GTK_CHECK_VERSION (3, 3, 6) + GtkCssProvider *css_prov = gtk_css_provider_new (); + GtkStyleContext *gsty; + + gtk_css_provider_load_from_data (css_prov, + "GtkEventBox {" + " background-color: transparent;" + "}", + -1, NULL); + + gsty = gtk_widget_get_style_context (weventbox); + gtk_style_context_add_provider (gsty, + GTK_STYLE_PROVIDER (css_prov), + GTK_STYLE_PROVIDER_PRIORITY_USER); + g_object_unref (css_prov); +#endif + + gtk_box_set_homogeneous (GTK_BOX (vb), FALSE); if (wimage && !text_image) gtk_box_pack_start (GTK_BOX (vb), wimage, TRUE, TRUE, 0); @@ -4283,7 +4496,6 @@ xg_make_tool_item (FRAME_PTR f, rather than the GtkButton specific signals "enter" and "leave", so we can have only one callback. The event will tell us what kind of event it is. */ - /* The EMACS_INT cast avoids a warning. */ g_signal_connect (G_OBJECT (weventbox), "enter-notify-event", G_CALLBACK (xg_tool_bar_help_callback), @@ -4299,6 +4511,24 @@ xg_make_tool_item (FRAME_PTR f, return ti; } +static int +is_box_type (GtkWidget *vb, int is_horizontal) +{ +#ifdef HAVE_GTK3 + int ret = 0; + if (GTK_IS_BOX (vb)) + { + GtkOrientation ori = gtk_orientable_get_orientation (GTK_ORIENTABLE (vb)); + ret = (ori == GTK_ORIENTATION_HORIZONTAL && is_horizontal) + || (ori == GTK_ORIENTATION_VERTICAL && ! is_horizontal); + } + return ret; +#else + return is_horizontal ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb); +#endif +} + + static int xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name, const char *icon_name, const struct image *img, @@ -4327,14 +4557,14 @@ xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name, else if (wimage) { gpointer gold_img = g_object_get_data (G_OBJECT (wimage), - XG_TOOL_BAR_IMAGE_DATA); + XG_TOOL_BAR_IMAGE_DATA); Pixmap old_img = (Pixmap) gold_img; if (old_img != img->pixmap) return 1; } /* Check button configuration and label. */ - if ((horiz ? GTK_IS_VBOX (vb) : GTK_IS_HBOX (vb)) + if (is_box_type (vb, horiz) || (label ? (wlbl == NULL) : (wlbl != NULL))) return 1; @@ -4403,26 +4633,24 @@ update_frame_tool_bar (FRAME_PTR f) int pack_tool_bar = x->handlebox_widget == NULL; Lisp_Object style; int text_image, horiz; + struct xg_frame_tb_info *tbinfo; if (! FRAME_GTK_WIDGET (f)) return; BLOCK_INPUT; - if (INTEGERP (Vtool_bar_button_margin) - && XINT (Vtool_bar_button_margin) > 0) + if (RANGED_INTEGERP (1, Vtool_bar_button_margin, INT_MAX)) { hmargin = XFASTINT (Vtool_bar_button_margin); vmargin = XFASTINT (Vtool_bar_button_margin); } else if (CONSP (Vtool_bar_button_margin)) { - if (INTEGERP (XCAR (Vtool_bar_button_margin)) - && XINT (XCAR (Vtool_bar_button_margin)) > 0) + if (RANGED_INTEGERP (1, XCAR (Vtool_bar_button_margin), INT_MAX)) hmargin = XFASTINT (XCAR (Vtool_bar_button_margin)); - if (INTEGERP (XCDR (Vtool_bar_button_margin)) - && XINT (XCDR (Vtool_bar_button_margin)) > 0) + if (RANGED_INTEGERP (1, XCDR (Vtool_bar_button_margin), INT_MAX)) vmargin = XFASTINT (XCDR (Vtool_bar_button_margin)); } @@ -4440,6 +4668,29 @@ update_frame_tool_bar (FRAME_PTR f) dir = gtk_widget_get_direction (GTK_WIDGET (wtoolbar)); style = Ftool_bar_get_system_style (); + + /* Are we up to date? */ + tbinfo = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY); + + if (! NILP (tbinfo->last_tool_bar) && ! NILP (f->tool_bar_items) + && tbinfo->n_last_items == f->n_tool_bar_items + && tbinfo->hmargin == hmargin && tbinfo->vmargin == vmargin + && tbinfo->dir == dir + && ! NILP (Fequal (tbinfo->style, style)) + && ! NILP (Fequal (tbinfo->last_tool_bar, f->tool_bar_items))) + { + UNBLOCK_INPUT; + return; + } + + tbinfo->last_tool_bar = f->tool_bar_items; + tbinfo->n_last_items = f->n_tool_bar_items; + tbinfo->style = style; + tbinfo->hmargin = hmargin; + tbinfo->vmargin = vmargin; + tbinfo->dir = dir; + text_image = EQ (style, Qtext_image_horiz); horiz = EQ (style, Qboth_horiz) || text_image; @@ -4554,7 +4805,7 @@ update_frame_tool_bar (FRAME_PTR f) ? TOOL_BAR_IMAGE_DISABLED_SELECTED : TOOL_BAR_IMAGE_DISABLED_DESELECTED); - xassert (ASIZE (image) >= idx); + eassert (ASIZE (image) >= idx); image = AREF (image, idx); } else @@ -4653,6 +4904,7 @@ free_frame_tool_bar (FRAME_PTR f) if (x->toolbar_widget) { + struct xg_frame_tb_info *tbinfo; int is_packed = x->handlebox_widget != 0; BLOCK_INPUT; /* We may have created the toolbar_widget in xg_create_tool_bar, but @@ -4674,6 +4926,16 @@ free_frame_tool_bar (FRAME_PTR f) FRAME_TOOLBAR_TOP_HEIGHT (f) = FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = 0; FRAME_TOOLBAR_LEFT_WIDTH (f) = FRAME_TOOLBAR_RIGHT_WIDTH (f) = 0; + tbinfo = g_object_get_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY); + if (tbinfo) + { + xfree (tbinfo); + g_object_set_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), + TB_INFO_KEY, + NULL); + } + xg_height_or_width_changed (f); UNBLOCK_INPUT; @@ -4714,6 +4976,7 @@ void xg_initialize (void) { GtkBindingSet *binding_set; + GtkSettings *settings; #if HAVE_XFT /* Work around a bug with corrupted data if libXft gets unloaded. This way @@ -4730,17 +4993,19 @@ xg_initialize (void) id_to_widget.max_size = id_to_widget.used = 0; id_to_widget.widgets = 0; + settings = gtk_settings_get_for_screen (gdk_display_get_default_screen + (gdk_display_get_default ())); /* Remove F10 as a menu accelerator, it does not mix well with Emacs key bindings. It doesn't seem to be any way to remove properties, so we set it to VoidSymbol which in X means "no key". */ - gtk_settings_set_string_property (gtk_settings_get_default (), + gtk_settings_set_string_property (settings, "gtk-menu-bar-accel", "VoidSymbol", EMACS_CLASS); /* Make GTK text input widgets use Emacs style keybindings. This is Emacs after all. */ - gtk_settings_set_string_property (gtk_settings_get_default (), + gtk_settings_set_string_property (settings, "gtk-key-theme-name", "Emacs", EMACS_CLASS); @@ -4757,6 +5022,8 @@ xg_initialize (void) gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK, "cancel", 0); update_theme_scrollbar_width (); + + x_last_font_name = NULL; } #endif /* USE_GTK */