; Merge from origin/emacs-26
[emacs.git] / src / w32xfns.c
blobe9261b0d0902e8f0e96363b3191916b5a07d5b59
1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2018 Free Software
3 Foundation, Inc.
5 This file is part of GNU Emacs.
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.
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.
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/>. */
20 #include <config.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <windows.h>
24 #include <windowsx.h>
26 #include "lisp.h"
27 #include "frame.h"
28 #include "w32term.h"
30 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
31 #define myfree(lp) GlobalFreePtr (lp)
33 CRITICAL_SECTION critsect;
35 #ifdef WINDOWSNT
36 extern HANDLE keyboard_handle;
37 #endif /* WINDOWSNT */
39 HANDLE input_available = NULL;
40 HANDLE interrupt_handle = NULL;
42 void
43 init_crit (void)
45 InitializeCriticalSection (&critsect);
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);
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)
58 memset (notifications_set_head, 0, sizeof(struct notifications_set));
59 notifications_set_head->next
60 = notifications_set_head->prev = notifications_set_head;
62 else
63 DebPrint(("Out of memory: can't initialize notifications sets."));
64 #endif
66 #ifdef WINDOWSNT
67 keyboard_handle = input_available;
68 #endif /* WINDOWSNT */
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);
79 void
80 delete_crit (void)
82 DeleteCriticalSection (&critsect);
84 if (input_available)
86 CloseHandle (input_available);
87 input_available = NULL;
89 if (interrupt_handle)
91 CloseHandle (interrupt_handle);
92 interrupt_handle = NULL;
95 #if HAVE_W32NOTIFY
96 if (notifications_set_head)
98 /* Free any remaining notifications set that could be left over. */
99 while (notifications_set_head->next != notifications_set_head)
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);
109 free (notifications_set_head);
110 #endif
113 void
114 signal_quit (void)
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);
121 void
122 select_palette (struct frame *f, HDC hdc)
124 struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
126 if (!display_info->has_palette)
127 return;
129 if (display_info->palette == 0)
130 return;
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;
138 if (RealizePalette (hdc) != GDI_ERROR)
140 Lisp_Object frame, framelist;
141 FOR_EACH_FRAME (framelist, frame)
143 SET_FRAME_GARBAGED (XFRAME (frame));
148 void
149 deselect_palette (struct frame *f, HDC hdc)
151 if (f->output_data.w32->old_palette)
152 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
155 /* Get a DC for frame and select palette for drawing; force an update of
156 all frames if palette's mapping changes. */
158 get_frame_dc (struct frame *f)
160 HDC hdc;
162 if (f->output_method != output_w32)
163 emacs_abort ();
165 enter_crit ();
167 hdc = GetDC (f->output_data.w32->window_desc);
169 /* If this gets called during startup before the frame is valid,
170 there is a chance of corrupting random data or crashing. */
171 if (hdc)
172 select_palette (f, hdc);
174 return hdc;
178 release_frame_dc (struct frame *f, HDC hdc)
180 int ret;
182 deselect_palette (f, hdc);
183 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
185 leave_crit ();
187 return ret;
190 typedef struct int_msg
192 W32Msg w32msg;
193 struct int_msg *lpNext;
194 } int_msg;
196 int_msg *lpHead = NULL;
197 int_msg *lpTail = NULL;
198 int nQueue = 0;
200 BOOL
201 get_next_msg (W32Msg * lpmsg, BOOL bWait)
203 BOOL bRet = FALSE;
205 enter_crit ();
207 /* The while loop takes care of multiple sets */
209 while (!nQueue && bWait)
211 leave_crit ();
212 WaitForSingleObject (input_available, INFINITE);
213 enter_crit ();
216 if (nQueue)
218 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
221 int_msg * lpCur = lpHead;
223 lpHead = lpHead->lpNext;
225 myfree (lpCur);
228 nQueue--;
229 /* Consolidate WM_PAINT messages to optimize redrawing. */
230 if (lpmsg->msg.message == WM_PAINT && nQueue)
232 int_msg * lpCur = lpHead;
233 int_msg * lpPrev = NULL;
234 int_msg * lpNext = NULL;
236 while (lpCur && nQueue)
238 lpNext = lpCur->lpNext;
239 if (lpCur->w32msg.msg.message == WM_PAINT)
241 /* Remove this message from the queue. */
242 if (lpPrev)
243 lpPrev->lpNext = lpNext;
244 else
245 lpHead = lpNext;
247 if (lpCur == lpTail)
248 lpTail = lpPrev;
250 /* Adjust clip rectangle to cover both. */
251 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
252 &(lpCur->w32msg.rect)))
254 SetRectEmpty (&(lpmsg->rect));
257 myfree (lpCur);
259 nQueue--;
261 lpCur = lpNext;
263 else
265 lpPrev = lpCur;
266 lpCur = lpNext;
271 bRet = TRUE;
274 if (nQueue == 0)
275 ResetEvent (input_available);
277 leave_crit ();
279 return (bRet);
282 extern char * w32_strerror (int error_no);
284 /* Tell the main thread that we have input available; if the main
285 thread is blocked in select(), we wake it up here. */
286 static void
287 notify_msg_ready (void)
289 SetEvent (input_available);
291 #ifdef CYGWIN
292 /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
293 among other files. */
294 (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0);
295 #endif /* CYGWIN */
298 BOOL
299 post_msg (W32Msg * lpmsg)
301 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
303 if (!lpNew)
304 return (FALSE);
306 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
307 lpNew->lpNext = NULL;
309 enter_crit ();
311 if (nQueue++)
313 lpTail->lpNext = lpNew;
315 else
317 lpHead = lpNew;
320 lpTail = lpNew;
321 notify_msg_ready ();
322 leave_crit ();
324 return (TRUE);
327 BOOL
328 prepend_msg (W32Msg *lpmsg)
330 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
332 if (!lpNew)
333 return (FALSE);
335 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
337 enter_crit ();
339 nQueue++;
340 lpNew->lpNext = lpHead;
341 lpHead = lpNew;
342 notify_msg_ready ();
343 leave_crit ();
345 return (TRUE);
348 /* Process all messages in the current thread's queue. Value is 1 if
349 one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */
351 drain_message_queue (void)
353 MSG msg;
354 int retval = 0;
356 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
358 if (msg.message == WM_EMACS_FILENOTIFY)
359 retval = 1;
360 TranslateMessage (&msg);
361 DispatchMessage (&msg);
363 return retval;