Replace bcopy, bzero, bcmp by memcpy, memmove, memset, memcmp
[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, 2009, 2010 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 (void)
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 (void)
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 (void)
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))
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 (W32Msg * lpmsg, BOOL bWait)
165 {
166 BOOL bRet = FALSE;
167
168 enter_crit ();
169
170 /* The while loop takes care of multiple sets */
171
172 while (!nQueue && bWait)
173 {
174 leave_crit ();
175 WaitForSingleObject (input_available, INFINITE);
176 enter_crit ();
177 }
178
179 if (nQueue)
180 {
181 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
182
183 {
184 int_msg * lpCur = lpHead;
185
186 lpHead = lpHead->lpNext;
187
188 myfree (lpCur);
189 }
190
191 nQueue--;
192 /* Consolidate WM_PAINT messages to optimise redrawing. */
193 if (lpmsg->msg.message == WM_PAINT && nQueue)
194 {
195 int_msg * lpCur = lpHead;
196 int_msg * lpPrev = NULL;
197 int_msg * lpNext = NULL;
198
199 while (lpCur && nQueue)
200 {
201 lpNext = lpCur->lpNext;
202 if (lpCur->w32msg.msg.message == WM_PAINT)
203 {
204 /* Remove this message from the queue. */
205 if (lpPrev)
206 lpPrev->lpNext = lpNext;
207 else
208 lpHead = lpNext;
209
210 if (lpCur == lpTail)
211 lpTail = lpPrev;
212
213 /* Adjust clip rectangle to cover both. */
214 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
215 &(lpCur->w32msg.rect)))
216 {
217 SetRectEmpty (&(lpmsg->rect));
218 }
219
220 myfree (lpCur);
221
222 nQueue--;
223
224 lpCur = lpNext;
225 }
226 else
227 {
228 lpPrev = lpCur;
229 lpCur = lpNext;
230 }
231 }
232 }
233
234 bRet = TRUE;
235 }
236
237 if (nQueue == 0)
238 ResetEvent (input_available);
239
240 leave_crit ();
241
242 return (bRet);
243 }
244
245 BOOL
246 post_msg (W32Msg * lpmsg)
247 {
248 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
249
250 if (!lpNew)
251 return (FALSE);
252
253 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
254 lpNew->lpNext = NULL;
255
256 enter_crit ();
257
258 if (nQueue++)
259 {
260 lpTail->lpNext = lpNew;
261 }
262 else
263 {
264 lpHead = lpNew;
265 }
266
267 lpTail = lpNew;
268 SetEvent (input_available);
269
270 leave_crit ();
271
272 return (TRUE);
273 }
274
275 BOOL
276 prepend_msg (W32Msg *lpmsg)
277 {
278 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
279
280 if (!lpNew)
281 return (FALSE);
282
283 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
284
285 enter_crit ();
286
287 nQueue++;
288 lpNew->lpNext = lpHead;
289 lpHead = lpNew;
290
291 leave_crit ();
292
293 return (TRUE);
294 }
295
296 /* Process all messages in the current thread's queue. */
297 void
298 drain_message_queue (void)
299 {
300 MSG msg;
301 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
302 {
303 TranslateMessage (&msg);
304 DispatchMessage (&msg);
305 }
306 }
307
308
309 /*
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.
319 */
320
321 static int
322 read_integer (register char *string, char **NextString)
323 {
324 register int Result = 0;
325 int Sign = 1;
326
327 if (*string == '+')
328 string++;
329 else if (*string == '-')
330 {
331 string++;
332 Sign = -1;
333 }
334 for (; (*string >= '0') && (*string <= '9'); string++)
335 {
336 Result = (Result * 10) + (*string - '0');
337 }
338 *NextString = string;
339 if (Sign >= 0)
340 return (Result);
341 else
342 return (-Result);
343 }
344
345 int
346 XParseGeometry (char *string,
347 int *x, int *y,
348 unsigned int *width, unsigned int *height)
349 {
350 int mask = NoValue;
351 register char *strind;
352 unsigned int tempWidth, tempHeight;
353 int tempX, tempY;
354 char *nextCharacter;
355
356 if ((string == NULL) || (*string == '\0')) return (mask);
357 if (*string == '=')
358 string++; /* ignore possible '=' at beg of geometry spec */
359
360 strind = (char *)string;
361 if (*strind != '+' && *strind != '-' && *strind != 'x')
362 {
363 tempWidth = read_integer (strind, &nextCharacter);
364 if (strind == nextCharacter)
365 return (0);
366 strind = nextCharacter;
367 mask |= WidthValue;
368 }
369
370 if (*strind == 'x' || *strind == 'X')
371 {
372 strind++;
373 tempHeight = read_integer (strind, &nextCharacter);
374 if (strind == nextCharacter)
375 return (0);
376 strind = nextCharacter;
377 mask |= HeightValue;
378 }
379
380 if ((*strind == '+') || (*strind == '-'))
381 {
382 if (*strind == '-')
383 {
384 strind++;
385 tempX = -read_integer (strind, &nextCharacter);
386 if (strind == nextCharacter)
387 return (0);
388 strind = nextCharacter;
389 mask |= XNegative;
390
391 }
392 else
393 {
394 strind++;
395 tempX = read_integer (strind, &nextCharacter);
396 if (strind == nextCharacter)
397 return (0);
398 strind = nextCharacter;
399 }
400 mask |= XValue;
401 if ((*strind == '+') || (*strind == '-'))
402 {
403 if (*strind == '-')
404 {
405 strind++;
406 tempY = -read_integer (strind, &nextCharacter);
407 if (strind == nextCharacter)
408 return (0);
409 strind = nextCharacter;
410 mask |= YNegative;
411
412 }
413 else
414 {
415 strind++;
416 tempY = read_integer (strind, &nextCharacter);
417 if (strind == nextCharacter)
418 return (0);
419 strind = nextCharacter;
420 }
421 mask |= YValue;
422 }
423 }
424
425 /* If strind isn't at the end of the string the it's an invalid
426 geometry specification. */
427
428 if (*strind != '\0') return (0);
429
430 if (mask & XValue)
431 *x = tempX;
432 if (mask & YValue)
433 *y = tempY;
434 if (mask & WidthValue)
435 *width = tempWidth;
436 if (mask & HeightValue)
437 *height = tempHeight;
438 return (mask);
439 }
440
441 /* x_sync is a no-op on W32. */
442 void
443 x_sync (void *f)
444 {
445 }
446
447 /* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
448 (do not change this comment) */