diff options
author | fvogel <fvogelnew1@free.fr> | 2020-11-15 20:16:26 (GMT) |
---|---|---|
committer | fvogel <fvogelnew1@free.fr> | 2020-11-15 20:16:26 (GMT) |
commit | c73c4d6eb0e6965654429e0c1a005836fed387c1 (patch) | |
tree | 74fcd1069cfa805023057ee6a7f080369cc6a99d | |
parent | cfcb386e4d14c11989ab24e34dd8d56573df8b39 (diff) | |
download | tk-c73c4d6eb0e6965654429e0c1a005836fed387c1.zip tk-c73c4d6eb0e6965654429e0c1a005836fed387c1.tar.gz tk-c73c4d6eb0e6965654429e0c1a005836fed387c1.tar.bz2 |
Eric's contribution, allowing changing the image of a systray icon without making it move in the systray.
-rw-r--r-- | library/systray.tcl | 43 | ||||
-rw-r--r-- | win/tkWinSysTray.c | 339 |
2 files changed, 161 insertions, 221 deletions
diff --git a/library/systray.tcl b/library/systray.tcl index 88d4365..ebc1fc4 100644 --- a/library/systray.tcl +++ b/library/systray.tcl @@ -159,19 +159,19 @@ proc ::tk::systray::create {args} { try { switch -- [tk windowingsystem] { "win32" { - set _ico [::tk::systray::_systray createfrom [dict get $values -image]] - ::tk::systray::_systray taskbar add $_ico -text [dict get $values -text] \ - -callback [list ::tk::systray::_win_callback %m %i] + set _ico [_systray add -image [dict get $values -image] \ + -text [dict get $values -text] \ + -callback [list ::tk::systray::_win_callback %m %i]] } "x11" { - ::tk::systray::_systray ._tray -image [dict get $values -image] -visible true - ::tk::systray::_balloon ._tray [dict get $values -text] + _systray ._tray -image [dict get $values -image] -visible true + _balloon ._tray [dict get $values -text] bind ._tray <Button-1> [dict get $values -button1] bind ._tray <Button-3> [dict get $values -button3] } "aqua" { - ::tk::systray::_systray create [dict get $values -image] [dict get $values -text] \ - [dict get $values -button1] [dict get $values -button3] + _systray create [dict get $values -image] [dict get $values -text] \ + [dict get $values -button1] [dict get $values -button3] } } } on ok {} { @@ -204,13 +204,10 @@ proc ::tk::systray::configure {args} { switch -- [tk windowingsystem] { "win32" { if {[dict exists $args -image]} { - set new_ico [::tk::systray::_systray createfrom [dict get $args -image]] - ::tk::systray::_systray taskbar delete $_ico - set _ico $new_ico - ::tk::systray::_systray taskbar add $_ico -text [dict get $values -text] \ - -callback [list ::tk::systray::_win_callback %m %i] - } elseif {[dict exists $args -text]} { - ::tk::systray::_systray taskbar modify $_ico -text [dict get $args -text] + _systray modify $_ico -image [dict get $args -image] + } + if {[dict exists $args -text]} { + _systray modify $_ico -text [dict get $args -text] } } "x11" { @@ -218,7 +215,7 @@ proc ::tk::systray::configure {args} { ._tray configure -image [dict get $args -image] } if {[dict exists $args -text]} { - ::tk::systray::_balloon ._tray [dict get $args -text] + _balloon ._tray [dict get $args -text] } if {[dict exists $args -button1]} { bind ._tray <Button-1> [dict get $args -button1] @@ -229,9 +226,9 @@ proc ::tk::systray::configure {args} { } "aqua" { foreach {key opt} {image -image text \ - -text b1_callback -button1 b3_callback -button3} { + -text b1_callback -button1 b3_callback -button3} { if {[dict exists $args $opt]} { - ::tk::systray::_systray modify $key [dict get $args $opt] + _systray modify $key [dict get $args $opt] } } } @@ -256,14 +253,14 @@ proc ::tk::systray::destroy {} { } switch -- [tk windowingsystem] { "win32" { - ::tk::systray::_systray taskbar delete $_ico + _systray delete $_ico set _ico "" } "x11" { ::destroy ._tray } "aqua" { - ::tk::systray::_systray destroy + _systray destroy } } set _created 0 @@ -304,17 +301,17 @@ proc ::tk::sysnotify {title message} { if {!$::tk::systray::_created} { error "must create a system tray icon with the \"tk systray\" command first" } - ::tk::sysnotify::_sysnotify notify $::tk::systray::_ico $title $message + _sysnotify notify $::tk::systray::_ico $title $message } "x11" { if {[info commands ::tk::sysnotify::_sysnotify] eq ""} { - ::tk::sysnotify::_notifywindow $title $message + _notifywindow $title $message } else { - ::tk::sysnotify::_sysnotify $title $message + _sysnotify $title $message } } "aqua" { - ::tk::sysnotify::_sysnotify $title $message + _sysnotify $title $message } } return diff --git a/win/tkWinSysTray.c b/win/tkWinSysTray.c index c422828..481aa1b 100644 --- a/win/tkWinSysTray.c +++ b/win/tkWinSysTray.c @@ -45,7 +45,7 @@ # define snprintf _snprintf #endif -static int CreateIcoFromTkImage(Tcl_Interp *interp, const char *image); +static BlockOfIconImagesPtr CreateIcoFromTkImage(Tcl_Interp *interp, const char *image); typedef struct IcoInfo { HICON hIcon; /* icon handle returned by LoadIcon. */ @@ -54,9 +54,9 @@ typedef struct IcoInfo { * cancel it. */ BlockOfIconImagesPtr lpIR; /* IconresourcePtr */ int iconpos; /* hIcon is the nth Icon*/ - char *taskbar_txt; /* malloced text to display in the taskbar */ + Tcl_Obj *taskbar_txt; /* text to display in the taskbar */ Tcl_Interp *interp; /* interp which created the icon */ - char *taskbar_command; /* command to eval if events in the taskbar + Tcl_Obj *taskbar_command; /* command to eval if events in the taskbar * arrive */ int taskbar_flags; /* taskbar related flags*/ HWND hwndFocus; @@ -255,12 +255,12 @@ DrawANDMask( /* *---------------------------------------------------------------------- * - * NotifyW -- + * TaskbarOperation -- * - * Display icon in system tray on more recent systems supporting Unicode. + * Management of icon display. * * Results: - * Icon is displayed. + * Icon is displayed or deleted. * * Side effects: * None. @@ -268,15 +268,12 @@ DrawANDMask( *---------------------------------------------------------------------- */ -static BOOL -NotifyW( +static int +TaskbarOperation( IcoInfo *icoPtr, - int oper, - HICON hIcon, - const char *txt) + int oper) { NOTIFYICONDATAW ni; - Tcl_DString dst; WCHAR *str; ni.cbSize = sizeof(NOTIFYICONDATAW); @@ -284,42 +281,19 @@ NotifyW( ni.uID = (unsigned int) icoPtr; ni.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; ni.uCallbackMessage = ICON_MESSAGE; - ni.hIcon = (HICON) hIcon; - - Tcl_DStringInit(&dst); - str = (WCHAR *)Tcl_UtfToWCharDString(txt, -1, &dst); - wcsncpy(ni.szTip, str, (Tcl_DStringLength(&dst) + 2) / 2); - Tcl_DStringFree(&dst); - return Shell_NotifyIconW(oper, &ni); -} - -/* - *---------------------------------------------------------------------- - * - * TaskbarOperation -- - * - * Management of icon display. - * - * Results: - * Icon is displayed or deleted. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ + ni.hIcon = icoPtr->hIcon; -static int -TaskbarOperation( - IcoInfo *icoPtr, - int oper, - HICON hIcon, - const char *txt) -{ - int result = NotifyW(icoPtr, oper, hIcon, txt); + if (icoPtr->taskbar_txt != NULL) { + Tcl_DString dst; + Tcl_DStringInit(&dst); + str = (WCHAR *)Tcl_UtfToWCharDString(Tcl_GetString(icoPtr->taskbar_txt), -1, &dst); + wcsncpy(ni.szTip, str, (Tcl_DStringLength(&dst) + 2) / 2); + Tcl_DStringFree(&dst); + } else { + ni.szTip[0] = 0; + } - Tcl_SetObjResult(icoPtr->interp, Tcl_NewIntObj(result)); - if (result == 1) { + if (Shell_NotifyIconW(oper, &ni) == 1) { if (oper == NIM_ADD || oper == NIM_MODIFY) { icoPtr->taskbar_flags |= TASKBAR_ICON; } @@ -327,6 +301,7 @@ TaskbarOperation( icoPtr->taskbar_flags &= ~TASKBAR_ICON; } } + /* Silently ignore error? */ return TCL_OK; } @@ -353,8 +328,6 @@ NewIcon( HICON hIcon, int itype, BlockOfIconImagesPtr lpIR, int iconpos) { - int n; - char buffer[5 + TCL_INTEGER_SPACE]; IcoInfo *icoPtr; icoPtr = (IcoInfo *)ckalloc(sizeof(IcoInfo)); @@ -364,10 +337,7 @@ NewIcon( icoPtr->itype = itype; icoPtr->lpIR = lpIR; icoPtr->iconpos = iconpos; - n = _snprintf(buffer, sizeof(buffer) - 1, "ico#%d", icoPtr->id); - buffer[n] = 0; - icoPtr->taskbar_txt = (char *)ckalloc(strlen(buffer) + 1); - strcpy(icoPtr->taskbar_txt, buffer); + icoPtr->taskbar_txt = NULL; icoPtr->interp = interp; icoPtr->taskbar_command = NULL; icoPtr->taskbar_flags = 0; @@ -378,7 +348,6 @@ NewIcon( } icoPtr->nextPtr = icoInterpPtr->firstIcoPtr; icoInterpPtr->firstIcoPtr = icoPtr; - Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, -1)); return icoPtr; } @@ -413,18 +382,17 @@ FreeIcoPtr( prevPtr->nextPtr = icoPtr->nextPtr; } if (icoPtr->taskbar_flags & TASKBAR_ICON) { - TaskbarOperation(icoPtr, NIM_DELETE, NULL, ""); + TaskbarOperation(icoPtr, NIM_DELETE); } if (icoPtr->itype != ICO_FILE) { FreeIconResource(icoPtr->lpIR); ckfree(icoPtr->lpIR); } if (icoPtr->taskbar_txt != NULL) { - ckfree(icoPtr->taskbar_txt); + Tcl_DecrRefCount(icoPtr->taskbar_txt); } - if (icoPtr->taskbar_command != NULL) { - ckfree(icoPtr->taskbar_command); + Tcl_DecrRefCount(icoPtr->taskbar_command); } ckfree(icoPtr); } @@ -753,7 +721,7 @@ TaskbarEval( fixup = 0; } expanded = TaskbarExpandPercents(icoPtr, msgstring, wParam, lParam, - icoPtr->taskbar_command, evalspace, &evalsize); + Tcl_GetString(icoPtr->taskbar_command), evalspace, &evalsize); if (icoPtr->interp != NULL) { int result; HWND hwnd = NULL; @@ -836,11 +804,7 @@ TaskbarHandlerProc( for (icoInterpPtr = firstIcoInterpPtr; icoInterpPtr != NULL; icoInterpPtr = icoInterpPtr->nextPtr) { for (icoPtr = icoInterpPtr->firstIcoPtr; icoPtr != NULL; icoPtr = icoPtr->nextPtr) { if (icoPtr->taskbar_flags & TASKBAR_ICON) { - HICON hIcon = icoPtr->hIcon; - if (icoPtr->iconpos != 0 && icoPtr->lpIR != NULL) { - hIcon = icoPtr->lpIR->IconImages[icoPtr->iconpos].hIcon; - } - TaskbarOperation(icoPtr, NIM_ADD, hIcon, icoPtr->taskbar_txt); + TaskbarOperation(icoPtr, NIM_ADD); } } } @@ -999,7 +963,7 @@ WinIcoDestroy( *---------------------------------------------------------------------- */ -static int +static BlockOfIconImagesPtr CreateIcoFromTkImage( Tcl_Interp *interp, /* Current interpreter. */ const char *image) /* Image to convert. */ @@ -1017,8 +981,8 @@ CreateIcoFromTkImage( photo = Tk_FindPhoto(interp, image); if (photo == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "image \"%s\" doesn't exist", image)); - return TCL_ERROR; + "image \"%s\" doesn't exist or is not a photo image", image)); + return NULL; } /* @@ -1028,13 +992,12 @@ CreateIcoFromTkImage( size = sizeof(BlockOfIconImages) + (sizeof(ICONIMAGE)); iconBits = (BlockOfIconImagesPtr)attemptckalloc(size); if (iconBits == NULL) { - return TCL_ERROR; + return NULL; } ZeroMemory(iconBits, size); iconBits->nNumImages = 1; - photo = Tk_FindPhoto(interp, image); Tk_PhotoGetSize(photo, &width, &height); Tk_PhotoGetImage(photo, &block); @@ -1066,7 +1029,7 @@ CreateIcoFromTkImage( FreeIconResource(iconBits); Tcl_SetObjResult(interp, Tcl_ObjPrintf( "failed to create an iconphoto with image \"%s\"", image)); - return TCL_ERROR; + return NULL; } /* @@ -1096,7 +1059,7 @@ CreateIcoFromTkImage( FreeIconResource(iconBits); Tcl_SetObjResult(interp, Tcl_ObjPrintf( "failed to create mask bitmap for \"%s\"", image)); - return TCL_ERROR; + return NULL; } ZeroMemory(bgraMask.ptr, width*height/8); @@ -1117,14 +1080,14 @@ CreateIcoFromTkImage( Tcl_SetObjResult(interp, Tcl_ObjPrintf( "failed to create icon for \"%s\"", image)); - return TCL_ERROR; + return NULL; } iconBits->IconImages[0].Width = width; iconBits->IconImages[0].Height = height; iconBits->IconImages[0].Colors = 4; iconBits->IconImages[0].hIcon = hIcon; - return TCL_OK; + return iconBits; } /* @@ -1150,147 +1113,127 @@ WinSystrayCmd( int objc, Tcl_Obj *const objv[]) { - size_t length; + static const char *cmdStrings[] = { + "add", "delete", "modify", NULL + }; + enum { CMD_ADD, CMD_DELETE, CMD_MODIFY }; + static const char *optStrings[] = { + "-image", "-text", "-callback", NULL + }; + enum { OPT_IMAGE, OPT_TEXT, OPT_CALLBACK }; + int cmd, opt; + HICON hIcon; int i; IcoInterpInfo *icoInterpPtr = (IcoInterpInfo*) clientData; IcoInfo *icoPtr; BlockOfIconImagesPtr lpIR = NULL; + if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "option arg arg ..."); + Tcl_WrongNumArgs(interp, 1, objv, "command ..."); return TCL_ERROR; } - - length = strlen(Tcl_GetString(objv[1])); - if ((strncmp(Tcl_GetString(objv[1]), "createfrom", length) == 0) && (length >= 2)) { - int pos = 0; - if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "createfrom <Tk image>"); - return TCL_ERROR; - } - if (CreateIcoFromTkImage(interp, Tcl_GetString(objv[2])) != TCL_OK) { - return TCL_ERROR; - } - lpIR = iconBits; - - if (lpIR == NULL) { - Tcl_AppendResult(interp, "reading of ", Tcl_GetString(objv[2]), " failed!", NULL); - return TCL_ERROR; - } - hIcon = NULL; - for (i = 0; i < lpIR->nNumImages; i++) { - /*take the first or a 32x32 16 color icon*/ - if (i == 0 || - (lpIR->IconImages[i].Height == 32 && lpIR->IconImages[i].Width == 32 && - lpIR->IconImages[i].Colors == 4)) { - hIcon = lpIR->IconImages[i].hIcon; - pos = i; + if (Tcl_GetIndexFromObj(interp, objv[1], cmdStrings, "command", + 0, &cmd) == TCL_ERROR) { + return TCL_ERROR; + } + switch (cmd) { + case CMD_ADD: + case CMD_MODIFY: { + Tcl_Obj *imageObj = NULL, *textObj = NULL, *callbackObj = NULL; + int optStart; + int oper; + if (cmd == CMD_ADD) { + optStart = 2; + oper = NIM_ADD; + } else { + optStart = 3; + oper = NIM_MODIFY; + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "id option value"); + return TCL_ERROR; + } + icoPtr = GetIcoPtr(interp, icoInterpPtr, Tcl_GetString(objv[2])); + if (icoPtr == NULL) { + return TCL_ERROR; + } } - } - if (hIcon == NULL) { - FreeIconResource(lpIR); - Tcl_AppendResult(interp, "Could not find an icon in ", Tcl_GetString(objv[2]), NULL); - return TCL_ERROR; - } - NewIcon(interp, icoInterpPtr, hIcon, ICO_FILE, lpIR, pos); - } else if ((strncmp(Tcl_GetString(objv[1]), "delete", length) == 0) && - (length >= 2)) { - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "delete id"); - return TCL_ERROR; - } - icoPtr = GetIcoPtr(interp, icoInterpPtr, Tcl_GetString(objv[2])); - if (icoPtr == NULL) { - return TCL_ERROR; - } - FreeIcoPtr(icoInterpPtr, icoPtr); - return TCL_OK; - } else if ((strncmp(Tcl_GetString(objv[1]), "text", length) == 0) && (length >= 2)) { - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "text <id> ?newtext?"); - return TCL_ERROR; - } - icoPtr = GetIcoPtr(interp, icoInterpPtr, Tcl_GetString(objv[2])); - if (icoPtr == NULL) { - return TCL_ERROR; - } - if (objc > 3) { - const char *newtxt = Tcl_GetString(objv[3]); - if (icoPtr->taskbar_txt != NULL) { - ckfree(icoPtr->taskbar_txt); + for (i=optStart; i<objc; i+=2) { + if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option", + 0, &opt) == TCL_ERROR) { + return TCL_ERROR; + } + if (i+1 >= objc) { + Tcl_AppendResult(interp, + "missing value for option \"", Tcl_GetString(objv[i]), "\"", NULL); + return TCL_ERROR; + } + switch (opt) { + case OPT_IMAGE: + imageObj = objv[i+1]; + break; + case OPT_TEXT: + textObj = objv[i+1]; + break; + case OPT_CALLBACK: + callbackObj = objv[i+1]; + break; + } } - icoPtr->taskbar_txt = (char *)ckalloc(strlen(newtxt) + 1); - strcpy(icoPtr->taskbar_txt, newtxt); - } - Tcl_AppendResult(interp, icoPtr->taskbar_txt, (char *) NULL); - return TCL_OK; - } else if ((strncmp(Tcl_GetString(objv[1]), "taskbar", length) == 0) && (length >= 2)) { - char *callback = NULL; - int oper; - Tcl_Obj *const *args; - int c; - int count; - char *txt; - if (objc < 4) { - Tcl_WrongNumArgs(interp, 1, objv, "taskbar <add/delete/modify> <id> -callback <callback>"); - return TCL_ERROR; - } - if (strcmp(Tcl_GetString(objv[2]), "add") == 0) { - oper = NIM_ADD; - } else if (strncmp(Tcl_GetString(objv[2]), "del", 3) == 0) { - oper = NIM_DELETE; - } else if (strncmp(Tcl_GetString(objv[2]), "mod", 3) == 0) { - oper = NIM_MODIFY; - } else { - Tcl_AppendResult(interp, "bad argument ", Tcl_GetString(objv[2]), " should be add, delete or modify", (char *) NULL); - return TCL_ERROR; - } - if ((icoPtr = GetIcoPtr(interp, icoInterpPtr, Tcl_GetString(objv[3]))) == NULL) - return TCL_ERROR; - hIcon = icoPtr->hIcon; - txt = icoPtr->taskbar_txt; - if (objc > 4) { - for (count = objc - 4, args = objv + 4; count > 1; count -= 2, args += 2) { - if (Tcl_GetString(args[0])[0] != '-') - goto wrongargs2; - c = Tcl_GetString(args[0])[1]; - length = strlen(Tcl_GetString(args[0])); - if ((c == '-') && (length == 2)) { - break; + if (cmd == CMD_ADD && imageObj == NULL) { + Tcl_SetResult(interp, "missing required option \"-image\"", TCL_STATIC); + return TCL_ERROR; + } + if (imageObj != NULL) { + lpIR = CreateIcoFromTkImage(interp, Tcl_GetString(imageObj)); + if (lpIR == NULL) { + return TCL_ERROR; } - if ((c == 'c') && (strncmp(Tcl_GetString(args[0]), "-callback", length) == 0)) { - callback = Tcl_GetString(args[1]); - } else if ((c == 't') && (strncmp(Tcl_GetString(args[0]), "-text", length) == 0)) { - txt = Tcl_GetString(args[1]); - } else { - goto wrongargs2; + } + if (cmd == CMD_ADD) { + hIcon = lpIR->IconImages[0].hIcon; + icoPtr = NewIcon(interp, icoInterpPtr, hIcon, ICO_FILE, lpIR, 0); + } else { + if (imageObj != NULL) { + DestroyIcon(icoPtr->hIcon); + icoPtr->hIcon = lpIR->IconImages[0].hIcon; } } - if (count == 1) - goto wrongargs2; - } - if (callback != NULL) { - if (icoPtr->taskbar_command != NULL) { - ckfree(icoPtr->taskbar_command); + if (callbackObj != NULL) { + if (icoPtr->taskbar_command != NULL) { + Tcl_DecrRefCount(icoPtr->taskbar_command); + } + icoPtr->taskbar_command = callbackObj; + Tcl_IncrRefCount(icoPtr->taskbar_command); } - icoPtr->taskbar_command = (char *)ckalloc(strlen(callback) + 1); - strcpy(icoPtr->taskbar_command, callback); - } - if (icoPtr->taskbar_txt != NULL) { - ckfree(icoPtr->taskbar_txt); + if (textObj != NULL) { + if (icoPtr->taskbar_txt != NULL) { + Tcl_DecrRefCount(icoPtr->taskbar_txt); + } + icoPtr->taskbar_txt = textObj; + Tcl_IncrRefCount(icoPtr->taskbar_txt); + } + TaskbarOperation(icoPtr, oper); + if (cmd == CMD_ADD) { + char buffer[5 + TCL_INTEGER_SPACE]; + int n; + n = _snprintf(buffer, sizeof(buffer) - 1, "ico#%d", icoPtr->id); + buffer[n] = 0; + Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, n)); + } + return TCL_OK; } - icoPtr->taskbar_txt = (char *)ckalloc(strlen(txt) + 1); - strcpy(icoPtr->taskbar_txt, txt); - return TaskbarOperation(icoPtr, oper, hIcon, txt); - wrongargs2: - Tcl_AppendResult(interp, "unknown option \"", args[0], "\",valid are:", - "-callback <tcl-callback> -text <tooltiptext>", (char *) NULL); - return TCL_ERROR; - } else { - Tcl_AppendResult(interp, "bad argument \"", Tcl_GetString(objv[1]), - "\": must be createfrom, delete, text, taskbar", - (char *) NULL); - return TCL_ERROR; + case CMD_DELETE: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "id"); + return TCL_ERROR; + } + icoPtr = GetIcoPtr(interp, icoInterpPtr, Tcl_GetString(objv[2])); + if (icoPtr == NULL) { + return TCL_ERROR; + } + FreeIcoPtr(icoInterpPtr, icoPtr); + return TCL_OK; } return TCL_OK; } |