TIP #159: Extending Tk 'wm' Command to Support Coloured Icons

From: Georgios Petasis (petasis_at_iit.demokritos.gr)
Date: 10/02/03


Date: Thu, 2 Oct 2003 15:59:50 +0000 (UTC)


 TIP #159: EXTENDING TK 'WM' COMMAND TO SUPPORT COLOURED ICONS
===============================================================
 Version: $Revision: 1.1 $
 Author: Georgios Petasis <petasis_at_iit.demokritos.gr>
 State: Draft
 Type: Project
 Tcl-Version: 8.5
 Vote: Pending
 Created: Wednesday, 01 October 2003
 URL: http://purl.org/tcl/tip/159.html
 WebEdit: http://purl.org/tcl/tip/edit/159
 Post-History:

-------------------------------------------------------------------------

 ABSTRACT
==========

 Currently, Tk lacks a mechanism for allowing scripts to place colour
 icons in the window manager decorations of a toplevel window. Tk
 supports only the placement of monochrome bitmaps through the _wm
 iconbitmap_ and _wm iconmask_ commands. This TIP proposes an extension
 of the _wm_ command with the _iconphoto_ subcommand, which will pass a
 set of photo images as possible window manager icons.

 RATIONALE
===========

 Almost all modern window managers or desktop environments offer support
 for using colour icons in toplevel window decorations. Tk has made some
 steps in this direction by allowing _wm iconbitmap_ command to also
 accept a Windows icon file, to be used as an icon for a toplevel under
 windows. This solution is quite incomplete, and of course works only
 under windows. No support for colour icons under Unix is currently
 offered and I (think) the same is also true for Mac OS.

 This TIP proposes the introduction of a new subcommand to the _wm_
 command, the _iconphoto_ subcommand. (_iconimage_ was an alternative
 that I rejected because bitmaps are also considered images by Tk). This
 subcommand will accept a Tk window name and a set of photo image names.
 These images will then passed to the window manager as possible window
 icons.

 The _wm iconphoto_ subcommand will be available under all platforms.
 However, at this stage of development I will focus mainly on Unix: I
 don't know anything about Mac OS (so others must help in this
 direction) and support for windows already exists. The final goal will
 be to support at least windows and Unix. There is currently a patch
 that implements the Unix port of _wm iconphoto_.

 Currently, two different approaches are used by Unix applications to
 specify colour icons. The first approach uses the same mechanism as _wm
 iconbitmap_ to pass the icon: instead of passing a monochrome pixmap
 (that is a bitmap), they pass a colour pixmap with 3 planes (no
 transparency). This approach works with many modern window managers
 (including the ones used by KDE and GNOME). However, as Joe English
 noted this approach violates the ICCCM, despite the fact that it is
 used by some applications (i.e. gvim).

 The second approach (again pointed by Joe English) is the one proposed
 by freedesktop.org: The application defines a window property that
 holds a special encoding of the colour icons. I don't know exactly how
 many window managers follow this proposal, but the window managers in
 two popular desktops (KDE and GNOME) support it. My proposal is of
 course to follow the second approach, as it does not violate the ICCCM.

 The window property that should be defined is "_NET_WM_ICON". From the
 specifications at <URL:http://www.freedesktop.org:>

       _NET_WM_ICON

       _NET_WM_ICON CARDINAL[][2+n]/32

       This is an array of possible icons for the client. This
       specification does not stipulate what size these icons should be,
       but individual desktop environments or toolkits may do so. The
       Window Manager MAY scale any of these icons to an appropriate
       size.

       This is an array of 32bit packed CARDINAL ARGB with high byte
       being A, low byte being B. The first two cardinals are width,
       height. Data is in rows, left to right and top to bottom.

       Currently both KDE and GNOME window managers scale the provided
       icons to proper sizes.

 SPECIFICATION
===============

 This document proposes the following changes to the Tk core:

    1. The addition of a new subcommand (_iconphoto_) to the _wm_
       command. This subcommand will accept the following arguments:

       window: the name of a Tk toplevel window.

       photo_image ?photo_image2 ...?:
              a set of Tk photo image names, that will be send to the
              window manager as potential icons.

 Currently, no other facilities are planned (like for example getting
 back the image names that are currently used as icons).

 Also, no facilities are provided to request the window manager what
 icon sizes are preferred, although Xlib offers a relevant function.

 REFERENCE IMPLEMENTATION
==========================

 Here is a possible implementation for the Unix platform. The patch is
 very small, so I have included it here:

   --- tk_XP/unix/tkUnixWm.c 2003-09-02 14:56:46.000000000 +0300
   +++ tk/unix/tkUnixWm.c 2003-10-01 10:04:40.000000000 +0300
   @@ -395,6 +395,9 @@
    static int WmIconnameCmd _ANSI_ARGS_((Tk_Window tkwin,
                               TkWindow *winPtr, Tcl_Interp *interp, int objc,
                               Tcl_Obj *CONST objv[]));
   +static int WmIconphotoCmd _ANSI_ARGS_((Tk_Window tkwin,
   + TkWindow *winPtr, Tcl_Interp *interp, int objc,
   + Tcl_Obj *CONST objv[]));
    static int WmIconpositionCmd _ANSI_ARGS_((Tk_Window tkwin,
                               TkWindow *winPtr, Tcl_Interp *interp, int objc,
                               Tcl_Obj *CONST objv[]));
   @@ -971,7 +974,8 @@
           "aspect", "attributes", "client", "colormapwindows",
           "command", "deiconify", "focusmodel", "frame",
           "geometry", "grid", "group", "iconbitmap",
   - "iconify", "iconmask", "iconname", "iconposition",
   + "iconify", "iconmask", "iconname",
   + "iconphoto", "iconposition",
           "iconwindow", "maxsize", "minsize", "overrideredirect",
            "positionfrom", "protocol", "resizable", "sizefrom",
            "stackorder", "state", "title", "transient",
   @@ -980,7 +984,8 @@
            WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
           WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FRAME,
           WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP,
   - WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME, WMOPT_ICONPOSITION,
   + WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME,
   + WMOPT_ICONPHOTO, WMOPT_ICONPOSITION,
           WMOPT_ICONWINDOW, WMOPT_MAXSIZE, WMOPT_MINSIZE, WMOPT_OVERRIDEREDIRECT,
            WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
            WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT,
   @@ -1072,6 +1077,8 @@
           return WmIconmaskCmd(tkwin, winPtr, interp, objc, objv);
          case WMOPT_ICONNAME:
           return WmIconnameCmd(tkwin, winPtr, interp, objc, objv);
   + case WMOPT_ICONPHOTO:
   + return WmIconphotoCmd(tkwin, winPtr, interp, objc, objv);
          case WMOPT_ICONPOSITION:
           return WmIconpositionCmd(tkwin, winPtr, interp, objc, objv);
          case WMOPT_ICONWINDOW:
   @@ -2061,6 +2068,122 @@
    /*
     *----------------------------------------------------------------------
     *
   + * WmIconphotoCmd --
   + *
   + * This procedure is invoked to process the "wm iconphoto"
   + * Tcl command.
   + * See the user documentation for details on what it does.
   + *
   + * Results:
   + * A standard Tcl result.
   + *
   + * Side effects:
   + * See the user documentation.
   + *
   + *----------------------------------------------------------------------
   + */
   +
   +static int
   +WmIconphotoCmd(tkwin, winPtr, interp, objc, objv)
   + Tk_Window tkwin; /* Main window of the application. */
   + TkWindow *winPtr; /* Toplevel to work with */
   + Tcl_Interp *interp; /* Current interpreter. */
   + int objc; /* Number of arguments. */
   + Tcl_Obj *CONST objv[]; /* Argument objects. */
   +{
   + register WmInfo *wmPtr = winPtr->wmInfoPtr;
   + Tk_PhotoHandle photo;
   + Tk_PhotoImageBlock block;
   + int i, size = 0, width, height, index = 0, x, y;
   + long R, G, B, A;
   + long *iconPropertyData;
   + unsigned char *pixelByte;
   +
   + if (objc < 4) {
   + Tcl_WrongNumArgs(interp, 2, objv,
   + "window photo_image ?photo_image2 ...?");
   + return TCL_ERROR;
   + }
   + /*
   + * Iterate over all images to retrieve their sizes, in order to allocate a
   + * buffer large enough to hold all images.
   + */
   + for (i = 3; i < objc; i++) {
   + photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
   + if (photo == NULL) return TCL_ERROR;
   + Tk_PhotoGetSize(photo, &width, &height);
   + /* We need to cardinals for width & height and one cardinal for each
   + * image pixel. */
   + size += 2 + width * height;
   + }
   + /* We have calculated the size of the data. Try to allocate the needed
   + * memory space. */
   + iconPropertyData = (long *) Tcl_AttemptAlloc(sizeof(long)*size);
   + if (iconPropertyData == NULL) {
   + return TCL_ERROR;
   + }
   + memset(iconPropertyData, 0, sizeof(long)*size);
   +
   + for (i = 3; i < objc; i++) {
   + photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
   + if (photo == NULL) {
   + Tcl_Free((char *) iconPropertyData);
   + return TCL_ERROR;
   + }
   + Tk_PhotoGetSize(photo, &width, &height);
   + Tk_PhotoGetImage(photo, &block);
   + /*
   + * Each image data will be placed as an array of 32bit packed
   + * CARDINAL, in a window property named "_NET_WM_ICON":
   + * _NET_WM_ICON
   + *
   + * _NET_WM_ICON CARDINAL[][2+n]/32
   + *
   + * This is an array of possible icons for the client.
   + * This specification does not stipulate what size these icons should
   + * be, but individual desktop environments or toolkits may do so.
   + * The Window Manager MAY scale any of these icons to an appropriate
   + * size.
   + *
   + * This is an array of 32bit packed CARDINAL ARGB with high byte being
   + * A, low byte being B. The first two cardinals are width, height.
   + * Data is in rows, left to right and top to bottom.
   + */
   +
   + /*
   + * Encode the image data in the iconPropertyData array.
   + */
   + iconPropertyData[index++] = width;
   + iconPropertyData[index++] = height;
   + for (y = 0; y < height; y++) {
   + for (x = 0; x < width; x++) {
   + R = *(block.pixelPtr + x*block.pixelSize +
   + y*block.pitch + block.offset[0]);
   + G = *(block.pixelPtr + x*block.pixelSize +
   + y*block.pitch + block.offset[1]);
   + B = *(block.pixelPtr + x*block.pixelSize +
   + y*block.pitch + block.offset[2]);
   + A = *(block.pixelPtr + x*block.pixelSize +
   + y*block.pitch + block.offset[3]);
   + pixelByte = (unsigned char *) &iconPropertyData[index];
   + pixelByte[3] = A;
   + pixelByte[2] = R;
   + pixelByte[1] = G;
   + pixelByte[0] = B;
   + index++;
   + }
   + }
   + }
   + XChangeProperty(winPtr->display, wmPtr->wrapperPtr->window,
   + Tk_InternAtom(tkwin, "_NET_WM_ICON"),
   + XA_CARDINAL, 32, PropModeReplace,
   + (unsigned char *) iconPropertyData, size);
   + Tcl_Free((char *) iconPropertyData);
   + return TCL_OK;
   +}
   +^L
   +/*
   + *----------------------------------------------------------------------
   + *
     * WmIconpositionCmd --
     *
     * This procedure is invoked to process the "wm iconposition"

 Note that also I have a reference implementation of the first approach
 (passing a colour pixmap instead of a bitmap), in case we decide to
 follow this approach (or both simultaneously :-) ).

 NOTES
=======

 I don't know if I have handled the assignment of the four bytes inside
 the long correctly. Currently the code works fine under Linux. It would
 be great if somebody could re-write the assignment to use bit-shift
 operations :-)

 COPYRIGHT
===========

 This document has been placed in the public domain.

-------------------------------------------------------------------------

 TIP AutoGenerator - written by Donal K. Fellows

[[Send Tcl/Tk announcements to tcl-announce@mitchell.org
  Announcements archived at http://groups.yahoo.com/group/tcl_announce/
  Send administrivia to tcl-announce-request@mitchell.org
  Tcl/Tk at http://tcl.tk/ ]]



Relevant Pages

  • Re: Good Glyph/Icon editor suggestions?
    ... Support for Vista icons with PNG compression ... More than 40 effects, including Drop Shadow ... Extract icons from 32 bit exe and dll ... Window menu for easy window switching ...
    (borland.public.delphi.thirdpartytools.general)
  • Missing Feature: Classic Icons
    ... A icon sixe was removed from the build window for Classic builds. ... Yet they continue to support old versions of Windows. ... paying hundreds of odllar so I have to manually alter the builds so they ... show the proper icons. ...
    (comp.lang.basic.realbasic)
  • Turning off computer
    ... click "Start", then "Turn Off Computer", the window comes ... up for Turn Off, Restart, etc. but behind that window it ... shops, support, time, date, etc. ... copied the first line of the icons on my desktop and ...
    (microsoft.public.windowsxp.general)
  • Re: Annoying desktop "reset"
    ... >>>Why does XP think it is necessary to reload all the desktop icons every ... >> A window will repaint in response to something changing in it. ... If you bind File and Print Sharing to the Internet, ... describe of repaining desktop and Explorer windows. ...
    (microsoft.public.windowsxp.configuration_manage)
  • Re: WinXP Batch File ???
    ... the icons are not damaged: in fact they are visible in the original ... >>> 0 Hides the window and activates another window. ... >>> compared to the title string of each running application. ... >>> You can use SendKeys to send more than one keystroke at a time. ...
    (microsoft.public.windowsxp.general)