Merge changes made in Gnus trunk.
[emacs.git] / src / w32xfns.c
blob4cbd812ec0f239cb7b9637814aaa8528a2e82946
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 (void)
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 (void)
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 (void)
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 (W32Msg * lpmsg, BOOL bWait)
166 BOOL bRet = FALSE;
168 enter_crit ();
170 /* The while loop takes care of multiple sets */
172 while (!nQueue && bWait)
174 leave_crit ();
175 WaitForSingleObject (input_available, INFINITE);
176 enter_crit ();
179 if (nQueue)
181 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
184 int_msg * lpCur = lpHead;
186 lpHead = lpHead->lpNext;
188 myfree (lpCur);
191 nQueue--;
192 /* Consolidate WM_PAINT messages to optimise redrawing. */
193 if (lpmsg->msg.message == WM_PAINT && nQueue)
195 int_msg * lpCur = lpHead;
196 int_msg * lpPrev = NULL;
197 int_msg * lpNext = NULL;
199 while (lpCur && nQueue)
201 lpNext = lpCur->lpNext;
202 if (lpCur->w32msg.msg.message == WM_PAINT)
204 /* Remove this message from the queue. */
205 if (lpPrev)
206 lpPrev->lpNext = lpNext;
207 else
208 lpHead = lpNext;
210 if (lpCur == lpTail)
211 lpTail = lpPrev;
213 /* Adjust clip rectangle to cover both. */
214 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
215 &(lpCur->w32msg.rect)))
217 SetRectEmpty (&(lpmsg->rect));
220 myfree (lpCur);
222 nQueue--;
224 lpCur = lpNext;
226 else
228 lpPrev = lpCur;
229 lpCur = lpNext;
234 bRet = TRUE;
237 if (nQueue == 0)
238 ResetEvent (input_available);
240 leave_crit ();
242 return (bRet);
245 BOOL
246 post_msg (W32Msg * lpmsg)
248 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
250 if (!lpNew)
251 return (FALSE);
253 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
254 lpNew->lpNext = NULL;
256 enter_crit ();
258 if (nQueue++)
260 lpTail->lpNext = lpNew;
262 else
264 lpHead = lpNew;
267 lpTail = lpNew;
268 SetEvent (input_available);
270 leave_crit ();
272 return (TRUE);
275 BOOL
276 prepend_msg (W32Msg *lpmsg)
278 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
280 if (!lpNew)
281 return (FALSE);
283 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
285 enter_crit ();
287 nQueue++;
288 lpNew->lpNext = lpHead;
289 lpHead = lpNew;
291 leave_crit ();
293 return (TRUE);
296 /* Process all messages in the current thread's queue. */
297 void
298 drain_message_queue (void)
300 MSG msg;
301 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
303 TranslateMessage (&msg);
304 DispatchMessage (&msg);
310 * XParseGeometry parses strings of the form
311 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
312 * width, height, xoffset, and yoffset are unsigned integers.
313 * Example: "=80x24+300-49"
314 * The equal sign is optional.
315 * It returns a bitmask that indicates which of the four values
316 * were actually found in the string. For each value found,
317 * the corresponding argument is updated; for each value
318 * not found, the corresponding argument is left unchanged.
321 static int
322 read_integer (register char *string, char **NextString)
324 register int Result = 0;
325 int Sign = 1;
327 if (*string == '+')
328 string++;
329 else if (*string == '-')
331 string++;
332 Sign = -1;
334 for (; (*string >= '0') && (*string <= '9'); string++)
336 Result = (Result * 10) + (*string - '0');
338 *NextString = string;
339 if (Sign >= 0)
340 return (Result);
341 else
342 return (-Result);
346 XParseGeometry (char *string,
347 int *x, int *y,
348 unsigned int *width, unsigned int *height)
350 int mask = NoValue;
351 register char *strind;
352 unsigned int tempWidth, tempHeight;
353 int tempX, tempY;
354 char *nextCharacter;
356 if ((string == NULL) || (*string == '\0')) return (mask);
357 if (*string == '=')
358 string++; /* ignore possible '=' at beg of geometry spec */
360 strind = (char *)string;
361 if (*strind != '+' && *strind != '-' && *strind != 'x')
363 tempWidth = read_integer (strind, &nextCharacter);
364 if (strind == nextCharacter)
365 return (0);
366 strind = nextCharacter;
367 mask |= WidthValue;
370 if (*strind == 'x' || *strind == 'X')
372 strind++;
373 tempHeight = read_integer (strind, &nextCharacter);
374 if (strind == nextCharacter)
375 return (0);
376 strind = nextCharacter;
377 mask |= HeightValue;
380 if ((*strind == '+') || (*strind == '-'))
382 if (*strind == '-')
384 strind++;
385 tempX = -read_integer (strind, &nextCharacter);
386 if (strind == nextCharacter)
387 return (0);
388 strind = nextCharacter;
389 mask |= XNegative;
392 else
394 strind++;
395 tempX = read_integer (strind, &nextCharacter);
396 if (strind == nextCharacter)
397 return (0);
398 strind = nextCharacter;
400 mask |= XValue;
401 if ((*strind == '+') || (*strind == '-'))
403 if (*strind == '-')
405 strind++;
406 tempY = -read_integer (strind, &nextCharacter);
407 if (strind == nextCharacter)
408 return (0);
409 strind = nextCharacter;
410 mask |= YNegative;
412 else
414 strind++;
415 tempY = read_integer (strind, &nextCharacter);
416 if (strind == nextCharacter)
417 return (0);
418 strind = nextCharacter;
420 mask |= YValue;
424 /* If strind isn't at the end of the string then it's an invalid
425 geometry specification. */
427 if (*strind != '\0') return (0);
429 if (mask & XValue)
430 *x = tempX;
431 if (mask & YValue)
432 *y = tempY;
433 if (mask & WidthValue)
434 *width = tempWidth;
435 if (mask & HeightValue)
436 *height = tempHeight;
437 return (mask);
440 /* x_sync is a no-op on W32. */
441 void
442 x_sync (void *f)
446 /* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
447 (do not change this comment) */