Commit | Line | Data |
---|---|---|
b46a6a83 | 1 | /* Functions taken directly from X sources for use with the Microsoft Windows API. |
ba318903 | 2 | Copyright (C) 1989, 1992-1995, 1999, 2001-2014 Free Software |
ab422c4d | 3 | Foundation, Inc. |
ee78dc32 GV |
4 | |
5 | This file is part of GNU Emacs. | |
6 | ||
9ec0b715 | 7 | GNU Emacs is free software: you can redistribute it and/or modify |
ee78dc32 | 8 | it under the terms of the GNU General Public License as published by |
9ec0b715 GM |
9 | the Free Software Foundation, either version 3 of the License, or |
10 | (at your option) any later version. | |
ee78dc32 GV |
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 | |
9ec0b715 | 18 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ |
ee78dc32 | 19 | |
ee78dc32 | 20 | #include <config.h> |
68c45bf0 | 21 | #include <signal.h> |
ee78dc32 | 22 | #include <stdio.h> |
0fda9b75 | 23 | |
ee78dc32 | 24 | #include "lisp.h" |
3e4731a3 | 25 | #include "keyboard.h" |
97aab3a2 | 26 | #include "frame.h" |
913250cf | 27 | #include "window.h" |
bd6bb544 GV |
28 | #include "charset.h" |
29 | #include "fontset.h" | |
ee78dc32 GV |
30 | #include "blockinput.h" |
31 | #include "w32term.h" | |
32 | #include "windowsx.h" | |
33 | ||
34 | #define myalloc(cb) GlobalAllocPtr (GPTR, cb) | |
35 | #define myfree(lp) GlobalFreePtr (lp) | |
36 | ||
dd118a07 | 37 | CRITICAL_SECTION critsect; |
0fda9b75 DC |
38 | |
39 | #ifdef WINDOWSNT | |
ee78dc32 | 40 | extern HANDLE keyboard_handle; |
0fda9b75 DC |
41 | #endif /* WINDOWSNT */ |
42 | ||
97aab3a2 | 43 | HANDLE input_available = NULL; |
1ce3dc2b | 44 | HANDLE interrupt_handle = NULL; |
ee78dc32 | 45 | |
177c0ea7 | 46 | void |
b56ceb92 | 47 | init_crit (void) |
ee78dc32 | 48 | { |
dd118a07 | 49 | InitializeCriticalSection (&critsect); |
ee78dc32 | 50 | |
97aab3a2 GV |
51 | /* For safety, input_available should only be reset by get_next_msg |
52 | when the input queue is empty, so make it a manual reset event. */ | |
0fda9b75 DC |
53 | input_available = CreateEvent (NULL, TRUE, FALSE, NULL); |
54 | ||
55 | #ifdef WINDOWSNT | |
56 | keyboard_handle = input_available; | |
57 | #endif /* WINDOWSNT */ | |
1ce3dc2b | 58 | |
04bf5b65 | 59 | /* interrupt_handle is signaled when quit (C-g) is detected, so that |
1ce3dc2b RS |
60 | blocking system calls can be interrupted. We make it a manual |
61 | reset event, so that if we should ever have multiple threads | |
62 | performing system calls, they will all be interrupted (I'm guessing | |
63 | that would the right response). Note that we use PulseEvent to | |
04bf5b65 | 64 | signal this event, so that it never remains signaled. */ |
1ce3dc2b | 65 | interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL); |
ee78dc32 GV |
66 | } |
67 | ||
177c0ea7 | 68 | void |
b56ceb92 | 69 | delete_crit (void) |
ee78dc32 | 70 | { |
97aab3a2 GV |
71 | DeleteCriticalSection (&critsect); |
72 | ||
73 | if (input_available) | |
74 | { | |
75 | CloseHandle (input_available); | |
76 | input_available = NULL; | |
77 | } | |
1ce3dc2b RS |
78 | if (interrupt_handle) |
79 | { | |
80 | CloseHandle (interrupt_handle); | |
81 | interrupt_handle = NULL; | |
82 | } | |
83 | } | |
84 | ||
85 | void | |
b56ceb92 | 86 | signal_quit (void) |
1ce3dc2b | 87 | { |
04bf5b65 | 88 | /* Make sure this event never remains signaled; if the main thread |
1ce3dc2b RS |
89 | isn't in a blocking call, then this should do nothing. */ |
90 | PulseEvent (interrupt_handle); | |
d484dc55 GV |
91 | } |
92 | ||
97aab3a2 | 93 | void |
a10c8269 | 94 | select_palette (struct frame *f, HDC hdc) |
d484dc55 | 95 | { |
aad3612f | 96 | struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f); |
90f4a9f8 AI |
97 | |
98 | if (!display_info->has_palette) | |
99 | return; | |
100 | ||
101 | if (display_info->palette == 0) | |
a8370d72 | 102 | return; |
90f4a9f8 | 103 | |
fbd6baed GV |
104 | if (!NILP (Vw32_enable_palette)) |
105 | f->output_data.w32->old_palette = | |
90f4a9f8 | 106 | SelectPalette (hdc, display_info->palette, FALSE); |
97aab3a2 | 107 | else |
fbd6baed | 108 | f->output_data.w32->old_palette = NULL; |
97aab3a2 | 109 | |
1c2cc4ef | 110 | if (RealizePalette (hdc) != GDI_ERROR) |
97aab3a2 GV |
111 | { |
112 | Lisp_Object frame, framelist; | |
113 | FOR_EACH_FRAME (framelist, frame) | |
dd118a07 | 114 | { |
97aab3a2 | 115 | SET_FRAME_GARBAGED (XFRAME (frame)); |
dd118a07 | 116 | } |
97aab3a2 GV |
117 | } |
118 | } | |
119 | ||
120 | void | |
a10c8269 | 121 | deselect_palette (struct frame *f, HDC hdc) |
97aab3a2 | 122 | { |
fbd6baed GV |
123 | if (f->output_data.w32->old_palette) |
124 | SelectPalette (hdc, f->output_data.w32->old_palette, FALSE); | |
97aab3a2 GV |
125 | } |
126 | ||
127 | /* Get a DC for frame and select palette for drawing; force an update of | |
128 | all frames if palette's mapping changes. */ | |
129 | HDC | |
a10c8269 | 130 | get_frame_dc (struct frame *f) |
97aab3a2 GV |
131 | { |
132 | HDC hdc; | |
133 | ||
56c16321 | 134 | if (f->output_method != output_w32) |
1088b922 | 135 | emacs_abort (); |
56c16321 | 136 | |
97aab3a2 GV |
137 | enter_crit (); |
138 | ||
fbd6baed | 139 | hdc = GetDC (f->output_data.w32->window_desc); |
86d1db20 JR |
140 | |
141 | /* If this gets called during startup before the frame is valid, | |
142 | there is a chance of corrupting random data or crashing. */ | |
143 | if (hdc) | |
144 | select_palette (f, hdc); | |
97aab3a2 GV |
145 | |
146 | return hdc; | |
147 | } | |
148 | ||
149 | int | |
a10c8269 | 150 | release_frame_dc (struct frame *f, HDC hdc) |
97aab3a2 GV |
151 | { |
152 | int ret; | |
153 | ||
154 | deselect_palette (f, hdc); | |
fbd6baed | 155 | ret = ReleaseDC (f->output_data.w32->window_desc, hdc); |
97aab3a2 GV |
156 | |
157 | leave_crit (); | |
158 | ||
159 | return ret; | |
ee78dc32 GV |
160 | } |
161 | ||
162 | typedef struct int_msg | |
163 | { | |
fbd6baed | 164 | W32Msg w32msg; |
ee78dc32 GV |
165 | struct int_msg *lpNext; |
166 | } int_msg; | |
167 | ||
168 | int_msg *lpHead = NULL; | |
169 | int_msg *lpTail = NULL; | |
170 | int nQueue = 0; | |
171 | ||
177c0ea7 | 172 | BOOL |
b56ceb92 | 173 | get_next_msg (W32Msg * lpmsg, BOOL bWait) |
ee78dc32 GV |
174 | { |
175 | BOOL bRet = FALSE; | |
177c0ea7 | 176 | |
dd118a07 | 177 | enter_crit (); |
177c0ea7 | 178 | |
ee78dc32 | 179 | /* The while loop takes care of multiple sets */ |
177c0ea7 | 180 | |
ee78dc32 GV |
181 | while (!nQueue && bWait) |
182 | { | |
dd118a07 | 183 | leave_crit (); |
97aab3a2 | 184 | WaitForSingleObject (input_available, INFINITE); |
dd118a07 | 185 | enter_crit (); |
ee78dc32 | 186 | } |
177c0ea7 | 187 | |
ee78dc32 GV |
188 | if (nQueue) |
189 | { | |
72af86bd | 190 | memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg)); |
ee78dc32 GV |
191 | |
192 | { | |
193 | int_msg * lpCur = lpHead; | |
177c0ea7 | 194 | |
ee78dc32 | 195 | lpHead = lpHead->lpNext; |
177c0ea7 | 196 | |
ee78dc32 GV |
197 | myfree (lpCur); |
198 | } | |
199 | ||
200 | nQueue--; | |
e1dbe924 | 201 | /* Consolidate WM_PAINT messages to optimize redrawing. */ |
b668cc18 JR |
202 | if (lpmsg->msg.message == WM_PAINT && nQueue) |
203 | { | |
204 | int_msg * lpCur = lpHead; | |
205 | int_msg * lpPrev = NULL; | |
206 | int_msg * lpNext = NULL; | |
207 | ||
208 | while (lpCur && nQueue) | |
209 | { | |
210 | lpNext = lpCur->lpNext; | |
211 | if (lpCur->w32msg.msg.message == WM_PAINT) | |
212 | { | |
213 | /* Remove this message from the queue. */ | |
214 | if (lpPrev) | |
215 | lpPrev->lpNext = lpNext; | |
216 | else | |
217 | lpHead = lpNext; | |
218 | ||
219 | if (lpCur == lpTail) | |
220 | lpTail = lpPrev; | |
221 | ||
222 | /* Adjust clip rectangle to cover both. */ | |
223 | if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect), | |
224 | &(lpCur->w32msg.rect))) | |
225 | { | |
ed3751c8 | 226 | SetRectEmpty (&(lpmsg->rect)); |
b668cc18 JR |
227 | } |
228 | ||
229 | myfree (lpCur); | |
230 | ||
231 | nQueue--; | |
232 | ||
233 | lpCur = lpNext; | |
234 | } | |
235 | else | |
236 | { | |
237 | lpPrev = lpCur; | |
238 | lpCur = lpNext; | |
239 | } | |
240 | } | |
241 | } | |
ee78dc32 GV |
242 | |
243 | bRet = TRUE; | |
244 | } | |
97aab3a2 GV |
245 | |
246 | if (nQueue == 0) | |
247 | ResetEvent (input_available); | |
177c0ea7 | 248 | |
dd118a07 | 249 | leave_crit (); |
177c0ea7 | 250 | |
ee78dc32 GV |
251 | return (bRet); |
252 | } | |
253 | ||
0fda9b75 DC |
254 | extern char * w32_strerror (int error_no); |
255 | ||
256 | /* Tell the main thread that we have input available; if the main | |
257 | thread is blocked in select(), we wake it up here. */ | |
258 | static void | |
259 | notify_msg_ready (void) | |
260 | { | |
261 | SetEvent (input_available); | |
262 | ||
263 | #ifdef CYGWIN | |
264 | /* Wakes up the main thread, which is blocked select()ing for /dev/windows, | |
265 | among other files. */ | |
266 | (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0); | |
267 | #endif /* CYGWIN */ | |
268 | } | |
269 | ||
177c0ea7 | 270 | BOOL |
b56ceb92 | 271 | post_msg (W32Msg * lpmsg) |
ee78dc32 GV |
272 | { |
273 | int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg)); | |
274 | ||
97aab3a2 GV |
275 | if (!lpNew) |
276 | return (FALSE); | |
ee78dc32 | 277 | |
72af86bd | 278 | memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg)); |
ee78dc32 GV |
279 | lpNew->lpNext = NULL; |
280 | ||
dd118a07 | 281 | enter_crit (); |
ee78dc32 GV |
282 | |
283 | if (nQueue++) | |
dd118a07 GV |
284 | { |
285 | lpTail->lpNext = lpNew; | |
286 | } | |
177c0ea7 | 287 | else |
dd118a07 GV |
288 | { |
289 | lpHead = lpNew; | |
dd118a07 | 290 | } |
ee78dc32 GV |
291 | |
292 | lpTail = lpNew; | |
0fda9b75 | 293 | notify_msg_ready (); |
dd118a07 | 294 | leave_crit (); |
ee78dc32 GV |
295 | |
296 | return (TRUE); | |
297 | } | |
298 | ||
7c69181b | 299 | BOOL |
fbd6baed | 300 | prepend_msg (W32Msg *lpmsg) |
7c69181b GV |
301 | { |
302 | int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg)); | |
303 | ||
304 | if (!lpNew) | |
305 | return (FALSE); | |
306 | ||
72af86bd | 307 | memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg)); |
7c69181b GV |
308 | |
309 | enter_crit (); | |
310 | ||
311 | nQueue++; | |
312 | lpNew->lpNext = lpHead; | |
313 | lpHead = lpNew; | |
0fda9b75 | 314 | notify_msg_ready (); |
7c69181b GV |
315 | leave_crit (); |
316 | ||
317 | return (TRUE); | |
318 | } | |
319 | ||
977c6479 EZ |
320 | /* Process all messages in the current thread's queue. Value is 1 if |
321 | one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */ | |
322 | int | |
b56ceb92 | 323 | drain_message_queue (void) |
716490f0 AI |
324 | { |
325 | MSG msg; | |
977c6479 EZ |
326 | int retval = 0; |
327 | ||
716490f0 AI |
328 | while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) |
329 | { | |
977c6479 EZ |
330 | if (msg.message == WM_EMACS_FILENOTIFY) |
331 | retval = 1; | |
716490f0 AI |
332 | TranslateMessage (&msg); |
333 | DispatchMessage (&msg); | |
334 | } | |
977c6479 | 335 | return retval; |
716490f0 | 336 | } |