Merge from emacs-24; up to 2012-05-08T14:11:47Z!monnier@iro.umontreal.ca
[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 #include "lisp.h"
23 #include "keyboard.h"
24 #include "frame.h"
25 #include "charset.h"
26 #include "fontset.h"
27 #include "blockinput.h"
28 #include "w32term.h"
29 #include "windowsx.h"
30
31 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
32 #define myfree(lp) GlobalFreePtr (lp)
33
34 CRITICAL_SECTION critsect;
35 extern HANDLE keyboard_handle;
36 HANDLE input_available = NULL;
37 HANDLE interrupt_handle = NULL;
38
39 void
40 init_crit (void)
41 {
42 InitializeCriticalSection (&critsect);
43
44 /* For safety, input_available should only be reset by get_next_msg
45 when the input queue is empty, so make it a manual reset event. */
46 keyboard_handle = input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
47
48 /* interrupt_handle is signaled when quit (C-g) is detected, so that
49 blocking system calls can be interrupted. We make it a manual
50 reset event, so that if we should ever have multiple threads
51 performing system calls, they will all be interrupted (I'm guessing
52 that would the right response). Note that we use PulseEvent to
53 signal this event, so that it never remains signaled. */
54 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
55 }
56
57 void
58 delete_crit (void)
59 {
60 DeleteCriticalSection (&critsect);
61
62 if (input_available)
63 {
64 CloseHandle (input_available);
65 input_available = NULL;
66 }
67 if (interrupt_handle)
68 {
69 CloseHandle (interrupt_handle);
70 interrupt_handle = NULL;
71 }
72 }
73
74 void
75 signal_quit (void)
76 {
77 /* Make sure this event never remains signaled; if the main thread
78 isn't in a blocking call, then this should do nothing. */
79 PulseEvent (interrupt_handle);
80 }
81
82 void
83 select_palette (FRAME_PTR f, HDC hdc)
84 {
85 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
86
87 if (!display_info->has_palette)
88 return;
89
90 if (display_info->palette == 0)
91 return;
92
93 if (!NILP (Vw32_enable_palette))
94 f->output_data.w32->old_palette =
95 SelectPalette (hdc, display_info->palette, FALSE);
96 else
97 f->output_data.w32->old_palette = NULL;
98
99 if (RealizePalette (hdc) != GDI_ERROR)
100 {
101 Lisp_Object frame, framelist;
102 FOR_EACH_FRAME (framelist, frame)
103 {
104 SET_FRAME_GARBAGED (XFRAME (frame));
105 }
106 }
107 }
108
109 void
110 deselect_palette (FRAME_PTR f, HDC hdc)
111 {
112 if (f->output_data.w32->old_palette)
113 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
114 }
115
116 /* Get a DC for frame and select palette for drawing; force an update of
117 all frames if palette's mapping changes. */
118 HDC
119 get_frame_dc (FRAME_PTR f)
120 {
121 HDC hdc;
122
123 if (f->output_method != output_w32)
124 emacs_abort ();
125
126 enter_crit ();
127
128 hdc = GetDC (f->output_data.w32->window_desc);
129
130 /* If this gets called during startup before the frame is valid,
131 there is a chance of corrupting random data or crashing. */
132 if (hdc)
133 select_palette (f, hdc);
134
135 return hdc;
136 }
137
138 int
139 release_frame_dc (FRAME_PTR f, HDC hdc)
140 {
141 int ret;
142
143 deselect_palette (f, hdc);
144 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
145
146 leave_crit ();
147
148 return ret;
149 }
150
151 typedef struct int_msg
152 {
153 W32Msg w32msg;
154 struct int_msg *lpNext;
155 } int_msg;
156
157 int_msg *lpHead = NULL;
158 int_msg *lpTail = NULL;
159 int nQueue = 0;
160
161 BOOL
162 get_next_msg (W32Msg * lpmsg, BOOL bWait)
163 {
164 BOOL bRet = FALSE;
165
166 enter_crit ();
167
168 /* The while loop takes care of multiple sets */
169
170 while (!nQueue && bWait)
171 {
172 leave_crit ();
173 WaitForSingleObject (input_available, INFINITE);
174 enter_crit ();
175 }
176
177 if (nQueue)
178 {
179 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
180
181 {
182 int_msg * lpCur = lpHead;
183
184 lpHead = lpHead->lpNext;
185
186 myfree (lpCur);
187 }
188
189 nQueue--;
190 /* Consolidate WM_PAINT messages to optimize redrawing. */
191 if (lpmsg->msg.message == WM_PAINT && nQueue)
192 {
193 int_msg * lpCur = lpHead;
194 int_msg * lpPrev = NULL;
195 int_msg * lpNext = NULL;
196
197 while (lpCur && nQueue)
198 {
199 lpNext = lpCur->lpNext;
200 if (lpCur->w32msg.msg.message == WM_PAINT)
201 {
202 /* Remove this message from the queue. */
203 if (lpPrev)
204 lpPrev->lpNext = lpNext;
205 else
206 lpHead = lpNext;
207
208 if (lpCur == lpTail)
209 lpTail = lpPrev;
210
211 /* Adjust clip rectangle to cover both. */
212 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
213 &(lpCur->w32msg.rect)))
214 {
215 SetRectEmpty (&(lpmsg->rect));
216 }
217
218 myfree (lpCur);
219
220 nQueue--;
221
222 lpCur = lpNext;
223 }
224 else
225 {
226 lpPrev = lpCur;
227 lpCur = lpNext;
228 }
229 }
230 }
231
232 bRet = TRUE;
233 }
234
235 if (nQueue == 0)
236 ResetEvent (input_available);
237
238 leave_crit ();
239
240 return (bRet);
241 }
242
243 BOOL
244 post_msg (W32Msg * lpmsg)
245 {
246 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
247
248 if (!lpNew)
249 return (FALSE);
250
251 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
252 lpNew->lpNext = NULL;
253
254 enter_crit ();
255
256 if (nQueue++)
257 {
258 lpTail->lpNext = lpNew;
259 }
260 else
261 {
262 lpHead = lpNew;
263 }
264
265 lpTail = lpNew;
266 SetEvent (input_available);
267
268 leave_crit ();
269
270 return (TRUE);
271 }
272
273 BOOL
274 prepend_msg (W32Msg *lpmsg)
275 {
276 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
277
278 if (!lpNew)
279 return (FALSE);
280
281 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
282
283 enter_crit ();
284
285 nQueue++;
286 lpNew->lpNext = lpHead;
287 lpHead = lpNew;
288
289 leave_crit ();
290
291 return (TRUE);
292 }
293
294 /* Process all messages in the current thread's queue. */
295 void
296 drain_message_queue (void)
297 {
298 MSG msg;
299 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
300 {
301 TranslateMessage (&msg);
302 DispatchMessage (&msg);
303 }
304 }
305
306 /* x_sync is a no-op on W32. */
307 void
308 x_sync (struct frame *f)
309 {
310 }