root/src/w32xfns.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_crit
  2. delete_crit
  3. signal_quit
  4. select_palette
  5. deselect_palette
  6. get_frame_dc
  7. release_frame_dc
  8. get_next_msg
  9. notify_msg_ready
  10. post_msg
  11. prepend_msg
  12. drain_message_queue

     1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
     2    Copyright (C) 1989, 1992-1995, 1999, 2001-2023 Free Software
     3    Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 #include <config.h>
    21 #include <signal.h>
    22 #include <stdio.h>
    23 #include <windows.h>
    24 #include <windowsx.h>
    25 
    26 #include "lisp.h"
    27 #include "frame.h"
    28 #include "w32term.h"
    29 
    30 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
    31 #define myfree(lp) GlobalFreePtr (lp)
    32 
    33 CRITICAL_SECTION critsect;
    34 
    35 #ifdef WINDOWSNT
    36 extern HANDLE keyboard_handle;
    37 #endif /* WINDOWSNT */
    38 
    39 HANDLE input_available = NULL;
    40 HANDLE interrupt_handle = NULL;
    41 
    42 void
    43 init_crit (void)
    44 {
    45   InitializeCriticalSection (&critsect);
    46 
    47   /* For safety, input_available should only be reset by get_next_msg
    48      when the input queue is empty, so make it a manual reset event. */
    49   input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
    50 
    51 #if HAVE_W32NOTIFY
    52   /* Initialize the linked list of notifications sets that will be
    53      used to communicate between the watching worker threads and the
    54      main thread.  */
    55   notifications_set_head = malloc (sizeof(struct notifications_set));
    56   if (notifications_set_head)
    57     {
    58       memset (notifications_set_head, 0, sizeof(struct notifications_set));
    59       notifications_set_head->next
    60         = notifications_set_head->prev = notifications_set_head;
    61     }
    62   else
    63     DebPrint(("Out of memory: can't initialize notifications sets."));
    64 #endif
    65 
    66 #ifdef WINDOWSNT
    67   keyboard_handle = input_available;
    68 #endif /* WINDOWSNT */
    69 
    70   /* interrupt_handle is signaled when quit (C-g) is detected, so that
    71      blocking system calls can be interrupted.  We make it a manual
    72      reset event, so that if we should ever have multiple threads
    73      performing system calls, they will all be interrupted (I'm guessing
    74      that would the right response).  Note that we use PulseEvent to
    75      signal this event, so that it never remains signaled.  */
    76   interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
    77 }
    78 
    79 void
    80 delete_crit (void)
    81 {
    82   DeleteCriticalSection (&critsect);
    83 
    84   if (input_available)
    85     {
    86       CloseHandle (input_available);
    87       input_available = NULL;
    88     }
    89   if (interrupt_handle)
    90     {
    91       CloseHandle (interrupt_handle);
    92       interrupt_handle = NULL;
    93     }
    94 
    95 #if HAVE_W32NOTIFY
    96   if (notifications_set_head)
    97     {
    98       /* Free any remaining notifications set that could be left over.  */
    99       while (notifications_set_head->next != notifications_set_head)
   100         {
   101           struct notifications_set *ns = notifications_set_head->next;
   102           notifications_set_head->next = ns->next;
   103           ns->next->prev = notifications_set_head;
   104           if (ns->notifications)
   105             free (ns->notifications);
   106           free (ns);
   107         }
   108     }
   109   free (notifications_set_head);
   110 #endif
   111 }
   112 
   113 void
   114 signal_quit (void)
   115 {
   116   /* Make sure this event never remains signaled; if the main thread
   117      isn't in a blocking call, then this should do nothing.  */
   118   PulseEvent (interrupt_handle);
   119 }
   120 
   121 void
   122 select_palette (struct frame *f, HDC hdc)
   123 {
   124   struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
   125 
   126   if (!display_info->has_palette)
   127     return;
   128 
   129   if (display_info->palette == 0)
   130     return;
   131 
   132   if (!NILP (Vw32_enable_palette))
   133     f->output_data.w32->old_palette =
   134       SelectPalette (hdc, display_info->palette, FALSE);
   135   else
   136     f->output_data.w32->old_palette = NULL;
   137 
   138   if (RealizePalette (hdc) != GDI_ERROR)
   139     {
   140       Lisp_Object frame, framelist;
   141       FOR_EACH_FRAME (framelist, frame)
   142         {
   143           SET_FRAME_GARBAGED (XFRAME (frame));
   144         }
   145     }
   146 }
   147 
   148 void
   149 deselect_palette (struct frame *f, HDC hdc)
   150 {
   151   if (f->output_data.w32->old_palette)
   152     SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
   153 }
   154 
   155 /* Get a DC for frame and select palette for drawing; force an update of
   156    all frames if palette's mapping changes.  */
   157 HDC
   158 get_frame_dc (struct frame *f)
   159 {
   160   HDC hdc, paint_dc;
   161   HBITMAP back_buffer;
   162   HGDIOBJ obj;
   163   struct w32_output *output;
   164 
   165   if (f->output_method != output_w32)
   166     emacs_abort ();
   167 
   168   enter_crit ();
   169   output = FRAME_OUTPUT_DATA (f);
   170 
   171   if (output->paint_dc)
   172     {
   173       if (output->paint_buffer_width != FRAME_PIXEL_WIDTH (f)
   174           || output->paint_buffer_height != FRAME_PIXEL_HEIGHT (f)
   175           || w32_disable_double_buffering)
   176         w32_release_paint_buffer (f);
   177       else
   178         {
   179           output->paint_buffer_dirty = 1;
   180           return output->paint_dc;
   181         }
   182     }
   183 
   184   hdc = GetDC (output->window_desc);
   185 
   186   /* If this gets called during startup before the frame is valid,
   187      there is a chance of corrupting random data or crashing. */
   188   if (hdc)
   189     {
   190       select_palette (f, hdc);
   191 
   192       if (!w32_disable_double_buffering
   193           && FRAME_OUTPUT_DATA (f)->want_paint_buffer)
   194         {
   195           back_buffer
   196             = CreateCompatibleBitmap (hdc, FRAME_PIXEL_WIDTH (f),
   197                                       FRAME_PIXEL_HEIGHT (f));
   198 
   199           if (back_buffer)
   200             {
   201               paint_dc = CreateCompatibleDC (hdc);
   202 
   203               if (!paint_dc)
   204                 DeleteObject (back_buffer);
   205               else
   206                 {
   207                   obj = SelectObject (paint_dc, back_buffer);
   208 
   209                   output->paint_dc_object = obj;
   210                   output->paint_dc = paint_dc;
   211                   output->paint_buffer_handle = hdc;
   212                   output->paint_buffer = back_buffer;
   213                   output->paint_buffer_width = FRAME_PIXEL_WIDTH (f);
   214                   output->paint_buffer_height = FRAME_PIXEL_HEIGHT (f);
   215                   output->paint_buffer_dirty = 1;
   216 
   217                   SET_FRAME_GARBAGED (f);
   218 
   219                   return paint_dc;
   220                 }
   221             }
   222         }
   223     }
   224 
   225   return hdc;
   226 }
   227 
   228 int
   229 release_frame_dc (struct frame *f, HDC hdc)
   230 {
   231   int ret;
   232 
   233   /* Avoid releasing the double-buffered DC here, since it'll be
   234      released upon the next buffer flip instead.  */
   235   if (hdc != FRAME_OUTPUT_DATA (f)->paint_dc)
   236     {
   237       deselect_palette (f, hdc);
   238       ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
   239     }
   240   else
   241     ret = 0;
   242 
   243   leave_crit ();
   244 
   245   return ret;
   246 }
   247 
   248 typedef struct int_msg
   249 {
   250   W32Msg w32msg;
   251   struct int_msg *lpNext;
   252 } int_msg;
   253 
   254 int_msg *lpHead = NULL;
   255 int_msg *lpTail = NULL;
   256 int nQueue = 0;
   257 
   258 BOOL
   259 get_next_msg (W32Msg * lpmsg, BOOL bWait)
   260 {
   261   BOOL bRet = FALSE;
   262 
   263   enter_crit ();
   264 
   265   /* The while loop takes care of multiple sets */
   266 
   267   while (!nQueue && bWait)
   268     {
   269       leave_crit ();
   270       WaitForSingleObject (input_available, INFINITE);
   271       enter_crit ();
   272     }
   273 
   274   if (nQueue)
   275     {
   276       memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
   277 
   278       {
   279         int_msg * lpCur = lpHead;
   280 
   281         lpHead = lpHead->lpNext;
   282 
   283         myfree (lpCur);
   284       }
   285 
   286       nQueue--;
   287       /* Consolidate WM_PAINT messages to optimize redrawing.  */
   288       if (lpmsg->msg.message == WM_PAINT && nQueue)
   289         {
   290           int_msg * lpCur = lpHead;
   291           int_msg * lpPrev = NULL;
   292           int_msg * lpNext = NULL;
   293 
   294           while (lpCur && nQueue)
   295             {
   296               lpNext = lpCur->lpNext;
   297               if (lpCur->w32msg.msg.message == WM_PAINT)
   298                 {
   299                   /* Remove this message from the queue.  */
   300                   if (lpPrev)
   301                     lpPrev->lpNext = lpNext;
   302                   else
   303                     lpHead = lpNext;
   304 
   305                   if (lpCur == lpTail)
   306                     lpTail = lpPrev;
   307 
   308                   /* Adjust clip rectangle to cover both.  */
   309                   if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
   310                                   &(lpCur->w32msg.rect)))
   311                     {
   312                       SetRectEmpty (&(lpmsg->rect));
   313                     }
   314 
   315                   myfree (lpCur);
   316 
   317                   nQueue--;
   318 
   319                   lpCur = lpNext;
   320                 }
   321               else
   322                 {
   323                   lpPrev = lpCur;
   324                   lpCur = lpNext;
   325                 }
   326             }
   327         }
   328 
   329       bRet = TRUE;
   330     }
   331 
   332   if (nQueue == 0)
   333     ResetEvent (input_available);
   334 
   335   leave_crit ();
   336 
   337   return (bRet);
   338 }
   339 
   340 extern char * w32_strerror (int error_no);
   341 
   342 /* Tell the main thread that we have input available; if the main
   343    thread is blocked in select(), we wake it up here.  */
   344 static void
   345 notify_msg_ready (void)
   346 {
   347   SetEvent (input_available);
   348 
   349 #ifdef CYGWIN
   350   /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
   351      among other files.  */
   352   (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0);
   353 #endif /* CYGWIN */
   354 }
   355 
   356 BOOL
   357 post_msg (W32Msg * lpmsg)
   358 {
   359   int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
   360 
   361   if (!lpNew)
   362     return (FALSE);
   363 
   364   memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
   365   lpNew->lpNext = NULL;
   366 
   367   enter_crit ();
   368 
   369   if (nQueue++)
   370     {
   371       lpTail->lpNext = lpNew;
   372     }
   373   else
   374     {
   375       lpHead = lpNew;
   376     }
   377 
   378   lpTail = lpNew;
   379   notify_msg_ready ();
   380   leave_crit ();
   381 
   382   return (TRUE);
   383 }
   384 
   385 BOOL
   386 prepend_msg (W32Msg *lpmsg)
   387 {
   388   int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
   389 
   390   if (!lpNew)
   391     return (FALSE);
   392 
   393   memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
   394 
   395   enter_crit ();
   396 
   397   nQueue++;
   398   lpNew->lpNext = lpHead;
   399   lpHead = lpNew;
   400   notify_msg_ready ();
   401   leave_crit ();
   402 
   403   return (TRUE);
   404 }
   405 
   406 /* Process all messages in the current thread's queue.  Value is 1 if
   407    one of these messages was WM_EMACS_FILENOTIFY, zero otherwise.  */
   408 int
   409 drain_message_queue (void)
   410 {
   411   MSG msg;
   412   int retval = 0;
   413 
   414   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
   415     {
   416       if (msg.message == WM_EMACS_FILENOTIFY)
   417         retval = 1;
   418       TranslateMessage (&msg);
   419       DispatchMessage (&msg);
   420     }
   421   return retval;
   422 }

/* [<][>][^][v][top][bottom][index][help] */