]> code.delx.au - gnu-emacs/blob - src/w32xfns.c
Add 2012 to FSF copyright years for Emacs files (do not merge to trunk)
[gnu-emacs] / 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, 2009, 2010, 2011, 2012 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 <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"
32
33 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
34 #define myfree(lp) GlobalFreePtr (lp)
35
36 CRITICAL_SECTION critsect;
37 extern HANDLE keyboard_handle;
38 HANDLE input_available = NULL;
39 HANDLE interrupt_handle = NULL;
40
41 void
42 init_crit ()
43 {
44 InitializeCriticalSection (&critsect);
45
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);
49
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);
57 }
58
59 void
60 delete_crit ()
61 {
62 DeleteCriticalSection (&critsect);
63
64 if (input_available)
65 {
66 CloseHandle (input_available);
67 input_available = NULL;
68 }
69 if (interrupt_handle)
70 {
71 CloseHandle (interrupt_handle);
72 interrupt_handle = NULL;
73 }
74 }
75
76 void
77 signal_quit ()
78 {
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);
82 }
83
84 void
85 select_palette (FRAME_PTR f, HDC hdc)
86 {
87 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
88
89 if (!display_info->has_palette)
90 return;
91
92 if (display_info->palette == 0)
93 return;
94
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;
100
101 if (RealizePalette (hdc) != GDI_ERROR)
102 {
103 Lisp_Object frame, framelist;
104 FOR_EACH_FRAME (framelist, frame)
105 {
106 SET_FRAME_GARBAGED (XFRAME (frame));
107 }
108 }
109 }
110
111 void
112 deselect_palette (FRAME_PTR f, HDC hdc)
113 {
114 if (f->output_data.w32->old_palette)
115 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
116 }
117
118 /* Get a DC for frame and select palette for drawing; force an update of
119 all frames if palette's mapping changes. */
120 HDC
121 get_frame_dc (FRAME_PTR f)
122 {
123 HDC hdc;
124
125 if (f->output_method != output_w32)
126 abort ();
127
128 enter_crit ();
129
130 hdc = GetDC (f->output_data.w32->window_desc);
131
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);
136
137 return hdc;
138 }
139
140 int
141 release_frame_dc (FRAME_PTR f, HDC hdc)
142 {
143 int ret;
144
145 deselect_palette (f, hdc);
146 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
147
148 leave_crit ();
149
150 return ret;
151 }
152
153 typedef struct int_msg
154 {
155 W32Msg w32msg;
156 struct int_msg *lpNext;
157 } int_msg;
158
159 int_msg *lpHead = NULL;
160 int_msg *lpTail = NULL;
161 int nQueue = 0;
162
163 BOOL
164 get_next_msg (lpmsg, bWait)
165 W32Msg * lpmsg;
166 BOOL bWait;
167 {
168 BOOL bRet = FALSE;
169
170 enter_crit ();
171
172 /* The while loop takes care of multiple sets */
173
174 while (!nQueue && bWait)
175 {
176 leave_crit ();
177 WaitForSingleObject (input_available, INFINITE);
178 enter_crit ();
179 }
180
181 if (nQueue)
182 {
183 bcopy (&(lpHead->w32msg), lpmsg, sizeof (W32Msg));
184
185 {
186 int_msg * lpCur = lpHead;
187
188 lpHead = lpHead->lpNext;
189
190 myfree (lpCur);
191 }
192
193 nQueue--;
194 /* Consolidate WM_PAINT messages to optimise redrawing. */
195 if (lpmsg->msg.message == WM_PAINT && nQueue)
196 {
197 int_msg * lpCur = lpHead;
198 int_msg * lpPrev = NULL;
199 int_msg * lpNext = NULL;
200
201 while (lpCur && nQueue)
202 {
203 lpNext = lpCur->lpNext;
204 if (lpCur->w32msg.msg.message == WM_PAINT)
205 {
206 /* Remove this message from the queue. */
207 if (lpPrev)
208 lpPrev->lpNext = lpNext;
209 else
210 lpHead = lpNext;
211
212 if (lpCur == lpTail)
213 lpTail = lpPrev;
214
215 /* Adjust clip rectangle to cover both. */
216 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
217 &(lpCur->w32msg.rect)))
218 {
219 SetRectEmpty (&(lpmsg->rect));
220 }
221
222 myfree (lpCur);
223
224 nQueue--;
225
226 lpCur = lpNext;
227 }
228 else
229 {
230 lpPrev = lpCur;
231 lpCur = lpNext;
232 }
233 }
234 }
235
236 bRet = TRUE;
237 }
238
239 if (nQueue == 0)
240 ResetEvent (input_available);
241
242 leave_crit ();
243
244 return (bRet);
245 }
246
247 BOOL
248 post_msg (lpmsg)
249 W32Msg * lpmsg;
250 {
251 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
252
253 if (!lpNew)
254 return (FALSE);
255
256 bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
257 lpNew->lpNext = NULL;
258
259 enter_crit ();
260
261 if (nQueue++)
262 {
263 lpTail->lpNext = lpNew;
264 }
265 else
266 {
267 lpHead = lpNew;
268 }
269
270 lpTail = lpNew;
271 SetEvent (input_available);
272
273 leave_crit ();
274
275 return (TRUE);
276 }
277
278 BOOL
279 prepend_msg (W32Msg *lpmsg)
280 {
281 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
282
283 if (!lpNew)
284 return (FALSE);
285
286 bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
287
288 enter_crit ();
289
290 nQueue++;
291 lpNew->lpNext = lpHead;
292 lpHead = lpNew;
293
294 leave_crit ();
295
296 return (TRUE);
297 }
298
299 /* Process all messages in the current thread's queue. */
300 void
301 drain_message_queue ()
302 {
303 MSG msg;
304 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
305 {
306 TranslateMessage (&msg);
307 DispatchMessage (&msg);
308 }
309 }
310
311
312 /*
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.
322 */
323
324 static int
325 read_integer (string, NextString)
326 register char *string;
327 char **NextString;
328 {
329 register int Result = 0;
330 int Sign = 1;
331
332 if (*string == '+')
333 string++;
334 else if (*string == '-')
335 {
336 string++;
337 Sign = -1;
338 }
339 for (; (*string >= '0') && (*string <= '9'); string++)
340 {
341 Result = (Result * 10) + (*string - '0');
342 }
343 *NextString = string;
344 if (Sign >= 0)
345 return (Result);
346 else
347 return (-Result);
348 }
349
350 int
351 XParseGeometry (string, x, y, width, height)
352 char *string;
353 int *x, *y;
354 unsigned int *width, *height; /* RETURN */
355 {
356 int mask = NoValue;
357 register char *strind;
358 unsigned int tempWidth, tempHeight;
359 int tempX, tempY;
360 char *nextCharacter;
361
362 if ((string == NULL) || (*string == '\0')) return (mask);
363 if (*string == '=')
364 string++; /* ignore possible '=' at beg of geometry spec */
365
366 strind = (char *)string;
367 if (*strind != '+' && *strind != '-' && *strind != 'x')
368 {
369 tempWidth = read_integer (strind, &nextCharacter);
370 if (strind == nextCharacter)
371 return (0);
372 strind = nextCharacter;
373 mask |= WidthValue;
374 }
375
376 if (*strind == 'x' || *strind == 'X')
377 {
378 strind++;
379 tempHeight = read_integer (strind, &nextCharacter);
380 if (strind == nextCharacter)
381 return (0);
382 strind = nextCharacter;
383 mask |= HeightValue;
384 }
385
386 if ((*strind == '+') || (*strind == '-'))
387 {
388 if (*strind == '-')
389 {
390 strind++;
391 tempX = -read_integer (strind, &nextCharacter);
392 if (strind == nextCharacter)
393 return (0);
394 strind = nextCharacter;
395 mask |= XNegative;
396
397 }
398 else
399 {
400 strind++;
401 tempX = read_integer (strind, &nextCharacter);
402 if (strind == nextCharacter)
403 return (0);
404 strind = nextCharacter;
405 }
406 mask |= XValue;
407 if ((*strind == '+') || (*strind == '-'))
408 {
409 if (*strind == '-')
410 {
411 strind++;
412 tempY = -read_integer (strind, &nextCharacter);
413 if (strind == nextCharacter)
414 return (0);
415 strind = nextCharacter;
416 mask |= YNegative;
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 then 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) */