Merge from trunk.
[bpt/emacs.git] / src / w32xfns.c
CommitLineData
b46a6a83 1/* Functions taken directly from X sources for use with the Microsoft Windows API.
acaf905b 2 Copyright (C) 1989, 1992-1995, 1999, 2001-2012 Free Software Foundation, Inc.
ee78dc32
GV
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
ee78dc32 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
ee78dc32
GV
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
ee78dc32 18
ee78dc32 19#include <config.h>
68c45bf0 20#include <signal.h>
ee78dc32 21#include <stdio.h>
0fda9b75 22
ee78dc32 23#include "lisp.h"
3e4731a3 24#include "keyboard.h"
97aab3a2 25#include "frame.h"
bd6bb544
GV
26#include "charset.h"
27#include "fontset.h"
ee78dc32
GV
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
dd118a07 35CRITICAL_SECTION critsect;
0fda9b75
DC
36
37#ifdef WINDOWSNT
ee78dc32 38extern HANDLE keyboard_handle;
0fda9b75
DC
39#endif /* WINDOWSNT */
40
97aab3a2 41HANDLE input_available = NULL;
1ce3dc2b 42HANDLE interrupt_handle = NULL;
ee78dc32 43
177c0ea7 44void
b56ceb92 45init_crit (void)
ee78dc32 46{
dd118a07 47 InitializeCriticalSection (&critsect);
ee78dc32 48
97aab3a2
GV
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. */
0fda9b75
DC
51 input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
52
53#ifdef WINDOWSNT
54 keyboard_handle = input_available;
55#endif /* WINDOWSNT */
1ce3dc2b 56
04bf5b65 57 /* interrupt_handle is signaled when quit (C-g) is detected, so that
1ce3dc2b
RS
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
04bf5b65 62 signal this event, so that it never remains signaled. */
1ce3dc2b 63 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
ee78dc32
GV
64}
65
177c0ea7 66void
b56ceb92 67delete_crit (void)
ee78dc32 68{
97aab3a2
GV
69 DeleteCriticalSection (&critsect);
70
71 if (input_available)
72 {
73 CloseHandle (input_available);
74 input_available = NULL;
75 }
1ce3dc2b
RS
76 if (interrupt_handle)
77 {
78 CloseHandle (interrupt_handle);
79 interrupt_handle = NULL;
80 }
81}
82
83void
b56ceb92 84signal_quit (void)
1ce3dc2b 85{
04bf5b65 86 /* Make sure this event never remains signaled; if the main thread
1ce3dc2b
RS
87 isn't in a blocking call, then this should do nothing. */
88 PulseEvent (interrupt_handle);
d484dc55
GV
89}
90
97aab3a2
GV
91void
92select_palette (FRAME_PTR f, HDC hdc)
d484dc55 93{
90f4a9f8
AI
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)
a8370d72 100 return;
90f4a9f8 101
fbd6baed
GV
102 if (!NILP (Vw32_enable_palette))
103 f->output_data.w32->old_palette =
90f4a9f8 104 SelectPalette (hdc, display_info->palette, FALSE);
97aab3a2 105 else
fbd6baed 106 f->output_data.w32->old_palette = NULL;
97aab3a2 107
1c2cc4ef 108 if (RealizePalette (hdc) != GDI_ERROR)
97aab3a2
GV
109 {
110 Lisp_Object frame, framelist;
111 FOR_EACH_FRAME (framelist, frame)
dd118a07 112 {
97aab3a2 113 SET_FRAME_GARBAGED (XFRAME (frame));
dd118a07 114 }
97aab3a2
GV
115 }
116}
117
118void
119deselect_palette (FRAME_PTR f, HDC hdc)
120{
fbd6baed
GV
121 if (f->output_data.w32->old_palette)
122 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
97aab3a2
GV
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. */
127HDC
128get_frame_dc (FRAME_PTR f)
129{
130 HDC hdc;
131
56c16321 132 if (f->output_method != output_w32)
1088b922 133 emacs_abort ();
56c16321 134
97aab3a2
GV
135 enter_crit ();
136
fbd6baed 137 hdc = GetDC (f->output_data.w32->window_desc);
86d1db20
JR
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);
97aab3a2
GV
143
144 return hdc;
145}
146
147int
148release_frame_dc (FRAME_PTR f, HDC hdc)
149{
150 int ret;
151
152 deselect_palette (f, hdc);
fbd6baed 153 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
97aab3a2
GV
154
155 leave_crit ();
156
157 return ret;
ee78dc32
GV
158}
159
160typedef struct int_msg
161{
fbd6baed 162 W32Msg w32msg;
ee78dc32
GV
163 struct int_msg *lpNext;
164} int_msg;
165
166int_msg *lpHead = NULL;
167int_msg *lpTail = NULL;
168int nQueue = 0;
169
177c0ea7 170BOOL
b56ceb92 171get_next_msg (W32Msg * lpmsg, BOOL bWait)
ee78dc32
GV
172{
173 BOOL bRet = FALSE;
177c0ea7 174
dd118a07 175 enter_crit ();
177c0ea7 176
ee78dc32 177 /* The while loop takes care of multiple sets */
177c0ea7 178
ee78dc32
GV
179 while (!nQueue && bWait)
180 {
dd118a07 181 leave_crit ();
97aab3a2 182 WaitForSingleObject (input_available, INFINITE);
dd118a07 183 enter_crit ();
ee78dc32 184 }
177c0ea7 185
ee78dc32
GV
186 if (nQueue)
187 {
72af86bd 188 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
ee78dc32
GV
189
190 {
191 int_msg * lpCur = lpHead;
177c0ea7 192
ee78dc32 193 lpHead = lpHead->lpNext;
177c0ea7 194
ee78dc32
GV
195 myfree (lpCur);
196 }
197
198 nQueue--;
e1dbe924 199 /* Consolidate WM_PAINT messages to optimize redrawing. */
b668cc18
JR
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 {
ed3751c8 224 SetRectEmpty (&(lpmsg->rect));
b668cc18
JR
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 }
ee78dc32
GV
240
241 bRet = TRUE;
242 }
97aab3a2
GV
243
244 if (nQueue == 0)
245 ResetEvent (input_available);
177c0ea7 246
dd118a07 247 leave_crit ();
177c0ea7 248
ee78dc32
GV
249 return (bRet);
250}
251
0fda9b75
DC
252extern 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. */
256static void
257notify_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
177c0ea7 268BOOL
b56ceb92 269post_msg (W32Msg * lpmsg)
ee78dc32
GV
270{
271 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
272
97aab3a2
GV
273 if (!lpNew)
274 return (FALSE);
ee78dc32 275
72af86bd 276 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
ee78dc32
GV
277 lpNew->lpNext = NULL;
278
dd118a07 279 enter_crit ();
ee78dc32
GV
280
281 if (nQueue++)
dd118a07
GV
282 {
283 lpTail->lpNext = lpNew;
284 }
177c0ea7 285 else
dd118a07
GV
286 {
287 lpHead = lpNew;
dd118a07 288 }
ee78dc32
GV
289
290 lpTail = lpNew;
0fda9b75 291 notify_msg_ready ();
dd118a07 292 leave_crit ();
ee78dc32
GV
293
294 return (TRUE);
295}
296
7c69181b 297BOOL
fbd6baed 298prepend_msg (W32Msg *lpmsg)
7c69181b
GV
299{
300 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
301
302 if (!lpNew)
303 return (FALSE);
304
72af86bd 305 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
7c69181b
GV
306
307 enter_crit ();
308
309 nQueue++;
310 lpNew->lpNext = lpHead;
311 lpHead = lpNew;
0fda9b75 312 notify_msg_ready ();
7c69181b
GV
313 leave_crit ();
314
315 return (TRUE);
316}
317
716490f0
AI
318/* Process all messages in the current thread's queue. */
319void
b56ceb92 320drain_message_queue (void)
716490f0
AI
321{
322 MSG msg;
323 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
324 {
325 TranslateMessage (&msg);
326 DispatchMessage (&msg);
327 }
328}
329
fbd6baed 330/* x_sync is a no-op on W32. */
ee78dc32 331void
17a2cbbd 332x_sync (struct frame *f)
ee78dc32
GV
333{
334}