Ultimately based on FSF.
Rewritten by Ben Wing.
Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
+ Subprocess and modal loop support by Kirill M. Katsnelson.
*/
#include <config.h>
#include "device.h"
#include "events.h"
#include "frame.h"
+#include "buffer.h"
+#include "faces.h"
#include "lstream.h"
#include "process.h"
#include "redisplay.h"
+#include "select.h"
#include "sysproc.h"
#include "syswait.h"
#include "systime.h"
#include "sysdep.h"
+#include "objects-msw.h"
#include "events-mod.h"
#ifdef HAVE_MSG_SELECT
#include "sysfile.h"
+#include "console-tty.h"
#elif defined(__CYGWIN32__)
typedef unsigned int SOCKET;
#endif
#include <io.h>
#include <errno.h>
+#if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20)
+typedef NMHDR *LPNMHDR;
+#endif
+
#ifdef HAVE_MENUBARS
#define ADJR_MENUFLAG TRUE
#else
/* Timer ID used for button2 emulation */
#define BUTTON_2_TIMER_ID 1
-extern Lisp_Object
+extern Lisp_Object
mswindows_get_toolbar_button_text (struct frame* f, int command_id);
extern Lisp_Object
mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
+extern Lisp_Object
+mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
static Lisp_Object mswindows_find_frame (HWND hwnd);
static Lisp_Object mswindows_find_console (HWND hwnd);
-static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
+static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
+ int extendedp);
static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
static void mswindows_set_chord_timer (HWND hwnd);
static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
/* The number of things we can wait on */
#define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
+#ifndef HAVE_MSG_SELECT
/* List of mswindows waitable handles. */
static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
/* Number of wait handles */
static int mswindows_waitable_count=0;
+#endif /* HAVE_MSG_SELECT */
+/* Brush for painting widgets */
+static HBRUSH widget_brush = 0;
+static LONG last_widget_brushed = 0;
/* Count of quit chars currently in the queue */
/* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
/* These are Lisp integers; see DEFVARS in this file for description. */
int mswindows_dynamic_frame_resize;
+int mswindows_meta_activates_menu;
int mswindows_num_mouse_buttons;
int mswindows_mouse_button_max_skew_x;
int mswindows_mouse_button_max_skew_y;
};
#define MAX_SLURP_STREAMS 32
-struct ntpipe_slurp_stream_shared_data
+struct ntpipe_slurp_stream_shared_data
shared_data_block[MAX_SLURP_STREAMS]={{0}};
struct ntpipe_slurp_stream
/* Now we got something to notify caller, either a byte or an
error/eof indication. Before we do, allow internal pipe
- buffer to accumulate little bit more data.
+ buffer to accumulate little bit more data.
Reader function pulses this event before waiting for
a character, to avoid pipe delay, and to get the byte
immediately. */
return s->thread_data->hev_caller;
}
-static int
+static ssize_t
ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
{
/* This function must be called from the main thread only */
- struct ntpipe_slurp_stream_shared_data* s =
+ struct ntpipe_slurp_stream_shared_data* s =
NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
if (!s->die_p)
/* Disallow pipe read delay for the thread: we need a character
ASAP */
SetEvent (s->hev_unsleep);
-
+
/* Check if we have a character ready. Give it a short delay,
for the thread to awake from pipe delay, just ion case*/
wait_result = WaitForSingleObject (s->hev_caller, 2);
ReadFile (s->hpipe, data, min (bytes_available, size),
&bytes_read, NULL);
}
-
+
/* Now we can unblock thread, so it attempts to read more */
SetEvent (s->hev_thread);
return bytes_read + 1;
return 0;
}
-static int
+static int
ntpipe_slurp_closer (Lstream *stream)
{
/* This function must be called from the main thread only */
- struct ntpipe_slurp_stream_shared_data* s =
+ struct ntpipe_slurp_stream_shared_data* s =
NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
/* Force thread to stop */
LSTREAM_TYPE_DATA (stream, ntpipe_shove)
#define MAX_SHOVE_BUFFER_SIZE 128
-
+
struct ntpipe_shove_stream
{
LPARAM user_data; /* Any user data stored in the stream object */
DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
sizeof (struct ntpipe_shove_stream));
+#ifndef HAVE_MSG_SELECT
static DWORD WINAPI
shove_thread (LPVOID vparam)
{
for (;;)
{
- DWORD bytes_written;
+ DWORD bytes_written;
/* Block on event and wait for a job */
InterlockedIncrement (&s->idle_p);
s->hpipe = hpipe;
s->user_data = param;
- /* Create reader thread. This could fail, so do not
+ /* Create reader thread. This could fail, so do not
create the event until thread is created */
s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
CREATE_SUSPENDED, &thread_id_unused);
struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
return s->user_data;
}
+#endif
-static int
+static ssize_t
ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
{
struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
str->eof_p = 1;
}
-static int
+static ssize_t
winsock_reader (Lstream *stream, unsigned char *data, size_t size)
{
struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
return 0;
if (str->error_p)
return -1;
-
+
/* Return as much of buffer as we have */
size = min (size, (size_t) (str->bufsize - str->bufpos));
memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
return size;
}
-static int
+static ssize_t
winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
{
struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
if (size == 0)
return 0;
-
+
{
ResetEvent (str->ov.hEvent);
|| sevt->event_type == misc_user_event);
}
-/*
+/*
* Add an emacs event to the proper dispatch queue
*/
static void
{
int user_p = mswindows_user_event_p (XEVENT(event));
enqueue_event (event,
- user_p ? &mswindows_u_dispatch_event_queue :
+ user_p ? &mswindows_u_dispatch_event_queue :
&mswindows_s_dispatch_event_queue,
user_p ? &mswindows_u_dispatch_event_queue_tail :
&mswindows_s_dispatch_event_queue_tail);
event->event.button.x = where.x;
event->event.button.y = where.y;
event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
-
+
if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
message==WM_RBUTTONDOWN)
{
event->event_type = button_press_event;
SetCapture (hwnd);
+ /* we need this to make sure the main window regains the focus
+ from control subwindows */
+ if (GetFocus() != hwnd)
+ {
+ SetFocus (hwnd);
+ mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
+ }
}
else
{
event->event_type = button_release_event;
ReleaseCapture ();
}
-
+
mswindows_enqueue_dispatch_event (emacs_event);
}
!NILP(mswindows_s_dispatch_event_queue));
event = dequeue_event (
- NILP(mswindows_u_dispatch_event_queue) ?
- &mswindows_s_dispatch_event_queue :
+ NILP(mswindows_u_dispatch_event_queue) ?
+ &mswindows_s_dispatch_event_queue :
&mswindows_u_dispatch_event_queue,
- NILP(mswindows_u_dispatch_event_queue) ?
+ NILP(mswindows_u_dispatch_event_queue) ?
&mswindows_s_dispatch_event_queue_tail :
&mswindows_u_dispatch_event_queue_tail);
/*
* Remove and return the first emacs event on the dispatch queue that matches
- * the supplied event
- * Timeout event matches if interval_id equals to that of the given event.
+ * the supplied event.
+ * Timeout event matches if interval_id is equal to that of the given event.
* Keypress event matches if logical AND between modifiers bitmask of the
- * event in the queue and that of the given event is non-zero
- * For all other event types, this function asserts.
+ * event in the queue and that of the given event is non-zero.
+ * For all other event types, this function aborts.
*/
Lisp_Object
-mswindows_cancel_dispatch_event (struct Lisp_Event* match)
+mswindows_cancel_dispatch_event (struct Lisp_Event *match)
{
Lisp_Object event;
- Lisp_Object previous_event=Qnil;
+ Lisp_Object previous_event = Qnil;
int user_p = mswindows_user_event_p (match);
- Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
+ Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
&mswindows_s_dispatch_event_queue;
- Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
+ Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
&mswindows_s_dispatch_event_queue_tail;
assert (match->event_type == timeout_event
EVENT_CHAIN_LOOP (event, *head)
{
- int found = 1;
- if (XEVENT_TYPE (event) != match->event_type)
- found = 0;
- if (found && match->event_type == timeout_event
- && (XEVENT(event)->event.timeout.interval_id !=
- match->event.timeout.interval_id))
- found = 0;
- if (found && match->event_type == key_press_event
- && ((XEVENT(event)->event.key.modifiers &
- match->event.key.modifiers) == 0))
- found = 0;
-
- if (found)
+ struct Lisp_Event *e = XEVENT (event);
+ if ((e->event_type == match->event_type) &&
+ ((e->event_type == timeout_event) ?
+ (e->event.timeout.interval_id == match->event.timeout.interval_id) :
+ /* Must be key_press_event */
+ ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
{
if (NILP (previous_event))
dequeue_event (head, tail);
if (EQ (*tail, event))
*tail = previous_event;
}
-
+
return event;
}
previous_event = event;
return Qnil;
}
\f
+#ifndef HAVE_MSG_SELECT
/************************************************************************/
/* Waitable handles manipulation */
/************************************************************************/
if (ix < 0)
return;
- mswindows_waitable_handles [ix] =
+ mswindows_waitable_handles [ix] =
mswindows_waitable_handles [--mswindows_waitable_count];
}
+#endif /* HAVE_MSG_SELECT */
\f
/************************************************************************/
{
Lisp_Object tmp;
- ++mswindows_in_modal_loop;
+ ++mswindows_in_modal_loop;
tmp = condition_case_1 (Qt,
bfun, barg,
mswindows_modal_loop_error_handler, Qnil);
}
/*
- * This is an unsafe part of event pump, guarded by
+ * This is an unsafe part of event pump, guarded by
* condition_case. See mswindows_pump_outstanding_events
*/
static Lisp_Object
Fdeallocate_event (event);
UNGCPRO;
-
+
/* Qt becomes return value of mswindows_pump_outstanding_events
once we get here */
return Qt;
Lisp_Object result = Qt;
struct gcpro gcpro1;
GCPRO1 (result);
-
+
if (NILP(mswindows_error_caught_in_modal_loop))
result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
UNGCPRO;
return result;
}
-static void
+static void
mswindows_drain_windows_queue ()
{
MSG msg;
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
+ /* we have to translate messages that are not sent to the main
+ window. this is so that key presses work ok in things like
+ edit fields. however, we *musn't* translate message for the
+ main window as this is handled in the wnd proc. */
+ if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
+ {
+ TranslateMessage (&msg);
+ }
DispatchMessage (&msg);
mswindows_unmodalize_signal_maybe ();
}
}
-/*
+/*
* This is a special flavor of the mswindows_need_event function,
* used while in event pump. Actually, there is only kind of events
* allowed while in event pump: a timer. An attempt to fetch any
/* We'll deadlock if go waiting */
if (mswindows_pending_timers_count == 0)
error ("Deadlock due to an attempt to call next-event in a wrong context");
-
+
/* Fetch and dispatch any pending timers */
GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
DispatchMessage (&msg);
SELECT_TYPE temp_mask = input_wait_mask;
EMACS_TIME sometime;
EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
-
+
if (badly_p)
pointer_to_this = 0;
else
pointer_to_this = &select_time_to_block;
}
- /* select() is slow and buggy so if we don't have any processes
- just wait as normal */
- if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
- {
- /* Now try getting a message or process event */
- active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
- FALSE, badly_p ? INFINITE : 0,
- QS_ALLINPUT);
-
- if (active == WAIT_TIMEOUT)
- {
- /* No luck trying - just return what we've already got */
- return;
- }
- else if (active == WAIT_OBJECT_0)
- {
- /* Got your message, thanks */
- mswindows_drain_windows_queue ();
- continue;
- }
- }
-
active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
-
+
if (active == 0)
{
+ assert (!badly_p);
return; /* timeout */
}
else if (active > 0)
{
mswindows_drain_windows_queue ();
}
-
+#ifdef HAVE_TTY
+ /* Look for a TTY event */
+ for (i = 0; i < MAXDESC-1; i++)
+ {
+ /* To avoid race conditions (among other things, an infinite
+ loop when called from Fdiscard_input()), we must return
+ user events ahead of process events. */
+ if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
+ {
+ struct console *c = tty_find_console_from_fd (i);
+ Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+ struct Lisp_Event* event = XEVENT (emacs_event);
+
+ assert (c);
+ if (read_event_from_tty_or_stream_desc (event, c, i))
+ {
+ mswindows_enqueue_dispatch_event (emacs_event);
+ return;
+ }
+ }
+ }
+#endif
/* Look for a process event */
for (i = 0; i < MAXDESC-1; i++)
{
{
struct Lisp_Process *p =
get_process_from_usid (FD_TO_USID(i));
-
+
mswindows_enqueue_process_event (p);
}
- else if (FD_ISSET (i, &tty_only_mask))
- {
- /* do we care about tty events? Do we
- ever get tty events? */
- }
else
{
/* We might get here when a fake event came
assert ((!badly_p && active == WAIT_TIMEOUT) ||
(active >= WAIT_OBJECT_0 &&
active <= WAIT_OBJECT_0 + mswindows_waitable_count));
-
+
if (active == WAIT_TIMEOUT)
{
/* No luck trying - just return what we've already got */
{
int ix = active - WAIT_OBJECT_0;
/* First, try to find which process' output has signaled */
- struct Lisp_Process *p =
+ struct Lisp_Process *p =
get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
if (p != NULL)
{
/* Event generators */
/************************************************************************/
-/*
+/*
* Callback procedure for synchronous timer messages
*/
static void CALLBACK
event->timestamp = dwtime;
event->event_type = timeout_event;
event->event.timeout.interval_id = id_timer;
+ event->event.timeout.function = Qnil;
+ event->event.timeout.object = Qnil;
mswindows_enqueue_dispatch_event (emacs_event);
}
-/*
+/*
* Callback procedure for dde messages
*
* We execute a dde Open("file") by simulating a file drop, so dde support
mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
DWORD dwData1, DWORD dwData2)
-{
+{
switch (uType)
- {
+ {
case XTYP_CONNECT:
if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
return (HDDEDATA)TRUE;
return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
sizeof (pairs), 0L, 0, uFmt, 0));
}
- return (HDDEDATA)NULL;
+ return (HDDEDATA)NULL;
case XTYP_EXECUTE:
if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
UNGCPRO;
return (HDDEDATA) DDE_FACK;
}
- DdeFreeDataHandle (hdata);
+ DdeFreeDataHandle (hdata);
return (HDDEDATA) DDE_FNOTPROCESSED;
- default:
- return (HDDEDATA) NULL;
- }
+ default:
+ return (HDDEDATA) NULL;
+ }
}
#endif
switch (message)
{
+ case WM_DESTROYCLIPBOARD:
+ /* We own the clipboard and someone else wants it. Delete our
+ cached copy of the clipboard contents so we'll ask for it from
+ Windows again when someone does a paste. */
+ handle_selection_clear(QCLIPBOARD);
+ break;
+
case WM_ERASEBKGND:
/* Erase background only during non-dynamic sizing */
msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
BYTE keymap[256];
int has_AltGr = mswindows_current_layout_has_AltGr ();
int mods;
+ int extendedp = lParam & 0x1000000;
Lisp_Object keysym;
GetKeyboardState (keymap);
mods = mswindows_modifier_state (keymap, has_AltGr);
- /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
- if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
+ /* Handle non-printables */
+ if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
+ extendedp)))
mswindows_enqueue_keypress_event (hwnd, keysym, mods);
- else
+ else /* Normal keys & modifiers */
{
int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
BYTE keymap_orig[256];
- MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
+ POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
+ MSG msg;
+
+ msg.hwnd = hwnd;
+ msg.message = message;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.time = GetMessageTime();
+ msg.pt = pnt;
/* GetKeyboardState() does not work as documented on Win95. We have
* to loosely track Left and Right modifiers on behalf of the OS,
* without screwing up Windows NT which tracks them properly. */
if (wParam == VK_CONTROL)
- keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+ keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
else if (wParam == VK_MENU)
- keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
+ keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
memcpy (keymap_orig, keymap, 256);
} /* else */
}
/* F10 causes menu activation by default. We do not want this */
- if (wParam != VK_F10)
+ if (wParam != VK_F10 && (mswindows_meta_activates_menu || wParam != VK_MENU))
goto defproc;
break;
mswindows_enqueue_mouse_button_event (hwnd, message,
MAKEPOINTS (lParam), GetMessageTime());
break;
-
+
case WM_LBUTTONUP:
msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
msframe->last_click_time = GetMessageTime();
}
msframe->last_click_time = GetMessageTime();
break;
-
+
case WM_TIMER:
if (wParam == BUTTON_2_TIMER_ID)
{
event->event.motion.x = MAKEPOINTS(lParam).x;
event->event.motion.y = MAKEPOINTS(lParam).y;
event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
-
+
mswindows_enqueue_dispatch_event (emacs_event);
}
break;
Qcancel_mode_internal, Qnil);
break;
-#ifdef HAVE_TOOLBARS
case WM_NOTIFY:
{
- LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
- Lisp_Object btext;
- if (tttext->hdr.code == TTN_NEEDTEXT)
+ LPNMHDR nmhdr = (LPNMHDR)lParam;
+
+ if (nmhdr->code == TTN_NEEDTEXT)
{
+#ifdef HAVE_TOOLBARS
+ LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
+ Lisp_Object btext;
+
/* find out which toolbar */
frame = XFRAME (mswindows_find_frame (hwnd));
- btext = mswindows_get_toolbar_button_text ( frame,
- tttext->hdr.idFrom );
-
+ btext = mswindows_get_toolbar_button_text ( frame,
+ nmhdr->idFrom );
+
tttext->lpszText = NULL;
tttext->hinst = NULL;
{
/* I think this is safe since the text will only go away
when the toolbar does...*/
- tttext->lpszText=XSTRING_DATA (btext);
+ GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS,
+ tttext->lpszText);
}
-#if 0
- tttext->uFlags |= TTF_DI_SETITEM;
#endif
- }
+ }
+ /* handle tree view callbacks */
+ else if (nmhdr->code == TVN_SELCHANGED)
+ {
+ NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
+ frame = XFRAME (mswindows_find_frame (hwnd));
+ mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
+ }
+ /* handle tab control callbacks */
+ else if (nmhdr->code == TCN_SELCHANGE)
+ {
+ TC_ITEM item;
+ int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
+ frame = XFRAME (mswindows_find_frame (hwnd));
+
+ item.mask = TCIF_PARAM;
+ SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
+ (LPARAM)&item);
+
+ mswindows_handle_gui_wm_command (frame, 0, item.lParam);
+ }
}
break;
-#endif
-
+
case WM_PAINT:
{
- PAINTSTRUCT paintStruct;
-
- frame = XFRAME (mswindows_find_frame (hwnd));
+ /* According to the docs we need to check GetUpdateRect() before
+ actually doing a WM_PAINT */
+ if (GetUpdateRect (hwnd, NULL, FALSE))
+ {
+ PAINTSTRUCT paintStruct;
+ int x, y, width, height;
- BeginPaint (hwnd, &paintStruct);
- mswindows_redraw_exposed_area (frame,
- paintStruct.rcPaint.left, paintStruct.rcPaint.top,
- paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
- EndPaint (hwnd, &paintStruct);
+ frame = XFRAME (mswindows_find_frame (hwnd));
+
+ BeginPaint (hwnd, &paintStruct);
+ x = paintStruct.rcPaint.left;
+ y = paintStruct.rcPaint.top;
+ width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
+ height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
+ /* Normally we want to ignore expose events when child
+ windows are unmapped, however once we are in the guts of
+ WM_PAINT we need to make sure that we don't register
+ unmaps then because they will not actually occur. */
+ if (!check_for_ignored_expose (frame, x, y, width, height))
+ {
+ hold_ignored_expose_registration = 1;
+ mswindows_redraw_exposed_area (frame, x, y, width, height);
+ hold_ignored_expose_registration = 0;
+ }
+
+ EndPaint (hwnd, &paintStruct);
+ }
+ else
+ goto defproc;
}
break;
if (FRAME_MSWINDOWS_TARGET_RECT (frame))
{
/* Yes, we have to size again */
- mswindows_size_frame_internal ( frame,
- FRAME_MSWINDOWS_TARGET_RECT
+ mswindows_size_frame_internal ( frame,
+ FRAME_MSWINDOWS_TARGET_RECT
(frame));
/* Reset so we do not get here again. The SetWindowPos call in
* mswindows_size_frame_internal can cause recursion here. */
if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
FRAME_VISIBLE_P (frame) = 1;
-
+
if (!msframe->sizing || mswindows_dynamic_frame_resize)
redisplay ();
}
SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
}
UNGCPRO;
- break;
+ break;
+ }
+
+ case WM_MOUSEWHEEL:
+ {
+ int keys = LOWORD (wParam); /* Modifier key flags */
+ int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
+ struct gcpro gcpro1, gcpro2;
+
+ if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
+ {
+ GCPRO2 (emacs_event, fobj);
+ mswindows_pump_outstanding_events (); /* Can GC */
+ UNGCPRO;
+ }
+ else
+ goto defproc;
+ break;
}
#endif
case WM_COMMAND:
{
WORD id = LOWORD (wParam);
+ WORD nid = HIWORD (wParam);
HWND cid = (HWND)lParam;
frame = XFRAME (mswindows_find_frame (hwnd));
if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
break;
#endif
-
+ /* widgets in a buffer only eval a callback for suitable events.*/
+ switch (nid)
+ {
+ case BN_CLICKED:
+ case EN_CHANGE:
+ case CBN_EDITCHANGE:
+ case CBN_SELCHANGE:
+ if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
+ return 0;
+ }
+ /* menubars always must come last since the hashtables do not
+ always exist*/
#ifdef HAVE_MENUBARS
if (!NILP (mswindows_handle_wm_command (frame, id)))
break;
#endif
- /* Bite me - a spurious command. This cannot happen. */
- error ("XEMACS BUG: Cannot decode command message");
+ return DefWindowProc (hwnd, message, wParam, lParam);
+ /* Bite me - a spurious command. This used to not be able to
+ happen but with the introduction of widgets its now
+ possible. */
}
break;
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ case WM_CTLCOLORSCROLLBAR:
+ {
+ /* if we get an opportunity to paint a widget then do so if
+ there is an appropriate face */
+ HWND crtlwnd = (HWND)lParam;
+ LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
+ if (ii)
+ {
+ Lisp_Object image_instance;
+ VOID_TO_LISP (image_instance, ii);
+ if (IMAGE_INSTANCEP (image_instance)
+ &&
+ IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
+ {
+ /* set colors for the buttons */
+ HDC hdc = (HDC)wParam;
+ if (last_widget_brushed != ii)
+ {
+ if (widget_brush)
+ DeleteObject (widget_brush);
+ widget_brush = CreateSolidBrush
+ (COLOR_INSTANCE_MSWINDOWS_COLOR
+ (XCOLOR_INSTANCE
+ (FACE_BACKGROUND
+ (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+ XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+ }
+ last_widget_brushed = ii;
+ SetTextColor
+ (hdc,
+ COLOR_INSTANCE_MSWINDOWS_COLOR
+ (XCOLOR_INSTANCE
+ (FACE_FOREGROUND
+ (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+ XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+ SetBkMode (hdc, OPAQUE);
+ SetBkColor
+ (hdc,
+ COLOR_INSTANCE_MSWINDOWS_COLOR
+ (XCOLOR_INSTANCE
+ (FACE_BACKGROUND
+ (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+ XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+ return (LRESULT)widget_brush;
+ }
+ }
+ }
+ goto defproc;
+
#ifdef HAVE_DRAGNDROP
case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
{
* Only returns non-Qnil for keys that don't generate WM_CHAR messages
* or whose ASCII codes (like space) xemacs doesn't like.
* Virtual key values are defined in winresrc.h
- * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
*/
-Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
+Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
+ int extendedp)
{
- switch (mswindows_key)
- {
- /* First the predefined ones */
- case VK_BACK: return QKbackspace;
- case VK_TAB: return QKtab;
- case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
- case VK_RETURN: return QKreturn;
- case VK_ESCAPE: return QKescape;
- case VK_SPACE: return QKspace;
- case VK_DELETE: return QKdelete;
-
- /* The rest */
- case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
- case VK_PRIOR: return KEYSYM ("prior");
- case VK_NEXT: return KEYSYM ("next");
- case VK_END: return KEYSYM ("end");
- case VK_HOME: return KEYSYM ("home");
- case VK_LEFT: return KEYSYM ("left");
- case VK_UP: return KEYSYM ("up");
- case VK_RIGHT: return KEYSYM ("right");
- case VK_DOWN: return KEYSYM ("down");
- case VK_SELECT: return KEYSYM ("select");
- case VK_PRINT: return KEYSYM ("print");
- case VK_EXECUTE: return KEYSYM ("execute");
- case VK_SNAPSHOT: return KEYSYM ("print");
- case VK_INSERT: return KEYSYM ("insert");
- case VK_HELP: return KEYSYM ("help");
-#if 0 /* XXX What are these supposed to do? */
- case VK_LWIN return KEYSYM ("");
- case VK_RWIN return KEYSYM ("");
+ if (extendedp) /* Keys not present on a 82 key keyboard */
+ {
+ switch (mswindows_key)
+ {
+ case VK_RETURN: return KEYSYM ("kp-enter");
+ case VK_PRIOR: return KEYSYM ("prior");
+ case VK_NEXT: return KEYSYM ("next");
+ case VK_END: return KEYSYM ("end");
+ case VK_HOME: return KEYSYM ("home");
+ case VK_LEFT: return KEYSYM ("left");
+ case VK_UP: return KEYSYM ("up");
+ case VK_RIGHT: return KEYSYM ("right");
+ case VK_DOWN: return KEYSYM ("down");
+ case VK_INSERT: return KEYSYM ("insert");
+ case VK_DELETE: return QKdelete;
+ }
+ }
+ else
+ {
+ switch (mswindows_key)
+ {
+ case VK_BACK: return QKbackspace;
+ case VK_TAB: return QKtab;
+ case '\n': return QKlinefeed;
+ case VK_CLEAR: return KEYSYM ("clear");
+ case VK_RETURN: return QKreturn;
+ case VK_ESCAPE: return QKescape;
+ case VK_SPACE: return QKspace;
+ case VK_PRIOR: return KEYSYM ("kp-prior");
+ case VK_NEXT: return KEYSYM ("kp-next");
+ case VK_END: return KEYSYM ("kp-end");
+ case VK_HOME: return KEYSYM ("kp-home");
+ case VK_LEFT: return KEYSYM ("kp-left");
+ case VK_UP: return KEYSYM ("kp-up");
+ case VK_RIGHT: return KEYSYM ("kp-right");
+ case VK_DOWN: return KEYSYM ("kp-down");
+ case VK_SELECT: return KEYSYM ("select");
+ case VK_PRINT: return KEYSYM ("print");
+ case VK_EXECUTE: return KEYSYM ("execute");
+ case VK_SNAPSHOT: return KEYSYM ("print");
+ case VK_INSERT: return KEYSYM ("kp-insert");
+ case VK_DELETE: return KEYSYM ("kp-delete");
+ case VK_HELP: return KEYSYM ("help");
+#if 0 /* FSF Emacs allows these to return configurable syms/mods */
+ case VK_LWIN return KEYSYM ("");
+ case VK_RWIN return KEYSYM ("");
#endif
- case VK_APPS: return KEYSYM ("menu");
- case VK_F1: return KEYSYM ("f1");
- case VK_F2: return KEYSYM ("f2");
- case VK_F3: return KEYSYM ("f3");
- case VK_F4: return KEYSYM ("f4");
- case VK_F5: return KEYSYM ("f5");
- case VK_F6: return KEYSYM ("f6");
- case VK_F7: return KEYSYM ("f7");
- case VK_F8: return KEYSYM ("f8");
- case VK_F9: return KEYSYM ("f9");
- case VK_F10: return KEYSYM ("f10");
- case VK_F11: return KEYSYM ("f11");
- case VK_F12: return KEYSYM ("f12");
- case VK_F13: return KEYSYM ("f13");
- case VK_F14: return KEYSYM ("f14");
- case VK_F15: return KEYSYM ("f15");
- case VK_F16: return KEYSYM ("f16");
- case VK_F17: return KEYSYM ("f17");
- case VK_F18: return KEYSYM ("f18");
- case VK_F19: return KEYSYM ("f19");
- case VK_F20: return KEYSYM ("f20");
- case VK_F21: return KEYSYM ("f21");
- case VK_F22: return KEYSYM ("f22");
- case VK_F23: return KEYSYM ("f23");
- case VK_F24: return KEYSYM ("f24");
- }
+ case VK_APPS: return KEYSYM ("menu");
+ case VK_NUMPAD0: return KEYSYM ("kp-0");
+ case VK_NUMPAD1: return KEYSYM ("kp-1");
+ case VK_NUMPAD2: return KEYSYM ("kp-2");
+ case VK_NUMPAD3: return KEYSYM ("kp-3");
+ case VK_NUMPAD4: return KEYSYM ("kp-4");
+ case VK_NUMPAD5: return KEYSYM ("kp-5");
+ case VK_NUMPAD6: return KEYSYM ("kp-6");
+ case VK_NUMPAD7: return KEYSYM ("kp-7");
+ case VK_NUMPAD8: return KEYSYM ("kp-8");
+ case VK_NUMPAD9: return KEYSYM ("kp-9");
+ case VK_MULTIPLY: return KEYSYM ("kp-multiply");
+ case VK_ADD: return KEYSYM ("kp-add");
+ case VK_SEPARATOR: return KEYSYM ("kp-separator");
+ case VK_SUBTRACT: return KEYSYM ("kp-subtract");
+ case VK_DECIMAL: return KEYSYM ("kp-decimal");
+ case VK_DIVIDE: return KEYSYM ("kp-divide");
+ case VK_F1: return KEYSYM ("f1");
+ case VK_F2: return KEYSYM ("f2");
+ case VK_F3: return KEYSYM ("f3");
+ case VK_F4: return KEYSYM ("f4");
+ case VK_F5: return KEYSYM ("f5");
+ case VK_F6: return KEYSYM ("f6");
+ case VK_F7: return KEYSYM ("f7");
+ case VK_F8: return KEYSYM ("f8");
+ case VK_F9: return KEYSYM ("f9");
+ case VK_F10: return KEYSYM ("f10");
+ case VK_F11: return KEYSYM ("f11");
+ case VK_F12: return KEYSYM ("f12");
+ case VK_F13: return KEYSYM ("f13");
+ case VK_F14: return KEYSYM ("f14");
+ case VK_F15: return KEYSYM ("f15");
+ case VK_F16: return KEYSYM ("f16");
+ case VK_F17: return KEYSYM ("f17");
+ case VK_F18: return KEYSYM ("f18");
+ case VK_F19: return KEYSYM ("f19");
+ case VK_F20: return KEYSYM ("f20");
+ case VK_F21: return KEYSYM ("f21");
+ case VK_F22: return KEYSYM ("f22");
+ case VK_F23: return KEYSYM ("f23");
+ case VK_F24: return KEYSYM ("f24");
+ }
+ }
return Qnil;
}
mswindows_need_event (1);
- event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
+ event = mswindows_dequeue_dispatch_event ();
XSETEVENT (event2, emacs_event);
Fcopy_event (event, event2);
Fdeallocate_event (event);
{
case XM_BUMPQUEUE:
break;
-
+
case WM_SETFOCUS:
case WM_KILLFOCUS:
{
case XM_UNMAPFRAME:
{
Lisp_Object frame = EVENT_CHANNEL (emacs_event);
- va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
+ va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
== XM_MAPFRAME ?
- Qmap_frame_hook : Qunmap_frame_hook,
+ Qmap_frame_hook : Qunmap_frame_hook,
1, frame);
}
break;
-
+
/* #### What about Enter & Leave */
#if 0
va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
}
}
+#ifndef HAVE_MSG_SELECT
static HANDLE
get_process_input_waitable (struct Lisp_Process *process)
{
HANDLE hev = get_process_input_waitable (process);
remove_waitable_handle (hev);
}
+#endif /* HAVE_MSG_SELECT */
static void
emacs_mswindows_select_console (struct console *con)
{
+#ifdef HAVE_MSG_SELECT
+ if (CONSOLE_MSWINDOWS_P (con))
+ return; /* mswindows consoles are automatically selected */
+
+ event_stream_unixoid_select_console (con);
+#endif
}
static void
emacs_mswindows_unselect_console (struct console *con)
{
+#ifdef HAVE_MSG_SELECT
+ if (CONSOLE_MSWINDOWS_P (con))
+ return; /* mswindows consoles are automatically selected */
+
+ event_stream_unixoid_unselect_console (con);
+#endif
}
static void
emacs_mswindows_quit_p (void)
{
+ MSG msg;
+
/* Quit cannot happen in modal loop: all program
input is dedicated to Windows. */
if (mswindows_in_modal_loop)
return;
- /* Drain windows queue. This sets up number of quit
- characters in in the queue */
- mswindows_drain_windows_queue ();
+ /* Drain windows queue. This sets up number of quit characters in the queue
+ * (and also processes wm focus change, move, resize, etc messages).
+ * We don't want to process WM_PAINT messages because this function can be
+ * called from almost anywhere and the windows' states may be changing. */
+ while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
+ PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
+ DispatchMessage (&msg);
if (mswindows_quit_chars_count > 0)
{
/************************************************************************/
/* initialization */
/************************************************************************/
-
+
void
-vars_of_event_mswindows (void)
+reinit_vars_of_event_mswindows (void)
{
- mswindows_u_dispatch_event_queue = Qnil;
- staticpro (&mswindows_u_dispatch_event_queue);
- mswindows_u_dispatch_event_queue_tail = Qnil;
-
- mswindows_s_dispatch_event_queue = Qnil;
- staticpro (&mswindows_s_dispatch_event_queue);
- mswindows_s_dispatch_event_queue_tail = Qnil;
-
- mswindows_error_caught_in_modal_loop = Qnil;
- staticpro (&mswindows_error_caught_in_modal_loop);
mswindows_in_modal_loop = 0;
mswindows_pending_timers_count = 0;
mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
#ifdef HAVE_MSG_SELECT
- mswindows_event_stream->select_process_cb =
+ mswindows_event_stream->select_process_cb =
(void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
- mswindows_event_stream->unselect_process_cb =
+ mswindows_event_stream->unselect_process_cb =
(void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
#endif
+}
+
+void
+vars_of_event_mswindows (void)
+{
+ reinit_vars_of_event_mswindows ();
+
+ mswindows_u_dispatch_event_queue = Qnil;
+ staticpro (&mswindows_u_dispatch_event_queue);
+ mswindows_u_dispatch_event_queue_tail = Qnil;
+ pdump_wire (&mswindows_u_dispatch_event_queue_tail);
+
+ mswindows_s_dispatch_event_queue = Qnil;
+ staticpro (&mswindows_s_dispatch_event_queue);
+ mswindows_s_dispatch_event_queue_tail = Qnil;
+ pdump_wire (&mswindows_s_dispatch_event_queue_tail);
+
+ mswindows_error_caught_in_modal_loop = Qnil;
+ staticpro (&mswindows_error_caught_in_modal_loop);
+
+ DEFVAR_BOOL ("mswindows-meta-activates-menu", &mswindows_meta_activates_menu /*
+*Controls whether pressing and releasing the Meta (Alt) key should
+activate the menubar.
+Default is t.
+*/ );
DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
*Controls redrawing frame contents during mouse-drag or keyboard resize
mswindows_mouse_button_max_skew_x = 0;
mswindows_mouse_button_max_skew_y = 0;
mswindows_mouse_button_tolerance = 0;
+ mswindows_meta_activates_menu = 1;
}
void