diff options
author | Kevin Walzer <kw@codebykevin.com> | 2020-10-02 02:34:37 (GMT) |
---|---|---|
committer | Kevin Walzer <kw@codebykevin.com> | 2020-10-02 02:34:37 (GMT) |
commit | 136444972d9963013205ee40b6ec4c1b8b806f30 (patch) | |
tree | 9968be5c03ec081295ee82efcdb03f875e295d69 | |
parent | c9cf198e8fc9bf2f5f2fd5c3c6f1c921da9af940 (diff) | |
download | tk-136444972d9963013205ee40b6ec4c1b8b806f30.zip tk-136444972d9963013205ee40b6ec4c1b8b806f30.tar.gz tk-136444972d9963013205ee40b6ec4c1b8b806f30.tar.bz2 |
Initial macOS implementation
-rw-r--r-- | macosx/TkMacOSXSysTray.c | 448 | ||||
-rw-r--r-- | macosx/tkMacOSXInit.c | 1 | ||||
-rw-r--r-- | unix/Makefile.in | 5 | ||||
-rw-r--r-- | win/tkWinSysTray.c | 2 |
4 files changed, 454 insertions, 2 deletions
diff --git a/macosx/TkMacOSXSysTray.c b/macosx/TkMacOSXSysTray.c new file mode 100644 index 0000000..e605201 --- /dev/null +++ b/macosx/TkMacOSXSysTray.c @@ -0,0 +1,448 @@ +/* + * tkMacOSXSysTray.c -- + * + * tkMacOSXSysTray.c implements a "systray" Tcl command which allows one to + * change the system tray/taskbar icon of a Tk toplevel window and + * a "sysnotify" command to post system notifications. + * + * Copyright (c) 2020 Kevin Walzer/WordTech Communications LLC. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include <tkInt.h> +#include <tkMacOSXInt.h> +#include "tkMacOSXPrivate.h" + +/* + * Script callback when status icon is clicked. + */ + +char * callbackproc; + +/* + * Class declaratons and implementations for TkStatusItem. + */ + +@interface TkStatusItem: NSObject { + NSStatusItem * statusItem; + NSStatusBar * statusBar; + NSImage * icon; + NSString * tooltip; + + +- (id) init; +- (void) setImage: withImage: (NSImage * ) image; +- (void) setText: withString: (NSString * ) string; +- (void) clickOnStatusItem: (id) sender; +- (void) dealloc; + +} + +@end + +@implementation TkStatusItem + +- (id) init { + [super init]; + statusBar = [NSStatusBar systemStatusBar]; + statusItem = [statusBar statusItemWithLength: NSSquareStatusItemLength]; + statusItem.button.target = self; + statusItem.button.action = @selector(clickOnStatusItem: ); + return self; +} + +- (void) setImage: withImage: (NSImage * ) image +{ + icon = image; + icon.template = YES; + statusItem.button.image = icon; +} + +- (void) setText: withString: (NSString * ) string +{ + tooltip = string; + statusItem.button.tooltip = tooltip; +} + +- (void) clickOnStatusItem: (id) sender +{ + if (NSApp.currentEvent.clickCount == 1) { + TkMainInfo * info = TkGetMainInfoList(); + Tcl_GlobalEval(info -> interp, callbackproc); + } +} + +- (void) dealloc +{ + [statusBar removeStatusItem: statusItem]; + [icon release]; + [tooltip release]; + [statusItem release]; + [statusBar release]; + + [super dealloc]; +} + +@end + +/* + * Class declaratons and implementations for TkNotifyItem. + */ + +@interface TkNotifyItem: NSObject { + + NSUserNotification *tk_notification; + NSString *header; + NSString *info + +- (id) init; +- (void) postNotification: withTitle: (NSString *) title andDetail: (NSString *) detail; +- (BOOL) userNotificationCenter:(NSUserNotificationCenter *)center + shouldPresentNotification:(NSUserNotification *)notification; +- (void) dealloc; +} + +@end + +@implementation: TkNotifyItem + +- (id) init +{ + [super init]; + tk_notification = [[NSUserNotification alloc] init]; + return self; +} + +- (void) postNotification: withTitle: (NSString * ) title andDetail: (NSString * ) detail +{ + header = title; + tk_notification.title = header; + info = detail; + tk_notification.informativeText = info; + tk_notification.soundName = NSUserNotificationDefaultSoundName; + +} + +- (BOOL) userNotificationCenter: (NSUserNotificationCenter * ) center + shouldPresentNotification: (NSUserNotification * ) notification +{ + return YES; +} + +- (void) dealloc +{ + [header release]; + [info release]; + [super dealloc]; +} + +@end + + +/* + * Forward declarations for procedures defined in this file. + */ + +static int +MacSystrayCmd(ClientData clientData, Tcl_Interp * interp, + int argc, + const char * argv[]); +static int +MacSystrayModifyCmd(ClientData clientData, Tcl_Interp * interp, + int argc, + const char * argv[]); +static void +MacSystrayDestroy(ClientData clientData); +static void SysNotifyDeleteCmd ( ClientData cd ); +static int SysNotifyCmd (ClientData clientData, Tcl_Interp * interp, + int argc, const char * argv[]); +int +MacSystrayInit(Tcl_Interp * interp); + +/* + *---------------------------------------------------------------------- + * + * MacSystrayCmd -- + * + * Main command for creating, displaying, and removing icons from status menu. + * + * Results: + * Management of icon display in status menu. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + +static int +MacSystrayCmd(ClientData clientData, Tcl_Interp * interp, + int argc, + const char * argv[]) { + + if ((strcmp argv[1], "modify") == 0) { + MacSystrayModifyCmd(clientData, interp, argc, argv); + return TCL_OK; + } + + if (argc < 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"systray create image ? text? callback?\"", (char * ) NULL); + return TCL_ERROR; + } + + /* + * Create the icon. + */ + + Tk_Window tkwin = Tk_MainWindow(interp); + TkWindow winPtr = (TkWindow) tkwin; + Display * d; + d = winPtr -> display; + NSImage * icon; + + char * tk_imagename = Tcl_GetString(argv[2]); + Tk_Image tk_image; + tk_image = Tk_GetImage(interp, tkwin, tk_imagename, NULL, NULL); + if (tk_image == NULL) { + Tcl_AppendResult(interp, "unable to obtain image for systray icon", (char * ) NULL); + return TCL_ERROR; + } + + Tk_SizeOfImage(tk_image, & width, & height); + if (width != 0 && height != 0) { + icon = TkMacOSXGetNSImageFromTkImage(d, tk_icon, + width, height); + [tk_item setImage: withImage: icon]; + } + + /* + * Set the text for the tooltip. + */ + + NSString * tooltip = [NSString stringWithUTF8String: Tcl_GetString(argv[3])]; + if (tooltip == nil) { + Tcl_AppendResult(interp, "unable to set tooltip for systray icon", (char * ) NULL); + return TCL_ERROR; + } + + [tk_item setText: withString: tooltip]; + + /* + * Set the proc for the callback. + */ + + callbackproc = Tcl_GetString(argv[4]); + if (callbackproc == NULL) { + Tcl_AppendResult(interp, "unable to get the callback for systray icon", (char * ) NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +static int +MacSystrayModifyCmd(ClientData clientData, Tcl_Interp * interp, + int argc, + const char * argv[]) { + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"systray modify object?\"", (char * ) NULL); + return TCL_ERROR; + } + + char * modifyitem = Tcl_GetString(argv[2]); + + /* + * Modify the icon. + */ + + if ((strcmp modifyitem, "image") == 0) { + + Tk_Window tkwin = Tk_MainWindow(interp); + TkWindow winPtr = (TkWindow) tkwin; + Display * d; + d = winPtr -> display; + NSImage * icon; + + char * tk_imagename = Tcl_GetString(argv[3]); + Tk_Image tk_image; + tk_image = Tk_GetImage(interp, tkwin, tk_imagename, NULL, NULL); + if (tk_image == NULL) { + Tcl_AppendResult(interp, "unable to obtain image for systray icon", (char * ) NULL); + return TCL_ERROR; + } + + Tk_SizeOfImage(tk_image, & width, & height); + if (width != 0 && height != 0) { + icon = TkMacOSXGetNSImageFromTkImage(d, tk_icon, + width, height); + [tk_item setImage: withImage: icon]; + } + } + + /* + * Modify the text for the tooltip. + */ + + if ((strcmp modifyitem, "text") == 0) { + + NSString * tooltip = [NSString stringWithUTF8String: Tcl_GetString(argv[2])]; + if (tooltip == nil) { + Tcl_AppendResult(interp, "unable to set tooltip for systray icon", (char * ) NULL); + return TCL_ERROR; + } + + [tk_item setText: withString: tooltip]; + } + + /* + * Modify the proc for the callback. + */ + + if ((strcmp modifyitem, "callback") == 0) { + callbackproc = Tcl_GetString(argv[2]); + if (callbackproc == NULL) { + Tcl_AppendResult(interp, "unable to get the callback for systray icon", (char * ) NULL); + return TCL_ERROR; + } + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * MacSystrayDestroy -- + * + * Deletes icon and hidden window from display. + * + * Results: + * Icon/window removed and memory freed. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +MacSystrayDestroy(ClientData clientData) { + + [tk_item dealloc]; + +} + + +/* + *---------------------------------------------------------------------- + * + * SysNotifyDeleteCmd -- + * + * Delete notification and clean up. + * + * Results: + * Window destroyed. + * + * Side effects: + * None. + * + *-------------------------------z--------------------------------------- + */ + + +static void SysNotifyDeleteCmd ( ClientData cd ) +{ + (void) cd; + [notify_item dealloc]; +} + + +/* + *---------------------------------------------------------------------- + * + * SysNotifyCreateCmd -- + * + * Create tray command and (unreal) window. + * + * Results: + * Icon tray and hidden window created. + * + * Side effects: + * None. + * + *-------------------------------z--------------------------------------- + */ + + +static int SysNotifyCmd(ClientData clientData, Tcl_Interp * interp, + int argc, const char * argv[]) +{ + (void)clientData; + + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args,must be:", + argv[0], " title message ", (char * ) NULL); + return TCL_ERROR; + } + + NSString *title = [NSString stringWithUTF8String: Tcl_GetString(argv[1])]; + NSString *message = [NSString stringWithUTF8String: Tcl_GetString(argv[2])]; + [notify_item postNotification: withTitle: title andDetail: message]; + + return TCL_OK; +} + + +/* + *---------------------------------------------------------------------- + * + * MacSystrayInit -- + * + * Initialize this package and create script-level commands. + * + * Results: + * Initialization of code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +MacSystrayInit(Tcl_Interp * interp) { + + /* + * Initialize TkStatusItem and TkNotifyItem. + */ + + if ([NSApp macOSVersion] < 101000) { + Tcl_AppendResult(interp, "Statusitem icons not supported on versions of macOS lower than 10.10", (char * ) NULL); + return TCL_OK; + } + + TkStatusItem *tk_item = [[TkStatusItem alloc] init]; + TkNotifyItem *notify_item = [[TkNotifyItem alloc] init]; + + + Tcl_CreateCommand(interp, "::tk::systray", MacSystrayCmd, (ClientData)interp, + (Tcl_CmdDeleteProc *) MacSystrayDestroy); + Tcl_CreateCommand(interp, "::tk::sysnotify", SysNotifyCmd, NULL, (Tcl_CmdDeleteProc *) SysNotifyDeleteCmd); + + return TCL_OK; +} + +/ + +/* + * Local Variables: + * mode: objc + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: + */ diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index bda5f46..f41cda7 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -460,6 +460,7 @@ TkpInit( TkMacOSXIconBitmapObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath", TkMacOSXGetAppPathCmd, NULL, NULL); + MacSystrayInit(interp); return TCL_OK; } diff --git a/unix/Makefile.in b/unix/Makefile.in index f215859..7faca90 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -410,7 +410,7 @@ AQUA_OBJS = tkMacOSXBitmap.o tkMacOSXButton.o tkMacOSXClipboard.o \ tkMacOSXMenubutton.o tkMacOSXMenus.o tkMacOSXMouseEvent.o \ tkMacOSXNotify.o tkMacOSXRegion.o tkMacOSXScrlbr.o tkMacOSXSend.o \ tkMacOSXServices.o tkMacOSXSubwindows.o tkMacOSXWindowEvent.o \ - tkMacOSXWm.o tkMacOSXXStubs.o \ + tkMacOSXWm.o tkMacOSXXStubs.o tkMacOSXSysTray.o\ tkFileFilter.o tkMacWinMenu.o tkPointer.o tkUnix3d.o tkUnixScale.o \ xcolors.o xdraw.o xgc.o ximage.o xutil.o \ ttkMacOSXTheme.o @@ -1379,6 +1379,9 @@ tkMacOSXWm.o: $(MAC_OSX_DIR)/tkMacOSXWm.c tkMacOSXXStubs.o: $(MAC_OSX_DIR)/tkMacOSXXStubs.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tkMacOSXXStubs.c +tkMacOSXSysTray.o: $(MAC_OSX_DIR)/tkMacOSXXStubs.c + $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tkMacOSXSysTray.c + tkFileFilter.o: $(GENERIC_DIR)/tkFileFilter.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkFileFilter.c diff --git a/win/tkWinSysTray.c b/win/tkWinSysTray.c index 878b6cd..a4f0b7a 100644 --- a/win/tkWinSysTray.c +++ b/win/tkWinSysTray.c @@ -1,7 +1,7 @@ /* * tkWinSysTray.c implements a "systray" Tcl command which permits to * change the system tray/taskbar icon of a Tk toplevel window and - * to post system notifications. + * a "systray" command to post system notifications. * * Copyright (c) 1995-1996 Microsoft Corp. * Copyright (c) 1998 Brueckner & Jarosch Ing.GmbH, Erfurt, Germany |