TkTray is an extension for managing system tray icons with Tk on [X] Window System. * Download: http://sw4me.com/tktray1.1.tar.gz * Description: http://sw4me.com/wiki/Tktray There are some other extensions for this purpose, like '''freedock''' mentioned at [system tray]. I decided to write my own implementation for a number of reasons: * '''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 is released under BSDL. It uses Tk image manipulation routines to handle images, thus no external dependencies are introduced. Tktray will handle the case when the system tray manager is not running yet when an icon is created. When the tray manager starts later, Tktray will notice it and request docking for all existing icons. Version history: * tktray 1.1 [http://sw4me.com/tktray1.1.tar.gz] - introduced '''bbox''' subcommand for getting on-screen icon coordinates * tktray 1.0 [http://sw4me.com/tktray1.0.tar.gz] - initial release ---- [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;cytkwin), + 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); See also: [winico] ---- [Category Package]