From 93716e0eb6d4e99a2deee2b5dc57a2f8af0ec098 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Dj=C3=A4rv?= Date: Sun, 2 Sep 2007 16:59:23 +0000 Subject: [PATCH] (file_for_image, find_rtl_image): New functions. (xg_get_image_for_pixmap): Use file_for_image (update_frame_tool_bar): If direction is RTL, use RTL image if defined. Use Gtk stock images or named theme icons if defined. --- src/ChangeLog | 13 +++ src/gtkutil.c | 289 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 240 insertions(+), 62 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index de94c9fb0a1..ecd83610758 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,16 @@ +2007-09-02 Jan Dj,Ad(Brv + + * keyboard.c: Qrtl is new. + (parse_tool_bar_item): Handle :rtl keyword. + (syms_of_keyboard): Intern :rtl keyword. + + * dispextern.h (enum tool_bar_item_idx): Add TOOL_BAR_ITEM_RTL_IMAGE. + + * gtkutil.c: (file_for_image, find_rtl_image): New functions. + (xg_get_image_for_pixmap): Use file_for_image + (update_frame_tool_bar): If direction is RTL, use RTL image if + defined. Use Gtk stock images or named theme icons if defined. + 2007-08-29 Martin Rudalics * keyboard.h (struct kboard): New elt Vlast_repeatable_command. diff --git a/src/gtkutil.c b/src/gtkutil.c index 5ca8c8885b6..36873f23e6d 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -298,6 +298,23 @@ xg_get_pixbuf_from_pix_and_mask (gpix, gmask, cmap) return icon_buf; } +static Lisp_Object +file_for_image(image) + Lisp_Object image; +{ + Lisp_Object specified_file = Qnil; + Lisp_Object tail; + extern Lisp_Object QCfile; + + for (tail = XCDR (image); + NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail)); + tail = XCDR (XCDR (tail))) + if (EQ (XCAR (tail), QCfile)) + specified_file = XCAR (XCDR (tail)); + + return specified_file; +} + /* 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 @@ -323,16 +340,8 @@ xg_get_image_for_pixmap (f, img, widget, old_widget) /* If we have a file, let GTK do all the image handling. This seems to be the only way to make insensitive and activated icons look good in all cases. */ - Lisp_Object specified_file = Qnil; - Lisp_Object tail; + Lisp_Object specified_file = file_for_image (img->spec); Lisp_Object file; - extern Lisp_Object QCfile; - - for (tail = XCDR (img->spec); - NILP (specified_file) && CONSP (tail) && CONSP (XCDR (tail)); - tail = XCDR (XCDR (tail))) - if (EQ (XCAR (tail), QCfile)) - specified_file = XCAR (XCDR (tail)); /* We already loaded the image once before calling this function, so this only fails if the image file has been removed. @@ -865,7 +874,7 @@ xg_create_frame_widgets (f) /* Since GTK clears its window by filling with the background color, we must keep X and GTK background in sync. */ - xg_pix_to_gcolor (wfixed, f->output_data.x->background_pixel, &bg); + xg_pix_to_gcolor (wfixed, FRAME_BACKGROUND_PIXEL (f), &bg); gtk_widget_modify_bg (wfixed, GTK_STATE_NORMAL, &bg); /* Also, do not let any background pixmap to be set, this looks very @@ -2034,7 +2043,7 @@ xg_create_one_menuitem (item, f, select_cb, highlight_cb, cl_data, group) return w; } -/* Callback called when keyboard traversal (started by menu-bar-open) ends. +/* Callback called when keyboard traversal (started by x-menu-bar-open) ends. WMENU is the menu for which traversal has been done. DATA points to the frame for WMENU. We must release grabs, some bad interaction between GTK and Emacs makes the menus keep the grabs. */ @@ -3332,6 +3341,20 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) /* The key for storing the button widget in its proxy menu item. */ #define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button" +/* The key for the data we put in the GtkImage widgets. The data is + the stock name used by Emacs. We use this to see if we need to update + the GtkImage with a new image. */ +#define XG_TOOL_BAR_STOCK_NAME "emacs-tool-bar-stock-name" + +/* As above, but this is used for named theme widgets, as opposed to + stock items. */ +#define XG_TOOL_BAR_ICON_NAME "emacs-tool-bar-icon-name" + +/* Callback function invoked when a tool bar item is pressed. + W is the button widget in the tool bar that got pressed, + CLIENT_DATA is an integer that is the index of the button in the + tool bar. 0 is the first button. */ + static gboolean xg_tool_bar_button_cb (widget, event, user_data) GtkWidget *widget; @@ -3614,6 +3637,8 @@ xg_tool_bar_item_expose_callback (w, event, client_data) return FALSE; } +#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX)) + /* This callback is called when a tool bar shall be redrawn. We need to update the images in case the image cache has deleted the pixmaps used in the tool bar. @@ -3691,6 +3716,40 @@ xg_create_tool_bar (f) SET_FRAME_GARBAGED (f); } +/* Find the right-to-left image named by RTL in the tool bar images for F. + Returns IMAGE if RTL is not found. */ + +static Lisp_Object +find_rtl_image (f, image, rtl) + FRAME_PTR f; + Lisp_Object image; + Lisp_Object rtl; +{ + int i; + Lisp_Object file, rtl_name; + struct gcpro gcpro1, gcpro2; + GCPRO2 (file, rtl_name); + + rtl_name = Ffile_name_nondirectory (rtl); + + for (i = 0; i < f->n_tool_bar_items; ++i) + { + Lisp_Object rtl_image = PROP (TOOL_BAR_ITEM_IMAGES); + if (!NILP (file = file_for_image (rtl_image))) + { + file = call1 (intern ("file-name-sans-extension"), + Ffile_name_nondirectory (file)); + if (EQ (Fequal (file, rtl_name), Qt)) + { + image = rtl_image; + break; + } + } + } + + return image; +} + /* Update the tool bar for frame F. Add new buttons and remove old. */ void @@ -3701,7 +3760,9 @@ update_frame_tool_bar (f) GtkRequisition old_req, new_req; struct x_output *x = f->output_data.x; int hmargin = 0, vmargin = 0; + GtkToolbar *wtoolbar; GtkToolItem *ti; + GtkTextDirection dir; if (! FRAME_GTK_WIDGET (f)) return; @@ -3735,20 +3796,28 @@ update_frame_tool_bar (f) if (! x->toolbar_widget) xg_create_tool_bar (f); - gtk_widget_size_request (x->toolbar_widget, &old_req); + wtoolbar = GTK_TOOLBAR (x->toolbar_widget); + gtk_widget_size_request (GTK_WIDGET (wtoolbar), &old_req); + dir = gtk_widget_get_direction (x->toolbar_widget); for (i = 0; i < f->n_tool_bar_items; ++i) { -#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX)) int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); int idx; int img_id; - struct image *img; + int icon_size = 0; + struct image *img = NULL; Lisp_Object image; - GtkWidget *wbutton; + Lisp_Object stock; + GtkStockItem stock_item; + char *stock_name = NULL; + char *icon_name = NULL; + Lisp_Object rtl; + GtkWidget *wbutton = NULL; GtkWidget *weventbox; + Lisp_Object func = intern ("x-gtk-map-stock"); ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i); @@ -3758,59 +3827,125 @@ update_frame_tool_bar (f) wbutton = gtk_bin_get_child (GTK_BIN (weventbox)); } - /* If image is a vector, choose the image according to the - button state. */ image = PROP (TOOL_BAR_ITEM_IMAGES); - if (VECTORP (image)) - { - if (enabled_p) - idx = (selected_p - ? TOOL_BAR_IMAGE_ENABLED_SELECTED - : TOOL_BAR_IMAGE_ENABLED_DESELECTED); - else - idx = (selected_p - ? TOOL_BAR_IMAGE_DISABLED_SELECTED - : TOOL_BAR_IMAGE_DISABLED_DESELECTED); - - xassert (ASIZE (image) >= idx); - image = AREF (image, idx); - } - else - idx = -1; /* Ignore invalid image specifications. */ if (!valid_image_p (image)) { - if (ti) gtk_widget_hide_all (GTK_WIDGET (ti)); + if (wbutton) gtk_widget_hide (wbutton); continue; } - img_id = lookup_image (f, image); - img = IMAGE_FROM_ID (f, img_id); - prepare_image_for_display (f, img); + if (EQ (Qt, Ffboundp (func))) + stock = call1 (func, file_for_image (image)); - if (img->load_failed_p || img->pixmap == None) + if (! NILP (stock) && STRINGP (stock)) { - if (ti) - gtk_widget_hide_all (GTK_WIDGET (ti)); - else + stock_name = SSDATA (stock); + if (stock_name[0] == 'n' && stock_name[1] == ':') { - /* Insert an empty (non-image) button */ - weventbox = gtk_event_box_new (); - wbutton = gtk_button_new (); - gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE); - gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE); - gtk_container_add (GTK_CONTAINER (weventbox), wbutton); - ti = gtk_tool_item_new (); - gtk_container_add (GTK_CONTAINER (ti), weventbox); - gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1); + GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (wtoolbar)); + GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (screen); + + icon_name = stock_name + 2; + stock_name = NULL; + stock = Qnil; + + if (! gtk_icon_theme_has_icon (icon_theme, icon_name)) + icon_name = NULL; + else + icon_size = gtk_toolbar_get_icon_size (wtoolbar); + } + else if (gtk_stock_lookup (SSDATA (stock), &stock_item)) + icon_size = gtk_toolbar_get_icon_size (wtoolbar); + else + { + stock = Qnil; + stock_name = NULL; + } + } + + if (stock_name == NULL && icon_name == NULL) + { + /* No stock image, or stock item not known. Try regular image. */ + + /* If image is a vector, choose the image according to the + button state. */ + if (dir == GTK_TEXT_DIR_RTL + && !NILP (rtl = PROP (TOOL_BAR_ITEM_RTL_IMAGE)) + && STRINGP (rtl)) + { + image = find_rtl_image (f, image, rtl); + } + + if (VECTORP (image)) + { + if (enabled_p) + idx = (selected_p + ? TOOL_BAR_IMAGE_ENABLED_SELECTED + : TOOL_BAR_IMAGE_ENABLED_DESELECTED); + else + idx = (selected_p + ? TOOL_BAR_IMAGE_DISABLED_SELECTED + : TOOL_BAR_IMAGE_DISABLED_DESELECTED); + + xassert (ASIZE (image) >= idx); + image = AREF (image, idx); + } + else + idx = -1; + + img_id = lookup_image (f, image); + img = IMAGE_FROM_ID (f, img_id); + prepare_image_for_display (f, img); + + if (img->load_failed_p || img->pixmap == None) + { + if (ti) + gtk_widget_hide_all (GTK_WIDGET (ti)); + else + { + /* Insert an empty (non-image) button */ + weventbox = gtk_event_box_new (); + wbutton = gtk_button_new (); + gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE); + gtk_button_set_relief (GTK_BUTTON (wbutton), + GTK_RELIEF_NONE); + gtk_container_add (GTK_CONTAINER (weventbox), wbutton); + ti = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (ti), weventbox); + gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, -1); + } + continue; } - continue; } if (ti == NULL) { - GtkWidget *w = xg_get_image_for_pixmap (f, img, x->widget, NULL); + GtkWidget *w; + if (stock_name) + { + w = gtk_image_new_from_stock (stock_name, icon_size); + g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_STOCK_NAME, + (gpointer) xstrdup (stock_name), + (GDestroyNotify) xfree); + } + else if (icon_name) + { + w = gtk_image_new_from_icon_name (icon_name, icon_size); + g_object_set_data_full (G_OBJECT (w), XG_TOOL_BAR_ICON_NAME, + (gpointer) xstrdup (icon_name), + (GDestroyNotify) xfree); + } + else + { + w = xg_get_image_for_pixmap (f, img, x->widget, NULL); + /* Save the image so we can see if an update is needed when + this function is called again. */ + g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA, + (gpointer)img->pixmap); + } + gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin); wbutton = gtk_button_new (); gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE); @@ -3834,10 +3969,6 @@ update_frame_tool_bar (f) gtk_widget_show_all (GTK_WIDGET (ti)); - /* Save the image so we can see if an update is needed when - this function is called again. */ - g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA, - (gpointer)img->pixmap); g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f); @@ -3879,13 +4010,47 @@ update_frame_tool_bar (f) GtkWidget *wimage = gtk_bin_get_child (GTK_BIN (wbutton)); Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA); - gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin); + gpointer old_stock_name = g_object_get_data (G_OBJECT (wimage), + XG_TOOL_BAR_STOCK_NAME); + gpointer old_icon_name = g_object_get_data (G_OBJECT (wimage), + XG_TOOL_BAR_ICON_NAME); + if (stock_name && + (! old_stock_name || strcmp (old_stock_name, stock_name) != 0)) + { + gtk_image_set_from_stock (GTK_IMAGE (wimage), + stock_name, icon_size); + g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME, + (gpointer) xstrdup (stock_name), + (GDestroyNotify) xfree); + g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, + NULL); + g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL); + } + else if (icon_name && + (! old_icon_name || strcmp (old_icon_name, icon_name) != 0)) + { + gtk_image_set_from_icon_name (GTK_IMAGE (wimage), + icon_name, icon_size); + g_object_set_data_full (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, + (gpointer) xstrdup (icon_name), + (GDestroyNotify) xfree); + g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, + NULL); + g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME, + NULL); + } + else if (img && old_img != img->pixmap) + { + (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); - if (old_img != img->pixmap) - (void) xg_get_image_for_pixmap (f, img, x->widget, wimage); + g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_STOCK_NAME, + NULL); + g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_ICON_NAME, NULL); + } - g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA, - (gpointer)img->pixmap); + gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin); gtk_widget_set_sensitive (wbutton, enabled_p); gtk_widget_show_all (GTK_WIDGET (ti)); @@ -3902,7 +4067,7 @@ update_frame_tool_bar (f) if (ti) gtk_widget_hide_all (GTK_WIDGET (ti)); } while (ti != NULL); - gtk_widget_size_request (x->toolbar_widget, &new_req); + gtk_widget_size_request (GTK_WIDGET (wtoolbar), &new_req); if (old_req.height != new_req.height && ! FRAME_X_OUTPUT (f)->toolbar_detached) { -- 2.39.2