(x_set_cursor_color): Set cursor_gc as well.
[bpt/emacs.git] / src / w32fns.c
index beb6128..319f8d9 100644 (file)
@@ -270,9 +270,13 @@ Lisp_Object Qw32_charset_mac;
 Lisp_Object Qw32_charset_unicode;
 #endif
 
+Lisp_Object Qfullscreen;
+Lisp_Object Qfullwidth;
+Lisp_Object Qfullheight;
+Lisp_Object Qfullboth;
+
 extern Lisp_Object Qtop;
 extern Lisp_Object Qdisplay;
-extern Lisp_Object Qtool_bar_lines;
 
 /* State variables for emulating a three button mouse. */
 #define LMOUSE 1
@@ -281,9 +285,9 @@ extern Lisp_Object Qtool_bar_lines;
 
 static int button_state = 0;
 static W32Msg saved_mouse_button_msg;
-static unsigned mouse_button_timer;    /* non-zero when timer is active */
+static unsigned mouse_button_timer = 0;        /* non-zero when timer is active */
 static W32Msg saved_mouse_move_msg;
-static unsigned mouse_move_timer;
+static unsigned mouse_move_timer = 0;
 
 /* Window that is tracking the mouse.  */
 static HWND track_mouse_window;
@@ -292,8 +296,14 @@ FARPROC track_mouse_event_fn;
 /* W95 mousewheel handler */
 unsigned int msh_mousewheel = 0;       
 
+/* Timers */
 #define MOUSE_BUTTON_ID        1
 #define MOUSE_MOVE_ID  2
+#define MENU_FREE_ID 3
+/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
+   is received.  */
+#define MENU_FREE_DELAY 1000
+static unsigned menu_free_timer = 0;
 
 /* The below are defined in frame.c.  */
 
@@ -681,6 +691,7 @@ static void x_change_window_heights P_ ((Lisp_Object, int));
 /* TODO: Native Input Method support; see x_create_im.  */
 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_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));
@@ -734,7 +745,8 @@ static struct x_frame_parm_table x_frame_parms[] =
   {"screen-gamma", x_set_screen_gamma},
   {"line-spacing", x_set_line_spacing},
   {"left-fringe", x_set_fringe_width},
-  {"right-fringe", x_set_fringe_width}
+  {"right-fringe", x_set_fringe_width},
+  {"fullscreen", x_set_fullscreen},
 };
 
 /* Attach the `x-frame-parameter' properties to
@@ -750,6 +762,27 @@ 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.w32->top_pos
+      || new_left != f->output_data.w32->left_pos)
+    {
+      int move_x = new_left;
+      int move_y = new_top;
+
+      f->output_data.w32->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;
    otherwise call the `x_set_...' function for that parameter.  */
@@ -778,6 +811,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;
 
@@ -835,11 +869,13 @@ x_set_frame_parameters (f, alist)
       val = values[p];
       if (EQ (prop, Qforeground_color)
          || EQ (prop, Qbackground_color)
-         || EQ (prop, Qfont))
+         || EQ (prop, Qfont)
+         || EQ (prop, Qfullscreen))
        {
          register Lisp_Object param_index, old_value;
 
          old_value = get_frame_param (f, prop);
+         fullscreen_is_being_set |= EQ (prop, Qfullscreen);
 
          if (NILP (Fequal (val, old_value)))
            {
@@ -876,7 +912,8 @@ x_set_frame_parameters (f, alist)
        icon_left = val;
       else if (EQ (prop, Qforeground_color)
               || EQ (prop, Qbackground_color)
-              || EQ (prop, Qfont))
+              || EQ (prop, Qfont)
+              || EQ (prop, Qfullscreen))
        /* Processed above.  */
        continue;
       else
@@ -929,6 +966,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
@@ -1032,19 +1084,20 @@ x_real_positions (f, xptr, yptr)
      int *xptr, *yptr;
 {
   POINT pt;
+  RECT rect;
 
-  {
-      RECT rect;
-      
-      GetClientRect(FRAME_W32_WINDOW(f), &rect);
-      AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
-      
-      pt.x = rect.left;
-      pt.y = rect.top;
-  }
+  GetClientRect(FRAME_W32_WINDOW(f), &rect);
+  AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
+
+  pt.x = rect.left;
+  pt.y = rect.top;
 
   ClientToScreen (FRAME_W32_WINDOW(f), &pt);
 
+  /* Remember x_pixels_diff and y_pixels_diff.  */
+  f->output_data.w32->x_pixels_diff = pt.x - rect.left;
+  f->output_data.w32->y_pixels_diff = pt.y - rect.top;
+
   *xptr = pt.x;
   *yptr = pt.y;
 }
@@ -1967,6 +2020,25 @@ x_set_line_spacing (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.w32->want_fullscreen = FULLSCREEN_NONE;
+  else if (EQ (new_value, Qfullboth))
+    f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
+  else if (EQ (new_value, Qfullwidth))
+    f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
+  else if (EQ (new_value, Qfullheight))
+    f->output_data.w32->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.  */
 
@@ -2214,11 +2286,18 @@ x_set_cursor_color (f, arg, oldval)
        fore_pixel = FRAME_BACKGROUND_PIXEL (f);
     }
 
-  FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
+  f->output_data.w32->cursor_foreground_pixel = fore_pixel;
   f->output_data.w32->cursor_pixel = pixel;
 
   if (FRAME_W32_WINDOW (f) != 0)
     {
+      BLOCK_INPUT;
+      /* Update frame's cursor_gc.  */
+      f->output_data.w32->cursor_gc->foreground = fore_pixel;
+      f->output_data.w32->cursor_gc->background = pixel;
+
+      UNBLOCK_INPUT;
+
       if (FRAME_VISIBLE_P (f))
        {
          x_update_cursor (f, 0);
@@ -3285,7 +3364,9 @@ x_figure_window_size (f, parms)
        : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
        ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
        : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
+
   x_compute_fringe_widths (f, 0);
+
   f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
   f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
 
@@ -3356,6 +3437,22 @@ x_figure_window_size (f, parms)
        window_prompting |= PPosition;
     }
 
+  if (f->output_data.w32->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.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
+      f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
+      f->output_data.w32->left_pos = left;
+      f->output_data.w32->top_pos = top;
+    }
+
   return window_prompting;
 }
 
@@ -4157,6 +4254,7 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
       {
        PAINTSTRUCT paintStruct;
         RECT update_rect;
+       bzero (&update_rect, sizeof (update_rect));
 
        f = x_window_to_frame (dpyinfo, hwnd);
        if (f == 0)
@@ -4168,18 +4266,15 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
         /* MSDN Docs say not to call BeginPaint if GetUpdateRect
            fails.  Apparently this can happen under some
            circumstances.  */
-        if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
+        if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
           {
             enter_crit ();
             BeginPaint (hwnd, &paintStruct);
 
-           if (w32_strict_painting)
-             /* The rectangles returned by GetUpdateRect and BeginPaint
-                do not always match.  GetUpdateRect seems to be the
-                more reliable of the two.  */
-             wmsg.rect = update_rect;
-           else
-             wmsg.rect = paintStruct.rcPaint;
+           /* The rectangles returned by GetUpdateRect and BeginPaint
+              do not always match.  Play it safe by assuming both areas
+              are invalid.  */
+           UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
 
 #if defined (W32_DEBUG_DISPLAY)
             DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
@@ -4686,6 +4781,18 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
          KillTimer (hwnd, mouse_move_timer);
          mouse_move_timer = 0;
        }
+      else if (wParam == menu_free_timer)
+       {
+         KillTimer (hwnd, menu_free_timer);
+         menu_free_timer = 0;
+         f = x_window_to_frame (dpyinfo, hwnd);
+         if (!f->output_data.w32->menu_command_in_progress)
+           {
+             /* Free memory used by owner-drawn and help-echo strings.  */
+             w32_free_menu_strings (hwnd);
+             f->output_data.w32->menubar_active = 0;
+           }
+       }
       return 0;
   
     case WM_NCACTIVATE:
@@ -4741,12 +4848,11 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
     case WM_EXITMENULOOP:
       f = x_window_to_frame (dpyinfo, hwnd);
 
-      /* Free memory used by owner-drawn and help-echo strings.  */
-      w32_free_menu_strings (hwnd);
-
-      /* Indicate that menubar can be modified again.  */
-      if (f)
-       f->output_data.w32->menubar_active = 0;
+      /* If a menu command is not already in progress, check again
+        after a short delay, since Windows often (always?) sends the
+        WM_EXITMENULOOP before the corresponding WM_COMMAND message.  */
+      if (f && !f->output_data.w32->menu_command_in_progress)
+       menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
       goto dflt;
 
     case WM_MENUSELECT:
@@ -4883,9 +4989,20 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
          w32_system_caret_hwnd = NULL;
          DestroyCaret ();
        }
+      goto command;
+    case WM_COMMAND:
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f && HIWORD (wParam) == 0)
+       {
+         f->output_data.w32->menu_command_in_progress = 1;
+         if (menu_free_timer)
+           {
+             KillTimer (hwnd, menu_free_timer);
+             menu_free_timer = 0;        
+           }
+       }
     case WM_MOVE:
     case WM_SIZE:
-    case WM_COMMAND:
     command:
       wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
@@ -5560,12 +5677,14 @@ This function is an internal primitive--use `make-frame' instead.  */)
   
   x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
                       "menuBar", "MenuBar", RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
+  x_default_parameter (f, parms, Qtool_bar_lines, make_number (HAVE_IMAGES),
                        "toolBar", "ToolBar", RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
                       "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
   x_default_parameter (f, parms, Qtitle, Qnil,
                       "title", "Title", RES_TYPE_STRING);
+  x_default_parameter (f, parms, Qfullscreen, Qnil,
+                       "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
 
   f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
   f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
@@ -5818,6 +5937,10 @@ w32_load_system_font (f,fontname,size)
            ended up with. */
       return NULL;
 
+    /* Specify anti-aliasing to prevent Cleartype fonts being used,
+       since those fonts leave garbage behind.  */
+    lf.lfQuality = ANTIALIASED_QUALITY;
+
     font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
     bzero (font, sizeof (*font));
 
@@ -5957,10 +6080,10 @@ w32_load_system_font (f,fontname,size)
 
     /* Set global flag fonts_changed_p to non-zero if the font loaded
        has a character with a smaller width than any other character
-       before, or if the font loaded has a smalle>r height than any
+       before, or if the font loaded has a smaller height than any
        other font loaded before.  If this happens, it will make a
        glyph matrix reallocation necessary.  */
-    fonts_changed_p = x_compute_min_glyph_bounds (f);
+    fonts_changed_p |= x_compute_min_glyph_bounds (f);
     UNBLOCK_INPUT;
     return fontp;
   }
@@ -6334,7 +6457,8 @@ w32_to_all_x_charsets (fncharset)
       /* Handle startup case of w32-charset-info-alist not
          being set up yet. */
       if (NILP(Vw32_charset_info_alist))
-        return "iso8859-1";
+        return Fcons (build_string ("iso8859-1"), Qnil);
+
       charset_type = Qw32_charset_ansi;
       break;
     case DEFAULT_CHARSET:
@@ -6522,8 +6646,8 @@ w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
   char height_dpi[8];
   char width_pixels[8];
   char *fontname_dash;
-  int display_resy = one_w32_display_info.resy;
-  int display_resx = one_w32_display_info.resx;
+  int display_resy = (int) one_w32_display_info.resy;
+  int display_resx = (int) one_w32_display_info.resx;
   int bufsz;
   struct coding_system coding;
 
@@ -6639,7 +6763,7 @@ x_to_w32_font (lpxstr, lplogfont)
       char name[50], weight[20], slant, pitch, pixels[10], height[10],
         width[10], resy[10], remainder[50];
       char * encoding;
-      int dpi = one_w32_display_info.resy;
+      int dpi = (int) one_w32_display_info.resy;
 
       fields = sscanf (lpxstr,
                       "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
@@ -7040,11 +7164,13 @@ enum_font_cb2 (lplf, lptm, FontType, lpef)
       {
         charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
 
-        /* Ensure that charset is valid for this font.
-          Continue if invalid in case charset contains a wildcard.  */
-        if (charset
-            && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
-          charset = NULL;
+       /* We already checked charsets above, but DEFAULT_CHARSET
+           slipped through.  So only allow exact matches for DEFAULT_CHARSET.  */
+       if (charset
+           && strncmp (charset, "*-*", 3) != 0
+           && lpef->logfont.lfCharSet == DEFAULT_CHARSET
+           && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
+         return 1;
       }
 
     if (charset)
@@ -7649,8 +7775,10 @@ If omitted or nil, that stands for the selected frame's display.  */)
   else
     cap = GetDeviceCaps (hdc,NUMCOLORS);
 
+  /* We force 24+ bit depths to 24-bit, both to prevent an overflow
+     and because probably is more meaningful on Windows anyway */
   if (cap < 0)
-    cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
+    cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
   
   ReleaseDC (dpyinfo->root_window, hdc);
   
@@ -8020,7 +8148,6 @@ DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
 }
 
 \f
-\f
 /***********************************************************************
                            Image types
  ***********************************************************************/
@@ -8046,8 +8173,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;
 
@@ -8377,6 +8504,64 @@ image_spec_value (spec, key, found)
 }
      
 
+#ifdef HAVE_IMAGES
+DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
+       doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
+PIXELS non-nil means return the size in pixels, otherwise return the
+size in canonical character units.
+FRAME is the frame on which the image will be displayed.  FRAME nil
+or omitted means use the selected frame.  */)
+     (spec, pixels, frame)
+     Lisp_Object spec, pixels, frame;
+{
+  Lisp_Object size;
+
+  size = Qnil;
+  if (valid_image_p (spec))
+    {
+      struct frame *f = check_x_frame (frame);
+      int id = lookup_image (f, spec);
+      struct image *img = IMAGE_FROM_ID (f, id);
+      int width = img->width + 2 * img->hmargin;
+      int height = img->height + 2 * img->vmargin;
+  
+      if (NILP (pixels))
+       size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
+                     make_float ((double) height / CANON_Y_UNIT (f)));
+      else
+       size = Fcons (make_number (width), make_number (height));
+    }
+  else
+    error ("Invalid image specification");
+
+  return size;
+}
+
+
+DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
+       doc: /* Return t if image SPEC has a mask bitmap.
+FRAME is the frame on which the image will be displayed.  FRAME nil
+or omitted means use the selected frame.  */)
+     (spec, frame)
+     Lisp_Object spec, frame;
+{
+  Lisp_Object mask;
+
+  mask = Qnil;
+  if (valid_image_p (spec))
+    {
+      struct frame *f = check_x_frame (frame);
+      int id = lookup_image (f, spec);
+      struct image *img = IMAGE_FROM_ID (f, id);
+      if (img->mask)
+       mask = Qt;
+    }
+  else
+    error ("Invalid image specification");
+
+  return mask;
+}
+#endif
 
 \f
 /***********************************************************************
@@ -8479,7 +8664,7 @@ image_ascent (img, face)
        ascent = height / 2;
     }
   else
-    ascent = height * img->ascent / 100.0;
+    ascent = (int) (height * img->ascent / 100.0);
 
   return ascent;
 }
@@ -8488,20 +8673,21 @@ image_ascent (img, face)
 \f
 /* Image background colors.  */
 
-static unsigned long
+/* Find the "best" corner color of a bitmap.  XIMG is assumed to a device
+   context with the bitmap selected.  */
+static COLORREF
 four_corners_best (ximg, width, height)
-     XImage *ximg;
+     HDC ximg;
      unsigned long width, height;
 {
-#if 0 /* TODO: Image support.  */
-  unsigned long corners[4], best;
+  COLORREF 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);
+  corners[0] = GetPixel (ximg, 0, 0);
+  corners[1] = GetPixel (ximg, width - 1, 0);
+  corners[2] = GetPixel (ximg, width - 1, height - 1);
+  corners[3] = GetPixel (ximg, 0, height - 1);
 
   /* Choose the most frequently found color as background.  */
   for (i = best_count = 0; i < 4; ++i)
@@ -8517,9 +8703,6 @@ four_corners_best (ximg, width, height)
     }
 
   return best;
-#else
-  return 0;
-#endif
 }
 
 /* Return the `background' field of IMG.  If IMG doesn't have one yet,
@@ -8617,29 +8800,29 @@ x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
      struct image *img;
      int pixmap_p, mask_p, colors_p;
 {
-#if 0 /* TODO: W32 image support  */
   if (pixmap_p && img->pixmap)
     {
-      XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
-      img->pixmap = None;
+      DeleteObject (img->pixmap);
+      img->pixmap = NULL;
       img->background_valid = 0;
     }
 
   if (mask_p && img->mask)
     {
-      XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
-      img->mask = None;
+      DeleteObject (img->mask);
+      img->mask = NULL;
       img->background_transparent_valid = 0;
     }
       
   if (colors_p && img->ncolors)
     {
+#if 0  /* TODO: color table support.  */
       x_free_colors (f, img->colors, img->ncolors);
+#endif
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
-#endif
 }
 
 /* Free X resources of image IMG which is used on frame F.  */
@@ -8649,18 +8832,18 @@ x_clear_image (f, img)
      struct frame *f;
      struct image *img;
 {
-#if 0 /* TODO: W32 image support  */
-
   if (img->pixmap)
     {
       BLOCK_INPUT;
-      XFreePixmap (NULL, img->pixmap);
+      DeleteObject (img->pixmap);
       img->pixmap = 0;
       UNBLOCK_INPUT;
     }
 
   if (img->ncolors)
     {
+#if 0 /* TODO: color table support  */
+
       int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
       
       /* If display has an immutable color map, freeing colors is not
@@ -8676,12 +8859,12 @@ x_clear_image (f, img)
                       img->ncolors, 0);
          UNBLOCK_INPUT;
        }
+#endif
       
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
-#endif
 }
 
 
@@ -8697,7 +8880,6 @@ x_alloc_image_color (f, img, color_name, dflt)
      Lisp_Object color_name;
      unsigned long dflt;
 {
-#if 0 /* TODO: allocing colors.  */
   XColor color;
   unsigned long result;
 
@@ -8717,8 +8899,6 @@ x_alloc_image_color (f, img, color_name, dflt)
   else
     result = dflt;
   return result;
-#endif
-  return 0;
 }
 
 
@@ -8793,20 +8973,23 @@ clear_image_cache (f, force_p)
     {
       EMACS_TIME t;
       unsigned long old;
-      int i, any_freed_p = 0;
+      int i, nfreed;
 
       EMACS_GET_TIME (t);
       old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
       
-      for (i = 0; i < c->used; ++i)
+      /* Block input so that we won't be interrupted by a SIGIO
+        while being in an inconsistent state.  */
+      BLOCK_INPUT;
+      
+      for (i = nfreed = 0; i < c->used; ++i)
        {
          struct image *img = c->images[i];
          if (img != NULL
-             && (force_p
-                 || (img->timestamp > old)))
+             && (force_p || (img->timestamp < old)))
            {
              free_image (f, img);
-             any_freed_p = 1;
+             ++nfreed;
            }
        }
 
@@ -8814,11 +8997,22 @@ clear_image_cache (f, force_p)
         Emacs was iconified for a longer period of time.  In that
         case, current matrices may still contain references to
         images freed above.  So, clear these matrices.  */
-      if (any_freed_p)
+      if (nfreed)
        {
-         clear_current_matrices (f);
+         Lisp_Object tail, frame;
+         
+         FOR_EACH_FRAME (tail, frame)
+           {
+             struct frame *f = XFRAME (frame);
+             if (FRAME_W32_P (f)
+                 && FRAME_X_IMAGE_CACHE (f) == c)
+               clear_current_matrices (f);
+           }
+
          ++windows_or_buffers_changed;
        }
+
+      UNBLOCK_INPUT;
     }
 }
 
@@ -8894,7 +9088,7 @@ postprocess_image (f, img)
            }
          else if (NILP (mask) && found_p && img->mask)
            {
-             XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+             DeleteObject (img->mask);
              img->mask = NULL;
            }
        }
@@ -9109,8 +9303,6 @@ forall_images_in_image_cache (f, fn)
                            W32 support code
  ***********************************************************************/
 
-#if 0 /* TODO: W32 specific image code.  */
-
 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
                                             XImage **, Pixmap *));
 static void x_destroy_x_image P_ ((XImage *));
@@ -9120,8 +9312,10 @@ static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
    frame F.  Set *XIMG and *PIXMAP to the XImage and Pixmap created.
    Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
-   via xmalloc.  Print error messages via image_error if an error
-   occurs.  Value is non-zero if successful.  */
+   via xmalloc.  DEPTH of zero signifies a 24 bit image, otherwise
+   DEPTH should indicate the bit depth of the image.  Print error
+   messages via image_error if an error occurs.  Value is non-zero if
+   successful.  */
 
 static int
 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
@@ -9130,37 +9324,71 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
      XImage **ximg;
      Pixmap *pixmap;
 {
-#if 0 /* TODO: Image support for W32 */
-  Display *display = FRAME_W32_DISPLAY (f);
-  Screen *screen = FRAME_X_SCREEN (f);
-  Window window = FRAME_W32_WINDOW (f);
+  BITMAPINFOHEADER *header;
+  HDC hdc;
+  int scanline_width_bits;
+  int remainder;
+  int palette_colors = 0;
 
-  xassert (interrupt_input_blocked);
+  if (depth == 0)
+    depth = 24;
+
+  if (depth != 1 && depth != 4 && depth != 8
+      && depth != 16 && depth != 24 && depth != 32)
+    {
+      image_error ("Invalid image bit depth specified", Qnil, Qnil);
+      return 0;
+    }
+
+  scanline_width_bits = width * depth;
+  remainder = scanline_width_bits % 32;
+
+  if (remainder)
+    scanline_width_bits += 32 - remainder;
 
-  if (depth <= 0)
-    depth = one_w32_display_info.n_cbits;
-  *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
-                       depth, ZPixmap, 0, NULL, width, height,
-                       depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
+  /* Bitmaps with a depth less than 16 need a palette.  */
+  /* BITMAPINFO structure already contains the first RGBQUAD.  */
+  if (depth < 16)
+    palette_colors = 1 << depth - 1;
+
+  *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
   if (*ximg == NULL)
     {
-      image_error ("Unable to allocate X image", Qnil, Qnil);
+      image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
       return 0;
     }
 
-  /* Allocate image raster.  */
-  (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
+  header = &((*ximg)->info.bmiHeader);
+  bzero (&((*ximg)->info), sizeof (BITMAPINFO));
+  header->biSize = sizeof (*header);
+  header->biWidth = width;
+  header->biHeight = -height;  /* negative indicates a top-down bitmap.  */
+  header->biPlanes = 1;
+  header->biBitCount = depth;
+  header->biCompression = BI_RGB;
+  header->biClrUsed = palette_colors;
+
+  hdc = get_frame_dc (f);
+
+  /* Create a DIBSection and raster array for the bitmap,
+     and store its handle in *pixmap.  */
+  *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
+                             &((*ximg)->data), NULL, 0);
 
-  /* Allocate a pixmap of the same size.  */
-  *pixmap = XCreatePixmap (display, window, width, height, depth);
-  if (*pixmap == 0)
+  /* Realize display palette and garbage all frames. */
+  release_frame_dc (f, hdc);
+
+  if (*pixmap == NULL)
     {
+      DWORD err = GetLastError();
+      Lisp_Object errcode;
+      /* All system errors are < 10000, so the following is safe.  */
+      XSETINT (errcode, (int) err);
+      image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
       x_destroy_x_image (*ximg);
-      *ximg = NULL;
-      image_error ("Unable to create X pixmap", Qnil, Qnil);
       return 0;
     }
-#endif
+
   return 1;
 }
 
@@ -9174,9 +9402,9 @@ x_destroy_x_image (ximg)
   xassert (interrupt_input_blocked);
   if (ximg)
     {
-      xfree (ximg->data);
+      /* Data will be freed by DestroyObject.  */
       ximg->data = NULL;
-      XDestroyImage (ximg);
+      xfree (ximg);
     }
 }
 
@@ -9190,15 +9418,16 @@ x_put_x_image (f, ximg, pixmap, width, height)
      XImage *ximg;
      Pixmap pixmap;
 {
+
+#if TODO  /* W32 specific image code.  */
   GC gc;
-  
+
   xassert (interrupt_input_blocked);
   gc = XCreateGC (NULL, pixmap, 0, NULL);
   XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
   XFreeGC (NULL, gc);
-}
-
 #endif
+}
 
 \f
 /***********************************************************************
@@ -9722,6 +9951,8 @@ xbm_load_image (f, img, contents, end)
   if (rc)
     {
       int depth = one_w32_display_info.n_cbits;
+      int planes = one_w32_display_info.n_planes;
+
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
       unsigned long background = FRAME_BACKGROUND_PIXEL (f);
       Lisp_Object value;
@@ -9739,16 +9970,9 @@ xbm_load_image (f, img, contents, end)
          img->background = background;
          img->background_valid = 1;
        }
-      
-#if 0 /* TODO : Port image display to W32 */
       img->pixmap
-       = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
-                                      FRAME_W32_WINDOW (f),
-                                      data,
-                                      img->width, img->height,
-                                      foreground, background,
-                                      depth);
-#endif
+       = CreateBitmap (img->width, img->height, planes, depth, data);
+
       xfree (data);
 
       if (img->pixmap == 0)
@@ -10356,13 +10580,14 @@ colors_in_color_table (n)
 #endif /* TODO */
 
 \f
+#ifdef HAVE_IMAGES /* TODO */
 /***********************************************************************
                              Algorithms
  ***********************************************************************/
-#if 0 /* TODO: image support. */
 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
+static void XPutPixel (XImage *, int, int, COLORREF);
 
 /* Non-zero means draw a cross on images having `:conversion
    disabled'.  */
@@ -10409,7 +10634,7 @@ x_to_xcolors (f, img, rgb_p)
   XImage *ximg;
 
   colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
-
+#if 0 /* TODO: implement image colors.  */
   /* Get the X image IMG->pixmap.  */
   ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
                    0, 0, img->width, img->height, ~0, ZPixmap);
@@ -10429,9 +10654,37 @@ x_to_xcolors (f, img, rgb_p)
     }
 
   XDestroyImage (ximg);
+#endif
   return colors;
 }
 
+/* Put a pixel of COLOR at position X, Y in XIMG.  XIMG must have been
+   created with CreateDIBSection, with the pointer to the bit values
+   stored in ximg->data.  */
+
+static void XPutPixel (ximg, x, y, color)
+     XImage * ximg;
+     int x, y;
+     COLORREF color;
+{
+  int width = ximg->info.bmiHeader.biWidth;
+  int height = ximg->info.bmiHeader.biHeight;
+  int rowbytes = width * 3;
+  unsigned char * pixel;
+
+  /* Don't support putting pixels in images with palettes.  */
+  xassert (ximg->info.bmiHeader.biBitCount == 24);
+
+  /* Ensure scanlines are aligned on 4 byte boundaries.  */
+  if (rowbytes % 4)
+    rowbytes += 4 - (rowbytes % 4);
+
+  pixel = ximg->data + y * rowbytes + x * 3;
+  *pixel = 255 - GetRValue (color);
+  *(pixel + 1) = 255 - GetGValue (color);
+  *(pixel + 2) = 255 - GetBValue (color);
+}
+
 
 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
    RGB members are set.  F is the frame on which this all happens.
@@ -10447,9 +10700,9 @@ x_from_xcolors (f, img, colors)
   XImage *oimg;
   Pixmap pixmap;
   XColor *p;
-  
+#if 0   /* TODO: color tables.  */
   init_color_table ();
-  
+#endif
   x_create_x_image_and_pixmap (f, img->width, img->height, 0,
                               &oimg, &pixmap);
   p = colors;
@@ -10457,7 +10710,11 @@ x_from_xcolors (f, img, colors)
     for (x = 0; x < img->width; ++x, ++p)
       {
        unsigned long pixel;
+#if 0  /* TODO: color tables.  */
        pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
+#else
+       pixel = PALETTERGB (p->red, p->green, p->blue);
+#endif
        XPutPixel (oimg, x, y, pixel);
       }
 
@@ -10467,8 +10724,10 @@ x_from_xcolors (f, img, colors)
   x_put_x_image (f, oimg, pixmap, img->width, img->height);
   x_destroy_x_image (oimg);
   img->pixmap = pixmap;
+#if 0  /* TODO: color tables.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
+#endif
 }
 
 
@@ -10619,9 +10878,9 @@ x_disable_image (f, img)
      struct frame *f;
      struct image *img;
 {
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
 
-  if (dpyinfo->n_planes >= 2)
+  if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
     {
       /* Color (or grayscale).  Convert to gray, and equalize.  Just
         drawing such images with a stipple can look very odd, so
@@ -10645,8 +10904,9 @@ x_disable_image (f, img)
 
   /* Draw a cross over the disabled image, if we must or if we
      should.  */
-  if (dpyinfo->n_planes < 2 || cross_disabled_images)
+  if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
     {
+#if 0 /* TODO: full image support  */
       Display *dpy = FRAME_X_DISPLAY (f);
       GC gc;
 
@@ -10668,6 +10928,7 @@ x_disable_image (f, img)
                     img->width - 1, 0);
          XFreeGC (dpy, gc);
        }
+#endif
     }
 }
 
@@ -10685,6 +10946,7 @@ x_build_heuristic_mask (f, img, how)
      struct image *img;
      Lisp_Object how;
 {
+#if 0 /* TODO: full image support.  */
   Display *dpy = FRAME_W32_DISPLAY (f);
   XImage *ximg, *mask_img;
   int x, y, rc, use_img_background;
@@ -10748,9 +11010,11 @@ x_build_heuristic_mask (f, img, how)
   XDestroyImage (ximg);
 
   return 1;
+#else
+  return 0;
+#endif
 }
-#endif /* TODO */
-
+#endif
 \f
 /***********************************************************************
                       PBM (mono, gray, color)
@@ -11015,12 +11279,13 @@ pbm_load (f, img)
       || (type != PBM_MONO && max_color_idx < 0))
     goto error;
 
-  if (!x_create_x_image_and_pixmap (f, width, height, 0,
-                                   &ximg, &img->pixmap))
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     goto error;
 
+#if 0  /* TODO: color tables.  */
   /* Initialize the color hash table.  */
   init_color_table ();
+#endif
 
   if (type == PBM_MONO)
     {
@@ -11085,28 +11350,32 @@ pbm_load (f, img)
            
            if (r < 0 || g < 0 || b < 0)
              {
-               xfree (ximg->data);
-               ximg->data = NULL;
-               XDestroyImage (ximg);
+               x_destroy_x_image (ximg);
                image_error ("Invalid pixel value in image `%s'",
                             img->spec, Qnil);
                 goto error;
              }
            
            /* RGB values are now in the range 0..max_color_idx.
-              Scale this to the range 0..0xffff supported by X.  */
-           r = (double) r * 65535 / max_color_idx;
-           g = (double) g * 65535 / max_color_idx;
-           b = (double) b * 65535 / max_color_idx;
-           XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+              Scale this to the range 0..0xff supported by W32.  */
+           r = (int) ((double) r * 255 / max_color_idx);
+           g = (int) ((double) g * 255 / max_color_idx);
+           b = (int) ((double) b * 255 / max_color_idx);
+           XPutPixel (ximg, x, y,
+#if 0  /* TODO: color tables.  */
+                      lookup_rgb_color (f, r, g, b));
+#else
+           PALETTERGB (r, g, b));
+#endif
          }
     }
-  
+
+#if 0  /* TODO: color tables.  */
   /* Store in IMG->colors the colors allocated for the image, and
      free the color table.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
-  
+#endif
   /* 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);
@@ -13708,9 +13977,17 @@ Text larger than the specified size is clipped.  */)
          BLOCK_INPUT;
          compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
                          PIXEL_HEIGHT (f), &root_x, &root_y);
+
+         /* Put tooltip in topmost group and in position.  */
          SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
                        root_x, root_y, 0, 0,
                        SWP_NOSIZE | SWP_NOACTIVATE);
+
+         /* Ensure tooltip is on top of other topmost windows (eg menus).  */
+         SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
+                       0, 0, 0, 0,
+                       SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
          UNBLOCK_INPUT;
          goto start_timer;
        }
@@ -13828,10 +14105,16 @@ Text larger than the specified size is clipped.  */)
     AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
                      FRAME_EXTERNAL_MENU_BAR (f));
 
+    /* Position and size tooltip, and put it in the topmost group.  */
     SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
                  root_x, root_y, rect.right - rect.left,
                  rect.bottom - rect.top, SWP_NOACTIVATE);
 
+    /* Ensure tooltip is on top of other topmost windows (eg menus).  */
+    SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
+                 0, 0, 0, 0,
+                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+
     /* Let redisplay know that we have made the frame visible already.  */
     f->async_visible = 1;
 
@@ -14414,14 +14697,16 @@ If the underlying system call fails, value is nil.  */)
 
     if (pfn_GetDiskFreeSpaceEx)
       {
+       /* Unsigned large integers cannot be cast to double, so
+          use signed ones instead.  */
        LARGE_INTEGER availbytes;
        LARGE_INTEGER freebytes;
        LARGE_INTEGER totalbytes;
 
        if (pfn_GetDiskFreeSpaceEx(rootname,
-                                  &availbytes,
-                                  &totalbytes,
-                                  &freebytes))
+                                  (ULARGE_INTEGER *)&availbytes,
+                                  (ULARGE_INTEGER *)&totalbytes,
+                                  (ULARGE_INTEGER *)&freebytes))
          value = list3 (make_float ((double) totalbytes.QuadPart),
                         make_float ((double) freebytes.QuadPart),
                         make_float ((double) availbytes.QuadPart));
@@ -14469,9 +14754,6 @@ syms_of_w32fns ()
 
   w32_visible_system_caret_hwnd = NULL;
 
-  /* 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 &&&*/
   Qauto_raise = intern ("auto-raise");
   staticpro (&Qauto_raise);
   Qauto_lower = intern ("auto-lower");
@@ -14538,7 +14820,14 @@ syms_of_w32fns ()
   staticpro (&Qcenter);
   Qcancel_timer = intern ("cancel-timer");
   staticpro (&Qcancel_timer);
-  /* This is the end of symbol initialization.  */
+  Qfullscreen = intern ("fullscreen");
+  staticpro (&Qfullscreen);
+  Qfullwidth = intern ("fullwidth");
+  staticpro (&Qfullwidth);
+  Qfullheight = intern ("fullheight");
+  staticpro (&Qfullheight);
+  Qfullboth = intern ("fullboth");
+  staticpro (&Qfullboth);
 
   Qhyper = intern ("hyper");
   staticpro (&Qhyper);
@@ -14554,6 +14843,7 @@ syms_of_w32fns ()
   staticpro (&Qcontrol);
   Qshift = intern ("shift");
   staticpro (&Qshift);
+  /* This is the end of symbol initialization.  */
 
   /* Text property `display' should be nonsticky by default.  */
   Vtext_property_default_nonsticky
@@ -14965,12 +15255,10 @@ versions of Windows) characters.  */);
   set_frame_fontset_func = x_set_font;
   check_window_system_func = check_w32;
 
-#if 0 /* TODO Image support for W32 */
+#ifdef IMAGES
   /* Images.  */
   Qxbm = intern ("xbm");
   staticpro (&Qxbm);
-  QCtype = intern (":type");
-  staticpro (&QCtype);
   QCconversion = intern (":conversion");
   staticpro (&QCconversion);
   QCheuristic_mask = intern (":heuristic-mask");
@@ -14985,6 +15273,7 @@ versions of Windows) characters.  */);
   staticpro (&QCrelief);
   Qpostscript = intern ("postscript");
   staticpro (&Qpostscript);
+#if 0 /* TODO: These need entries at top of file.  */
   QCloader = intern (":loader");
   staticpro (&QCloader);
   QCbounding_box = intern (":bounding-box");
@@ -14993,10 +15282,12 @@ versions of Windows) characters.  */);
   staticpro (&QCpt_width);
   QCpt_height = intern (":pt-height");
   staticpro (&QCpt_height);
+#endif
   QCindex = intern (":index");
   staticpro (&QCindex);
   Qpbm = intern ("pbm");
   staticpro (&Qpbm);
+#endif
 
 #if HAVE_XPM
   Qxpm = intern ("xpm");
@@ -15023,13 +15314,16 @@ versions of Windows) characters.  */);
   staticpro (&Qpng);
 #endif
 
+#ifdef HAVE_IMAGES
   defsubr (&Sclear_image_cache);
+  defsubr (&Simage_size);
+  defsubr (&Simage_mask_p);
+#endif
 
 #if GLYPH_DEBUG
   defsubr (&Simagep);
   defsubr (&Slookup_image);
 #endif
-#endif /* TODO */
 
   hourglass_atimer = NULL;
   hourglass_shown_p = 0;
@@ -15053,10 +15347,14 @@ init_xfns ()
   image_types = NULL;
   Vimage_types = Qnil;
 
+#if HAVE_PBM
+  define_image_type (&pbm_type);
+#endif
+
 #if 0 /* TODO : Image support for W32 */
   define_image_type (&xbm_type);
   define_image_type (&gs_type);
-  define_image_type (&pbm_type);
+#endif
   
 #if HAVE_XPM
   define_image_type (&xpm_type);
@@ -15077,7 +15375,6 @@ init_xfns ()
 #if HAVE_PNG
   define_image_type (&png_type);
 #endif
-#endif /* TODO */
 }
 
 #undef abort