(fontset_find_font): Check if rfont_def is Qnil or not.
[bpt/emacs.git] / src / gtkutil.c
index 140796a..41f2518 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions for creating and updating GTK widgets.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -53,13 +53,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_GTK_MULTIDISPLAY
 
-/* Gtk does not work well without any display open.  Emacs may close
-   all its displays.  In that case, keep a display around just for
-   the purpose of having one.  */
+/* Keep track of the default display, or NULL if there is none.  Emacs
+   may close all its displays.  */
 
 static GdkDisplay *gdpy_def;
 
-
 /* Return the GdkDisplay that corresponds to the X display DPY.  */
 
 static GdkDisplay *
@@ -121,8 +119,14 @@ xg_display_open (display_name, dpy)
   GdkDisplay *gdpy;
 
   gdpy = gdk_display_open (display_name);
-  *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
+  if (!gdpy_def && gdpy)
+    {
+      gdpy_def = gdpy;
+      gdk_display_manager_set_default_display (gdk_display_manager_get (),
+                                              gdpy);
+    }
 
+  *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
   return gdpy != NULL;
 
 #else /* not HAVE_GTK_MULTIDISPLAY */
@@ -140,40 +144,30 @@ xg_display_close (Display *dpy)
 #ifdef HAVE_GTK_MULTIDISPLAY
   GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
 
-  /* If this is the default display, we must change it before calling
-     dispose, otherwise it will crash on some Gtk+ versions.  */
+  /* If this is the default display, try to change it before closing.
+     If there is no other display to use, gdpy_def is set to NULL, and
+     the next call to xg_display_open resets the default display.  */
   if (gdk_display_get_default () == gdpy)
     {
       struct x_display_info *dpyinfo;
-      Display *new_dpy = 0;
-      GdkDisplay *gdpy_new;
+      GdkDisplay *gdpy_new = NULL;
 
       /* Find another display.  */
       for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
         if (dpyinfo->display != dpy)
           {
-            new_dpy = dpyinfo->display;
+           gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
+           gdk_display_manager_set_default_display (gdk_display_manager_get (),
+                                                    gdpy_new);
             break;
           }
-
-      if (new_dpy)
-        gdpy_new = gdk_x11_lookup_xdisplay (new_dpy);
-      else
-        {
-          if (!gdpy_def)
-            gdpy_def = gdk_display_open (gdk_display_get_name (gdpy));
-          gdpy_new = gdpy_def;
-        }
-
-      gdk_display_manager_set_default_display (gdk_display_manager_get (),
-                                               gdpy_new);
+      gdpy_def = gdpy_new;
     }
 
-  /* GTK 2.2-2.8 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 < 10
+  /* GTK 2.2-2.8 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.  */
   g_object_run_dispose (G_OBJECT (gdpy));
 #else
   /* This seems to be fixed in GTK 2.10. */
@@ -233,7 +227,7 @@ free_widget_value (wv)
     {
       /* When the number of already allocated cells is too big,
         We free it.  */
-      free (wv);
+      xfree (wv);
       malloc_cpt--;
     }
   else
@@ -531,7 +525,7 @@ get_utf8_string (str)
   if (!g_utf8_validate (str, -1, NULL))
     utf8_str = g_locale_to_utf8 (str, -1, 0, 0, 0);
 
-  if (!utf8_str) 
+  if (!utf8_str)
     {
       /* Probably some control characters in str.  Escape them. */
       size_t nr_bad = 0;
@@ -551,7 +545,7 @@ get_utf8_string (str)
           error = NULL;
         }
 
-      if (error) 
+      if (error)
         {
           g_error_free (error);
           error = NULL;
@@ -574,12 +568,12 @@ get_utf8_string (str)
           error = NULL;
         }
 
-      if (cp) 
+      if (cp)
         {
           strcat (utf8_str, cp);
           g_free (cp);
         }
-      if (error) 
+      if (error)
         {
           g_error_free (error);
           error = NULL;
@@ -655,14 +649,9 @@ xg_frame_resized (f, pixelwidth, pixelheight)
       FRAME_PIXEL_WIDTH (f) = pixelwidth;
       FRAME_PIXEL_HEIGHT (f) = pixelheight;
 
-      if (rows != FRAME_LINES (f) || columns != FRAME_COLS (f)
-          || (f->new_text_lines != 0 && f->new_text_lines != rows)
-          || (f->new_text_cols != 0 && f->new_text_cols != columns))
-        {
-          change_frame_size (f, rows, columns, 0, 1, 0);
-          SET_FRAME_GARBAGED (f);
-          cancel_mouse_face (f);
-        }
+      change_frame_size (f, rows, columns, 0, 1, 0);
+      SET_FRAME_GARBAGED (f);
+      cancel_mouse_face (f);
     }
 }
 
@@ -934,97 +923,95 @@ x_wm_set_size_hint (f, flags, user_position)
      long flags;
      int user_position;
 {
-  if (FRAME_GTK_OUTER_WIDGET (f))
-  {
-    /* Must use GTK routines here, otherwise GTK resets the size hints
-       to its own defaults.  */
-    GdkGeometry size_hints;
-    gint hint_flags = 0;
-    int base_width, base_height;
-    int min_rows = 0, min_cols = 0;
-    int win_gravity = f->win_gravity;
-
-    if (flags)
-      {
-        memset (&size_hints, 0, sizeof (size_hints));
-        f->output_data.x->size_hints = size_hints;
-        f->output_data.x->hint_flags = hint_flags;
-      }
-     else
-       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 = FRAME_COLUMN_WIDTH (f);
-    size_hints.height_inc = FRAME_LINE_HEIGHT (f);
-
-    hint_flags |= GDK_HINT_BASE_SIZE;
-    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);
-
-    size_hints.base_width = base_width;
-    size_hints.base_height = base_height;
-    size_hints.min_width  = base_width + min_cols * size_hints.width_inc;
-    size_hints.min_height = base_height + min_rows * size_hints.height_inc;
-
-
-    /* These currently have a one to one mapping with the X values, but I
-       don't think we should rely on that.  */
-    hint_flags |= GDK_HINT_WIN_GRAVITY;
-    size_hints.win_gravity = 0;
-    if (win_gravity == NorthWestGravity)
-      size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
-    else if (win_gravity == NorthGravity)
-      size_hints.win_gravity = GDK_GRAVITY_NORTH;
-    else if (win_gravity == NorthEastGravity)
-      size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
-    else if (win_gravity == WestGravity)
-      size_hints.win_gravity = GDK_GRAVITY_WEST;
-    else if (win_gravity == CenterGravity)
-      size_hints.win_gravity = GDK_GRAVITY_CENTER;
-    else if (win_gravity == EastGravity)
-      size_hints.win_gravity = GDK_GRAVITY_EAST;
-    else if (win_gravity == SouthWestGravity)
-      size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
-    else if (win_gravity == SouthGravity)
-      size_hints.win_gravity = GDK_GRAVITY_SOUTH;
-    else if (win_gravity == SouthEastGravity)
-      size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
-    else if (win_gravity == StaticGravity)
-      size_hints.win_gravity = GDK_GRAVITY_STATIC;
-
-    if (flags & PPosition) hint_flags |= GDK_HINT_POS;
-    if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
-    if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
-
-    if (user_position)
-      {
-        hint_flags &= ~GDK_HINT_POS;
-        hint_flags |= GDK_HINT_USER_POS;
-      }
+  /* Don't set size hints during initialization; that apparently leads
+     to a race condition.  See the thread at
+     http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html  */
+  if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
+    return;
 
-    if (hint_flags != f->output_data.x->hint_flags
-        || memcmp (&size_hints,
-                   &f->output_data.x->size_hints,
-                   sizeof (size_hints)) != 0)
-      {
-        BLOCK_INPUT;
+  /* Must use GTK routines here, otherwise GTK resets the size hints
+     to its own defaults.  */
+  GdkGeometry size_hints;
+  gint hint_flags = 0;
+  int base_width, base_height;
+  int min_rows = 0, min_cols = 0;
+  int win_gravity = f->win_gravity;
 
-        gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-                                       NULL,
-                                       &size_hints,
-                                       hint_flags);
+  if (flags)
+    {
+      memset (&size_hints, 0, sizeof (size_hints));
+      f->output_data.x->size_hints = size_hints;
+      f->output_data.x->hint_flags = hint_flags;
+    }
+  else
+    flags = f->size_hint_flags;
 
-        f->output_data.x->size_hints = size_hints;
-        f->output_data.x->hint_flags = hint_flags;
-        UNBLOCK_INPUT;
-      }
-  }
+  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 = FRAME_COLUMN_WIDTH (f);
+  size_hints.height_inc = FRAME_LINE_HEIGHT (f);
+
+  hint_flags |= GDK_HINT_BASE_SIZE;
+  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);
+
+  size_hints.base_width = base_width;
+  size_hints.base_height = base_height;
+  size_hints.min_width  = base_width + min_cols * size_hints.width_inc;
+  size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+
+  /* These currently have a one to one mapping with the X values, but I
+     don't think we should rely on that.  */
+  hint_flags |= GDK_HINT_WIN_GRAVITY;
+  size_hints.win_gravity = 0;
+  if (win_gravity == NorthWestGravity)
+    size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
+  else if (win_gravity == NorthGravity)
+    size_hints.win_gravity = GDK_GRAVITY_NORTH;
+  else if (win_gravity == NorthEastGravity)
+    size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
+  else if (win_gravity == WestGravity)
+    size_hints.win_gravity = GDK_GRAVITY_WEST;
+  else if (win_gravity == CenterGravity)
+    size_hints.win_gravity = GDK_GRAVITY_CENTER;
+  else if (win_gravity == EastGravity)
+    size_hints.win_gravity = GDK_GRAVITY_EAST;
+  else if (win_gravity == SouthWestGravity)
+    size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
+  else if (win_gravity == SouthGravity)
+    size_hints.win_gravity = GDK_GRAVITY_SOUTH;
+  else if (win_gravity == SouthEastGravity)
+    size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
+  else if (win_gravity == StaticGravity)
+    size_hints.win_gravity = GDK_GRAVITY_STATIC;
+
+  if (flags & PPosition) hint_flags |= GDK_HINT_POS;
+  if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
+  if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
+
+  if (user_position)
+    {
+      hint_flags &= ~GDK_HINT_POS;
+      hint_flags |= GDK_HINT_USER_POS;
+    }
+
+  if (hint_flags != f->output_data.x->hint_flags
+      || memcmp (&size_hints,
+                &f->output_data.x->size_hints,
+                sizeof (size_hints)) != 0)
+    {
+      BLOCK_INPUT;
+      gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+                                    NULL, &size_hints, hint_flags);
+      f->output_data.x->size_hints = size_hints;
+      f->output_data.x->hint_flags = hint_flags;
+      UNBLOCK_INPUT;
+    }
 }
 
 /* Change background color of a frame.
@@ -1409,8 +1396,8 @@ xg_get_file_with_chooser (f, prompt, default_filename,
   wbox = gtk_vbox_new (FALSE, 0);
   gtk_widget_show (wbox);
   wtoggle = gtk_check_button_new_with_label ("Show hidden files.");
-  
-  if (x_gtk_show_hidden_files) 
+
+  if (x_gtk_show_hidden_files)
     {
       g_object_set (G_OBJECT (filewin), "show-hidden", TRUE, NULL);
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), TRUE);
@@ -1431,7 +1418,7 @@ xg_get_file_with_chooser (f, prompt, default_filename,
       strcat (message, "\nIf you don't like this file selector, use the "
               "corresponding\nkey binding or customize "
               "use-file-dialog to turn it off.");
-    
+
       wmessage = gtk_label_new (message);
       gtk_widget_show (wmessage);
     }
@@ -1454,7 +1441,7 @@ xg_get_file_with_chooser (f, prompt, default_filename,
          an absolute name starting with /.  */
       if (default_filename[0] != '/')
         file = Fexpand_file_name (file, Qnil);
-      
+
       utf8_filename = SSDATA (ENCODE_UTF_8 (file));
       if (! NILP (Ffile_directory_p (file)))
         gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin),
@@ -2604,7 +2591,7 @@ xg_update_menubar (menubar, f, list, iter, pos, val,
 /* Update the menu item W so it corresponds to VAL.
    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.
-   CL_DATA is the data to set in the widget for menu invokation.  */
+   CL_DATA is the data to set in the widget for menu invocation.  */
 
 static void
 xg_update_menu_item (val, w, select_cb, highlight_cb, cl_data)
@@ -3150,7 +3137,7 @@ 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.
+   the scroll bar repetition timer in GTK gets handled.
    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.
@@ -3466,17 +3453,21 @@ xg_tool_bar_callback (w, client_data)
      to `(tool_bar)', see keyboard.c.  */
   event.kind = TOOL_BAR_EVENT;
   event.frame_or_window = frame;
-  event.arg = frame;    
-  kbd_buffer_store_event (&event);      
-  
-  event.kind = TOOL_BAR_EVENT;          
+  event.arg = frame;
+  kbd_buffer_store_event (&event);
+
+  event.kind = TOOL_BAR_EVENT;
   event.frame_or_window = frame;
   event.arg = key;
   /* Convert between the modifier bits GDK uses and the modifier bits
-     Emacs uses.  This assumes GDK an X masks are the same, which they are when
+     Emacs uses.  This assumes GDK and X masks are the same, which they are when
      this is written.  */
   event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
   kbd_buffer_store_event (&event);
+   /* Return focus to the frame after we have clicked on a detached
+      tool bar button. */
+   Fx_focus_frame (frame);
 }
 
 /* Callback function invoked when a tool bar item is pressed in a detached
@@ -3494,6 +3485,8 @@ xg_tool_bar_proxy_callback (w, client_data)
   GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
                                                       XG_TOOL_BAR_PROXY_BUTTON));
   xg_tool_bar_callback (wbutton, client_data);
+  FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (wbutton),
+                                               XG_FRAME_DATA);
 }
 
 /* This callback is called when a tool item should create a proxy item,
@@ -3511,7 +3504,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
   GtkWidget *wmenuitem = gtk_image_menu_item_new ();
   GtkWidget *wmenuimage;
 
-  if (gtk_button_get_use_stock (wbutton)) 
+  if (gtk_button_get_use_stock (wbutton))
     wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
                                            GTK_ICON_SIZE_MENU);
   else
@@ -3536,7 +3529,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
       else if (store_type == GTK_IMAGE_PIXBUF)
         {
           gint width, height;
-      
+
           if (settings &&
               gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
                                                  &width, &height))
@@ -3555,7 +3548,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
               abort ();
             }
         }
-      else if (store_type == GTK_IMAGE_ICON_NAME) 
+      else if (store_type == GTK_IMAGE_ICON_NAME)
         {
           const gchar *icon_name;
           GtkIconSize icon_size;
@@ -3575,7 +3568,7 @@ xg_tool_bar_menu_proxy (toolitem, user_data)
 
   g_signal_connect (G_OBJECT (wmenuitem),
                     "activate",
-                    GTK_SIGNAL_FUNC (xg_tool_bar_proxy_callback),
+                    G_CALLBACK (xg_tool_bar_proxy_callback),
                     user_data);
 
   g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
@@ -3797,7 +3790,7 @@ find_rtl_image (f, image, 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))) 
+      if (!NILP (file = file_for_image (rtl_image)))
         {
           file = call1 (intern ("file-name-sans-extension"),
                        Ffile_name_nondirectory (file));
@@ -3873,7 +3866,7 @@ update_frame_tool_bar (f)
       int icon_size = 0;
       struct image *img = NULL;
       Lisp_Object image;
-      Lisp_Object stock;
+      Lisp_Object stock = Qnil;
       GtkStockItem stock_item;
       char *stock_name = NULL;
       char *icon_name = NULL;
@@ -3923,7 +3916,7 @@ update_frame_tool_bar (f)
             }
           else if (gtk_stock_lookup (SSDATA (stock), &stock_item))
               icon_size = gtk_toolbar_get_icon_size (wtoolbar);
-          else 
+          else
             {
               stock = Qnil;
               stock_name = NULL;
@@ -3963,7 +3956,7 @@ update_frame_tool_bar (f)
           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)
@@ -3995,7 +3988,7 @@ update_frame_tool_bar (f)
                                       (gpointer) xstrdup (stock_name),
                                       (GDestroyNotify) xfree);
             }
-          else if (icon_name) 
+          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,
@@ -4025,11 +4018,11 @@ update_frame_tool_bar (f)
 
           /* The EMACS_INT cast avoids a warning. */
           g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
-                            GTK_SIGNAL_FUNC (xg_tool_bar_menu_proxy),
+                            G_CALLBACK (xg_tool_bar_menu_proxy),
                             (gpointer) (EMACS_INT) i);
 
           g_signal_connect (G_OBJECT (wbutton), "clicked",
-                            GTK_SIGNAL_FUNC (xg_tool_bar_callback),
+                            G_CALLBACK (xg_tool_bar_callback),
                             (gpointer) (EMACS_INT) i);
 
           gtk_widget_show_all (GTK_WIDGET (ti));
@@ -4046,12 +4039,12 @@ update_frame_tool_bar (f)
 
           gtk_widget_set_sensitive (wbutton, enabled_p);
           gtk_tool_item_set_homogeneous (ti, FALSE);
-          
+
           /* Callback to save modifyer mask (Shift/Control, etc).  GTK makes
              no distinction based on modifiers in the activate callback,
              so we have to do it ourselves.  */
           g_signal_connect (wbutton, "button-release-event",
-                            GTK_SIGNAL_FUNC (xg_tool_bar_button_cb),
+                            G_CALLBACK (xg_tool_bar_button_cb),
                             NULL);
 
           g_object_set_data (G_OBJECT (wbutton), XG_FRAME_DATA, (gpointer)f);
@@ -4224,12 +4217,13 @@ xg_initialize ()
 
   /* Make dialogs close on C-g.  Since file dialog inherits from
      dialog, this works for them also.  */
-  binding_set = gtk_binding_set_by_class (gtk_type_class (GTK_TYPE_DIALOG));
+  binding_set = gtk_binding_set_by_class (g_type_class_ref (GTK_TYPE_DIALOG));
   gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
                                 "close", 0);
 
   /* Make menus close on C-g.  */
-  binding_set = gtk_binding_set_by_class (gtk_type_class (GTK_TYPE_MENU_SHELL));
+  binding_set = gtk_binding_set_by_class (g_type_class_ref
+                                          (GTK_TYPE_MENU_SHELL));
   gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK,
                                 "cancel", 0);
 }