+# General purpose code for being a tray applet
-#----- general machinery -----
+proc manyset {list args} {
+ foreach val $list var $args {
+ upvar 1 $var my
+ set my $val
+ }
+}
+
+package require Tclx
package require tktray
-#load /home/ian/things/Systray/tktray-1.3.8/libtktray1.3.8.so
+#----- general machinery -----
+
+# Interface:
+#
+# tk::tktray widget is called .i
+#
+# Tooltip:
+#
+# Caller may call
+# applet::setup-tooltip ON-VISIBLE ON-INVISIBLE
+# to make applet have a tooltip.
+#
+# ON-VISIBLE and ON-INVISIBLE will be globally eval'd
+# when the tooltip becomes visible and invisible.
+#
+# Caller should call
+# applet::tooltip-set TEXT-MAYBE-MULTILINE
+# whenever they like.
+#
+# Inner window subprocess:
+#
+# Caller that needs access to inner window should define
+# proc innerwindow {} { ... }
+# and run
+# innerwindow
+# This will create
+# .i.i.b frame to contain container
+# .i.i.b.c actual container
+#
+# Button presses
+#
+# Caller may bind .i.i <ButtonPress-$b>
+#
+# Alternatively caller may call applet::setup-button-menu $b
+# which will generate a menu .m$b which the user can configure
+# and which will automatically be posted and unposted etc.
wm withdraw .
tktray::icon .i -class example
.i configure -docked 1
-set posted 0
-foreach b {1 3} {
+namespace eval applet {
+
+
+# used by both menus and tooltips
+variable posted 0
+
+#----- menus -----
+
+proc setup-button-menu {b} {
+ bind .i.i <ButtonPress> { applet::menubuttonpressed %b %X %Y }
menu .m$b -tearoff 0
}
-proc pressed {b x y} {
- global posted
- tooltip_cancel
+proc menubuttonpressed {b x y} {
+ variable posted
+ tooltip-cancel
if {$posted == $b} {
puts "unpost $posted toggle"
.m$posted unpost
}
proc msel {} {
- global posted
+ variable posted
set posted 0
}
-proc setupinnerwindow {} {
- global innerwindow_after innerwindow
- catch { after cancel $innerwindow_after }
- catch { unset innerwindow_after }
- if {[info exists innerwindow]} return
- set children {}
- foreach child [winfo children .i] {
- if {![winfo exists $child]} continue
- lappend children $child
- }
- if {[llength $children]==1} {
- set innerwindow [lindex $children 0]
- bind $innerwindow <Destroy> {
- innerwindow-unavailable
- catch { unset innerwindow }
- after idle setupinnerwindow
- }
- innerwindow-available
- } else {
- after 5000 setupinnerwindow
- }
-}
+#----- tooltips -----
-bind .i <ButtonPress> { pressed %b %X %Y }
+variable tooltip_on_vis {}
+variable tooltip_on_invis {}
-proc tooltip_starttimer {state x y} {
- global tooltip_after posted tooltip_inwindow
- if {$state || $posted || !$tooltip_inwindow} { tooltip_cancel; return }
+proc tooltip-starttimer {state x y} {
+ variable tooltip_after
+ variable posted
+ variable tooltip_inwindow
+ if {$state || $posted || !$tooltip_inwindow} { tooltip-cancel; return }
catch { after cancel $tooltip_after }
- set tooltip_after [after 500 tooltip_show $x $y]
+ set tooltip_after [after 500 applet::tooltip-show $x $y]
}
-proc tooltip_cancel {} {
- global tooltip_after
+proc tooltip-cancel {} {
+ variable tooltip_after
+ variable tooltip_on_invis
catch { after cancel $tooltip_after }
catch { unset $tooltip_after }
wm withdraw .tt
+ uplevel #0 $tooltip_on_invis
}
set tooltip_inwindow 0
-proc tooltip_enter {state x y} {
- global tooltip_inwindow
+proc tooltip-enter {state x y} {
+ variable tooltip_inwindow
set tooltip_inwindow 1
- tooltip_starttimer $state $x $y
+ tooltip-starttimer $state $x $y
}
-proc tooltip_leave {} {
- global tooltip_inwindow
+proc tooltip-leave {} {
+ variable tooltip_inwindow
set tooltip_inwindow 0
- tooltip_cancel
+ tooltip-cancel
}
-proc setuptooltip {} {
- bind .i <Enter> { tooltip_enter %s %X %Y }
- bind .i <Leave> { tooltip_leave }
- bind .i <ButtonRelease> { tooltip_cancel; tooltip_starttimer %s %X %Y }
- bind .i <Motion> { tooltip_starttimer %s %X %Y }
+proc setup-tooltip {on_vis on_invis} {
+ foreach v {vis invis} {
+ variable tooltip_on_$v [set on_$v]
+ }
+ bind .i <Enter> { applet::tooltip-enter %s %X %Y }
+ bind .i <Leave> { applet::tooltip-leave }
+ bind .i <ButtonRelease> {
+ applet::tooltip-cancel
+ applet::tooltip-starttimer %s %X %Y
+ }
+ bind .i <Motion> { applet::tooltip-starttimer %s %X %Y }
toplevel .tt -background black
wm withdraw .tt
wm overrideredirect .tt 1
label .tt.t -justify left -background {#EEE1B3}
pack .tt.t -padx 1 -pady 1
- settooltip {}
+ tooltip-set {}
}
-proc settooltip {s} {
+proc tooltip-set {s} {
.tt.t configure -text $s
}
-proc tooltip_show {x y} {
+proc tooltip-show {x y} {
+ variable tooltip_on_vis
incr x 9
incr y 9
wm geometry .tt +$x+$y
wm deiconify .tt
+ uplevel #0 $tooltip_on_vis
}
+}
+
+
+proc innerwindow-resetup-required {why} {
+ variable innerwindow_after
+puts "IW-EVENT $why"
+ if {[info exists innerwindow_after]} return
+ set innerwindow_after [after idle innerwindow-resetup]
+}
+
+proc innerwindow-resetup {} {
+ variable innerwindow_after
+ unset innerwindow_after
+
+puts RESETUP
+
+ innerwindow-destroying
+
+ catch { destroy .i.i.c }
+ if {![winfo exists .i.i]} return
+ destroy [frame .i.i.make-exist]
+ catch { destroy .i.i.b.c }
+ catch { destroy .i.i.b }
+ frame .i.i.b
+ pack .i.i.b -fill both -side left -expand 1
+ frame .i.i.b.c -container 1 -background orange
+ pack .i.i.b.c -fill both -side left -expand 1
+#
+ global inner_lastw inner_lasth
+ #set w [winfo width .i.i]
+# set w [winfo width .i.i]
+# set h [winfo height .i.i]
+
+# if {$w != $inner_lastw || $h != $inner_lasth} {
+# set inner_lastw $w
+# set inner_lasth $h
+# innerwindow-ph-dummy configure -width $w -height 2
+ innerwindow-ready
+# }
+}
+
+proc setupinnerwindow {w} {
+ global inner_lastw inner_lasth
+ set inner_lastw -2
+ set inner_lasth -2
+
+ image create photo innerwindow-ph-dummy -width $w -height 2
+ .i configure -image innerwindow-ph-dummy
+
+ destroy [frame .i.make-exist]
+ destroy [frame .i.i.make-exist]
+ bind .i <<IconConfigure>> { innerwindow-resetup-required IconConfigure }
+}
+
+
+
proc setimage {image} {
.i configure -image $image
}
+
+proc fork-then {ondeath inchild} {
+ global children errorCode errorInfo
+ foreach f {stdout stderr} {
+ if {[catch { flush $f } emsg]} {
+ catch { bgerror $emsg }
+ }
+ }
+ set pid [fork]
+ if {!$pid} {
+ if {[catch {
+ uplevel 1 $inchild
+ } emsg]} {
+ puts stderr "CHILD ERROR $emsg\n$errorCode\n$errorInfo\n"
+ }
+ kill KILL [id process]
+ }
+ set children($pid) $ondeath
+ return $pid
+}
+
+proc chld-handler {} {
+ global children
+ while 1 {
+ if {[catch { set got [wait -nohang] }]} break
+ if {![llength $got]} break
+ manyset $got pid how how2
+ if {[info exists children($pid)]} {
+ set l $children($pid)
+ unset children($pid)
+ if {[catch {
+ uplevel #0 [concat [list $l] $how $how2]
+ } emsg]} {
+ catch { bgerror $emsg }
+ }
+ }
+ }
+}
+
+signal -restart trap CHLD { after idle chld-handler }