Merge.
[emacs.git] / src / w32xfns.c
blobfbbf11bd65c574958840f5f7e1c79e1c5ea4b3f7
1 /* Functions taken directly from X sources for use with the Microsoft W32 API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2011 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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.
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.
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/>. */
19 #include <config.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <setjmp.h>
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"
32 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
33 #define myfree(lp) GlobalFreePtr (lp)
35 CRITICAL_SECTION critsect;
36 extern HANDLE keyboard_handle;
37 HANDLE input_available = NULL;
38 HANDLE interrupt_handle = NULL;
40 void
41 init_crit (void)
43 InitializeCriticalSection (&critsect);
45 /* For safety, input_available should only be reset by get_next_msg
46 when the input queue is empty, so make it a manual reset event. */
47 keyboard_handle = input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
49 /* interrupt_handle is signaled when quit (C-g) is detected, so that
50 blocking system calls can be interrupted. We make it a manual
51 reset event, so that if we should ever have multiple threads
52 performing system calls, they will all be interrupted (I'm guessing
53 that would the right response). Note that we use PulseEvent to
54 signal this event, so that it never remains signaled. */
55 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
58 void
59 delete_crit (void)
61 DeleteCriticalSection (&critsect);
63 if (input_available)
65 CloseHandle (input_available);
66 input_available = NULL;
68 if (interrupt_handle)
70 CloseHandle (interrupt_handle);
71 interrupt_handle = NULL;
75 void
76 signal_quit (void)
78 /* Make sure this event never remains signaled; if the main thread
79 isn't in a blocking call, then this should do nothing. */
80 PulseEvent (interrupt_handle);
83 void
84 select_palette (FRAME_PTR f, HDC hdc)
86 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
88 if (!display_info->has_palette)
89 return;
91 if (display_info->palette == 0)
92 return;
94 if (!NILP (Vw32_enable_palette))
95 f->output_data.w32->old_palette =
96 SelectPalette (hdc, display_info->palette, FALSE);
97 else
98 f->output_data.w32->old_palette = NULL;
100 if (RealizePalette (hdc) != GDI_ERROR)
102 Lisp_Object frame, framelist;
103 FOR_EACH_FRAME (framelist, frame)
105 SET_FRAME_GARBAGED (XFRAME (frame));
110 void
111 deselect_palette (FRAME_PTR f, HDC hdc)
113 if (f->output_data.w32->old_palette)
114 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
117 /* Get a DC for frame and select palette for drawing; force an update of
118 all frames if palette's mapping changes. */
120 get_frame_dc (FRAME_PTR f)
122 HDC hdc;
124 if (f->output_method != output_w32)
125 abort ();
127 enter_crit ();
129 hdc = GetDC (f->output_data.w32->window_desc);
131 /* If this gets called during startup before the frame is valid,
132 there is a chance of corrupting random data or crashing. */
133 if (hdc)
134 select_palette (f, hdc);
136 return hdc;
140 release_frame_dc (FRAME_PTR f, HDC hdc)
142 int ret;
144 deselect_palette (f, hdc);
145 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
147 leave_crit ();
149 return ret;
152 typedef struct int_msg
154 W32Msg w32msg;
155 struct int_msg *lpNext;
156 } int_msg;
158 int_msg *lpHead = NULL;
159 int_msg *lpTail = NULL;
160 int nQueue = 0;
162 BOOL
163 get_next_msg (W32Msg * lpmsg, BOOL bWait)
165 BOOL bRet = FALSE;
167 enter_crit ();
169 /* The while loop takes care of multiple sets */
171 while (!nQueue && bWait)
173 leave_crit ();
174 WaitForSingleObject (input_available, INFINITE);
175 enter_crit ();
178 if (nQueue)
180 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
183 int_msg * lpCur = lpHead;
185 lpHead = lpHead->lpNext;
187 myfree (lpCur);
190 nQueue--;
191 /* Consolidate WM_PAINT messages to optimise redrawing. */
192 if (lpmsg->msg.message == WM_PAINT && nQueue)
194 int_msg * lpCur = lpHead;
195 int_msg * lpPrev = NULL;
196 int_msg * lpNext = NULL;
198 while (lpCur && nQueue)
200 lpNext = lpCur->lpNext;
201 if (lpCur->w32msg.msg.message == WM_PAINT)
203 /* Remove this message from the queue. */
204 if (lpPrev)
205 lpPrev->lpNext = lpNext;
206 else
207 lpHead = lpNext;
209 if (lpCur == lpTail)
210 lpTail = lpPrev;
212 /* Adjust clip rectangle to cover both. */
213 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
214 &(lpCur->w32msg.rect)))
216 SetRectEmpty (&(lpmsg->rect));
219 myfree (lpCur);
221 nQueue--;
223 lpCur = lpNext;
225 else
227 lpPrev = lpCur;
228 lpCur = lpNext;
233 bRet = TRUE;
236 if (nQueue == 0)
237 ResetEvent (input_available);
239 leave_crit ();
241 return (bRet);
244 BOOL
245 post_msg (W32Msg * lpmsg)
247 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
249 if (!lpNew)
250 return (FALSE);
252 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
253 lpNew->lpNext = NULL;
255 enter_crit ();
257 if (nQueue++)
259 lpTail->lpNext = lpNew;
261 else
263 lpHead = lpNew;
266 lpTail = lpNew;
267 SetEvent (input_available);
269 leave_crit ();
271 return (TRUE);
274 BOOL
275 prepend_msg (W32Msg *lpmsg)
277 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
279 if (!lpNew)
280 return (FALSE);
282 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
284 enter_crit ();
286 nQueue++;
287 lpNew->lpNext = lpHead;
288 lpHead = lpNew;
290 leave_crit ();
292 return (TRUE);
295 /* Process all messages in the current thread's queue. */
296 void
297 drain_message_queue (void)
299 MSG msg;
300 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
302 TranslateMessage (&msg);
303 DispatchMessage (&msg);
309 * XParseGeometry parses strings of the form
310 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
311 * width, height, xoffset, and yoffset are unsigned integers.
312 * Example: "=80x24+300-49"
313 * The equal sign is optional.
314 * It returns a bitmask that indicates which of the four values
315 * were actually found in the string. For each value found,
316 * the corresponding argument is updated; for each value
317 * not found, the corresponding argument is left unchanged.
320 static int
321 read_integer (register char *string, char **NextString)
323 register int Result = 0;
324 int Sign = 1;
326 if (*string == '+')
327 string++;
328 else if (*string == '-')
330 string++;
331 Sign = -1;
333 for (; (*string >= '0') && (*string <= '9'); string++)
335 Result = (Result * 10) + (*string - '0');
337 *NextString = string;
338 if (Sign >= 0)
339 return (Result);
340 else
341 return (-Result);
345 XParseGeometry (char *string,
346 int *x, int *y,
347 unsigned int *width, unsigned int *height)
349 int mask = NoValue;
350 register char *strind;
351 unsigned int tempWidth, tempHeight;
352 int tempX, tempY;
353 char *nextCharacter;
355 if ((string == NULL) || (*string == '\0')) return (mask);
356 if (*string == '=')
357 string++; /* ignore possible '=' at beg of geometry spec */
359 strind = (char *)string;
360 if (*strind != '+' && *strind != '-' && *strind != 'x')
362 tempWidth = read_integer (strind, &nextCharacter);
363 if (strind == nextCharacter)
364 return (0);
365 strind = nextCharacter;
366 mask |= WidthValue;
369 if (*strind == 'x' || *strind == 'X')
371 strind++;
372 tempHeight = read_integer (strind, &nextCharacter);
373 if (strind == nextCharacter)
374 return (0);
375 strind = nextCharacter;
376 mask |= HeightValue;
379 if ((*strind == '+') || (*strind == '-'))
381 if (*strind == '-')
383 strind++;
384 tempX = -read_integer (strind, &nextCharacter);
385 if (strind == nextCharacter)
386 return (0);
387 strind = nextCharacter;
388 mask |= XNegative;
391 else
393 strind++;
394 tempX = read_integer (strind, &nextCharacter);
395 if (strind == nextCharacter)
396 return (0);
397 strind = nextCharacter;
399 mask |= XValue;
400 if ((*strind == '+') || (*strind == '-'))
402 if (*strind == '-')
404 strind++;
405 tempY = -read_integer (strind, &nextCharacter);
406 if (strind == nextCharacter)
407 return (0);
408 strind = nextCharacter;
409 mask |= YNegative;
411 else
413 strind++;
414 tempY = read_integer (strind, &nextCharacter);
415 if (strind == nextCharacter)
416 return (0);
417 strind = nextCharacter;
419 mask |= YValue;
423 /* If strind isn't at the end of the string then it's an invalid
424 geometry specification. */
426 if (*strind != '\0') return (0);
428 if (mask & XValue)
429 *x = tempX;
430 if (mask & YValue)
431 *y = tempY;
432 if (mask & WidthValue)
433 *width = tempWidth;
434 if (mask & HeightValue)
435 *height = tempHeight;
436 return (mask);
439 /* x_sync is a no-op on W32. */
440 void
441 x_sync (void *f)