A very simple window manager

I had to open a TK GUI, which is not under control of the underlaying window manager.

There is an alternate page from Larry Smith: weedesk

The problems to be solved are:

  1. the new toplevel should not "steal" the focus.
  2. window manager controls are needed.

To fulfill 1 "wm overrideredirect $toplevel 1" is the starting point. But then GUI has to control the focus fully. This also removes the control by window manager, but the moving of the GUI window has to be implemented.

This script here is my solution for

  • handling the focus
  • moving the window
package require Tk

package provide vlxwm 0.1

namespace eval vlxwm { }
namespace eval vlxwm::focus {
    variable helper
}
namespace eval vlxwm::move {
    variable controlID
}

#######################################################################
proc vlxwm::focus::save {} {
    variable helper
    if ![info exists helper] {
        ::set helper .xxx[clock clicks]
        # create a new toplevel window
        # this is controlled by the window manager
        toplevel $helper
        wm geometry $helper 0x0-1-1
    }
    raise $helper
    update 
    wm withdraw $helper
    after 250
}
proc vlxwm::focus::restore {} {
    variable helper
    if ![info exists helper] return
    # destroy this toplevel and windows manager focus on the last know window
    # which is not this gui, because of overrideredirect
    destroy $helper
    unset helper
}
proc vlxwm::focus::set {w} {
    save
    ::bind $w <Leave> vlxwm::focus::restore 

    wm overrideredirect  [winfo toplevel $w] 0
    raise  $w
    focus -force $w
    wm overrideredirect  [winfo toplevel $w] 1
}
proc vlxwm::focus::bind {w} {
    ::bind $w <Leave>         +[list vlxwm::focus::restore]
    ::bind $w <ButtonPress-1> +[list vlxwm::focus::set %W]
}
#######################################################################
# enable the move of the window
proc vlxwm::move::Enable {wg x y} {
    variable controlID
    control  [winfo toplevel $wg] $x $y
}
proc vlxwm::move::Disable {} {
    variable controlID
    after cancel $controlID
}
proc vlxwm::move::control {wg x y} {
    variable controlID
    if [info exists controlID] {after cancel $controlID}

    # top left corner of toplevel
    set tx [winfo x $wg]
    set ty [winfo y $wg]

    # get current possion
    set npx [winfo pointerx $wg]
    set npy [winfo pointery $wg]

    set dpx [expr {$npx - $x}]
    set dpy [expr {$npy - $y}]

    # new toplevel position
    set ntx [expr {$tx + $dpx}]
    set nty [expr {$ty + $dpy}]
    wm geometry $wg +${ntx}+${nty}
    set controlID [after 10 [list vlxwm::move::control $wg $npx $npy]]
}

proc vlxwm::move::bind {wg} {
    ::bind $wg <ButtonPress-1>   +[list vlxwm::move::Enable %W %X %Y]
    ::bind $wg <ButtonRelease-1> +[list vlxwm::move::Disable]
}

##########################################################
##########################################################
proc leave args {
    puts "gui left"

}

proc press args {
    puts "pressed"
}

wm withdraw .
toplevel .my -bg black -border 5
wm overrideredirect  .my 1
label  .my.move -text move -bg seashell
text   .my.text -height 10 -width 40
button .my.exit -command exit -text exit


grid .my.move -sticky we
grid .my.text -sticky nwse
grid .my.exit -sticky nwse

::bind .my.text  <ButtonPress-1>   [list press]
::bind .my       <Leave>           [list leave]

vlxwm::move::bind .my.move
vlxwm::focus::bind .my.text