Mercurial > hg > xemacs-beta
comparison src/event-msw.c @ 223:2c611d1463a6 r20-4b10
Import from CVS: tag r20-4b10
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:10:54 +0200 |
parents | 262b8bb4a523 |
children | 12579d965149 |
comparison
equal
deleted
inserted
replaced
222:aae4c8b01452 | 223:2c611d1463a6 |
---|---|
44 #include "systime.h" | 44 #include "systime.h" |
45 | 45 |
46 #include "event-msw.h" | 46 #include "event-msw.h" |
47 | 47 |
48 static struct event_stream *mswindows_event_stream; | 48 static struct event_stream *mswindows_event_stream; |
49 static Lisp_Object mswindows_dispatch_event_queue, mswindows_dispatch_event_queue_tail; | 49 |
50 CRITICAL_SECTION mswindows_dispatch_crit; | 50 /* |
51 * Two separate queues, for efficiency, one (_u_) for user events, and | |
52 * another (_s_) for non-user ones. We always return events out of the | |
53 * first one until it is empty and only then proceed with the second | |
54 * one. | |
55 */ | |
56 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail; | |
57 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail; | |
51 | 58 |
52 /* | 59 /* |
53 * List of mswindows waitable handles. | 60 * List of mswindows waitable handles. |
54 * Apart from the dispatch queue semaphore, all of these handles may be waited | 61 * Apart from the dispatch queue semaphore, all of these handles may be waited |
55 * on multiple times in emacs_mswindows_next_event before being processed and so | 62 * on multiple times in emacs_mswindows_next_event before being processed and so |
58 static HANDLE mswindows_waitable[MAX_WAITABLE]; | 65 static HANDLE mswindows_waitable[MAX_WAITABLE]; |
59 | 66 |
60 /* random emacs info associated with each of the wait handles */ | 67 /* random emacs info associated with each of the wait handles */ |
61 static mswindows_waitable_info_type mswindows_waitable_info[MAX_WAITABLE]; | 68 static mswindows_waitable_info_type mswindows_waitable_info[MAX_WAITABLE]; |
62 | 69 |
70 /* Count of quit chars currently in the queue */ | |
71 /* Incremented in WM_CHAR handler in msw-proc.c | |
72 Decremented in mswindows_dequeue_dispatch_event() */ | |
73 int mswindows_quit_chars_count = 0; | |
74 | |
75 /* These are Lisp integers; see DEFVARS in this file for description. */ | |
76 int mswindows_dynamic_frame_resize; | |
77 int mswindows_num_mouse_buttons; | |
78 int mswindows_button2_max_skew_x; | |
79 int mswindows_button2_max_skew_y; | |
80 int mswindows_button2_chord_time; | |
81 | |
63 /* Number of wait handles */ | 82 /* Number of wait handles */ |
64 static mswindows_waitable_count=0; | 83 static mswindows_waitable_count=0; |
65 | 84 |
66 /* | 85 static int |
67 * Add an emacs event to the dispatch queue and increment the semaphore | 86 mswindows_user_event_p (struct Lisp_Event* sevt) |
87 { | |
88 return (sevt->event_type == key_press_event | |
89 || sevt->event_type == button_press_event | |
90 || sevt->event_type == button_release_event | |
91 || sevt->event_type == pointer_motion_event); | |
92 } | |
93 | |
94 /* | |
95 * Add an emacs event to the proper dispatch queue | |
68 */ | 96 */ |
69 void | 97 void |
70 mswindows_enqueue_dispatch_event (Lisp_Object event) | 98 mswindows_enqueue_dispatch_event (Lisp_Object event) |
71 { | 99 { |
72 enqueue_event (event, &mswindows_dispatch_event_queue, | 100 int user_p = mswindows_user_event_p (XEVENT(event)); |
73 &mswindows_dispatch_event_queue_tail); | 101 enqueue_event (event, |
74 ReleaseSemaphore(mswindows_waitable[0], 1, NULL); | 102 user_p ? &mswindows_u_dispatch_event_queue : |
75 } | 103 &mswindows_s_dispatch_event_queue, |
76 | 104 user_p ? &mswindows_u_dispatch_event_queue_tail : |
77 /* | 105 &mswindows_s_dispatch_event_queue_tail); |
78 * Remove and return the first emacs event on the dispatch queue. Don't | 106 |
79 * decrement the queue's semaphore because it will be decremented by being | 107 /* This one does not go to window procedure, hence does not |
80 * waited on. | 108 generate XM_BUMPQUEUE magic event! */ |
109 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); | |
110 } | |
111 | |
112 /* | |
113 * Remove and return the first emacs event on the dispatch queue. | |
114 * Give a preference to user events over non-user ones. | |
81 */ | 115 */ |
82 static Lisp_Object | 116 static Lisp_Object |
83 mswindows_dequeue_dispatch_event (void) | 117 mswindows_dequeue_dispatch_event () |
84 { | 118 { |
85 Lisp_Object event; | 119 Lisp_Object event; |
86 event = dequeue_event (&mswindows_dispatch_event_queue, | 120 struct Lisp_Event* sevt; |
87 &mswindows_dispatch_event_queue_tail); | 121 |
122 assert (!NILP(mswindows_u_dispatch_event_queue) || | |
123 !NILP(mswindows_s_dispatch_event_queue)); | |
124 | |
125 event = dequeue_event ( | |
126 NILP(mswindows_u_dispatch_event_queue) ? | |
127 &mswindows_s_dispatch_event_queue : | |
128 &mswindows_u_dispatch_event_queue, | |
129 NILP(mswindows_u_dispatch_event_queue) ? | |
130 &mswindows_s_dispatch_event_queue_tail : | |
131 &mswindows_u_dispatch_event_queue_tail); | |
132 | |
133 sevt = XEVENT(event); | |
134 if (sevt->event_type == key_press_event | |
135 && (sevt->event.key.modifiers & FAKE_MOD_QUIT)) | |
136 { | |
137 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT; | |
138 --mswindows_quit_chars_count; | |
139 } | |
140 | |
88 return event; | 141 return event; |
89 } | 142 } |
90 | 143 |
91 /* | 144 /* |
92 * Remove and return the first emacs event on the dispatch queue that matches | 145 * Remove and return the first emacs event on the dispatch queue that matches |
93 * the supplied event and decrement the queue's semaphore. | 146 * the supplied event |
94 * Only supports timeout events. | 147 * Timeout event matches if interval_id equals to that of the given event. |
95 */ | 148 * Keypress event matches if logical AND between modifiers bitmask of the |
149 * event in the queue and that of the given event is non-zero | |
150 * For all other event types, this function asserts. | |
151 */ | |
152 | |
96 Lisp_Object | 153 Lisp_Object |
97 mswindows_cancel_dispatch_event (Lisp_Object match_event) | 154 mswindows_cancel_dispatch_event (struct Lisp_Event* match) |
98 { | 155 { |
99 Lisp_Object event; | 156 Lisp_Object event; |
100 Lisp_Object previous_event=Qnil; | 157 Lisp_Object previous_event=Qnil; |
101 struct Lisp_Event *match = XEVENT(match_event); | 158 int user_p = mswindows_user_event_p (match); |
102 | 159 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : |
103 assert (match->event_type == timeout_event); | 160 &mswindows_s_dispatch_event_queue; |
104 | 161 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : |
105 EVENT_CHAIN_LOOP (event, mswindows_dispatch_event_queue) | 162 &mswindows_s_dispatch_event_queue_tail; |
106 if (XEVENT_TYPE (event) == match->event_type) | 163 |
107 { | 164 assert (match->event_type == timeout_event |
108 /* We only handle timeouts */ | 165 || match->event_type == key_press_event); |
109 if (XEVENT(event)->event.timeout.interval_id == | 166 |
110 match->event.timeout.interval_id) | 167 EVENT_CHAIN_LOOP (event, *head) |
111 { | 168 { |
112 if (NILP (previous_event)) | 169 int found = 1; |
113 dequeue_event (&mswindows_dispatch_event_queue, | 170 if (XEVENT_TYPE (event) != match->event_type) |
114 &mswindows_dispatch_event_queue_tail); | 171 found = 0; |
115 else | 172 if (found && match->event_type == timeout_event |
116 { | 173 && (XEVENT(event)->event.timeout.interval_id != |
117 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event)); | 174 match->event.timeout.interval_id)) |
118 if (EQ (mswindows_dispatch_event_queue_tail, event)) | 175 found = 0; |
119 mswindows_dispatch_event_queue_tail = previous_event; | 176 if (found && match->event_type == key_press_event |
120 } | 177 && ((XEVENT(event)->event.key.modifiers & |
121 | 178 match->event.key.modifiers) == 0)) |
122 /* Decrement the dispatch queue counter */ | 179 found = 0; |
123 WaitForSingleObject(mswindows_waitable[0], INFINITE); | 180 |
124 return event; | 181 if (found) |
125 } | 182 { |
126 } | 183 if (NILP (previous_event)) |
127 else | 184 dequeue_event (head, tail); |
185 else | |
186 { | |
187 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event)); | |
188 if (EQ (*tail, event)) | |
189 *tail = previous_event; | |
190 } | |
191 | |
192 return event; | |
193 } | |
128 previous_event = event; | 194 previous_event = event; |
129 | 195 } |
130 return Qnil; | |
131 } | 196 } |
132 | 197 |
133 /* | 198 /* |
134 * Find a free waitable slot | 199 * Find a free waitable slot |
135 */ | 200 */ |
154 int waitable; | 219 int waitable; |
155 | 220 |
156 switch (info->type) | 221 switch (info->type) |
157 { | 222 { |
158 case mswindows_waitable_type_dispatch: | 223 case mswindows_waitable_type_dispatch: |
224 assert (0); /* kkm - should not get here */ | |
159 /* Can only have one waitable for the dispatch queue, and it's the first one */ | 225 /* Can only have one waitable for the dispatch queue, and it's the first one */ |
160 assert (mswindows_waitable_count++ == 0); | 226 assert (mswindows_waitable_count++ == 0); |
161 waitable=0; | 227 waitable=0; |
162 InitializeCriticalSection(&mswindows_dispatch_crit); | 228 // InitializeCriticalSection(&mswindows_dispatch_crit); |
163 assert (mswindows_waitable[0] = CreateSemaphore (NULL, 0, 0x7fffffff, NULL)); | 229 assert (mswindows_waitable[0] = CreateSemaphore (NULL, 0, 0x7fffffff, NULL)); |
164 return mswindows_waitable_info+0; | 230 return mswindows_waitable_info+0; |
165 | |
166 #if 0 /* Windows95 doesn't support WaitableTimers */ | |
167 case mswindows_waitable_type_timeout: | |
168 { | |
169 LARGE_INTEGER due; | |
170 due.QuadPart = 10000 * (LONGLONG) info->data.timeout.milliseconds; | |
171 waitable = mswindows_find_free_waitable(); | |
172 mswindows_waitable[waitable] = CreateWaitableTimer(NULL, TRUE, NULL); | |
173 SetWaitableTimer(mswindows_waitable[waitable], &due, 0, NULL, NULL, FALSE); | |
174 mswindows_waitable_info[waitable].data.timeout.id = waitable; | |
175 } | |
176 break; | |
177 #endif | |
178 | 231 |
179 default: | 232 default: |
180 assert(0); | 233 assert(0); |
181 } | 234 } |
182 mswindows_waitable_info[waitable].type = info->type; | 235 mswindows_waitable_info[waitable].type = info->type; |
191 { | 244 { |
192 int waitable; | 245 int waitable; |
193 | 246 |
194 switch (info->type) | 247 switch (info->type) |
195 { | 248 { |
196 #if 0 | |
197 case mswindows_waitable_type_timeout: | |
198 waitable = info->data.timeout.id; | |
199 CancelWaitableTimeout(mswindows_waitable[waitable]); | |
200 break; | |
201 #endif | |
202 | 249 |
203 default: | 250 default: |
204 assert(0); | 251 assert(0); |
205 } | 252 } |
206 | 253 |
209 mswindows_waitable_info[waitable].type = mswindows_waitable_type_none; | 256 mswindows_waitable_info[waitable].type = mswindows_waitable_type_none; |
210 if (waitable == mswindows_waitable_count-1) | 257 if (waitable == mswindows_waitable_count-1) |
211 --mswindows_waitable_count; | 258 --mswindows_waitable_count; |
212 } | 259 } |
213 | 260 |
261 /* | |
262 * Callback procedure for synchronous timer messages | |
263 */ | |
264 static void CALLBACK | |
265 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) | |
266 { | |
267 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
268 struct Lisp_Event *event = XEVENT (emacs_event); | |
269 | |
270 KillTimer (NULL, id_timer); | |
271 | |
272 event->channel = Qnil; | |
273 event->timestamp = dwtime; | |
274 event->event_type = timeout_event; | |
275 event->event.timeout.interval_id = id_timer; | |
276 | |
277 mswindows_enqueue_dispatch_event (emacs_event); | |
278 } | |
279 | |
280 static void | |
281 mswindows_drain_windows_queue () | |
282 { | |
283 MSG msg; | |
284 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | |
285 DispatchMessage (&msg); | |
286 } | |
287 | |
288 /* | |
289 * This drains the event queue and fills up two internal queues until | |
290 * an event of a type specified by USER_P is retrieved. | |
291 * | |
292 * If user_p, then the function drains until the first user event, or | |
293 * the first non-user event if there no user events. Otherwise, If | |
294 * not user_p, it does not give preference to user events. | |
295 * | |
296 * If badly_p, then the function does not return until an event is | |
297 * available. | |
298 * | |
299 * The code does not rely on MsgWaitForMultipleObjects preference for | |
300 * messages over waitable handles. | |
301 * | |
302 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event | |
303 */ | |
304 static void | |
305 mswindows_need_event (int user_p, int badly_p) | |
306 { | |
307 int active; | |
308 | |
309 /* Have to drain Windows message queue first, otherwise, we may miss | |
310 quit char when called from quit_p */ | |
311 mswindows_drain_windows_queue (); | |
312 | |
313 while (NILP (mswindows_u_dispatch_event_queue) && | |
314 (user_p || NILP (mswindows_s_dispatch_event_queue))) | |
315 { | |
316 /* If we already have an event, we've got someting to return - no wait! */ | |
317 if (!NILP (mswindows_u_dispatch_event_queue) | |
318 || !NILP (mswindows_s_dispatch_event_queue)) | |
319 badly_p = 0; | |
320 | |
321 /* Now try getting a message */ | |
322 active = MsgWaitForMultipleObjects (mswindows_waitable_count, | |
323 mswindows_waitable, | |
324 FALSE, badly_p ? INFINITE : 0, | |
325 QS_ALLINPUT); | |
326 | |
327 /* This will assert if handle being waited for becomes abandoned. | |
328 Not the case currently tho */ | |
329 assert ((!badly_p && active == WAIT_TIMEOUT) || | |
330 (active >= WAIT_OBJECT_0 && | |
331 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); | |
332 | |
333 if (active == WAIT_TIMEOUT) | |
334 { | |
335 /* No luck trying - just return what we've already got */ | |
336 return; | |
337 } | |
338 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) | |
339 { | |
340 /* Got your message, thanks */ | |
341 mswindows_drain_windows_queue (); | |
342 } | |
343 else | |
344 { | |
345 /* XXX FIXME: We should do some kind of round-robin scheme to ensure fairness */ | |
346 int waitable = active - WAIT_OBJECT_0; | |
347 mswindows_waitable_info_type *info = mswindows_waitable_info + waitable; | |
348 | |
349 switch (info->type) | |
350 { | |
351 /* XXX FIXME: Should enque subprocess event here so that it is not lost */ | |
352 default: | |
353 assert(0); | |
354 } | |
355 } | |
356 } /* while */ | |
357 | |
358 return; | |
359 } | |
360 | |
214 | 361 |
215 /************************************************************************/ | 362 /************************************************************************/ |
216 /* methods */ | 363 /* methods */ |
217 /************************************************************************/ | 364 /************************************************************************/ |
218 | 365 |
219 static int | 366 static int |
220 emacs_mswindows_add_timeout (EMACS_TIME thyme) | 367 emacs_mswindows_add_timeout (EMACS_TIME thyme) |
221 { | 368 { |
369 int milliseconds; | |
222 EMACS_TIME current_time; | 370 EMACS_TIME current_time; |
223 int milliseconds; | |
224 int id; | |
225 mswindows_request_type request; | |
226 | |
227 EMACS_GET_TIME (current_time); | 371 EMACS_GET_TIME (current_time); |
228 EMACS_SUB_TIME (thyme, thyme, current_time); | 372 EMACS_SUB_TIME (thyme, thyme, current_time); |
229 milliseconds = EMACS_SECS (thyme) * 1000 + EMACS_USECS (thyme) / 1000; | 373 milliseconds = EMACS_SECS (thyme) * 1000 + |
374 (EMACS_USECS (thyme) + 500) / 1000; | |
230 if (milliseconds < 1) | 375 if (milliseconds < 1) |
231 milliseconds = 1; | 376 milliseconds = 1; |
232 request.thing1 = (void *) milliseconds; | 377 return SetTimer (NULL, 0, milliseconds, mswindows_wm_timer_callback); |
233 id = mswindows_make_request(WM_XEMACS_SETTIMER, 0, &request); | |
234 assert(id); /* XXX */ | |
235 return id; | |
236 } | 378 } |
237 | 379 |
238 static void | 380 static void |
239 emacs_mswindows_remove_timeout (int id) | 381 emacs_mswindows_remove_timeout (int id) |
240 { | 382 { |
241 mswindows_request_type request = { (void *) id }; | 383 struct Lisp_Event match_against; |
242 mswindows_make_request(WM_XEMACS_KILLTIMER, 0, &request); | 384 Lisp_Object emacs_event; |
385 | |
386 KillTimer (NULL, id); | |
387 | |
388 /* If there is a dispatch event generated by this | |
389 timeout in the queue, we have to remove it too. */ | |
390 match_against.event_type = timeout_event; | |
391 match_against.event.timeout.interval_id = id; | |
392 emacs_event = mswindows_cancel_dispatch_event (&match_against); | |
393 if (!NILP (emacs_event)) | |
394 Fdeallocate_event(emacs_event); | |
243 } | 395 } |
244 | 396 |
245 /* If `user_p' is false, then return whether there are any win32, timeout, | 397 /* If `user_p' is false, then return whether there are any win32, timeout, |
246 * or subprocess events pending (that is, whether | 398 * or subprocess events pending (that is, whether |
247 * emacs_mswindows_next_event() would return immediately without blocking). | 399 * emacs_mswindows_next_event() would return immediately without blocking). |
252 * emacs_mswindows_next_event() would not block. | 404 * emacs_mswindows_next_event() would not block. |
253 */ | 405 */ |
254 static int | 406 static int |
255 emacs_mswindows_event_pending_p (int user_p) | 407 emacs_mswindows_event_pending_p (int user_p) |
256 { | 408 { |
257 if (user_p) | 409 mswindows_need_event (user_p, 0); |
258 { | 410 |
259 /* Iterate over the dispatch queue looking for user-events */ | 411 return (!NILP (mswindows_u_dispatch_event_queue) |
260 int found = 0; | 412 || (!user_p && !NILP (mswindows_s_dispatch_event_queue))); |
261 Lisp_Object event; | |
262 | |
263 EnterCriticalSection (&mswindows_dispatch_crit); | |
264 EVENT_CHAIN_LOOP (event, mswindows_dispatch_event_queue) | |
265 if (command_event_p (event)) | |
266 found = 1; | |
267 LeaveCriticalSection (&mswindows_dispatch_crit); | |
268 return found; | |
269 } | |
270 else | |
271 { | |
272 /* Check for any kind of input, including the dispatch queue */ | |
273 #if 0 | |
274 /* Want do do the following, but it's not clear whether this would | |
275 * cause the waitables to become unsignalled */ | |
276 return (WaitForMultipleObjects (mswindows_waitable_count, | |
277 mswindows_waitable, FALSE, 0) | |
278 != WAIT_TIMEOUT); | |
279 #else | |
280 return !NILP (mswindows_dispatch_event_queue); | |
281 #endif | |
282 } | |
283 } | |
284 | |
285 static struct console * | |
286 find_console_from_fd (int fd) | |
287 { | |
288 return 0; | |
289 } | 413 } |
290 | 414 |
291 /* | 415 /* |
292 * Return the next event | 416 * Return the next event |
293 * We return windows events off the dispatch event queue in preference to other events | |
294 */ | 417 */ |
295 static void | 418 static void |
296 emacs_mswindows_next_event (struct Lisp_Event *emacs_event) | 419 emacs_mswindows_next_event (struct Lisp_Event *emacs_event) |
297 { | 420 { |
298 DWORD active; | 421 Lisp_Object event, event2; |
299 active = WaitForMultipleObjects (mswindows_waitable_count, mswindows_waitable, | 422 |
300 FALSE, INFINITE); | 423 /* Give strong preference to user events */ |
301 assert(active >= WAIT_OBJECT_0 && active <= WAIT_OBJECT_0 + mswindows_waitable_count - 1); | 424 mswindows_need_event (1, 1); |
302 | 425 |
303 /* Windows events on the dispatch event queue */ | 426 /* XXX Copied from event-Xt.c */ |
304 if (active == WAIT_OBJECT_0) | 427 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue)); |
305 { | 428 XSETEVENT (event2, emacs_event); |
306 /* XXX Copied from event-Xt.c */ | 429 Fcopy_event (event, event2); |
307 Lisp_Object event, event2; | 430 Fdeallocate_event (event); |
308 | |
309 EnterCriticalSection (&mswindows_dispatch_crit); | |
310 XSETEVENT (event2, emacs_event); | |
311 event = mswindows_dequeue_dispatch_event (); | |
312 Fcopy_event (event, event2); | |
313 Fdeallocate_event (event); | |
314 LeaveCriticalSection (&mswindows_dispatch_crit); | |
315 } | |
316 else | |
317 { | |
318 /* XXX FIXME: We should do some kind of round-robin scheme to ensure fairness */ | |
319 int waitable = active - WAIT_OBJECT_0; | |
320 mswindows_waitable_info_type *info = mswindows_waitable_info + waitable; | |
321 | |
322 switch (info->type) | |
323 { | |
324 case mswindows_waitable_type_timeout: | |
325 emacs_event->channel = Qnil; | |
326 emacs_event->event_type = timeout_event; | |
327 emacs_event->event.timeout.interval_id = info->data.timeout.id; | |
328 mswindows_remove_waitable(info); | |
329 break; | |
330 | |
331 default: | |
332 assert(0); | |
333 } | |
334 } | |
335 } | 431 } |
336 | 432 |
337 /* | 433 /* |
338 * Handle a magic event off the dispatch queue. | 434 * Handle a magic event off the dispatch queue. |
339 * XXX split into seperate functions for clarity. | |
340 */ | 435 */ |
341 static void | 436 static void |
342 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) | 437 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) |
343 { | 438 { |
344 RECT *rect = &EVENT_MSWINDOWS_MAGIC_DATA(emacs_event); | |
345 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | |
346 Lisp_Object frame = Qnil; | |
347 XSETFRAME (frame, f); | |
348 #if 0 | 439 #if 0 |
349 stderr_out("magic %x, (%d,%d), (%d,%d)\n", | 440 stderr_out("magic %x, (%d,%d), (%d,%d)\n", |
350 EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event), | 441 EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event), |
351 rect->left, rect->top, rect->right, rect->bottom); | 442 rect->left, rect->top, rect->right, rect->bottom); |
352 #endif | 443 #endif |
353 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) | 444 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) |
354 { | 445 { |
355 case WM_SETFOCUS: | 446 case WM_SETFOCUS: |
356 case WM_KILLFOCUS: | 447 case WM_KILLFOCUS: |
357 { | 448 { |
449 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
450 struct frame *f = XFRAME (frame); | |
358 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); | 451 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); |
359 Lisp_Object conser; | 452 Lisp_Object conser; |
453 | |
360 /* struct gcpro gcpro1; */ | 454 /* struct gcpro gcpro1; */ |
361 | 455 |
362 /* Clear sticky modifiers here (if we had any) */ | 456 /* Clear sticky modifiers here (if we had any) */ |
363 | 457 |
364 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); | 458 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); |
366 emacs_handle_focus_change_preliminary (conser); | 460 emacs_handle_focus_change_preliminary (conser); |
367 /* Under X the stuff up to here is done in the X event handler. | 461 /* Under X the stuff up to here is done in the X event handler. |
368 I Don't know why */ | 462 I Don't know why */ |
369 emacs_handle_focus_change_final (conser); | 463 emacs_handle_focus_change_final (conser); |
370 /* UNGCPRO; */ | 464 /* UNGCPRO; */ |
465 | |
371 } | 466 } |
372 break; | 467 break; |
373 | 468 |
374 /* XXX What about Enter & Leave */ | 469 case XM_BUMPQUEUE: |
470 /* This is a nice event, when we're in need to queue *something* */ | |
471 break; | |
472 | |
473 case XM_MAPFRAME: | |
474 case XM_UNMAPFRAME: | |
475 { | |
476 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
477 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) | |
478 == XM_MAPFRAME ? | |
479 Qmap_frame_hook : Qunmap_frame_hook, | |
480 1, frame); | |
481 } | |
482 break; | |
483 | |
484 /* XXX What about Enter & Leave */ | |
375 #if 0 | 485 #if 0 |
376 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : | 486 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : |
377 Qmouse_leave_frame_hook, 1, frame); | 487 Qmouse_leave_frame_hook, 1, frame); |
378 break; | |
379 #endif | 488 #endif |
380 | |
381 case WM_SIZE: | |
382 if ((rect->left & rect->top & rect->right & rect->bottom) == -1) | |
383 { | |
384 /* Iconified */ | |
385 FRAME_VISIBLE_P (f) = 0; | |
386 va_run_hook_with_args (Qunmap_frame_hook, 1, frame); | |
387 Fframe_iconified_p (frame); | |
388 } | |
389 else | |
390 { | |
391 /* If we're uniconified, our size may or may not have changed */ | |
392 int columns, rows; | |
393 int was_visible = FRAME_VISIBLE_P (f); | |
394 | |
395 FRAME_VISIBLE_P (f) = 1; | |
396 FRAME_PIXWIDTH(f) = rect->right; | |
397 FRAME_PIXHEIGHT(f) = rect->bottom; | |
398 | |
399 pixel_to_char_size (f, rect->right, rect->bottom, &columns, &rows); | |
400 change_frame_size (f, rows, columns, 0); | |
401 /* MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); /* XXX Too extreme? */ | |
402 | |
403 if (!was_visible) | |
404 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
405 | |
406 } | |
407 break; | |
408 | |
409 case WM_PAINT: | |
410 mswindows_redraw_exposed_area(f, rect->left, rect->top, | |
411 rect->right, rect->bottom); | |
412 break; | |
413 | |
414 case WM_CLOSE: | |
415 enqueue_misc_user_event (frame, Qeval, list3 (Qdelete_frame, frame, Qt)); | |
416 break; | |
417 | 489 |
418 default: | 490 default: |
419 assert(0); | 491 assert(0); |
420 } | 492 } |
421 } | 493 } |
441 } | 513 } |
442 | 514 |
443 static void | 515 static void |
444 emacs_mswindows_quit_p (void) | 516 emacs_mswindows_quit_p (void) |
445 { | 517 { |
518 mswindows_need_event (1, 0); | |
519 | |
520 if (mswindows_quit_chars_count > 0) | |
521 { | |
522 /* Yes there's a hidden one... Throw it away */ | |
523 struct Lisp_Event match_against; | |
524 Lisp_Object emacs_event; | |
525 | |
526 match_against.event_type = key_press_event; | |
527 match_against.event.key.modifiers = FAKE_MOD_QUIT; | |
528 | |
529 emacs_event = mswindows_cancel_dispatch_event (&match_against); | |
530 assert (!NILP (emacs_event)); | |
531 | |
532 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT | |
533 ? Qcritical : Qt); | |
534 | |
535 Fdeallocate_event(emacs_event); | |
536 --mswindows_quit_chars_count; | |
537 } | |
446 } | 538 } |
447 | 539 |
448 /* This is called from GC when a process object is about to be freed. | 540 /* This is called from GC when a process object is about to be freed. |
449 If we've still got pointers to it in this file, we're gonna lose hard. | 541 If we've still got pointers to it in this file, we're gonna lose hard. |
450 */ | 542 */ |
472 /************************************************************************/ | 564 /************************************************************************/ |
473 | 565 |
474 void | 566 void |
475 vars_of_event_mswindows (void) | 567 vars_of_event_mswindows (void) |
476 { | 568 { |
477 mswindows_dispatch_event_queue = Qnil; | 569 mswindows_u_dispatch_event_queue = Qnil; |
478 staticpro (&mswindows_dispatch_event_queue); | 570 staticpro (&mswindows_u_dispatch_event_queue); |
479 mswindows_dispatch_event_queue_tail = Qnil; | 571 mswindows_u_dispatch_event_queue_tail = Qnil; |
572 | |
573 mswindows_s_dispatch_event_queue = Qnil; | |
574 staticpro (&mswindows_s_dispatch_event_queue); | |
575 mswindows_s_dispatch_event_queue_tail = Qnil; | |
480 | 576 |
481 mswindows_event_stream = xnew (struct event_stream); | 577 mswindows_event_stream = xnew (struct event_stream); |
482 | 578 |
483 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | 579 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; |
484 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | 580 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; |
485 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; | 581 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; |
486 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; | 582 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; |
487 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; | 583 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; |
488 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; | 584 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; |
489 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; | 585 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; |
490 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; | 586 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; |
491 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; | 587 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; |
492 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; | 588 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; |
589 | |
590 DEFVAR_BOOL ("w32-dynamic-frame-resize", &mswindows_dynamic_frame_resize /* | |
591 *Controls redrawing frame contents during mouse-drag or keyboard resize | |
592 operation. When non-nil, the frame is redrawn while being resized. When | |
593 nil, frame is not redrawn, and exposed areas are filled with default | |
594 MDI application background color. Note that this option only has effect | |
595 if "Show window contents while dragging" is on in system Display/Plus! | |
596 settings. | |
597 Default is t on fast machines, nil on slow. | |
598 */ ); | |
599 | |
600 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */ | |
601 DEFVAR_INT ("w32-mouse-button-tolerance", &mswindows_button2_chord_time /* | |
602 *Analogue of double click interval for faking middle mouse events. | |
603 The value is the minimum time in milliseconds that must elapse between | |
604 left/right button down events before they are considered distinct events. | |
605 If both mouse buttons are depressed within this interval, a middle mouse | |
606 button down event is generated instead. | |
607 If negative or zero, currently set system default is used instead. | |
608 */ ); | |
609 | |
610 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */ | |
611 DEFVAR_INT ("w32-num-mouse-buttons", &mswindows_num_mouse_buttons /* | |
612 Number of physical mouse buttons. | |
613 */ ); | |
614 | |
615 DEFVAR_INT ("w32-mouse-button-max-skew-x", &mswindows_button2_max_skew_x /* | |
616 *Maximum horizontal distance in pixels between points in which left and | |
617 right button clicks occured for them to be translated into single | |
618 middle button event. Clicks must occur in time not longer than defined | |
619 by the variable w32-mouse-button-tolerance. | |
620 If negative or zero, currently set system default is used instead. | |
621 */ ); | |
622 | |
623 DEFVAR_INT ("w32-mouse-button-max-skew-y", &mswindows_button2_max_skew_y /* | |
624 *Maximum vertical distance in pixels between points in which left and | |
625 right button clicks occured for them to be translated into single | |
626 middle button event. Clicks must occur in time not longer than defined | |
627 by the variable w32-mouse-button-tolerance. | |
628 If negative or zero, currently set system default is used instead. | |
629 */ ); | |
630 | |
631 mswindows_button2_max_skew_x = 0; | |
632 mswindows_button2_max_skew_y = 0; | |
633 mswindows_button2_chord_time = 0; | |
493 } | 634 } |
494 | 635 |
495 void | 636 void |
496 syms_of_event_mswindows (void) | 637 syms_of_event_mswindows (void) |
497 { | 638 { |
499 | 640 |
500 void | 641 void |
501 init_event_mswindows_late (void) | 642 init_event_mswindows_late (void) |
502 { | 643 { |
503 event_stream = mswindows_event_stream; | 644 event_stream = mswindows_event_stream; |
504 } | 645 |
646 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE); | |
647 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS); | |
648 } |