diff src/w32fns.c @ 15147:38c0ce06203f

(quit_char, Vwin32_enable_italics, Vwin32_enable_palette): New variables. (syms_of_win32fns): Set up new lisp variables.
author Geoff Voelker <voelker@cs.washington.edu>
date Fri, 03 May 1996 18:39:41 +0000
parents fb947ec168a8
children 220145cf7546
line wrap: on
line diff
--- a/src/w32fns.c	Fri May 03 18:39:18 1996 +0000
+++ b/src/w32fns.c	Fri May 03 18:39:41 1996 +0000
@@ -41,6 +41,7 @@
 extern void abort ();
 extern void free_frame_menubar ();
 extern struct scroll_bar *x_window_to_scroll_bar ();
+extern int quit_char;
 
 /* The colormap for converting color names to RGB values */
 Lisp_Object Vwin32_color_map;
@@ -52,6 +53,17 @@
    are passed on to Windows.  */
 Lisp_Object Vwin32_pass_optional_keys_to_system;
 
+/* Switch to control whether we inhibit requests for italicised fonts (which
+   are synthesized, look ugly, and are trashed by cursor movement under NT). */
+Lisp_Object Vwin32_enable_italics;
+
+/* Enable palette management. */
+Lisp_Object Vwin32_enable_palette;
+
+/* Control how close left/right button down events must be to
+   be converted to a middle button down event. */
+Lisp_Object Vwin32_mouse_button_tolerance;
+
 /* The name we're using in resource queries.  */
 Lisp_Object Vx_resource_name;
 
@@ -139,6 +151,15 @@
 Lisp_Object Quser_size;
 Lisp_Object Qdisplay;
 
+/* State variables for emulating a three button mouse. */
+#define LMOUSE 1
+#define MMOUSE 2
+#define RMOUSE 4
+
+static int button_state = 0;
+static Win32Msg saved_mouse_msg;
+static unsigned timer_id;	/* non-zero when timer is active */
+
 /* The below are defined in frame.c.  */
 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
 extern Lisp_Object Qunsplittable, Qmenu_bar_lines;
@@ -147,6 +168,10 @@
 
 extern Lisp_Object last_mouse_scroll_bar;
 extern int last_mouse_scroll_bar_pos;
+
+/* From win32term.c. */
+extern Lisp_Object Vwin32_num_mouse_buttons;
+
 Time last_mouse_movement_time;
 
 
@@ -823,25 +848,90 @@
 }
 
 
-#if 0
-DEFUN ("win32-rgb", Fwin32_rgb, Swin32_rgb, 3, 3, 0,
-       "Convert RGB numbers to a windows color reference.")
-    (red, green, blue)
-    Lisp_Object red, green, blue;
+DEFUN ("win32-define-rgb-color", Fwin32_define_rgb_color, Swin32_define_rgb_color, 4, 4, 0,
+  "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
+This adds or updates a named color to win32-color-map, making it available for use.\n\
+The original entry's RGB ref is returned, or nil if the entry is new.")
+    (red, green, blue, name)
+    Lisp_Object red, green, blue, name;
 {
-    Lisp_Object rgb;
-
-    CHECK_NUMBER (red, 0);
-    CHECK_NUMBER (green, 0);
-    CHECK_NUMBER (blue, 0);
-
-    XSET (rgb, Lisp_Int, RGB(XUINT(red), XUINT(green), XUINT(blue)));
-
-    return (rgb);
+  Lisp_Object rgb;
+  Lisp_Object oldrgb = Qnil;
+  Lisp_Object entry;
+
+  CHECK_NUMBER (red, 0);
+  CHECK_NUMBER (green, 0);
+  CHECK_NUMBER (blue, 0);
+  CHECK_STRING (name, 0);
+
+  XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
+
+  BLOCK_INPUT;
+
+  /* replace existing entry in win32-color-map or add new entry. */
+  entry = Fassoc (name, Vwin32_color_map);
+  if (NILP (entry))
+    {
+      entry = Fcons (name, rgb);
+      Vwin32_color_map = Fcons (entry, Vwin32_color_map);
+    }
+  else
+    {
+      oldrgb = Fcdr (entry);
+      Fsetcdr (entry, rgb);
+    }
+
+  UNBLOCK_INPUT;
+
+  return (oldrgb);
 }
 
-
-#else
+DEFUN ("win32-load-color-file", Fwin32_load_color_file, Swin32_load_color_file, 1, 1, 0,
+  "Create an alist of color entries from an external file (ie. rgb.txt).\n\
+Assign this value to win32-color-map to replace the existing color map.\n\
+\
+The file should define one named RGB color per line like so:\
+  R G B   name\n\
+where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
+    (filename)
+    Lisp_Object filename;
+{
+  FILE *fp;
+  Lisp_Object cmap = Qnil;
+  Lisp_Object abspath;
+
+  CHECK_STRING (filename, 0);
+  abspath = Fexpand_file_name (filename, Qnil);
+
+  fp = fopen (XSTRING (filename)->data, "rt");
+  if (fp)
+    {
+      char buf[512];
+      int red, green, blue;
+      int num;
+
+      BLOCK_INPUT;
+
+      while (fgets (buf, sizeof (buf), fp) != NULL) {
+	if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
+	  {
+	    char *name = buf + num;
+	    num = strlen (name) - 1;
+	    if (name[num] == '\n')
+	      name[num] = 0;
+	    cmap = Fcons (Fcons (build_string (name),
+				 make_number (RGB (red, green, blue))),
+			  cmap);
+	  }
+      }
+      fclose (fp);
+
+      UNBLOCK_INPUT;
+    }
+
+  return cmap;
+}
+
 /* The default colors for the win32 color map */
 typedef struct colormap_t 
 {
@@ -1115,7 +1205,6 @@
   
   return (cmap);
 }
-#endif
 
 Lisp_Object 
 win32_to_x_color (rgb)
@@ -1168,6 +1257,122 @@
   return ret;
 }
 
+
+void
+win32_regenerate_palette (FRAME_PTR f)
+{
+  struct win32_palette_entry * list;
+  LOGPALETTE *          log_palette;
+  HPALETTE              new_palette;
+  int                   i;
+
+  /* don't bother trying to create palette if not supported */
+  if (! FRAME_WIN32_DISPLAY_INFO (f)->has_palette)
+    return;
+
+  log_palette = (LOGPALETTE *)
+    alloca (sizeof (LOGPALETTE) +
+	     FRAME_WIN32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
+  log_palette->palVersion = 0x300;
+  log_palette->palNumEntries = FRAME_WIN32_DISPLAY_INFO (f)->num_colors;
+
+  list = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+  for (i = 0;
+       i < FRAME_WIN32_DISPLAY_INFO (f)->num_colors;
+       i++, list = list->next)
+    log_palette->palPalEntry[i] = list->entry;
+
+  new_palette = CreatePalette (log_palette);
+
+  enter_crit ();
+
+  if (FRAME_WIN32_DISPLAY_INFO (f)->palette)
+    DeleteObject (FRAME_WIN32_DISPLAY_INFO (f)->palette);
+  FRAME_WIN32_DISPLAY_INFO (f)->palette = new_palette;
+
+  /* Realize display palette and garbage all frames. */
+  release_frame_dc (f, get_frame_dc (f));
+
+  leave_crit ();
+}
+
+#define WIN32_COLOR(pe)  RGB (pe.peRed, pe.peGreen, pe.peBlue)
+#define SET_WIN32_COLOR(pe, color) \
+  do \
+    { \
+      pe.peRed = GetRValue (color); \
+      pe.peGreen = GetGValue (color); \
+      pe.peBlue = GetBValue (color); \
+      pe.peFlags = 0; \
+    } while (0)
+
+#if 0
+/* Keep these around in case we ever want to track color usage. */
+void
+win32_map_color (FRAME_PTR f, COLORREF color)
+{
+  struct win32_palette_entry * list = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+
+  if (NILP (Vwin32_enable_palette))
+    return;
+
+  /* check if color is already mapped */
+  while (list)
+    {
+      if (WIN32_COLOR (list->entry) == color)
+        {
+	  ++list->refcount;
+	  return;
+	}
+      list = list->next;
+    }
+
+  /* not already mapped, so add to list and recreate Windows palette */
+  list = (struct win32_palette_entry *)
+    xmalloc (sizeof (struct win32_palette_entry));
+  SET_WIN32_COLOR (list->entry, color);
+  list->refcount = 1;
+  list->next = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+  FRAME_WIN32_DISPLAY_INFO (f)->color_list = list;
+  FRAME_WIN32_DISPLAY_INFO (f)->num_colors++;
+
+  /* set flag that palette must be regenerated */
+  FRAME_WIN32_DISPLAY_INFO (f)->regen_palette = TRUE;
+}
+
+void
+win32_unmap_color (FRAME_PTR f, COLORREF color)
+{
+  struct win32_palette_entry * list = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+  struct win32_palette_entry **prev = &FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+
+  if (NILP (Vwin32_enable_palette))
+    return;
+
+  /* check if color is already mapped */
+  while (list)
+    {
+      if (WIN32_COLOR (list->entry) == color)
+        {
+	  if (--list->refcount == 0)
+	    {
+	      *prev = list->next;
+	      xfree (list);
+	      FRAME_WIN32_DISPLAY_INFO (f)->num_colors--;
+	      break;
+	    }
+	  else
+	    return;
+	}
+      prev = &list->next;
+      list = list->next;
+    }
+
+  /* set flag that palette must be regenerated */
+  FRAME_WIN32_DISPLAY_INFO (f)->regen_palette = TRUE;
+}
+#endif
+
 /* Decide if color named COLOR is valid for the display associated with
    the selected frame; if so, return the rgb values in COLOR_DEF.
    If ALLOC is nonzero, allocate a new colormap cell.  */
@@ -1185,11 +1390,42 @@
 
   if (!NILP (tem)) 
     {
-      /* map color to nearest in (default) palette, to avoid
-	 dithering on limited color displays. */
+      if (!NILP (Vwin32_enable_palette))
+	{
+	  struct win32_palette_entry * entry =
+	    FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+	  struct win32_palette_entry ** prev =
+	    &FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+      
+	  /* check if color is already mapped */
+	  while (entry)
+	    {
+	      if (WIN32_COLOR (entry->entry) == XUINT (tem))
+		break;
+	      prev = &entry->next;
+	      entry = entry->next;
+	    }
+
+	  if (entry == NULL && alloc)
+	    {
+	      /* not already mapped, so add to list */
+	      entry = (struct win32_palette_entry *)
+		xmalloc (sizeof (struct win32_palette_entry));
+	      SET_WIN32_COLOR (entry->entry, XUINT (tem));
+	      entry->next = NULL;
+	      *prev = entry;
+	      FRAME_WIN32_DISPLAY_INFO (f)->num_colors++;
+
+	      /* set flag that palette must be regenerated */
+	      FRAME_WIN32_DISPLAY_INFO (f)->regen_palette = TRUE;
+	    }
+	}
+      /* Ensure COLORREF value is snapped to nearest color in (default)
+	 palette by simulating the PALETTERGB macro.  This works whether
+	 or not the display device has a palette. */
       *color_def = XUINT (tem) | 0x2000000;
       return 1;
-    } 
+    }
   else 
     {
       return 0;
@@ -1243,6 +1479,7 @@
 {
   f->output_data.win32->foreground_pixel
     = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+
   if (FRAME_WIN32_WINDOW (f) != 0)
     {
       recompute_basic_faces (f);
@@ -2332,7 +2569,7 @@
 {
   WNDCLASS wc;
 
-  wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+  wc.style = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc = (WNDPROC) win32_wnd_proc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = WND_EXTRA_BYTES;
@@ -2391,71 +2628,12 @@
       SetWindowLong (hwnd, WND_X_UNITS_INDEX, FONT_WIDTH (f->output_data.win32->font));
       SetWindowLong (hwnd, WND_Y_UNITS_INDEX, f->output_data.win32->line_height);
       SetWindowLong (hwnd, WND_BACKGROUND_INDEX, f->output_data.win32->background_pixel);
+
+      /* Do this to discard the default setting specified by our parent. */
+      ShowWindow (hwnd, SW_HIDE);
     }
 }
 
-DWORD 
-win_msg_worker (dw)
-     DWORD dw;
-{
-  MSG msg;
-  
-  /* Ensure our message queue is created */
-  
-  PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
-  
-  PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
-  
-  while (GetMessage (&msg, NULL, 0, 0))
-    {
-      if (msg.hwnd == NULL)
-	{
-	  switch (msg.message)
-	    {
-	    case WM_EMACS_CREATEWINDOW:
-	      win32_createwindow ((struct frame *) msg.wParam);
-	      PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
-	      break;
-	    case WM_EMACS_CREATESCROLLBAR:
-	      {
-		HWND hwnd = win32_createscrollbar ((struct frame *) msg.wParam,
-						   (struct scroll_bar *) msg.lParam);
-		PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, (WPARAM)hwnd, 0);
-	      }
-	      break;
-	    case WM_EMACS_KILL:
-	      return (0);
-	    }
-	}
-      else
-	{
-	  DispatchMessage (&msg);
-	}
-    }
-  
-  return (0);
-}
-
-HDC 
-map_mode (hdc)
-     HDC hdc;
-{
-  if (hdc) 
-    {
-#if 0
-      /* Make mapping mode be in 1/20 of point */
-      
-      SetMapMode (hdc, MM_ANISOTROPIC);
-      SetWindowExtEx (hdc, 1440, 1440, NULL);
-      SetViewportExtEx (hdc,
-			GetDeviceCaps (hdc, LOGPIXELSX),
-			GetDeviceCaps (hdc, LOGPIXELSY),
-			NULL);
-#endif
-    }
-  return (hdc);
-}
-
 /* Convert between the modifier bits Win32 uses and the modifier bits
    Emacs uses.  */
 unsigned int
@@ -2643,6 +2821,60 @@
   return wparam;
 }
 
+/* Main message dispatch loop. */
+
+DWORD 
+win_msg_worker (dw)
+     DWORD dw;
+{
+  MSG msg;
+  
+  /* Ensure our message queue is created */
+  
+  PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+  
+  PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
+  
+  while (GetMessage (&msg, NULL, 0, 0))
+    {
+      if (msg.hwnd == NULL)
+	{
+	  switch (msg.message)
+	    {
+	    case WM_TIMER:
+	      if (saved_mouse_msg.msg.hwnd)
+		{
+		  Win32Msg wmsg = saved_mouse_msg;
+		  my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
+			       wmsg.msg.wParam, wmsg.msg.lParam);
+		  saved_mouse_msg.msg.hwnd = 0;
+		}
+	      timer_id = 0;
+	      break;
+	    case WM_EMACS_CREATEWINDOW:
+	      win32_createwindow ((struct frame *) msg.wParam);
+	      PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
+	      break;
+	    case WM_EMACS_CREATESCROLLBAR:
+	      {
+		HWND hwnd = win32_createscrollbar ((struct frame *) msg.wParam,
+						   (struct scroll_bar *) msg.lParam);
+		PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, (WPARAM)hwnd, 0);
+	      }
+	      break;
+	    case WM_EMACS_KILL:
+	      return (0);
+	    }
+	}
+      else
+	{
+	  DispatchMessage (&msg);
+	}
+    }
+  
+  return (0);
+}
+
 /* Main window procedure */
 
 extern char *lispy_function_keys[];
@@ -2662,50 +2894,33 @@
   switch (msg) 
     {
     case WM_ERASEBKGND:
-      {
-	HBRUSH hb;
-	HANDLE oldobj;
-	RECT rect;
-	
-	GetClientRect (hwnd, &rect);
-	
-	hb = CreateSolidBrush (GetWindowLong (hwnd, WND_BACKGROUND_INDEX));
-	
-	oldobj = SelectObject ((HDC)wParam, hb);
-	
-	FillRect((HDC)wParam, &rect, hb);
-	
-	SelectObject((HDC)wParam, oldobj);
-	
-	DeleteObject (hb);
-	
-	return (0);
-      }
+      enter_crit ();
+      GetUpdateRect (hwnd, &wmsg.rect, FALSE);
+      leave_crit ();
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      return 1;
+    case WM_PALETTECHANGED:
+      /* ignore our own changes */
+      if ((HWND)wParam != hwnd)
+        {
+	  /* simply notify main thread it may need to update frames */
+	  my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+	}
+      return 0;
     case WM_PAINT:
       {
 	PAINTSTRUCT paintStruct;
-		    
+
+	enter_crit ();
 	BeginPaint (hwnd, &paintStruct);
 	wmsg.rect = paintStruct.rcPaint;
 	EndPaint (hwnd, &paintStruct);
-      
+	leave_crit ();
+
 	my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       
 	return (0);
       }
-      
-    case WM_CREATE:
-      {
-	HDC hdc = my_get_dc (hwnd);
-
-	/* Make mapping mode be in 1/20 of point */
-
-	map_mode (hdc);
-
-	ReleaseDC (hwnd, hdc);
-      }
-      
-      return (0);
 
     case WM_KEYUP:
     case WM_SYSKEYUP:
@@ -2749,15 +2964,140 @@
     case WM_CHAR:
       wmsg.dwModifiers = construct_modifiers (wParam, lParam);
 
+      enter_crit ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+
+      /* Detect quit_char and set quit-flag directly.  Note that we dow
+         this *after* posting the message to ensure the main thread will
+         be woken up if blocked in sys_select(). */
+      {
+	int c = wParam;
+	if (isalpha (c) && (wmsg.dwModifiers == LEFT_CTRL_PRESSED 
+			    || wmsg.dwModifiers == RIGHT_CTRL_PRESSED))
+	  c = make_ctrl_char (c) & 0377;
+	if (c == quit_char)
+	  Vquit_flag = Qt;
+      }
+      leave_crit ();
       break;
 
+      /* Simulate middle mouse button events when left and right buttons
+	 are used together, but only if user has two button mouse. */
     case WM_LBUTTONDOWN:
+    case WM_RBUTTONDOWN:
+      if (XINT (Vwin32_num_mouse_buttons) == 3)
+	goto handle_plain_button;
+
+      {
+	int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
+	int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
+
+	if (button_state & this) abort ();
+
+	if (button_state == 0)
+	  SetCapture (hwnd);
+
+	button_state |= this;
+
+	if (button_state & other)
+	  {
+	    if (timer_id)
+	      {
+		KillTimer (NULL, timer_id);
+		timer_id = 0;
+
+		/* Generate middle mouse event instead. */
+		msg = WM_MBUTTONDOWN;
+		button_state |= MMOUSE;
+	      }
+	    else if (button_state & MMOUSE)
+	      {
+		/* Ignore button event if we've already generated a
+		   middle mouse down event.  This happens if the
+		   user releases and press one of the two buttons
+		   after we've faked a middle mouse event. */
+		return 0;
+	      }
+	    else
+	      {
+		/* Flush out saved message. */
+		wmsg = saved_mouse_msg;
+		my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
+			     wmsg.msg.wParam, wmsg.msg.lParam);
+	      }
+	    wmsg.dwModifiers = win32_get_modifiers ();
+	    my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+
+	    /* Clear message buffer. */
+	    saved_mouse_msg.msg.hwnd = 0;
+	  }
+	else
+	  {
+	    /* Hold onto message for now. */
+	    timer_id =
+	      SetTimer (NULL, 0, XINT (Vwin32_mouse_button_tolerance), NULL);
+	    saved_mouse_msg.msg.hwnd = hwnd;
+	    saved_mouse_msg.msg.message = msg;
+	    saved_mouse_msg.msg.wParam = wParam;
+	    saved_mouse_msg.msg.lParam = lParam;
+	    saved_mouse_msg.msg.time = GetMessageTime ();
+	    saved_mouse_msg.dwModifiers = win32_get_modifiers ();
+	  }
+      }
+      return 0;
+
     case WM_LBUTTONUP:
+    case WM_RBUTTONUP:
+      if (XINT (Vwin32_num_mouse_buttons) == 3)
+	goto handle_plain_button;
+
+      {
+	int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
+	int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
+
+	if ((button_state & this) == 0) abort ();
+
+	button_state &= ~this;
+
+	if (button_state & MMOUSE)
+	  {
+	    /* Only generate event when second button is released. */
+	    if ((button_state & other) == 0)
+	      {
+		msg = WM_MBUTTONUP;
+		button_state &= ~MMOUSE;
+
+		if (button_state) abort ();
+	      }
+	    else
+	      return 0;
+	  }
+	else
+	  {
+	    /* Flush out saved message if necessary. */
+	    if (saved_mouse_msg.msg.hwnd)
+	      {
+		wmsg = saved_mouse_msg;
+		my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
+			     wmsg.msg.wParam, wmsg.msg.lParam);
+	      }
+	  }
+	wmsg.dwModifiers = win32_get_modifiers ();
+	my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+
+	/* Always clear message buffer and cancel timer. */
+	saved_mouse_msg.msg.hwnd = 0;
+	KillTimer (NULL, timer_id);
+	timer_id = 0;
+
+	if (button_state == 0)
+	  ReleaseCapture ();
+      }
+      return 0;
+
     case WM_MBUTTONDOWN:
     case WM_MBUTTONUP:
-    case WM_RBUTTONDOWN:
-    case WM_RBUTTONUP:
+    handle_plain_button:
       {
 	BOOL up;
 
@@ -2769,9 +3109,28 @@
       }
       
       wmsg.dwModifiers = win32_get_modifiers ();
-      
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
-      goto dflt;
+      return 0;
+
+#if 0
+    case WM_MOUSEMOVE:
+      /* Flush out saved message if necessary. */
+      if (saved_mouse_msg.msg.hwnd)
+	{
+	  wmsg = saved_mouse_msg;
+	  my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
+		       wmsg.msg.wParam, wmsg.msg.lParam);
+	}
+      wmsg.dwModifiers = win32_get_modifiers ();
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+
+      /* Always clear message buffer and cancel timer. */
+      saved_mouse_msg.msg.hwnd = 0;
+      KillTimer (NULL, timer_id);
+      timer_id = 0;
+
+      return 0;
+#endif
 
     case WM_SETFOCUS:
       reset_modifiers ();
@@ -2782,10 +3141,12 @@
     case WM_VSCROLL:
     case WM_SYSCOMMAND:
     case WM_COMMAND:
+      wmsg.dwModifiers = win32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       goto dflt;
 
     case WM_CLOSE:
+      wmsg.dwModifiers = win32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       return 0;
 
@@ -2805,6 +3166,7 @@
 	    DWORD dwYUnits;
 	    RECT wr;
 	    
+	    wp.length = sizeof(wp);
 	    GetWindowRect (hwnd, &wr);
 	    
 	    enter_crit ();
@@ -2854,6 +3216,14 @@
       if (ret == 0) return (0);
       
       goto dflt;
+    case WM_EMACS_SHOWWINDOW:
+      return ShowWindow (hwnd, wParam);
+    case WM_EMACS_SETWINDOWPOS:
+      {
+	Win32WindowPos * pos = (Win32WindowPos *) wParam;
+	return SetWindowPos (hwnd, pos->hwndAfter,
+			     pos->x, pos->y, pos->cx, pos->cy, pos->flags);
+      }
     case WM_EMACS_DESTROYWINDOW:
       DestroyWindow ((HWND) wParam);
       break;
@@ -3027,6 +3397,8 @@
 
   /* Note that Windows does support scroll bars.  */
   FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
+  /* By default, make scrollbars the system standard width. */
+  f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
 
   XSETFRAME (frame, f);
   GCPRO1 (frame);
@@ -3250,90 +3622,64 @@
 }
 
 DEFUN ("focus-frame", Ffocus_frame, Sfocus_frame, 1, 1, 0,
-  "Set the focus on FRAME.")
+  "This function is obsolete, and does nothing.")
   (frame)
      Lisp_Object frame;
 {
-  CHECK_LIVE_FRAME (frame, 0);
-
-  if (FRAME_WIN32_P (XFRAME (frame)))
-    {
-      BLOCK_INPUT;
-      x_focus_on_frame (XFRAME (frame));
-      UNBLOCK_INPUT;
-      return frame;
-    }
-
   return Qnil;
 }
 
 DEFUN ("unfocus-frame", Funfocus_frame, Sunfocus_frame, 0, 0, 0,
-       "If a frame has been focused, release it.")
-     ()
+  "This function is obsolete, and does nothing.")
+  ()
 {
-  if (FRAME_WIN32_P (selected_frame))
-    {
-      struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (selected_frame);
-
-      if (dpyinfo->win32_focus_frame)
-	{
-	  BLOCK_INPUT;
-	  x_unfocus_frame (dpyinfo->win32_focus_frame);
-	  UNBLOCK_INPUT;
-	}
-    }
-  
   return Qnil;
 }
 
-XFontStruct 
-*win32_load_font (dpyinfo,name)
+XFontStruct *
+win32_load_font (dpyinfo,name)
 struct win32_display_info *dpyinfo;
 char * name;
 {
   XFontStruct * font = NULL;
   BOOL ok;
-  
+
   {
     LOGFONT lf;
-	
-    if (!name || !x_to_win32_font(name, &lf)) 
+
+    if (!name || !x_to_win32_font (name, &lf))
       return (NULL);
-	
+
     font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
-	
+
     if (!font) return (NULL);
-	
+
     BLOCK_INPUT;
-	
-    font->hfont = CreateFontIndirect(&lf);
+
+    font->hfont = CreateFontIndirect (&lf);
   }
-  
-    if (font->hfont == NULL) 
-      {
-	ok = FALSE;
-      } 
-    else 
-      {
-	HDC hdc;
-	HANDLE oldobj;
-
-	hdc = my_get_dc (dpyinfo->root_window);
-	
-	oldobj = SelectObject (hdc, font->hfont);
-	
-	ok = GetTextMetrics (hdc, &font->tm);
-	
-	SelectObject (hdc, oldobj);
-	
-	ReleaseDC (dpyinfo->root_window, hdc);
-      }
-  
+
+  if (font->hfont == NULL) 
+    {
+      ok = FALSE;
+    } 
+  else 
+    {
+      HDC hdc;
+      HANDLE oldobj;
+
+      hdc = GetDC (dpyinfo->root_window);
+      oldobj = SelectObject (hdc, font->hfont);
+      ok = GetTextMetrics (hdc, &font->tm);
+      SelectObject (hdc, oldobj);
+      ReleaseDC (dpyinfo->root_window, hdc);
+    }
+
   UNBLOCK_INPUT;
-  
+
   if (ok) return (font);
-  
-  win32_unload_font(dpyinfo, font);
+
+  win32_unload_font (dpyinfo, font);
   return (NULL);
 }
 
@@ -3428,31 +3774,70 @@
      char * lpw;
 {
   if (!lpw) return (FW_DONTCARE);
-  
-  if (stricmp (lpw, "bold") == 0)
-    return (FW_BOLD);
-  else if (stricmp (lpw, "demibold") == 0)
-    return (FW_SEMIBOLD);
-  else if (stricmp (lpw, "medium") == 0)
-    return (FW_MEDIUM);
-  else if (stricmp (lpw, "normal") == 0)
-    return (FW_NORMAL);
+
+  if (stricmp (lpw,"heavy") == 0)             return FW_HEAVY;
+  else if (stricmp (lpw,"extrabold") == 0)    return FW_EXTRABOLD;
+  else if (stricmp (lpw,"bold") == 0)         return FW_BOLD;
+  else if (stricmp (lpw,"demibold") == 0)     return FW_SEMIBOLD;
+  else if (stricmp (lpw,"medium") == 0)       return FW_MEDIUM;
+  else if (stricmp (lpw,"normal") == 0)       return FW_NORMAL;
+  else if (stricmp (lpw,"light") == 0)        return FW_LIGHT;
+  else if (stricmp (lpw,"extralight") == 0)   return FW_EXTRALIGHT;
+  else if (stricmp (lpw,"thin") == 0)         return FW_THIN;
   else
-    return (FW_DONTCARE);
+    return FW_DONTCARE;
 }
 
+
 char * 
 win32_to_x_weight (fnweight)
      int fnweight;
 {
-  if (fnweight >= FW_BOLD) 
-    return ("bold");
-  else if (fnweight >= FW_SEMIBOLD) 
-    return ("demibold");
-  else if (fnweight >= FW_MEDIUM) 
-    return ("medium");
-  else  
-    return ("normal");
+  if (fnweight >= FW_HEAVY)      return "heavy";
+  if (fnweight >= FW_EXTRABOLD)  return "extrabold";
+  if (fnweight >= FW_BOLD)       return "bold";
+  if (fnweight >= FW_SEMIBOLD)   return "semibold";
+  if (fnweight >= FW_MEDIUM)     return "medium";
+  if (fnweight >= FW_NORMAL)     return "normal";
+  if (fnweight >= FW_LIGHT)      return "light";
+  if (fnweight >= FW_EXTRALIGHT) return "extralight";
+  if (fnweight >= FW_THIN)       return "thin";
+  else
+    return "*";
+}
+
+LONG
+x_to_win32_charset (lpcs)
+    char * lpcs;
+{
+  if (!lpcs) return (0);
+
+  if (stricmp (lpcs,"ansi") == 0)               return ANSI_CHARSET;
+  else if (stricmp (lpcs,"iso8859-1") == 0)     return ANSI_CHARSET;
+  else if (stricmp (lpcs,"iso8859") == 0)       return ANSI_CHARSET;
+  else if (stricmp (lpcs,"oem") == 0)	        return OEM_CHARSET;
+#ifdef UNICODE_CHARSET
+  else if (stricmp (lpcs,"unicode") == 0)       return UNICODE_CHARSET;
+  else if (stricmp (lpcs,"iso10646") == 0)      return UNICODE_CHARSET;
+#endif
+  else
+    return 0;
+}
+
+char *
+win32_to_x_charset (fncharset)
+    int fncharset;
+{
+  switch (fncharset)
+    {
+    case ANSI_CHARSET:     return "ansi";
+    case OEM_CHARSET:      return "oem";
+    case SYMBOL_CHARSET:   return "symbol";
+#ifdef UNICODE_CHARSET
+    case UNICODE_CHARSET:  return "unicode";
+#endif
+    }
+  return "*";
 }
 
 BOOL 
@@ -3463,29 +3848,25 @@
 {
   if (!lpxstr) return (FALSE);
 
-  if (lplogfont) 
+  if (lplogfont)
     {
-      int height = (lplogfont->lfHeight * 1440) 
-	/ one_win32_display_info.height_in;
-      int width = (lplogfont->lfWidth * 1440) 
-	/ one_win32_display_info.width_in;
-
-      height = abs (height);
       _snprintf (lpxstr, len - 1,
-		 "-*-%s-%s-%c-%s-%s-*-%d-*-*-%c-%d-*-*-",
+		 "-*-%s-%s-%c-*-*-%d-%d-*-*-%c-%d-*-%s-",
 		 lplogfont->lfFaceName,
 		 win32_to_x_weight (lplogfont->lfWeight),
-		 lplogfont->lfItalic ? 'i' : 'r',
-		 "*", "*", 
-		 height,
+		 lplogfont->lfItalic?'i':'r',
+		 abs (lplogfont->lfHeight),
+		 (abs (lplogfont->lfHeight) * 720) / one_win32_display_info.height_in,
 		 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH) ? 'p' : 'c',
-		 width);
-    } 
-  else 
+		 lplogfont->lfWidth * 10,
+		 win32_to_x_charset (lplogfont->lfCharSet)
+		 );
+    }
+  else
     {
-      strncpy (lpxstr, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-", len - 1);
+      strncpy (lpxstr,"-*-*-*-*-*-*-*-*-*-*-*-*-*-*-", len - 1);
     }
-
+  
   lpxstr[len - 1] = 0;		/* just to be sure */
   return (TRUE);
 }
@@ -3498,59 +3879,132 @@
   if (!lplogfont) return (FALSE);
   
   memset (lplogfont, 0, sizeof (*lplogfont));
-  
-  lplogfont->lfCharSet = OEM_CHARSET;
+
+#if 0
   lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
   lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
   lplogfont->lfQuality = DEFAULT_QUALITY;
-  
-  if (lpxstr && *lpxstr == '-') lpxstr++;
+#else
+  /* go for maximum quality */
+  lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
+  lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
+  lplogfont->lfQuality = PROOF_QUALITY;
+#endif
+
+  if (!lpxstr)
+    return FALSE;
+
+  /* Provide a simple escape mechanism for specifying Windows font names
+   * directly -- if font spec does not beginning with '-', assume this
+   * format:
+   *   "<font name>[:height in pixels[:width in pixels[:weight]]]"
+   */
   
-  {
-    int fields;
-    char name[50], weight[20], slant, pitch, height[10], width[10];
-    
-    fields = (lpxstr
-	      ? sscanf (lpxstr, 
-			"%*[^-]-%[^-]-%[^-]-%c-%*[^-]-%*[^-]-%*[^-]-%[^-]-%*[^-]-%*[^-]-%c-%[^-]",
-			name, weight, &slant, height, &pitch, width)
-	      : 0);
-    
-    if (fields == EOF) return (FALSE);
-    
-    if (fields > 0 && name[0] != '*') 
+  if (*lpxstr == '-')
+    {
+      int fields;
+      char name[50], weight[20], slant, pitch, pixels[10], height[10], width[10], remainder[20];
+      char * encoding;
+
+      fields = sscanf (lpxstr,
+		       "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%*[^-]-%c-%9[^-]-%19s",
+		       name, weight, &slant, pixels, height, &pitch, width, remainder);
+
+      if (fields == EOF) return (FALSE);
+
+      if (fields > 0 && name[0] != '*')
+        {
+	  strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
+	  lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
+	}
+      else
+        {
+	  lplogfont->lfFaceName[0] = 0;
+	}
+
+      fields--;
+
+      lplogfont->lfWeight = x_to_win32_weight ((fields > 0 ? weight : ""));
+
+      fields--;
+
+      if (!NILP (Vwin32_enable_italics))
+	lplogfont->lfItalic = (fields > 0 && slant == 'i');
+
+      fields--;
+
+      if (fields > 0 && pixels[0] != '*')
+	lplogfont->lfHeight = atoi (pixels);
+
+      fields--;
+
+      if (fields > 0 && lplogfont->lfHeight == 0 && height[0] != '*')
+	lplogfont->lfHeight = (atoi (height)
+			       * one_win32_display_info.height_in) / 720;
+
+      fields--;
+
+      lplogfont->lfPitchAndFamily =
+	(fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
+
+      fields--;
+
+      if (fields > 0 && width[0] != '*')
+	lplogfont->lfWidth = atoi (width) / 10;
+
+      fields--;
+
+      /* Not all font specs include the registry field, so we allow for an
+	 optional registry field before the encoding when parsing
+	 remainder.  Also we strip the trailing '-' if present. */
       {
-	strncpy (lplogfont->lfFaceName, name, LF_FACESIZE);
-      } 
-    else 
-      {
-	lplogfont->lfFaceName[0] = 0;
+	int len = strlen (remainder);
+	if (len > 0 && remainder[len-1] == '-')
+	  remainder[len-1] = 0;
       }
-    
-    fields--;
-    
-    lplogfont->lfWeight = x_to_win32_weight((fields > 0 ? weight : ""));
-    
-    fields--;
-    
-    lplogfont->lfItalic = (fields > 0 && slant == 'i');
-    
-    fields--;
-    
-    if (fields > 0 && height[0] != '*')
-      lplogfont->lfHeight = (atoi (height) * one_win32_display_info.height_in) / 1440;
-    
-    fields--;
-    
-    lplogfont->lfPitchAndFamily = (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
-    
-    fields--;
-    
-    if (fields > 0 && width[0] != '*')
-      lplogfont->lfWidth = (atoi (width) * one_win32_display_info.width_in) / 1440;
-
-    lplogfont->lfCharSet = ANSI_CHARSET;
-  }
+      encoding = remainder;
+      if (strncmp (encoding, "*-", 2) == 0)
+	encoding += 2;
+      lplogfont->lfCharSet = x_to_win32_charset (fields > 0 ? encoding : "");
+    }
+  else
+    {
+      int fields;
+      char name[100], height[10], width[10], weight[20];
+
+      fields = sscanf (lpxstr,
+		       "%99[^:]:%9[^:]:%9[^:]:%19s",
+		       name, height, width, weight);
+
+      if (fields == EOF) return (FALSE);
+
+      if (fields > 0)
+        {
+	  strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
+	  lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
+	}
+      else
+        {
+	  lplogfont->lfFaceName[0] = 0;
+	}
+
+      fields--;
+
+      if (fields > 0)
+	lplogfont->lfHeight = atoi (height);
+
+      fields--;
+
+      if (fields > 0)
+	lplogfont->lfWidth = atoi (width);
+
+      fields--;
+
+      lplogfont->lfWeight = x_to_win32_weight ((fields > 0 ? weight : ""));
+    }
+
+  /* This makes TrueType fonts work better. */
+  lplogfont->lfHeight = - abs (lplogfont->lfHeight);
   
   return (TRUE);
 }
@@ -3744,7 +4198,7 @@
   ef.numFonts = 0;
 
   {
-    ef.hdc = my_get_dc (FRAME_WIN32_WINDOW (f));
+    ef.hdc = GetDC (FRAME_WIN32_WINDOW (f));
 
     EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1, (LPARAM)&ef);
     
@@ -3930,9 +4384,11 @@
   HDC hdc;
   int cap;
 
-  hdc = my_get_dc (dpyinfo->root_window);
-  
-  cap = GetDeviceCaps (hdc,NUMCOLORS);
+  hdc = GetDC (dpyinfo->root_window);
+  if (dpyinfo->has_palette)
+    cap = GetDeviceCaps (hdc,SIZEPALETTE);
+  else
+    cap = GetDeviceCaps (hdc,NUMCOLORS);
   
   ReleaseDC (dpyinfo->root_window, hdc);
   
@@ -4011,7 +4467,7 @@
   HDC hdc;
   int cap;
 
-  hdc = my_get_dc (dpyinfo->root_window);
+  hdc = GetDC (dpyinfo->root_window);
   
   cap = GetDeviceCaps (hdc, VERTSIZE);
   
@@ -4033,7 +4489,7 @@
   HDC hdc;
   int cap;
 
-  hdc = my_get_dc (dpyinfo->root_window);
+  hdc = GetDC (dpyinfo->root_window);
   
   cap = GetDeviceCaps (hdc, HORZSIZE);
   
@@ -4190,7 +4646,27 @@
   if (! NILP (xrm_string))
     CHECK_STRING (xrm_string, 1);
 
-  Vwin32_color_map = Fwin32_default_color_map ();
+  /* Allow color mapping to be defined externally; first look in user's
+     HOME directory, then in Emacs etc dir for a file called rgb.txt. */
+  {
+    Lisp_Object color_file;
+    struct gcpro gcpro1;
+
+    color_file = build_string("~/rgb.txt");
+
+    GCPRO1 (color_file);
+
+    if (NILP (Ffile_readable_p (color_file)))
+      color_file =
+	Fexpand_file_name (build_string ("rgb.txt"),
+			   Fsymbol_value (intern ("data-directory")));
+
+    Vwin32_color_map = Fwin32_load_color_file (color_file);
+
+    UNGCPRO;
+  }
+  if (NILP (Vwin32_color_map))
+    Vwin32_color_map = Fwin32_default_color_map ();
 
   if (! NILP (xrm_string))
     xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
@@ -4198,6 +4674,15 @@
     xrm_option = (unsigned char *) 0;
 
   /* Use this general default value to start with.  */
+  /* First remove .exe suffix from invocation-name - it looks ugly. */
+  {
+    char basename[ MAX_PATH ], *str;
+
+    strcpy (basename, XSTRING (Vinvocation_name)->data);
+    str = strrchr (basename, '.');
+    if (str) *str = 0;
+    Vinvocation_name = build_string (basename);
+  }
   Vx_resource_name = Vinvocation_name;
 
   validate_x_resource_name ();
@@ -4402,6 +4887,23 @@
 and application keys) are passed on to Windows.");
   Vwin32_pass_optional_keys_to_system = Qnil;
 
+  DEFVAR_LISP ("win32-enable-italics", &Vwin32_enable_italics,
+	       "Non-nil enables selection of artificially italicized fonts.");
+  Vwin32_enable_italics = Qnil;
+
+  DEFVAR_LISP ("win32-enable-palette", &Vwin32_enable_palette,
+	       "Non-nil enables Windows palette management to map colors exactly.");
+  Vwin32_enable_palette = Qt;
+
+  DEFVAR_INT ("win32-mouse-button-tolerance",
+	      &Vwin32_mouse_button_tolerance,
+	      "Analogue of double click interval for faking middle mouse events.\n\
+The value is the minimum time in milliseconds that must elapse between\n\
+left/right button down events before they are considered distinct events.\n\
+If both mouse buttons are depressed within this interval, a middle mouse\n\
+button down event is generated instead.");
+  XSETINT (Vwin32_mouse_button_tolerance, GetDoubleClickTime () / 2);
+
   init_x_parm_symbols ();
 
   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
@@ -4477,6 +4979,9 @@
   /* Win32 specific functions */
 
   defsubr (&Swin32_select_font);
+  defsubr (&Swin32_define_rgb_color);
+  defsubr (&Swin32_default_color_map);
+  defsubr (&Swin32_load_color_file);
 }
 
 #undef abort
@@ -4484,9 +4989,23 @@
 void 
 win32_abort()
 {
-    MessageBox (NULL,
-		"A fatal error has occurred - aborting!",
-		"Emacs Abort Dialog",
-		MB_OK|MB_ICONEXCLAMATION);
-    abort();
+  int button;
+  button = MessageBox (NULL,
+		       "A fatal error has occurred!\n\n"
+		       "Select Abort to exit, Retry to debug, Ignore to continue",
+		       "Emacs Abort Dialog",
+		       MB_ICONEXCLAMATION | MB_TASKMODAL
+		       | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
+  switch (button)
+    {
+    case IDRETRY:
+      DebugBreak ();
+      break;
+    case IDIGNORE:
+      break;
+    case IDABORT:
+    default:
+      abort ();
+      break;
+    }
 }