Updated 2012-07-29 21:58:40 by RLE

2005 update edit

At least in version 8.4.11, you can have transparent toplevels in Windows XP, Windows 2000, and Mac OS X with the wm attributes command. The following is a neat example I made that demonstrates a transparent toplevel window. The rest of this page is at least two years old. -Paul Walton
 # Description: This creates a small window demonstrating toplevel transparency in Windows XP, 2000, and Mac OS X.
 # Author: Paul Walton

 # Show the console when ctrl+c is pressed.
 bind . <Control-c> { catch {console show} }

 # Enable window dragging.
 bind . <Button-1> { if {"%W" == "."} {dragStart %x %y} }
 bind . <Button1-Motion> { if {"%W" == "."} {dragTo %X %Y} }

 # Enable automatic fading/unfading when the mouse enters or leaves the main window.
 bind . <Leave> { if {"%W" == "."} {fade start} }
 bind . <Enter> { if {"%W" == "."} {unfade start} }




 # Define some aspects of the main window.
 wm overrideredirect . 1
 wm geometry . 400x200
 wm attributes . -alpha .65 -topmost 1


 # Global variable that is linked with the scale widget and contains the current alpha level of the main window
 set AlphaLevel 0.65

 # Global variables that are booleans specifing whether the window should currently be fading in or out.
 set Fading 0
 set Unfading 0



 # Create small "X" to close the window with.
 pack [button .close -text "x" -command {destroy .} -relief flat -overrelief groove] -padx 10 -side top -anchor w

 # Create a slider bar with the scale widget to adjust the transparency.
 pack [scale .adjust -from 1.0 -to 0.02 -resolution 0.01 -variable AlphaLevel -command {wm attributes . -alpha}] -side top




 proc dragStart {windowX windowY} {
        # This sets the anchor point for dragging the window with the cursor.
        # This should be called whenever the left mouse button is pressed on the window.

        set ::DragHoldPosition(x) $windowX
        set ::DragHoldPosition(y) $windowY
 }

 proc dragTo {screenX screenY} {
        # This positions the window to the new coordinates, giving a dragging effect.
        # This should be called whenever there is mouse motion while the left mouse button is pressed down.

        set positionX [expr { $screenX - $::DragHoldPosition(x) }]
        set positionY [expr { $screenY - $::DragHoldPosition(y) }]

        wm geometry . [winfo width .]x[winfo height .]+$positionX+$positionY
 }




 proc fade {mode} {
        # This slowly fades the window until it is barely visible.
        # This proc should be called whenever the mouse leaves the main window.
        # The fading effect stops if the mouse re-enters the window.

        global Fading AlphaLevel


        switch -- $mode {
                start {
                        # Make sure that unfading is stopped.
                        unfade stop
                        # Set the fading flag.
                        set Fading 1
                        fade more
                }
                stop {
                        set Fading 0
                        return
                }
                more {
                        if { $Fading == 0 } {
                                # Fading has been stopped.
                                return
                        }
                }
                default {
                        return
                }
        }

        # Get the level of transparency of the window (0 to 1.0).
        set alphaLevel [wm attributes . -alpha]

        # Check if the window has faded enough.
        if { $alphaLevel <= .20 } {
                # The window has faded enough.
                set Fading 0
        } else {
                # Fade the window some more.
                wm attributes . -alpha [expr {$alphaLevel - 0.025} ]
                set AlphaLevel [wm attributes . -alpha]
                after 100 fade more
        }

        return
 }



 proc unfade {mode} {
        # This slowly unfades the window until it is visible enough.
        # This proc should be called whenever the mouse enters the main window.
        # The unfading effect stops if the mouse exit the window.

        global Unfading AlphaLevel


        switch -- $mode {
                start {
                        # Make sure fading is stopped.
                        fade stop
                        # Set the unfading flag.
                        set Unfading 1
                        unfade more
                }
                stop {
                        set Unfading 0
                        return
                }
                more {
                        if { $Unfading == 0 } {
                                # Unfading has been stopped.
                                return
                        }
                }
                default {
                        return
                }
        }

        # Get the level of transparency of the window (0 to 1.0).
        set alphaLevel [wm attributes . -alpha]

        # Check if the window has unfaded enough.
        if { $alphaLevel >= 0.90 } {
                # The window has unfaded enough.
                set Unfading 0
        } else {
                # Unfade the window some more.
                wm attributes . -alpha [expr {$alphaLevel + 0.05} ]
                set AlphaLevel [wm attributes . -alpha]
                after 100 unfade more
        }

        return
 }

Simulating transparent toplevels edit

Someone was enquiring on the Tcl'ers Chat if Tk could do transparent toplevels. It can't natively, but you can simulate them using a canvas. Here is some code which should work on Microsoft Windows systems. It simply gets the wallpaper picture by querying the registry, and then draws the appropriate part of it as a background on the canvas. There are some problems, which should be addressed:

  • Only works on windows (unix/mac code would be welcome)
  • Assumes scaled wallpaper (you can check the WallpaperTile value to see if it's actually tiled, and possibly other registry settings - I'll leave that as an exercise...)
  • Only scales the image by integer amounts - this is a limitation of Tk's image scaling code.
  • You have to pack child widgets into $path.c - the canvas. You could use snit or some other code to make this more transparent (pun intended).
 # Creates a "transparent" window on windows...
 package require Tk
 package require registry
 package require Img

 proc transtop {path args} {
     uplevel 1 [list toplevel $path] $args
     # Create a canvas in this toplevel
     pack [canvas $path.c] -fill both -expand 1
     # Find out the desktop wallpaper image
     set file [registry get HKEY_CURRENT_USER\\Control\ Panel\\Desktop \
         Wallpaper]
     set im [image create photo -file [file normalize $file]]
     set bg [image create photo]
     set scalex [expr {int(double([winfo screenwidth $path]) /
                 double([image width $im]) + 0.9)}]
     set scaley [expr {int(double([winfo screenheight $path]) /
                 double([image height $im]) + 0.9)}]
     $bg copy $im -zoom $scalex $scaley
     set id [$path.c create image 0 0 -anchor nw -image $bg]
     updateBgImage $path.c $id
     bind $path <Configure> [list updateBgImage $path.c $id]

     return $path
 }

 proc updateBgImage {c id} {
     set x [expr {0 - [winfo rootx $c]}]
     set y [expr {0 - [winfo rooty $c]}]
     $c coords $id $x $y
 }

 if {$argv0 eq [info script]} {
     # Main
     transtop .t
     bind .t <Destroy> { exit }
     wm withdraw .
 }

FW notes this is by Neil Madden, who seems to have forgotten to ;) And also notes that TkTrans is the standard full implementation.

NEM D'oh! Yes, it is by me. Is TkTrans a compiled extension, or pure Tcl code? Either way, if you can use it instead of this code, I would. Note also, that using transparency in an application is likely to be a hideous usability error. Having a semi-transparent background would probably be better. Also, note that if you pack other widgets (text widgets, buttons, labels etc) onto the canvas, they will not be transparent...

FW: It's compiled, for Windows. Any #FF00FF pixel is made transparent, so you can make nonstandardly shaped windows. I've also just noticed DKF's new extension Shape, however, which has a less trivial code but supports Windows and X (and maybe eventually Mac OSes) and doesn't forbid you from using a shade of bright purple in your applications ;) This one's a really clever idea, but I still don't think it has an application, as a good amount of people won't just have the desktop behind the window.

GS (031206) Is there a way to save a screenshot in a file from the clipboard ? If it is possible, we can use the cwind package do a snapshot of the desktop with:
 package require cwind
 ::cwind::send |SNAP|

And after we can put the file into the canvas.

I have made a test by hand saving the image desktop with MsPaint. The result is funny.

ABU 28-nov-2005

Paul's idea of fading-windows has been implemented in a full application : Sticky 2.0 - See Stickies

Paul Walton 02-feb-2006

Cool program, ABU. I also implemented the fading effect into a desktop calendar program I made, which you can download here: [1] (Windows 2000/NT/XP only) This program's two main functions are keeping track of things in a calendar and displaying collections of photos as your desktop wallpaper. You can download these 'photo packs' through the program. I recommend the photo pack hubbleBig.pics, which is a collection of 45 space images from the Hubble telescope. Some of the other photo packs might not be suitable for work, due to the nature of the website I made the program for, although they haven't put any nudity on it yet that I've seen.

RS 2006-02-03: Here's a very simple demo that works on Windows XP with Tcl 8.4.9 - see the window fade away, and come back again:
 package req Tk
 pack [label .t -font {Helvetica 24} -text "Hello, world"]
 for {set i 20} {$i>=0} {incr i -1} {
    wm attributes . -alpha [expr $i/20.]
    if {$i==19} update
    after 250
 }
 for {set i 1} {$i<=20} {incr i} {
    wm attributes . -alpha [expr $i/20.]
    after 250
 }

In my tests I found that the -alpha changes are fully visible when the window is updated the first time it has not the full 1.0 (that's the $i==19 test). More updates were apparently not necessary.

Paul Walton: The whole window flashes when going from a 1.0 alpha level to a <1.0 level and vice versa. So anytime I implement a fading effect, I always limit the transparency to 99%. Also, at least on XP, the window will disappear if the alpha level is below 0.02, meaning you cannot click on the window.

NEM contributes this little proc for fading a window:
 proc fade {win {final 0.0} {step 0.2}} {
     set alpha [wm attributes $win -alpha]
     if {$alpha == $final} { return }
     wm attribute $win -alpha [expr {$alpha-$step}]
     after 50 [info level 0]
 }

Works well for fading out balloon help.

Lars H: The $alpha == $final condition worries me. Since this is a matter of computers and real numbers, it should at the very least be $alpha <= $final. (I suppose the automatic clamping of -alpha values to the 0.0 to 1.0 range makes this work for the default $final.)

NEM: Yes, it slightly worries me too. But I wanted the proc to be able to fade-in as well as fade-out. Perhaps it would be better to see if it is "near" the final?
 if {abs($alpha-$final) < abs($step)} { wm attributes $win -alpha $final; return }

That seems more robust.

Tony tonytraductor:

Can transparency be set on Linux, too? I want to create an img viewer and a transparent text widget to facilitate creation of Ascii art, overlaying the transparent text widget over an image, to type over the image to create the art. Thanks. /tony

PT: yes and no -- if the X desktop supports compositing (compiz/beryl or something similar) then the [wm attributes -alpha] option will be enabled and you can create transparent toplevels just as for Windows XP. However, I don't think you can make a transparent text widget.

tonytraductor - Ai, que lástima...That's too bad. After all, it's really just the text widget that I want transparent, and I want it to work in plain old X without compiz/beryl. Thanks for clearing that up for me, though. -t

ZB 2009-04-14 But shouldn't be transparency for toplevels available when usage of "composite" extension has been set in /etc/xorg.conf? I'm able to make the chosen window transparent using "transset" utility, but still no success trying something like: "wm attributes . -alpha 0.3".

WJG (14-Apr-09) If you're looking for transparency effects on the Linux desktop try Gnocl. There's some sample screengrabs here [2]. A top level can have a bitmask, background image, alpha blending and the option to display window borders. If the fancy takes you you could even animate the window around the screen under script control. (No Tickle bindings to Compiz though... mmm how hard would that be to implement?) ZB Update: your clockDemo seems to be working as expected, but any attempt to make f.e. button-box window transparent - using just something like "-opacity 0.2" - is ignored. Window remains "solid".

ZB Yes, I'm aware of Gnocl's advantages - but seeing PT's comment above I was wondering, why Tk ignores "alpha" attribute on compositing-enabled Xorg. Should I file a bug perhaps?