Mercurial > hg > xemacs-beta
comparison src/event-msw.c @ 276:6330739388db r21-0b36
Import from CVS: tag r21-0b36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:30:37 +0200 |
parents | ca9a9ec9c1c1 |
children | 90d73dddcdc4 |
comparison
equal
deleted
inserted
replaced
275:a68ae4439f57 | 276:6330739388db |
---|---|
52 #include "sysproc.h" | 52 #include "sysproc.h" |
53 #include "syswait.h" | 53 #include "syswait.h" |
54 #include "systime.h" | 54 #include "systime.h" |
55 | 55 |
56 #include "events-mod.h" | 56 #include "events-mod.h" |
57 | 57 #include <io.h> |
58 #include <errno.h> | 58 #include <errno.h> |
59 | 59 |
60 #ifdef BROKEN_CYGWIN | 60 #ifdef BROKEN_CYGWIN |
61 int WINAPI DdeCmpStringHandles (HSZ, HSZ); | 61 int WINAPI DdeCmpStringHandles (HSZ, HSZ); |
62 HDDEDATA WINAPI DdeCreateDataHandle (DWORD, LPBYTE, DWORD, DWORD, HSZ, | 62 HDDEDATA WINAPI DdeCreateDataHandle (DWORD, LPBYTE, DWORD, DWORD, HSZ, |
139 #define HANDLE_TO_USID(h) ((USID)(h)) | 139 #define HANDLE_TO_USID(h) ((USID)(h)) |
140 | 140 |
141 #define NTPIPE_SLURP_STREAM_DATA(stream) \ | 141 #define NTPIPE_SLURP_STREAM_DATA(stream) \ |
142 LSTREAM_TYPE_DATA (stream, ntpipe_slurp) | 142 LSTREAM_TYPE_DATA (stream, ntpipe_slurp) |
143 | 143 |
144 struct ntpipe_slurp_stream | 144 /* This structure is allocated by the main thread, and is deallocated |
145 { | 145 in the thread upon exit. There are situations when a thread |
146 LPARAM user_data; /* Any user data stored in the stream object */ | 146 remains blocked for a long time, much longer than the lstream |
147 exists. For exmaple, "start notepad" command is issued from the | |
148 shell, then the shell is closed by C-c C-d. Although the shell | |
149 process exits, its output pipe will not get closed until the | |
150 notepad process exits also, because it inherits the pipe form the | |
151 shell. In this case, we abandon the thread, and let it live until | |
152 all such processes exit. While struct ntpipe_slurp_stream is | |
153 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ | |
154 | |
155 struct ntpipe_slurp_stream_shared_data | |
156 { | |
147 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | 157 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ |
148 /* This is a manual-reset object. */ | 158 /* This is a manual-reset object. */ |
149 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ | 159 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ |
150 /* This is a manual-reset object. */ | 160 /* This is a manual-reset object. */ |
151 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ | 161 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ |
152 /* This is a manual-reset object. */ | 162 /* This is a manual-reset object. */ |
153 HANDLE hpipe; /* Pipe read end handle. */ | 163 HANDLE hpipe; /* Pipe read end handle. */ |
154 HANDLE hthread; /* Reader thread handle. */ | 164 LONG die_p; /* Thread must exit ASAP if non-zero */ |
155 BYTE onebyte; /* One byte buffer read by thread */ | |
156 DWORD die_p; /* Thread must exit ASAP if non-zero */ | |
157 BOOL eof_p : 1; /* Set when thread saw EOF */ | 165 BOOL eof_p : 1; /* Set when thread saw EOF */ |
158 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | 166 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ |
167 BOOL inuse_p : 1; /* this structure is in use */ | |
168 LONG lock_count; /* Client count of this struct, 0=safe to free */ | |
169 BYTE onebyte; /* One byte buffer read by thread */ | |
170 }; | |
171 | |
172 #define MAX_SLURP_STREAMS 32 | |
173 struct ntpipe_slurp_stream_shared_data | |
174 shared_data_block[MAX_SLURP_STREAMS]={0}; | |
175 | |
176 struct ntpipe_slurp_stream | |
177 { | |
178 LPARAM user_data; /* Any user data stored in the stream object */ | |
179 struct ntpipe_slurp_stream_shared_data* thread_data; | |
159 }; | 180 }; |
160 | 181 |
161 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp, | 182 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp, |
162 sizeof (struct ntpipe_slurp_stream)); | 183 sizeof (struct ntpipe_slurp_stream)); |
163 | 184 |
185 /* This function is thread-safe, and is called from either thread | |
186 context. It serializes freeing shared dtata structure */ | |
187 static void | |
188 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s) | |
189 { | |
190 if (InterlockedDecrement (&s->lock_count) == 0) | |
191 { | |
192 /* Destroy events */ | |
193 CloseHandle (s->hev_thread); | |
194 CloseHandle (s->hev_caller); | |
195 CloseHandle (s->hev_unsleep); | |
196 s->inuse_p = 0; | |
197 } | |
198 } | |
199 | |
200 static struct ntpipe_slurp_stream_shared_data* | |
201 slurper_allocate_shared_data() | |
202 { | |
203 int i=0; | |
204 for (i=0; i<MAX_SLURP_STREAMS; i++) | |
205 { | |
206 if (!shared_data_block[i].inuse_p) | |
207 { | |
208 shared_data_block[i].inuse_p=1; | |
209 return &shared_data_block[i]; | |
210 } | |
211 } | |
212 return (struct ntpipe_slurp_stream_shared_data*)0; | |
213 } | |
214 | |
164 static DWORD WINAPI | 215 static DWORD WINAPI |
165 slurp_thread (LPVOID vparam) | 216 slurp_thread (LPVOID vparam) |
166 { | 217 { |
167 struct ntpipe_slurp_stream *s = (struct ntpipe_slurp_stream*)vparam; | 218 struct ntpipe_slurp_stream_shared_data *s = |
219 (struct ntpipe_slurp_stream_shared_data*)vparam; | |
168 | 220 |
169 for (;;) | 221 for (;;) |
170 { | 222 { |
171 /* Read one byte from the pipe */ | 223 /* Read one byte from the pipe */ |
172 DWORD actually_read; | 224 DWORD actually_read; |
190 | 242 |
191 /* Now we got something to notify caller, either a byte or an | 243 /* Now we got something to notify caller, either a byte or an |
192 error/eof indication. Before we do, allow internal pipe | 244 error/eof indication. Before we do, allow internal pipe |
193 buffer to accumulate little bit more data. | 245 buffer to accumulate little bit more data. |
194 Reader function pulses this event before waiting for | 246 Reader function pulses this event before waiting for |
195 a character, to avoid pipde delay, and to get the byte | 247 a character, to avoid pipe delay, and to get the byte |
196 immediately. */ | 248 immediately. */ |
197 if (!s->die_p) | 249 if (!s->die_p) |
198 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY); | 250 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY); |
199 | 251 |
200 /* Either make event loop generate a process event, or | 252 /* Either make event loop generate a process event, or |
207 | 259 |
208 /* Block until the client finishes with retireving the rest of | 260 /* Block until the client finishes with retireving the rest of |
209 pipe data */ | 261 pipe data */ |
210 WaitForSingleObject (s->hev_thread, INFINITE); | 262 WaitForSingleObject (s->hev_thread, INFINITE); |
211 } | 263 } |
264 | |
265 slurper_free_shared_data_maybe (s); | |
212 | 266 |
213 return 0; | 267 return 0; |
214 } | 268 } |
215 | 269 |
216 static Lisp_Object | 270 static Lisp_Object |
218 { | 272 { |
219 Lisp_Object obj; | 273 Lisp_Object obj; |
220 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r"); | 274 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r"); |
221 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr); | 275 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr); |
222 DWORD thread_id_unused; | 276 DWORD thread_id_unused; |
277 HANDLE hthread; | |
223 | 278 |
224 /* We deal only with pipes, for we're using PeekNamedPipe api */ | 279 /* We deal only with pipes, for we're using PeekNamedPipe api */ |
225 assert (GetFileType (hpipe) == FILE_TYPE_PIPE); | 280 assert (GetFileType (hpipe) == FILE_TYPE_PIPE); |
226 | 281 |
227 s->die_p = 0; | 282 s->thread_data = slurper_allocate_shared_data(); |
228 s->eof_p = FALSE; | 283 |
229 s->error_p = FALSE; | 284 /* Create reader thread. This could fail, so do not create events |
230 s->hpipe = hpipe; | 285 until thread is created */ |
286 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data, | |
287 CREATE_SUSPENDED, &thread_id_unused); | |
288 if (hthread == NULL) | |
289 { | |
290 Lstream_delete (lstr); | |
291 s->thread_data->inuse_p=0; | |
292 return Qnil; | |
293 } | |
294 | |
295 /* Shared data are initially owned by both main and slurper | |
296 threads. */ | |
297 s->thread_data->lock_count = 2; | |
298 s->thread_data->die_p = 0; | |
299 s->thread_data->eof_p = FALSE; | |
300 s->thread_data->error_p = FALSE; | |
301 s->thread_data->hpipe = hpipe; | |
231 s->user_data = param; | 302 s->user_data = param; |
232 | 303 |
233 /* Create reader thread. This could fail, so do not | |
234 create events until thread is created */ | |
235 s->hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s, | |
236 CREATE_SUSPENDED, &thread_id_unused); | |
237 if (s->hthread == NULL) | |
238 { | |
239 Lstream_delete (lstr); | |
240 return Qnil; | |
241 } | |
242 | |
243 /* hev_thread is a manual-reset event, initially signaled */ | 304 /* hev_thread is a manual-reset event, initially signaled */ |
244 s->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL); | 305 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL); |
245 /* hev_caller is a manual-reset event, initially nonsignaled */ | 306 /* hev_caller is a manual-reset event, initially nonsignaled */ |
246 s->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL); | 307 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL); |
247 /* hev_unsleep is a manual-reset event, initially nonsignaled */ | 308 /* hev_unsleep is a manual-reset event, initially nonsignaled */ |
248 s->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL); | 309 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL); |
249 | 310 |
250 /* Now let it go */ | 311 /* Now let it go */ |
251 ResumeThread (s->hthread); | 312 ResumeThread (hthread); |
313 CloseHandle (hthread); | |
252 | 314 |
253 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | 315 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; |
254 XSETLSTREAM (obj, lstr); | 316 XSETLSTREAM (obj, lstr); |
255 return obj; | 317 return obj; |
256 } | 318 } |
264 | 326 |
265 static HANDLE | 327 static HANDLE |
266 get_ntpipe_input_stream_waitable (Lstream *stream) | 328 get_ntpipe_input_stream_waitable (Lstream *stream) |
267 { | 329 { |
268 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream); | 330 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream); |
269 return s->hev_caller; | 331 return s->thread_data->hev_caller; |
270 } | 332 } |
271 | 333 |
272 static int | 334 static int |
273 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) | 335 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) |
274 { | 336 { |
275 /* This function must be called from the main thread only */ | 337 /* This function must be called from the main thread only */ |
276 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream); | 338 struct ntpipe_slurp_stream_shared_data* s = |
339 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; | |
277 | 340 |
278 if (!s->die_p) | 341 if (!s->die_p) |
279 { | 342 { |
280 DWORD wait_result; | 343 DWORD wait_result; |
281 /* Disallow pipe read delay for the thread: we need a character ASAP */ | 344 /* Disallow pipe read delay for the thread: we need a character |
345 ASAP */ | |
282 SetEvent (s->hev_unsleep); | 346 SetEvent (s->hev_unsleep); |
283 | 347 |
284 /* Check if we have a character ready. Give it a short delay, for | 348 /* Check if we have a character ready. Give it a short delay, |
285 the thread to awake from pipe delay, just ion case*/ | 349 for the thread to awake from pipe delay, just ion case*/ |
286 wait_result = WaitForSingleObject (s->hev_caller, 2); | 350 wait_result = WaitForSingleObject (s->hev_caller, 2); |
287 | 351 |
288 /* Revert to the normal sleep behavior. */ | 352 /* Revert to the normal sleep behavior. */ |
289 ResetEvent (s->hev_unsleep); | 353 ResetEvent (s->hev_unsleep); |
290 | 354 |
306 if (s->eof_p) | 370 if (s->eof_p) |
307 return 0; | 371 return 0; |
308 if (s->error_p || s->die_p) | 372 if (s->error_p || s->die_p) |
309 return -1; | 373 return -1; |
310 | 374 |
311 /* Ok, there were no error neither eof - we've got a byte from the pipe */ | 375 /* Ok, there were no error neither eof - we've got a byte from the |
376 pipe */ | |
312 *(data++) = s->onebyte; | 377 *(data++) = s->onebyte; |
313 --size; | 378 --size; |
314 | 379 |
315 if (size > 0) | 380 { |
316 { | 381 DWORD bytes_read = 0; |
317 DWORD bytes_available, bytes_read; | 382 if (size > 0) |
318 | 383 { |
319 /* If the api call fails, return at least one byte already read. | 384 DWORD bytes_available; |
320 ReadFile in thread will return error */ | 385 |
321 if (!PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL)) | 386 /* If the api call fails, return at least one byte already |
322 return 1; | 387 read. ReadFile in thread will return error */ |
323 | 388 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL)) |
324 /* Fetch available bytes. The same consideration applies, so do | 389 { |
325 not check for errors. ReadFile in the thread will fail if the | 390 |
326 next call fails. */ | 391 /* Fetch available bytes. The same consideration applies, |
327 ReadFile (s->hpipe, data, min (bytes_available, size), &bytes_read, NULL); | 392 so do not check for errors. ReadFile in the thread will |
328 | 393 fail if the next call fails. */ |
329 /* Now we can unblock thread, so it attempts to read more */ | 394 if (bytes_available) |
330 SetEvent (s->hev_thread); | 395 ReadFile (s->hpipe, data, min (bytes_available, size), |
331 return bytes_read + 1; | 396 &bytes_read, NULL); |
332 } | 397 } |
333 else | 398 |
334 { | 399 /* Now we can unblock thread, so it attempts to read more */ |
335 SetEvent (s->hev_thread); | 400 SetEvent (s->hev_thread); |
336 return 1; | 401 return bytes_read + 1; |
337 } | 402 } |
403 } | |
338 } | 404 } |
339 | 405 |
340 static int | 406 static int |
341 ntpipe_slurp_closer (Lstream *stream) | 407 ntpipe_slurp_closer (Lstream *stream) |
342 { | 408 { |
343 /* This function must be called from the main thread only */ | 409 /* This function must be called from the main thread only */ |
344 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream); | 410 struct ntpipe_slurp_stream_shared_data* s = |
411 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; | |
345 | 412 |
346 /* Force thread to stop */ | 413 /* Force thread to stop */ |
347 InterlockedIncrement (&s->die_p); | 414 InterlockedIncrement (&s->die_p); |
348 | 415 |
349 /* Break the pipe, in case the thread still blocked on read */ | 416 /* Set events which could possibly block slurper. Let it finish soon |
350 CloseHandle (s->hpipe); | 417 or later. */ |
351 | |
352 /* Set events which could possibly block slurper */ | |
353 SetEvent (s->hev_unsleep); | 418 SetEvent (s->hev_unsleep); |
354 SetEvent (s->hev_thread); | 419 SetEvent (s->hev_thread); |
355 | 420 |
356 /* Wait while thread terminates */ | 421 /* Unlock and maybe free shared data */ |
357 WaitForSingleObject (s->hthread, INFINITE); | 422 slurper_free_shared_data_maybe (s); |
358 CloseHandle (s->hthread); | |
359 | |
360 /* Destroy events */ | |
361 CloseHandle (s->hev_thread); | |
362 CloseHandle (s->hev_caller); | |
363 CloseHandle (s->hev_unsleep); | |
364 | 423 |
365 return 0; | 424 return 0; |
366 } | 425 } |
367 | 426 |
368 static void | 427 static void |
379 #define MAX_FLUSH_TIME 500 | 438 #define MAX_FLUSH_TIME 500 |
380 | 439 |
381 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ | 440 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ |
382 LSTREAM_TYPE_DATA (stream, ntpipe_shove) | 441 LSTREAM_TYPE_DATA (stream, ntpipe_shove) |
383 | 442 |
443 #define MAX_SHOVE_BUFFER_SIZE 128 | |
444 | |
384 struct ntpipe_shove_stream | 445 struct ntpipe_shove_stream |
385 { | 446 { |
386 LPARAM user_data; /* Any user data stored in the stream object */ | 447 LPARAM user_data; /* Any user data stored in the stream object */ |
387 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | 448 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ |
388 /* This is an auto-reset object. */ | 449 /* This is an auto-reset object. */ |
389 HANDLE hpipe; /* Pipe write end handle. */ | 450 HANDLE hpipe; /* Pipe write end handle. */ |
390 HANDLE hthread; /* Reader thread handle. */ | 451 HANDLE hthread; /* Reader thread handle. */ |
391 LPVOID buffer; /* Buffer being written */ | 452 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ |
392 DWORD size; /* Number of bytes to write */ | 453 DWORD size; /* Number of bytes to write */ |
393 DWORD die_p; /* Thread must exit ASAP if non-zero */ | 454 LONG die_p; /* Thread must exit ASAP if non-zero */ |
394 DWORD idle_p; /* Non-zero if thread is waiting for job */ | 455 LONG idle_p; /* Non-zero if thread is waiting for job */ |
395 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | 456 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ |
396 BOOL blocking_p : 1;/* Last write attempt would cause blocking */ | 457 BOOL blocking_p : 1;/* Last write attempt would cause blocking */ |
397 }; | 458 }; |
398 | 459 |
399 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove, | 460 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove, |
421 { | 482 { |
422 s->error_p = TRUE; | 483 s->error_p = TRUE; |
423 InterlockedIncrement (&s->die_p); | 484 InterlockedIncrement (&s->die_p); |
424 } | 485 } |
425 | 486 |
426 /* free it */ | |
427 LocalFree ((HLOCAL)s->buffer); | |
428 | |
429 if (s->die_p) | 487 if (s->die_p) |
430 break; | 488 break; |
431 } | 489 } |
432 | 490 |
433 return 0; | 491 return 0; |
484 | 542 |
485 s->blocking_p = !s->idle_p; | 543 s->blocking_p = !s->idle_p; |
486 if (s->blocking_p) | 544 if (s->blocking_p) |
487 return 0; | 545 return 0; |
488 | 546 |
489 /* Make a copy of data to be written. We intentionally avoid using | 547 if (size>MAX_SHOVE_BUFFER_SIZE) |
490 xalloc/xfree, because gnu malloc is not thread-safe */ | 548 return 0; |
491 s->buffer = (LPVOID) LocalAlloc (LMEM_FIXED, size); | 549 |
492 if (s->buffer == NULL) | |
493 return -1; | |
494 memcpy (s->buffer, data, size); | 550 memcpy (s->buffer, data, size); |
495 s->size = size; | 551 s->size = size; |
496 | 552 |
497 /* Start output */ | 553 /* Start output */ |
498 InterlockedDecrement (&s->idle_p); | 554 InterlockedDecrement (&s->idle_p); |
575 } | 631 } |
576 | 632 |
577 /* | 633 /* |
578 * Add an emacs event to the proper dispatch queue | 634 * Add an emacs event to the proper dispatch queue |
579 */ | 635 */ |
580 void | 636 static void |
581 mswindows_enqueue_dispatch_event (Lisp_Object event) | 637 mswindows_enqueue_dispatch_event (Lisp_Object event) |
582 { | 638 { |
583 int user_p = mswindows_user_event_p (XEVENT(event)); | 639 int user_p = mswindows_user_event_p (XEVENT(event)); |
584 enqueue_event (event, | 640 enqueue_event (event, |
585 user_p ? &mswindows_u_dispatch_event_queue : | 641 user_p ? &mswindows_u_dispatch_event_queue : |
586 &mswindows_s_dispatch_event_queue, | 642 &mswindows_s_dispatch_event_queue, |
587 user_p ? &mswindows_u_dispatch_event_queue_tail : | 643 user_p ? &mswindows_u_dispatch_event_queue_tail : |
588 &mswindows_s_dispatch_event_queue_tail); | 644 &mswindows_s_dispatch_event_queue_tail); |
589 | 645 |
590 /* This one does not go to window procedure, hence does not | 646 /* Avoid blocking on WaitMessage */ |
591 generate XM_BUMPQUEUE magic event! */ | |
592 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); | 647 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); |
593 } | 648 } |
594 | 649 |
595 void | 650 void |
651 mswindows_bump_queue (void) | |
652 { | |
653 /* Bump queue, by putting in an empty event */ | |
654 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
655 struct Lisp_Event* event = XEVENT (emacs_event); | |
656 | |
657 event->event_type = empty_event; | |
658 | |
659 mswindows_enqueue_dispatch_event (emacs_event); | |
660 } | |
661 | |
662 static void | |
596 mswindows_enqueue_magic_event (HWND hwnd, UINT message) | 663 mswindows_enqueue_magic_event (HWND hwnd, UINT message) |
597 { | 664 { |
598 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 665 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
599 struct Lisp_Event* event = XEVENT (emacs_event); | 666 struct Lisp_Event* event = XEVENT (emacs_event); |
600 | 667 |
913 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); | 980 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); |
914 UNGCPRO; | 981 UNGCPRO; |
915 return result; | 982 return result; |
916 } | 983 } |
917 | 984 |
918 | |
919 | |
920 static void | 985 static void |
921 mswindows_drain_windows_queue () | 986 mswindows_drain_windows_queue () |
922 { | 987 { |
923 MSG msg; | 988 MSG msg; |
924 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | 989 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) |
1029 else | 1094 else |
1030 { | 1095 { |
1031 /* None. This means that the process handle itself has signaled. | 1096 /* None. This means that the process handle itself has signaled. |
1032 Remove the handle from the wait vector, and make status_ntoify | 1097 Remove the handle from the wait vector, and make status_ntoify |
1033 note the exited process */ | 1098 note the exited process */ |
1034 CloseHandle (mswindows_waitable_handles[ix]); | |
1035 mswindows_waitable_handles [ix] = | 1099 mswindows_waitable_handles [ix] = |
1036 mswindows_waitable_handles [--mswindows_waitable_count]; | 1100 mswindows_waitable_handles [--mswindows_waitable_count]; |
1037 kick_status_notify (); | 1101 kick_status_notify (); |
1102 /* Have to return something: there may be no accompanying | |
1103 process event */ | |
1104 mswindows_bump_queue (); | |
1038 } | 1105 } |
1039 } | 1106 } |
1040 } /* while */ | 1107 } /* while */ |
1041 } | 1108 } |
1042 | 1109 |
1185 return 1; | 1252 return 1; |
1186 | 1253 |
1187 case WM_CLOSE: | 1254 case WM_CLOSE: |
1188 fobj = mswindows_find_frame (hwnd); | 1255 fobj = mswindows_find_frame (hwnd); |
1189 enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); | 1256 enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); |
1190 mswindows_enqueue_magic_event (hwnd, XM_BUMPQUEUE); | 1257 mswindows_bump_queue (); |
1191 break; | 1258 break; |
1192 | 1259 |
1193 case WM_KEYDOWN: | 1260 case WM_KEYDOWN: |
1194 case WM_SYSKEYDOWN: | 1261 case WM_SYSKEYDOWN: |
1195 { | 1262 { |
1609 | 1676 |
1610 case WM_EXITSIZEMOVE: | 1677 case WM_EXITSIZEMOVE: |
1611 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 1678 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
1612 msframe->sizing = 0; | 1679 msframe->sizing = 0; |
1613 /* Queue noop event */ | 1680 /* Queue noop event */ |
1614 mswindows_enqueue_magic_event (hwnd, XM_BUMPQUEUE); | 1681 mswindows_bump_queue (); |
1615 return 0; | 1682 return 0; |
1616 | 1683 |
1617 #ifdef HAVE_SCROLLBARS | 1684 #ifdef HAVE_SCROLLBARS |
1618 case WM_VSCROLL: | 1685 case WM_VSCROLL: |
1619 case WM_HSCROLL: | 1686 case WM_HSCROLL: |
1652 XFRAME (mswindows_find_frame (hwnd))))) | 1719 XFRAME (mswindows_find_frame (hwnd))))) |
1653 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | 1720 SendMessage (hwnd, WM_CANCELMODE, 0, 0); |
1654 } | 1721 } |
1655 break; | 1722 break; |
1656 | 1723 |
1657 case WM_EXITMENULOOP: | |
1658 if (UNBOUNDP (mswindows_handle_wm_exitmenuloop ( | |
1659 XFRAME (mswindows_find_frame (hwnd))))) | |
1660 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
1661 break; | |
1662 | |
1663 #endif /* HAVE_MENUBARS */ | 1724 #endif /* HAVE_MENUBARS */ |
1664 | 1725 |
1665 case WM_COMMAND: | 1726 case WM_COMMAND: |
1666 { | 1727 { |
1667 WORD id = LOWORD (wParam); | 1728 WORD id = LOWORD (wParam); |
1668 frame = XFRAME (mswindows_find_frame (hwnd)); | 1729 frame = XFRAME (mswindows_find_frame (hwnd)); |
1730 | |
1731 #ifdef HAVE_TOOLBARS | |
1732 if (!NILP (mswindows_handle_toolbar_wm_command (frame, id))) | |
1733 break; | |
1734 #endif | |
1669 | 1735 |
1670 #ifdef HAVE_MENUBARS | 1736 #ifdef HAVE_MENUBARS |
1671 if (!NILP (mswindows_handle_wm_command (frame, id))) | 1737 if (!NILP (mswindows_handle_wm_command (frame, id))) |
1672 break; | 1738 break; |
1673 #endif | |
1674 | |
1675 #ifdef HAVE_TOOLBARS | |
1676 /* O Toolbar Implementor, this place may have something for you!;*/ | |
1677 #endif | 1739 #endif |
1678 | 1740 |
1679 /* Bite me - a spurious command. This cannot happen. */ | 1741 /* Bite me - a spurious command. This cannot happen. */ |
1680 error ("XEMACS BUG: Cannot decode command message"); | 1742 error ("XEMACS BUG: Cannot decode command message"); |
1681 } | 1743 } |
1927 if (l == 0) | 1989 if (l == 0) |
1928 { | 1990 { |
1929 /* We are in progress of frame creation. Return the frame | 1991 /* We are in progress of frame creation. Return the frame |
1930 being created, as it still not remembered in the window | 1992 being created, as it still not remembered in the window |
1931 extra storage. */ | 1993 extra storage. */ |
1932 assert (!NILP (mswindows_frame_being_created)); | 1994 assert (!NILP (Vmswindows_frame_being_created)); |
1933 return mswindows_frame_being_created; | 1995 return Vmswindows_frame_being_created; |
1934 } | 1996 } |
1935 VOID_TO_LISP (f, l); | 1997 VOID_TO_LISP (f, l); |
1936 return f; | 1998 return f; |
1937 } | 1999 } |
1938 | 2000 |
2037 /* UNGCPRO; */ | 2099 /* UNGCPRO; */ |
2038 | 2100 |
2039 } | 2101 } |
2040 break; | 2102 break; |
2041 | 2103 |
2042 case XM_BUMPQUEUE: | |
2043 /* This is a nice event, when we're in need to queue *something* */ | |
2044 break; | |
2045 | |
2046 case XM_MAPFRAME: | 2104 case XM_MAPFRAME: |
2047 case XM_UNMAPFRAME: | 2105 case XM_UNMAPFRAME: |
2048 { | 2106 { |
2049 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | 2107 Lisp_Object frame = EVENT_CHANNEL (emacs_event); |
2050 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) | 2108 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) |
2072 get_process_streams (process, &instr, &outstr); | 2130 get_process_streams (process, &instr, &outstr); |
2073 assert (!NILP (instr)); | 2131 assert (!NILP (instr)); |
2074 return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); | 2132 return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); |
2075 } | 2133 } |
2076 | 2134 |
2077 static HANDLE | |
2078 get_process_handle (struct Lisp_Process *p) | |
2079 { | |
2080 /* #### The guess is that cygwin uses the same algorithm for | |
2081 computing pids: negate if less than zero, '95 case */ | |
2082 Lisp_Object process, pid; | |
2083 XSETPROCESS (process, p); | |
2084 pid = Fprocess_id (process); | |
2085 if (INTP (pid)) | |
2086 { | |
2087 HANDLE hproc; | |
2088 int ipid = XINT (pid); | |
2089 if (ipid < 0) | |
2090 ipid = -ipid; | |
2091 hproc = OpenProcess (SYNCHRONIZE, FALSE, ipid); | |
2092 /* #### This is WRONG! The process migh have ended before we got here. */ | |
2093 /* assert (hproc != NULL); */ | |
2094 /* Instead, we fake "a signaled hadle", which will trigger | |
2095 immediately upon entering the message loop */ | |
2096 if (hproc = NULL) | |
2097 hproc = CreateEvent (NULL, TRUE, TRUE, NULL); | |
2098 return hproc; | |
2099 } | |
2100 else | |
2101 return NULL; | |
2102 } | |
2103 | |
2104 static void | 2135 static void |
2105 emacs_mswindows_select_process (struct Lisp_Process *process) | 2136 emacs_mswindows_select_process (struct Lisp_Process *process) |
2106 { | 2137 { |
2107 HANDLE hev = get_process_input_waitable (process); | 2138 HANDLE hev = get_process_input_waitable (process); |
2108 HANDLE hprocess; | |
2109 | 2139 |
2110 if (!add_waitable_handle (hev)) | 2140 if (!add_waitable_handle (hev)) |
2111 error ("Too many active processes"); | 2141 error ("Too many active processes"); |
2112 | 2142 |
2113 hprocess = get_process_handle (process); | 2143 #ifdef HAVE_WIN32_PROCESSES |
2114 if (hprocess) | 2144 { |
2115 { | 2145 HANDLE hprocess = get_nt_process_handle (process); |
2116 if (!add_waitable_handle (hprocess)) | 2146 if (!add_waitable_handle (hprocess)) |
2117 { | 2147 { |
2118 remove_waitable_handle (hev); | 2148 remove_waitable_handle (hev); |
2119 CloseHandle (hprocess); | 2149 error ("Too many active processes"); |
2120 error ("Too many active processes"); | 2150 } |
2121 } | 2151 } |
2122 } | 2152 #endif |
2123 } | 2153 } |
2124 | 2154 |
2125 static void | 2155 static void |
2126 emacs_mswindows_unselect_process (struct Lisp_Process *process) | 2156 emacs_mswindows_unselect_process (struct Lisp_Process *process) |
2127 { | 2157 { |
2142 } | 2172 } |
2143 | 2173 |
2144 static void | 2174 static void |
2145 emacs_mswindows_quit_p (void) | 2175 emacs_mswindows_quit_p (void) |
2146 { | 2176 { |
2177 /* Quit cannot happen in modal loop: all program | |
2178 input is dedicated to Windows. */ | |
2179 if (mswindows_in_modal_loop) | |
2180 return; | |
2181 | |
2147 /* Drain windows queue. This sets up number of quit | 2182 /* Drain windows queue. This sets up number of quit |
2148 characters in in the queue */ | 2183 characters in in the queue */ |
2149 mswindows_drain_windows_queue (); | 2184 mswindows_drain_windows_queue (); |
2150 | 2185 |
2151 if (mswindows_quit_chars_count > 0) | 2186 if (mswindows_quit_chars_count > 0) |
2189 hout = (HANDLE) outhandle; | 2224 hout = (HANDLE) outhandle; |
2190 fdi = fdo = -1; | 2225 fdi = fdo = -1; |
2191 #elif defined (HAVE_UNIX_PROCESSES) | 2226 #elif defined (HAVE_UNIX_PROCESSES) |
2192 /* We are passed UNIX fds. This must be Cygwin. | 2227 /* We are passed UNIX fds. This must be Cygwin. |
2193 Fetch os handles */ | 2228 Fetch os handles */ |
2194 hin = inhandle >= 0 ? get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE; | 2229 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE; |
2195 hout = outhandle >= 0 ? get_sfhandle ((int)outhandle) : INVALID_HANDLE_VALUE; | 2230 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE; |
2231 fdi=(int)inhandle; | |
2232 fdo=(int)outhandle; | |
2196 #else | 2233 #else |
2197 #error "So, WHICH kind of processes do you want?" | 2234 #error "So, WHICH kind of processes do you want?" |
2198 #endif | 2235 #endif |
2199 | 2236 |
2200 *instream = (hin != INVALID_HANDLE_VALUE | 2237 *instream = (hin != INVALID_HANDLE_VALUE |
2201 ? make_ntpipe_input_stream (hin, fdi) | 2238 ? make_ntpipe_input_stream (hin, fdi) |
2202 : Qnil); | 2239 : Qnil); |
2203 | 2240 |
2241 #ifdef HAVE_WIN32_PROCESSES | |
2204 *outstream = (hout != INVALID_HANDLE_VALUE | 2242 *outstream = (hout != INVALID_HANDLE_VALUE |
2205 ? make_ntpipe_output_stream (hout, fdo) | 2243 ? make_ntpipe_output_stream (hout, fdo) |
2206 : Qnil); | 2244 : Qnil); |
2245 #elif defined (HAVE_UNIX_PROCESSES) | |
2246 *outstream = (fdo >= 0 | |
2247 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK) | |
2248 : Qnil); | |
2249 | |
2250 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS) | |
2251 /* FLAGS is process->pty_flag for UNIX_PROCESSES */ | |
2252 if (flags && fdo >= 0) | |
2253 { | |
2254 Bufbyte eof_char = get_eof_char (fdo); | |
2255 int pty_max_bytes = get_pty_max_bytes (fdo); | |
2256 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char); | |
2257 } | |
2258 #endif | |
2259 #endif | |
2207 | 2260 |
2208 return (NILP (*instream) ? USID_ERROR | 2261 return (NILP (*instream) ? USID_ERROR |
2209 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream)))); | 2262 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream)))); |
2210 } | 2263 } |
2211 | 2264 |
2216 /* Oh nothing special here for Win32 at all */ | 2269 /* Oh nothing special here for Win32 at all */ |
2217 #if defined (HAVE_UNIX_PROCESSES) | 2270 #if defined (HAVE_UNIX_PROCESSES) |
2218 int in = (NILP(instream) ? -1 | 2271 int in = (NILP(instream) ? -1 |
2219 : get_ntpipe_input_stream_param (XLSTREAM (instream))); | 2272 : get_ntpipe_input_stream_param (XLSTREAM (instream))); |
2220 int out = (NILP(outstream) ? -1 | 2273 int out = (NILP(outstream) ? -1 |
2221 : get_ntpipe_output_stream_param (XLSTREAM (outstream))); | 2274 : filedesc_stream_fd (XLSTREAM (outstream))); |
2222 | 2275 |
2223 if (in >= 0) | 2276 if (in >= 0) |
2224 close (in); | 2277 close (in); |
2225 if (out != in && out >= 0) | 2278 if (out != in && out >= 0) |
2226 close (out); | 2279 close (out); |