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