Commit 28714a27 authored by YAMAMOTO Mitsuharu's avatar YAMAMOTO Mitsuharu
Browse files

Include keymap.h.

(mac_ready_for_apple_events): New variable.
(Vmac_apple_event_map, Qmac_apple_event_class)
(Qmac_apple_event_id): New variables.
(syms_of_macselect): Initialize them.
(Qundefined, mac_store_apple_event): Add externs.
(struct apple_event_binding): New struct.
(find_event_binding_fun, find_event_binding)
(mac_find_apple_event_spec, defer_apple_events)
(mac_handle_apple_event, init_apple_event_handler)
(copy_scrap_flavor_data): New functions.
(Fmac_process_deferred_apple_events): New defun.
(syms_of_macselect): Defsubr it.
(mac_store_services_event): Fix extern.
(mac_handle_service_event): Don't allocate Lisp objects during
asynchronous input processing.  Use mac_store_services_event
instead of mac_store_application_menu_event.
parent 31b6888a
......@@ -23,6 +23,7 @@ Boston, MA 02110-1301, USA. */
#include "lisp.h"
#include "macterm.h"
#include "blockinput.h"
#include "keymap.h"
#if !TARGET_API_MAC_CARBON
#include <Endian.h>
......@@ -907,6 +908,253 @@ and t is the same as `SECONDARY'. */)
return result;
}
int mac_ready_for_apple_events = 0;
static Lisp_Object Vmac_apple_event_map;
static Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id;
static struct
{
AppleEvent *buf;
int size, count;
} deferred_apple_events;
extern Lisp_Object Qundefined;
extern OSErr mac_store_apple_event P_ ((Lisp_Object, Lisp_Object,
const AEDesc *));
struct apple_event_binding
{
UInt32 code; /* Apple event class or ID. */
Lisp_Object key, binding;
};
static void
find_event_binding_fun (key, binding, args, data)
Lisp_Object key, binding, args;
void *data;
{
struct apple_event_binding *event_binding =
(struct apple_event_binding *)data;
Lisp_Object code_string;
if (!SYMBOLP (key))
return;
code_string = Fget (key, args);
if (STRINGP (code_string) && SBYTES (code_string) == 4
&& (EndianU32_BtoN (*((UInt32 *) SDATA (code_string)))
== event_binding->code))
{
event_binding->key = key;
event_binding->binding = binding;
}
}
static void
find_event_binding (keymap, event_binding, class_p)
Lisp_Object keymap;
struct apple_event_binding *event_binding;
int class_p;
{
if (event_binding->code == 0)
event_binding->binding =
access_keymap (keymap, event_binding->key, 0, 1, 0);
else
{
event_binding->binding = Qnil;
map_keymap (keymap, find_event_binding_fun,
class_p ? Qmac_apple_event_class : Qmac_apple_event_id,
event_binding, 0);
}
}
void
mac_find_apple_event_spec (class, id, class_key, id_key, binding)
AEEventClass class;
AEEventID id;
Lisp_Object *class_key, *id_key, *binding;
{
struct apple_event_binding event_binding;
Lisp_Object keymap;
*binding = Qnil;
keymap = get_keymap (Vmac_apple_event_map, 0, 0);
if (NILP (keymap))
return;
event_binding.code = class;
event_binding.key = *class_key;
event_binding.binding = Qnil;
find_event_binding (keymap, &event_binding, 1);
*class_key = event_binding.key;
keymap = get_keymap (event_binding.binding, 0, 0);
if (NILP (keymap))
return;
event_binding.code = id;
event_binding.key = *id_key;
event_binding.binding = Qnil;
find_event_binding (keymap, &event_binding, 0);
*id_key = event_binding.key;
*binding = event_binding.binding;
}
static OSErr
defer_apple_events (apple_event, reply)
const AppleEvent *apple_event, *reply;
{
OSErr err;
err = AESuspendTheCurrentEvent (apple_event);
/* Mac OS 10.3 Xcode manual says AESuspendTheCurrentEvent makes
copies of the Apple event and the reply, but Mac OS 10.4 Xcode
manual says it doesn't. Anyway we create copies of them and save
it in `deferred_apple_events'. */
if (err == noErr)
{
if (deferred_apple_events.buf == NULL)
{
deferred_apple_events.size = 16;
deferred_apple_events.count = 0;
deferred_apple_events.buf =
xmalloc (sizeof (AppleEvent) * deferred_apple_events.size);
if (deferred_apple_events.buf == NULL)
err = memFullErr;
}
else if (deferred_apple_events.count == deferred_apple_events.size)
{
AppleEvent *newbuf;
deferred_apple_events.size *= 2;
newbuf = xrealloc (deferred_apple_events.buf,
sizeof (AppleEvent) * deferred_apple_events.size);
if (newbuf)
deferred_apple_events.buf = newbuf;
else
err = memFullErr;
}
}
if (err == noErr)
{
int count = deferred_apple_events.count;
AEDuplicateDesc (apple_event, deferred_apple_events.buf + count);
AEDuplicateDesc (reply, deferred_apple_events.buf + count + 1);
deferred_apple_events.count += 2;
}
return err;
}
static pascal OSErr
mac_handle_apple_event (apple_event, reply, refcon)
const AppleEvent *apple_event;
AppleEvent *reply;
SInt32 refcon;
{
OSErr err;
AEEventClass event_class;
AEEventID event_id;
Lisp_Object class_key, id_key, binding;
/* We can't handle an Apple event that requests a reply, but this
seems to be too restrictive. */
#if 0
if (reply->descriptorType != typeNull)
return errAEEventNotHandled;
#endif
if (!mac_ready_for_apple_events)
{
err = defer_apple_events (apple_event, reply);
if (err != noErr)
return errAEEventNotHandled;
return noErr;
}
err = AEGetAttributePtr (apple_event, keyEventClassAttr, typeType, NULL,
&event_class, sizeof (AEEventClass), NULL);
if (err == noErr)
err = AEGetAttributePtr (apple_event, keyEventIDAttr, typeType, NULL,
&event_id, sizeof (AEEventID), NULL);
if (err == noErr)
{
mac_find_apple_event_spec (event_class, event_id,
&class_key, &id_key, &binding);
if (!NILP (binding) && !EQ (binding, Qundefined))
{
if (INTEGERP (binding))
return XINT (binding);
err = mac_store_apple_event (class_key, id_key, apple_event);
if (err == noErr)
return noErr;
}
}
return errAEEventNotHandled;
}
void
init_apple_event_handler ()
{
OSErr err;
long result;
/* Make sure we have Apple events before starting. */
err = Gestalt (gestaltAppleEventsAttr, &result);
if (err != noErr)
abort ();
if (!(result & (1 << gestaltAppleEventsPresent)))
abort ();
err = AEInstallEventHandler (typeWildCard, typeWildCard,
#if TARGET_API_MAC_CARBON
NewAEEventHandlerUPP (mac_handle_apple_event),
#else
NewAEEventHandlerProc (mac_handle_apple_event),
#endif
0L, false);
if (err != noErr)
abort ();
}
DEFUN ("mac-process-deferred-apple-events", Fmac_process_deferred_apple_events, Smac_process_deferred_apple_events, 0, 0, 0,
doc: /* Process Apple events that are deferred at the startup time. */)
()
{
OSErr err;
Lisp_Object result = Qnil;
long i, count;
AppleEvent apple_event, reply;
AEKeyword keyword;
if (mac_ready_for_apple_events)
return Qnil;
BLOCK_INPUT;
mac_ready_for_apple_events = 1;
if (deferred_apple_events.buf)
{
for (i = 0; i < deferred_apple_events.count; i += 2)
{
AEResumeTheCurrentEvent (deferred_apple_events.buf + i,
deferred_apple_events.buf + i + 1,
((AEEventHandlerUPP)
kAEUseStandardDispatch), 0);
AEDisposeDesc (deferred_apple_events.buf + i);
AEDisposeDesc (deferred_apple_events.buf + i + 1);
}
xfree (deferred_apple_events.buf);
bzero (&deferred_apple_events, sizeof (deferred_apple_events));
result = Qt;
}
UNBLOCK_INPUT;
return result;
}
#ifdef MAC_OSX
void
......@@ -920,7 +1168,56 @@ init_service_handler ()
GetEventTypeCount (specs), specs, NULL, NULL);
}
extern void mac_store_services_event P_ ((EventRef));
extern OSErr mac_store_services_event P_ ((EventRef));
static OSStatus
copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
ScrapRef from_scrap, to_scrap;
ScrapFlavorType flavor_type;
{
OSStatus err;
Size size, size_allocated;
char *buf = NULL;
err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
if (err == noErr)
buf = xmalloc (size);
while (buf)
{
size_allocated = size;
err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
if (err != noErr)
{
xfree (buf);
buf = NULL;
}
else if (size_allocated < size)
{
char *newbuf = xrealloc (buf, size);
if (newbuf)
buf = newbuf;
else
{
xfree (buf);
buf = NULL;
}
}
else
break;
}
if (err == noErr)
if (buf == NULL)
err = memFullErr;
else
{
err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
size, buf);
xfree (buf);
}
return err;
}
static OSStatus
mac_handle_service_event (call_ref, event, data)
......@@ -929,7 +1226,12 @@ mac_handle_service_event (call_ref, event, data)
void *data;
{
OSStatus err = noErr;
ScrapRef cur_scrap;
ScrapRef cur_scrap, specific_scrap;
UInt32 event_kind = GetEventKind (event);
CFMutableArrayRef copy_types, paste_types;
CFStringRef type;
Lisp_Object rest;
ScrapFlavorType flavor_type;
/* Check if Vmac_services_selection is a valid selection that has a
corresponding scrap. */
......@@ -940,86 +1242,103 @@ mac_handle_service_event (call_ref, event, data)
if (!(err == noErr && cur_scrap))
return eventNotHandledErr;
switch (GetEventKind (event))
switch (event_kind)
{
case kEventServiceGetTypes:
{
CFMutableArrayRef copy_types, paste_types;
CFStringRef type;
Lisp_Object rest;
ScrapFlavorType flavor_type;
/* Set paste types. */
err = GetEventParameter (event, kEventParamServicePasteTypes,
typeCFMutableArrayRef, NULL,
sizeof (CFMutableArrayRef), NULL,
&paste_types);
if (err == noErr)
for (rest = Vselection_converter_alist; CONSP (rest);
rest = XCDR (rest))
if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
&& (flavor_type =
get_flavor_type_from_symbol (XCAR (XCAR (rest)))))
/* Set paste types. */
err = GetEventParameter (event, kEventParamServicePasteTypes,
typeCFMutableArrayRef, NULL,
sizeof (CFMutableArrayRef), NULL,
&paste_types);
if (err != noErr)
break;
for (rest = Vselection_converter_alist; CONSP (rest);
rest = XCDR (rest))
if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
&& (flavor_type =
get_flavor_type_from_symbol (XCAR (XCAR (rest)))))
{
type = CreateTypeStringWithOSType (flavor_type);
if (type)
{
type = CreateTypeStringWithOSType (flavor_type);
if (type)
{
CFArrayAppendValue (paste_types, type);
CFRelease (type);
}
CFArrayAppendValue (paste_types, type);
CFRelease (type);
}
}
/* Set copy types. */
err = GetEventParameter (event, kEventParamServiceCopyTypes,
typeCFMutableArrayRef, NULL,
sizeof (CFMutableArrayRef), NULL,
&copy_types);
if (err == noErr
&& !NILP (Fx_selection_owner_p (Vmac_services_selection)))
for (rest = get_scrap_target_type_list (cur_scrap);
CONSP (rest) && SYMBOLP (XCAR (rest)); rest = XCDR (rest))
{
flavor_type = get_flavor_type_from_symbol (XCAR (rest));
if (flavor_type)
{
type = CreateTypeStringWithOSType (flavor_type);
if (type)
{
CFArrayAppendValue (copy_types, type);
CFRelease (type);
}
}
}
}
break;
/* Set copy types. */
err = GetEventParameter (event, kEventParamServiceCopyTypes,
typeCFMutableArrayRef, NULL,
sizeof (CFMutableArrayRef), NULL,
&copy_types);
if (err != noErr)
break;
if (NILP (Fx_selection_owner_p (Vmac_services_selection)))
break;
else
goto copy_all_flavors;
case kEventServiceCopy:
{
ScrapRef specific_scrap;
Lisp_Object rest, data;
err = GetEventParameter (event, kEventParamScrapRef,
typeScrapRef, NULL,
sizeof (ScrapRef), NULL, &specific_scrap);
if (err == noErr
&& !NILP (Fx_selection_owner_p (Vmac_services_selection)))
for (rest = get_scrap_target_type_list (cur_scrap);
CONSP (rest) && SYMBOLP (XCAR (rest)); rest = XCDR (rest))
{
data = get_scrap_string (cur_scrap, XCAR (rest));
if (STRINGP (data))
err = put_scrap_string (specific_scrap, XCAR (rest), data);
}
else
err = GetEventParameter (event, kEventParamScrapRef,
typeScrapRef, NULL,
sizeof (ScrapRef), NULL, &specific_scrap);
if (err != noErr
|| NILP (Fx_selection_owner_p (Vmac_services_selection)))
{
err = eventNotHandledErr;
break;
}
copy_all_flavors:
{
UInt32 count, i;
ScrapFlavorInfo *flavor_info = NULL;
ScrapFlavorFlags flags;
err = GetScrapFlavorCount (cur_scrap, &count);
if (err == noErr)
flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
if (flavor_info)
{
err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
if (err != noErr)
{
xfree (flavor_info);
flavor_info = NULL;
}
}
if (flavor_info == NULL)
break;
for (i = 0; i < count; i++)
{
flavor_type = flavor_info[i].flavorType;
err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
{
if (event_kind == kEventServiceCopy)
err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
flavor_type);
else /* event_kind == kEventServiceGetTypes */
{
type = CreateTypeStringWithOSType (flavor_type);
if (type)
{
CFArrayAppendValue (copy_types, type);
CFRelease (type);
}
}
}
}
xfree (flavor_info);
}
break;
case kEventServicePaste:
case kEventServicePerform:
{
ScrapRef specific_scrap;
Lisp_Object rest, data;
int data_exists_p = 0;
err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
......@@ -1033,25 +1352,24 @@ mac_handle_service_event (call_ref, event, data)
{
if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
continue;
data = get_scrap_string (specific_scrap, XCAR (XCAR (rest)));
if (STRINGP (data))
{
err = put_scrap_string (cur_scrap, XCAR (XCAR (rest)),
data);
if (err != noErr)
break;
data_exists_p = 1;
}
flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)));
if (flavor_type == 0)
continue;
err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
flavor_type);
if (err == noErr)
data_exists_p = 1;
}
if (err == noErr)
if (data_exists_p)
mac_store_application_menu_event (event);
else
err = eventNotHandledErr;
if (!data_exists_p)
err = eventNotHandledErr;
else
err = mac_store_services_event (event);
}
break;
}
if (err != noErr)
err = eventNotHandledErr;
return err;
}
#endif
......@@ -1065,6 +1383,7 @@ syms_of_macselect ()
defsubr (&Sx_disown_selection_internal);
defsubr (&Sx_selection_owner_p);
defsubr (&Sx_selection_exists_p);
defsubr (&Smac_process_deferred_apple_events);
Vselection_alist = Qnil;
staticpro (&Vselection_alist);
......@@ -1106,6 +1425,10 @@ next communication only. After the communication, this variable is
set to nil. */);
Vnext_selection_coding_system = Qnil;
DEFVAR_LISP ("mac-apple-event-map", &Vmac_apple_event_map,
doc: /* Keymap for Apple events handled by Emacs. */);
Vmac_apple_event_map = Fmake_sparse_keymap (Qnil);
#ifdef MAC_OSX
DEFVAR_LISP ("mac-services-selection", &Vmac_services_selection,
doc: /* Selection name for communication via Services menu. */);
......@@ -1125,6 +1448,12 @@ set to nil. */);
Qmac_ostype = intern ("mac-ostype");
staticpro (&Qmac_ostype);
Qmac_apple_event_class = intern ("mac-apple-event-class");
staticpro (&Qmac_apple_event_class);
Qmac_apple_event_id = intern ("mac-apple-event-id");
staticpro (&Qmac_apple_event_id);
}
/* arch-tag: f3c91ad8-99e0-4bd6-9eef-251b2f848732
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment