(x_encode_text): Return stringp non-NULL if coding_system
[bpt/emacs.git] / src / xfns.c
index 088d085..cd3dcdd 100644 (file)
@@ -24,6 +24,10 @@ Boston, MA 02111-1307, USA.  */
 #include <stdio.h>
 #include <math.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 /* This makes the fields of a Display accessible, in Xlib header files.  */
 
 #define XLIB_ILLEGAL_ACCESS
@@ -181,7 +185,7 @@ Lisp_Object Vx_pixel_size_width_font_regexp;
 
 Lisp_Object Qauto_raise;
 Lisp_Object Qauto_lower;
-Lisp_Object Qbar;
+Lisp_Object Qbar, Qhbar;
 Lisp_Object Qborder_color;
 Lisp_Object Qborder_width;
 Lisp_Object Qbox;
@@ -215,6 +219,10 @@ Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
 Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
 Lisp_Object Qcompound_text, Qcancel_timer;
 Lisp_Object Qwait_for_wm;
+Lisp_Object Qfullscreen;
+Lisp_Object Qfullwidth;
+Lisp_Object Qfullheight;
+Lisp_Object Qfullboth;
 
 /* The below are defined in frame.c.  */
 
@@ -261,7 +269,7 @@ check_x_frame (frame)
 
   if (NILP (frame))
     frame = selected_frame;
-  CHECK_LIVE_FRAME (frame, 0);
+  CHECK_LIVE_FRAME (frame);
   f = XFRAME (frame);
   if (! FRAME_X_P (f))
     error ("Non-X frame used");
@@ -295,7 +303,7 @@ check_x_display_info (frame)
     {
       FRAME_PTR f;
 
-      CHECK_LIVE_FRAME (frame, 0);
+      CHECK_LIVE_FRAME (frame);
       f = XFRAME (frame);
       if (! FRAME_X_P (f))
        error ("Non-X frame used");
@@ -641,7 +649,7 @@ x_create_bitmap_from_file (f, file)
     }
 
   /* Search bitmap-file-path for the file, if appropriate.  */
-  fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
+  fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
   if (fd < 0)
     return -1;
   emacs_close (fd);
@@ -729,6 +737,7 @@ static void x_disable_image P_ ((struct frame *, struct image *));
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -736,6 +745,7 @@ void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
@@ -773,32 +783,36 @@ static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
 
 static struct x_frame_parm_table x_frame_parms[] =
 {
-  "auto-raise",                        x_set_autoraise,
-  "auto-lower",                        x_set_autolower,
-  "background-color",          x_set_background_color,
-  "border-color",              x_set_border_color,
-  "border-width",              x_set_border_width,
-  "cursor-color",              x_set_cursor_color,
-  "cursor-type",               x_set_cursor_type,
-  "font",                      x_set_font,
-  "foreground-color",          x_set_foreground_color,
-  "icon-name",                 x_set_icon_name,
-  "icon-type",                 x_set_icon_type,
-  "internal-border-width",     x_set_internal_border_width,
-  "menu-bar-lines",            x_set_menu_bar_lines,
-  "mouse-color",               x_set_mouse_color,
-  "name",                      x_explicitly_set_name,
-  "scroll-bar-width",          x_set_scroll_bar_width,
-  "title",                     x_set_title,
-  "unsplittable",              x_set_unsplittable,
-  "vertical-scroll-bars",      x_set_vertical_scroll_bars,
-  "visibility",                        x_set_visibility,
-  "tool-bar-lines",            x_set_tool_bar_lines,
-  "scroll-bar-foreground",     x_set_scroll_bar_foreground,
-  "scroll-bar-background",     x_set_scroll_bar_background,
-  "screen-gamma",              x_set_screen_gamma,
-  "line-spacing",              x_set_line_spacing,
-  "wait-for-wm",               x_set_wait_for_wm
+  {"auto-raise",               x_set_autoraise},
+  {"auto-lower",               x_set_autolower},
+  {"background-color",         x_set_background_color},
+  {"border-color",             x_set_border_color},
+  {"border-width",             x_set_border_width},
+  {"cursor-color",             x_set_cursor_color},
+  {"cursor-type",              x_set_cursor_type},
+  {"font",                     x_set_font},
+  {"foreground-color",         x_set_foreground_color},
+  {"icon-name",                        x_set_icon_name},
+  {"icon-type",                        x_set_icon_type},
+  {"internal-border-width",    x_set_internal_border_width},
+  {"menu-bar-lines",           x_set_menu_bar_lines},
+  {"mouse-color",              x_set_mouse_color},
+  {"name",                     x_explicitly_set_name},
+  {"scroll-bar-width",         x_set_scroll_bar_width},
+  {"title",                    x_set_title},
+  {"unsplittable",             x_set_unsplittable},
+  {"vertical-scroll-bars",     x_set_vertical_scroll_bars},
+  {"visibility",               x_set_visibility},
+  {"tool-bar-lines",           x_set_tool_bar_lines},
+  {"scroll-bar-foreground",    x_set_scroll_bar_foreground},
+  {"scroll-bar-background",    x_set_scroll_bar_background},
+  {"screen-gamma",             x_set_screen_gamma},
+  {"line-spacing",             x_set_line_spacing},
+  {"left-fringe",              x_set_fringe_width},
+  {"right-fringe",             x_set_fringe_width},
+  {"wait-for-wm",              x_set_wait_for_wm},
+  {"fullscreen",                x_set_fullscreen},
+  
 };
 
 /* Attach the `x-frame-parameter' properties to
@@ -814,6 +828,28 @@ init_x_parm_symbols ()
          make_number (i));
 }
 \f
+
+/* Really try to move where we want to be in case of fullscreen.  Some WMs
+   moves the window where we tell them.  Some (mwm, twm) moves the outer
+   window manager window there instead.
+   Try to compensate for those WM here. */
+static void
+x_fullscreen_move (f, new_top, new_left)
+     struct frame *f;
+     int new_top;
+     int new_left;
+{
+  if (new_top != f->output_data.x->top_pos
+      || new_left != f->output_data.x->left_pos)
+    {
+      int move_x = new_left + f->output_data.x->x_pixels_outer_diff;
+      int move_y = new_top + f->output_data.x->y_pixels_outer_diff;
+
+      f->output_data.x->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
+      x_set_offset (f, move_x, move_y, 1);
+    }
+}
+
 /* Change the parameters of frame F as specified by ALIST.
    If a parameter is not specially recognized, do nothing special;
    otherwise call the `x_set_...' function for that parameter.
@@ -844,6 +880,7 @@ x_set_frame_parameters (f, alist)
   int i, p;
   int left_no_change = 0, top_no_change = 0;
   int icon_left_no_change = 0, icon_top_no_change = 0;
+  int fullscreen_is_being_set = 0;
 
   struct gcpro gcpro1, gcpro2;
 
@@ -892,23 +929,34 @@ x_set_frame_parameters (f, alist)
   /* Process foreground_color and background_color before anything else.
      They are independent of other properties, but other properties (e.g.,
      cursor_color) are dependent upon them.  */
+  /* Process default font as well, since fringe widths depends on it.  */
+  /* Also, process fullscreen, width and height depend upon that */
   for (p = 0; p < i; p++) 
     {
       Lisp_Object prop, val;
 
       prop = parms[p];
       val = values[p];
-      if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
+      if (EQ (prop, Qforeground_color)
+         || EQ (prop, Qbackground_color)
+         || EQ (prop, Qfont)
+          || EQ (prop, Qfullscreen))
        {
          register Lisp_Object param_index, old_value;
 
-         param_index = Fget (prop, Qx_frame_parameter);
          old_value = get_frame_param (f, prop);
-         store_frame_param (f, prop, val);
-         if (NATNUMP (param_index)
-             && (XFASTINT (param_index)
-                 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
-           (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
+         fullscreen_is_being_set |= EQ (prop, Qfullscreen);
+         
+         if (NILP (Fequal (val, old_value)))
+           {
+             store_frame_param (f, prop, val);
+
+             param_index = Fget (prop, Qx_frame_parameter);
+             if (NATNUMP (param_index)
+                 && (XFASTINT (param_index)
+                     < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
+               (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
+           }
        }
     }
 
@@ -932,17 +980,22 @@ x_set_frame_parameters (f, alist)
        icon_top = val;
       else if (EQ (prop, Qicon_left))
        icon_left = val;
-      else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
+      else if (EQ (prop, Qforeground_color)
+              || EQ (prop, Qbackground_color)
+              || EQ (prop, Qfont)
+               || EQ (prop, Qfullscreen))
        /* Processed above.  */
        continue;
       else
        {
          register Lisp_Object param_index, old_value;
 
-         param_index = Fget (prop, Qx_frame_parameter);
          old_value = get_frame_param (f, prop);
+
          store_frame_param (f, prop, val);
-         if (NATNUMP (param_index)
+
+         param_index = Fget (prop, Qx_frame_parameter);
+         if (NATNUMP (param_index)
              && (XFASTINT (param_index)
                  < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
            (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
@@ -983,6 +1036,21 @@ x_set_frame_parameters (f, alist)
        XSETINT (icon_top, 0);
     }
 
+  if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
+    {
+      /* If the frame is visible already and the fullscreen parameter is
+         being set, it is too late to set WM manager hints to specify
+         size and position.
+         Here we first get the width, height and position that applies to
+         fullscreen.  We then move the frame to the appropriate
+         position.  Resize of the frame is taken care of in the code after
+         this if-statement. */
+      int new_left, new_top;
+      
+      x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
+      x_fullscreen_move (f, new_top, new_left);
+    }
+  
   /* Don't set these parameters unless they've been explicitly
      specified.  The window might be mapped or resized while we're in
      this function, and we don't want to override that unless the lisp
@@ -1085,70 +1153,115 @@ x_real_positions (f, xptr, yptr)
      FRAME_PTR f;
      int *xptr, *yptr;
 {
-  int win_x, win_y;
-  Window child;
+  int win_x, win_y, outer_x, outer_y;
+  int real_x = 0, real_y = 0;
+  int had_errors = 0;
+  Window win = f->output_data.x->parent_desc;
 
-  /* This is pretty gross, but seems to be the easiest way out of
-     the problem that arises when restarting window-managers.  */
+  int count;
 
-#ifdef USE_X_TOOLKIT
-  Window outer = (f->output_data.x->widget
-                 ? XtWindow (f->output_data.x->widget)
-                 : FRAME_X_WINDOW (f));
-#else
-  Window outer = f->output_data.x->window_desc;
-#endif
-  Window tmp_root_window;
-  Window *tmp_children;
-  unsigned int tmp_nchildren;
+  BLOCK_INPUT;
+
+  count = x_catch_errors (FRAME_X_DISPLAY (f));
 
-  while (1)
+  if (win == FRAME_X_DISPLAY_INFO (f)->root_window)
+    win = FRAME_OUTER_WINDOW (f);
+
+  /* This loop traverses up the containment tree until we hit the root
+     window.  Window managers may intersect many windows between our window
+     and the root window.  The window we find just before the root window
+     should be the outer WM window. */
+  for (;;)
     {
-      int count = x_catch_errors (FRAME_X_DISPLAY (f));
-      Window outer_window;
+      Window wm_window, rootw;
+      Window *tmp_children;
+      unsigned int tmp_nchildren;
+      int success;
 
-      XQueryTree (FRAME_X_DISPLAY (f), outer, &tmp_root_window,
-                 &f->output_data.x->parent_desc,
-                 &tmp_children, &tmp_nchildren);
-      XFree ((char *) tmp_children);
+      success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
+                           &wm_window, &tmp_children, &tmp_nchildren);
 
-      win_x = win_y = 0;
+      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
 
-      /* Find the position of the outside upper-left corner of
-        the inner window, with respect to the outer window.  */
-      if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
-       outer_window = f->output_data.x->parent_desc;
-      else
-       outer_window = outer;
+      /* Don't free tmp_children if XQueryTree failed.  */
+      if (! success)
+       break;
+
+      XFree ((char *) tmp_children);
 
+      if (wm_window == rootw || had_errors)
+        break;
+
+      win = wm_window;
+    }
+    
+  if (! had_errors)
+    {
+      int ign;
+      Window child, rootw;
+          
+      /* Get the real coordinates for the WM window upper left corner */
+      XGetGeometry (FRAME_X_DISPLAY (f), win,
+                    &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);
+
+      /* Translate real coordinates to coordinates relative to our
+         window.  For our window, the upper left corner is 0, 0.
+         Since the upper left corner of the WM window is outside
+         our window, win_x and win_y will be negative:
+
+         ------------------          ---> x
+         |      title                |
+         | -----------------         v y
+         | |  our window
+      */
       XTranslateCoordinates (FRAME_X_DISPLAY (f),
 
                             /* From-window, to-window.  */
-                            outer_window,
                             FRAME_X_DISPLAY_INFO (f)->root_window,
+                             FRAME_X_WINDOW (f),
 
                             /* From-position, to-position.  */
-                            0, 0, &win_x, &win_y,
+                             real_x, real_y, &win_x, &win_y,
 
                             /* Child of win.  */
                             &child);
 
-      /* It is possible for the window returned by the XQueryNotify
-        to become invalid by the time we call XTranslateCoordinates.
-        That can happen when you restart some window managers.
-        If so, we get an error in XTranslateCoordinates.
-        Detect that and try the whole thing over.  */
-      if (! x_had_errors_p (FRAME_X_DISPLAY (f)))
+      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
        {
-         x_uncatch_errors (FRAME_X_DISPLAY (f), count);
-         break;
+          outer_x = win_x;
+          outer_y = win_y;
        }
+      else
+        {
+          XTranslateCoordinates (FRAME_X_DISPLAY (f),
 
-      x_uncatch_errors (FRAME_X_DISPLAY (f), count);
+                                 /* From-window, to-window.  */
+                                 FRAME_X_DISPLAY_INFO (f)->root_window,
+                                 FRAME_OUTER_WINDOW (f),
+                                     
+                                 /* From-position, to-position.  */
+                                 real_x, real_y, &outer_x, &outer_y,
+                         
+                                 /* Child of win.  */
+                                 &child);
     }
 
-  *xptr = win_x;
-  *yptr = win_y;
+      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
+    }
+      
+  x_uncatch_errors (FRAME_X_DISPLAY (f), count);
+      
+  UNBLOCK_INPUT;
+
+  if (had_errors) return;
+      
+  f->output_data.x->x_pixels_diff = -win_x;
+  f->output_data.x->y_pixels_diff = -win_y;
+  f->output_data.x->x_pixels_outer_diff = -outer_x;
+  f->output_data.x->y_pixels_outer_diff = -outer_y;
+
+  *xptr = real_x;
+  *yptr = real_y;
 }
 
 /* Insert a description of internally-recorded parameters of frame X
@@ -1183,6 +1296,14 @@ x_report_frame_params (f, alistptr)
                   make_number (f->output_data.x->border_width));
   store_in_alist (alistptr, Qinternal_border_width,
                   make_number (f->output_data.x->internal_border_width));
+  store_in_alist (alistptr, Qleft_fringe,
+                  make_number (f->output_data.x->left_fringe_width));
+  store_in_alist (alistptr, Qright_fringe,
+                  make_number (f->output_data.x->right_fringe_width));
+  store_in_alist (alistptr, Qscroll_bar_width,
+           make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+                        ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
+                        : 0));
   sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
   store_in_alist (alistptr, Qwindow_id,
                   build_string (buf));
@@ -1264,7 +1385,7 @@ x_decode_color (f, color_name, mono_color)
 {
   XColor cdef;
 
-  CHECK_STRING (color_name, 0);
+  CHECK_STRING (color_name);
 
 #if 0 /* Don't do this.  It's wrong when we're not using the default
         colormap, it makes freeing difficult, and it's probably not
@@ -1324,6 +1445,25 @@ x_set_wait_for_wm (f, new_value, old_value)
 }
 
 
+/* Change the `fullscreen' frame parameter of frame F.  OLD_VALUE is
+   the previous value of that parameter, NEW_VALUE is the new value. */
+
+static void
+x_set_fullscreen (f, new_value, old_value)
+     struct frame *f;
+     Lisp_Object new_value, old_value;
+{
+  if (NILP (new_value))
+    f->output_data.x->want_fullscreen = FULLSCREEN_NONE;
+  else if (EQ (new_value, Qfullboth))
+    f->output_data.x->want_fullscreen = FULLSCREEN_BOTH;
+  else if (EQ (new_value, Qfullwidth))
+    f->output_data.x->want_fullscreen = FULLSCREEN_WIDTH;
+  else if (EQ (new_value, Qfullheight))
+    f->output_data.x->want_fullscreen = FULLSCREEN_HEIGHT;
+}
+
+
 /* Change the `screen-gamma' frame parameter of frame F.  OLD_VALUE is
    the previous value of that parameter, NEW_VALUE is the new
    value.  */
@@ -1466,7 +1606,7 @@ x_set_mouse_color (f, arg, oldval)
 
   if (!NILP (Vx_pointer_shape))
     {
-      CHECK_NUMBER (Vx_pointer_shape, 0);
+      CHECK_NUMBER (Vx_pointer_shape);
       cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
     }
   else
@@ -1475,7 +1615,7 @@ x_set_mouse_color (f, arg, oldval)
 
   if (!NILP (Vx_nontext_pointer_shape))
     {
-      CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
+      CHECK_NUMBER (Vx_nontext_pointer_shape);
       nontext_cursor
        = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
     }
@@ -1485,7 +1625,7 @@ x_set_mouse_color (f, arg, oldval)
 
   if (!NILP (Vx_hourglass_pointer_shape))
     {
-      CHECK_NUMBER (Vx_hourglass_pointer_shape, 0);
+      CHECK_NUMBER (Vx_hourglass_pointer_shape);
       hourglass_cursor
        = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
     }
@@ -1496,7 +1636,7 @@ x_set_mouse_color (f, arg, oldval)
   x_check_errors (dpy, "bad nontext pointer cursor: %s");
   if (!NILP (Vx_mode_pointer_shape))
     {
-      CHECK_NUMBER (Vx_mode_pointer_shape, 0);
+      CHECK_NUMBER (Vx_mode_pointer_shape);
       mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
     }
   else
@@ -1505,16 +1645,16 @@ x_set_mouse_color (f, arg, oldval)
 
   if (!NILP (Vx_sensitive_text_pointer_shape))
     {
-      CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
+      CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
       cross_cursor
        = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
     }
   else
-    cross_cursor = XCreateFontCursor (dpy, XC_crosshair);
+    cross_cursor = XCreateFontCursor (dpy, XC_hand2);
 
   if (!NILP (Vx_window_horizontal_drag_shape))
     {
-      CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
+      CHECK_NUMBER (Vx_window_horizontal_drag_shape);
       horizontal_drag_cursor
        = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
     }
@@ -1668,7 +1808,7 @@ x_set_border_color (f, arg, oldval)
 {
   int pix;
 
-  CHECK_STRING (arg, 0);
+  CHECK_STRING (arg);
   pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
   x_set_border_pixel (f, pix);
   update_face_from_frame_parameter (f, Qborder_color, arg);
@@ -1723,6 +1863,19 @@ x_specified_cursor_type (arg, width)
       type = BAR_CURSOR;
       *width = XINT (XCDR (arg));
     }
+  else if (EQ (arg, Qhbar))
+    {
+      type = HBAR_CURSOR;
+      *width = 2;
+    }
+  else if (CONSP (arg)
+          && EQ (XCAR (arg), Qhbar)
+          && INTEGERP (XCDR (arg))
+          && XINT (XCDR (arg)) >= 0)
+    {
+      type = HBAR_CURSOR;
+      *width = XINT (XCDR (arg));
+    }
   else if (NILP (arg))
     type = NO_CURSOR;
   else
@@ -1744,9 +1897,8 @@ x_set_cursor_type (f, arg, oldval)
   FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
   f->output_data.x->cursor_width = width;
 
-  /* Make sure the cursor gets redrawn.  This is overkill, but how
-     often do people change cursor types?  */
-  update_mode_lines++;
+  /* Make sure the cursor gets redrawn.  */
+  cursor_type_changed = 1;
 }
 \f
 void
@@ -1847,7 +1999,7 @@ x_set_font (f, arg, oldval)
   Lisp_Object frame;
   int old_fontset = f->output_data.x->fontset;
 
-  CHECK_STRING (arg, 1);
+  CHECK_STRING (arg);
 
   fontset_name = Fquery_fontset (arg, Qnil);
 
@@ -1893,12 +2045,20 @@ x_set_font (f, arg, oldval)
     }
 }
 
+static void
+x_set_fringe_width (f, new_value, old_value)
+     struct frame *f;
+     Lisp_Object new_value, old_value;
+{
+  x_compute_fringe_widths (f, 1);
+}
+
 void
 x_set_border_width (f, arg, oldval)
      struct frame *f;
      Lisp_Object arg, oldval;
 {
-  CHECK_NUMBER (arg, 0);
+  CHECK_NUMBER (arg);
 
   if (XINT (arg) == f->output_data.x->border_width)
     return;
@@ -1916,7 +2076,7 @@ x_set_internal_border_width (f, arg, oldval)
 {
   int old = f->output_data.x->internal_border_width;
 
-  CHECK_NUMBER (arg, 0);
+  CHECK_NUMBER (arg);
   f->output_data.x->internal_border_width = XINT (arg);
   if (f->output_data.x->internal_border_width < 0)
     f->output_data.x->internal_border_width = 0;
@@ -1935,6 +2095,8 @@ x_set_internal_border_width (f, arg, oldval)
       SET_FRAME_GARBAGED (f);
       do_pending_window_change (0);
     }
+  else
+    SET_FRAME_GARBAGED (f);
 }
 
 void
@@ -2201,6 +2363,10 @@ x_set_scroll_bar_background (f, value, oldval)
    CODING_SYSTEM, and return a newly allocated memory area which
    should be freed by `xfree' by a caller.
 
+   SELECTIONP non-zero means the string is being encoded for an X
+   selection, so it is safe to run pre-write conversions (which
+   may run Lisp code).
+
    Store the byte length of resulting text in *TEXT_BYTES.
 
    If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
@@ -2209,9 +2375,10 @@ x_set_scroll_bar_background (f, value, oldval)
    the result should be `COMPOUND_TEXT'.  */
 
 unsigned char *
-x_encode_text (string, coding_system, text_bytes, stringp)
+x_encode_text (string, coding_system, selectionp, text_bytes, stringp)
      Lisp_Object string, coding_system;
      int *text_bytes, *stringp;
+     int selectionp;
 {
   unsigned char *str = XSTRING (string)->data;
   int chars = XSTRING (string)->size;
@@ -2220,6 +2387,7 @@ x_encode_text (string, coding_system, text_bytes, stringp)
   int bufsize;
   unsigned char *buf;
   struct coding_system coding;
+  extern Lisp_Object Qcompound_text_with_extensions;
 
   charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
   if (charset_info == 0)
@@ -2231,6 +2399,15 @@ x_encode_text (string, coding_system, text_bytes, stringp)
     }
 
   setup_coding_system (coding_system, &coding);
+  if (selectionp
+      && SYMBOLP (coding.pre_write_conversion)
+      && !NILP (Ffboundp (coding.pre_write_conversion)))
+    {
+      string = run_pre_post_conversion_on_str (string, &coding, 1);
+      str = XSTRING (string)->data;
+      chars = XSTRING (string)->size;
+      bytes = STRING_BYTES (XSTRING (string));
+    }
   coding.src_multibyte = 1;
   coding.dst_multibyte = 0;
   coding.mode |= CODING_MODE_LAST_BLOCK;
@@ -2242,7 +2419,9 @@ x_encode_text (string, coding_system, text_bytes, stringp)
   buf = (unsigned char *) xmalloc (bufsize);
   encode_coding (&coding, str, buf, bytes, bufsize);
   *text_bytes = coding.produced;
-  *stringp = (charset_info == 1 || !EQ (coding_system, Qcompound_text));
+  *stringp = (charset_info == 1
+             || (!EQ (coding_system, Qcompound_text)
+                 && !EQ (coding_system, Qcompound_text_with_extensions)));
   return buf;
 }
 
@@ -2289,7 +2468,7 @@ x_set_name (f, name, explicit)
       name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name);
     }
   else
-    CHECK_STRING (name, 0);
+    CHECK_STRING (name);
 
   /* Don't change the name if it's already NAME.  */
   if (! NILP (Fstring_equal (name, f->name)))
@@ -2314,7 +2493,7 @@ x_set_name (f, name, explicit)
        coding_system = Vlocale_coding_system;
        if (NILP (coding_system))
          coding_system = Qcompound_text;
-       text.value = x_encode_text (name, coding_system, &bytes, &stringp);
+       text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
        text.encoding = (stringp ? XA_STRING
                         : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
        text.format = 8;
@@ -2326,7 +2505,7 @@ x_set_name (f, name, explicit)
          }
        else
          {
-           icon.value = x_encode_text (f->icon_name, coding_system,
+           icon.value = x_encode_text (f->icon_name, coding_system, 0,
                                        &bytes, &stringp);
            icon.encoding = (stringp ? XA_STRING
                             : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
@@ -2407,7 +2586,7 @@ x_set_title (f, name, old_name)
   if (NILP (name))
     name = f->name;
   else
-    CHECK_STRING (name, 0);
+    CHECK_STRING (name);
 
   if (FRAME_X_WINDOW (f))
     {
@@ -2421,7 +2600,7 @@ x_set_title (f, name, old_name)
        coding_system = Vlocale_coding_system;
        if (NILP (coding_system))
          coding_system = Qcompound_text;
-       text.value = x_encode_text (name, coding_system, &bytes, &stringp);
+       text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp);
        text.encoding = (stringp ? XA_STRING
                         : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
        text.format = 8;
@@ -2433,7 +2612,7 @@ x_set_title (f, name, old_name)
          }
        else
          {
-           icon.value = x_encode_text (f->icon_name, coding_system,
+           icon.value = x_encode_text (f->icon_name, coding_system, 0,
                                        &bytes, &stringp);
            icon.encoding = (stringp ? XA_STRING
                             : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
@@ -2639,7 +2818,7 @@ validate_x_resource_name ()
 extern char *x_get_string_resource ();
 
 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
-  doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
+       doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
 class, where INSTANCE is the name under which Emacs was invoked, or
 the name specified by the `-name' or `-rn' command-line arguments.
@@ -2657,13 +2836,13 @@ and the class is `Emacs.CLASS.SUBCLASS'.  */)
 
   check_x ();
 
-  CHECK_STRING (attribute, 0);
-  CHECK_STRING (class, 0);
+  CHECK_STRING (attribute);
+  CHECK_STRING (class);
 
   if (!NILP (component))
-    CHECK_STRING (component, 1);
+    CHECK_STRING (component);
   if (!NILP (subclass))
-    CHECK_STRING (subclass, 2);
+    CHECK_STRING (subclass);
   if (NILP (component) != NILP (subclass))
     error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
 
@@ -2723,13 +2902,13 @@ display_x_get_resource (dpyinfo, attribute, class, component, subclass)
   char *name_key;
   char *class_key;
 
-  CHECK_STRING (attribute, 0);
-  CHECK_STRING (class, 0);
+  CHECK_STRING (attribute);
+  CHECK_STRING (class);
 
   if (!NILP (component))
-    CHECK_STRING (component, 1);
+    CHECK_STRING (component);
   if (!NILP (subclass))
-    CHECK_STRING (subclass, 2);
+    CHECK_STRING (subclass);
   if (NILP (component) != NILP (subclass))
     error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
 
@@ -3010,7 +3189,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.  */)
   unsigned int width, height;
   Lisp_Object result;
 
-  CHECK_STRING (string, 0);
+  CHECK_STRING (string);
 
   geometry = XParseGeometry ((char *) XSTRING (string)->data,
                             &x, &y, &width, &height);
@@ -3089,12 +3268,12 @@ x_figure_window_size (f, parms)
     {
       if (!EQ (tem0, Qunbound))
        {
-         CHECK_NUMBER (tem0, 0);
+         CHECK_NUMBER (tem0);
          f->height = XINT (tem0);
        }
       if (!EQ (tem1, Qunbound))
        {
-         CHECK_NUMBER (tem1, 0);
+         CHECK_NUMBER (tem1);
          SET_FRAME_WIDTH (f, XINT (tem1));
        }
       if (!NILP (tem2) && !EQ (tem2, Qunbound))
@@ -3107,8 +3286,9 @@ x_figure_window_size (f, parms)
     = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
        ? 0
        : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
-  f->output_data.x->flags_areas_extra
-    = FRAME_FLAGS_AREA_WIDTH (f);
+
+  x_compute_fringe_widths (f, 0);
+
   f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
   f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
 
@@ -3139,7 +3319,7 @@ x_figure_window_size (f, parms)
        f->output_data.x->top_pos = 0;
       else
        {
-         CHECK_NUMBER (tem0, 0);
+         CHECK_NUMBER (tem0);
          f->output_data.x->top_pos = XINT (tem0);
          if (f->output_data.x->top_pos < 0)
            window_prompting |= YNegative;
@@ -3167,7 +3347,7 @@ x_figure_window_size (f, parms)
        f->output_data.x->left_pos = 0;
       else
        {
-         CHECK_NUMBER (tem1, 0);
+         CHECK_NUMBER (tem1);
          f->output_data.x->left_pos = XINT (tem1);
          if (f->output_data.x->left_pos < 0)
            window_prompting |= XNegative;
@@ -3179,6 +3359,22 @@ x_figure_window_size (f, parms)
        window_prompting |= PPosition;
     }
 
+  if (f->output_data.x->want_fullscreen != FULLSCREEN_NONE)
+    {
+      int left, top;
+      int width, height;
+      
+      /* It takes both for some WM:s to place it where we want */
+      window_prompting = USPosition | PPosition;
+      x_fullscreen_adjust (f, &width, &height, &top, &left);
+      f->width = width;
+      f->height = height;
+      f->output_data.x->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
+      f->output_data.x->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
+      f->output_data.x->left_pos = left;
+      f->output_data.x->top_pos = top;
+    }
+  
   return window_prompting;
 }
 
@@ -3920,8 +4116,8 @@ x_icon (f, parms)
   icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
   if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
     {
-      CHECK_NUMBER (icon_x, 0);
-      CHECK_NUMBER (icon_y, 0);
+      CHECK_NUMBER (icon_x);
+      CHECK_NUMBER (icon_y);
     }
   else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
     error ("Both left and top icon corners of icon must be specified");
@@ -4145,7 +4341,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
   if (EQ (parent, Qunbound))
     parent = Qnil;
   if (! NILP (parent))
-    CHECK_NUMBER (parent, 0);
+    CHECK_NUMBER (parent);
 
   /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
   /* No need to protect DISPLAY because that's not used after passing
@@ -4309,7 +4505,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
   x_default_parameter (f, parms, Qborder_width, make_number (2),
                       "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
   
-  /* This defaults to 2 in order to match xterm.  We recognize either
+  /* This defaults to 1 in order to match xterm.  We recognize either
      internalBorderWidth or internalBorder (which is what xterm calls
      it).  */
   if (NILP (Fassq (Qinternal_border_width, parms)))
@@ -4344,6 +4540,10 @@ This function is an internal primitive--use `make-frame' instead.  */)
                       "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
   x_default_parameter (f, parms, Qline_spacing, Qnil,
                       "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
+  x_default_parameter (f, parms, Qleft_fringe, Qnil,
+                      "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
+  x_default_parameter (f, parms, Qright_fringe, Qnil,
+                      "rightFringe", "RightFringe", RES_TYPE_NUMBER);
 
   x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
                                        "scrollBarForeground",
@@ -4371,6 +4571,8 @@ This function is an internal primitive--use `make-frame' instead.  */)
                       "title", "Title", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qwait_for_wm, Qt,
                       "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
+  x_default_parameter (f, parms, Qfullscreen, Qnil,
+                       "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
 
   f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
 
@@ -4384,7 +4586,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
     {
       int margin, relief, bar_height;
       
-      relief = (tool_bar_button_relief > 0
+      relief = (tool_bar_button_relief >= 0
                ? tool_bar_button_relief
                : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
 
@@ -4581,7 +4783,7 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
   XColor foo;
   FRAME_PTR f = check_x_frame (frame);
 
-  CHECK_STRING (color, 1);
+  CHECK_STRING (color);
 
   if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
     return Qt;
@@ -4597,7 +4799,7 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
   XColor foo;
   FRAME_PTR f = check_x_frame (frame);
 
-  CHECK_STRING (color, 1);
+  CHECK_STRING (color);
 
   if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
     {
@@ -4963,7 +5165,7 @@ visual_classes[] =
   {"PseudoColor",      PseudoColor},
   {"TrueColor",                TrueColor},
   {"DirectColor",      DirectColor},
-  NULL
+  {NULL, 0}
 };
 
 
@@ -4980,7 +5182,7 @@ XScreenNumberOfScreen (scr)
   int i;
 
   for (i = 0; i < dpy->nscreens; ++i)
-    if (scr == dpy->screens[i])
+    if (scr == dpy->screens + i)
       break;
 
   return i;
@@ -5077,7 +5279,7 @@ x_display_info_for_name (name)
   Lisp_Object names;
   struct x_display_info *dpyinfo;
 
-  CHECK_STRING (name, 0);
+  CHECK_STRING (name);
 
   if (! EQ (Vwindow_system, intern ("x")))
     error ("Not using X Windows");
@@ -5123,9 +5325,9 @@ terminate Emacs if we can't open the connection.  */)
   unsigned char *xrm_option;
   struct x_display_info *dpyinfo;
 
-  CHECK_STRING (display, 0);
+  CHECK_STRING (display);
   if (! NILP (xrm_string))
-    CHECK_STRING (xrm_string, 1);
+    CHECK_STRING (xrm_string);
 
   if (! EQ (Vwindow_system, intern ("x")))
     error ("Not using X Windows");
@@ -5269,8 +5471,8 @@ Lisp_Object Qxbm;
 /* Keywords.  */
 
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
-extern Lisp_Object QCdata;
-Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
+extern Lisp_Object QCdata, QCtype;
+Lisp_Object QCascent, QCmargin, QCrelief;
 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
 
@@ -5465,7 +5667,7 @@ parse_image_spec (spec, keywords, nkeywords, type)
 
       /* Find key in KEYWORDS.  Error if not found.  */
       for (i = 0; i < nkeywords; ++i)
-       if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
+       if (strcmp (keywords[i].name, XSTRING (SYMBOL_NAME (key))->data) == 0)
          break;
 
       if (i == nkeywords)
@@ -5768,6 +5970,104 @@ image_ascent (img, face)
   return ascent;
 }
 
+\f
+/* Image background colors.  */
+
+static unsigned long
+four_corners_best (ximg, width, height)
+     XImage *ximg;
+     unsigned long width, height;
+{
+  unsigned long corners[4], best;
+  int i, best_count;
+
+  /* Get the colors at the corners of ximg.  */
+  corners[0] = XGetPixel (ximg, 0, 0);
+  corners[1] = XGetPixel (ximg, width - 1, 0);
+  corners[2] = XGetPixel (ximg, width - 1, height - 1);
+  corners[3] = XGetPixel (ximg, 0, height - 1);
+
+  /* Choose the most frequently found color as background.  */
+  for (i = best_count = 0; i < 4; ++i)
+    {
+      int j, n;
+         
+      for (j = n = 0; j < 4; ++j)
+       if (corners[i] == corners[j])
+         ++n;
+
+      if (n > best_count)
+       best = corners[i], best_count = n;
+    }
+
+  return best;
+}
+
+/* Return the `background' field of IMG.  If IMG doesn't have one yet,
+   it is guessed heuristically.  If non-zero, XIMG is an existing XImage
+   object to use for the heuristic.  */
+
+unsigned long
+image_background (img, f, ximg)
+     struct image *img;
+     struct frame *f;
+     XImage *ximg;
+{
+  if (! img->background_valid)
+    /* IMG doesn't have a background yet, try to guess a reasonable value.  */
+    {
+      int free_ximg = !ximg;
+
+      if (! ximg)
+       ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
+                         0, 0, img->width, img->height, ~0, ZPixmap);
+
+      img->background = four_corners_best (ximg, img->width, img->height);
+
+      if (free_ximg)
+       XDestroyImage (ximg);
+
+      img->background_valid = 1;
+    }
+
+  return img->background;
+}
+
+/* Return the `background_transparent' field of IMG.  If IMG doesn't
+   have one yet, it is guessed heuristically.  If non-zero, MASK is an
+   existing XImage object to use for the heuristic.  */
+
+int
+image_background_transparent (img, f, mask)
+     struct image *img;
+     struct frame *f;
+     XImage *mask;
+{
+  if (! img->background_transparent_valid)
+    /* IMG doesn't have a background yet, try to guess a reasonable value.  */
+    {
+      if (img->mask)
+       {
+         int free_mask = !mask;
+
+         if (! mask)
+           mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
+                             0, 0, img->width, img->height, ~0, ZPixmap);
+
+         img->background_transparent
+           = !four_corners_best (mask, img->width, img->height);
+
+         if (free_mask)
+           XDestroyImage (mask);
+       }
+      else
+       img->background_transparent = 0;
+
+      img->background_transparent_valid = 1;
+    }
+
+  return img->background_transparent;
+}
 
 \f
 /***********************************************************************
@@ -5798,12 +6098,14 @@ x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
     {
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
       img->pixmap = None;
+      img->background_valid = 0;
     }
 
   if (mask_p && img->mask)
     {
       XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
       img->mask = None;
+      img->background_transparent_valid = 0;
     }
       
   if (colors_p && img->ncolors)
@@ -6133,8 +6435,9 @@ lookup_image (f, spec)
       else
        {
          /* Handle image type independent image attributes
-            `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'.  */
-         Lisp_Object ascent, margin, relief;
+            `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
+            `:background COLOR'.  */
+         Lisp_Object ascent, margin, relief, bg;
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (INTEGERP (ascent))
@@ -6162,6 +6465,18 @@ lookup_image (f, spec)
              img->vmargin += abs (img->relief);
            }
 
+         if (! img->background_valid)
+           {
+             bg = image_spec_value (img->spec, QCbackground, NULL);
+             if (!NILP (bg))
+               {
+                 img->background
+                   = x_alloc_image_color (f, img, bg,
+                                          FRAME_BACKGROUND_PIXEL (f));
+                 img->background_valid = 1;
+               }
+           }
+
          /* Do image transformations and compute masks, unless we
             don't have the image yet.  */
          if (!EQ (*img->type->type, Qpostscript))
@@ -6362,7 +6677,7 @@ x_find_image_file (file)
   GCPRO2 (file_found, search_path);
 
   /* Try to find FILE in data-directory, then x-bitmap-file-path.  */
-  fd = openp (search_path, file, Qnil, &file_found, 0);
+  fd = openp (search_path, file, Qnil, &file_found, Qnil);
   
   if (fd == -1)
     file_found = Qnil;
@@ -6875,10 +7190,13 @@ xbm_load_image (f, img, contents, end)
       value = image_spec_value (img->spec, QCforeground, NULL);
       if (!NILP (value))
        foreground = x_alloc_image_color (f, img, value, foreground);
-      
       value = image_spec_value (img->spec, QCbackground, NULL);
       if (!NILP (value))
-       background = x_alloc_image_color (f, img, value, background);
+       {
+         background = x_alloc_image_color (f, img, value, background);
+         img->background = background;
+         img->background_valid = 1;
+       }
 
       img->pixmap
        = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
@@ -7081,6 +7399,7 @@ enum xpm_keyword_index
   XPM_HEURISTIC_MASK,
   XPM_MASK,
   XPM_COLOR_SYMBOLS,
+  XPM_BACKGROUND,
   XPM_LAST
 };
 
@@ -7098,7 +7417,8 @@ static struct image_keyword xpm_format[XPM_LAST] =
   {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":color-symbols",   IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":color-symbols",   IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type XBM.  */
@@ -8041,13 +8361,14 @@ x_build_heuristic_mask (f, img, how)
 {
   Display *dpy = FRAME_X_DISPLAY (f);
   XImage *ximg, *mask_img;
-  int x, y, rc, look_at_corners_p;
+  int x, y, rc, use_img_background;
   unsigned long bg = 0;
 
   if (img->mask)
     {
       XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
       img->mask = None;
+      img->background_transparent_valid = 0;
     }
 
   /* Create an image and pixmap serving as mask.  */
@@ -8061,17 +8382,14 @@ x_build_heuristic_mask (f, img, how)
                    ~0, ZPixmap);
 
   /* Determine the background color of ximg.  If HOW is `(R G B)'
-     take that as color.  Otherwise, try to determine the color
-     heuristically. */
-  look_at_corners_p = 1;
+     take that as color.  Otherwise, use the image's background color. */
+  use_img_background = 1;
   
   if (CONSP (how))
     {
-      int rgb[3], i = 0;
+      int rgb[3], i;
 
-      while (i < 3
-            && CONSP (how)
-            && NATNUMP (XCAR (how)))
+      for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
        {
          rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
          how = XCDR (how);
@@ -8080,44 +8398,14 @@ x_build_heuristic_mask (f, img, how)
       if (i == 3 && NILP (how))
        {
          char color_name[30];
-         XColor exact, color;
-         Colormap cmap;
-
          sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
-         
-         cmap = FRAME_X_COLORMAP (f);
-         if (XLookupColor (dpy, cmap, color_name, &exact, &color))
-           {
-             bg = color.pixel;
-             look_at_corners_p = 0;
-           }
+         bg = x_alloc_image_color (f, img, build_string (color_name), 0);
+         use_img_background = 0;
        }
     }
   
-  if (look_at_corners_p)
-    {
-      unsigned long corners[4];
-      int i, best_count;
-
-      /* Get the colors at the corners of ximg.  */
-      corners[0] = XGetPixel (ximg, 0, 0);
-      corners[1] = XGetPixel (ximg, img->width - 1, 0);
-      corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
-      corners[3] = XGetPixel (ximg, 0, img->height - 1);
-
-      /* Choose the most frequently found color as background.  */
-      for (i = best_count = 0; i < 4; ++i)
-       {
-         int j, n;
-         
-         for (j = n = 0; j < 4; ++j)
-           if (corners[i] == corners[j])
-             ++n;
-
-         if (n > best_count)
-           bg = corners[i], best_count = n;
-       }
-    }
+  if (use_img_background)
+    bg = four_corners_best (ximg, img->width, img->height);
 
   /* Set all bits in mask_img to 1 whose color in ximg is different
      from the background color bg.  */
@@ -8125,6 +8413,9 @@ x_build_heuristic_mask (f, img, how)
     for (x = 0; x < img->width; ++x)
       XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
 
+  /* Fill in the background_transparent field while we have the mask handy. */
+  image_background_transparent (img, f, mask_img);
+
   /* Put mask_img into img->mask.  */
   x_put_x_image (f, mask_img, img->mask, img->width, img->height);
   x_destroy_x_image (mask_img);
@@ -8383,7 +8674,11 @@ pbm_load (f, img)
        fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
       if (fmt[PBM_BACKGROUND].count
          && STRINGP (fmt[PBM_BACKGROUND].value))
-       bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
+       {
+         bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
+         img->background = bg;
+         img->background_valid = 1;
+       }
       
       for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x)
@@ -8446,6 +8741,10 @@ pbm_load (f, img)
      free the color table.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
+
+  /* Maybe fill in the background field while we have ximg handy. */
+  if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
+    IMAGE_BACKGROUND (img, f, ximg);
   
   /* Put the image into a pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -8491,6 +8790,7 @@ enum png_keyword_index
   PNG_ALGORITHM,
   PNG_HEURISTIC_MASK,
   PNG_MASK,
+  PNG_BACKGROUND,
   PNG_LAST
 };
 
@@ -8507,7 +8807,8 @@ static struct image_keyword png_format[PNG_LAST] =
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type `png'.  */
@@ -8616,7 +8917,6 @@ png_load (f, img)
   png_byte channels;
   png_uint_32 row_bytes;
   int transparent_p;
-  char *gamma_str;
   double screen_gamma, image_gamma;
   int intent;
   struct png_memory_storage tbr;  /* Data to be read */
@@ -8754,36 +9054,53 @@ png_load (f, img)
       || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
     png_set_gray_to_rgb (png_ptr);
 
-  /* The value 2.2 is a guess for PC monitors from PNG example.c.  */
-  gamma_str = getenv ("SCREEN_GAMMA");
-  screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
+  screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2);
 
   /* Tell the PNG lib to handle gamma correction for us.  */
 
 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
   if (png_get_sRGB (png_ptr, info_ptr, &intent))
-    /* There is a special chunk in the image specifying the gamma.  */
-    png_set_sRGB (png_ptr, info_ptr, intent);
+    /* The libpng documentation says this is right in this case.  */
+    png_set_gamma (png_ptr, screen_gamma, 0.45455);
   else
 #endif
   if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
     /* Image contains gamma information.  */
     png_set_gamma (png_ptr, screen_gamma, image_gamma);
   else
-    /* Use a default of 0.5 for the image gamma.  */
-    png_set_gamma (png_ptr, screen_gamma, 0.5);
+    /* Use the standard default for the image gamma.  */
+    png_set_gamma (png_ptr, screen_gamma, 0.45455);
 
   /* Handle alpha channel by combining the image with a background
      color.  Do this only if a real alpha channel is supplied.  For
      simple transparency, we prefer a clipping mask.  */
   if (!transparent_p)
     {
-      png_color_16 *image_background;
+      png_color_16 *image_bg;
+      Lisp_Object specified_bg
+       = image_spec_value (img->spec, QCbackground, NULL);
+
+      if (STRINGP (specified_bg))
+       /* The user specified `:background', use that.  */
+       {
+         XColor color;
+         if (x_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
+           {
+             png_color_16 user_bg;
 
-      if (png_get_bKGD (png_ptr, info_ptr, &image_background))
+             bzero (&user_bg, sizeof user_bg);
+             user_bg.red = color.red;
+             user_bg.green = color.green;
+             user_bg.blue = color.blue;
+
+             png_set_background (png_ptr, &user_bg,
+                                 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+           }
+       }
+      else if (png_get_bKGD (png_ptr, info_ptr, &image_bg))
        /* Image contains a background color with which to 
           combine the image.  */
-       png_set_background (png_ptr, image_background,
+       png_set_background (png_ptr, image_bg,
                            PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
       else
        {
@@ -8896,6 +9213,18 @@ png_load (f, img)
        }
     }
 
+  if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
+    /* Set IMG's background color from the PNG image, unless the user
+       overrode it.  */
+    {
+      png_color_16 *bg;
+      if (png_get_bKGD (png_ptr, info_ptr, &bg))
+       {
+         img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
+         img->background_valid = 1;
+       }
+    }
+
   /* Remember colors allocated for this image.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
@@ -8908,6 +9237,9 @@ png_load (f, img)
   img->width = width;
   img->height = height;
 
+  /* Maybe fill in the background field while we have ximg handy. */
+  IMAGE_BACKGROUND (img, f, ximg);
+
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
@@ -8915,6 +9247,10 @@ png_load (f, img)
   /* Same for the mask.  */
   if (mask_img)
     {
+      /* Fill in the background_transparent field while we have the mask
+        handy. */
+      image_background_transparent (img, f, mask_img);
+
       x_put_x_image (f, mask_img, img->mask, img->width, img->height);
       x_destroy_x_image (mask_img);
     }
@@ -8968,6 +9304,7 @@ enum jpeg_keyword_index
   JPEG_ALGORITHM,
   JPEG_HEURISTIC_MASK,
   JPEG_MASK,
+  JPEG_BACKGROUND,
   JPEG_LAST
 };
 
@@ -8984,7 +9321,8 @@ static struct image_keyword jpeg_format[JPEG_LAST] =
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":conversions",     IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type `jpeg'.  */
@@ -9283,6 +9621,10 @@ jpeg_load (f, img)
   jpeg_destroy_decompress (&cinfo);
   if (fp)
     fclose ((FILE *) fp);
+
+  /* Maybe fill in the background field while we have ximg handy. */
+  if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
+    IMAGE_BACKGROUND (img, f, ximg);
   
   /* Put the image into the pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -9323,6 +9665,7 @@ enum tiff_keyword_index
   TIFF_ALGORITHM,
   TIFF_HEURISTIC_MASK,
   TIFF_MASK,
+  TIFF_BACKGROUND,
   TIFF_LAST
 };
 
@@ -9339,7 +9682,8 @@ static struct image_keyword tiff_format[TIFF_LAST] =
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":conversions",     IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type `tiff'.  */
@@ -9631,14 +9975,18 @@ tiff_load (f, img)
   /* Remember the colors allocated for the image.  Free the color table.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
+      
+  img->width = width;
+  img->height = height;
+
+  /* Maybe fill in the background field while we have ximg handy. */
+  if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
+    IMAGE_BACKGROUND (img, f, ximg);
 
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
   xfree (buf);
-      
-  img->width = width;
-  img->height = height;
 
   UNGCPRO;
   return 1;
@@ -9677,6 +10025,7 @@ enum gif_keyword_index
   GIF_HEURISTIC_MASK,
   GIF_MASK,
   GIF_IMAGE,
+  GIF_BACKGROUND,
   GIF_LAST
 };
 
@@ -9694,7 +10043,8 @@ static struct image_keyword gif_format[GIF_LAST] =
   {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":image",           IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0}
+  {":image",           IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type `gif'.  */
@@ -9843,8 +10193,8 @@ gif_load (f, img)
       return 0;
     }
 
-  width = img->width = gif->SWidth;
-  height = img->height = gif->SHeight;
+  width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
+  height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
 
   /* Create the X image and pixmap.  */
   if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
@@ -9942,6 +10292,10 @@ gif_load (f, img)
     }
   
   DGifCloseFile (gif);
+
+  /* Maybe fill in the background field while we have ximg handy. */
+  if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
+    IMAGE_BACKGROUND (img, f, ximg);
   
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -9987,6 +10341,7 @@ enum gs_keyword_index
   GS_ALGORITHM,
   GS_HEURISTIC_MASK,
   GS_MASK,
+  GS_BACKGROUND,
   GS_LAST
 };
 
@@ -10006,7 +10361,8 @@ static struct image_keyword gs_format[GS_LAST] =
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type `ghostscript'.  */
@@ -10250,8 +10606,8 @@ selected frame.  Value is VALUE.  */)
   struct frame *f = check_x_frame (frame);
   Atom prop_atom;
 
-  CHECK_STRING (prop, 1);
-  CHECK_STRING (value, 2);
+  CHECK_STRING (prop);
+  CHECK_STRING (value);
 
   BLOCK_INPUT;
   prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
@@ -10277,7 +10633,7 @@ FRAME nil or omitted means use the selected frame.  Value is PROP.  */)
   struct frame *f = check_x_frame (frame);
   Atom prop_atom;
 
-  CHECK_STRING (prop, 1);
+  CHECK_STRING (prop);
   BLOCK_INPUT;
   prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
   XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom);
@@ -10308,7 +10664,7 @@ value.  */)
   int actual_format;
   unsigned long actual_size, bytes_remaining;
 
-  CHECK_STRING (prop, 1);
+  CHECK_STRING (prop);
   BLOCK_INPUT;
   prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False);
   rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
@@ -10907,7 +11263,7 @@ compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
   
   /* Move the tooltip window where the mouse pointer is.  Resize and
      show it.  */
-  if (!INTEGERP (left) && !INTEGERP (top))
+  if (!INTEGERP (left) || !INTEGERP (top))
     {
       BLOCK_INPUT;
       XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
@@ -10927,10 +11283,15 @@ compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
 
   if (INTEGERP (left))
     *root_x = XINT (left);
-  else if (*root_x + XINT (dx) + width > FRAME_X_DISPLAY_INFO (f)->width)
+  else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width)
+    /* It fits to the right of the pointer.  */
+    *root_x += XINT (dx);
+  else if (width + XINT (dx) <= *root_x)
+    /* It fits to the left of the pointer.  */
     *root_x -= width + XINT (dx);
   else
-    *root_x += XINT (dx);
+    /* Put it left-justified on the screen--it ought to fit that way.  */
+    *root_x = 0;
 }
 
 
@@ -10961,7 +11322,6 @@ Text larger than the specified size is clipped.  */)
 {
   struct frame *f;
   struct window *w;
-  Lisp_Object buffer, top, left, max_width, max_height;
   int root_x, root_y;
   struct buffer *old_buffer;
   struct text_pos pos;
@@ -10974,22 +11334,22 @@ Text larger than the specified size is clipped.  */)
 
   GCPRO4 (string, parms, frame, timeout);
 
-  CHECK_STRING (string, 0);
+  CHECK_STRING (string);
   f = check_x_frame (frame);
   if (NILP (timeout))
     timeout = make_number (5);
   else
-    CHECK_NATNUM (timeout, 2);
+    CHECK_NATNUM (timeout);
   
   if (NILP (dx))
     dx = make_number (5);
   else
-    CHECK_NUMBER (dx, 5);
+    CHECK_NUMBER (dx);
   
   if (NILP (dy))
     dy = make_number (-10);
   else
-    CHECK_NUMBER (dy, 6);
+    CHECK_NUMBER (dy);
 
   if (NILP (last_show_tip_args))
     last_show_tip_args = Fmake_vector (make_number (3), Qnil);
@@ -11254,8 +11614,8 @@ selection dialog's entry field, if MUSTMATCH is non-nil.  */)
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
   GCPRO5 (prompt, dir, default_filename, mustmatch, file);
-  CHECK_STRING (prompt, 0);
-  CHECK_STRING (dir, 1);
+  CHECK_STRING (prompt);
+  CHECK_STRING (dir);
 
   /* Prevent redisplay.  */
   specbind (Qinhibit_redisplay, Qt);
@@ -11487,6 +11847,8 @@ syms_of_xfns ()
   staticpro (&Qauto_lower);
   Qbar = intern ("bar");
   staticpro (&Qbar);
+  Qhbar = intern ("hbar");
+  staticpro (&Qhbar);
   Qborder_color = intern ("border-color");
   staticpro (&Qborder_color);
   Qborder_width = intern ("border-width");
@@ -11557,6 +11919,14 @@ syms_of_xfns ()
   staticpro (&Qcancel_timer);
   Qwait_for_wm = intern ("wait-for-wm");
   staticpro (&Qwait_for_wm);
+  Qfullscreen = intern ("fullscreen");
+  staticpro (&Qfullscreen);
+  Qfullwidth = intern ("fullwidth");
+  staticpro (&Qfullwidth);
+  Qfullheight = intern ("fullheight");
+  staticpro (&Qfullheight);
+  Qfullboth = intern ("fullboth");
+  staticpro (&Qfullboth);
   /* This is the end of symbol initialization.  */
 
   /* Text property `display' should be nonsticky by default.  */
@@ -11769,8 +12139,6 @@ meaning don't clear the cache.  */);
   /* Images.  */
   Qxbm = intern ("xbm");
   staticpro (&Qxbm);
-  QCtype = intern (":type");
-  staticpro (&QCtype);
   QCconversion = intern (":conversion");
   staticpro (&QCconversion);
   QCheuristic_mask = intern (":heuristic-mask");