Simplify redefinition of 'abort' (Bug#12316).
[bpt/emacs.git] / src / gtkutil.c
index 4879479..3bce5be 100644 (file)
@@ -24,6 +24,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <signal.h>
 #include <stdio.h>
 #include <setjmp.h>
+
+#include <c-ctype.h>
+
 #include "lisp.h"
 #include "xterm.h"
 #include "blockinput.h"
@@ -75,6 +78,18 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #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)
@@ -98,6 +113,16 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 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;
+};
+
 \f
 /***********************************************************************
                       Display handling functions
@@ -229,7 +254,7 @@ void
 free_widget_value (widget_value *wv)
 {
   if (wv->free_list)
-    abort ();
+    emacs_abort ();
 
   if (malloc_cpt > 25)
     {
@@ -1265,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;
@@ -1317,13 +1348,14 @@ 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);
-  /* Use one row here so base_height does not become zero.
+  /* 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;
@@ -1979,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:
@@ -1989,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)
@@ -2015,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 */
 
@@ -2122,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);
@@ -2133,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);
+            }
+        }
+    }
 }
 
 
@@ -3379,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.
@@ -3947,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)
@@ -3962,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)
@@ -4208,6 +4348,21 @@ xg_create_tool_bar (FRAME_PTR f)
 #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;
@@ -4245,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;
@@ -4478,6 +4633,7 @@ 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;
@@ -4512,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;
 
@@ -4725,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
@@ -4746,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;
@@ -4832,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 */