More small cl.texi updates
[emacs.git] / src / w32xfns.c
blobcb452571665e765a1b302d2bd58bf269348708d3
1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19 #include <config.h>
20 #include <signal.h>
21 #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"
32 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
33 #define myfree(lp) GlobalFreePtr (lp)
35 CRITICAL_SECTION critsect;
37 #ifdef WINDOWSNT
38 extern HANDLE keyboard_handle;
39 #endif /* WINDOWSNT */
41 HANDLE input_available = NULL;
42 HANDLE interrupt_handle = NULL;
44 void
45 init_crit (void)
47 InitializeCriticalSection (&critsect);
49 /* For safety, input_available should only be reset by get_next_msg
50 when the input queue is empty, so make it a manual reset event. */
51 input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
53 #ifdef WINDOWSNT
54 keyboard_handle = input_available;
55 #endif /* WINDOWSNT */
57 /* interrupt_handle is signaled when quit (C-g) is detected, so that
58 blocking system calls can be interrupted. We make it a manual
59 reset event, so that if we should ever have multiple threads
60 performing system calls, they will all be interrupted (I'm guessing
61 that would the right response). Note that we use PulseEvent to
62 signal this event, so that it never remains signaled. */
63 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
66 void
67 delete_crit (void)
69 DeleteCriticalSection (&critsect);
71 if (input_available)
73 CloseHandle (input_available);
74 input_available = NULL;
76 if (interrupt_handle)
78 CloseHandle (interrupt_handle);
79 interrupt_handle = NULL;
83 void
84 signal_quit (void)
86 /* Make sure this event never remains signaled; if the main thread
87 isn't in a blocking call, then this should do nothing. */
88 PulseEvent (interrupt_handle);
91 void
92 select_palette (FRAME_PTR f, HDC hdc)
94 struct w32_display_info *display_info = FRAME_W32_DISPLAY_INFO (f);
96 if (!display_info->has_palette)
97 return;
99 if (display_info->palette == 0)
100 return;
102 if (!NILP (Vw32_enable_palette))
103 f->output_data.w32->old_palette =
104 SelectPalette (hdc, display_info->palette, FALSE);
105 else
106 f->output_data.w32->old_palette = NULL;
108 if (RealizePalette (hdc) != GDI_ERROR)
110 Lisp_Object frame, framelist;
111 FOR_EACH_FRAME (framelist, frame)
113 SET_FRAME_GARBAGED (XFRAME (frame));
118 void
119 deselect_palette (FRAME_PTR f, HDC hdc)
121 if (f->output_data.w32->old_palette)
122 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
125 /* Get a DC for frame and select palette for drawing; force an update of
126 all frames if palette's mapping changes. */
128 get_frame_dc (FRAME_PTR f)
130 HDC hdc;
132 if (f->output_method != output_w32)
133 emacs_abort ();
135 enter_crit ();
137 hdc = GetDC (f->output_data.w32->window_desc);
139 /* If this gets called during startup before the frame is valid,
140 there is a chance of corrupting random data or crashing. */
141 if (hdc)
142 select_palette (f, hdc);
144 return hdc;
148 release_frame_dc (FRAME_PTR f, HDC hdc)
150 int ret;
152 deselect_palette (f, hdc);
153 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
155 leave_crit ();
157 return ret;
160 typedef struct int_msg
162 W32Msg w32msg;
163 struct int_msg *lpNext;
164 } int_msg;
166 int_msg *lpHead = NULL;
167 int_msg *lpTail = NULL;
168 int nQueue = 0;
170 BOOL
171 get_next_msg (W32Msg * lpmsg, BOOL bWait)
173 BOOL bRet = FALSE;
175 enter_crit ();
177 /* The while loop takes care of multiple sets */
179 while (!nQueue && bWait)
181 leave_crit ();
182 WaitForSingleObject (input_available, INFINITE);
183 enter_crit ();
186 if (nQueue)
188 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
191 int_msg * lpCur = lpHead;
193 lpHead = lpHead->lpNext;
195 myfree (lpCur);
198 nQueue--;
199 /* Consolidate WM_PAINT messages to optimize redrawing. */
200 if (lpmsg->msg.message == WM_PAINT && nQueue)
202 int_msg * lpCur = lpHead;
203 int_msg * lpPrev = NULL;
204 int_msg * lpNext = NULL;
206 while (lpCur && nQueue)
208 lpNext = lpCur->lpNext;
209 if (lpCur->w32msg.msg.message == WM_PAINT)
211 /* Remove this message from the queue. */
212 if (lpPrev)
213 lpPrev->lpNext = lpNext;
214 else
215 lpHead = lpNext;
217 if (lpCur == lpTail)
218 lpTail = lpPrev;
220 /* Adjust clip rectangle to cover both. */
221 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
222 &(lpCur->w32msg.rect)))
224 SetRectEmpty (&(lpmsg->rect));
227 myfree (lpCur);
229 nQueue--;
231 lpCur = lpNext;
233 else
235 lpPrev = lpCur;
236 lpCur = lpNext;
241 bRet = TRUE;
244 if (nQueue == 0)
245 ResetEvent (input_available);
247 leave_crit ();
249 return (bRet);
252 extern char * w32_strerror (int error_no);
254 /* Tell the main thread that we have input available; if the main
255 thread is blocked in select(), we wake it up here. */
256 static void
257 notify_msg_ready (void)
259 SetEvent (input_available);
261 #ifdef CYGWIN
262 /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
263 among other files. */
264 (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0);
265 #endif /* CYGWIN */
268 BOOL
269 post_msg (W32Msg * lpmsg)
271 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
273 if (!lpNew)
274 return (FALSE);
276 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
277 lpNew->lpNext = NULL;
279 enter_crit ();
281 if (nQueue++)
283 lpTail->lpNext = lpNew;
285 else
287 lpHead = lpNew;
290 lpTail = lpNew;
291 notify_msg_ready ();
292 leave_crit ();
294 return (TRUE);
297 BOOL
298 prepend_msg (W32Msg *lpmsg)
300 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
302 if (!lpNew)
303 return (FALSE);
305 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
307 enter_crit ();
309 nQueue++;
310 lpNew->lpNext = lpHead;
311 lpHead = lpNew;
312 notify_msg_ready ();
313 leave_crit ();
315 return (TRUE);
318 /* Process all messages in the current thread's queue. */
319 void
320 drain_message_queue (void)
322 MSG msg;
323 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
325 TranslateMessage (&msg);
326 DispatchMessage (&msg);
330 /* x_sync is a no-op on W32. */
331 void
332 x_sync (struct frame *f)