home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1993, 1994 Marc Parmet.
- * This file is part of the Macintosh port of GNU Emacs.
- *
- * GNU Emacs 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.
- */
-
- #if defined(THINK_C)
- #include <MacHeaders>
- #else
- #include <Types.h>
- #include <Memory.h>
- #include <Quickdraw.h>
- #include <Windows.h>
- #include <TextEdit.h>
- #include <LowMem.h>
- #include <Dialogs.h>
- #include <ToolUtils.h>
- #endif
-
- #include <Retrace.h>
- #include <GestaltEqu.h>
- #include <AppleEvents.h>
- #include "unix-types.h"
- #include "unix-constants.h"
- #include "kbd-patch-data.h"
- #include "emacs-version.h"
-
- #define QUIT_MODIFIERS controlKey
- #define QUIT_CHAR 'g'
-
- extern int Vaccept_high_level_events;
- extern int Vmodifier_vector;
-
- char got_interrupt_from_terminal;
- static short cached_event_head,cached_event_tail; // Queue is empty when equal
- static short cached_key_head,cached_key_tail; // Queue is empty when equal
- #define MAX_KEYS 50
- #define MAX_EVENTS 50
- static struct {
- EventRecord e;
- AppleEvent ae,reply;
- long refCon;
- } cached_events[MAX_EVENTS];
- static char cached_keys[MAX_KEYS];
- static char clipboard_fix,clipboard_fix_update_contents;
-
- WindowPtr console_window(),tty_window();
-
- static int
- typed_to_denoted(int modifiers)
- {
- register int i;
- register struct keyboard_patch_vector *v;
-
- if (Vmodifier_vector == 0) return modifiers;
- if (modifiers == 0) return 0;
-
- v = MODIFIER_XVECTOR(Vmodifier_vector);
- for (i = 0; i<v->size; ++i)
- if (v->contents[i].typed == modifiers)
- return v->contents[i].denoted;
-
- return 0;
- }
-
- static void
- do_content(EventRecord *e,WindowPtr w)
- {
- if (w == tty_window())
- tty_content();
- else if (w == console_window())
- console_content(e);
- }
-
- static void
- do_update(WindowPtr w)
- {
- if (w == tty_window())
- tty_update();
- else if (w == console_window())
- console_update();
- else {
- BeginUpdate(w);
- EndUpdate(w);
- }
- }
-
- static void
- do_activate(WindowPtr w,int activate)
- {
- if (w == tty_window())
- tty_activate();
- else if (w == console_window())
- console_activate(activate);
-
- // fixup_menus();
- }
-
- static void
- do_drag(EventRecord *e,WindowPtr w)
- {
- if (w == tty_window())
- tty_drag(e);
- else if (w == console_window())
- console_drag(e);
- }
-
- extern int input_pending;
-
- static void
- do_menu(long choice)
- {
- unsigned char s[256];
- short menu,item;
-
- if (FrontWindow() == console_window()) {
- input_pending = 0;
- do_menu_internal(choice);
- }
- else {
- menu = HiWord(choice);
- item = LoWord(choice);
- GetItem(GetMHandle(menu),item,s);
- if (!pstrcmp(s,"\pClose")) {
- /* This is an awful fix. Find something better. */
- HideWindow(tty_window());
- HiliteMenu(0);
- }
- else {
- SelectWindow(console_window());
- do_menu(choice);
- }
- }
- }
-
- static void
- refresh_screen(void)
- {
- /* This can result in a reentrant call to the kernel. Beware. */
- input_pending = 0;
- redisplay();
- }
-
- static void
- do_mouseDown(EventRecord *e)
- {
- short partCode;
- WindowPtr w;
- long choice;
-
- switch (partCode = FindWindow(e->where,&w)) {
- case inMenuBar:
- do_MenuSelect_before_hooks();
- choice = MenuSelect(e->where);
- if (HiWord(choice) != 0) do_menu(choice);
- break;
- case inGoAway:
- tty_goaway(e);
- break;
- /* case inDrag:
- do_drag(e,w);
- break; */
- case inGrow:
- console_grow(e);
- break;
- case inContent:
- do_content(e,w);
- break;
- }
- }
-
- static void
- enqueue_key(char c)
- {
- if ((cached_key_head+1) % MAX_KEYS == cached_key_tail) return;
- cached_keys[cached_key_head] = c;
- cached_key_head = (cached_key_head + 1) % MAX_KEYS;
- }
-
- pascal short
- ae_receive_func(AppleEvent *ae,AppleEvent *reply,long refCon)
- {
- cached_events[cached_event_head].ae = *ae;
- cached_events[cached_event_head].reply = *reply;
- cached_events[cached_event_head].refCon = refCon;
- AESuspendTheCurrentEvent(ae);
- return noErr;
- }
-
- static void
- do_event(EventRecord *e,AppleEvent *ae,AppleEvent *reply,long refCon)
- {
- char c;
- int err;
- long choice;
- short modifiers;
- unsigned char virtual_keycode;
-
- switch (e->what) {
- case mouseDown:
- do_mouseDown(e);
- refresh_screen();
- break;
- case kHighLevelEvent:
- {
- extern ae_receive_func2();
- static AEEventHandlerUPP ae_receive_func2_upp;
- if (ae_receive_func2_upp == 0L)
- ae_receive_func2_upp = NewAEEventHandlerProc(ae_receive_func2);
- err = AEResumeTheCurrentEvent(ae,reply,ae_receive_func2_upp,refCon);
- refresh_screen();
- break;
- }
- case keyDown:
- case autoKey:
- modifiers = typed_to_denoted(e->modifiers & MODIFIER_KEYS);
- if (modifiers == cmdKey) {
- // Command key combination
- choice = MenuKey(e->message & charCodeMask);
- if (HiWord(choice) != 0) {
- do_menu(choice);
- refresh_screen();
- }
- }
- else {
- // Regular keystroke
- ObscureCursor();
-
- if (modifiers & metaKey) enqueue_key(27);
- virtual_keycode = (e->message >> 8) & 0x7f;
- if (virtual_keycode >= 0x40) {
- enqueue_key('x' & 0x1f);
- enqueue_key('*');
- c = virtual_keycode;
- if (!(modifiers & shiftKey)) c -= 0x40;
- enqueue_key(c);
- }
- else {
- c = e->message & charCodeMask;
- if (virtual_keycode == 0x33) c = 0x7f; // delete, above return
- if (c == '\015' && modifiers == shiftKey) c = '\012';
- if (modifiers & controlKey) c &= 0x1f;
- enqueue_key(c);
- }
- }
- break;
- }
- }
-
- static void
- enqueue_event(EventRecord *e)
- {
- if ((cached_event_head+1) % MAX_EVENTS != cached_event_tail) {
- cached_events[cached_event_head].e = *e;
- if (e->what == kHighLevelEvent) AEProcessAppleEvent(e);
- cached_event_head = (cached_event_head + 1) % MAX_EVENTS;
- }
- }
-
- static int
- emacs_is_front_process(void)
- {
- short err;
- Boolean same;
- ProcessSerialNumber psn1,psn2;
-
- err = GetFrontProcess(&psn1);
- if (err) return 1;
- err = GetCurrentProcess(&psn2);
- if (err) return 1;
- err = SameProcess(&psn1,&psn2,&same);
- return err || same;
- }
-
- void
- read_events(int yield)
- {
- WindowPtr w;
- EventRecord e;
- short partCode;
- Boolean have_event;
- short mask,modifiers,yieldtime;
- static int time_of_last_keystroke,time_of_last_WaitNextEvent,
- time_of_last_highlevel;
-
- if (emacs_is_front_process()) {
- /* It's possible we'll get to this point while in a modal dialog called
- up from elisp. Garbage collection, by printing the message "Garbage
- collecting...", will bring us here, as will any I/O. It's not good
- to call WaitNextEvent when a modal dialog is up, so we try to detect
- this case, and return immediately. */
- if (LMGetWindowList()->windowKind == dialogKind) return;
-
- if (FrontWindow() == tty_window())
- yieldtime = 0;
- else if (yield) {
- /* Console is frontmost. Emacs entered the kernel, every entry
- to the kernel brings us here.
- Every 120 ticks, yield for 15 ticks. */
- if (time_of_last_WaitNextEvent + 120 > TickCount()) return;
- yieldtime = 15;
- }
- else {
- /* Console is frontmost, Emacs is calling 'read' to get keystrokes.
- Every 2 ticks, get input trying not to yield. */
- if (time_of_last_keystroke + 2 >= TickCount()) return;
- yieldtime = 0;
- }
- }
- else {
- /* Emacs is in the background. Take 1/15 of a second but then
- yield for 30 ticks, unless we've been busy lately. */
- if (time_of_last_WaitNextEvent + 1 >= TickCount()) return;
- if (time_of_last_highlevel + 180 > TickCount())
- yieldtime = 0;
- else {
- yieldtime = 30;
- }
- }
-
- mask = everyEvent;
- if (!Vaccept_high_level_events) mask &= ~highLevelEventMask;
-
- while (1) {
- have_event = WaitNextEvent(mask,&e,yieldtime,0L);
- time_of_last_WaitNextEvent = e.when;
- if (!have_event) {
- SetCursor(&qd.arrow);
- return;
- }
-
- switch (e.what) {
- case nullEvent:
- return;
- case updateEvt:
- do_update((WindowPtr)e.message);
- break;
- case activateEvt:
- do_activate((WindowPtr)e.message,e.modifiers & activeFlag);
- break;
- case osEvt:
- /* This is not what is described in IM VI, p. 5-20,
- which seems to be wrong. */
- if (*(char *)&e.message == suspendResumeMessage) {
- if (BitTst(&e.message,32 - resumeFlag)) {
- /* Resume */
- clipboard_fix = 1;
- clipboard_fix_update_contents =
- BitTst(&e.message,32 - convertClipboardFlag);
- do_activate(FrontWindow(),1);
- }
- else {
- /* Suspend */
- clipboard_fix = 1;
- clipboard_fix_update_contents = 0;
- do_activate(FrontWindow(),0);
- }
- }
- break;
- case kHighLevelEvent:
- #if 0
- asm {
- move.l e.message,d0
- move.l e.where,d1
- }
- DebugStr("\pEmacs got high level event;d0;d1");
- #endif
- time_of_last_highlevel = e.when;
- enqueue_event(&e);
- break;
- case mouseDown:
- switch (partCode = FindWindow(e.where,&w)) {
- case inMenuBar:
- case inGoAway:
- case inContent:
- case inGrow:
- enqueue_event(&e);
- break;
- case inDrag:
- do_drag(&e,w);
- break;
- }
- break;
- case keyDown:
- case autoKey:
- time_of_last_keystroke = e.when;
- modifiers = typed_to_denoted(e.modifiers & MODIFIER_KEYS);
- if (QUIT_MODIFIERS != 0 && modifiers == QUIT_MODIFIERS &&
- (char)e.message == QUIT_CHAR)
- got_interrupt_from_terminal = 1;
- else
- enqueue_event(&e);
- break;
- }
- }
- }
-
- // This is how we catch control-g when hung in a loop.
-
- static struct VBLTask probe;
-
- static void
- do_quit_char_probe(void)
- {
- EvQElPtr q;
-
- probe.vblCount = 15;
-
- if (QUIT_MODIFIERS == 0) return;
- for (q = (EvQElPtr)GetEvQHdr()->qHead; q != 0L; q = (EvQElPtr)q->qLink)
- if (q->evtQWhat == keyDown &&
- (Vmodifier_vector == 0 ?
- (q->evtQModifiers & MODIFIER_KEYS) == QUIT_MODIFIERS &&
- (char)q->evtQMessage == (QUIT_CHAR & 0x1f) :
- typed_to_denoted(q->evtQModifiers & MODIFIER_KEYS) == QUIT_MODIFIERS &&
- (char)q->evtQMessage == QUIT_CHAR))
- /* It is critical here that we use the far memory model and avoid
- addressing off of a5. */
- got_interrupt_from_terminal = 1;
- }
-
- void
- unix_init_kbd(void)
- {
- short err;
- struct keyboard_patch_data *kbpd;
- static VBLUPP do_quit_char_probe_upp;
-
- if (do_quit_char_probe_upp == 0L)
- do_quit_char_probe_upp = NewVBLProc(do_quit_char_probe);
-
- probe.qLink = 0L;
- probe.qType = vType;
- probe.vblAddr = do_quit_char_probe_upp;
- probe.vblCount = 15;
- probe.vblPhase = 0;
-
- // err = VInstall((QElemPtr)&probe);
- // if (err) ExitToShell();
-
- err = Gestalt('EMAc',(long *)&kbpd);
- if (err || kbpd->version != emacs_version_complete) {
- InitCursor();
- switch (Alert(137,0L)) {
- case 1: return;
- case 2: ExitToShell();
- }
- }
-
- kbpd->v = (long *)&Vmodifier_vector;
- err = GetCurrentProcess(&kbpd->emacs_psn);
- if (err) ExitToShell();
- }
-
- static int
- user_cancelled(void)
- {
- register EvQElPtr q;
-
- for (q = (EvQElPtr)GetEvQHdr()->qHead; q != 0L; q = (EvQElPtr)q->qLink)
- if (q->evtQWhat == keyDown &&
- (((q->evtQModifiers & cmdKey) && (char)q->evtQMessage == '.') ||
- (char)q->evtQMessage == (QUIT_CHAR & 0x1f)))
- return 1;
-
- return 0;
- }
-
- pascal Boolean
- ae_send_idle_function(EventRecord *e,long *sleepTime,RgnHandle *mouseRgn)
- {
- *sleepTime = 30;
- *mouseRgn = 0L;
-
- if (user_cancelled()) return 1;
-
- switch (e->what) {
- case nullEvent:
- spin_beachball();
- break;
- case osEvt:
- break;
- case updateEvt:
- do_update((WindowPtr)e->message);
- break;
- case activateEvt:
- do_activate((WindowPtr)e->message,e->modifiers & activeFlag);
- break;
- }
-
- return 0;
- }
-
- int
- number_of_pending_events(void)
- {
- int events_available;
-
- read_events(0);
- events_available = (cached_event_head + MAX_KEYS - cached_event_tail) % MAX_KEYS;
- return cached_key_head != cached_key_tail || clipboard_fix ||
- (events_available > 0 &&
- !(events_available == 1 &&
- cached_events[cached_event_tail].e.message == kCoreEventClass &&
- *(long *)&cached_events[cached_event_tail].e.where == kAEOpenApplication));
- }
-
- int
- handle_all_events_but_keystrokes(char *p,int n)
- {
- int m;
- long refCon;
- EventRecord e;
- AppleEvent ae,reply;
-
- read_events(0);
-
- if (clipboard_fix) {
- clipboard_fix = 0;
- fixup_clipboard(clipboard_fix_update_contents);
- refresh_screen();
- }
-
- while (cached_event_head != cached_event_tail) {
- e = cached_events[cached_event_tail].e;
- ae = cached_events[cached_event_tail].ae;
- reply = cached_events[cached_event_tail].reply;
- refCon = cached_events[cached_event_tail].refCon;
- cached_event_tail = (cached_event_tail + 1) % MAX_EVENTS;
- do_event(&e,&ae,&reply,refCon);
- }
-
- m = 0;
- while (cached_key_head != cached_key_tail && m != n) {
- p[m++] = cached_keys[cached_key_tail];
- cached_key_tail = (cached_key_tail + 1) % MAX_KEYS;
- }
-
- return m;
- }
-
- void
- discard_tty_input(void)
- {
- FlushEvents(keyDownMask | autoKeyMask,0);
- }
-