]> code.delx.au - gnu-emacs/blobdiff - src/xfns.c
Reformat copyright line.
[gnu-emacs] / src / xfns.c
index ed068b1ca23aed41daca0882502234d81bbde41a..6f18e4e813a5780b94d2344334d3e88bb2a75bb5 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions for the X window system.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-                 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+                 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -21,6 +21,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 #include <stdio.h>
 #include <math.h>
+#include <setjmp.h>
+#include <ctype.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -62,6 +64,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <X11/bitmaps/gray>
 #endif
 
+#include "xsettings.h"
+
 #ifdef USE_GTK
 #include "gtkutil.h"
 #endif
@@ -97,13 +101,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <Xm/FileSB.h>
 #endif
 
-/* Do the EDITRES protocol if running X11R5
-   Exception: HP-UX (at least version A.09.05) has X11R5 without EditRes */
-
-#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
+#if !defined(NO_EDITRES)
 #define HACK_EDITRES
 extern void _XEditResCheckMessages ();
-#endif /* R5 + Athena */
+#endif /* not defined NO_EDITRES */
 
 /* Unique id counter for widgets created by the Lucid Widget Library.  */
 
@@ -196,7 +197,7 @@ Lisp_Object Qnone;
 Lisp_Object Qsuppress_icon;
 Lisp_Object Qundefined_color;
 Lisp_Object Qcompound_text, Qcancel_timer;
-static Lisp_Object Qfont_param;
+Lisp_Object Qfont_param;
 
 /* In dispnew.c */
 
@@ -377,10 +378,7 @@ x_any_window_to_frame (dpyinfo, wdesc)
 #ifdef USE_GTK
               GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
               if (gwdesc != 0
-                  && (gwdesc == x->widget
-                      || gwdesc == x->edit_widget
-                      || gwdesc == x->vbox_widget
-                      || gwdesc == x->menubar_widget))
+                  && gtk_widget_get_toplevel (gwdesc) == x->widget)
                 found = f;
 #else
              if (wdesc == XtWindow (x->widget)
@@ -401,54 +399,6 @@ x_any_window_to_frame (dpyinfo, wdesc)
   return found;
 }
 
-/* Likewise, but exclude the menu bar widget.  */
-
-struct frame *
-x_non_menubar_window_to_frame (dpyinfo, wdesc)
-     struct x_display_info *dpyinfo;
-     int wdesc;
-{
-  Lisp_Object tail, frame;
-  struct frame *f;
-  struct x_output *x;
-
-  if (wdesc == None) return 0;
-
-  for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
-    {
-      frame = XCAR (tail);
-      if (!FRAMEP (frame))
-        continue;
-      f = XFRAME (frame);
-      if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
-       continue;
-      x = f->output_data.x;
-      /* This frame matches if the window is any of its widgets.  */
-      if (x->hourglass_window == wdesc)
-       return f;
-      else if (x->widget)
-       {
-#ifdef USE_GTK
-          GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
-          if (gwdesc != 0
-              && (gwdesc == x->widget
-                  || gwdesc == x->edit_widget
-                  || gwdesc == x->vbox_widget))
-            return f;
-#else
-         if (wdesc == XtWindow (x->widget)
-             || wdesc == XtWindow (x->column_widget)
-             || wdesc == XtWindow (x->edit_widget))
-           return f;
-#endif
-       }
-      else if (FRAME_X_WINDOW (f) == wdesc)
-       /* A tooltip frame.  */
-       return f;
-    }
-  return 0;
-}
-
 /* Likewise, but consider only the menu bar widget.  */
 
 struct frame *
@@ -476,15 +426,14 @@ x_menubar_window_to_frame (dpyinfo, wdesc)
       if (x->menubar_widget)
         {
           GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc);
-          int found = 0;
 
-          BLOCK_INPUT;
+         /* This gives false positives, but the rectangle check in xterm.c
+            where this is called takes care of that.  */
           if (gwdesc != 0
               && (gwdesc == x->menubar_widget
-                  || gtk_widget_get_parent (gwdesc) == x->menubar_widget))
-            found = 1;
-          UNBLOCK_INPUT;
-          if (found) return f;
+                  || gtk_widget_is_ancestor (x->menubar_widget, gwdesc)
+                 || gtk_widget_is_ancestor (gwdesc, x->menubar_widget)))
+            return f;
         }
 #else
       if (x->menubar_widget
@@ -1368,7 +1317,43 @@ x_set_menu_bar_lines (f, value, oldval)
 #else /* not USE_X_TOOLKIT && not USE_GTK */
   FRAME_MENU_BAR_LINES (f) = nlines;
   change_window_heights (f->root_window, nlines - olines);
-#endif /* not USE_X_TOOLKIT */
+
+  /* If the menu bar height gets changed, the internal border below
+     the top margin has to be cleared.  Also, if the menu bar gets
+     larger, the area for the added lines has to be cleared except for
+     the first menu bar line that is to be drawn later.  */
+  if (nlines != olines)
+    {
+      int height = FRAME_INTERNAL_BORDER_WIDTH (f);
+      int width = FRAME_PIXEL_WIDTH (f);
+      int y;
+
+      /* height can be zero here. */
+      if (height > 0 && width > 0)
+       {
+         y = FRAME_TOP_MARGIN_HEIGHT (f);
+
+         BLOCK_INPUT;
+         x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                       0, y, width, height, False);
+         UNBLOCK_INPUT;
+       }
+
+      if (nlines > 1 && nlines > olines)
+       {
+         y = (olines == 0 ? 1 : olines) * FRAME_LINE_HEIGHT (f);
+         height = nlines * FRAME_LINE_HEIGHT (f) - y;
+
+         BLOCK_INPUT;
+         x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                       0, y, width, height, False);
+         UNBLOCK_INPUT;
+       }
+
+      if (nlines == 0 && WINDOWP (f->menu_bar_window))
+       clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix);
+    }
+#endif /* not USE_X_TOOLKIT && not USE_GTK */
   adjust_glyphs (f);
 }
 
@@ -1454,7 +1439,7 @@ x_set_tool_bar_lines (f, value, oldval)
     {
       int height = FRAME_INTERNAL_BORDER_WIDTH (f);
       int width = FRAME_PIXEL_WIDTH (f);
-      int y = nlines * FRAME_LINE_HEIGHT (f);
+      int y = (FRAME_MENU_BAR_LINES (f) + nlines) * FRAME_LINE_HEIGHT (f);
 
       /* height can be zero here. */
       if (height > 0 && width > 0)
@@ -2939,14 +2924,6 @@ x_icon (f, parms)
    background, border and mouse colors; also create the
    mouse cursor and the gray border tile.  */
 
-static char cursor_bits[] =
-  {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-  };
-
 static void
 x_make_gc (f)
      struct frame *f;
@@ -3005,7 +2982,7 @@ x_make_gc (f)
 }
 
 
-/* Free what was was allocated in x_make_gc.  */
+/* Free what was allocated in x_make_gc.  */
 
 void
 x_free_gcs (f)
@@ -3087,10 +3064,22 @@ x_default_font_parameter (f, parms)
 {
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
   Lisp_Object font_param = x_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
-                               RES_TYPE_STRING);
+                                      RES_TYPE_STRING);
   Lisp_Object font;
+  int got_from_gconf = 0;
   if (EQ (font_param, Qunbound))
     font_param = Qnil;
+
+  if (NILP (font_param))
+    {
+      /* System font takes precedendce over X resources.  We must suggest this
+         regardless of font-use-system-font because .emacs may not have been
+         read yet.  */
+      const char *system_font = xsettings_get_system_font ();
+      if (system_font) font_param = make_string (system_font,
+                                                 strlen (system_font));
+    }
+  
   font = !NILP (font_param) ? font_param
     : x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
 
@@ -3130,7 +3119,11 @@ x_default_font_parameter (f, parms)
         we've applied the `default' face settings.  */
       x_set_frame_parameters (f, Fcons (Fcons (Qfont_param, font_param), Qnil));
     }
-  x_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING);
+
+  x_default_parameter (f, parms, Qfont, font,
+                       got_from_gconf ? NULL : "font",
+                       got_from_gconf ? NULL : "Font",
+                       RES_TYPE_STRING);
 }
 
 
@@ -3152,6 +3145,91 @@ If FRAME is nil, use the selected frame.  */)
   return Qnil;
 }
 
+/* Return current desktop index for the display where frame F is.
+   If we can't find out the current desktop, return 0.  */
+
+static int
+x_get_current_desktop (f)
+     struct frame *f;
+{
+  Atom actual_type;
+  unsigned long actual_size, bytes_remaining;
+  int rc, actual_format;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  long max_len = 10;
+  Display *dpy = FRAME_X_DISPLAY (f);
+  long *data = NULL;
+  int current_desktop;
+
+  BLOCK_INPUT;
+  x_catch_errors (dpy);
+  rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+                           XInternAtom (dpy, "_NET_CURRENT_DESKTOP", False),
+                           0, max_len, False, XA_CARDINAL,
+                           &actual_type, &actual_format, &actual_size,
+                           &bytes_remaining, (unsigned char **)&data);
+
+  if (rc != Success || actual_type != XA_CARDINAL || x_had_errors_p (dpy)
+      || actual_size == 0 || actual_format != 32)
+    current_desktop = 0;
+  else
+    current_desktop = (int)*data;
+
+  if (data) XFree (data);
+  x_uncatch_errors ();
+  UNBLOCK_INPUT;
+  return current_desktop;
+}
+
+/* Return current size for DESKTOP_INDEX on the display where frame F is.
+   If we can't find out the size, return 0, otherwise 1.  */
+
+static int
+x_get_desktop_workarea (f, desktop_index, deskw, deskh)
+     struct frame *f;
+     int desktop_index;
+     int *deskw, *deskh;
+{
+  Atom actual_type;
+  unsigned long actual_size, bytes_remaining;
+  int rc, actual_format;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  long max_len = 1000; /* This handles 250 desktops, who has that many?  */
+  Display *dpy = FRAME_X_DISPLAY (f);
+  long *data = NULL;
+  int retval;
+
+  BLOCK_INPUT;
+  x_catch_errors (dpy);
+  rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+                           XInternAtom (dpy, "_NET_WORKAREA", False),
+                           0, max_len, False, XA_CARDINAL,
+                           &actual_type, &actual_format, &actual_size,
+                           &bytes_remaining, (unsigned char **)&data);
+
+  if (rc != Success || actual_type != XA_CARDINAL || x_had_errors_p (dpy)
+      || actual_size < 3 || actual_format != 32)
+    retval = 0;
+  else
+    {
+      int idx;
+      
+      if (actual_size == 4 /* Only one info for all desktops.  */
+          || desktop_index*4 > actual_size) /* destop_index out of range.  */
+        desktop_index = 0;
+
+      idx = desktop_index*4;
+      *deskw = data[idx+2] - data[idx];
+      *deskh = data[idx+3] - data[idx+1];
+      retval = 1;
+    }
+  
+  if (data) XFree (data);
+  x_uncatch_errors ();
+  UNBLOCK_INPUT;
+  return retval;
+}
+
 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
        1, 1, 0,
        doc: /* Make a new X window, which is called a "frame" in Emacs terms.
@@ -3171,7 +3249,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
   Lisp_Object name;
   int minibuffer_only = 0;
   long window_prompting = 0;
-  int width, height;
+  int width, height, deskw = -1, deskh = -1, current_desktop = -1;
   int count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   Lisp_Object display;
@@ -3439,6 +3517,58 @@ This function is an internal primitive--use `make-frame' instead.  */)
   /* Compute the size of the X window.  */
   window_prompting = x_figure_window_size (f, parms, 1);
 
+  /* Don't make height higher than display height unless the user asked
+     for it.  */
+  height = FRAME_LINES (f);
+  tem = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
+  if (EQ (tem, Qunbound))
+    {
+      int ph = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
+      int dph = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
+      /* Some desktops have fixed menus above and/or panels below.  Try to
+         figure out the usable size we have for emacs.  */
+      current_desktop = x_get_current_desktop (f);
+      x_get_desktop_workarea (f, current_desktop, &deskw, &deskh);
+      if (deskh > 0 && deskh < dph) dph = deskh;
+      
+      if (ph > dph)
+        {
+          height = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, dph) -
+            FRAME_TOOL_BAR_LINES (f) - FRAME_MENU_BAR_LINES (f);
+          if (FRAME_EXTERNAL_TOOL_BAR (f))
+            height -= 2; /* We can't know how big it will be.  */
+          if (FRAME_EXTERNAL_MENU_BAR (f))
+            height -= 2; /* We can't know how big it will be.  */
+        }
+    }
+
+  /* Don't make width wider than display width unless the user asked
+     for it.  */
+  width = FRAME_COLS (f);
+  tem = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
+  if (EQ (tem, Qunbound))
+    {
+      int pw = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, FRAME_COLS (f));
+      int dpw = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
+      if (deskw == -1)
+        {
+          current_desktop = x_get_current_desktop (f);
+          x_get_desktop_workarea (f, current_desktop, &deskw, &deskh);
+        }
+      if (deskw > 0 && deskw < dpw) dpw = deskw;
+      
+      if (pw > dpw)
+        width = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, dpw);
+    }
+
+  if (height != FRAME_LINES (f) || width != FRAME_COLS (f))
+    {
+      check_frame_size (f, &height, &width);
+      FRAME_LINES (f) = height;
+      SET_FRAME_COLS (f, width);
+    }
+  
+
   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
   f->no_split = minibuffer_only || EQ (tem, Qt);
 
@@ -4868,6 +4998,7 @@ x_create_tip_frame (dpyinfo, parms, text)
   {
     XSetWindowAttributes attrs;
     unsigned long mask;
+    Atom type = FRAME_X_DISPLAY_INFO (f)->Xatom_net_window_type_tooltip;
 
     BLOCK_INPUT;
     mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
@@ -4892,6 +5023,10 @@ x_create_tip_frame (dpyinfo, parms, text)
                       f->border_width,
                       CopyFromParent, InputOutput, CopyFromParent,
                       mask, &attrs);
+    XChangeProperty (FRAME_X_DISPLAY (f), tip_window,
+                     FRAME_X_DISPLAY_INFO (f)->Xatom_net_window_type,
+                     XA_ATOM, 32, PropModeReplace,
+                     (unsigned char *)&type, 1);
     UNBLOCK_INPUT;
   }
 
@@ -5631,10 +5766,10 @@ If FRAME is omitted or nil, it defaults to the selected frame. */)
 {
   FRAME_PTR f = check_x_frame (frame);
   char *name;
-  Lisp_Object default_font, font = Qnil;
+  Lisp_Object font;
   Lisp_Object font_param;
   char *default_name = NULL;
-  struct gcpro gcpro1;
+  struct gcpro gcpro1, gcpro2;
   int count = SPECPDL_INDEX ();
 
   check_x ();
@@ -5648,22 +5783,37 @@ If FRAME is omitted or nil, it defaults to the selected frame. */)
 
   BLOCK_INPUT;
 
-  GCPRO1(font_param);
-  font_param = Fframe_parameter (frame, Qfont_param);
+  GCPRO2(font_param, font);
+
+  XSETFONT (font, FRAME_FONT (f));
+  font_param = Ffont_get (font, intern (":name"));
+  if (STRINGP (font_param))
+    default_name = xstrdup (SDATA (font_param));
+  else 
+    {
+      font_param = Fframe_parameter (frame, Qfont_param);
+      if (STRINGP (font_param))
+        default_name = xstrdup (SDATA (font_param));
+    }
+
+  if (default_name == NULL && x_last_font_name != NULL)
+    default_name = xstrdup (x_last_font_name);
 
-  if (x_last_font_name != NULL)
-    default_name = x_last_font_name;
-  else if (STRINGP (font_param))
-    default_name = SDATA (font_param);
-  else if (FONTP (default_font))
+  /* Convert fontconfig names to Gtk names, i.e. remove - before number */
+  if (default_name) 
     {
-      XSETFONT (default_font, FRAME_FONT (f));
-      default_name = alloca (256);
-      if (font_unparse_gtkname (default_font, f, default_name, 256) < 0)
-       default_name = NULL;
+      char *p = strrchr (default_name, '-');
+      if (p)
+        {
+          char *ep = p+1;
+          while (isdigit (*ep))
+            ++ep;
+          if (*ep == '\0') *p = ' ';
+        }
     }
 
   name = xg_get_font_name (f, default_name);
+  xfree (default_name);
 
   if (name)
     {
@@ -5840,17 +5990,17 @@ syms_of_xfns ()
   /* The section below is built by the lisp expression at the top of the file,
      just above where these variables are declared.  */
   /*&&& init symbols here &&&*/
-  Qnone = intern ("none");
+  Qnone = intern_c_string ("none");
   staticpro (&Qnone);
-  Qsuppress_icon = intern ("suppress-icon");
+  Qsuppress_icon = intern_c_string ("suppress-icon");
   staticpro (&Qsuppress_icon);
-  Qundefined_color = intern ("undefined-color");
+  Qundefined_color = intern_c_string ("undefined-color");
   staticpro (&Qundefined_color);
-  Qcompound_text = intern ("compound-text");
+  Qcompound_text = intern_c_string ("compound-text");
   staticpro (&Qcompound_text);
-  Qcancel_timer = intern ("cancel-timer");
+  Qcancel_timer = intern_c_string ("cancel-timer");
   staticpro (&Qcancel_timer);
-  Qfont_param = intern ("font-parameter");
+  Qfont_param = intern_c_string ("font-parameter");
   staticpro (&Qfont_param);
   /* This is the end of symbol initialization.  */
 
@@ -5860,9 +6010,9 @@ syms_of_xfns ()
 
 
   Fput (Qundefined_color, Qerror_conditions,
-       Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
+       pure_cons (Qundefined_color, pure_cons (Qerror, Qnil)));
   Fput (Qundefined_color, Qerror_message,
-       build_string ("Undefined color"));
+       make_pure_c_string ("Undefined color"));
 
   DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
     doc: /* The shape of the pointer when over text.
@@ -5959,12 +6109,12 @@ The default is to just show an arrow and pressing on that arrow shows
 the tool bar buttons.  */);
   x_gtk_whole_detached_tool_bar = 0;
 
-  Fprovide (intern ("x"), Qnil);
+  Fprovide (intern_c_string ("x"), Qnil);
 
 #ifdef USE_X_TOOLKIT
-  Fprovide (intern ("x-toolkit"), Qnil);
+  Fprovide (intern_c_string ("x-toolkit"), Qnil);
 #ifdef USE_MOTIF
-  Fprovide (intern ("motif"), Qnil);
+  Fprovide (intern_c_string ("motif"), Qnil);
 
   DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
               doc: /* Version info for LessTif/Motif.  */);
@@ -5977,8 +6127,8 @@ the tool bar buttons.  */);
      is not an X toolkit in that sense (USE_X_TOOLKIT is not defined).
      But for a user it is a toolkit for X, and indeed, configure
      accepts --with-x-toolkit=gtk.  */
-  Fprovide (intern ("x-toolkit"), Qnil);
-  Fprovide (intern ("gtk"), Qnil);
+  Fprovide (intern_c_string ("x-toolkit"), Qnil);
+  Fprovide (intern_c_string ("gtk"), Qnil);
 
   DEFVAR_LISP ("gtk-version-string", &Vgtk_version_string,
                doc: /* Version info for GTK+.  */);
@@ -5986,7 +6136,7 @@ the tool bar buttons.  */);
     char gtk_version[40];
     g_snprintf (gtk_version, sizeof (gtk_version), "%u.%u.%u",
                 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
-    Vgtk_version_string = build_string (gtk_version);
+    Vgtk_version_string = make_pure_string (gtk_version, strlen (gtk_version), strlen (gtk_version), 0);
   }
 #endif /* USE_GTK */