Mercurial > hg > xemacs-beta
view src/msw-proc.c @ 221:6c0ae1f9357f r20-4b9
Import from CVS: tag r20-4b9
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:10:02 +0200 |
parents | 262b8bb4a523 |
children | 2c611d1463a6 |
line wrap: on
line source
/* mswindows specific event-handling. Copyright (C) 1997 Jonathan Harris. This file is part of XEmacs. XEmacs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. XEmacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Synched up with: Not in FSF. */ /* Authorship: Jonathan Harris, November 1997 for 20.4. */ /* * Comment: * * X on UNIX may be bad, but the win32 API really really really sucks. * * Windows user-input type events are stored in a per-thread message queue * and retrieved using GetMessage(). It is not possible to wait on this * queue and on other events (eg process input) simultaneously. Also, the * main event-handling code in windows (the "windows procedure") is called * asynchronously when windows has certain other types of events ("nonqueued * messages") to deliver. The documentation doesn't appear to specify the * context in which the windows procedure is called, but I assume that the * thread that created the window is temporarily highjacked for this purpose * when it calls GetMessage (a bit like X callbacks?). * * We spawn off a single thread to deal with both queued and non-queued * events. The thread turns both kinds of events into emacs_events and stuffs * them in a queue which XEmacs reads at its leisure. This file contains the * code for that thread. * * Unfortunately, under win32 a seemingly-random selection of resources are * owned by the thread that created/asked for them and not by the process. In * particular, only the thread that created a window can retrieve messages * destined for that window ("GetMessage does not retrieve messages for * windows that belong to other threads..."). This means that our message- * processing thread also has to do all window creation, deletion and various * other random stuff. We handle this bogosity by getting the main XEmacs * thread to send special user-defined messages to the message-processing * thread to instruct it to create windows etc. * * More bogosity: Windows95 doesn't offer any one-shot timers, only a * periodic timer. Worse, if you don't want a periodic timer to be associated * with a particular mswindows window (we don't) your periodic timers don't * have unique ids associated with them. We get round this lameness by * setting off a single periodic timer and we use this to schedule timeouts * manually. Implementing basic stuff like one-shot timers at the application * level is not particularly efficient, but Windows95 leaves us no choice. */ #include <config.h> #include "lisp.h" #include "console-msw.h" #include "device.h" #include "frame.h" #include "events.h" #include "event-msw.h" #ifdef DEBUG_XEMACS # include "opaque.h" /* For the debug functions at the end of this file */ # undef DEBUG_MESSAGES # undef DEBUG_TIMEOUTS #endif #define MSWINDOWS_FRAME_STYLE WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_TILEDWINDOW #define MSWINDOWS_POPUP_STYLE WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_CAPTION|WS_POPUP static LRESULT WINAPI mswindows_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static Lisp_Object mswindows_find_console (HWND hwnd); static Lisp_Object mswindows_find_frame (HWND hwnd); static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods); static int mswindows_modifier_state (void); static int mswindows_enqueue_timeout (int milliseconds); static void mswindows_dequeue_timeout (int interval_id); /* Virtual keycode of the '@' key */ static int virtual_at_key; /* Timeout queue */ struct mswindows_timeout { int ticks; int interval_id; struct mswindows_timeout *next; }; typedef struct mswindows_timeout mswindows_timeout; static mswindows_timeout timeout_pool[MSW_TIMEOUT_MAX]; static mswindows_timeout *timeout_head = NULL; static int timeout_mswindows_id; /* * Entry point for the "windows" message-processing thread */ DWORD mswindows_win_thread() { WNDCLASS wc; MSG msg; mswindows_waitable_info_type info; /* Register the main window class */ wc.style = CS_OWNDC; /* One DC per window */ wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; /* ? */ wc.hInstance = NULL; /* ? */ wc.hIcon = LoadIcon (NULL, XEMACS_CLASS); wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */ wc.lpszMenuName = NULL; /* XXX FIXME? Add a menu? */ wc.lpszClassName = XEMACS_CLASS; RegisterClass(&wc); /* XXX FIXME: Should use RegisterClassEx */ info.type = mswindows_waitable_type_dispatch; mswindows_add_waitable(&info); /* Ensure our message queue is created XXX FIXME: Is this necessary? */ PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE); /* Notify the main thread that we're ready */ assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, 0)); /* Hack! Windows doesn't report Ctrl-@ characters so we have to find out * which virtual key generates '@' at runtime */ virtual_at_key = VkKeyScan ('@'); if (virtual_at_key & 0x200) /* 0x200 means the control key */ /* If you need Ctrl just to generate @, you can't do Ctrl-@ */ virtual_at_key = -1; else virtual_at_key &= 0xff; /* The low byte contains the keycode */ /* Main windows loop */ while (1) { GetMessage (&msg, NULL, 0, 0); /* * Process things that don't have an associated window, so wouldn't * get sent to mswindows_wnd_proc */ /* Request from main thread */ if (msg.message>=WM_XEMACS_BASE && msg.message<=WM_XEMACS_END) mswindows_handle_request(&msg); /* Timeout(s) */ else if (msg.message == WM_TIMER) { EnterCriticalSection (&mswindows_dispatch_crit); if (timeout_head!=NULL) --(timeout_head->ticks); while (timeout_head!=NULL && timeout_head->ticks==0) { Lisp_Object emacs_event; struct Lisp_Event *event; int id = timeout_head->interval_id; #ifdef DEBUG_TIMEOUTS stderr_out("--> %x\n", id); #endif mswindows_dequeue_timeout (id); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = Qnil; event->timestamp = msg.time; event->event_type = timeout_event; event->event.timeout.interval_id = id; mswindows_enqueue_dispatch_event (emacs_event); } LeaveCriticalSection (&mswindows_dispatch_crit); } else /* Pass on to mswindows_wnd_proc */ DispatchMessage (&msg); } } /* * The windows procedure for the window class XEMACS_CLASS * Stuffs messages in the mswindows event queue */ static LRESULT WINAPI mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { /* Note: Remember to initialise these before use */ Lisp_Object emacs_event; struct Lisp_Event *event; static sizing = 0; MSG msg = { hwnd, message, wParam, lParam, 0, {0,0} }; msg.time = GetMessageTime(); #ifdef DEBUG_MESSAGES stderr_out("Message %04x, wParam=%04x, lParam=%08lx\n", message, wParam, lParam); #endif switch (message) { case WM_KEYDOWN: case WM_SYSKEYDOWN: { /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */ Lisp_Object keysym; int mods = mswindows_modifier_state(); if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods))) { EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = mswindows_find_console(hwnd); event->timestamp = msg.time; event->event_type = key_press_event; event->event.key.keysym = keysym; event->event.key.modifiers = mods; mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); return (0); } } TranslateMessage (&msg); /* Maybe generates WM_[SYS]CHAR in message queue */ goto defproc; case WM_CHAR: case WM_SYSCHAR: { EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = mswindows_find_console(hwnd); event->timestamp = msg.time; event->event_type = key_press_event; /* XEmacs doesn't seem to like Shift on non-alpha keys */ event->event.key.modifiers = isalpha(wParam) ? mswindows_modifier_state() : mswindows_modifier_state() & ~MOD_SHIFT; if (wParam<' ') /* Control char not already handled under WM_KEYDOWN */ { /* Don't capitalise alpha control keys */ event->event.key.keysym = isalpha(wParam+'a'-1) ? make_char(wParam+'a'-1) : make_char(wParam+'A'-1); } else { /* Assumes that emacs keysym == ASCII code */ event->event.key.keysym = make_char(wParam); } mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); } break; case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: { /* XXX FIXME: Do middle button emulation */ short x, y; EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = mswindows_find_frame(hwnd); event->timestamp = msg.time; event->event.button.button = (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 : ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2); x = LOWORD (lParam); y = HIWORD (lParam); event->event.button.x = x; event->event.button.y = y; event->event.button.modifiers = mswindows_modifier_state(); if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN || message==WM_RBUTTONDOWN) { event->event_type = button_press_event; SetCapture (hwnd); } else { event->event_type = button_release_event; ReleaseCapture (); } mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); } break; case WM_MOUSEMOVE: /* Optimization: don't report mouse movement while size is changind */ if (!sizing) { short x, y; EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = mswindows_find_frame(hwnd); event->timestamp = msg.time; event->event_type = pointer_motion_event; x = LOWORD (lParam); y = HIWORD (lParam); event->event.motion.x = x; event->event.motion.y = y; event->event.motion.modifiers = mswindows_modifier_state(); mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); } break; case WM_PAINT: if (GetUpdateRect(hwnd, NULL, FALSE)) { PAINTSTRUCT paintStruct; EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = mswindows_find_frame(hwnd); event->timestamp = msg.time; event->event_type = magic_event; BeginPaint (hwnd, &paintStruct); EVENT_MSWINDOWS_MAGIC_TYPE(event) = message; EVENT_MSWINDOWS_MAGIC_DATA(event) = paintStruct.rcPaint; EndPaint (hwnd, &paintStruct); mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); } break; case WM_SIZE: /* We only care about this message if our size has really changed */ if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) { RECT rect; EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT(emacs_event); event->channel = mswindows_find_frame(hwnd); event->timestamp = msg.time; event->event_type = magic_event; if (wParam==SIZE_MINIMIZED) rect.left = rect.top = rect.right = rect.bottom = -1; else GetClientRect(hwnd, &rect); EVENT_MSWINDOWS_MAGIC_TYPE(event) = message; EVENT_MSWINDOWS_MAGIC_DATA(event) = rect; mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); } break; /* Misc magic events which only require that the frame be identified */ case WM_SETFOCUS: case WM_KILLFOCUS: case WM_CLOSE: { EnterCriticalSection (&mswindows_dispatch_crit); emacs_event = Fmake_event (Qnil, Qnil); event = XEVENT (emacs_event); event->channel = mswindows_find_frame (hwnd); event->timestamp = msg.time; event->event_type = magic_event; EVENT_MSWINDOWS_MAGIC_TYPE (event) = message; mswindows_enqueue_dispatch_event (emacs_event); LeaveCriticalSection (&mswindows_dispatch_crit); } break; case WM_WINDOWPOSCHANGING: { WINDOWPOS *wp = (LPWINDOWPOS) lParam; WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; GetWindowPlacement(hwnd, &wpl); /* Only interested if size is changing and we're not being iconified */ if ((wpl.showCmd != SW_SHOWMINIMIZED) && !(wp->flags & SWP_NOSIZE)) { RECT ncsize = { 0, 0, 0, 0 }; int pixwidth, pixheight; AdjustWindowRect (&ncsize, GetWindowLong (hwnd, GWL_STYLE), FALSE); round_size_to_char (XFRAME (mswindows_find_frame (hwnd)), wp->cx - (ncsize.right - ncsize.left), wp->cy - (ncsize.bottom - ncsize.top), &pixwidth, &pixheight); /* Convert client sizes to window sizes */ pixwidth += (ncsize.right - ncsize.left); pixheight += (ncsize.bottom - ncsize.top); if (wpl.showCmd != SW_SHOWMAXIMIZED) { /* Adjust so that the bottom or right doesn't move if it's * the top or left that's being changed */ RECT rect; GetWindowRect (hwnd, &rect); if (rect.left != wp->x) wp->x += wp->cx - pixwidth; if (rect.top != wp->y) wp->y += wp->cy - pixheight; } wp->cx = pixwidth; wp->cy = pixheight; } } break; case WM_ENTERSIZEMOVE: case WM_EXITSIZEMOVE: sizing = (message == WM_ENTERSIZEMOVE); goto defproc; defproc: default: return DefWindowProc (hwnd, message, wParam, lParam); } return (0); } /* * Make a request to the message-processing thread to do things that * can't be done in the main thread. */ LPARAM mswindows_make_request(UINT message, WPARAM wParam, mswindows_request_type *request) { MSG msg; assert(PostThreadMessage (mswindows_win_thread_id, message, wParam, (LPARAM) request)); GetMessage (&msg, NULL, WM_XEMACS_ACK, WM_XEMACS_ACK); return (msg.lParam); } /* * Handle a request from the main thread to do things that have to be * done in the message-processing thread. */ static void mswindows_handle_request (MSG *msg) { mswindows_request_type *request = (mswindows_request_type *) msg->lParam; switch (msg->message) { case WM_XEMACS_CREATEWINDOW: { struct frame *f = request->thing1; Lisp_Object *props = request->thing2; Lisp_Object name, height, width, popup, top, left; int pixel_width, pixel_height; RECT rect; DWORD style; HWND hwnd; name = Fplist_get (*props, Qname, Qnil); height = Fplist_get (*props, Qheight, Qnil); width = Fplist_get (*props, Qwidth, Qnil); popup = Fplist_get (*props, Qpopup, Qnil); top = Fplist_get (*props, Qtop, Qnil); left = Fplist_get (*props, Qleft, Qnil); style = (NILP(popup)) ? MSWINDOWS_FRAME_STYLE : MSWINDOWS_POPUP_STYLE; FRAME_WIDTH (f) = INTP(width) ? XINT(width) : 80; FRAME_HEIGHT (f) = INTP(height) ? XINT(height) : 30; char_to_pixel_size (f, FRAME_WIDTH(f), FRAME_HEIGHT (f), &FRAME_PIXWIDTH (f), &FRAME_PIXHEIGHT (f)); rect.left = rect.top = 0; rect.right = FRAME_PIXWIDTH (f); rect.bottom = FRAME_PIXHEIGHT (f); #ifdef HAVE_MENUBARS AdjustWindowRect(&rect, style, TRUE); #else AdjustWindowRect(&rect, style, FALSE); #endif hwnd = CreateWindow (XEMACS_CLASS, STRINGP(f->name) ? XSTRING_DATA(f->name) : (STRINGP(name) ? XSTRING_DATA(name) : XEMACS_CLASS), style, INTP(left) ? XINT(left) : CW_USEDEFAULT, INTP(top) ? XINT(top) : CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, NULL, NULL, NULL, NULL); assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, (LPARAM) hwnd)); } return; case WM_XEMACS_DESTROYWINDOW: { struct frame *f = request->thing1; ReleaseDC(FRAME_MSWINDOWS_HANDLE(f), FRAME_MSWINDOWS_DC(f)); DestroyWindow(FRAME_MSWINDOWS_HANDLE(f)); assert (PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, 0)); } break; case WM_XEMACS_SETTIMER: { int id; EnterCriticalSection (&mswindows_dispatch_crit); id = mswindows_enqueue_timeout((int) request->thing1); LeaveCriticalSection (&mswindows_dispatch_crit); assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, id)); } break; case WM_XEMACS_KILLTIMER: { EnterCriticalSection (&mswindows_dispatch_crit); mswindows_dequeue_timeout((int) request->thing1); LeaveCriticalSection (&mswindows_dispatch_crit); assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, 0)); } break; default: assert(0); } } /* Returns the state of the modifier keys in the format expected by the * Lisp_Event key_data, button_data and motion_data modifiers member */ int mswindows_modifier_state (void) { /* Set high bit of GetKeyState's return value indicates the key is down */ return ((GetKeyState (VK_SHIFT) & 0x8000) ? MOD_SHIFT : 0) | ((GetKeyState (VK_CONTROL) & 0x8000) ? MOD_CONTROL: 0) | ((GetKeyState (VK_MENU) & 0x8000) ? MOD_META : 0); } /* * Translate a mswindows virtual key to a keysym. * 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) { 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 (""); #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"); default: /* Special handling for Ctrl-'@' because '@' lives shifted on varying * virtual keys and because Windows doesn't report Ctrl-@ as a WM_CHAR */ if (((mods & (MOD_SHIFT|MOD_CONTROL)) == (MOD_SHIFT|MOD_CONTROL)) && (mswindows_key == virtual_at_key)) return make_char('@'); } return Qnil; } /* * Add a timeout to the queue. Returns the id or 0 on failure */ static int mswindows_enqueue_timeout (int milliseconds) { static int timeout_last_interval_id; int target_ticks = (milliseconds + MSW_TIMEOUT_GRANULARITY-1) / MSW_TIMEOUT_GRANULARITY; mswindows_timeout *target; int i; /* Find a free timeout */ for (i=0; i<MSW_TIMEOUT_MAX; i++) { target = timeout_pool + i; if (target->interval_id == 0) break; } /* No free timeout */ if (i==MSW_TIMEOUT_MAX) return 0; if (++timeout_last_interval_id == 0) ++timeout_last_interval_id; if (timeout_head == NULL || timeout_head->ticks >= target_ticks) { /* First or only timeout in the queue (common case) */ target->interval_id = timeout_last_interval_id; target->ticks = target_ticks; target->next = timeout_head; timeout_head = target; if (target->next == NULL) { /* Queue was empty - restart the timer */ timeout_mswindows_id = SetTimer (NULL, 0, MSW_TIMEOUT_GRANULARITY, NULL); #ifdef DEBUG_TIMEOUTS stderr_out("Start\n"); #endif } else target->next->ticks -= target->ticks; } else { /* Find the timeout before this new one */ mswindows_timeout *prev = timeout_head; int tick_count = prev->ticks; /* Number of ticks up to prev */ while (prev->next != NULL) { if (tick_count + prev->next->ticks >= target_ticks) break; prev = prev->next; tick_count += prev->ticks; } /* Insert the new timeout in the queue */ target->interval_id = timeout_last_interval_id; target->ticks = target_ticks - tick_count; target->next = prev->next; prev->next = target; if (target->next != NULL) target->next->ticks -= target->ticks; } #ifdef DEBUG_TIMEOUTS stderr_out("Set %x %d %d\n", timeout_last_interval_id, target_ticks, milliseconds); #endif return timeout_last_interval_id; } /* * Remove a timeout from the queue */ static void mswindows_dequeue_timeout (int interval_id) { mswindows_timeout *target; mswindows_timeout *prev; target = timeout_head; prev = NULL; while (target != NULL) { if (target->interval_id == interval_id) { #ifdef DEBUG_TIMEOUTS stderr_out("Kil %x %d\n", interval_id, target->ticks); #endif target->interval_id = 0; /* Mark free */ if (prev!=NULL) { prev->next = target->next; if (target->next != NULL) target->next->ticks += target->ticks; } else if ((timeout_head = target->next) == NULL) { /* Queue is now empty - stop the timer */ KillTimer (NULL, timeout_mswindows_id); timeout_mswindows_id = 0; #ifdef DEBUG_TIMEOUTS stderr_out("Stop\n"); #endif } return; } else { prev = target; target = target->next; } } /* Ack! the timeout wasn't in the timeout queue which means that it's * probably gone off and is now sitting in the dispatch queue. XEmacs will * be very unhappy if it sees the timeout so we have to fish it out of the * dispatch queue. This only happens if XEmacs can't keep up with events */ #ifdef DEBUG_TIMEOUTS stderr_out("Kil %x - not found\n", interval_id); #endif { Lisp_Object match_event, emacs_event; struct Lisp_Event *event; match_event = Fmake_event (Qnil, Qnil); event = XEVENT(match_event); event->channel = Qnil; event->event_type = timeout_event; event->event.timeout.interval_id = interval_id; emacs_event = mswindows_cancel_dispatch_event (match_event); if (!NILP (emacs_event)) Fdeallocate_event(emacs_event); Fdeallocate_event(match_event); } } /* * Find the console that matches the supplied mswindows window handle */ static Lisp_Object mswindows_find_console (HWND hwnd) { Lisp_Object concons; CONSOLE_LOOP (concons) { Lisp_Object console = XCAR (concons); /* We only support one console so this must be it */ return console; } return Qnil; } /* * Find the frame that matches the supplied mswindows window handle */ static Lisp_Object mswindows_find_frame (HWND hwnd) { Lisp_Object frmcons, devcons, concons; FRAME_LOOP_NO_BREAK (frmcons, devcons, concons) { struct frame *f; Lisp_Object frame = XCAR (frmcons); f = XFRAME (frame); if (FRAME_TYPE_P(f, mswindows)) /* Might be a stream-type frame */ if (FRAME_MSWINDOWS_HANDLE(f)==hwnd) return frame; } assert(0); /* XXX Can't happen! we only get messages for our windows */ return Qnil; } #ifdef DEBUG_XEMACS /* * Random helper functions for debugging. * Intended for use in the MSVC "Watch" window which doesn't like * the aborts that the error_check_foo() functions can make. */ struct lrecord_header *DHEADER(Lisp_Object obj) { return (LRECORDP (obj)) ? XRECORD_LHEADER (obj) : NULL; } int DOPAQUE_DATA (Lisp_Object obj) { return (OPAQUEP (obj)) ? OPAQUE_DATA (XOPAQUE (obj)) : NULL; } struct Lisp_Event *DEVENT(Lisp_Object obj) { return (EVENTP (obj)) ? XEVENT (obj) : NULL; } struct Lisp_Cons *DCONS(Lisp_Object obj) { return (CONSP (obj)) ? XCONS (obj) : NULL; } Lisp_Object DCAR(Lisp_Object obj) { return (CONSP (obj)) ? XCAR (obj) : 0; } Lisp_Object DCDR(Lisp_Object obj) { return (CONSP (obj)) ? XCDR (obj) : 0; } Lisp_Object DCONSCDR(Lisp_Object obj) { return ((CONSP (obj)) && (CONSP (XCDR (obj)))) ? XCONS (XCDR (obj)) : 0; } Lisp_Object DCARCDR(Lisp_Object obj) { return ((CONSP (obj)) && (CONSP (XCDR (obj)))) ? XCAR (XCDR (obj)) : 0; } char *DSTRING(Lisp_Object obj) { return (STRINGP (obj)) ? XSTRING_DATA (obj) : NULL; } struct Lisp_Vector *DVECTOR(Lisp_Object obj) { return (VECTORP (obj)) ? XVECTOR (obj) : NULL; } struct Lisp_Symbol *DSYMBOL(Lisp_Object obj) { return (SYMBOLP (obj)) ? XSYMBOL (obj) : NULL; } char *DSYMNAME(Lisp_Object obj) { return (SYMBOLP (obj)) ? XSYMBOL (obj)->name->_data : NULL; } #endif