(syms_of_ntproc) <w32-get-true-file-attributes>: Doc fix.
[bpt/emacs.git] / src / w32xfns.c
index 0fda8c8..7f50ab5 100644 (file)
@@ -1,11 +1,12 @@
-/* Functions taken directly from X sources
-   Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation.
+/* Functions taken directly from X sources for use with the Microsoft W32 API.
+   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1999, 2001, 2002, 2003,
+                 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,12 +16,17 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
-#include <signal.h>
 #include <config.h>
+#include <signal.h>
 #include <stdio.h>
 #include "lisp.h"
+#include "keyboard.h"
+#include "frame.h"
+#include "charset.h"
+#include "fontset.h"
 #include "blockinput.h"
 #include "w32term.h"
 #include "windowsx.h"
@@ -30,41 +36,124 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 CRITICAL_SECTION critsect;
 extern HANDLE keyboard_handle;
-HANDLE hEvent = NULL;
+HANDLE input_available = NULL;
+HANDLE interrupt_handle = NULL;
 
-void 
+void
 init_crit ()
 {
   InitializeCriticalSection (&critsect);
-  keyboard_handle = hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+  /* For safety, input_available should only be reset by get_next_msg
+     when the input queue is empty, so make it a manual reset event. */
+  keyboard_handle = input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
+
+  /* interrupt_handle is signalled when quit (C-g) is detected, so that
+     blocking system calls can be interrupted.  We make it a manual
+     reset event, so that if we should ever have multiple threads
+     performing system calls, they will all be interrupted (I'm guessing
+     that would the right response).  Note that we use PulseEvent to
+     signal this event, so that it never remains signalled.  */
+  interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
 }
 
-void 
-enter_crit ()
+void
+delete_crit ()
 {
-  EnterCriticalSection (&critsect);
+  DeleteCriticalSection (&critsect);
+
+  if (input_available)
+    {
+      CloseHandle (input_available);
+      input_available = NULL;
+    }
+  if (interrupt_handle)
+    {
+      CloseHandle (interrupt_handle);
+      interrupt_handle = NULL;
+    }
 }
 
-void 
-leave_crit ()
+void
+signal_quit ()
 {
-  LeaveCriticalSection (&critsect);
+  /* Make sure this event never remains signalled; if the main thread
+     isn't in a blocking call, then this should do nothing.  */
+  PulseEvent (interrupt_handle);
 }
 
-void 
-delete_crit ()
+void
+select_palette (FRAME_PTR f, HDC hdc)
 {
-  DeleteCriticalSection (&critsect);
-  if (hEvent)
+  struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
+
+  if (!display_info->has_palette)
+    return;
+
+  if (display_info->palette == 0)
+    return;
+
+  if (!NILP (Vw32_enable_palette))
+    f->output_data.w32->old_palette =
+      SelectPalette (hdc, display_info->palette, FALSE);
+  else
+    f->output_data.w32->old_palette = NULL;
+
+  if (RealizePalette (hdc))
+  {
+    Lisp_Object frame, framelist;
+    FOR_EACH_FRAME (framelist, frame)
     {
-      CloseHandle (hEvent);
-      hEvent = NULL;
+      SET_FRAME_GARBAGED (XFRAME (frame));
     }
+  }
+}
+
+void
+deselect_palette (FRAME_PTR f, HDC hdc)
+{
+  if (f->output_data.w32->old_palette)
+    SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
+}
+
+/* Get a DC for frame and select palette for drawing; force an update of
+   all frames if palette's mapping changes.  */
+HDC
+get_frame_dc (FRAME_PTR f)
+{
+  HDC hdc;
+
+  if (f->output_method != output_w32)
+    abort ();
+
+  enter_crit ();
+
+  hdc = GetDC (f->output_data.w32->window_desc);
+
+  /* If this gets called during startup before the frame is valid,
+     there is a chance of corrupting random data or crashing. */
+  if (hdc)
+    select_palette (f, hdc);
+
+  return hdc;
+}
+
+int
+release_frame_dc (FRAME_PTR f, HDC hdc)
+{
+  int ret;
+
+  deselect_palette (f, hdc);
+  ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
+
+  leave_crit ();
+
+  return ret;
 }
 
 typedef struct int_msg
 {
-  Win32Msg w32msg;
+  W32Msg w32msg;
   struct int_msg *lpNext;
 } int_msg;
 
@@ -72,55 +161,100 @@ int_msg *lpHead = NULL;
 int_msg *lpTail = NULL;
 int nQueue = 0;
 
-BOOL 
+BOOL
 get_next_msg (lpmsg, bWait)
-     Win32Msg * lpmsg;
+     W32Msg * lpmsg;
      BOOL bWait;
 {
   BOOL bRet = FALSE;
-  
+
   enter_crit ();
-  
+
   /* The while loop takes care of multiple sets */
-  
+
   while (!nQueue && bWait)
     {
       leave_crit ();
-      WaitForSingleObject (hEvent, INFINITE);
+      WaitForSingleObject (input_available, INFINITE);
       enter_crit ();
     }
-  
+
   if (nQueue)
     {
-      bcopy (&(lpHead->w32msg), lpmsg, sizeof (Win32Msg));
+      bcopy (&(lpHead->w32msg), lpmsg, sizeof (W32Msg));
 
       {
        int_msg * lpCur = lpHead;
-           
+
        lpHead = lpHead->lpNext;
-           
+
        myfree (lpCur);
       }
 
       nQueue--;
+      /* Consolidate WM_PAINT messages to optimise redrawing.  */
+      if (lpmsg->msg.message == WM_PAINT && nQueue)
+        {
+          int_msg * lpCur = lpHead;
+          int_msg * lpPrev = NULL;
+          int_msg * lpNext = NULL;
+
+          while (lpCur && nQueue)
+            {
+              lpNext = lpCur->lpNext;
+              if (lpCur->w32msg.msg.message == WM_PAINT)
+                {
+                  /* Remove this message from the queue.  */
+                  if (lpPrev)
+                    lpPrev->lpNext = lpNext;
+                  else
+                    lpHead = lpNext;
+
+                  if (lpCur == lpTail)
+                    lpTail = lpPrev;
+
+                  /* Adjust clip rectangle to cover both.  */
+                  if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
+                                  &(lpCur->w32msg.rect)))
+                    {
+                      SetRectEmpty(&(lpmsg->rect));
+                    }
+
+                  myfree (lpCur);
+
+                  nQueue--;
+
+                  lpCur = lpNext;
+                }
+              else
+                {
+                  lpPrev = lpCur;
+                  lpCur = lpNext;
+                }
+            }
+        }
 
       bRet = TRUE;
     }
-  
+
+  if (nQueue == 0)
+    ResetEvent (input_available);
+
   leave_crit ();
-  
+
   return (bRet);
 }
 
-BOOL 
+BOOL
 post_msg (lpmsg)
-     Win32Msg * lpmsg;
+     W32Msg * lpmsg;
 {
   int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
 
-  if (!lpNew) return (FALSE);
+  if (!lpNew)
+    return (FALSE);
 
-  bcopy (lpmsg, &(lpNew->w32msg), sizeof (Win32Msg));
+  bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
   lpNew->lpNext = NULL;
 
   enter_crit ();
@@ -129,19 +263,53 @@ post_msg (lpmsg)
     {
       lpTail->lpNext = lpNew;
     }
-  else 
+  else
     {
       lpHead = lpNew;
-      SetEvent (hEvent);
     }
 
   lpTail = lpNew;
-    
+  SetEvent (input_available);
+
+  leave_crit ();
+
+  return (TRUE);
+}
+
+BOOL
+prepend_msg (W32Msg *lpmsg)
+{
+  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
+
+  if (!lpNew)
+    return (FALSE);
+
+  bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
+
+  enter_crit ();
+
+  nQueue++;
+  lpNew->lpNext = lpHead;
+  lpHead = lpNew;
+
   leave_crit ();
 
   return (TRUE);
 }
 
+/* Process all messages in the current thread's queue.  */
+void
+drain_message_queue ()
+{
+  MSG msg;
+  while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+    {
+      TranslateMessage (&msg);
+      DispatchMessage (&msg);
+    }
+}
+
+
 /*
  *    XParseGeometry parses strings of the form
  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
@@ -151,7 +319,7 @@ post_msg (lpmsg)
  *   It returns a bitmask that indicates which of the four values
  *   were actually found in the string.  For each value found,
  *   the corresponding argument is updated;  for each value
- *   not found, the corresponding argument is left unchanged. 
+ *   not found, the corresponding argument is left unchanged.
  */
 
 static int
@@ -161,7 +329,7 @@ read_integer (string, NextString)
 {
   register int Result = 0;
   int Sign = 1;
-  
+
   if (*string == '+')
     string++;
   else if (*string == '-')
@@ -180,7 +348,7 @@ read_integer (string, NextString)
     return (-Result);
 }
 
-int 
+int
 XParseGeometry (string, x, y, width, height)
      char *string;
      int *x, *y;
@@ -191,23 +359,23 @@ XParseGeometry (string, x, y, width, height)
   unsigned int tempWidth, tempHeight;
   int tempX, tempY;
   char *nextCharacter;
-  
+
   if ((string == NULL) || (*string == '\0')) return (mask);
   if (*string == '=')
     string++;  /* ignore possible '=' at beg of geometry spec */
-  
+
   strind = (char *)string;
-  if (*strind != '+' && *strind != '-' && *strind != 'x') 
+  if (*strind != '+' && *strind != '-' && *strind != 'x')
     {
       tempWidth = read_integer (strind, &nextCharacter);
-      if (strind == nextCharacter) 
+      if (strind == nextCharacter)
        return (0);
       strind = nextCharacter;
       mask |= WidthValue;
     }
-  
-  if (*strind == 'x' || *strind == 'X') 
-    {  
+
+  if (*strind == 'x' || *strind == 'X')
+    {
       strind++;
       tempHeight = read_integer (strind, &nextCharacter);
       if (strind == nextCharacter)
@@ -215,10 +383,10 @@ XParseGeometry (string, x, y, width, height)
       strind = nextCharacter;
       mask |= HeightValue;
     }
-  
-  if ((*strind == '+') || (*strind == '-')) 
+
+  if ((*strind == '+') || (*strind == '-'))
     {
-      if (*strind == '-') 
+      if (*strind == '-')
        {
          strind++;
          tempX = -read_integer (strind, &nextCharacter);
@@ -229,7 +397,7 @@ XParseGeometry (string, x, y, width, height)
 
        }
       else
-       {       
+       {
          strind++;
          tempX = read_integer (strind, &nextCharacter);
          if (strind == nextCharacter)
@@ -237,9 +405,9 @@ XParseGeometry (string, x, y, width, height)
          strind = nextCharacter;
        }
       mask |= XValue;
-      if ((*strind == '+') || (*strind == '-')) 
+      if ((*strind == '+') || (*strind == '-'))
        {
-         if (*strind == '-') 
+         if (*strind == '-')
            {
              strind++;
              tempY = -read_integer (strind, &nextCharacter);
@@ -260,12 +428,12 @@ XParseGeometry (string, x, y, width, height)
          mask |= YValue;
        }
     }
-  
+
   /* If strind isn't at the end of the string the it's an invalid
      geometry specification. */
-  
+
   if (*strind != '\0') return (0);
-  
+
   if (mask & XValue)
     *x = tempX;
   if (mask & YValue)
@@ -277,17 +445,12 @@ XParseGeometry (string, x, y, width, height)
   return (mask);
 }
 
-/* The semantics of the use of using_x_p is really using_a_window_system.  */
-int
-using_x_p (void)
-{
-  return 1;
-}
-
-/* x_sync is a no-op on Win32.  */
+/* x_sync is a no-op on W32.  */
 void
 x_sync (f)
      void *f;
 {
 }
 
+/* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
+   (do not change this comment) */