]> code.delx.au - gnu-emacs/blob - src/w32xfns.c
29636d1de80820bc2cc8ce173a3d99975985e8da
[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
10 (at 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 #ifdef WINDOWSNT
52 keyboard_handle = input_available;
53 #endif /* WINDOWSNT */
54
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);
62 }
63
64 void
65 delete_crit (void)
66 {
67 DeleteCriticalSection (&critsect);
68
69 if (input_available)
70 {
71 CloseHandle (input_available);
72 input_available = NULL;
73 }
74 if (interrupt_handle)
75 {
76 CloseHandle (interrupt_handle);
77 interrupt_handle = NULL;
78 }
79 }
80
81 void
82 signal_quit (void)
83 {
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);
87 }
88
89 void
90 select_palette (struct frame *f, HDC hdc)
91 {
92 struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
93
94 if (!display_info->has_palette)
95 return;
96
97 if (display_info->palette == 0)
98 return;
99
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;
105
106 if (RealizePalette (hdc) != GDI_ERROR)
107 {
108 Lisp_Object frame, framelist;
109 FOR_EACH_FRAME (framelist, frame)
110 {
111 SET_FRAME_GARBAGED (XFRAME (frame));
112 }
113 }
114 }
115
116 void
117 deselect_palette (struct frame *f, HDC hdc)
118 {
119 if (f->output_data.w32->old_palette)
120 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
121 }
122
123 /* Get a DC for frame and select palette for drawing; force an update of
124 all frames if palette's mapping changes. */
125 HDC
126 get_frame_dc (struct frame *f)
127 {
128 HDC hdc;
129
130 if (f->output_method != output_w32)
131 emacs_abort ();
132
133 enter_crit ();
134
135 hdc = GetDC (f->output_data.w32->window_desc);
136
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);
141
142 return hdc;
143 }
144
145 int
146 release_frame_dc (struct frame *f, HDC hdc)
147 {
148 int ret;
149
150 deselect_palette (f, hdc);
151 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
152
153 leave_crit ();
154
155 return ret;
156 }
157
158 typedef struct int_msg
159 {
160 W32Msg w32msg;
161 struct int_msg *lpNext;
162 } int_msg;
163
164 int_msg *lpHead = NULL;
165 int_msg *lpTail = NULL;
166 int nQueue = 0;
167
168 BOOL
169 get_next_msg (W32Msg * lpmsg, BOOL bWait)
170 {
171 BOOL bRet = FALSE;
172
173 enter_crit ();
174
175 /* The while loop takes care of multiple sets */
176
177 while (!nQueue && bWait)
178 {
179 leave_crit ();
180 WaitForSingleObject (input_available, INFINITE);
181 enter_crit ();
182 }
183
184 if (nQueue)
185 {
186 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
187
188 {
189 int_msg * lpCur = lpHead;
190
191 lpHead = lpHead->lpNext;
192
193 myfree (lpCur);
194 }
195
196 nQueue--;
197 /* Consolidate WM_PAINT messages to optimize redrawing. */
198 if (lpmsg->msg.message == WM_PAINT && nQueue)
199 {
200 int_msg * lpCur = lpHead;
201 int_msg * lpPrev = NULL;
202 int_msg * lpNext = NULL;
203
204 while (lpCur && nQueue)
205 {
206 lpNext = lpCur->lpNext;
207 if (lpCur->w32msg.msg.message == WM_PAINT)
208 {
209 /* Remove this message from the queue. */
210 if (lpPrev)
211 lpPrev->lpNext = lpNext;
212 else
213 lpHead = lpNext;
214
215 if (lpCur == lpTail)
216 lpTail = lpPrev;
217
218 /* Adjust clip rectangle to cover both. */
219 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
220 &(lpCur->w32msg.rect)))
221 {
222 SetRectEmpty (&(lpmsg->rect));
223 }
224
225 myfree (lpCur);
226
227 nQueue--;
228
229 lpCur = lpNext;
230 }
231 else
232 {
233 lpPrev = lpCur;
234 lpCur = lpNext;
235 }
236 }
237 }
238
239 bRet = TRUE;
240 }
241
242 if (nQueue == 0)
243 ResetEvent (input_available);
244
245 leave_crit ();
246
247 return (bRet);
248 }
249
250 extern char * w32_strerror (int error_no);
251
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)
256 {
257 SetEvent (input_available);
258
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 */
264 }
265
266 BOOL
267 post_msg (W32Msg * lpmsg)
268 {
269 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
270
271 if (!lpNew)
272 return (FALSE);
273
274 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
275 lpNew->lpNext = NULL;
276
277 enter_crit ();
278
279 if (nQueue++)
280 {
281 lpTail->lpNext = lpNew;
282 }
283 else
284 {
285 lpHead = lpNew;
286 }
287
288 lpTail = lpNew;
289 notify_msg_ready ();
290 leave_crit ();
291
292 return (TRUE);
293 }
294
295 BOOL
296 prepend_msg (W32Msg *lpmsg)
297 {
298 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
299
300 if (!lpNew)
301 return (FALSE);
302
303 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
304
305 enter_crit ();
306
307 nQueue++;
308 lpNew->lpNext = lpHead;
309 lpHead = lpNew;
310 notify_msg_ready ();
311 leave_crit ();
312
313 return (TRUE);
314 }
315
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. */
318 int
319 drain_message_queue (void)
320 {
321 MSG msg;
322 int retval = 0;
323
324 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
325 {
326 if (msg.message == WM_EMACS_FILENOTIFY)
327 retval = 1;
328 TranslateMessage (&msg);
329 DispatchMessage (&msg);
330 }
331 return retval;
332 }