Implement cygw32
[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>
d7306fe6 22#include <setjmp.h>
0fda9b75 23
ee78dc32 24#include "lisp.h"
3e4731a3 25#include "keyboard.h"
97aab3a2 26#include "frame.h"
bd6bb544
GV
27#include "charset.h"
28#include "fontset.h"
ee78dc32
GV
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
dd118a07 36CRITICAL_SECTION critsect;
0fda9b75
DC
37
38#ifdef WINDOWSNT
ee78dc32 39extern HANDLE keyboard_handle;
0fda9b75
DC
40#endif /* WINDOWSNT */
41
97aab3a2 42HANDLE input_available = NULL;
1ce3dc2b 43HANDLE interrupt_handle = NULL;
ee78dc32 44
177c0ea7 45void
b56ceb92 46init_crit (void)
ee78dc32 47{
dd118a07 48 InitializeCriticalSection (&critsect);
ee78dc32 49
97aab3a2
GV
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. */
0fda9b75
DC
52 input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
53
54#ifdef WINDOWSNT
55 keyboard_handle = input_available;
56#endif /* WINDOWSNT */
1ce3dc2b 57
04bf5b65 58 /* interrupt_handle is signaled when quit (C-g) is detected, so that
1ce3dc2b
RS
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
04bf5b65 63 signal this event, so that it never remains signaled. */
1ce3dc2b 64 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
ee78dc32
GV
65}
66
177c0ea7 67void
b56ceb92 68delete_crit (void)
ee78dc32 69{
97aab3a2
GV
70 DeleteCriticalSection (&critsect);
71
72 if (input_available)
73 {
74 CloseHandle (input_available);
75 input_available = NULL;
76 }
1ce3dc2b
RS
77 if (interrupt_handle)
78 {
79 CloseHandle (interrupt_handle);
80 interrupt_handle = NULL;
81 }
82}
83
84void
b56ceb92 85signal_quit (void)
1ce3dc2b 86{
04bf5b65 87 /* Make sure this event never remains signaled; if the main thread
1ce3dc2b
RS
88 isn't in a blocking call, then this should do nothing. */
89 PulseEvent (interrupt_handle);
d484dc55
GV
90}
91
97aab3a2
GV
92void
93select_palette (FRAME_PTR f, HDC hdc)
d484dc55 94{
90f4a9f8
AI
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)
a8370d72 101 return;
90f4a9f8 102
fbd6baed
GV
103 if (!NILP (Vw32_enable_palette))
104 f->output_data.w32->old_palette =
90f4a9f8 105 SelectPalette (hdc, display_info->palette, FALSE);
97aab3a2 106 else
fbd6baed 107 f->output_data.w32->old_palette = NULL;
97aab3a2 108
1c2cc4ef 109 if (RealizePalette (hdc) != GDI_ERROR)
97aab3a2
GV
110 {
111 Lisp_Object frame, framelist;
112 FOR_EACH_FRAME (framelist, frame)
dd118a07 113 {
97aab3a2 114 SET_FRAME_GARBAGED (XFRAME (frame));
dd118a07 115 }
97aab3a2
GV
116 }
117}
118
119void
120deselect_palette (FRAME_PTR f, HDC hdc)
121{
fbd6baed
GV
122 if (f->output_data.w32->old_palette)
123 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
97aab3a2
GV
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. */
128HDC
129get_frame_dc (FRAME_PTR f)
130{
131 HDC hdc;
132
56c16321
AI
133 if (f->output_method != output_w32)
134 abort ();
135
97aab3a2
GV
136 enter_crit ();
137
fbd6baed 138 hdc = GetDC (f->output_data.w32->window_desc);
86d1db20
JR
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);
97aab3a2
GV
144
145 return hdc;
146}
147
148int
149release_frame_dc (FRAME_PTR f, HDC hdc)
150{
151 int ret;
152
153 deselect_palette (f, hdc);
fbd6baed 154 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
97aab3a2
GV
155
156 leave_crit ();
157
158 return ret;
ee78dc32
GV
159}
160
161typedef struct int_msg
162{
fbd6baed 163 W32Msg w32msg;
ee78dc32
GV
164 struct int_msg *lpNext;
165} int_msg;
166
167int_msg *lpHead = NULL;
168int_msg *lpTail = NULL;
169int nQueue = 0;
170
177c0ea7 171BOOL
b56ceb92 172get_next_msg (W32Msg * lpmsg, BOOL bWait)
ee78dc32
GV
173{
174 BOOL bRet = FALSE;
177c0ea7 175
dd118a07 176 enter_crit ();
177c0ea7 177
ee78dc32 178 /* The while loop takes care of multiple sets */
177c0ea7 179
ee78dc32
GV
180 while (!nQueue && bWait)
181 {
dd118a07 182 leave_crit ();
97aab3a2 183 WaitForSingleObject (input_available, INFINITE);
dd118a07 184 enter_crit ();
ee78dc32 185 }
177c0ea7 186
ee78dc32
GV
187 if (nQueue)
188 {
72af86bd 189 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
ee78dc32
GV
190
191 {
192 int_msg * lpCur = lpHead;
177c0ea7 193
ee78dc32 194 lpHead = lpHead->lpNext;
177c0ea7 195
ee78dc32
GV
196 myfree (lpCur);
197 }
198
199 nQueue--;
e1dbe924 200 /* Consolidate WM_PAINT messages to optimize redrawing. */
b668cc18
JR
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 {
ed3751c8 225 SetRectEmpty (&(lpmsg->rect));
b668cc18
JR
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 }
ee78dc32
GV
241
242 bRet = TRUE;
243 }
97aab3a2
GV
244
245 if (nQueue == 0)
246 ResetEvent (input_available);
177c0ea7 247
dd118a07 248 leave_crit ();
177c0ea7 249
ee78dc32
GV
250 return (bRet);
251}
252
0fda9b75
DC
253extern 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. */
257static void
258notify_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
177c0ea7 269BOOL
b56ceb92 270post_msg (W32Msg * lpmsg)
ee78dc32
GV
271{
272 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
273
97aab3a2
GV
274 if (!lpNew)
275 return (FALSE);
ee78dc32 276
72af86bd 277 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
ee78dc32
GV
278 lpNew->lpNext = NULL;
279
dd118a07 280 enter_crit ();
ee78dc32
GV
281
282 if (nQueue++)
dd118a07
GV
283 {
284 lpTail->lpNext = lpNew;
285 }
177c0ea7 286 else
dd118a07
GV
287 {
288 lpHead = lpNew;
dd118a07 289 }
ee78dc32
GV
290
291 lpTail = lpNew;
0fda9b75 292 notify_msg_ready ();
dd118a07 293 leave_crit ();
ee78dc32
GV
294
295 return (TRUE);
296}
297
7c69181b 298BOOL
fbd6baed 299prepend_msg (W32Msg *lpmsg)
7c69181b
GV
300{
301 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
302
303 if (!lpNew)
304 return (FALSE);
305
72af86bd 306 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
7c69181b
GV
307
308 enter_crit ();
309
310 nQueue++;
311 lpNew->lpNext = lpHead;
312 lpHead = lpNew;
0fda9b75 313 notify_msg_ready ();
7c69181b
GV
314 leave_crit ();
315
316 return (TRUE);
317}
318
716490f0
AI
319/* Process all messages in the current thread's queue. */
320void
b56ceb92 321drain_message_queue (void)
716490f0
AI
322{
323 MSG msg;
324 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
325 {
326 TranslateMessage (&msg);
327 DispatchMessage (&msg);
328 }
329}
330
331
ee78dc32
GV
332/*
333 * XParseGeometry parses strings of the form
334 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
335 * width, height, xoffset, and yoffset are unsigned integers.
336 * Example: "=80x24+300-49"
337 * The equal sign is optional.
338 * It returns a bitmask that indicates which of the four values
339 * were actually found in the string. For each value found,
340 * the corresponding argument is updated; for each value
177c0ea7 341 * not found, the corresponding argument is left unchanged.
ee78dc32
GV
342 */
343
344static int
b56ceb92 345read_integer (register char *string, char **NextString)
ee78dc32
GV
346{
347 register int Result = 0;
348 int Sign = 1;
177c0ea7 349
ee78dc32
GV
350 if (*string == '+')
351 string++;
352 else if (*string == '-')
353 {
354 string++;
355 Sign = -1;
356 }
357 for (; (*string >= '0') && (*string <= '9'); string++)
358 {
359 Result = (Result * 10) + (*string - '0');
360 }
361 *NextString = string;
362 if (Sign >= 0)
363 return (Result);
364 else
365 return (-Result);
366}
367
177c0ea7 368int
b56ceb92
JB
369XParseGeometry (char *string,
370 int *x, int *y,
371 unsigned int *width, unsigned int *height)
ee78dc32
GV
372{
373 int mask = NoValue;
374 register char *strind;
375 unsigned int tempWidth, tempHeight;
376 int tempX, tempY;
377 char *nextCharacter;
177c0ea7 378
ee78dc32
GV
379 if ((string == NULL) || (*string == '\0')) return (mask);
380 if (*string == '=')
381 string++; /* ignore possible '=' at beg of geometry spec */
177c0ea7 382
ee78dc32 383 strind = (char *)string;
177c0ea7 384 if (*strind != '+' && *strind != '-' && *strind != 'x')
ee78dc32
GV
385 {
386 tempWidth = read_integer (strind, &nextCharacter);
177c0ea7 387 if (strind == nextCharacter)
ee78dc32
GV
388 return (0);
389 strind = nextCharacter;
390 mask |= WidthValue;
391 }
177c0ea7
JB
392
393 if (*strind == 'x' || *strind == 'X')
394 {
ee78dc32
GV
395 strind++;
396 tempHeight = read_integer (strind, &nextCharacter);
397 if (strind == nextCharacter)
398 return (0);
399 strind = nextCharacter;
400 mask |= HeightValue;
401 }
177c0ea7
JB
402
403 if ((*strind == '+') || (*strind == '-'))
ee78dc32 404 {
177c0ea7 405 if (*strind == '-')
ee78dc32
GV
406 {
407 strind++;
408 tempX = -read_integer (strind, &nextCharacter);
409 if (strind == nextCharacter)
410 return (0);
411 strind = nextCharacter;
412 mask |= XNegative;
413
414 }
415 else
177c0ea7 416 {
ee78dc32
GV
417 strind++;
418 tempX = read_integer (strind, &nextCharacter);
419 if (strind == nextCharacter)
420 return (0);
421 strind = nextCharacter;
422 }
423 mask |= XValue;
177c0ea7 424 if ((*strind == '+') || (*strind == '-'))
ee78dc32 425 {
177c0ea7 426 if (*strind == '-')
ee78dc32
GV
427 {
428 strind++;
429 tempY = -read_integer (strind, &nextCharacter);
430 if (strind == nextCharacter)
431 return (0);
432 strind = nextCharacter;
433 mask |= YNegative;
ee78dc32
GV
434 }
435 else
436 {
437 strind++;
438 tempY = read_integer (strind, &nextCharacter);
439 if (strind == nextCharacter)
440 return (0);
441 strind = nextCharacter;
442 }
443 mask |= YValue;
444 }
445 }
177c0ea7 446
9d4f32e8 447 /* If strind isn't at the end of the string then it's an invalid
ee78dc32 448 geometry specification. */
177c0ea7 449
ee78dc32 450 if (*strind != '\0') return (0);
177c0ea7 451
ee78dc32
GV
452 if (mask & XValue)
453 *x = tempX;
454 if (mask & YValue)
455 *y = tempY;
456 if (mask & WidthValue)
457 *width = tempWidth;
458 if (mask & HeightValue)
459 *height = tempHeight;
460 return (mask);
461}
462
fbd6baed 463/* x_sync is a no-op on W32. */
ee78dc32 464void
17a2cbbd 465x_sync (struct frame *f)
ee78dc32
GV
466{
467}