1 package require Tcl 8.0 ;# we need binary command
4 # Define fvwm message types of fvwm95-2.0.43
37 536870912 NewAddWindow
38 1073741824 NewConfigureWindow
42 array set gravityText {
56 foreach {code name} [array get msgType] {
57 set msgCodes($name) $code
58 set AllEvents [expr $AllEvents|$code]
60 set msgCodes(DeadPipe) 0
61 variable WindowListMask [expr $msgCodes(End_WindowList)|\
62 $msgCodes(NewDesk)|$msgCodes(NewPage)| $msgCodes(FocusChange)|\
63 $msgCodes(DefaultIcon)|$msgCodes(ConfigureWindow)|\
64 $msgCodes(WindowName)|$msgCodes(IconName)| $msgCodes(ResName)|\
65 $msgCodes(ResClass)|$msgCodes(IconFile)|$msgCodes(MiniIcon)]
66 variable MessagesWithString [expr $msgCodes(WindowName)|$msgCodes(IconName)|\
67 $msgCodes(ResClass)|$msgCodes(ResName)|$msgCodes(Error)|\
68 $msgCodes(ConfigInfo)|$msgCodes(String)|$msgCodes(DefaultIcon)|\
69 $msgCodes(IconFile)|$msgCodes(MiniIcon)|$msgCodes(VisibleName)]
71 # Find out how to format binary integers
72 # Note, on 64-bit platform there should be 64bit integer
75 if {$::tcl_platform(byteOrder)=="littleEndian"} {
80 if {$::argc<5||![regexp {[0-9]+} [lindex $::argv 0]]||
81 ![regexp {[0-9]+} [lindex $::argv 1]]||
82 ! [regexp {[0-9]+} [lindex $::argv 3]]||
83 ![regexp {[0-9]+} [lindex $::argv 4]]} {
84 error "Should be started as fvwm module" {FVWM 0 "Invalid invocation"}
86 if {[catch {package require Tclx}]} {
87 if {[string equal $tcl_platform(os) Linux]} {
88 variable outfd [open /dev/fd/[lindex $::argv 0] w]
89 variable infd [open /dev/fd/[lindex $::argv 1] r]
91 error "Tclx is required for all systems except Linux"
94 variable outfd [dup [lindex $::argv 0]]
95 variable infd [dup [lindex $::argv 1]]
97 if {[info tclversion]>=8.1} {
98 fconfigure $outfd -buffering none -translation binary -encoding binary
99 fconfigure $infd -buffering none -blocking yes -translation binary -encoding binary
100 proc get_eventString {infd stringLen} {
101 return [encoding convertfrom [lindex [split [read $infd $stringLen] "\0"] 0]]
104 fconfigure $outfd -buffering none -translation binary
105 fconfigure $infd -buffering none -blocking yes -translation binary
106 proc get_eventString {infd stringLen} {
107 return [lindex [split [read $infd $stringLen] "\0"] 0]
110 variable configFile [lindex $::argv 2]
111 variable WindowId [lindex $::argv 3]
113 variable Mask $AllEvents
114 switch [lindex $::argv 4] {
115 0 {set Context NO_CONTEXT}
116 1 {set Context WINDOW}
117 2 {set Context TITLE}
120 16 {set Context FRAME}
121 32 {set Context SIDEBAR}
122 64 {set Context LEFT1}
123 128 {set Context LEFT2}
124 256 {set Context LEFT3}
125 512 {set Context LEFT4}
126 1024 {set Context LEFT5}
127 2048 {set Context RIGHT1}
128 4096 {set Context RIGHT2}
129 8192 {set Context RIGHT3}
130 16384 {set Context RIGHT4}
131 32768 {set Context RIGHT5}
132 default {set Context Unknown}
135 set ::argv {lrange 5 end $::argv}
139 DeadPipe ::fvwm::myExit
146 # Send message to fvwm
148 proc send {message {window 0}} {
151 puts -nonewline $outfd [binary format ${intFormat}2 \
152 [list $window [string length $message]]]
153 puts -nonewline $outfd $message
154 puts -nonewline $outfd [binary format $intFormat 1]
157 # Used for special event handling during list asquition
159 variable internalHandler ""
162 # Indicates that list is done
166 # Fileevent handler for fvwm input pipe
171 variable internalHandler
176 set event [ReadMessage]
177 set type [lindex $event 0]
180 # Process getting list specially
182 if [string length $internalHandler] {
183 eval $internalHandler $event
186 if [info exist handlers($type)] {
187 namespace eval :: "$handlers($type) $event"
191 # Parses fvwm message and converts it to list
193 proc ReadMessage {} {
198 variable MessagesWithString
199 variable internalHandler
200 binary scan [read $infd $intSize] $intFormat sign
201 binary scan [read $infd $intSize] $intFormat type
202 binary scan [read $infd $intSize] $intFormat len
203 binary scan [read $infd $intSize] $intFormat timestamp
204 if {[eof $infd] && ![ info exist type]} {
208 if {![info exist msgType($type)]} {
209 after idle {error "Unknown message type [format %x $type]"\
210 [list FVWM 1 $type "Unknown message"]
213 set event $msgType($type)
214 if {($type & $MessagesWithString) !=0} {
215 set stringLen [expr ($len-7)*$intSize]
218 for {set i 4} {$i<$len} {incr i} {
219 binary scan [read $infd 4] $intFormat value
223 lappend event [get_eventString $infd $stringLen]
230 # setMask - set event mask for fvwm
235 if {[llength $list]==1&&![catch {expr $list+1}]} {
236 #mask is numeric. Suppose user knows what he does
237 send "Set_Mask $list"
243 if {![info exist msgCodes($type)]} {
244 return -code error -errorcode [list FVWM 3 $type "Invalid event"]\
245 "Invalid event name $type"
247 set value [expr {$value|$msgCodes($type)}]
249 send "Set_Mask $value"
253 # Binds handler to specific event
258 if ![llength $args] {
259 return [array names handlers]
261 set type [lindex $args 0]
262 if ![info exist msgCodes($type)] {
263 return -code error -errorcode [list FVWM 3 $type "Invalid event"]\
264 "Invalid event name $type"
266 if [llength $args]==1 {
267 if [info exist handlers($type)] {
268 return $handlers($type)
273 if {![llength $args]>2} {
274 return -code error -errorcode NONE "Wrong # args should be \
275 ::fvwm::bind event script"
277 set handlers($type) [lindex $args 1]
284 # configHandler - internal procedure which handles config
287 proc configHandler {type args} {
288 variable configPattern
290 variable internalHandler
291 if {$type=="End_ConfigInfo"} {
292 uplevel \#0 set ::fvwm::listDone 1
293 } elseif {$type=="ConfigInfo"} {
294 regsub "\[\t\n\r \]*$" [lindex $args 3] "" line
295 if {[regexp "\\*(\[a-zA-Z0-9_-\]+)\[ \t\]*(.*)\$" $line junk name value]} {
296 if [string match $configPattern $name] {
297 lappend listToFill($name) $value
299 } elseif {[regexp "(\[a-zA-Z0-9_-\]+)\[ \t\]*(.*)\$" $line junk\
301 if [string match *Path $name] {
302 eval lappend listToFill($name) [split $value ":"]
304 lappend listToFill($name) $value
310 # getConfig - requests from fvwm configuration info and fills given
313 proc getConfig {array {pattern *}} {
315 variable configPattern
318 variable internalHandler
322 set myMask [expr $msgCodes(ConfigInfo)|$msgCodes(End_ConfigInfo)]
323 if {($Mask&$myMask)!=$myMask} {
324 send "Set_Mask $myMask"
326 set configPattern $pattern
327 set internalHandler configHandler
328 send "Send_ConfigInfo"
329 vwait ::fvwm::listDone
330 set internalHandler ""
331 if [info exists listToFill(PixmapPath)] {
332 set PixmapPath $listToFill(PixmapPath)
336 if [info exists listToFill(IconPath)] {
337 set IconPath $listToFill(IconPath)
341 uplevel array set $array [list [array get listToFill]]
343 if {($Mask&$myMask)!=$myMask} {
344 send "Set_Mask $Mask"
348 # winListHandler - handles various events which fvwm sends in response
351 proc winListHandler {type args} {
356 End_WindowList {uplevel #0 set ::fvwm::listDone 1}
357 NewDesk {set listToFill(Desk) [lindex $args 0]}
359 set listToFill(Page) [concat [lrange $args 0 1] [lrange $args 2 3]]
362 set listToFill(Focus) [lindex $args 0]
363 # Don't know how to convert fvwm color info to something
365 # set listToFill(FocusColors) [list\
366 # [format "#%06x" [lindex $args 1]]\
367 # [format "#%06x" [lindex $args 2]]]
369 DefaultIcon {set listToFill(DefaultIcon) [lindex $args 3]}
371 set windowId [lindex $args 0]
372 set listToFill($windowId,frame) [concat [lindex $args 1]\
373 [lrange $args 3 6] [lrange $args 9 10]]
374 set listToFill($windowId,desk) [lindex $args 7]
375 set listToFill($windowId,flags) [lindex $args 8]
376 set listToFill($windowId,base) [lrange $args 11 12]
377 set listToFill($windowId,grid) [lrange $args 13 14]
378 set listToFill($windowId,minSize) [lrange $args 15 16]
379 set listToFill($windowId,maxSize) [lrange $args 17 18]
380 set listToFill($windowId,iconIds) [lrange $args 19 20]
381 set listToFill($windowId,gravity) $gravityText([lindex $args 22])
382 # set listToFill($windowId,colors) [list\
383 # [format "#%06x" [lindex $args 22]]\
384 # [format "#%06x" [lindex $args 23]]]
387 set windowId [lindex $args 0]
388 set listToFill($windowId,frame) [concat [lindex $args 1]\
389 [lrange $args 3 6] [lrange $args 9 10]]
390 set listToFill($windowId,desk) [lindex $args 7]
391 set listToFill($windowId,flags) [lindex $args 26]
392 set listToFill($windowId,base) [lrange $args 10 11]
393 set listToFill($windowId,grid) [lrange $args 12 13]
394 set listToFill($windowId,minSize) [lrange $args 14 15]
395 set listToFill($windowId,maxSize) [lrange $args 16 17]
396 set listToFill($windowId,iconIds) [lrange $args 18 19]
397 # set fd [open $::env(HOME)/tflog a]
398 # puts $fd [array get listToFill $windowId,*]
400 set listToFill($windowId,gravity) $gravityText([lindex $args 22])
401 # set listToFill($windowId,colors) [list\
402 # [format "#%06x" [lindex $args 22]]\
403 # [format "#%06x" [lindex $args 23]]]
405 WindowName {set listToFill([lindex $args 0],title) [lindex $args 3]}
406 IconName {set listToFill([lindex $args 0],iconName) [lindex $args 3]}
407 ResName {set listToFill([lindex $args 0],resource) [lindex $args 3]}
408 ResClass {set listToFill([lindex $args 0],class) [lindex $args 3]}
409 IconFile {set listToFill([lindex $args 0],icon) [lindex $args 3]}
410 MiniIcon {set listToFill([lindex $args 0],miniIcon) [lindex $args 3]}
411 Iconify {set listToFill([lindex $args 0],iconic) 1}
415 # getWindowList - fills given array with info of current desktop
417 proc getWindowList {array {pattern *}} {
422 variable WindowListMask
423 variable internalHandler
426 if {($Mask&$WindowListMask)!=$WindowListMask} {
427 send "Set_Mask $WindowListMask"
429 catch {unset listToFill}
430 set internalHandler winListHandler
431 send "Send_WindowList"
432 vwait ::fvwm::listDone
433 set internalHandler ""
434 uplevel array set $array [list [array get listToFill]]
436 if {($Mask&$WindowListMask)!=$WindowListMask} {
437 send "Set_Mask $WindowListMask"
441 # searches icon through fvwm PixmapPath or IconPath
443 proc iconPath {name {where -pixmap}} {
446 if {![info exist PixmapPath]&&![info exist IconPath]} {
449 if {$where=="-pixmap"} {
451 } elseif {$where=="-icon"} {
454 return -code error "Invalid option. Should be -pixmap or -icon"
458 if {[lsearch -exact [glob -nocomplain [file join $dir *]]\
459 [file join $dir $name]]!=-1} {
460 return [file join $dir $name]
468 fileevent $infd readable [namespace code getMessage]
470 # Default handler for fvwm error message. Raises Tcl asynchroneus error
471 # after idle to avoid closing pipe. Defined in the global namespace
474 if {[llength [info command Error]]==0} {
475 proc Error {msgtype zero0 zero1 zero2 msg} {
476 after idle "error [list $msg] \{[list FVWM 2 $msg]\}"
479 package provide Fvwm 1.3