From 08fe0c62213c3897a4afcf8ee9c2de44d61f1442 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 23 Oct 2019 21:52:37 +0000 Subject: Rework and simplify services so the TkService object won't interfere with IME. It didn't need to be a subclass of NSView, or be in the Responder chain. --- library/entry.tcl | 5 -- library/text.tcl | 6 --- library/tk.tcl | 5 -- library/ttk/entry.tcl | 7 --- macosx/tkMacOSXInit.c | 6 +-- macosx/tkMacOSXKeyEvent.c | 1 - macosx/tkMacOSXServices.c | 126 +++++++------------------------------------ macosx/tkMacOSXWindowEvent.c | 18 +++++-- 8 files changed, 35 insertions(+), 139 deletions(-) diff --git a/library/entry.tcl b/library/entry.tcl index 8d1b1b3..36c331d 100644 --- a/library/entry.tcl +++ b/library/entry.tcl @@ -74,11 +74,6 @@ bind Entry <> { # Standard Motif bindings: -bind Entry { - if {[tk windowingsystem] eq "aqua"} { - ::tk::RegisterServiceWidget %W - } -} bind Entry <1> { tk::EntryButton1 %W %x %W selection clear diff --git a/library/text.tcl b/library/text.tcl index c4e3388..0530cf5 100644 --- a/library/text.tcl +++ b/library/text.tcl @@ -42,12 +42,6 @@ # Standard Motif bindings: -bind Text { - if {[tk windowingsystem] eq "aqua"} { - ::tk::RegisterServiceWidget %W - } -} - bind Text <1> { tk::TextButton1 %W %x %y %W tag remove sel 0.0 end diff --git a/library/tk.tcl b/library/tk.tcl index 572c1f0..60107cf 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -687,11 +687,6 @@ if {[tk windowingsystem] eq "aqua"} { if {[tk windowingsystem] eq "aqua"} { - #register to send data to macOS Services - proc ::tk::RegisterServiceWidget {w} { - ::tk::mac::registerServiceWidget $w - } - #stub procedures to respond to "do script" Apple Events proc ::tk::mac::DoScriptFile {file} { source $file diff --git a/library/ttk/entry.tcl b/library/ttk/entry.tcl index 8f21ecc..6a34488 100644 --- a/library/ttk/entry.tcl +++ b/library/ttk/entry.tcl @@ -58,13 +58,6 @@ option add *TEntry.cursor [ttk::cursor text] widgetDefault # and I'll put it back. # -##Bindings to register with macOS Services API. -bind T.Entry { - if {[tk windowingsystem] eq "aqua"} { - ::tk::RegisterServiceWidget %W - } -} - ## Clipboard events: # bind TEntry <> { ttk::entry::Cut %W } diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 2ba4d28..e3ea481 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -406,8 +406,7 @@ TkpInit( /* * Initialize the NSServices object here. Apple's docs say to do this * in applicationDidFinishLaunching, but the Tcl interpreter is not - * initialized until this function call. Only the main interpreter - * is allowed to provide services. + * initialized until this function call. */ TkMacOSXServices_Init(interp); @@ -427,9 +426,6 @@ TkpInit( Tcl_CreateObjCommand(interp, "::tk::mac::iconBitmap", TkMacOSXIconBitmapObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath", TkMacOSXGetAppPath, NULL, NULL); - Tcl_CreateObjCommand(interp, "::tk::mac::registerServiceWidget", - TkMacOSXRegisterServiceWidgetObjCmd, NULL, NULL); - return TCL_OK; } diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index ce9a452..e3a4193 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -381,7 +381,6 @@ static unsigned isFunctionKey(unsigned int code); replacementRange: (NSRange)repRange { TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); - Tk_Window tkwin = (Tk_Window) winPtr; Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr; NSString *temp; NSString *str = [aString respondsToSelector:@selector (string)] ? diff --git a/macosx/tkMacOSXServices.c b/macosx/tkMacOSXServices.c index 02c0fda..914ef53 100644 --- a/macosx/tkMacOSXServices.c +++ b/macosx/tkMacOSXServices.c @@ -10,14 +10,11 @@ * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#include #include #include -static Tcl_Interp *ServicesInterp; - /* - * Event proc which calls the PerformService procedure + * Event proc which calls the PerformService procedure. */ static int @@ -25,21 +22,24 @@ ServicesEventProc( Tcl_Event *event, int flags) { - Tcl_GlobalEval(ServicesInterp, "::tk::mac::PerformService"); + TkMainInfo *info = TkGetMainInfoList(); + Tcl_GlobalEval(info->interp, "::tk::mac::PerformService"); return 1; } /* - * Class declarations for TkService class. + * The Wish application can send the current selection in the Tk clipboard + * to other applications which accept messages of type NSString. The TkService + * object provides this service via its provideService method. (The method + * must be specified in the application's Info.plist file for this to work.) */ -@interface TkService : NSView { +@interface TkService : NSObject { } + (void) initialize; -- (void)provideService:(NSPasteboard *)pboard userData:(NSString *)data error:(NSString **)error; -- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType; +- (void) provideService:(NSPasteboard *)pboard userData:(NSString *)data error:(NSString **)error; - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard types:(NSArray *)types; @end @@ -57,32 +57,8 @@ ServicesEventProc( return; } - -- (id)validRequestorForSendType:(NSString *)sendType - returnType:(NSString *)returnType -{ - if ([sendType isEqualToString:@"NSStringPboardType"] || - [sendType isEqualToString:@"NSPasteboardTypeString"]) { - return self; - } - return [super validRequestorForSendType:sendType returnType:returnType]; -} - /* - * Make sure the view accepts events. - */ - -- (BOOL)acceptsFirstResponder -{ - return YES; -} -- (BOOL)becomeFirstResponder -{ - return YES; -} - -/* - * Get selected text, copy to pasteboard. + * Get the current selection and copy it to the sysstem pasteboard. */ - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard @@ -90,6 +66,7 @@ ServicesEventProc( { NSArray *typesDeclared = nil; NSString *pboardType = nil; + TkMainInfo *info = TkGetMainInfoList(); for (NSString *typeString in types) { if ([typeString isEqualToString:@"NSStringPboardType"] || @@ -102,9 +79,9 @@ ServicesEventProc( if (!typesDeclared) { return NO; } - Tcl_Eval(ServicesInterp, "selection get"); + Tcl_Eval(info->interp, "selection get"); - char *copystring = Tcl_GetString(Tcl_GetObjResult(ServicesInterp)); + char *copystring = Tcl_GetString(Tcl_GetObjResult(info->interp)); NSString *writestring = [NSString stringWithUTF8String:copystring]; [pboard declareTypes:typesDeclared owner:nil]; @@ -112,8 +89,8 @@ ServicesEventProc( } /* - * This is the method that actually calls the Tk service; this is the method - * that must be defined in info.plist. + * This is the method that actually calls the Tk service; it must be specified + * in Info.plist. */ - (void)provideService:(NSPasteboard *)pboard @@ -125,8 +102,8 @@ ServicesEventProc( Tcl_Event *event; /* - * Get string from private pasteboard, write to general pasteboard to make - * available to Tcl service. + * Get a string from the private pasteboard and copy it to the general + * pasteboard to make it available to other applications. */ for (NSString *typeString in types) { @@ -150,69 +127,8 @@ ServicesEventProc( @end /* - * Register a specific widget to access the Services menu. - */ - -int -TkMacOSXRegisterServiceWidgetObjCmd( - ClientData cd, - Tcl_Interp *ip, - int objc, - Tcl_Obj *const objv[]) -{ - /* - * Need proper number of args. - */ - - if (objc != 2) { - Tcl_WrongNumArgs(ip, 1, objv, "path?"); - return TCL_ERROR; - } - - /* - * Get the object that holds this Tk Window... - */ - - Rect bounds; - NSRect frame; - Tk_Window path = - Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip)); - - if (path == NULL) { - return TCL_ERROR; - } - - Tk_MakeWindowExist(path); - Tk_MapWindow(path); - Drawable d = Tk_WindowId(path); - - /* - * Get NSView from Tk window and add subview. - */ - - TkService *serviceview = [[TkService alloc] init]; - NSView *view = TkMacOSXGetRootControl(d); - - if ([serviceview superview] != view) { - [view addSubview:serviceview]; - } - TkMacOSXWinBounds((TkWindow*)path, &bounds); - - /* - * Hack to make sure subview is set to take up entire geometry of window. - */ - - frame = NSMakeRect(bounds.left, bounds.top, 100000, 100000); - frame.origin.y = 0; - if (!NSEqualRects(frame, [serviceview frame])) { - [serviceview setFrame:frame]; - } - [serviceview release]; - return TCL_OK; -} - -/* - * Initalize the package in the Tcl interpreter, create Tcl commands. + * Instiantiate a TkService object and register it with the NSApplication. + * This is called (once only) from TkpInit. */ int @@ -220,12 +136,10 @@ TkMacOSXServices_Init( Tcl_Interp *interp) { /* - * Initialize instance of TclServices to provide service functionality. + * Initialize an instance of TkService and register it with the NSApp. */ TkService *service = [[TkService alloc] init]; - - ServicesInterp = interp; [NSApp setServicesProvider:service]; return TCL_OK; } diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 833df8c..c7b1c6a 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -1186,11 +1186,21 @@ RedisplayView( return YES; } -- (void) keyDown: (NSEvent *) theEvent +/* + * When the services menu is opened this is called for each Responder in + * the Responder chain until a service provider is found. The TkContentView + * should be the first (and generally only) Responder in the chain. We + * return the TkServices object that was created in TkpInit. + */ + +- (id)validRequestorForSendType:(NSString *)sendType + returnType:(NSString *)returnType { -#ifdef TK_MAC_DEBUG_EVENTS - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); -#endif + if ([sendType isEqualToString:@"NSStringPboardType"] || + [sendType isEqualToString:@"NSPasteboardTypeString"]) { + return [NSApp servicesProvider]; + } + return [super validRequestorForSendType:sendType returnType:returnType]; } @end -- cgit v0.12