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  Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING.  If not, write to
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22#include <config.h>
23#include <signal.h>
24#include <stdio.h>
25#include "lisp.h"
26#include "keyboard.h"
27#include "frame.h"
28#include "charset.h"
29#include "fontset.h"
30#include "blockinput.h"
31#include "w32term.h"
32#include "windowsx.h"
33
34#define myalloc(cb) GlobalAllocPtr (GPTR, cb)
35#define myfree(lp) GlobalFreePtr (lp)
36
37CRITICAL_SECTION critsect;
38extern HANDLE keyboard_handle;
39HANDLE input_available = NULL;
40HANDLE interrupt_handle = NULL;
41
42void
43init_crit ()
44{
45  InitializeCriticalSection (&critsect);
46
47  /* For safety, input_available should only be reset by get_next_msg
48     when the input queue is empty, so make it a manual reset event. */
49  keyboard_handle = input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
50
51  /* interrupt_handle is signalled when quit (C-g) is detected, so that
52     blocking system calls can be interrupted.  We make it a manual
53     reset event, so that if we should ever have multiple threads
54     performing system calls, they will all be interrupted (I'm guessing
55     that would the right response).  Note that we use PulseEvent to
56     signal this event, so that it never remains signalled.  */
57  interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
58}
59
60void
61delete_crit ()
62{
63  DeleteCriticalSection (&critsect);
64
65  if (input_available)
66    {
67      CloseHandle (input_available);
68      input_available = NULL;
69    }
70  if (interrupt_handle)
71    {
72      CloseHandle (interrupt_handle);
73      interrupt_handle = NULL;
74    }
75}
76
77void
78signal_quit ()
79{
80  /* Make sure this event never remains signalled; if the main thread
81     isn't in a blocking call, then this should do nothing.  */
82  PulseEvent (interrupt_handle);
83}
84
85void
86select_palette (FRAME_PTR f, HDC hdc)
87{
88  struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
89
90  if (!display_info->has_palette)
91    return;
92
93  if (display_info->palette == 0)
94    return;
95
96  if (!NILP (Vw32_enable_palette))
97    f->output_data.w32->old_palette =
98      SelectPalette (hdc, display_info->palette, FALSE);
99  else
100    f->output_data.w32->old_palette = NULL;
101
102  if (RealizePalette (hdc))
103  {
104    Lisp_Object frame, framelist;
105    FOR_EACH_FRAME (framelist, frame)
106    {
107      SET_FRAME_GARBAGED (XFRAME (frame));
108    }
109  }
110}
111
112void
113deselect_palette (FRAME_PTR f, HDC hdc)
114{
115  if (f->output_data.w32->old_palette)
116    SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
117}
118
119/* Get a DC for frame and select palette for drawing; force an update of
120   all frames if palette's mapping changes.  */
121HDC
122get_frame_dc (FRAME_PTR f)
123{
124  HDC hdc;
125
126  if (f->output_method != output_w32)
127    abort ();
128
129  enter_crit ();
130
131  hdc = GetDC (f->output_data.w32->window_desc);
132
133  /* If this gets called during startup before the frame is valid,
134     there is a chance of corrupting random data or crashing. */
135  if (hdc)
136    select_palette (f, hdc);
137
138  return hdc;
139}
140
141int
142release_frame_dc (FRAME_PTR f, HDC hdc)
143{
144  int ret;
145
146  deselect_palette (f, hdc);
147  ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
148
149  leave_crit ();
150
151  return ret;
152}
153
154typedef struct int_msg
155{
156  W32Msg w32msg;
157  struct int_msg *lpNext;
158} int_msg;
159
160int_msg *lpHead = NULL;
161int_msg *lpTail = NULL;
162int nQueue = 0;
163
164BOOL
165get_next_msg (lpmsg, bWait)
166     W32Msg * lpmsg;
167     BOOL bWait;
168{
169  BOOL bRet = FALSE;
170
171  enter_crit ();
172
173  /* The while loop takes care of multiple sets */
174
175  while (!nQueue && bWait)
176    {
177      leave_crit ();
178      WaitForSingleObject (input_available, INFINITE);
179      enter_crit ();
180    }
181
182  if (nQueue)
183    {
184      bcopy (&(lpHead->w32msg), lpmsg, sizeof (W32Msg));
185
186      {
187	int_msg * lpCur = lpHead;
188
189	lpHead = lpHead->lpNext;
190
191	myfree (lpCur);
192      }
193
194      nQueue--;
195
196      bRet = TRUE;
197    }
198
199  if (nQueue == 0)
200    ResetEvent (input_available);
201
202  leave_crit ();
203
204  return (bRet);
205}
206
207BOOL
208post_msg (lpmsg)
209     W32Msg * lpmsg;
210{
211  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
212
213  if (!lpNew)
214    return (FALSE);
215
216  bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
217  lpNew->lpNext = NULL;
218
219  enter_crit ();
220
221  if (nQueue++)
222    {
223      lpTail->lpNext = lpNew;
224    }
225  else
226    {
227      lpHead = lpNew;
228    }
229
230  lpTail = lpNew;
231  SetEvent (input_available);
232
233  leave_crit ();
234
235  return (TRUE);
236}
237
238BOOL
239prepend_msg (W32Msg *lpmsg)
240{
241  int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
242
243  if (!lpNew)
244    return (FALSE);
245
246  bcopy (lpmsg, &(lpNew->w32msg), sizeof (W32Msg));
247
248  enter_crit ();
249
250  nQueue++;
251  lpNew->lpNext = lpHead;
252  lpHead = lpNew;
253
254  leave_crit ();
255
256  return (TRUE);
257}
258
259/* Process all messages in the current thread's queue.  */
260void
261drain_message_queue ()
262{
263  MSG msg;
264  while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
265    {
266      TranslateMessage (&msg);
267      DispatchMessage (&msg);
268    }
269}
270
271
272/*
273 *    XParseGeometry parses strings of the form
274 *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
275 *   width, height, xoffset, and yoffset are unsigned integers.
276 *   Example:  "=80x24+300-49"
277 *   The equal sign is optional.
278 *   It returns a bitmask that indicates which of the four values
279 *   were actually found in the string.  For each value found,
280 *   the corresponding argument is updated;  for each value
281 *   not found, the corresponding argument is left unchanged.
282 */
283
284static int
285read_integer (string, NextString)
286     register char *string;
287     char **NextString;
288{
289  register int Result = 0;
290  int Sign = 1;
291
292  if (*string == '+')
293    string++;
294  else if (*string == '-')
295    {
296      string++;
297      Sign = -1;
298    }
299  for (; (*string >= '0') && (*string <= '9'); string++)
300    {
301      Result = (Result * 10) + (*string - '0');
302    }
303  *NextString = string;
304  if (Sign >= 0)
305    return (Result);
306  else
307    return (-Result);
308}
309
310int
311XParseGeometry (string, x, y, width, height)
312     char *string;
313     int *x, *y;
314     unsigned int *width, *height;    /* RETURN */
315{
316  int mask = NoValue;
317  register char *strind;
318  unsigned int tempWidth, tempHeight;
319  int tempX, tempY;
320  char *nextCharacter;
321
322  if ((string == NULL) || (*string == '\0')) return (mask);
323  if (*string == '=')
324    string++;  /* ignore possible '=' at beg of geometry spec */
325
326  strind = (char *)string;
327  if (*strind != '+' && *strind != '-' && *strind != 'x')
328    {
329      tempWidth = read_integer (strind, &nextCharacter);
330      if (strind == nextCharacter)
331	return (0);
332      strind = nextCharacter;
333      mask |= WidthValue;
334    }
335
336  if (*strind == 'x' || *strind == 'X')
337    {
338      strind++;
339      tempHeight = read_integer (strind, &nextCharacter);
340      if (strind == nextCharacter)
341	return (0);
342      strind = nextCharacter;
343      mask |= HeightValue;
344    }
345
346  if ((*strind == '+') || (*strind == '-'))
347    {
348      if (*strind == '-')
349	{
350	  strind++;
351	  tempX = -read_integer (strind, &nextCharacter);
352	  if (strind == nextCharacter)
353	    return (0);
354	  strind = nextCharacter;
355	  mask |= XNegative;
356
357	}
358      else
359	{
360	  strind++;
361	  tempX = read_integer (strind, &nextCharacter);
362	  if (strind == nextCharacter)
363	    return (0);
364	  strind = nextCharacter;
365	}
366      mask |= XValue;
367      if ((*strind == '+') || (*strind == '-'))
368	{
369	  if (*strind == '-')
370	    {
371	      strind++;
372	      tempY = -read_integer (strind, &nextCharacter);
373	      if (strind == nextCharacter)
374		return (0);
375	      strind = nextCharacter;
376	      mask |= YNegative;
377
378	    }
379	  else
380	    {
381	      strind++;
382	      tempY = read_integer (strind, &nextCharacter);
383	      if (strind == nextCharacter)
384		return (0);
385	      strind = nextCharacter;
386	    }
387	  mask |= YValue;
388	}
389    }
390
391  /* If strind isn't at the end of the string the it's an invalid
392     geometry specification. */
393
394  if (*strind != '\0') return (0);
395
396  if (mask & XValue)
397    *x = tempX;
398  if (mask & YValue)
399    *y = tempY;
400  if (mask & WidthValue)
401    *width = tempWidth;
402  if (mask & HeightValue)
403    *height = tempHeight;
404  return (mask);
405}
406
407/* x_sync is a no-op on W32.  */
408void
409x_sync (f)
410     void *f;
411{
412}
413
414/* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
415   (do not change this comment) */
416