1 /* Functions taken directly from X sources for use with the Microsoft Windows API.
2 Copyright (C) 1989, 1992-1995, 1999, 2001-2018 Free Software
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 (at
10 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 <https://www.gnu.org/licenses/>. */
30 #define myalloc(cb) GlobalAllocPtr (GPTR, cb)
31 #define myfree(lp) GlobalFreePtr (lp)
33 CRITICAL_SECTION critsect
;
36 extern HANDLE keyboard_handle
;
37 #endif /* WINDOWSNT */
39 HANDLE input_available
= NULL
;
40 HANDLE interrupt_handle
= NULL
;
45 InitializeCriticalSection (&critsect
);
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 input_available
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
52 /* Initialize the linked list of notifications sets that will be
53 used to communicate between the watching worker threads and the
55 notifications_set_head
= malloc (sizeof(struct notifications_set
));
56 if (notifications_set_head
)
58 memset (notifications_set_head
, 0, sizeof(struct notifications_set
));
59 notifications_set_head
->next
60 = notifications_set_head
->prev
= notifications_set_head
;
63 DebPrint(("Out of memory: can't initialize notifications sets."));
67 keyboard_handle
= input_available
;
68 #endif /* WINDOWSNT */
70 /* interrupt_handle is signaled when quit (C-g) is detected, so that
71 blocking system calls can be interrupted. We make it a manual
72 reset event, so that if we should ever have multiple threads
73 performing system calls, they will all be interrupted (I'm guessing
74 that would the right response). Note that we use PulseEvent to
75 signal this event, so that it never remains signaled. */
76 interrupt_handle
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
82 DeleteCriticalSection (&critsect
);
86 CloseHandle (input_available
);
87 input_available
= NULL
;
91 CloseHandle (interrupt_handle
);
92 interrupt_handle
= NULL
;
96 if (notifications_set_head
)
98 /* Free any remaining notifications set that could be left over. */
99 while (notifications_set_head
->next
!= notifications_set_head
)
101 struct notifications_set
*ns
= notifications_set_head
->next
;
102 notifications_set_head
->next
= ns
->next
;
103 ns
->next
->prev
= notifications_set_head
;
104 if (ns
->notifications
)
105 free (ns
->notifications
);
109 free (notifications_set_head
);
116 /* Make sure this event never remains signaled; if the main thread
117 isn't in a blocking call, then this should do nothing. */
118 PulseEvent (interrupt_handle
);
122 select_palette (struct frame
*f
, HDC hdc
)
124 struct w32_display_info
*display_info
= FRAME_DISPLAY_INFO (f
);
126 if (!display_info
->has_palette
)
129 if (display_info
->palette
== 0)
132 if (!NILP (Vw32_enable_palette
))
133 f
->output_data
.w32
->old_palette
=
134 SelectPalette (hdc
, display_info
->palette
, FALSE
);
136 f
->output_data
.w32
->old_palette
= NULL
;
138 if (RealizePalette (hdc
) != GDI_ERROR
)
140 Lisp_Object frame
, framelist
;
141 FOR_EACH_FRAME (framelist
, frame
)
143 SET_FRAME_GARBAGED (XFRAME (frame
));
149 deselect_palette (struct frame
*f
, HDC hdc
)
151 if (f
->output_data
.w32
->old_palette
)
152 SelectPalette (hdc
, f
->output_data
.w32
->old_palette
, FALSE
);
155 /* Get a DC for frame and select palette for drawing; force an update of
156 all frames if palette's mapping changes. */
158 get_frame_dc (struct frame
*f
)
162 if (f
->output_method
!= output_w32
)
167 hdc
= GetDC (f
->output_data
.w32
->window_desc
);
169 /* If this gets called during startup before the frame is valid,
170 there is a chance of corrupting random data or crashing. */
172 select_palette (f
, hdc
);
178 release_frame_dc (struct frame
*f
, HDC hdc
)
182 deselect_palette (f
, hdc
);
183 ret
= ReleaseDC (f
->output_data
.w32
->window_desc
, hdc
);
190 typedef struct int_msg
193 struct int_msg
*lpNext
;
196 int_msg
*lpHead
= NULL
;
197 int_msg
*lpTail
= NULL
;
201 get_next_msg (W32Msg
* lpmsg
, BOOL bWait
)
207 /* The while loop takes care of multiple sets */
209 while (!nQueue
&& bWait
)
212 WaitForSingleObject (input_available
, INFINITE
);
218 memcpy (lpmsg
, &lpHead
->w32msg
, sizeof (W32Msg
));
221 int_msg
* lpCur
= lpHead
;
223 lpHead
= lpHead
->lpNext
;
229 /* Consolidate WM_PAINT messages to optimize redrawing. */
230 if (lpmsg
->msg
.message
== WM_PAINT
&& nQueue
)
232 int_msg
* lpCur
= lpHead
;
233 int_msg
* lpPrev
= NULL
;
234 int_msg
* lpNext
= NULL
;
236 while (lpCur
&& nQueue
)
238 lpNext
= lpCur
->lpNext
;
239 if (lpCur
->w32msg
.msg
.message
== WM_PAINT
)
241 /* Remove this message from the queue. */
243 lpPrev
->lpNext
= lpNext
;
250 /* Adjust clip rectangle to cover both. */
251 if (!UnionRect (&(lpmsg
->rect
), &(lpmsg
->rect
),
252 &(lpCur
->w32msg
.rect
)))
254 SetRectEmpty (&(lpmsg
->rect
));
275 ResetEvent (input_available
);
282 extern char * w32_strerror (int error_no
);
284 /* Tell the main thread that we have input available; if the main
285 thread is blocked in select(), we wake it up here. */
287 notify_msg_ready (void)
289 SetEvent (input_available
);
292 /* Wakes up the main thread, which is blocked select()ing for /dev/windows,
293 among other files. */
294 (void) PostThreadMessage (dwMainThreadId
, WM_EMACS_INPUT_READY
, 0, 0);
299 post_msg (W32Msg
* lpmsg
)
301 int_msg
* lpNew
= (int_msg
*) myalloc (sizeof (int_msg
));
306 memcpy (&lpNew
->w32msg
, lpmsg
, sizeof (W32Msg
));
307 lpNew
->lpNext
= NULL
;
313 lpTail
->lpNext
= lpNew
;
328 prepend_msg (W32Msg
*lpmsg
)
330 int_msg
* lpNew
= (int_msg
*) myalloc (sizeof (int_msg
));
335 memcpy (&lpNew
->w32msg
, lpmsg
, sizeof (W32Msg
));
340 lpNew
->lpNext
= lpHead
;
348 /* Process all messages in the current thread's queue. Value is 1 if
349 one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */
351 drain_message_queue (void)
356 while (PeekMessage (&msg
, NULL
, 0, 0, PM_REMOVE
))
358 if (msg
.message
== WM_EMACS_FILENOTIFY
)
360 TranslateMessage (&msg
);
361 DispatchMessage (&msg
);