b49abffa130d032be76f7683b7a59ecf363a6a3f
[bpt/emacs.git] / 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-2013 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
24 #include "lisp.h"
25 #include "keyboard.h"
26 #include "frame.h"
27 #include "window.h"
28 #include "charset.h"
29 #include "fontset.h"
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
37 CRITICAL_SECTION critsect;
38
39 #ifdef WINDOWSNT
40 extern HANDLE keyboard_handle;
41 #endif /* WINDOWSNT */
42
43 HANDLE input_available = NULL;
44 HANDLE interrupt_handle = NULL;
45
46 void
47 init_crit (void)
48 {
49 InitializeCriticalSection (&critsect);
50
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. */
53 input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
54
55 #ifdef WINDOWSNT
56 keyboard_handle = input_available;
57 #endif /* WINDOWSNT */
58
59 /* interrupt_handle is signaled when quit (C-g) is detected, so that
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
64 signal this event, so that it never remains signaled. */
65 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
66 }
67
68 void
69 delete_crit (void)
70 {
71 DeleteCriticalSection (&critsect);
72
73 if (input_available)
74 {
75 CloseHandle (input_available);
76 input_available = NULL;
77 }
78 if (interrupt_handle)
79 {
80 CloseHandle (interrupt_handle);
81 interrupt_handle = NULL;
82 }
83 }
84
85 void
86 signal_quit (void)
87 {
88 /* Make sure this event never remains signaled; if the main thread
89 isn't in a blocking call, then this should do nothing. */
90 PulseEvent (interrupt_handle);
91 }
92
93 void
94 select_palette (struct frame *f, HDC hdc)
95 {
96 struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
97
98 if (!display_info->has_palette)
99 return;
100
101 if (display_info->palette == 0)
102 return;
103
104 if (!NILP (Vw32_enable_palette))
105 f->output_data.w32->old_palette =
106 SelectPalette (hdc, display_info->palette, FALSE);
107 else
108 f->output_data.w32->old_palette = NULL;
109
110 if (RealizePalette (hdc) != GDI_ERROR)
111 {
112 Lisp_Object frame, framelist;
113 FOR_EACH_FRAME (framelist, frame)
114 {
115 SET_FRAME_GARBAGED (XFRAME (frame));
116 }
117 }
118 }
119
120 void
121 deselect_palette (struct frame *f, HDC hdc)
122 {
123 if (f->output_data.w32->old_palette)
124 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
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
130 get_frame_dc (struct frame *f)
131 {
132 HDC hdc;
133
134 if (f->output_method != output_w32)
135 emacs_abort ();
136
137 enter_crit ();
138
139 hdc = GetDC (f->output_data.w32->window_desc);
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);
145
146 return hdc;
147 }
148
149 int
150 release_frame_dc (struct frame *f, HDC hdc)
151 {
152 int ret;
153
154 deselect_palette (f, hdc);
155 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
156
157 leave_crit ();
158
159 return ret;
160 }
161
162 typedef struct int_msg
163 {
164 W32Msg w32msg;
165 struct int_msg *lpNext;
166 } int_msg;
167
168 int_msg *lpHead = NULL;
169 int_msg *lpTail = NULL;
170 int nQueue = 0;
171
172 BOOL
173 get_next_msg (W32Msg * lpmsg, BOOL bWait)
174 {
175 BOOL bRet = FALSE;
176
177 enter_crit ();
178
179 /* The while loop takes care of multiple sets */
180
181 while (!nQueue && bWait)
182 {
183 leave_crit ();
184 WaitForSingleObject (input_available, INFINITE);
185 enter_crit ();
186 }
187
188 if (nQueue)
189 {
190 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
191
192 {
193 int_msg * lpCur = lpHead;
194
195 lpHead = lpHead->lpNext;
196
197 myfree (lpCur);
198 }
199
200 nQueue--;
201 /* Consolidate WM_PAINT messages to optimize redrawing. */
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 {
226 SetRectEmpty (&(lpmsg->rect));
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 }
242
243 bRet = TRUE;
244 }
245
246 if (nQueue == 0)
247 ResetEvent (input_available);
248
249 leave_crit ();
250
251 return (bRet);
252 }
253
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
270 BOOL
271 post_msg (W32Msg * lpmsg)
272 {
273 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
274
275 if (!lpNew)
276 return (FALSE);
277
278 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
279 lpNew->lpNext = NULL;
280
281 enter_crit ();
282
283 if (nQueue++)
284 {
285 lpTail->lpNext = lpNew;
286 }
287 else
288 {
289 lpHead = lpNew;
290 }
291
292 lpTail = lpNew;
293 notify_msg_ready ();
294 leave_crit ();
295
296 return (TRUE);
297 }
298
299 BOOL
300 prepend_msg (W32Msg *lpmsg)
301 {
302 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
303
304 if (!lpNew)
305 return (FALSE);
306
307 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
308
309 enter_crit ();
310
311 nQueue++;
312 lpNew->lpNext = lpHead;
313 lpHead = lpNew;
314 notify_msg_ready ();
315 leave_crit ();
316
317 return (TRUE);
318 }
319
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
323 drain_message_queue (void)
324 {
325 MSG msg;
326 int retval = 0;
327
328 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
329 {
330 if (msg.message == WM_EMACS_FILENOTIFY)
331 retval = 1;
332 TranslateMessage (&msg);
333 DispatchMessage (&msg);
334 }
335 return retval;
336 }