; Fix a typo in comment
[emacs.git] / src / w32xfns.c
blobf3aa9789ac639afde4d478aaa967062a56cf7721
1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2017 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 <http://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 #ifdef WINDOWSNT
52 keyboard_handle = input_available;
53 #endif /* WINDOWSNT */
55 /* interrupt_handle is signaled when quit (C-g) is detected, so that
56 blocking system calls can be interrupted. We make it a manual
57 reset event, so that if we should ever have multiple threads
58 performing system calls, they will all be interrupted (I'm guessing
59 that would the right response). Note that we use PulseEvent to
60 signal this event, so that it never remains signaled. */
61 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
64 void
65 delete_crit (void)
67 DeleteCriticalSection (&critsect);
69 if (input_available)
71 CloseHandle (input_available);
72 input_available = NULL;
74 if (interrupt_handle)
76 CloseHandle (interrupt_handle);
77 interrupt_handle = NULL;
81 void
82 signal_quit (void)
84 /* Make sure this event never remains signaled; if the main thread
85 isn't in a blocking call, then this should do nothing. */
86 PulseEvent (interrupt_handle);
89 void
90 select_palette (struct frame *f, HDC hdc)
92 struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
94 if (!display_info->has_palette)
95 return;
97 if (display_info->palette == 0)
98 return;
100 if (!NILP (Vw32_enable_palette))
101 f->output_data.w32->old_palette =
102 SelectPalette (hdc, display_info->palette, FALSE);
103 else
104 f->output_data.w32->old_palette = NULL;
106 if (RealizePalette (hdc) != GDI_ERROR)
108 Lisp_Object frame, framelist;
109 FOR_EACH_FRAME (framelist, frame)
111 SET_FRAME_GARBAGED (XFRAME (frame));
116 void
117 deselect_palette (struct frame *f, HDC hdc)
119 if (f->output_data.w32->old_palette)
120 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
123 /* Get a DC for frame and select palette for drawing; force an update of
124 all frames if palette's mapping changes. */
126 get_frame_dc (struct frame *f)
128 HDC hdc;
130 if (f->output_method != output_w32)
131 emacs_abort ();
133 enter_crit ();
135 hdc = GetDC (f->output_data.w32->window_desc);
137 /* If this gets called during startup before the frame is valid,
138 there is a chance of corrupting random data or crashing. */
139 if (hdc)
140 select_palette (f, hdc);
142 return hdc;
146 release_frame_dc (struct frame *f, HDC hdc)
148 int ret;
150 deselect_palette (f, hdc);
151 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
153 leave_crit ();
155 return ret;
158 typedef struct int_msg
160 W32Msg w32msg;
161 struct int_msg *lpNext;
162 } int_msg;
164 int_msg *lpHead = NULL;
165 int_msg *lpTail = NULL;
166 int nQueue = 0;
168 BOOL
169 get_next_msg (W32Msg * lpmsg, BOOL bWait)
171 BOOL bRet = FALSE;
173 enter_crit ();
175 /* The while loop takes care of multiple sets */
177 while (!nQueue && bWait)
179 leave_crit ();
180 WaitForSingleObject (input_available, INFINITE);
181 enter_crit ();
184 if (nQueue)
186 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
189 int_msg * lpCur = lpHead;
191 lpHead = lpHead->lpNext;
193 myfree (lpCur);
196 nQueue--;
197 /* Consolidate WM_PAINT messages to optimize redrawing. */
198 if (lpmsg->msg.message == WM_PAINT && nQueue)
200 int_msg * lpCur = lpHead;
201 int_msg * lpPrev = NULL;
202 int_msg * lpNext = NULL;
204 while (lpCur && nQueue)
206 lpNext = lpCur->lpNext;
207 if (lpCur->w32msg.msg.message == WM_PAINT)
209 /* Remove this message from the queue. */
210 if (lpPrev)
211 lpPrev->lpNext = lpNext;
212 else
213 lpHead = lpNext;
215 if (lpCur == lpTail)
216 lpTail = lpPrev;
218 /* Adjust clip rectangle to cover both. */
219 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
220 &(lpCur->w32msg.rect)))
222 SetRectEmpty (&(lpmsg->rect));
225 myfree (lpCur);
227 nQueue--;
229 lpCur = lpNext;
231 else
233 lpPrev = lpCur;
234 lpCur = lpNext;
239 bRet = TRUE;
242 if (nQueue == 0)
243 ResetEvent (input_available);
245 leave_crit ();
247 return (bRet);
250 extern char * w32_strerror (int error_no);
252 /* Tell the main thread that we have input available; if the main
253 thread is blocked in select(), we wake it up here. */
254 static void
255 notify_msg_ready (void)
257 SetEvent (input_available);
259 #ifdef CYGWIN
260 /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
261 among other files. */
262 (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0);
263 #endif /* CYGWIN */
266 BOOL
267 post_msg (W32Msg * lpmsg)
269 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
271 if (!lpNew)
272 return (FALSE);
274 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
275 lpNew->lpNext = NULL;
277 enter_crit ();
279 if (nQueue++)
281 lpTail->lpNext = lpNew;
283 else
285 lpHead = lpNew;
288 lpTail = lpNew;
289 notify_msg_ready ();
290 leave_crit ();
292 return (TRUE);
295 BOOL
296 prepend_msg (W32Msg *lpmsg)
298 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
300 if (!lpNew)
301 return (FALSE);
303 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
305 enter_crit ();
307 nQueue++;
308 lpNew->lpNext = lpHead;
309 lpHead = lpNew;
310 notify_msg_ready ();
311 leave_crit ();
313 return (TRUE);
316 /* Process all messages in the current thread's queue. Value is 1 if
317 one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */
319 drain_message_queue (void)
321 MSG msg;
322 int retval = 0;
324 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
326 if (msg.message == WM_EMACS_FILENOTIFY)
327 retval = 1;
328 TranslateMessage (&msg);
329 DispatchMessage (&msg);
331 return retval;