Merge from emacs--rel--22
[bpt/emacs.git] / src / w32xfns.c
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 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
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.
11
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.
16
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/>. */
19
20 #include <config.h>
21 #include <signal.h>
22 #include <stdio.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"
31
32 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
33 #define myfree(lp) GlobalFreePtr (lp)
34
35 CRITICAL_SECTION critsect;
36 extern HANDLE keyboard_handle;
37 HANDLE input_available = NULL;
38 HANDLE interrupt_handle = NULL;
39
40 void
41 init_crit ()
42 {
43 InitializeCriticalSection (&critsect);
44
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);
48
49 /* interrupt_handle is signalled 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 signalled. */
55 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
56 }
57
58 void
59 delete_crit ()
60 {
61 DeleteCriticalSection (&critsect);
62
63 if (input_available)
64 {
65 CloseHandle (input_available);
66 input_available = NULL;
67 }
68 if (interrupt_handle)
69 {
70 CloseHandle (interrupt_handle);
71 interrupt_handle = NULL;
72 }
73 }
74
75 void
76 signal_quit ()
77 {
78 /* Make sure this event never remains signalled; if the main thread
79 isn't in a blocking call, then this should do nothing. */
80 PulseEvent (interrupt_handle);
81 }
82
83 void
84 select_palette (FRAME_PTR f, HDC hdc)
85 {
86 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
87
88 if (!display_info->has_palette)
89 return;
90
91 if (display_info->palette == 0)
92 return;
93
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;
99
100 if (RealizePalette (hdc))
101 {
102 Lisp_Object frame, framelist;
103 FOR_EACH_FRAME (framelist, frame)
104 {
105 SET_FRAME_GARBAGED (XFRAME (frame));
106 }
107 }
108 }
109
110 void
111 deselect_palette (FRAME_PTR f, HDC hdc)
112 {
113 if (f->output_data.w32->old_palette)
114 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
115 }
116
117 /* Get a DC for frame and select palette for drawing; force an update of
118 all frames if palette's mapping changes. */
119 HDC
120 get_frame_dc (FRAME_PTR f)
121 {
122 HDC hdc;
123
124 if (f->output_method != output_w32)
125 abort ();
126
127 enter_crit ();
128
129 hdc = GetDC (f->output_data.w32->window_desc);
130
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);
135
136 return hdc;
137 }
138
139 int
140 release_frame_dc (FRAME_PTR f, HDC hdc)
141 {
142 int ret;
143
144 deselect_palette (f, hdc);
145 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
146
147 leave_crit ();
148
149 return ret;
150 }
151
152 typedef struct int_msg
153 {
154 W32Msg w32msg;
155 struct int_msg *lpNext;
156 } int_msg;
157
158 int_msg *lpHead = NULL;
159 int_msg *lpTail = NULL;
160 int nQueue = 0;
161
162 BOOL
163 get_next_msg (lpmsg, bWait)
164 W32Msg * lpmsg;
165 BOOL bWait;
166 {
167 BOOL bRet = FALSE;
168
169 enter_crit ();
170
171 /* The while loop takes care of multiple sets */
172
173 while (!nQueue && bWait)
174 {
175 leave_crit ();
176 WaitForSingleObject (input_available, INFINITE);
177 enter_crit ();
178 }
179
180 if (nQueue)
181 {
182 bcopy (&(lpHead->w32msg), lpmsg, sizeof (W32Msg));
183
184 {
185 int_msg * lpCur = lpHead;
186
187 lpHead = lpHead->lpNext;
188
189 myfree (lpCur);
190 }
191
192 nQueue--;
193 /* Consolidate WM_PAINT messages to optimise redrawing. */
194 if (lpmsg->msg.message == WM_PAINT && nQueue)
195 {
196 int_msg * lpCur = lpHead;
197 int_msg * lpPrev = NULL;
198 int_msg * lpNext = NULL;
199
200 while (lpCur && nQueue)
201 {
202 lpNext = lpCur->lpNext;
203 if (lpCur->w32msg.msg.message == WM_PAINT)
204 {
205 /* Remove this message from the queue. */
206 if (lpPrev)
207 lpPrev->lpNext = lpNext;
208 else
209 lpHead = lpNext;
210
211 if (lpCur == lpTail)
212 lpTail = lpPrev;
213
214 /* Adjust clip rectangle to cover both. */
215 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
216 &(lpCur->w32msg.rect)))
217 {
218 SetRectEmpty(&(lpmsg->rect));
219 }
220
221 myfree (lpCur);
222
223 nQueue--;
224
225 lpCur = lpNext;
226 }
227 else
228 {
229 lpPrev = lpCur;
230 lpCur = lpNext;
231 }
232 }
233 }
234
235 bRet = TRUE;
236 }
237
238 if (nQueue == 0)
239 ResetEvent (input_available);
240
241 leave_crit ();
242
243 return (bRet);
244 }
245
246 BOOL
247 post_msg (lpmsg)
248 W32Msg * lpmsg;
249 {
250 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
251
252 if (!lpNew)
253 return (FALSE);
254
255 bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
256 lpNew->lpNext = NULL;
257
258 enter_crit ();
259
260 if (nQueue++)
261 {
262 lpTail->lpNext = lpNew;
263 }
264 else
265 {
266 lpHead = lpNew;
267 }
268
269 lpTail = lpNew;
270 SetEvent (input_available);
271
272 leave_crit ();
273
274 return (TRUE);
275 }
276
277 BOOL
278 prepend_msg (W32Msg *lpmsg)
279 {
280 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
281
282 if (!lpNew)
283 return (FALSE);
284
285 bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
286
287 enter_crit ();
288
289 nQueue++;
290 lpNew->lpNext = lpHead;
291 lpHead = lpNew;
292
293 leave_crit ();
294
295 return (TRUE);
296 }
297
298 /* Process all messages in the current thread's queue. */
299 void
300 drain_message_queue ()
301 {
302 MSG msg;
303 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
304 {
305 TranslateMessage (&msg);
306 DispatchMessage (&msg);
307 }
308 }
309
310
311 /*
312 * XParseGeometry parses strings of the form
313 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
314 * width, height, xoffset, and yoffset are unsigned integers.
315 * Example: "=80x24+300-49"
316 * The equal sign is optional.
317 * It returns a bitmask that indicates which of the four values
318 * were actually found in the string. For each value found,
319 * the corresponding argument is updated; for each value
320 * not found, the corresponding argument is left unchanged.
321 */
322
323 static int
324 read_integer (string, NextString)
325 register char *string;
326 char **NextString;
327 {
328 register int Result = 0;
329 int Sign = 1;
330
331 if (*string == '+')
332 string++;
333 else if (*string == '-')
334 {
335 string++;
336 Sign = -1;
337 }
338 for (; (*string >= '0') && (*string <= '9'); string++)
339 {
340 Result = (Result * 10) + (*string - '0');
341 }
342 *NextString = string;
343 if (Sign >= 0)
344 return (Result);
345 else
346 return (-Result);
347 }
348
349 int
350 XParseGeometry (string, x, y, width, height)
351 char *string;
352 int *x, *y;
353 unsigned int *width, *height; /* RETURN */
354 {
355 int mask = NoValue;
356 register char *strind;
357 unsigned int tempWidth, tempHeight;
358 int tempX, tempY;
359 char *nextCharacter;
360
361 if ((string == NULL) || (*string == '\0')) return (mask);
362 if (*string == '=')
363 string++; /* ignore possible '=' at beg of geometry spec */
364
365 strind = (char *)string;
366 if (*strind != '+' && *strind != '-' && *strind != 'x')
367 {
368 tempWidth = read_integer (strind, &nextCharacter);
369 if (strind == nextCharacter)
370 return (0);
371 strind = nextCharacter;
372 mask |= WidthValue;
373 }
374
375 if (*strind == 'x' || *strind == 'X')
376 {
377 strind++;
378 tempHeight = read_integer (strind, &nextCharacter);
379 if (strind == nextCharacter)
380 return (0);
381 strind = nextCharacter;
382 mask |= HeightValue;
383 }
384
385 if ((*strind == '+') || (*strind == '-'))
386 {
387 if (*strind == '-')
388 {
389 strind++;
390 tempX = -read_integer (strind, &nextCharacter);
391 if (strind == nextCharacter)
392 return (0);
393 strind = nextCharacter;
394 mask |= XNegative;
395
396 }
397 else
398 {
399 strind++;
400 tempX = read_integer (strind, &nextCharacter);
401 if (strind == nextCharacter)
402 return (0);
403 strind = nextCharacter;
404 }
405 mask |= XValue;
406 if ((*strind == '+') || (*strind == '-'))
407 {
408 if (*strind == '-')
409 {
410 strind++;
411 tempY = -read_integer (strind, &nextCharacter);
412 if (strind == nextCharacter)
413 return (0);
414 strind = nextCharacter;
415 mask |= YNegative;
416
417 }
418 else
419 {
420 strind++;
421 tempY = read_integer (strind, &nextCharacter);
422 if (strind == nextCharacter)
423 return (0);
424 strind = nextCharacter;
425 }
426 mask |= YValue;
427 }
428 }
429
430 /* If strind isn't at the end of the string the it's an invalid
431 geometry specification. */
432
433 if (*strind != '\0') return (0);
434
435 if (mask & XValue)
436 *x = tempX;
437 if (mask & YValue)
438 *y = tempY;
439 if (mask & WidthValue)
440 *width = tempWidth;
441 if (mask & HeightValue)
442 *height = tempHeight;
443 return (mask);
444 }
445
446 /* x_sync is a no-op on W32. */
447 void
448 x_sync (f)
449 void *f;
450 {
451 }
452
453 /* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
454 (do not change this comment) */