Mercurial > hg > xemacs-beta
diff src/event-msw.c @ 213:78f53ef88e17 r20-4b5
Import from CVS: tag r20-4b5
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:06:47 +0200 |
parents | |
children | 262b8bb4a523 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/event-msw.c Mon Aug 13 10:06:47 2007 +0200 @@ -0,0 +1,423 @@ +/* The mswindows event_stream interface. + Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 1995 Sun Microsystems, Inc. + Copyright (C) 1996 Ben Wing. + 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: + + Ultimately based on FSF. + Rewritten by Ben Wing. + Rewritten for mswindows by Jonathan Harris, November 1997 for 20.4. + */ + +#include <config.h> +#include "lisp.h" + +#include "device.h" +#include "console-msw.h" +#include "events.h" +#include "frame.h" +#include "process.h" + +#include "sysproc.h" +#include "syswait.h" +#include "systime.h" + +#include "event-msw.h" + +static struct event_stream *mswindows_event_stream; +static Lisp_Object mswindows_dispatch_event_queue, mswindows_dispatch_event_queue_tail; +static mswindows_waitable_count=0; +CRITICAL_SECTION mswindows_dispatch_crit; + +static Lisp_Object mswindows_dequeue_dispatch_event (void); + +/* + * List of mswindows waitable handles. + * Apart from the dispatch queue semaphore, all of these handles may be waited + * on multiple times in emacs_mswindows_next_event before being processed and so must + * be manual-reset events. + */ +static HANDLE mswindows_waitable[MAX_WAITABLE]; + +/* random emacs info associated with each of the wait handles */ +static mswindows_waitable_info_type mswindows_waitable_info[MAX_WAITABLE]; + +void +mswindows_enqueue_dispatch_event (Lisp_Object event) +{ + assert(mswindows_waitable_count); +// EnterCriticalSection (&mswindows_dispatch_crit); + enqueue_event (event, &mswindows_dispatch_event_queue, &mswindows_dispatch_event_queue_tail); + ReleaseSemaphore(mswindows_waitable[0], 1, NULL); +// LeaveCriticalSection (&mswindows_dispatch_crit); +} + +static Lisp_Object +mswindows_dequeue_dispatch_event (void) +{ + Lisp_Object event; + assert(mswindows_waitable_count); +// EnterCriticalSection (&mswindows_dispatch_crit); + event = dequeue_event (&mswindows_dispatch_event_queue, &mswindows_dispatch_event_queue_tail); +// LeaveCriticalSection (&mswindows_dispatch_crit); + return event; +} + +/* + * Find a free waitable slot + */ +static int +mswindows_find_free_waitable(void) +{ + int i; + for (i=0; i<mswindows_waitable_count; i++) + if (mswindows_waitable_info[i].type == mswindows_waitable_type_none) + return i; + assert (mswindows_waitable_count < MAX_WAITABLE); + return mswindows_waitable_count++; +} + +/* + * Create a new waitable using the type and data passed in by the info structure + * Returns a pointer to the info associated with the assigned waitable object + */ +mswindows_waitable_info_type * +mswindows_add_waitable(mswindows_waitable_info_type *info) +{ + int waitable; + + switch (info->type) + { + case mswindows_waitable_type_dispatch: + /* Can only have one waitable for the dispatch queue, and it's the first one */ + assert (mswindows_waitable_count++ == 0); + waitable=0; + InitializeCriticalSection(&mswindows_dispatch_crit); + assert (mswindows_waitable[0] = CreateSemaphore (NULL, 0, 0x7fffffff, NULL)); + return mswindows_waitable_info+0; + +#if 0 /* Windows95 doesn't support WaitableTimers */ + case mswindows_waitable_type_timeout: + { + LARGE_INTEGER due; + due.QuadPart = 10000 * (LONGLONG) info->data.timeout.milliseconds; + waitable = mswindows_find_free_waitable(); + mswindows_waitable[waitable] = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(mswindows_waitable[waitable], &due, 0, NULL, NULL, FALSE); + mswindows_waitable_info[waitable].data.timeout.id = waitable; + } + break; +#endif + + default: + assert(0); + } + mswindows_waitable_info[waitable].type = info->type; + return mswindows_waitable_info+waitable; +} + +/* + * Remove a waitable using the type and data passed in by the info structure. + */ +void +mswindows_remove_waitable(mswindows_waitable_info_type *info) +{ + int waitable; + + switch (info->type) + { +#if 0 + case mswindows_waitable_type_timeout: + waitable = info->data.timeout.id; + CancelWaitableTimeout(mswindows_waitable[waitable]); + break; +#endif + + default: + assert(0); + } + + CloseHandle(mswindows_waitable[waitable]); + mswindows_waitable[waitable] = 0; + mswindows_waitable_info[waitable].type = mswindows_waitable_type_none; + if (waitable == mswindows_waitable_count-1) + --mswindows_waitable_count; +} + + +/************************************************************************/ +/* methods */ +/************************************************************************/ + +static int +emacs_mswindows_add_timeout (EMACS_TIME thyme) +{ + EMACS_TIME current_time; + int milliseconds; + int id; + mswindows_request_type request; + + EMACS_GET_TIME (current_time); + EMACS_SUB_TIME (thyme, thyme, current_time); + milliseconds = EMACS_SECS (thyme) * 1000 + EMACS_USECS (thyme) / 1000; + if (milliseconds < 1) + milliseconds = 1; + request.thing1 = (void *) milliseconds; + id = mswindows_make_request(WM_XEMACS_SETTIMER, 0, &request); + assert(id); /* XXX */ + return id; +} + +static void +emacs_mswindows_remove_timeout (int id) +{ + mswindows_request_type request = { (void *) id }; + mswindows_make_request(WM_XEMACS_KILLTIMER, 0, &request); +} + +static int +emacs_mswindows_event_pending_p (int user_p) +{ + return 0; +} + +static struct console * +find_console_from_fd (int fd) +{ + return 0; +} + +/* + * Return the next event + * We return windows events off the dispatch event queue in preference to other events + */ +static void +emacs_mswindows_next_event (struct Lisp_Event *emacs_event) +{ + DWORD active; + active = WaitForMultipleObjects (mswindows_waitable_count, mswindows_waitable, + FALSE, INFINITE); + assert(active >= WAIT_OBJECT_0 && active <= WAIT_OBJECT_0 + mswindows_waitable_count - 1); + + /* Windows events on the dispatch event queue */ + if (active == WAIT_OBJECT_0) + { + /* XXX Copied from event-Xt.c */ + Lisp_Object event, event2; + + EnterCriticalSection (&mswindows_dispatch_crit); + XSETEVENT (event2, emacs_event); + event = mswindows_dequeue_dispatch_event (); + Fcopy_event (event, event2); + Fdeallocate_event (event); + LeaveCriticalSection (&mswindows_dispatch_crit); + } + else + { + /* XXX FIXME: We should do some kind of round-robin scheme to ensure fairness */ + int waitable = active - WAIT_OBJECT_0; + mswindows_waitable_info_type *info = mswindows_waitable_info + waitable; + + switch (info->type) + { + case mswindows_waitable_type_timeout: + emacs_event->channel = Qnil; + emacs_event->event_type = timeout_event; + emacs_event->event.timeout.interval_id = info->data.timeout.id; + mswindows_remove_waitable(info); + break; + + default: + assert(0); + } + } +} + +/* + * Handle a magic event off the dispatch queue. + * XXX split into seperate functions for clarity. + */ +static void +emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) +{ + RECT *rect = &EVENT_MSWINDOWS_MAGIC_DATA(emacs_event); + struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); + Lisp_Object frame = Qnil; + XSETFRAME (frame, f); +#if 0 + stderr_out("magic %x, (%d,%d), (%d,%d)\n", + EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event), + rect->left, rect->top, rect->right, rect->bottom); +#endif + switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) + { + case WM_SETFOCUS: + case WM_KILLFOCUS: + { + int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); + Lisp_Object conser; + /* struct gcpro gcpro1; */ + + /* Clear sticky modifiers here (if we had any) */ + + conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); + /* GCPRO1 (conser); XXX Not necessary? */ + emacs_handle_focus_change_preliminary (conser); + /* Under X the stuff up to here is done in the X event handler. + I Don't know why */ + emacs_handle_focus_change_final (conser); + /* UNGCPRO; */ + } + break; + + /* XXX What about Enter & Leave */ +#if 0 + va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : + Qmouse_leave_frame_hook, 1, frame); + break; +#endif + + case WM_SIZE: + if ((rect->left & rect->top & rect->right & rect->bottom) == -1) + { + /* Iconified */ + FRAME_VISIBLE_P (f) = 0; + va_run_hook_with_args (Qunmap_frame_hook, 1, frame); + Fframe_iconified_p (frame); + } + else + { + /* If we're uniconified, our size may or may not have changed */ + int columns, rows; + int was_visible = FRAME_VISIBLE_P (f); + pixel_to_char_size (f, rect->right, rect->bottom, &columns, &rows); + + FRAME_VISIBLE_P (f) = 1; + if (f->height!=rows || f->width!=columns || f->size_change_pending) + { + /* Size changed */ + f->pixwidth = rect->right; + f->pixheight = rect->bottom; + change_frame_size (f, rows, columns, 0); +/* MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); /* XXX Too extreme? */ + } + + if (!was_visible) + va_run_hook_with_args (Qmap_frame_hook, 1, frame); + + } + break; + + case WM_PAINT: + mswindows_redraw_exposed_area(f, rect->left, rect->top, + rect->right, rect->bottom); + break; + + default: + assert(0); + } +} + +static void +emacs_mswindows_select_process (struct Lisp_Process *process) +{ +} + +static void +emacs_mswindows_unselect_process (struct Lisp_Process *process) +{ +} + +static void +emacs_mswindows_select_console (struct console *con) +{ +} + +static void +emacs_mswindows_unselect_console (struct console *con) +{ +} + +static void +emacs_mswindows_quit_p (void) +{ +} + +/* This is called from GC when a process object is about to be freed. + If we've still got pointers to it in this file, we're gonna lose hard. + */ +void +debug_process_finalization (struct Lisp_Process *p) +{ +#if 0 /* #### */ + int i; + int infd, outfd; + get_process_file_descriptors (p, &infd, &outfd); + /* if it still has fds, then it hasn't been killed yet. */ + assert (infd < 0); + assert (outfd < 0); + /* Better not still be in the "with input" table; we know it's got no fds. */ + for (i = 0; i < MAXDESC; i++) + { + Lisp_Object process = filedesc_fds_with_input [i]; + assert (!PROCESSP (process) || XPROCESS (process) != p); + } +#endif +} + +/************************************************************************/ +/* initialization */ +/************************************************************************/ + +void +vars_of_event_mswindows (void) +{ + mswindows_dispatch_event_queue = Qnil; + staticpro (&mswindows_dispatch_event_queue); + mswindows_dispatch_event_queue_tail = Qnil; + + mswindows_event_stream = xnew (struct event_stream); + + mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; + mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; + mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; + mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; + mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; + mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; + mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; + mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; + mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; + mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; +} + +void +syms_of_event_mswindows (void) +{ +} + +void +init_event_mswindows_late (void) +{ + event_stream = mswindows_event_stream; +}