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