Tweak previous change.
[emacs.git] / src / w32xfns.c
blob07f754778638e4e1976be5e360ca261658554e6a
1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2013 Free Software
3 Foundation, Inc.
5 This file is part of GNU Emacs.
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.
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.
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/>. */
20 #include <config.h>
21 #include <signal.h>
22 #include <stdio.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"
33 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
34 #define myfree(lp) GlobalFreePtr (lp)
36 CRITICAL_SECTION critsect;
38 #ifdef WINDOWSNT
39 extern HANDLE keyboard_handle;
40 #endif /* WINDOWSNT */
42 HANDLE input_available = NULL;
43 HANDLE interrupt_handle = NULL;
45 void
46 init_crit (void)
48 InitializeCriticalSection (&critsect);
50 /* For safety, input_available should only be reset by get_next_msg
51 when the input queue is empty, so make it a manual reset event. */
52 input_available = CreateEvent (NULL, TRUE, FALSE, NULL);
54 #ifdef WINDOWSNT
55 keyboard_handle = input_available;
56 #endif /* WINDOWSNT */
58 /* interrupt_handle is signaled when quit (C-g) is detected, so that
59 blocking system calls can be interrupted. We make it a manual
60 reset event, so that if we should ever have multiple threads
61 performing system calls, they will all be interrupted (I'm guessing
62 that would the right response). Note that we use PulseEvent to
63 signal this event, so that it never remains signaled. */
64 interrupt_handle = CreateEvent (NULL, TRUE, FALSE, NULL);
67 void
68 delete_crit (void)
70 DeleteCriticalSection (&critsect);
72 if (input_available)
74 CloseHandle (input_available);
75 input_available = NULL;
77 if (interrupt_handle)
79 CloseHandle (interrupt_handle);
80 interrupt_handle = NULL;
84 void
85 signal_quit (void)
87 /* Make sure this event never remains signaled; if the main thread
88 isn't in a blocking call, then this should do nothing. */
89 PulseEvent (interrupt_handle);
92 void
93 select_palette (struct frame *f, HDC hdc)
95 struct w32_display_info *display_info = FRAME_DISPLAY_INFO (f);
97 if (!display_info->has_palette)
98 return;
100 if (display_info->palette == 0)
101 return;
103 if (!NILP (Vw32_enable_palette))
104 f->output_data.w32->old_palette =
105 SelectPalette (hdc, display_info->palette, FALSE);
106 else
107 f->output_data.w32->old_palette = NULL;
109 if (RealizePalette (hdc) != GDI_ERROR)
111 Lisp_Object frame, framelist;
112 FOR_EACH_FRAME (framelist, frame)
114 SET_FRAME_GARBAGED (XFRAME (frame));
119 void
120 deselect_palette (struct frame *f, HDC hdc)
122 if (f->output_data.w32->old_palette)
123 SelectPalette (hdc, f->output_data.w32->old_palette, FALSE);
126 /* Get a DC for frame and select palette for drawing; force an update of
127 all frames if palette's mapping changes. */
129 get_frame_dc (struct frame *f)
131 HDC hdc;
133 if (f->output_method != output_w32)
134 emacs_abort ();
136 enter_crit ();
138 hdc = GetDC (f->output_data.w32->window_desc);
140 /* If this gets called during startup before the frame is valid,
141 there is a chance of corrupting random data or crashing. */
142 if (hdc)
143 select_palette (f, hdc);
145 return hdc;
149 release_frame_dc (struct frame *f, HDC hdc)
151 int ret;
153 deselect_palette (f, hdc);
154 ret = ReleaseDC (f->output_data.w32->window_desc, hdc);
156 leave_crit ();
158 return ret;
161 typedef struct int_msg
163 W32Msg w32msg;
164 struct int_msg *lpNext;
165 } int_msg;
167 int_msg *lpHead = NULL;
168 int_msg *lpTail = NULL;
169 int nQueue = 0;
171 BOOL
172 get_next_msg (W32Msg * lpmsg, BOOL bWait)
174 BOOL bRet = FALSE;
176 enter_crit ();
178 /* The while loop takes care of multiple sets */
180 while (!nQueue && bWait)
182 leave_crit ();
183 WaitForSingleObject (input_available, INFINITE);
184 enter_crit ();
187 if (nQueue)
189 memcpy (lpmsg, &lpHead->w32msg, sizeof (W32Msg));
192 int_msg * lpCur = lpHead;
194 lpHead = lpHead->lpNext;
196 myfree (lpCur);
199 nQueue--;
200 /* Consolidate WM_PAINT messages to optimize redrawing. */
201 if (lpmsg->msg.message == WM_PAINT && nQueue)
203 int_msg * lpCur = lpHead;
204 int_msg * lpPrev = NULL;
205 int_msg * lpNext = NULL;
207 while (lpCur && nQueue)
209 lpNext = lpCur->lpNext;
210 if (lpCur->w32msg.msg.message == WM_PAINT)
212 /* Remove this message from the queue. */
213 if (lpPrev)
214 lpPrev->lpNext = lpNext;
215 else
216 lpHead = lpNext;
218 if (lpCur == lpTail)
219 lpTail = lpPrev;
221 /* Adjust clip rectangle to cover both. */
222 if (!UnionRect (&(lpmsg->rect), &(lpmsg->rect),
223 &(lpCur->w32msg.rect)))
225 SetRectEmpty (&(lpmsg->rect));
228 myfree (lpCur);
230 nQueue--;
232 lpCur = lpNext;
234 else
236 lpPrev = lpCur;
237 lpCur = lpNext;
242 bRet = TRUE;
245 if (nQueue == 0)
246 ResetEvent (input_available);
248 leave_crit ();
250 return (bRet);
253 extern char * w32_strerror (int error_no);
255 /* Tell the main thread that we have input available; if the main
256 thread is blocked in select(), we wake it up here. */
257 static void
258 notify_msg_ready (void)
260 SetEvent (input_available);
262 #ifdef CYGWIN
263 /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
264 among other files. */
265 (void) PostThreadMessage (dwMainThreadId, WM_EMACS_INPUT_READY, 0, 0);
266 #endif /* CYGWIN */
269 BOOL
270 post_msg (W32Msg * lpmsg)
272 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
274 if (!lpNew)
275 return (FALSE);
277 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
278 lpNew->lpNext = NULL;
280 enter_crit ();
282 if (nQueue++)
284 lpTail->lpNext = lpNew;
286 else
288 lpHead = lpNew;
291 lpTail = lpNew;
292 notify_msg_ready ();
293 leave_crit ();
295 return (TRUE);
298 BOOL
299 prepend_msg (W32Msg *lpmsg)
301 int_msg * lpNew = (int_msg *) myalloc (sizeof (int_msg));
303 if (!lpNew)
304 return (FALSE);
306 memcpy (&lpNew->w32msg, lpmsg, sizeof (W32Msg));
308 enter_crit ();
310 nQueue++;
311 lpNew->lpNext = lpHead;
312 lpHead = lpNew;
313 notify_msg_ready ();
314 leave_crit ();
316 return (TRUE);
319 /* Process all messages in the current thread's queue. Value is 1 if
320 one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */
322 drain_message_queue (void)
324 MSG msg;
325 int retval = 0;
327 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
329 if (msg.message == WM_EMACS_FILENOTIFY)
330 retval = 1;
331 TranslateMessage (&msg);
332 DispatchMessage (&msg);
334 return retval;