From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Lennart Borgman Newsgroups: gmane.emacs.devel Subject: Re: [PATCH] system-type cygwin with window-system w32 Date: Thu, 21 Jul 2011 19:44:03 +0200 Message-ID: References: <4E246E75.6040807@gmx.de> <4E24726D.1080609@gmail.com> <4E2476BA.40201@gmail.com> <4E2480E6.5040306@gmx.de> <4E24855D.5030607@gmail.com> <4E249F37.3050101@gmx.de> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Trace: dough.gmane.org 1311270278 5677 80.91.229.12 (21 Jul 2011 17:44:38 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 21 Jul 2011 17:44:38 +0000 (UTC) Cc: Daniel Colascione , emacs-devel@gnu.org To: grischka Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Jul 21 19:44:33 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QjxIV-0007BO-KV for ged-emacs-devel@m.gmane.org; Thu, 21 Jul 2011 19:44:32 +0200 Original-Received: from localhost ([::1]:33930 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QjxIV-0008Hy-5q for ged-emacs-devel@m.gmane.org; Thu, 21 Jul 2011 13:44:31 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:41345) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QjxIR-0008HG-91 for emacs-devel@gnu.org; Thu, 21 Jul 2011 13:44:29 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QjxIO-0007Nv-SV for emacs-devel@gnu.org; Thu, 21 Jul 2011 13:44:27 -0400 Original-Received: from mail-ey0-f174.google.com ([209.85.215.174]:39287) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QjxIO-0007Nk-Ck for emacs-devel@gnu.org; Thu, 21 Jul 2011 13:44:24 -0400 Original-Received: by eyx24 with SMTP id 24so2698413eyx.19 for ; Thu, 21 Jul 2011 10:44:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type:content-transfer-encoding; bh=51pNAdcGWlXMEl5e1JF2Zn37BtkVl7jYh0iuywU9GfQ=; b=o+t2WaJ0B7seRZkiaI3n2s1Eir+zeBySH4fA91KxoSG8ltQbYWn0V9L6KRKuXl3lpU WG/lFrkP1PcMVlkmacrNDdlsEbdYRcvDL532uQCUid705/8Og0gWV2O1nlhBkMn9HGUU gqZm6AUQ7Kbz60BRc6fxg8IQUTW4fh0EBUz08= Original-Received: by 10.213.27.143 with SMTP id i15mr399938ebc.38.1311270263298; Thu, 21 Jul 2011 10:44:23 -0700 (PDT) Original-Received: by 10.213.114.16 with HTTP; Thu, 21 Jul 2011 10:44:03 -0700 (PDT) In-Reply-To: <4E249F37.3050101@gmx.de> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.215.174 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:142188 Archived-At: What happened to this? Is not this a very important problem? On Mon, Jul 18, 2011 at 23:01, grischka wrote: > Daniel Colascione wrote: >>> >>> Actually the NT build works quite well with one single thread. >>> Already tested here. >> >> Do you have a patch handy? > > Attached. =C2=A0Patch was against state at commit: > > =C2=A0 =C2=A0 =C2=A0Jan D. =C2=A02011-02-01 09:53:03 > =C2=A0 =C2=A0 =C2=A0Use add/delete_read_fd in xsmfns to simplify. =C2=A0A= lso ... > > Hopefully still applies cleanly. > > It is minimal, and maybe not quite obvious. =C2=A0Basically the two windo= w > message switches (w32fns.c and w32term.c) could be merged into one. > The patch calls the one from the other. > > There is an elisp variable 'w32-single-thread' which should return 1 > if you want to make sure you're using the right build. :) > > Note that you can for example drag the "Open File" dialog across the > main window and it still gets redrawn. > >>> * peek for messages in the QUIT macro (say via ELSE_PENDING_SIGNALS) >>> =C2=A0which is for C-g to interrupt lisp. >> >> I don't think this approach alone would be sufficient. =C2=A0I may be wr= ong, >> but I think the Windows window manager will consider a program to be >> "unresponsive" if it stops actually pumping messages; I don't think >> peeking is sufficient. =C2=A0Also, [1] says that we shouldn't delay pump= ing >> messages even if we're able to guarantee we'll get around to them later. >> (Running lisp code is indistinguishable from sleep in this case.) > >> Using PeekMessage in lisp code instead of actually pumping messages >> would be like telling your credit card company, "Yeah, I got the bill, >> and I'll get around to responding sometime in the next two years". =C2= =A0I >> don't think it'd go over well. > > "Two years" or anyway "indistinguishable from sleep" is never really > acceptable. =C2=A0Because then emacs can't process key/mouse events > regardless how many threads you have in the backend. > > We need to think in terms of UI timings here. =C2=A0Reference is the kbd > repeat rate, say 30ms, which is also in the range of eye perception > capability and frame repeat rates. =C2=A0Up to this is smooth. =C2=A0More= can > be tolerable though, even up to 1 or more seconds. =C2=A0Say for popping > up new windows, frames, etc. > > So if your elisp doesn't finish in 30ms, you know ;) > >>> * break command_loop_1() such that it can be used to handle just one >>> =C2=A0event which is to handle scrollbar messages because the widgets >>> =C2=A0run their own message loop deep in windows. =C2=A0Otherwise all t= he >>> =C2=A0scrolling would happen only after you release the mouse button. >> >> I doubt that the scrollbar is the only special case we'd need to conside= r. > > AFAICS scrollbar and paint. And maybe clipboard rendering. =C2=A0Emacs > handles paint directly via expose_frame() though, not via the event > queue. > >> I don't understand how this approach helps. =C2=A0The problem, AIUI, isn= 't >> that we have Lisp events, but that we read input and wait for processes >> in many places, and it's hard to be confident that each place we pump >> messages is a safe place to process lisp code. =C2=A0I don't understand = how >> draining the lisp event queue would help. > > As I see it this is just recursion. =C2=A0 Such things happen all the tim= e > in all GUIs that use callbacks. =C2=A0Windows, GTK, whatever. =C2=A0It ha= ppens > in emacs already: > > =C2=A0 =C2=A0 =C2=A0(run-with-idle-timer ... lisp-code) > > --- grischka > > > diff --git a/nt/config.nt b/nt/config.nt > index d612a41..dd4cd38 100644 > --- a/nt/config.nt > +++ b/nt/config.nt > @@ -467,6 +467,8 @@ extern char *getenv (); > =C2=A0#endif > =C2=A0#endif > > +#define SINGLE_THREAD > + > =C2=A0/* Redefine abort. =C2=A0*/ > =C2=A0#ifdef HAVE_NTGUI > =C2=A0#define abort =C2=A0w32_abort > diff --git a/src/keyboard.c b/src/keyboard.c > index d533213..e824682 100644 > --- a/src/keyboard.c > +++ b/src/keyboard.c > @@ -1290,7 +1290,7 @@ cancel_hourglass_unwind (Lisp_Object arg) > =C2=A0EXFUN (Fwindow_system, 1); > > =C2=A0Lisp_Object > -command_loop_1 (void) > +command_loop_1a (int repeat) > =C2=A0{ > =C2=A0 Lisp_Object cmd; > =C2=A0 Lisp_Object keybuf[30]; > @@ -1336,7 +1336,7 @@ command_loop_1 (void) > =C2=A0 if (!CONSP (last_command_event)) > =C2=A0 =C2=A0 current_kboard->Vlast_repeatable_command =3D real_this_comm= and; > > - =C2=A0while (1) > + =C2=A0while (repeat || detect_input_pending()) > =C2=A0 =C2=A0 { > =C2=A0 =C2=A0 =C2=A0 if (! FRAME_LIVE_P (XFRAME (selected_frame))) > =C2=A0 =C2=A0 =C2=A0 =C2=A0Fkill_emacs (Qnil); > @@ -1659,6 +1659,12 @@ command_loop_1 (void) > =C2=A0 =C2=A0 } > =C2=A0} > > +Lisp_Object > +command_loop_1 () > +{ > + =C2=A0 =C2=A0return command_loop_1a(1); > +} > + > =C2=A0/* Adjust point to a boundary of a region that has such a property > =C2=A0 =C2=A0that should be treated intangible. =C2=A0For the moment, we = check > =C2=A0 =C2=A0`composition', `display' and `invisible' properties. > diff --git a/src/lisp.h b/src/lisp.h > index cfff42a..efe76f6 100644 > --- a/src/lisp.h > +++ b/src/lisp.h > @@ -2013,6 +2013,10 @@ extern char *stack_bottom; > =C2=A0 =C2=A0This is a good thing to do around a loop that has no side ef= fects > =C2=A0 =C2=A0and (in particular) cannot call arbitrary Lisp code. =C2=A0*= / > > +#if defined HAVE_NTGUI && defined SINGLE_THREAD > +#define ELSE_PENDING_SIGNALS else w32_peek_messages(); > +void w32_peek_messages(); > +#else > =C2=A0#ifdef SYNC_INPUT > =C2=A0extern void process_pending_signals (void); > =C2=A0extern int pending_signals; > @@ -2022,6 +2026,7 @@ extern int pending_signals; > =C2=A0#else =C2=A0/* not SYNC_INPUT */ > =C2=A0#define ELSE_PENDING_SIGNALS > =C2=A0#endif /* not SYNC_INPUT */ > +#endif /* not HAVE_NTGUI */ > > =C2=A0#define QUIT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 \ > =C2=A0 do { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 \ > diff --git a/src/w32fns.c b/src/w32fns.c > index b09bb0b..93f80f9 100644 > --- a/src/w32fns.c > +++ b/src/w32fns.c > @@ -87,6 +87,10 @@ extern const char *const lispy_function_keys[]; > =C2=A0static unsigned hourglass_timer =3D 0; > =C2=A0static HWND hourglass_hwnd =3D NULL; > > +#ifdef SINGLE_THREAD > +int w32_single_thread; > +#endif > + > =C2=A0#ifndef IDC_HAND > =C2=A0#define IDC_HAND MAKEINTRESOURCE(32649) > =C2=A0#endif > @@ -2242,17 +2246,15 @@ unregister_hot_keys (HWND hwnd) > > =C2=A0/* Main message dispatch loop. */ > > -static void > -w32_msg_pump (deferred_msg * msg_buf) > +unsigned dispatch_msg (MSG *pmsg) > =C2=A0{ > =C2=A0 MSG msg; > =C2=A0 int result; > =C2=A0 HWND focus_window; > > - =C2=A0msh_mousewheel =3D RegisterWindowMessage (MSH_MOUSEWHEEL); > + =C2=A0result =3D 0; > + =C2=A0msg =3D *pmsg; > > - =C2=A0while (GetMessage (&msg, NULL, 0, 0)) > - =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 if (msg.hwnd =3D=3D NULL) > =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (msg.message) > @@ -2269,8 +2271,10 @@ w32_msg_pump (deferred_msg * msg_buf) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0and older v= ersions will never be patched. =C2=A0*/ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 CoInitialize (NULL); > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0w32_createwindow ((struct= frame *) msg.wParam); > +#ifndef SINGLE_THREAD > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!PostThreadMessage (d= wMainThreadId, WM_EMACS_DONE, 0, 0)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0abort (); > +#endif > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case WM_EMACS_SETLOCALE: > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0SetThreadLocale (msg.wPar= am); > @@ -2278,9 +2282,11 @@ w32_msg_pump (deferred_msg * msg_buf) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case WM_EMACS_SETKEYBOARDLAYOUT: > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D (int) Activate= KeyboardLayout ((HKL) msg.wParam, 0); > +#ifndef SINGLE_THREAD > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!PostThreadMessage (d= wMainThreadId, WM_EMACS_DONE, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result, 0)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0abort (); > +#endif > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case WM_EMACS_REGISTER_HOT_KEY: > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0focus_window =3D GetFocus= (); > @@ -2300,8 +2306,10 @@ w32_msg_pump (deferred_msg * msg_buf) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cell is nev= er made into garbage and is not relocated by > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0GC. =C2=A0*= / > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0XSETCAR ((Lisp_Object) ((= EMACS_INT) msg.lParam), Qnil); > +#ifndef SINGLE_THREAD > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!PostThreadMessage (d= wMainThreadId, WM_EMACS_DONE, 0, 0)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0abort (); > +#endif > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case WM_EMACS_TOGGLE_LOCK_KEY: > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > @@ -2331,9 +2339,12 @@ w32_msg_pump (deferred_msg * msg_buf) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KE= YUP, 0); > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cur_= state =3D !cur_state; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > +#ifndef SINGLE_THREAD > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!PostThreadMes= sage (dwMainThreadId, WM_EMACS_DONE, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cur_state= , 0)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0abort (); > +#endif > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 result =3D cur_state; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > =C2=A0#ifdef MSG_DEBUG > @@ -2349,11 +2360,37 @@ w32_msg_pump (deferred_msg * msg_buf) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DispatchMessage (&msg); > =C2=A0 =C2=A0 =C2=A0 =C2=A0} > > + =C2=A0 =C2=A0return result; > +} > + > +static void > +w32_msg_pump (deferred_msg * msg_buf) > +{ > +#ifndef SINGLE_THREAD > + =C2=A0MSG msg; > + =C2=A0msh_mousewheel =3D RegisterWindowMessage (MSH_MOUSEWHEEL); > + =C2=A0while (GetMessage (&msg, NULL, 0, 0)) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0dispatch_msg(&msg); > =C2=A0 =C2=A0 =C2=A0 /* Exit nested loop when our deferred message has co= mpleted. =C2=A0*/ > =C2=A0 =C2=A0 =C2=A0 if (msg_buf->completed) > =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > =C2=A0 =C2=A0 } > +#endif > +} > + > +#ifdef SINGLE_THREAD > +unsigned do_thread_msg(unsigned threadid, unsigned umsg, WPARAM wParam, > LPARAM lParam) > +{ > + =C2=A0 =C2=A0MSG msg; > + =C2=A0 =C2=A0msg.hwnd =3D NULL; > + =C2=A0 =C2=A0msg.message =3D umsg; > + =C2=A0 =C2=A0msg.wParam =3D wParam; > + =C2=A0 =C2=A0msg.lParam =3D lParam; > + =C2=A0 =C2=A0return dispatch_msg(&msg); > =C2=A0} > +#endif > + > > =C2=A0deferred_msg * deferred_msg_head; > > @@ -2427,7 +2464,9 @@ complete_deferred_msg (HWND hwnd, UINT msg, LRESULT > result) > =C2=A0 msg_buf->completed =3D 1; > > =C2=A0 /* Ensure input thread is woken so it notices the completion. =C2= =A0*/ > +#ifndef SINGLE_THREAD > =C2=A0 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0); > +#endif > =C2=A0} > > =C2=A0static void > @@ -2448,7 +2487,9 @@ cancel_all_deferred_msgs (void) > =C2=A0 /* leave_crit (); */ > > =C2=A0 /* Ensure input thread is woken so it notices the completion. =C2= =A0*/ > +#ifndef SINGLE_THREAD > =C2=A0 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0); > +#endif > =C2=A0} > > =C2=A0DWORD WINAPI > @@ -2654,6 +2695,10 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, > LPARAM lParam) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dedicated to one frame a= nd does not bother checking > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 that hwnd matches before= combining them. =C2=A0*/ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 my_post_msg (&wmsg, hwnd, WM_EM= ACS_PAINT, wParam, lParam); > +#ifdef SINGLE_THREAD > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0w32_read_socket(0, 0, NULL); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0//command_loop_1a(0); > +#endif > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 0; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 } > @@ -3205,6 +3250,10 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, > LPARAM lParam) > =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0wmsg.dwModifiers =3D w32_get_modifiers = (); > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0my_post_msg (&wmsg, hwnd, msg, wParam, = lParam); > +#ifdef SINGLE_THREAD > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (msg =3D=3D WM_VSCROLL) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0command_loop_1a(0); > +#endif > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > =C2=A0 =C2=A0 =C2=A0 =C2=A0} > > @@ -3808,11 +3857,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, > LPARAM lParam) > =C2=A0static void > =C2=A0my_create_window (struct frame * f) > =C2=A0{ > +#ifdef SINGLE_THREAD > + =C2=A0do_thread_msg (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)= f, 0); > +#else > =C2=A0 MSG msg; > > =C2=A0 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, > (WPARAM)f, 0)) > =C2=A0 =C2=A0 abort (); > =C2=A0 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE); > +#endif > =C2=A0} > > > @@ -6308,6 +6361,15 @@ The return value is the hotkey-id if registered, > otherwise nil. =C2=A0*/) > > =C2=A0 =C2=A0 =C2=A0 /* Notify input thread about new hot-key definition,= so that it > =C2=A0 =C2=A0 =C2=A0 =C2=A0 takes effect without needing to switch focus.= =C2=A0*/ > +#ifdef SINGLE_THREAD > +#ifdef USE_LISP_UNION_TYPE > + =C2=A0 =C2=A0 =C2=A0do_thread_msg (dwWindowsThreadId, WM_EMACS_REGISTER= _HOT_KEY, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (WPARAM) key.i, 0); > +#else > + =C2=A0 =C2=A0 =C2=A0do_thread_msg (dwWindowsThreadId, WM_EMACS_REGISTER= _HOT_KEY, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (WPARAM) key, 0); > +#endif > +#else > =C2=A0#ifdef USE_LISP_UNION_TYPE > =C2=A0 =C2=A0 =C2=A0 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGIS= TER_HOT_KEY, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (WPARAM) key.i, 0); > @@ -6315,6 +6377,7 @@ The return value is the hotkey-id if registered, > otherwise nil. =C2=A0*/) > =C2=A0 =C2=A0 =C2=A0 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGIS= TER_HOT_KEY, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (WPARAM) key, 0); > =C2=A0#endif > +#endif > =C2=A0 =C2=A0 } > > =C2=A0 return key; > @@ -6336,6 +6399,16 @@ DEFUN ("w32-unregister-hot-key", > Fw32_unregister_hot_key, > =C2=A0 =C2=A0 { > =C2=A0 =C2=A0 =C2=A0 /* Notify input thread about hot-key definition bein= g removed, so > =C2=A0 =C2=A0 =C2=A0 =C2=A0 that it takes effect without needing focus sw= itch. =C2=A0*/ > +#ifdef SINGLE_THREAD > +#ifdef USE_LISP_UNION_TYPE > + =C2=A0 =C2=A0 =C2=A0do_thread_msg (dwWindowsThreadId, WM_EMACS_UNREGIST= ER_HOT_KEY, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 (WPARAM) XINT (XCAR (item)), (LPARAM) item.i); > +#else > + =C2=A0 =C2=A0 =C2=A0do_thread_msg (dwWindowsThreadId, WM_EMACS_UNREGIST= ER_HOT_KEY, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 (WPARAM) XINT (XCAR (item)), (LPARAM) item); > + > +#endif > +#else > =C2=A0#ifdef USE_LISP_UNION_TYPE > =C2=A0 =C2=A0 =C2=A0 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_U= NREGISTER_HOT_KEY, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (WPARAM) XINT (XCAR (item)), (LPARAM) item.i)) > @@ -6347,6 +6420,7 @@ DEFUN ("w32-unregister-hot-key", > Fw32_unregister_hot_key, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MSG msg; > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0GetMessage (&msg, NULL, WM_EMACS_DONE, = WM_EMACS_DONE); > =C2=A0 =C2=A0 =C2=A0 =C2=A0} > +#endif > =C2=A0 =C2=A0 =C2=A0 return Qt; > =C2=A0 =C2=A0 } > =C2=A0 return Qnil; > @@ -6401,6 +6475,9 @@ is set to off if the low bit of NEW-STATE is zero, > otherwise on. =C2=A0*/) > =C2=A0 (Lisp_Object key, Lisp_Object new_state) > =C2=A0{ > =C2=A0 int vk_code; > +#ifdef SINGLE_THREAD > + =C2=A0unsigned ret; > +#endif > > =C2=A0 if (EQ (key, intern ("capslock"))) > =C2=A0 =C2=A0 vk_code =3D VK_CAPITAL; > @@ -6414,6 +6491,16 @@ is set to off if the low bit of NEW-STATE is zero, > otherwise on. =C2=A0*/) > =C2=A0 if (!dwWindowsThreadId) > =C2=A0 =C2=A0 return make_number (w32_console_toggle_lock_key (vk_code, n= ew_state)); > > +#ifdef SINGLE_THREAD > +#ifdef USE_LISP_UNION_TYPE > + =C2=A0ret =3D do_thread_msg (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KE= Y, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (WPARAM) vk_code, (LPARAM) new_state.i); > +#else > + =C2=A0ret =3D do_thread_msg (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KE= Y, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 (WPARAM) vk_code, (LPARAM) new_state); > +#endif > + =C2=A0return make_number (ret); > +#else > =C2=A0#ifdef USE_LISP_UNION_TYPE > =C2=A0 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY= , > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (WPARAM) vk_code, (LPARAM) new_state.i)) > @@ -6427,6 +6514,7 @@ is set to off if the low bit of NEW-STATE is zero, > otherwise on. =C2=A0*/) > =C2=A0 =C2=A0 =C2=A0 return make_number (msg.wParam); > =C2=A0 =C2=A0 } > =C2=A0 return Qnil; > +#endif > =C2=A0} > > =C2=A0DEFUN ("w32-window-exists-p", Fw32_window_exists_p, Sw32_window_exi= sts_p, > @@ -7053,6 +7141,14 @@ Set this to nil to get the old behavior for > repainting; this should > =C2=A0only be necessary if the default setting causes problems. =C2=A0*/)= ; > =C2=A0 w32_strict_painting =3D 1; > > +#ifdef SINGLE_THREAD > + =C2=A0DEFVAR_BOOL ("w32-single-thread", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&w32_single_thread, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0doc: /* using single th= read */); > + > + =C2=A0w32_single_thread =3D 1; > +#endif > + > =C2=A0#if 0 /* TODO: Port to W32 */ > =C2=A0 defsubr (&Sx_change_window_property); > =C2=A0 defsubr (&Sx_delete_window_property); > diff --git a/src/w32proc.c b/src/w32proc.c > index 1c009c7..49eab27 100644 > --- a/src/w32proc.c > +++ b/src/w32proc.c > @@ -2028,7 +2028,11 @@ If successful, the new locale id is returned, > otherwise nil. =C2=A0*/) > =C2=A0 /* Need to set input thread locale if present. =C2=A0*/ > =C2=A0 if (dwWindowsThreadId) > =C2=A0 =C2=A0 /* Reply is not needed. =C2=A0*/ > +#ifdef SINGLE_THREAD > + =C2=A0 =C2=A0do_thread_msg (dwWindowsThreadId, WM_EMACS_SETLOCALE, XINT= (lcid), 0); > +#else > =C2=A0 =C2=A0 PostThreadMessage (dwWindowsThreadId, WM_EMACS_SETLOCALE, X= INT (lcid), > 0); > +#endif > > =C2=A0 return make_number (GetThreadLocale ()); > =C2=A0} > @@ -2194,6 +2198,10 @@ If successful, the new layout id is returned, > otherwise nil. =C2=A0*/) > =C2=A0 /* Synchronize layout with input thread. =C2=A0*/ > =C2=A0 if (dwWindowsThreadId) > =C2=A0 =C2=A0 { > +#ifdef SINGLE_THREAD > + =C2=A0 =C2=A0 =C2=A0if (0 =3D=3D do_thread_msg (dwWindowsThreadId, > WM_EMACS_SETKEYBOARDLAYOUT, (WPARAM) kl, 0)) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return Qnil; > +#else > =C2=A0 =C2=A0 =C2=A0 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_S= ETKEYBOARDLAYOUT, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (WPARAM) kl, 0)) > =C2=A0 =C2=A0 =C2=A0 =C2=A0{ > @@ -2203,6 +2211,7 @@ If successful, the new layout id is returned, > otherwise nil. =C2=A0*/) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (msg.wParam =3D=3D 0) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return Qnil; > =C2=A0 =C2=A0 =C2=A0 =C2=A0} > +#endif > =C2=A0 =C2=A0 } > =C2=A0 else if (!ActivateKeyboardLayout ((HKL) kl, 0)) > =C2=A0 =C2=A0 return Qnil; > diff --git a/src/w32term.c b/src/w32term.c > index cd4ee54..83eed4a 100644 > --- a/src/w32term.c > +++ b/src/w32term.c > @@ -4018,7 +4018,7 @@ static char dbcs_lead =3D 0; > =C2=A0 =C2=A0recursively with different messages by the system. > =C2=A0*/ > > -static int > +int > =C2=A0w32_read_socket (struct terminal *terminal, int expected, > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 struct input_even= t *hold_quit) > =C2=A0{ > @@ -6294,6 +6294,12 @@ w32_initialize (void) > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GetCurrent= Process (), &hMainThread, 0, TRUE, > DUPLICATE_SAME_ACCESS); > > =C2=A0 /* Wait for thread to start */ > +#ifdef SINGLE_THREAD > + =C2=A0DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 GetCurre= ntProcess (), &hWindowsThread, 0, TRUE, > DUPLICATE_SAME_ACCESS); > + =C2=A0dwWindowsThreadId =3D GetCurrentThreadId (); > + =C2=A0msh_mousewheel =3D RegisterWindowMessage (MSH_MOUSEWHEEL); > +#else > =C2=A0 { > =C2=A0 =C2=A0 MSG msg; > > @@ -6305,6 +6311,7 @@ w32_initialize (void) > > =C2=A0 =C2=A0 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE); > =C2=A0 } > +#endif > > =C2=A0 /* It is desirable that mainThread should have the same notion of > =C2=A0 =C2=A0 =C2=A0focus window and active window as windowsThread. =C2= =A0Unfortunately, the > diff --git a/src/w32xfns.c b/src/w32xfns.c > index df9acca..a3c1af4 100644 > --- a/src/w32xfns.c > +++ b/src/w32xfns.c > @@ -299,11 +299,19 @@ drain_message_queue (void) > =C2=A0 MSG msg; > =C2=A0 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) > =C2=A0 =C2=A0 { > +#ifdef SINGLE_THREAD > + =C2=A0 =C2=A0 =C2=A0dispatch_msg(&msg); > +#else > =C2=A0 =C2=A0 =C2=A0 TranslateMessage (&msg); > =C2=A0 =C2=A0 =C2=A0 DispatchMessage (&msg); > +#endif > =C2=A0 =C2=A0 } > =C2=A0} > > +void w32_peek_messages() > +{ > + =C2=A0 =C2=A0drain_message_queue (); > +} > > =C2=A0/* > =C2=A0* =C2=A0 =C2=A0XParseGeometry parses strings of the form > >