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 ()
 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))
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             }
419           else
420             {
421               strind++;
422               tempY = read_integer (strind, &nextCharacter);
423               if (strind == nextCharacter)
424                 return (0);
425               strind = nextCharacter;
426             }
427           mask |= YValue;
428         }
429     }
430 
431   /* If strind isn't at the end of the string the it's an invalid
432      geometry specification. */
433 
434   if (*strind != '\0') return (0);
435 
436   if (mask & XValue)
437     *x = tempX;
438   if (mask & YValue)
439     *y = tempY;
440   if (mask & WidthValue)
441     *width = tempWidth;
442   if (mask & HeightValue)
443     *height = tempHeight;
444   return (mask);
445 }
446 
447 /* x_sync is a no-op on W32.  */
448 void
449 x_sync (f)
450      void *f;
451 {
452 }
453 
454 /* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be
455    (do not change this comment) */