Merge from mainline.
[emacs.git] / src / w32xfns.c
blobd77eb6b68eacc9f1d3e6d503b20604fb134df4b6
1 /* Functions taken directly from X sources for use with the Microsoft W32 API.
2 Copyright (C) 1989, 1992, 1993, 1994, 1995, 1999, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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.
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.
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/>. */
20 #include <config.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <setjmp.h>
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"
33 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
34 #define myfree(lp) GlobalFreePtr (lp)
36 CRITICAL_SECTION critsect;
37 extern HANDLE keyboard_handle;
38 HANDLE input_available = NULL;
39 HANDLE interrupt_handle = NULL;
41 void
42 init_crit ()
44 InitializeCriticalSection (&critsect);
46 /* For safety, input_available should only be reset by get_next_msg
47 when the input queue is empty, so make it a manual reset event. */
48 keyboard_handle = input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
50 /* interrupt_handle is signaled when quit (C-g) is detected, so that
51 blocking system calls can be interrupted. We make it a manual
52 reset event, so that if we should ever have multiple threads
53 performing system calls, they will all be interrupted (I'm guessing
54 that would the right response). Note that we use PulseEvent to
55 signal this event, so that it never remains signaled. */
56 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
59 void
60 delete_crit ()
62 DeleteCriticalSection (&critsect);
64 if (input_available)
66 CloseHandle (input_available);
67 input_available = NULL;
69 if (interrupt_handle)
71 CloseHandle (interrupt_handle);
72 interrupt_handle = NULL;
76 void
77 signal_quit ()
79 /* Make sure this event never remains signaled; if the main thread
80 isn't in a blocking call, then this should do nothing. */
81 PulseEvent (interrupt_handle);
84 void
85 select_palette (FRAME_PTR f, HDC hdc)
87 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
89 if (!display_info->has_palette)
90 return;
92 if (display_info->palette == 0)
93 return;
95 if (!NILP (Vw32_enable_palette))
96 f->output_data.w32->old_palette =
97 SelectPalette (hdc, display_info->palette, FALSE);
98 else
99 f->output_data.w32->old_palette = NULL;
101 if (RealizePalette (hdc))
103 Lisp_Object frame, framelist;
104 FOR_EACH_FRAME (framelist, frame)
106 SET_FRAME_GARBAGED (XFRAME (frame));
111 void
112 deselect_palette (FRAME_PTR f, HDC hdc)
114 if (f->output_data.w32->old_palette)
115 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
118 /* Get a DC for frame and select palette for drawing; force an update of
119 all frames if palette's mapping changes. */
121 get_frame_dc (FRAME_PTR f)
123 HDC hdc;
125 if (f->output_method != output_w32)
126 abort ();
128 enter_crit ();
130 hdc = GetDC (f->output_data.w32->window_desc);
132 /* If this gets called during startup before the frame is valid,
133 there is a chance of corrupting random data or crashing. */
134 if (hdc)
135 select_palette (f, hdc);
137 return hdc;
141 release_frame_dc (FRAME_PTR f, HDC hdc)
143 int ret;
145 deselect_palette (f, hdc);
146 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
148 leave_crit ();
150 return ret;
153 typedef struct int_msg
155 W32Msg w32msg;
156 struct int_msg *lpNext;
157 } int_msg;
159 int_msg *lpHead = NULL;
160 int_msg *lpTail = NULL;
161 int nQueue = 0;
163 BOOL
164 get_next_msg (lpmsg, bWait)
165 W32Msg * lpmsg;
166 BOOL bWait;
168 BOOL bRet = FALSE;
170 enter_crit ();
172 /* The while loop takes care of multiple sets */
174 while (!nQueue && bWait)
176 leave_crit ();
177 WaitForSingleObject (input_available, INFINITE);
178 enter_crit ();
181 if (nQueue)
183 bcopy (&(lpHead->w32msg), lpmsg, sizeof (W32Msg));
186 int_msg * lpCur = lpHead;
188 lpHead = lpHead->lpNext;
190 myfree (lpCur);
193 nQueue--;
194 /* Consolidate WM_PAINT messages to optimise redrawing. */
195 if (lpmsg->msg.message == WM_PAINT && nQueue)
197 int_msg * lpCur = lpHead;
198 int_msg * lpPrev = NULL;
199 int_msg * lpNext = NULL;
201 while (lpCur && nQueue)
203 lpNext = lpCur->lpNext;
204 if (lpCur->w32msg.msg.message == WM_PAINT)
206 /* Remove this message from the queue. */
207 if (lpPrev)
208 lpPrev->lpNext = lpNext;
209 else
210 lpHead = lpNext;
212 if (lpCur == lpTail)
213 lpTail = lpPrev;
215 /* Adjust clip rectangle to cover both. */
216 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
217 &(lpCur->w32msg.rect)))
219 SetRectEmpty(&(lpmsg->rect));
222 myfree (lpCur);
224 nQueue--;
226 lpCur = lpNext;
228 else
230 lpPrev = lpCur;
231 lpCur = lpNext;
236 bRet = TRUE;
239 if (nQueue == 0)
240 ResetEvent (input_available);
242 leave_crit ();
244 return (bRet);
247 BOOL
248 post_msg (lpmsg)
249 W32Msg * lpmsg;
251 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
253 if (!lpNew)
254 return (FALSE);
256 bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
257 lpNew->lpNext = NULL;
259 enter_crit ();
261 if (nQueue++)
263 lpTail->lpNext = lpNew;
265 else
267 lpHead = lpNew;
270 lpTail = lpNew;
271 SetEvent (input_available);
273 leave_crit ();
275 return (TRUE);
278 BOOL
279 prepend_msg (W32Msg *lpmsg)
281 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
283 if (!lpNew)
284 return (FALSE);
286 bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
288 enter_crit ();
290 nQueue++;
291 lpNew->lpNext = lpHead;
292 lpHead = lpNew;
294 leave_crit ();
296 return (TRUE);
299 /* Process all messages in the current thread's queue. */
300 void
301 drain_message_queue ()
303 MSG msg;
304 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
306 TranslateMessage (&msg);
307 DispatchMessage (&msg);
313 * XParseGeometry parses strings of the form
314 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
315 * width, height, xoffset, and yoffset are unsigned integers.
316 * Example: "=80x24+300-49"
317 * The equal sign is optional.
318 * It returns a bitmask that indicates which of the four values
319 * were actually found in the string. For each value found,
320 * the corresponding argument is updated; for each value
321 * not found, the corresponding argument is left unchanged.
324 static int
325 read_integer (string, NextString)
326 register char *string;
327 char **NextString;
329 register int Result = 0;
330 int Sign = 1;
332 if (*string == '+')
333 string++;
334 else if (*string == '-')
336 string++;
337 Sign = -1;
339 for (; (*string >= '0') && (*string <= '9'); string++)
341 Result = (Result * 10) + (*string - '0');
343 *NextString = string;
344 if (Sign >= 0)
345 return (Result);
346 else
347 return (-Result);
351 XParseGeometry (string, x, y, width, height)
352 char *string;
353 int *x, *y;
354 unsigned int *width, *height; /* RETURN */
356 int mask = NoValue;
357 register char *strind;
358 unsigned int tempWidth, tempHeight;
359 int tempX, tempY;
360 char *nextCharacter;
362 if ((string == NULL) || (*string == '\0')) return (mask);
363 if (*string == '=')
364 string++; /* ignore possible '=' at beg of geometry spec */
366 strind = (char *)string;
367 if (*strind != '+' && *strind != '-' && *strind != 'x')
369 tempWidth = read_integer (strind, &nextCharacter);
370 if (strind == nextCharacter)
371 return (0);
372 strind = nextCharacter;
373 mask |= WidthValue;
376 if (*strind == 'x' || *strind == 'X')
378 strind++;
379 tempHeight = read_integer (strind, &nextCharacter);
380 if (strind == nextCharacter)
381 return (0);
382 strind = nextCharacter;
383 mask |= HeightValue;
386 if ((*strind == '+') || (*strind == '-'))
388 if (*strind == '-')
390 strind++;
391 tempX = -read_integer (strind, &nextCharacter);
392 if (strind == nextCharacter)
393 return (0);
394 strind = nextCharacter;
395 mask |= XNegative;
398 else
400 strind++;
401 tempX = read_integer (strind, &nextCharacter);
402 if (strind == nextCharacter)
403 return (0);
404 strind = nextCharacter;
406 mask |= XValue;
407 if ((*strind == '+') || (*strind == '-'))
409 if (*strind == '-')
411 strind++;
412 tempY = -read_integer (strind, &nextCharacter);
413 if (strind == nextCharacter)
414 return (0);
415 strind = nextCharacter;
416 mask |= YNegative;
419 else
421 strind++;
422 tempY = read_integer (strind, &nextCharacter);
423 if (strind == nextCharacter)
424 return (0);
425 strind = nextCharacter;
427 mask |= YValue;
431 /* If strind isn't at the end of the string the it's an invalid
432 geometry specification. */
434 if (*strind != '\0') return (0);
436 if (mask & XValue)
437 *x = tempX;
438 if (mask & YValue)
439 *y = tempY;
440 if (mask & WidthValue)
441 *width = tempWidth;
442 if (mask & HeightValue)
443 *height = tempHeight;
444 return (mask);
447 /* x_sync is a no-op on W32. */
448 void
449 x_sync (f)
450 void *f;
454 /* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
455 (do not change this comment) */