Spelling fixes.
[bpt/emacs.git] / src / gtkutil.c
index 6e54006..0b7fd41 100644 (file)
@@ -20,6 +20,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 
 #ifdef USE_GTK
+#include <float.h>
 #include <signal.h>
 #include <stdio.h>
 #include <setjmp.h>
@@ -42,6 +43,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_GTK3
 #include <gtk/gtkx.h>
+#include "emacsgtkfixed.h"
 #endif
 
 #define FRAME_TOTAL_PIXEL_HEIGHT(f) \
@@ -88,12 +90,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #define XG_BIN_CHILD(x) gtk_bin_get_child (GTK_BIN (x))
 
-/* Get the current value of the range, truncated to an integer.  */
-static int
-int_gtk_range_get_value (GtkRange *range)
-{
-  return gtk_range_get_value (range);
-}
+static void update_theme_scrollbar_width (void);
 
 \f
 /***********************************************************************
@@ -273,8 +270,8 @@ xg_get_pixbuf_from_pixmap (FRAME_PTR f, Pixmap pix)
                                       GDK_COLORSPACE_RGB,
                                       FALSE,
                                       xim->bitmap_unit,
-                                      (int) width,
-                                      (int) height,
+                                      width,
+                                      height,
                                       xim->bytes_per_line,
                                       NULL,
                                       NULL);
@@ -425,7 +422,7 @@ xg_get_image_for_pixmap (FRAME_PTR f,
 static void
 xg_set_cursor (GtkWidget *w, GdkCursor *cursor)
 {
-  GdkWindow *window = gtk_widget_get_window(w);
+  GdkWindow *window = gtk_widget_get_window (w);
   GList *children = gdk_window_peek_children (window);
 
   gdk_window_set_cursor (window, cursor);
@@ -491,7 +488,8 @@ get_utf8_string (const char *str)
   if (!utf8_str)
     {
       /* Probably some control characters in str.  Escape them. */
-      size_t nr_bad = 0;
+      ptrdiff_t len;
+      ptrdiff_t nr_bad = 0;
       gsize bytes_read;
       gsize bytes_written;
       unsigned char *p = (unsigned char *)str;
@@ -515,7 +513,10 @@ get_utf8_string (const char *str)
         }
       if (cp) g_free (cp);
 
-      up = utf8_str = xmalloc (strlen (str) + nr_bad * 4 + 1);
+      len = strlen (str);
+      if ((min (PTRDIFF_MAX, SIZE_MAX) - len - 1) / 4 < nr_bad)
+       memory_full (SIZE_MAX);
+      up = utf8_str = xmalloc (len + nr_bad * 4 + 1);
       p = (unsigned char *)str;
 
       while (! (cp = g_locale_to_utf8 ((char *)p, -1, &bytes_read,
@@ -567,7 +568,7 @@ xg_check_special_colors (struct frame *f,
     GtkStyleContext *gsty
       = gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
     GdkRGBA col;
-    char buf[64];
+    char buf[sizeof "rgbi://" + 3 * (DBL_MAX_10_EXP + sizeof "-1.000000" - 1)];
     int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
     if (get_fg)
       gtk_style_context_get_color (gsty, state, &col);
@@ -637,6 +638,9 @@ qttip_cb (GtkWidget  *widget,
   struct x_output *x = f->output_data.x;
   if (x->ttip_widget == NULL)
     {
+      GtkWidget *p;
+      GList *list, *iter;
+
       g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL);
       x->ttip_widget = tooltip;
       g_object_ref (G_OBJECT (tooltip));
@@ -644,6 +648,18 @@ qttip_cb (GtkWidget  *widget,
       g_object_ref (G_OBJECT (x->ttip_lbl));
       gtk_tooltip_set_custom (tooltip, x->ttip_lbl);
       x->ttip_window = GTK_WINDOW (gtk_widget_get_toplevel (x->ttip_lbl));
+
+      /* Change stupid Gtk+ default line wrapping.  */
+      p = gtk_widget_get_parent (x->ttip_lbl);
+      list = gtk_container_get_children (GTK_CONTAINER (p));
+      for (iter = list; iter; iter = g_list_next (iter))
+        {
+          GtkWidget *w = GTK_WIDGET (iter->data);
+          if (GTK_IS_LABEL (w))
+            gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
+        }
+      g_list_free (list);
+
       /* ATK needs an empty title for some reason.  */
       gtk_window_set_title (x->ttip_window, "");
       /* Realize so we can safely get screen later on.  */
@@ -663,8 +679,8 @@ qttip_cb (GtkWidget  *widget,
 
 int
 xg_prepare_tooltip (FRAME_PTR f,
-                      Lisp_Object string,
-                      int *width,
+                    Lisp_Object string,
+                    int *width,
                     int *height)
 {
 #ifndef USE_GTK_TOOLTIP
@@ -701,10 +717,9 @@ xg_prepare_tooltip (FRAME_PTR f,
                      (gtk_widget_get_display (GTK_WIDGET (x->ttip_window))),
                      "gdk-display-current-tooltip", NULL);
 
-  /* Put out dummy widget in so we can get callbacks for unrealize and
+  /* Put our dummy widget in so we can get callbacks for unrealize and
      hierarchy-changed.  */
   gtk_tooltip_set_custom (x->ttip_widget, widget);
-
   gtk_tooltip_set_text (x->ttip_widget, SSDATA (encoded_string));
   gtk_widget_get_preferred_size (GTK_WIDGET (x->ttip_window), NULL, &req);
   if (width) *width = req.width;
@@ -735,7 +750,7 @@ xg_show_tooltip (FRAME_PTR f, int root_x, int root_y)
 }
 
 /* Hide tooltip if shown.  Do nothing if not shown.
-   Return non-zero if tip was hidden, non-ero if not (i.e. not using
+   Return non-zero if tip was hidden, non-zero if not (i.e. not using
    system tooltips).  */
 
 int
@@ -783,7 +798,7 @@ xg_set_geometry (FRAME_PTR f)
       int xneg = f->size_hint_flags & XNegative;
       int top = f->top_pos;
       int yneg = f->size_hint_flags & YNegative;
-      char geom_str[32];
+      char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
 
       if (xneg)
         left = -left;
@@ -876,7 +891,7 @@ xg_frame_resized (FRAME_PTR f, int pixelwidth, int pixelheight)
     }
 }
 
-/* Resize the outer window of frame F after chainging the height.
+/* Resize the outer window of frame F after changing the height.
    COLUMNS/ROWS is the size the edit area shall have after the resize.  */
 
 void
@@ -972,6 +987,7 @@ xg_win_to_widget (Display *dpy, Window wdesc)
     {
       GdkEvent event;
       event.any.window = gdkwin;
+      event.any.type = GDK_NOTHING;
       gwdesc = gtk_get_event_widget (&event);
     }
 
@@ -1015,13 +1031,32 @@ style_changed_cb (GObject *go,
   struct input_event event;
   GdkDisplay *gdpy = (GdkDisplay *) user_data;
   const char *display_name = gdk_display_get_name (gdpy);
+  Display *dpy = GDK_DISPLAY_XDISPLAY (gdpy);
 
   EVENT_INIT (event);
   event.kind = CONFIG_CHANGED_EVENT;
-  event.frame_or_window = make_string (display_name, strlen (display_name));
+  event.frame_or_window = build_string (display_name);
   /* Theme doesn't change often, so intern is called seldom.  */
   event.arg = intern ("theme-name");
   kbd_buffer_store_event (&event);
+
+  update_theme_scrollbar_width ();
+
+  /* If scroll bar width changed, we need set the new size on all frames
+     on this display.  */
+  if (dpy)
+    {
+      Lisp_Object rest, frame;
+      FOR_EACH_FRAME (rest, frame)
+        {
+          FRAME_PTR f = XFRAME (frame);
+          if (FRAME_X_DISPLAY (f) == dpy)
+            {
+              x_set_scroll_bar_default_width (f);
+              xg_frame_set_char_size (f, FRAME_COLS (f), FRAME_LINES (f));
+            }
+        }
+    }
 }
 
 /* Called when a delete-event occurs on WIDGET.  */
@@ -1069,7 +1104,12 @@ xg_create_frame_widgets (FRAME_PTR f)
 
   wvbox = gtk_vbox_new (FALSE, 0);
   whbox = gtk_hbox_new (FALSE, 0);
-  wfixed = gtk_fixed_new ();  /* Must have this to place scroll bars  */
+
+#ifdef HAVE_GTK3
+  wfixed = emacs_fixed_new (f);
+#else
+  wfixed = gtk_fixed_new ();
+#endif
 
   if (! wtop || ! wvbox || ! whbox || ! wfixed)
     {
@@ -1162,6 +1202,7 @@ xg_create_frame_widgets (FRAME_PTR f)
   gtk_widget_modify_style (wfixed, style);
 #else
   gtk_widget_set_can_focus (wfixed, TRUE);
+  gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
 #endif
 
 #ifdef USE_GTK_TOOLTIP
@@ -1303,7 +1344,7 @@ x_wm_set_size_hint (FRAME_PTR f, long int flags, int user_position)
     {
       BLOCK_INPUT;
       gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-                                    NULL, &size_hints, hint_flags);
+                                     NULL, &size_hints, hint_flags);
       f->output_data.x->size_hints = size_hints;
       f->output_data.x->hint_flags = hint_flags;
       UNBLOCK_INPUT;
@@ -1382,7 +1423,7 @@ get_dialog_title (char key)
 /* Callback for dialogs that get WM_DELETE_WINDOW.  We pop down
    the dialog, but return TRUE so the event does not propagate further
    in GTK.  This prevents GTK from destroying the dialog widget automatically
-   and we can always destrou the widget manually, regardles of how
+   and we can always destroy the widget manually, regardless of how
    it was popped down (button press or WM_DELETE_WINDOW).
    W is the dialog widget.
    EVENT is the GdkEvent that represents WM_DELETE_WINDOW (not used).
@@ -1872,12 +1913,12 @@ xg_get_file_name (FRAME_PTR f,
   int filesel_done = 0;
   xg_get_file_func func;
 
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
   /* I really don't know why this is needed, but without this the GLIBC add on
      library linuxthreads hangs when the Gnome file chooser backend creates
      threads.  */
   sigblock (sigmask (__SIGRTMIN));
-#endif /* HAVE_GTK_AND_PTHREAD */
+#endif /* HAVE_PTHREAD */
 
 #ifdef HAVE_GTK_FILE_SELECTION_NEW
 
@@ -1897,7 +1938,7 @@ xg_get_file_name (FRAME_PTR f,
 
   filesel_done = xg_dialog_run (f, w);
 
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
   sigunblock (sigmask (__SIGRTMIN));
 #endif
 
@@ -1925,9 +1966,9 @@ xg_get_font_name (FRAME_PTR f, const char *default_name)
   char *fontname = NULL;
   int done = 0;
 
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
   sigblock (sigmask (__SIGRTMIN));
-#endif /* HAVE_GTK_AND_PTHREAD */
+#endif /* HAVE_PTHREAD */
 
   w = gtk_font_selection_dialog_new ("Pick a font");
   if (!default_name)
@@ -1939,7 +1980,7 @@ xg_get_font_name (FRAME_PTR f, const char *default_name)
 
   done = xg_dialog_run (f, w);
 
-#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+#if defined (HAVE_PTHREAD) && defined (__SIGRTMIN)
   sigunblock (sigmask (__SIGRTMIN));
 #endif
 
@@ -2253,7 +2294,7 @@ tearoff_activate (GtkWidget *widget, gpointer client_data)
 
 
 /* Create a menu item widget, and connect the callbacks.
-   ITEM decribes the menu item.
+   ITEM describes the menu item.
    F is the frame the created menu belongs to.
    SELECT_CB is the callback to use when a menu item is selected.
    HIGHLIGHT_CB is the callback to call when entering/leaving menu items.
@@ -3214,6 +3255,7 @@ xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
   gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
   if (! gw) return 0;
   gevent.any.window = gw;
+  gevent.any.type = GDK_NOTHING;
   gwdesc = gtk_get_event_widget (&gevent);
   if (! gwdesc) return 0;
   if (! GTK_IS_MENU_BAR (gwdesc)
@@ -3250,6 +3292,10 @@ xg_event_is_for_menubar (FRAME_PTR f, XEvent *event)
 
 int xg_ignore_gtk_scrollbar;
 
+/* The width of the scroll bar for the current theme.  */
+
+static int scroll_bar_width_for_theme;
+
 /* Xlib's `Window' 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 to get around the 32 bit limitation.  */
@@ -3257,8 +3303,8 @@ int xg_ignore_gtk_scrollbar;
 static struct
 {
   GtkWidget **widgets;
-  int max_size;
-  int used;
+  ptrdiff_t max_size;
+  ptrdiff_t used;
 } id_to_widget;
 
 /* Grow this much every time we need to allocate more  */
@@ -3267,17 +3313,20 @@ static struct
 
 /* Store the widget pointer W in id_to_widget and return the integer index.  */
 
-static int
+static ptrdiff_t
 xg_store_widget_in_map (GtkWidget *w)
 {
-  int i;
+  ptrdiff_t i;
 
   if (id_to_widget.max_size == id_to_widget.used)
     {
-      int new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
+      ptrdiff_t new_size;
+      if (TYPE_MAXIMUM (Window) - ID_TO_WIDGET_INCR < id_to_widget.max_size)
+       memory_full (SIZE_MAX);
 
-      id_to_widget.widgets = xrealloc (id_to_widget.widgets,
-                                       sizeof (GtkWidget *)*new_size);
+      new_size = id_to_widget.max_size + ID_TO_WIDGET_INCR;
+      id_to_widget.widgets = xnrealloc (id_to_widget.widgets,
+                                       new_size, sizeof (GtkWidget *));
 
       for (i = id_to_widget.max_size; i < new_size; ++i)
         id_to_widget.widgets[i] = 0;
@@ -3306,7 +3355,7 @@ xg_store_widget_in_map (GtkWidget *w)
    Called when scroll bar is destroyed.  */
 
 static void
-xg_remove_widget_from_map (int idx)
+xg_remove_widget_from_map (ptrdiff_t idx)
 {
   if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
     {
@@ -3318,7 +3367,7 @@ xg_remove_widget_from_map (int idx)
 /* Get the widget pointer at IDX from id_to_widget. */
 
 static GtkWidget *
-xg_get_widget_from_map (int idx)
+xg_get_widget_from_map (ptrdiff_t idx)
 {
   if (idx < id_to_widget.max_size && id_to_widget.widgets[idx] != 0)
     return id_to_widget.widgets[idx];
@@ -3326,13 +3375,41 @@ xg_get_widget_from_map (int idx)
   return 0;
 }
 
+static void
+update_theme_scrollbar_width (void)
+{
+#ifdef HAVE_GTK3
+  GtkAdjustment *vadj;
+#else
+  GtkObject *vadj;
+#endif
+  GtkWidget *wscroll;
+  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));
+  g_object_ref_sink (G_OBJECT (wscroll));
+  gtk_widget_style_get (wscroll, "slider-width", &w, "trough-border", &b, NULL);
+  gtk_widget_destroy (wscroll);
+  g_object_unref (G_OBJECT (wscroll));
+  w += 2*b;
+  if (w < 16) w = 16;
+  scroll_bar_width_for_theme = w;
+}
+
+int
+xg_get_default_scrollbar_width (void)
+{
+  return scroll_bar_width_for_theme;
+}
+
 /* Return the scrollbar id for X Window WID on display DPY.
    Return -1 if WID not in id_to_widget.  */
 
-int
+ptrdiff_t
 xg_get_scroll_id_for_window (Display *dpy, Window wid)
 {
-  int idx;
+  ptrdiff_t idx;
   GtkWidget *w;
 
   w = xg_win_to_widget (dpy, wid);
@@ -3354,7 +3431,7 @@ xg_get_scroll_id_for_window (Display *dpy, Window wid)
 static void
 xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
 {
-  int id = (intptr_t) data;
+  intptr_t id = (intptr_t) data;
   xg_remove_widget_from_map (id);
 }
 
@@ -3429,7 +3506,7 @@ xg_create_scroll_bar (FRAME_PTR f,
 /* Remove the scroll bar represented by SCROLLBAR_ID from the frame F.  */
 
 void
-xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id)
+xg_remove_scroll_bar (FRAME_PTR f, ptrdiff_t scrollbar_id)
 {
   GtkWidget *w = xg_get_widget_from_map (scrollbar_id);
   if (w)
@@ -3448,7 +3525,7 @@ xg_remove_scroll_bar (FRAME_PTR f, int scrollbar_id)
 
 void
 xg_update_scrollbar_pos (FRAME_PTR f,
-                         int scrollbar_id,
+                         ptrdiff_t scrollbar_id,
                          int top,
                          int left,
                          int width,
@@ -3509,6 +3586,15 @@ xg_update_scrollbar_pos (FRAME_PTR f,
     }
 }
 
+/* Get the current value of the range, truncated to an integer.  */
+
+static int
+int_gtk_range_get_value (GtkRange *range)
+{
+  return gtk_range_get_value (range);
+}
+
+
 /* Set the thumb size and position of scroll bar BAR.  We are currently
    displaying PORTION out of a whole WHOLE, and our position POSITION.  */
 
@@ -3570,7 +3656,7 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar,
              gtk_adjustment_set_page_size (adj, size);
              gtk_adjustment_set_step_increment (adj, new_step);
              /* Assume a page increment is about 95% of the page size  */
-             gtk_adjustment_set_page_increment (adj,(int) (0.95*size));
+             gtk_adjustment_set_page_increment (adj, size - size / 20);
              changed = 1;
            }
        }
@@ -4135,6 +4221,7 @@ xg_make_tool_item (FRAME_PTR f,
   GtkToolItem *ti = gtk_tool_item_new ();
   GtkWidget *vb = horiz ? gtk_hbox_new (FALSE, 0) : gtk_vbox_new (FALSE, 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 (wimage && !text_image)
@@ -4150,7 +4237,7 @@ xg_make_tool_item (FRAME_PTR f,
   gtk_container_add (GTK_CONTAINER (weventbox), wb);
   gtk_container_add (GTK_CONTAINER (ti), weventbox);
 
-  if (wimage)
+  if (wimage || label)
     {
       intptr_t ii = i;
       gpointer gi = (gpointer) ii;
@@ -4215,21 +4302,21 @@ xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
   GtkWidget *wlbl = xg_get_tool_bar_widgets (vb, &wimage);
 
   /* Check if the tool icon matches.  */
-  if (stock_name)
+  if (stock_name && wimage)
     {
       old = g_object_get_data (G_OBJECT (wimage),
                               XG_TOOL_BAR_STOCK_NAME);
       if (!old || strcmp (old, stock_name))
        return 1;
     }
-  else if (icon_name)
+  else if (icon_name && wimage)
     {
       old = g_object_get_data (G_OBJECT (wimage),
                               XG_TOOL_BAR_ICON_NAME);
       if (!old || strcmp (old, icon_name))
        return 1;
     }
-  else
+  else if (wimage)
     {
       gpointer gold_img = g_object_get_data (G_OBJECT (wimage),
                                            XG_TOOL_BAR_IMAGE_DATA);
@@ -4244,7 +4331,7 @@ xg_tool_item_stale_p (GtkWidget *wbutton, const char *stock_name,
     return 1;
 
   /* Ensure label is correct.  */
-  if (label)
+  if (label && wlbl)
     gtk_label_set_text (GTK_LABEL (wlbl), label);
   return 0;
 }
@@ -4353,7 +4440,7 @@ update_frame_tool_bar (FRAME_PTR f)
       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;
+      ptrdiff_t img_id;
       int icon_size = 0;
       struct image *img = NULL;
       Lisp_Object image;
@@ -4661,6 +4748,7 @@ xg_initialize (void)
                                           (GTK_TYPE_MENU_SHELL));
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_g, GDK_CONTROL_MASK,
                                 "cancel", 0);
+  update_theme_scrollbar_width ();
 }
 
 #endif /* USE_GTK */