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);