]> code.delx.au - gnu-emacs/blob - src/w32xfns.c
Remove now-inaccurate bytecode comments
[gnu-emacs] / src / w32xfns.c
1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2016 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 <http://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;
161
162 if (f->output_method != output_w32)
163 emacs_abort ();
164
165 enter_crit ();
166
167 hdc = GetDC (f->output_data.w32->window_desc);
168
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);
173
174 return hdc;
175 }
176
177 int
178 release_frame_dc (struct frame *f, HDC hdc)
179 {
180 int ret;
181
182 deselect_palette (f, hdc);
183 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
184
185 leave_crit ();
186
187 return ret;
188 }
189
190 typedef struct int_msg
191 {
192 W32Msg w32msg;
193 struct int_msg *lpNext;
194 } int_msg;
195
196 int_msg *lpHead = NULL;
197 int_msg *lpTail = NULL;
198 int nQueue = 0;
199
200 BOOL
201 get_next_msg (W32Msg * lpmsg, BOOL bWait)
202 {
203 BOOL bRet = FALSE;
204
205 enter_crit ();
206
207 /* The while loop takes care of multiple sets */
208
209 while (!nQueue && bWait)
210 {
211 leave_crit ();
212 WaitForSingleObject (input_available, INFINITE);
213 enter_crit ();
214 }
215
216 if (nQueue)
217 {
218 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
219
220 {
221 int_msg * lpCur = lpHead;
222
223 lpHead = lpHead->lpNext;
224
225 myfree (lpCur);
226 }
227
228 nQueue--;
229 /* Consolidate WM_PAINT messages to optimize redrawing. */
230 if (lpmsg->msg.message == WM_PAINT && nQueue)
231 {
232 int_msg * lpCur = lpHead;
233 int_msg * lpPrev = NULL;
234 int_msg * lpNext = NULL;
235
236 while (lpCur && nQueue)
237 {
238 lpNext = lpCur->lpNext;
239 if (lpCur->w32msg.msg.message == WM_PAINT)
240 {
241 /* Remove this message from the queue. */
242 if (lpPrev)
243 lpPrev->lpNext = lpNext;
244 else
245 lpHead = lpNext;
246
247 if (lpCur == lpTail)
248 lpTail = lpPrev;
249
250 /* Adjust clip rectangle to cover both. */
251 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
252 &(lpCur->w32msg.rect)))
253 {
254 SetRectEmpty (&(lpmsg->rect));
255 }
256
257 myfree (lpCur);
258
259 nQueue--;
260
261 lpCur = lpNext;
262 }
263 else
264 {
265 lpPrev = lpCur;
266 lpCur = lpNext;
267 }
268 }
269 }
270
271 bRet = TRUE;
272 }
273
274 if (nQueue == 0)
275 ResetEvent (input_available);
276
277 leave_crit ();
278
279 return (bRet);
280 }
281
282 extern char * w32_strerror (int error_no);
283
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)
288 {
289 SetEvent (input_available);
290
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 */
296 }
297
298 BOOL
299 post_msg (W32Msg * lpmsg)
300 {
301 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
302
303 if (!lpNew)
304 return (FALSE);
305
306 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
307 lpNew->lpNext = NULL;
308
309 enter_crit ();
310
311 if (nQueue++)
312 {
313 lpTail->lpNext = lpNew;
314 }
315 else
316 {
317 lpHead = lpNew;
318 }
319
320 lpTail = lpNew;
321 notify_msg_ready ();
322 leave_crit ();
323
324 return (TRUE);
325 }
326
327 BOOL
328 prepend_msg (W32Msg *lpmsg)
329 {
330 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
331
332 if (!lpNew)
333 return (FALSE);
334
335 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
336
337 enter_crit ();
338
339 nQueue++;
340 lpNew->lpNext = lpHead;
341 lpHead = lpNew;
342 notify_msg_ready ();
343 leave_crit ();
344
345 return (TRUE);
346 }
347
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. */
350 int
351 drain_message_queue (void)
352 {
353 MSG msg;
354 int retval = 0;
355
356 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
357 {
358 if (msg.message == WM_EMACS_FILENOTIFY)
359 retval = 1;
360 TranslateMessage (&msg);
361 DispatchMessage (&msg);
362 }
363 return retval;
364 }