- Download: http://code.google.com/p/tktray/downloads/list (updated 2010/05/18 by A/AK)
- Description: http://sw4me.com/wiki/Tktray (tktray.html inside the package is newer)
- freedock is good enough, but GPL license restricts its uses.
- tksystray introduces dependency on Imlib. Also, it manages icon windows in the way that prevents wm geometry and winfo from returning something useful. Copying conditions of tksystray are unclear, as no license file is provided.
- tktray 1.3.8 [1] - support for alpha composition, non-photo image types, some bug fixes...
- tktray 1.3.3 [2] - TEA update, C89 -ansi -pedantic, support for complex alpha images, a lot of bug fixes...
- tktray 1.2 [3] - prevent crash in some cases where Tk image goes away (thanks to Sergey Golovan)
- tktray 1.1 [4] - introduced bbox subcommand for getting on-screen icon coordinates
- tktray 1.0 [5] - initial release
Googie - 3 Nov 2009 - Just tried it (v1.2) under Slackware64 13.0 with Xorg 1.6.3 and KDE 4.3.1 with composition effects enabled. It crashes while trying to:
tktray::icon .tray -image $imgThe crash message is:
X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 53 (X_CreatePixmap) Value in failed request: 0x0 Serial number of failed request: 415 Current serial number in output stream: 416
WK I couldn't contact the author directly, and it seems that older GCCs throw a bunch of errors, here's a patch for 1.1 version:
diff -r -u tktray-1.1-orig/tktray.c tktray-1.1/tktray.c --- tktray-1.1-orig/tktray.c 2006-01-06 18:43:47.000000000 +0100 +++ tktray-1.1/tktray.c 2007-02-03 14:51:56.000000000 +0100 @@ -72,7 +72,14 @@ static void TKU_ImageChanged(ClientData cd,int x, int y, int w, int h, int imgw, int imgh) { + register int cx,cy; + XImage *xim; + char *ida; + XGCValues gcv; TKU_ImageRep *ir = (TKU_ImageRep*) cd; + GC gc; + Tk_PhotoImageBlock pib; + ir->resized = ( (ir->w != imgw) || (ir->h != imgh) ||(ir->mask == None) ); if (ir->resized) { @@ -91,11 +98,9 @@ x = 0; y = 0; w = imgw; h = imgh; } /* Allright: create XImage, put it onto mask */ - char *ida = Tcl_Alloc(w*h); - XImage *xim = XCreateImage(Tk_Display(ir->tkwin), + ida = Tcl_Alloc(w*h); + xim = XCreateImage(Tk_Display(ir->tkwin), Tk_Visual(ir->tkwin),1,XYBitmap,0,ida,w,h,8,0); - register int cx,cy; - Tk_PhotoImageBlock pib; Tk_PhotoGetImage(ir->photo,&pib); for(cy=0;cy<h;++cy) for(cx=0;cx<w;++cx) { @@ -105,10 +110,9 @@ XPutPixel(xim, cx, cy, alpha<128? 0: 1); } - XGCValues gcv; gcv.foreground = 1; gcv.background = 0; - GC gc = XCreateGC(Tk_Display(ir->tkwin), + gc = XCreateGC(Tk_Display(ir->tkwin), ir->mask,GCForeground|GCBackground,&gcv); XSync(Tk_Display(ir->tkwin),False); //FIXME: DEBUG: XPutImage(Tk_Display(ir->tkwin),ir->mask,gc,xim,0,0,x,y,w,h); @@ -125,6 +129,8 @@ TKU_BindImageRep( Tcl_Interp * interp, Tk_Window tkwin, CONST char *image_name, TKU_ImageRep *ir) { Tk_PhotoHandle photo; + int w,h; + if (image_name == NULL) return TCL_ERROR; photo = Tk_FindPhoto(interp, image_name); @@ -136,7 +142,6 @@ ir->photo = photo; ir->tkimg = Tk_GetImage(interp, tkwin, image_name, TKU_ImageChanged, (ClientData)ir); - int w,h; Tk_PhotoGetSize(photo,&w,&h); TKU_ImageChanged((ClientData)ir,0,0,w,h,w,h); return TCL_OK; @@ -229,6 +234,7 @@ Window child_return; int wcmd; int i; + unsigned long timeout = 0; enum {XWC_CONFIGURE=0, XWC_BALLOON, XWC_BBOX}; const char *st_wcmd[]={"configure","balloon","bbox",NULL}; @@ -250,7 +256,6 @@ Tcl_WrongNumArgs(interp, 2, objv, "message ?timeout?"); return TCL_ERROR; } - unsigned long timeout = 0; if (objc==4) if (Tcl_GetLongFromObj(interp,objv[3],&timeout)!=TCL_OK) return TCL_ERROR; @@ -304,8 +309,8 @@ Window tray = XGetSelectionOwner(dpy,icon->docksel); if (tray != None) { - Tk_MakeWindowExist(tkwin); XEvent ev; + Tk_MakeWindowExist(tkwin); memset(&ev, 0, sizeof(ev)); ev.xclient.type = ClientMessage; ev.xclient.window = tray; @@ -370,8 +375,9 @@ Tk_Window tkwin = icon -> tkwin; Window w = icon -> wrapper; Display *dpy = Tk_Display(tkwin); + Atom XEMBED_INFO; Tk_MakeWindowExist(tkwin); - Atom XEMBED_INFO = Tk_InternAtom(tkwin,"_XEMBED_INFO"); + XEMBED_INFO = Tk_InternAtom(tkwin,"_XEMBED_INFO"); if (mask & ICON_CONF_IMAGE) { TKU_BindImageRep(icon->interp,tkwin, icon->imageString,&icon->img); @@ -398,8 +404,9 @@ DockIcon *icon = (DockIcon*) cd; icon->flags |=ICON_FLAG_RESHAPE_ON_REDRAW; if (icon->img.resized) { + XSizeHints *xszh; Tk_MakeWindowExist(icon->tkwin); - XSizeHints *xszh = XAllocSizeHints(); + xszh = XAllocSizeHints(); xszh->flags = PMinSize; xszh->min_width = imgw+2; xszh->min_height = imgh+2; @@ -453,10 +460,12 @@ static void DisplayIcon(ClientData cd) { + int winw; + int winh; DockIcon *icon = (DockIcon*)cd; if (icon->flags & ICON_FLAG_DELETED) return ; - int winw = Tk_Width(icon->tkwin), - winh = Tk_Height(icon->tkwin); + winw = Tk_Width(icon->tkwin), + winh = Tk_Height(icon->tkwin); icon->flags&=(~ICON_FLAG_REDRAW_PENDING); if (winw==0||winh==0||(!icon->visible)|| icon->img.tkimg==NULL) @@ -512,15 +521,18 @@ { Tk_Window tkwin = icon -> tkwin; Display* dpy = Tk_Display(tkwin); + int length; + XEvent ev; + if (icon->tray == None) return 0; - int length = strlen(utf8msg); - XEvent ev; + length = strlen(utf8msg); + memset(&ev, 0, sizeof(ev)); ev.type = ClientMessage; ev.xclient.window = icon->wrapper; ev.xclient.message_type = - Tk_InternAtom(tkwin,"_NET_SYSTEM_TRAY_OPCODE"); + Tk_InternAtom(tkwin,"_NET_SYSTEM_TRAY_OPCODE"); ev.xclient.format = 32; ev.xclient.data.l[0]=time(NULL); ev.xclient.data.l[1]=SYSTEM_TRAY_BEGIN_MESSAGE; @@ -530,6 +542,7 @@ XSendEvent(dpy, icon->tray, False, NoEventMask, &ev); XSync(dpy, False); /* Sending message elements */ + ev.xclient.message_type = Tk_InternAtom(tkwin,"_NET_SYSTEM_TRAY_MESSAGE_DATA"); ev.xclient.format = 8; @@ -553,14 +566,16 @@ int objc, Tcl_Obj * CONST objv[]) { DockIcon *icon; + Tk_Window tkwin; if (objc < 2||(objc%2)) { Tcl_WrongNumArgs(interp, 1, objv, "pathName ?option value ...?"); return TCL_ERROR; } - Tk_Window tkwin = - Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), Tcl_GetString(objv[1]),""); + TkpWmSetState((TkWindow*)tkwin, WithdrawnState); + if (tkwin == NULL) return TCL_ERROR; TKU_CompleteToplevel(tkwin);